Discussion:
Matlab vs Python (was RE: Discussion: Introducing new operators for matrix computation)
(too old to reply)
Huaiyu Zhu
2000-07-17 19:42:18 UTC
Permalink
As to the claim that additional operators for linear algebra is somehow
comparable to the special syntaxes/quirks of various programming languages,
no real argument has been presented so far. It's more like: If I don't care
and don't use such things, they must belong to a special domain and be
somehow comparable to some other things that I do know and dislike.
- Python is a general purpose language, and as such it can't
support special case syntax for Matrix/cgi/xml/db programming.
(special syntax has previously been requested for both cgi and
db programming).
I don't see what this tells me about Matrix being comparable to cgi/xml/db,
especially on the level of syntax requirements.
If you really want to convince people, I would like to see examples of
how adding these operators would make working in other domains easier
(directly, not through translation through linear algebra).
I'm not sure what this is asking for. My first impression is similar to
"show me an example of how using C syntax would make working in assembly
easier (directly, not by compiling a C program)".

On second thought, maybe you are thinking about situations like: when doing
web programming you want to add server statistics and put the graphics on
the page? Of course it helps, but you have to translate the numbers into
linear algebra. I don't think these arguments leading anywhere.

Or maybe you want this?

a = ["Alice", "Bob"]
b = " is "
c = ["a girl", "a boy"]
d = a .+ b .+ c

If the request had been: if you really want to convince people that string
literals are worth having in the language, you need to give examples of it
make working in other domains easier (directly, not through translating
through strings), I would have exactly the same reaction. Strings are good
for text. Even though you can use regular expression to calculate pi to any
place you want, which is another domain, that's not the reason strings are
the language.

The morale of the arguement is: requiring every syntax to be useful in every
domain is too extreme and not quite useful. But considering exactly what
the domain is and exactly how it might be used may help.

Huaiyu
Bjorn Pettersen
2000-07-15 00:10:27 UTC
Permalink
On Fri, 14 Jul 2000 11:38:51 -0600, Bjorn Pettersen <bjorn at roguewave.com>
Well, this could actually be generally useful, but not with the .+
syntax (since the dot would interfer with methods on the sequence
object).
You're quoting me out of context here. What I could find generally
useful is a way to spell component-wise operations...
My impression from the python-dev list is that this is not the case. Some
say it is easy to distinguish
a. + b
a .+ b
[snip]

As you might have guessed, I don't really care what is done in the
matrix case -- I don't use matrices. If a component-wise "operator"
were to be added to Python however, I would expect it to work with e.g.
list and in that case a dot is ambigous:

mylist.foo() # are you calling the foo method on the list or the
elements?

I have a feeling that what you really want these operators to do is
paralell component-wise operations on more than one collection object
though, which is exactly what list comprehensions do (in a general way).

-- bjorn
Paul Prescod
2000-07-17 23:10:06 UTC
Permalink
Post by gjm11
...
Only if you implement matrices as lists of lists, in which
case operations like * and / won't work anyway. I was assuming
that (1) you have a special Matrix class, and (2) the machinery
for list comprehensions is flexible enough to let it express
other kinds of mapping.
Today, the list comprehension syntax is syntactic sugar for

a=[]
for i in firstloop:
for j in secondloop: ...
a.append( i, j )

I don't see any easy way to guess what type you want as "output" so it
has to default to a fixed type. You could of course do this:

Matrix( [...] )

I would be curious about ideas for allowing the output object to be
specified or inferred. What would the protocol be?
--
Paul Prescod - Not encumbered by corporate consensus
It's difficult to extract sense from strings, but they're the only
communication coin we can count on.
- http://www.cs.yale.edu/~perlis-alan/quotes.html
Rainer Deyke
2000-07-15 05:04:22 UTC
Permalink
"Bjorn Pettersen" <bjorn at roguewave.com> wrote in message
Post by Bjorn Pettersen
mylist.foo() # are you calling the foo method on the list or the
elements?
A valid point (though not very clearly stated). Suppose that for all X, .X
is the elementwise operator such that:

a = b .X c

is equivalent to:

a = []
for x in range(len(b)):
a.append(b[x] X c[x])

What about situations where X is a function instead of an operator? Should
we allow the following syntax?

a = b..f()

(Equivalent to the following:)

a = []
for x in b:
a.append(x.f())

Is b..f(c) equivalent to this:

a = []
for x in range(len(b))
a.append(b[x].f(c[x]))

or is it equivalent to this:

a = []
for x in b:
a.append(x.f(c))

For that matter, what if X is .+ (or ..+)? Should we allow this:

a = b ..+ c

as equivalent to this:

a = []
for x in range(len(b))
a.append(b .+ c)

There has to be a better way to do elementwise operations.


--
Rainer Deyke (root at rainerdeyke.com)
Shareware action/role-playing games - http://rainerdeyke.com
"In ihren Reihen zu stehen heisst unter Feinden zu kaempfen" - Abigor
Gareth McCaughan
2000-07-15 22:38:30 UTC
Permalink
How would you write this in list compresension (in less than 10 lines)?
B*(sin(A*x+b).*(A*y)/3)/C
Note that * is matrix multiplication and .* is elementwise. Note that C is
a matrix so the / is matrixwise. If you want to write everything as for
loops it takes at least 30 lines, without any decent error analysis.
B*[p*q/3 for p in A*x+b, q in A*y]/C

(I've forgotten the proposed syntax for comprehension, so that
may be slightly wrong.) I'm not sure what precedences you want
the .* and / operators to have, so it's possible that I really
mean

B*[p*q for p in A*x+b, q in (A*y)/3]/C ;

of course they evaluate to the same thing anyway.
--
Gareth McCaughan Gareth.McCaughan at pobox.com
sig under construction
Gareth McCaughan
2000-07-17 20:27:16 UTC
Permalink
How would you write this in list compresension (in less than 10 lines)?
B*(sin(A*x+b).*(A*y)/3)/C
Note that * is matrix multiplication and .* is elementwise. Note that C is
a matrix so the / is matrixwise. If you want to write everything as for
loops it takes at least 30 lines, without any decent error analysis.
B*[p*q/3 for p in A*x+b, q in A*y]/C
Someone else had already given a similar answer. But more work is needed
The x, b and y could be matrices, so p and q need to be double loops.
Only if you implement matrices as lists of lists, in which
case operations like * and / won't work anyway. I was assuming
that (1) you have a special Matrix class, and (2) the machinery
for list comprehensions is flexible enough to let it express
other kinds of mapping.
The [ ... ] need to be a double lists. Is list comprehension defined for
this?
It doesn't even exist yet. :-)

I repeat that I'm assuming that there's mechanism for doing
"comprehension" on aggregate objects other than lists, so
that [f(p) for p in FOO] can be made to build a copy of FOO
with the operation f applied to its elements. I think this
is the Python Way (consider e.g. the fact that it does
tuple indexing and list indexing and dictionary indexing
all with a uniform syntax).
B*[..]/C would not work without a cast from double list to matrix.
Not if my assumption above is correct.
For all these errors, what would the error messages look like? Do they
involve the dummy indices p and q? A previous answer also reused the name b
for the dummy variable, which would make the error even more obscure.
These are not errors unless my (perfectly reasonable) assumptions
turn out to be false.
Besides, the main point of using matrix is to be free from specifying loops
over indices with dummy names. Compare this double loop with extra syntax
with a single operator .* and you may wonder why this is considered at all.
And compare the cumbersome expression above with the much simpler
&
which I have just defined to mean what you write as
"B*(sin(A*x+b).*(A*y)/3)/C". It's easy to make things
look neater by adding syntactic sugar, provided you're
doing it to only one smallish class of things at a
time. But there's such a thing as too much syntactic
sugar. One design decision that's pretty fundamental
to Python is that there's very little syntactic sugar;
if you prefer a language that goes the other way, you
can always try APL or J. They're pretty good with
matrices, too. :-)
--
Gareth McCaughan Gareth.McCaughan at pobox.com
sig under construction
Huaiyu Zhu
2000-07-17 06:12:35 UTC
Permalink
How would you write this in list compresension (in less than 10 lines)?
B*(sin(A*x+b).*(A*y)/3)/C
Note that * is matrix multiplication and .* is elementwise. Note that C is
a matrix so the / is matrixwise. If you want to write everything as for
loops it takes at least 30 lines, without any decent error analysis.
B*[p*q/3 for p in A*x+b, q in A*y]/C
Someone else had already given a similar answer. But more work is needed
for such things to work:

The x, b and y could be matrices, so p and q need to be double loops.

The [ ... ] need to be a double lists. Is list comprehension defined for
this?

B*[..]/C would not work without a cast from double list to matrix.

For all these errors, what would the error messages look like? Do they
involve the dummy indices p and q? A previous answer also reused the name b
for the dummy variable, which would make the error even more obscure.

Besides, the main point of using matrix is to be free from specifying loops
over indices with dummy names. Compare this double loop with extra syntax
with a single operator .* and you may wonder why this is considered at all.

Since this is going way off original topic I'll stop here. I admit that I'm
at fault to a large extent.

As to the question of what's the precedence of the proposed .* like
operators, they are the same as their ordinary counterparts, because they
become identical when the operands are numbers or 1x1 matrices.


Huaiyu
Huaiyu Zhu
2000-07-18 02:54:21 UTC
Permalink
e(r'(A .* B)\C') # --> PyAlgebra.evaluate(r'(A .* B)\C', globals(), locals())
where A, B and C are bound to variables in the current namespace
automatically? Does this not go 95% of the way toward the ideal solution?
Well, not that much. What about this:

webpage = webobject(url)
result = e(r'transform * get_data_from(webpage)')

If it is allowed wouldn't we allow

result = e(r'transform * get_data_from(webobject(url))')

or even using "http:..." in place of url? Eventually, wouldn't the
e(r'...') be able to parse the whole python grammer?

If on the other hand it is limited to numerical type objects only it is too
limited. In MatPy.gplot we use lists, dicts and strings to deal with
multiline plots and titles, etc.

Well, maybe I just don't like to treat numerical type objects any
differently from other objects because they are intermixed all over in the
programs. Otherwise a python-octave gateway or just stick with octave may
even be preferable.

One of my biggest gripe about matlab is it forces me to treat strings as
part of matrix. Now you are asking me to treat matrix as part of string.
:-)
I disagree with your conclusion. Having worked with many algebra and
statistical languages, I know the road you are undertaking. It doesn't and
can't stop with one extra dot in the grammar. To do it right, you need the
ability to break more rules that are intrinsic to Python's core. e.g.,
consider changing the rules for '\' as above.
This makes some sense, but I know a lot of people who can resist the
temptation of other syntactic sugar, except infix operator for arithmetics -
it's just too good a thing to miss.

There are proposals for using @/ and /@ for two directions of division, or
using % for left division. I'm comfortable with the current solve(a,b), or
maybe a shorter sol(a,b) but am open to any suggestions.
Another advantage to compromising and implementing a domain specific
mini-language is that it simplifies some very tough design issues that only
come up when working with the full Python grammar. Some of these syntactic
and semantic issues are very likely irreconcilable. In the end we could end
up with a any number of splinter languages with inferior support and narrow
audiences. Lets not forget we are a community of users with very diverse
goals, all trying make our lives easier by building better tools.
I'm not quite with you here. Exactly for the purpose of making numerical
objects and other objects work seemlessly together I am against changing
syntactic structure, and only for adding syntactic contents within current
structure. Well, let's see if this makes sense. What I'm saying is, .* is
just another operator, so if you replace it with * the syntax structure does
not change. On the other hand, using e(r'...') changes the structure because
variable names within a string suddenly gets out. In this sense it is less
like a function call with a string literal argument, but rather a special
syntax zone delimited with strange combination symbols e(r' and '). If a
program is littered with such special zones the effect is very much like an
aspect of Perl that I happen to dislike.

Just my thoughts.

Huaiyu
Matt Feinstein
2000-07-13 12:33:49 UTC
Permalink
On Wed, 12 Jul 2000 19:32:32 GMT, hzhu at knowledgetrack.com (Huaiyu Zhu)
We are at a crucial juncture concerning introduction of new operators into
Python for matrix computation,
1. Experiences with Matlab show that different operators for matrix and
elementwise operators are very important
2. It is difficult to add .* and ./ as . is already a valid token. It seems
3. Gregory Lielens has just implemented a patch that could parse additional
a at b is equivalent to a*b, overloaded using __mmul__ and __rmmul__
He indicates similar constructions can be added easily.
We intend to add these operators together with Thomas Wouters's augmented
assignment operators (+=,*=, etc) to MatPy, but before that several
- Consistent with Matlab.
- Consistent with current MatPy.
- Convenient for matrix computations.
- Inconsistent with NumPy
- How to differentiate left and right div (matlab a\b and a/b)?
- Consistent with NumPy
- Can use a at b as inner product so that a at b works irrespective of whether a
and b are row or col operators.
- Inconsistent with current MatPy. Need great effort to switch.
- Using two symbol operator for matrix mul is cumbersome for long formulas.
- It kind of looks ugly.
3. Use a at b as matrix mul, and a*b as elementwise mul. This has most of the
pros and cons of choice 2, except
- Single symbol operators for matrix mul and element mul.
- Can't use a at b as inner product.
My own preference would be 'as consistent as possible with MATLAB,
with some caveats'-- this would mean option 1, with some thought about
changes in places where the current MATLAB syntax drops the ball
(IMO). I don't think MATLAB's inelegances should be preserved for the
sake of consistency. On the other hand, I think it's very important to
make the translation from MATLAB language to Python as automatic as
possible.

The main thing I'd think about in addition to standard MATLAB syntax
is a natural 'prolongation' syntax. In other words, contexts in which
the vector [1 2 3] is naturally expanded to [1 2 3;1 2 3;1 2 3;...].
This operation is part of one of the basic strategies in
vectorization-- prolongation, followed by some vectorized operation,
followed in turn by selection or contraction. Presently, MATLAB can do
this, but only in an idomatic and peculiar way. There are some dangers
in this route-- it encourages a tendency to syntactical trickiness--
the history of the APL language provides a case in point and a
warning.

One thing that MATLAB does correctly (again, IMO) is its relatively
relaxed attitude towards distinctions among scalars, 1x1 vectors &
matrices as well as among different kinds of nulls and NAN's. You can
test for these distinctions if you want to, but generally MATLAB will
just quietly do the right thing. There's a tendency to get wrapped up
in fine distinctions in cases where there's really no ambiguity about
what the programmer wants to do.

--
Matt Feinstein
mfein at aplcomm.jhuapl.edu
Organizational Department of Repeated
and Unnecessary Redundancy
Matt Feinstein
2000-07-14 12:52:39 UTC
Permalink
On Fri, 14 Jul 2000 14:51:05 +0200, Gregory Lielens
Post by Matt Feinstein
The main thing I'd think about in addition to standard MATLAB syntax
is a natural 'prolongation' syntax.
What I mean is, given vectors, e.g.,
d = [d1 d2]
c = [ c1 c2 c3]
an apparently incorrect element-wise multiplication like
d'.*c
would be interpreted as
[d1 d1 d1; d2 d2 d2].*[c1 c2 c3;c1 c2 c3]
which is a classical matrix product d'*c, I think,at least if you
distinguish between line and column vectors...
AUUGH. That's what happens when you post too early in the morning.

--
Matt Feinstein
mfein at aplcomm.jhuapl.edu
Organizational Department of Repeated
and Unnecessary Redundancy
Huaiyu Zhu
2000-07-13 19:47:23 UTC
Permalink
On Thu, 13 Jul 2000 12:33:49 GMT, Matt Feinstein <mfein at aplcomm.jhuapl.edu>
Post by Matt Feinstein
My own preference would be 'as consistent as possible with MATLAB,
with some caveats'-- this would mean option 1, with some thought about
changes in places where the current MATLAB syntax drops the ball
(IMO). I don't think MATLAB's inelegances should be preserved for the
sake of consistency.
Any specific examples in mind?
Post by Matt Feinstein
On the other hand, I think it's very important to
make the translation from MATLAB language to Python as automatic as
possible.
Agreed. OTOH, it is forgone conclusion that we can't have both a\b and a/b.
So they have to be something similar to a/@b and a@/b. That's my main
problem with option 1. Using a fine symbol like \ as an escape marker looks
like a great waste to mathematicians but this has been with so many
programming languages for such a long time.
Post by Matt Feinstein
The main thing I'd think about in addition to standard MATLAB syntax
is a natural 'prolongation' syntax.
Are you thinking about this?
a = [1 2]
b = [3 4]
[a,b] # [1 2 3 4]
[a;b] # [1 2; 3 4]

Currently in MatPy we have the following, which is more general because no
special syntax is needed. But maybe we can find a better names?

Matrix_r([a,b])
Matrix_c([a,b])
Post by Matt Feinstein
One thing that MATLAB does correctly (again, IMO) is its relatively
relaxed attitude towards distinctions among scalars, 1x1 vectors &
matrices as well as among different kinds of nulls and NAN's. You can
test for these distinctions if you want to, but generally MATLAB will
just quietly do the right thing. There's a tendency to get wrapped up
in fine distinctions in cases where there's really no ambiguity about
what the programmer wants to do.
Right now in MatPy the distinction between 1x1 matrix and scalar is
maintained, intentionally. So if size(x)==(3,1) then a*x works if a is
scalar but not if a is 1x1 matrix. I had had a fair bit of surprises in
matlab where something would work properly until someday it is given a
vector of length one, which is treated as a scalar.

On the other hand, there is no need to distinct vectors from 1xn and nx1
matrices and that's where we depart from NumPy.

Huaiyu
Doug Schwarz
2000-07-14 13:01:22 UTC
Permalink
In article <396f0031.3421579 at aplnews>, mfein at aplcomm.jhuapl.edu (Matt
What I mean is, given vectors, e.g.,
d = [d1 d2]
c = [ c1 c2 c3]
an apparently incorrect element-wise multiplication like
d'.*c
would be interpreted as
[d1 d1 d1; d2 d2 d2].*[c1 c2 c3;c1 c2 c3]
Please forgive this slightly off-topic response.

Matt,

Are you aware of the Generalized Arithmetic Operators (genops) functions
I developed for MATLAB? They implement as MEX functions exactly this
behavior. For more info please see

<http://www.servtech.com/~schwarz/genops.html>

We now return you to your regularly scheduled Python discussion.
--
Doug Schwarz
Eastman Kodak Company
douglas.schwarz at kodak.com
Matt Feinstein
2000-07-14 12:03:55 UTC
Permalink
On Thu, 13 Jul 2000 19:47:23 GMT, hzhu at localhost.localdomain (Huaiyu
Post by Huaiyu Zhu
Post by Matt Feinstein
The main thing I'd think about in addition to standard MATLAB syntax
is a natural 'prolongation' syntax.
Are you thinking about this?
a = [1 2]
b = [3 4]
[a,b] # [1 2 3 4]
[a;b] # [1 2; 3 4]
What I mean is, given vectors, e.g.,

d = [d1 d2]
c = [ c1 c2 c3]

an apparently incorrect element-wise multiplication like

d'.*c

would be interpreted as

[d1 d1 d1; d2 d2 d2].*[c1 c2 c3;c1 c2 c3]


--
Matt Feinstein
mfein at aplcomm.jhuapl.edu
Organizational Department of Repeated
and Unnecessary Redundancy
Gregory Lielens
2000-07-14 12:51:05 UTC
Permalink
Post by Matt Feinstein
The main thing I'd think about in addition to standard MATLAB syntax
is a natural 'prolongation' syntax.
What I mean is, given vectors, e.g.,
d = [d1 d2]
c = [ c1 c2 c3]
an apparently incorrect element-wise multiplication like
d'.*c
would be interpreted as
[d1 d1 d1; d2 d2 d2].*[c1 c2 c3;c1 c2 c3]
which is a classical matrix product d'*c, I think,at least if you
distinguish between line and column vectors...

Is there other uses of the prolongation syntax wich is not feasable with
an inner product c=a at b defined as
c(i1,...,in,k1,...,km)= sum_over_j(a(i1,...,in,j) * b(j,k1,...,km)), and
well choosen dimensions for a and c?
If creation of dummy dimension in arrays (i.e. with size 1) is easy, I
think it is a good (better?) alternative
to prolongation...

Such inner product is valid for array of arbitrary dimensions, and
degenerate to matrix product when both operands are matrix, it should
thus be suitable to both for NumPy and MatPy...
I think it is valid proposition for the meaning of the new
multiplicative operator, should such operator be adopted (and I hope so
:-))


Greg.
Johann Hibschman
2000-07-18 03:26:51 UTC
Permalink
- that many problems can be reduced to matrix operations is
a non-argument, since the same is true of functional/
procedural/oo/predicate programming.
I agree, but there is a big userbase waiting for an alternative
to the $$ Matlab.
Octave is already there as a free alternative, so I doubt python will
attract many of those people.

Personally, I find that the matrix-orientation of Matlab makes it
harder to get things done. I more often have 3 or higher dimensional
arrays than I have plain old 2D matrices, so I'd rather see the more
general Numeric Python syntax than any over-specialized matrix code.

When you're contracting a 4-tensor with a vector, you almost need an
index-based notation.

As it is, the only things missing from NumPy is an easy spelling of
matrix-matrix multiplication, and if you really need that, you can
just define your own class to do it.
--
Johann Hibschman johann at physics.berkeley.edu
gjm11
2000-07-17 22:20:03 UTC
Permalink
How would you write this in list compresension (in less than 10 lines)?
B*(sin(A*x+b).*(A*y)/3)/C
Note that * is matrix multiplication and .* is elementwise. Note that C is
a matrix so the / is matrixwise. If you want to write everything as for
loops it takes at least 30 lines, without any decent error analysis.
B*[p*q/3 for p in A*x+b, q in A*y]/C
Someone else had already given a similar answer. But more work is needed
The x, b and y could be matrices, so p and q need to be double loops.
Only if you implement matrices as lists of lists, in which
case operations like * and / won't work anyway. I was assuming
that (1) you have a special Matrix class, and (2) the machinery
for list comprehensions is flexible enough to let it express
other kinds of mapping.
The [ ... ] need to be a double lists. Is list comprehension defined for
this?
It doesn't even exist yet. :-)

I repeat that I'm assuming that there's mechanism for doing
"comprehension" on aggregate objects other than lists, so
that [f(p) for p in FOO] can be made to build a copy of FOO
with the operation f applied to its elements. I think this
is the Python Way (consider e.g. the fact that it does
tuple indexing and list indexing and dictionary indexing
all with a uniform syntax).
B*[..]/C would not work without a cast from double list to matrix.
Not if my assumption above is correct.
For all these errors, what would the error messages look like? Do they
involve the dummy indices p and q? A previous answer also reused the name b
for the dummy variable, which would make the error even more obscure.
These are not errors unless my (perfectly reasonable) assumptions
turn out to be false.
Besides, the main point of using matrix is to be free from specifying loops
over indices with dummy names. Compare this double loop with extra syntax
with a single operator .* and you may wonder why this is considered at all.
And compare the cumbersome expression above with the much simpler
&
which I have just defined to mean what you write as
"B*(sin(A*x+b).*(A*y)/3)/C". It's easy to make things
look neater by adding syntactic sugar, provided you're
doing it to only one smallish class of things at a
time. But there's such a thing as too much syntactic
sugar. One design decision that's pretty fundamental
to Python is that there's very little syntactic sugar;
if you prefer a language that goes the other way, you
can always try APL or J. They're pretty good with
matrices, too. :-)

--
Gareth McCaughan Gareth.McCaughan at pobox.com
sig under construction
Paul Prescod
2000-07-17 19:59:32 UTC
Permalink
...
Right, but you weren't the person who brought up the millions of Matlab
users this time.
...
On the other hand, open source may beat them
easily, as long as
1. we are using a better language which has more potential
2. users have incentive to contribute because it's already useful
3. there's no big hurdle beyond what's already in Numerical Recipe
You presume a great deal of human labour which you cannot provide by
yourself. We cannot extend Python based on your faith that these people
will come along and do the work to make it a serious Matlab competitor.
Anyhow, you can prove me wrong by making MatrixPython as popular as
Python. Then we will come to YOU and ask if we can merge grammars to
unify our communities.

I could just as easily claim that if we add regular expressions to the
Python syntax, all of the Perl users would come over here. I don't have
any evidence, though.
--
Paul Prescod - Not encumbered by corporate consensus
It's difficult to extract sense from strings, but they're the only
communication coin we can count on.
- http://www.cs.yale.edu/~perlis-alan/quotes.html
Moshe Zadka
2000-07-18 06:29:34 UTC
Permalink
Consider the proposal of having two classes, Matrixwise and Elementwise,
with methods to cast to each other. I don't know why
(a.E()*b.E()).M()*(c.E()*d.E()).M()
would be more preferable to
(a.*b)*(c.*d)
For the same reason

import sys, re

r = re.compile("a(.*)z")
while 1:
line = sys.stdin.readline()
if not line:
break
m = r.search(line)
if m:
print m.group(1)

To:
while(<STDIN>) {
print $1 . "\n" if /a(.*)z/;
}

It's more verbose, and people are able to understand it without learning
weird corners of the language. (BTW: as a former Perl hacker, I find the
Perl code *extremely* readable, and I spend more time understanding the
Python code. But that doesn't change the fact that Perl took me longer to
master then Python, and even then I didn't really understand Perl. For
example, could I lose the ";" in the Perl code? I think so, but I'm not
sure)

--
Moshe Zadka <moshez at math.huji.ac.il>
There is no GOD but Python, and HTTP is its prophet.
http://advogato.org/person/moshez
John Lull
2000-07-18 13:09:12 UTC
Permalink
At the dawn of the third millenium (by the common reckoning), Paul
Look, if you took a poll of all programmers in the world, only a small
fraction use matrices very often. Therefore it is a niche. Most
programmers use numbers and strings every day, however.
By that reasoning, cryptography ought not be part of the standard
distribution, either. Nor should complex numbers.

A very large part of the *reason* it's not used more is that linear
algebra is simply *not* natively available in any common language
other than Matlab.
Neil Hodgson
2000-07-18 14:02:57 UTC
Permalink
Post by John Lull
By that reasoning, cryptography ought not be part of the standard
distribution, either. Nor should complex numbers.
I'm all for that one. Lets remove complex numbers. With creaping
featurism, each new feature makes someone very happy. The small amount of
added pain to the majority isn't noticeable until the layers of crud have
become deep enough to start paralysing development. Its /so/ hard to remove
something once its in and backwards compatibility becomes an implied but
unbreakable contract.

I don't care so much about cryptography as its just another library with
no syntactic overhead but removing complex numbers would decrease Python's
complexity ;)

Neil
Paul Prescod
2000-07-18 19:24:30 UTC
Permalink
Post by John Lull
By that reasoning, cryptography ought not be part of the standard
distribution, either. Nor should complex numbers.
We aren't talking about the standard distribution. We're talking about
the language syntax. If many matrix-people wanted matrices in the
standard library, it would probably be there. Cryptography required no
new syntax and complex numbers required very little. There is already
more syntax in the core language for matrices than for complex numbers.
--
Paul Prescod - Not encumbered by corporate consensus
Just how compassionate can a Republican get before he has to leave the
GOP and join Vegans for Global Justice? ... One moment, George W. Bush
is holding a get-to-know-you meeting with a bunch of gay Republicans.
The next he is holding forth on education or the environment ... It is
enough to make a red-blooded conservative choke on his spotted-owl
drumstick. - April 29th, Economist
David M. Cooke
2000-07-17 21:39:33 UTC
Permalink
Maybe you should consider how to scale back your syntactic request.
Perhaps a single keyword or symbol at the beginning of an expression
could make it element-wise or matrix-wise.
Well, that would be fine if it is workable, ie, when they don't appear in
the same expression.
Consider the proposal of having two classes, Matrixwise and Elementwise,
with methods to cast to each other. I don't know why
(a.E()*b.E()).M()*(c.E()*d.E()).M()
would be more preferable to
(a.*b)*(c.*d)
Well, it doesn't have to be as complicated as your first example. Assume
the default is Matrixwise, and we get rid of some ()'s by overriding
__getattr__, so that we can right

(a.E*b.E)*(c.E*d.E)

Better? It's not great, you have to remember to put .E on both. Ahh!
But what if we assume that if one operand has .E, the other does also!
Then we can write

(a.E*b)*(c.E*d)

which is two characters more than your second example.
--
|>|\/|<
----------------------------------------------------------------------------
David M. Cooke
cookedm at mcmaster.ca
John Lull
2000-07-18 14:51:52 UTC
Permalink
At the dawn of the third millenium (by the common reckoning), Paul
I don't think you need __getattr__
self.T=Transpose( self )
self.H=Hermitian( self )
self.I=Inverse( self )
self.C=Conjugate( self )
self.E=Elementwise( self )
self.M=self # matrixwise is default
... other matrix-like methods ...
This, I think, works for everything but .E. You can write a method
Transpose which, for most possible classes derived from Matrix, does
the right thing by returning a derived class object with the data
transposed. An element-wise matrix, however, would have exactly the
same data as the original matrix, it just has a lot of the *methods*
replaced. To make this work for derived classes, you have to either
add a level of indirection to all the standard operator methods, or
prohibit overriding the standard operator methods.

How about one small change to Python, breaking no existing code, and
applicable (I'm sure) to domains far-afield from linear algebra:

Currently,
object operator other
is really just convenient shorthand for:
object.__operatorname__(other)
or
other.__roperatorname__(object)
where operator is any binary arithmetic operator.

What if we simply make
object @operator other
convenient shorthand for:
object.__alt__operatorname__(other)
or
other.__alt__roperatorname__(object)
for all those same operators?

This would be a syntax error when applied to anything other than an
object, and would raise an appropriate exception if neither object nor
other provided an appropriat __alt method.

This would provide a way of adding a reasonable variety of
domain-specific operators to *any* class with very little impact on
the language, zero runtime penalty, and obvious & correct behaviour
when creating derived classes. It would not break any existing code
and should be very simple to implement.

I haven't thought through whether the same behavior should apply to
anything other than binary arithmetic operators. Doing so would seem
very Pythonic.

Regards,
John
Paul Prescod
2000-07-20 14:30:31 UTC
Permalink
...
It has no advantage on a simple expression like this, assuming a and b
provide newOp() and otherOp() respectively. The advantage only shows
up on complex expressions, where the functional notation can make it
much more difficult to read, or in a case where b.__otherOp__()
provides __rnewOp__().
Well, if there is any possibility of a name-based system "winning" then
I am strongly in favor of it. You could make it a little shorter by
using ~ instead of ..

~elMul~
~matMul~
~newfunc~

I think that that would be very extensible and reasonably readable. If
the word in the middle could be a re-assignable name then you could say:

eM=elMul

a ~eM~ b
--
Paul Prescod - Not encumbered by corporate consensus
"Hardly anything more unwelcome can befall a scientific writer than
having the foundations of his edifice shaken after the work is
finished. I have been placed in this position by a letter from
Mr. Bertrand Russell..."
- Frege, Appendix of Basic Laws of Arithmetic (of Russell's Paradox)
Huaiyu Zhu
2000-07-18 21:12:57 UTC
Permalink
I really like this kind of ideas. Anyone able to implement it? What it
takes to change a patch of grammar to an importable module?

Maybe the way to do it is to change the python implementation of operator
into an object oriented approach? Similar to PyObject we'll have a
PyOperator which defines the symbol, name, scoping and precedence rules.
This way handling operators within python would be similar to hadling
ordinary objects, by import NewOperator. To discourage abuses there may be
restrictions on what is allowed as symbols and what precedence rules are
allowed and so forth, and perhaps prohibit dynamic changes within an
importing module.

If everything about operators is concentrated within one class I think this
will also make python itself simpler. In any case I think this fits in the
idea of doing things in organized way and removing arbitrary restrictions.

(This is just my guesstimate so that others may come with hard facts.)

Huaiyu
Post by John Lull
How about one small change to Python, breaking no existing code, and
Currently,
object operator other
object.__operatorname__(other)
or
other.__roperatorname__(object)
where operator is any binary arithmetic operator.
What if we simply make
object.__alt__operatorname__(other)
or
other.__alt__roperatorname__(object)
for all those same operators?
This would be a syntax error when applied to anything other than an
object, and would raise an appropriate exception if neither object nor
other provided an appropriat __alt method.
This would provide a way of adding a reasonable variety of
domain-specific operators to *any* class with very little impact on
the language, zero runtime penalty, and obvious & correct behaviour
when creating derived classes. It would not break any existing code
and should be very simple to implement.
I haven't thought through whether the same behavior should apply to
anything other than binary arithmetic operators. Doing so would seem
very Pythonic.
Regards,
John
Barry A. Warsaw
2000-07-19 12:50:56 UTC
Permalink
TP> + There *must* be a PEP for this.

There already is: PEP 211, Adding New Operators to Python. And it's
been assigned to Greg Wilson, although he may want to re-assign it.
It's currently just boilerplate.

-Barry
Paul Prescod
2000-07-20 06:51:19 UTC
Permalink
...
a..newOp..(b..otherOp..c)
I really like the fact that the operator uses a word instead of a
cryptic symbol, but I can't understand why anyone would prefer the above
to:

a.newOp(b.otherOp(c))

The only thing you've bought is the ability to look up the operation on
the right-side of the operator and a slightly more symmetric "look".
--
Paul Prescod - Not encumbered by corporate consensus
"Hardly anything more unwelcome can befall a scientific writer than
having the foundations of his edifice shaken after the work is
finished. I have been placed in this position by a letter from
Mr. Bertrand Russell..."
- Frege, Appendix of Basic Laws of Arithmetic (of Russell's Paradox)
John Lull
2000-07-20 12:53:02 UTC
Permalink
At the dawn of the third millenium (by the common reckoning), Paul
Post by Paul Prescod
...
a..newOp..(b..otherOp..c)
I really like the fact that the operator uses a word instead of a
cryptic symbol, but I can't understand why anyone would prefer the above
a.newOp(b.otherOp(c))
It has no advantage on a simple expression like this, assuming a and b
provide newOp() and otherOp() respectively. The advantage only shows
up on complex expressions, where the functional notation can make it
much more difficult to read, or in a case where b.__otherOp__()
provides __rnewOp__().
Paul Prescod
2000-07-18 21:01:12 UTC
Permalink
...An element-wise matrix, however, would have exactly the
same data as the original matrix, it just has a lot of the *methods*
replaced.
So? That's easy.
To make this work for derived classes, you have to either
add a level of indirection to all the standard operator methods, or
prohibit overriding the standard operator methods.
Either option is easy. Are we really that concerned about matrix
subclasses?
This would provide a way of adding a reasonable variety of
domain-specific operators to *any* class with very little impact on
the language, zero runtime penalty, and obvious & correct behaviour
when creating derived classes. It would not break any existing code
and should be very simple to implement.
This is basically the original proposal slightly reworded. The problem
is that alot of people think that adding operators without predefined,
cross-module semantic is un-pythonic. Python allows operator overloading
but the meaning behind the syntaxes are always well-defined. "+" is for
addition-like things. "*" is for multiplication-like things. [] for
indexing-like things, "." for attribute-like things and so forth.
--
Paul Prescod - Not encumbered by corporate consensus
Just how compassionate can a Republican get before he has to leave the
GOP and join Vegans for Global Justice? ... One moment, George W. Bush
is holding a get-to-know-you meeting with a bunch of gay Republicans.
The next he is holding forth on education or the environment ... It is
enough to make a red-blooded conservative choke on his spotted-owl
drumstick. - April 29th, Economist
John Lull
2000-07-19 14:07:11 UTC
Permalink
(posted & mailed)
Post by Paul Prescod
This is basically the original proposal slightly reworded. The problem
is that alot of people think that adding operators without predefined,
cross-module semantic is un-pythonic. Python allows operator overloading
but the meaning behind the syntaxes are always well-defined. "+" is for
addition-like things. "*" is for multiplication-like things. [] for
indexing-like things, "." for attribute-like things and so forth.
I'm not proposing we change that -- even though someone is *already*
free to abuse the notation by overriding __operatorname__() methods.
People simply don't do it, because they know their software won't get
used if they do.


Do I understand you correctly?

We should not add domain-specific operators, because they clutter the
language without enhancing other domains.

We should not add non-domain-specific operators, because they might be
used differently in different domains.

By that standard, Python should *never* have any new operators.


I'm sorry, I fail to see the problem with *one* operator modifier,
clearly flagged as being domain-specific, and providing well-defined
behavior. Anyone seeing 'a @* b' *knows* that @* is not traditional
multiplication, and will have some domain-specific behavior. If
someone wants to misuse @+ to mean 'subtract', frankly I don't think
we need to worry about it -- because their package just won't get
used, and won't be around long.

Regards,
John

Huaiyu Zhu
2000-07-18 20:07:39 UTC
Permalink
On Tue, 18 Jul 2000 14:54:10 +0200, Gregory Lielens <gregory.lielens at fft.be>
I think that it is the more elegant solution if the introduction of new
operators is rejected...
This could turn to be even more elegant, if it allow something like
C = A.I*b to be equivalent to Matlab's C = A\b, i.e. without any
inversion of matrix A.
Wait. Wouldn't this be in fact an operator .I* acting on a and b? I would
think this is more than the additional operator .* etc. Module writers
would have a feast on the abundance of supplies. :-)
This kind of "retarded" evaluation could even lead to further
optimizations, and I tink
that the trace-back problem is avoided if we can ensure that any new
matrix that is produced and returned
by an expression evaluation or a function is always in a "blank" state,
i.e. without any I, T, H,... flag
on...
Maybe Travis can answer this: how is transpose implemented in NumPy today?
Does it produce a new copy or just changes the indexing?

Huaiyu
Tim Hochberg
2000-07-18 20:34:27 UTC
Permalink
Post by Huaiyu Zhu
Maybe Travis can answer this: how is transpose implemented in NumPy today?
Does it produce a new copy or just changes the indexing?
I'm not Travis, but I'll answer anyway: it just changes the indexing.

-tim
Gregory Lielens
2000-07-18 12:54:10 UTC
Permalink
Yep. See code below.
BTW, you meant
(a.E*b.E).M*(c.E*d.E).M
for otherwise it is equivalent to (a.*b).*(c.*d).
Actually, I was thinking that elementwise multiplication would return
an object that does matrixwise multiplication (the idea being that
elementwise is a special case, just as .* is used for it instead of *
in Matlab).
Post by David M. Cooke
But what if we assume that if one operand has .E, the other does also!
Then we can write
(a.E*b)*(c.E*d)
This won't work. It would introduce many hard-to-trace bugs. Looking at
(a*b)*(c*d)
and you have to trace the program all the way down to figure out the
identities of a,b,c,d. Note that in concept the identities of the objects
do not change. We are changing their identities only as labels to help
picking different operators. I can foresee great confusion in practice with
this approach.
I realize this. Note that you have to trace the program to tell that
a,b,c,d are matrices anyway :-). A lot of this is removed by always
having an operation return a Matrixwise object.
I think that it is the more elegant solution if the introduction of new
operators is rejected...
This could turn to be even more elegant, if it allow something like
C = A.I*b to be equivalent to Matlab's C = A\b, i.e. without any
inversion of matrix A.

This kind of "retarded" evaluation could even lead to further
optimizations, and I tink
that the trace-back problem is avoided if we can ensure that any new
matrix that is produced and returned
by an expression evaluation or a function is always in a "blank" state,
i.e. without any I, T, H,... flag
on...

A minor problem of this approach could be the time spend in checking the
flags, but the main problem I see is that it will make the code for
*,+,...more complex for optimized version. For any unoptimized function
or operator, something like a FlagReset method shoul be called for all
arguments, to have the updated matrices...
If the flags treatment prove to take significative time, one solution
should to move them in the C struct which
implement NumPy arrays, which will makes thing even more complex, I am
affraid...
But appart from this complexity, this is quite appealing imho...


Greg.
Paul Prescod
2000-07-18 00:22:31 UTC
Permalink
...
That's a good point. Can __getattr__ be made to work only on a selected
number of attributes? We could use it on T, H, I, C for transpose,
Hermitian transpose, inverse and conjugate. But if it works on all the
undefind members the error message may be too obscure.
I don't think you need __getattr__

class Matrix:
def __init__( self, ....):
self.T=Transpose( self )
self.H=Hermitian( self )
self.I=Inverse( self )
self.C=Conjugate( self )
self.E=Elementwise( self )
self.M=self # matrixwise is default
... other matrix-like methods ...

class Transpose:
def __init__( self, mymatrix ):
self.mymatrix=mymatrix
... other matrix-like methods, but transposed ...

Notice that no computation (e.g. actual transposition) needs to be done
until you actually need to calculate a value. Maybe you can find
optimizations that allow only tiny parts of matrices to be computed.
--
Paul Prescod - Not encumbered by corporate consensus
Just how compassionate can a Republican get before he has to leave the
GOP and join Vegans for Global Justice? ... One moment, George W. Bush
is holding a get-to-know-you meeting with a bunch of gay Republicans.
The next he is holding forth on education or the environment ... It is
enough to make a red-blooded conservative choke on his spotted-owl
drumstick. - April 29th, Economist
David M. Cooke
2000-07-18 01:41:00 UTC
Permalink
On 17 Jul 2000 17:39:33 -0400, David M. Cooke <cookedm at physics.mcmaster.ca>
Post by David M. Cooke
Consider the proposal of having two classes, Matrixwise and Elementwise,
with methods to cast to each other. I don't know why
(a.E()*b.E()).M()*(c.E()*d.E()).M()
would be more preferable to
(a.*b)*(c.*d)
Well, it doesn't have to be as complicated as your first example. Assume
the default is Matrixwise, and we get rid of some ()'s by overriding
__getattr__, so that we can right
(a.E*b.E)*(c.E*d.E)
That's a good point. Can __getattr__ be made to work only on a selected
number of attributes? We could use it on T, H, I, C for transpose,
Hermitian transpose, inverse and conjugate. But if it works on all the
undefind members the error message may be too obscure. Any examples?
Yep. See code below.
BTW, you meant
(a.E*b.E).M*(c.E*d.E).M
for otherwise it is equivalent to (a.*b).*(c.*d).
Actually, I was thinking that elementwise multiplication would return
an object that does matrixwise multiplication (the idea being that
elementwise is a special case, just as .* is used for it instead of *
in Matlab).
Post by David M. Cooke
But what if we assume that if one operand has .E, the other does also!
Then we can write
(a.E*b)*(c.E*d)
This won't work. It would introduce many hard-to-trace bugs. Looking at
(a*b)*(c*d)
and you have to trace the program all the way down to figure out the
identities of a,b,c,d. Note that in concept the identities of the objects
do not change. We are changing their identities only as labels to help
picking different operators. I can foresee great confusion in practice with
this approach.
I realize this. Note that you have to trace the program to tell that
a,b,c,d are matrices anyway :-). A lot of this is removed by always
having an operation return a Matrixwise object.

Anyways, here's some code that implements what I was talking about. It
uses the UserArray and Matrix classes included with NumPy:

# matclass.py
from UserArray import UserArray
from Matrix import Matrix

class Matrixwise(Matrix):
def __init__(self, data, typecode=None):
if isinstance(data, UserArray):
UserArray.__init__(self, data.array, typecode=typecode)
else:
UserArray.__init__(self, data, typecode)

def __getattr__(self, name):
if name == 'E':
return Elementwise(self)
else:
try:
return self.__dict__[name]
except KeyError:
raise AttributeError, name

def __mul__(self, other):
if isinstance(other, Elementwise):
return Elementwise.__rmul__(self, other)
else:
return Matrix.__mul__(self, other)

class Elementwise(UserArray):
def __init__(self, data, typecode=None):
if isinstance(data, UserArray):
UserArray.__init__(self, data.array, typecode)
else:
UserArray.__init__(self, data, typecode)

def __mul__(self, other):
return Matrixwise(UserArray.__mul__(self, other).array)
Post by David M. Cooke
import matclass
a = matclass.Matrixwise([[2,3],[4,5]])
b = matclass.Matrixwise([[1,2],[3,4]])
a*b
matclass.Matrixwise([[11, 16],
[19, 28]])
Post by David M. Cooke
a.E*b.E
matclass.Matrixwise([[ 2, 6],
[12, 20]])
Post by David M. Cooke
a.E*b
matclass.Matrixwise([[ 2, 6],
[12, 20]])
Post by David M. Cooke
a*b.E
matclass.Matrixwise([[ 2, 6],
[12, 20]])

Obviously, this can be extended to include transpose, etc.
--
|>|\/|<
----------------------------------------------------------------------------
David M. Cooke
cookedm at mcmaster.ca
Huaiyu Zhu
2000-07-17 23:28:40 UTC
Permalink
On 17 Jul 2000 17:39:33 -0400, David M. Cooke <cookedm at physics.mcmaster.ca>
Post by David M. Cooke
Consider the proposal of having two classes, Matrixwise and Elementwise,
with methods to cast to each other. I don't know why
(a.E()*b.E()).M()*(c.E()*d.E()).M()
would be more preferable to
(a.*b)*(c.*d)
Well, it doesn't have to be as complicated as your first example. Assume
the default is Matrixwise, and we get rid of some ()'s by overriding
__getattr__, so that we can right
(a.E*b.E)*(c.E*d.E)
That's a good point. Can __getattr__ be made to work only on a selected
number of attributes? We could use it on T, H, I, C for transpose,
Hermitian transpose, inverse and conjugate. But if it works on all the
undefind members the error message may be too obscure. Any examples?

BTW, you meant

(a.E*b.E).M*(c.E*d.E).M

for otherwise it is equivalent to (a.*b).*(c.*d).
Post by David M. Cooke
But what if we assume that if one operand has .E, the other does also!
Then we can write
(a.E*b)*(c.E*d)
This won't work. It would introduce many hard-to-trace bugs. Looking at

(a*b)*(c*d)

and you have to trace the program all the way down to figure out the
identities of a,b,c,d. Note that in concept the identities of the objects
do not change. We are changing their identities only as labels to help
picking different operators. I can foresee great confusion in practice with
this approach.

Huaiyu
Kevin Jacobs
2000-07-17 19:56:11 UTC
Permalink
I've held back a few times from contributing my 0.02 cents, but here goes:

1) Python is a nifty language that allows its programmers to revel in
the richness of its dynamic object model.

2) Such models are always subject to abuse and can result in horrible and
unmaintainable hacks. These are frequently disguised as nifty syntactic
'features'.

3) Such attempts are bound to lead to terminal feeping-creaturism if not
carefully kept out of the core language.

Ok, we all know this. Most of us accept it. Lets move on. Thus far, I am
in line with the main-stream non-linear algebra proponents. However, I'd
love to see clean linear algebra implemented in Python. So the dilemma is
how to make the marriage work.

First, Huaiyu has done an outstanding job as not only an advocate, but
implementor, of such a hybrid system. This is always the first step.
People can complain about the lack of something from now until doomsday, but
without someone at bat nothing will ever happen. So, we have a critical
mass. Now what? Now he is asking for advice and guidance. And what do we
tell him? I'm sure that both (all) camps know their party lines at this
point, but it seems to me that little constructive has been done to work
around the issues. So, here I go. Brainstorming...

Silly idea 1:

Until add-on Python grammar modules are available, what about a PyAlgebra
evaluator module. For a precedent, see regular expressions. The
difference is that linear-algebra syntax can be made too Python-like for
some tastes.

e.g.:

import PyAlgebra

PyAlgebra.run(r'A = (A .* B)\C')
e = PyAlgebra(r"D = A'*B")
e.run() # or e()

Admittedly, its not perfect, nor optimally compact, but it is no longer
encumbered by having to support the full Python grammar and is free to
redefine as much as necessary.

Silly idea 2:

How about a "Linear-Algebra Python" to "Stock Python" translator. Parsing
Python isn't rocket science, so a fairly simple source-to-source
translator can hide all the new syntax and turn it into redistributable
stock but ugly Python code. No fuss or muss, assuming that the original
source is available when necessary.

Silly idea 3:

Lets continue arguing until everyone, both pro and con, gets irritated,
starts calling each other Nazis and gives up.

Feel free to chime in!

-Kevin
--
-----------> Kevin Jacobs <-----------|-------> (216) 778-8211 <--------
S.A.G.E. Project Technical Coordinator | Department of Epidemiology
& System Administrator | & Biostatistics
Internet E-mail: jacobs at darwin.cwru.edu | Case Western Reserve University
----------------------------------------------------------------------------
Gordon McMillan
2000-07-17 23:19:16 UTC
Permalink
Post by Kevin Jacobs
Until add-on Python grammar modules are available, what about a
PyAlgebra evaluator module. For a precedent, see regular expressions.
The difference is that linear-algebra syntax can be made too
Python-like for some tastes.
import PyAlgebra
PyAlgebra.run(r'A = (A .* B)\C')
e = PyAlgebra(r"D = A'*B")
e.run() # or e()
I proposed something very similar to Huaiyu the other day:

PyAlgebra.evaluate(r'(A .* B)\C', A=A, B=B, C=C)

I know Thomas Wouters did, too. I haven't seen a post reflecting these
suggestions.

In fact, looking at this thread in one of those tree-view newsreaders, it
becomes obvious that branches die when a proposal is made, but arguments
Post by Kevin Jacobs
Lets continue arguing until everyone, both pro and con, gets
irritated,
starts calling each other Nazis and gives up.
...has already won.

- Gordon
Huaiyu Zhu
2000-07-18 01:00:28 UTC
Permalink
Post by Gordon McMillan
PyAlgebra.evaluate(r'(A .* B)\C', A=A, B=B, C=C)
I know Thomas Wouters did, too. I haven't seen a post reflecting these
suggestions.
Good point. So let me say why I do not like this. (Doesn't mean it has to
die.) :-)

In a program where there are a lot of computations, you'll get either
something like a ritual on every line,

PyAlgebra.evaluate(r'(A .* B)\C', A=A, B=B, C=C)
PyAlgebra.evaluate(r'(A .* B)\C', A=A, B=B, C=C)
PyAlgebra.evaluate(r'(A .* B)\C', A=A, B=B, C=C)

for what could be

(A .* B)\C
(A .* B)\C
(A .* B)\C

or you get

PyAlgebra.evaluate(r'(A .* B)\C
(A .* B)\C
(A .* B)\C', A=A, B=B, C=C)

Everybody would rush for the latter. In the end what's inside the quote
would be a minilanguage with all the bells and wistles of python. This
would be just similar to patching the parser, with lesser results.
Post by Gordon McMillan
In fact, looking at this thread in one of those tree-view newsreaders, it
becomes obvious that branches die when a proposal is made, but arguments
Post by Kevin Jacobs
Lets continue arguing until everyone, both pro and con, gets
irritated,
starts calling each other Nazis and gives up.
...has already won.
You got it. I'm making a resolution of not going down that road from now on.

Huaiyu
Gordon McMillan
2000-07-18 03:11:34 UTC
Permalink
Post by Huaiyu Zhu
Post by Gordon McMillan
PyAlgebra.evaluate(r'(A .* B)\C', A=A, B=B, C=C)
Good point. So let me say why I do not like this. (Doesn't mean it has
to die.) :-)
In a program where there are a lot of computations, you'll get either
something like a ritual on every line,
PyAlgebra.evaluate(r'(A .* B)\C', A=A, B=B, C=C)
PyAlgebra.evaluate(r'(A .* B)\C', A=A, B=B, C=C)
PyAlgebra.evaluate(r'(A .* B)\C', A=A, B=B, C=C)
[snip]
Post by Huaiyu Zhu
or you get
PyAlgebra.evaluate(r'(A .* B)\C
(A .* B)\C
(A .* B)\C', A=A, B=B, C=C)
Everybody would rush for the latter. In the end what's inside the quote
would be a minilanguage with all the bells and wistles of python. This
would be just similar to patching the parser, with lesser results.
It would be exactly what SQL and regular expression users deal with every
day. I'm sure some ex-Perlers wish that regexes were "first class" objects,
but there's little noise about it; and none whatsoever from SQL users.

And you get the advantage that you can use the same syntax Matlab uses.

-Gordon
Kevin Jacobs
2000-07-18 02:01:58 UTC
Permalink
Post by Huaiyu Zhu
In a program where there are a lot of computations, you'll get either
something like a ritual on every line,
PyAlgebra.evaluate(r'(A .* B)\C', A=A, B=B, C=C)
PyAlgebra.evaluate(r'(A .* B)\C', A=A, B=B, C=C)
PyAlgebra.evaluate(r'(A .* B)\C', A=A, B=B, C=C)
What if it could be as simple as:

e(r'(A .* B)\C') # --> PyAlgebra.evaluate(r'(A .* B)\C', globals(), locals())
e(r'(A .* B)\C')
e(r'(A .* B)\C')

where A, B and C are bound to variables in the current namespace
automatically? Does this not go 95% of the way toward the ideal solution?
Post by Huaiyu Zhu
Everybody would rush for the latter. In the end what's inside the quote
would be a minilanguage with all the bells and wistles of python. This
would be just similar to patching the parser, with lesser results.
I disagree with your conclusion. Having worked with many algebra and
statistical languages, I know the road you are undertaking. It doesn't and
can't stop with one extra dot in the grammar. To do it right, you need the
ability to break more rules that are intrinsic to Python's core. e.g.,
consider changing the rules for '\' as above.

Another advantage to compromising and implementing a domain specific
mini-language is that it simplifies some very tough design issues that only
come up when working with the full Python grammar. Some of these syntactic
and semantic issues are very likely irreconcilable. In the end we could end
up with a any number of splinter languages with inferior support and narrow
audiences. Lets not forget we are a community of users with very diverse
goals, all trying make our lives easier by building better tools.

-Kevin
--
-----------> Kevin Jacobs <-----------|-------> (216) 778-8211 <--------
S.A.G.E. Project Technical Coordinator | Department of Epidemiology
& System Administrator | & Biostatistics
Internet E-mail: jacobs at darwin.cwru.edu | Case Western Reserve University
----------------------------------------------------------------------------
Tim Hochberg
2000-07-17 20:46:42 UTC
Permalink
"Kevin Jacobs" <jacobs at darwin.epbi.cwru.edu> wrote in message

[SNIP]
Post by Kevin Jacobs
Until add-on Python grammar modules are available, what about a PyAlgebra
evaluator module. For a precedent, see regular expressions. The
difference is that linear-algebra syntax can be made too Python-like for
some tastes.
import PyAlgebra
PyAlgebra.run(r'A = (A .* B)\C')
e = PyAlgebra(r"D = A'*B")
e.run() # or e()
Admittedly, its not perfect, nor optimally compact, but it is no longer
encumbered by having to support the full Python grammar and is free to
redefine as much as necessary.
Interestingly, an idea very similar to this was floated in the NumPy
community a couple years ago, but for entirely different reasons. The
motivation for this at the time was in order to support more efficient
matrix operations (eliminating intermediate results and such) and possibly
compiling the expression to native code. Digging through some of the NumPy
archives would probably reveal some interesting discussion of this possibly
not so silly idea.

-tim
Alex Martelli
2000-07-17 21:17:32 UTC
Permalink
"Kevin Jacobs" <jacobs at darwin.epbi.cwru.edu> wrote in message
news:8kvocr$5mq$1 at eeyore.INS.CWRU.Edu...
[snip]
Post by Kevin Jacobs
Until add-on Python grammar modules are available, what about a PyAlgebra
evaluator module. For a precedent, see regular expressions. The
difference is that linear-algebra syntax can be made too Python-like for
some tastes.
import PyAlgebra
PyAlgebra.run(r'A = (A .* B)\C')
e = PyAlgebra(r"D = A'*B")
e.run() # or e()
[snip]
Post by Kevin Jacobs
Feel free to chime in!
Seems to me we could do better (in terms of concision) along
the general idea of KJSI1. As PyAlgebra is basically just
parsing arbitrary syntax into (presumably) some suitable
Python function-like object, what it returns from parsing a
string could well have free variables just as well as bound
ones.

Free variables (to be bound at evaluation-time either by
name or positionally) might be the syntactic default, with
some special marker for parsing-time-bound variables. Or
maybe the difference need not be know at parse-time. And
I think this should be an expression-evaluator, only -- no
assignment -- dunno, it seems smoother to me... sort of:

from PyAlgebra import parse

expr = parse(r'(Left .* Right)\Divisor')
Result = expr(Left=X, Right=Y, Divisor=Z)

being equivalent to something like:

Result = X.dotProduct(Y).rightDiv(Z)


Is there anything that stands in the way of implementing this
sort of thing right now? Is it much of an improvement? Would
smoother integrated syntax sugar such as

Result = (X .* Y) \ Z

be perceived as hugely better than

Result = whatever(r'(X .* Y) \ Z')

???


I dunno -- I perceive no loss by having RE isolated in such
a way, rather than merged into the language's syntax as in
Perl; indeed, I personally perceive it as an advantage, for
all that RE's are something I use SO frequently. But then,
I'm not the target-audience for this sort of thing, I guess.
So I can hardly judge how that target-audience would react.


Alex
hzhu
2000-07-15 06:00:02 UTC
Permalink
The problem is that Python provides no way for an add-on module to
define new operators.
But that's not really an accident. There are languages that allow you to
define new operators. REBOL is the most flexible example. Python
emphasizes syntactic *simplicity*.
Well, I think there are two levels of syntactic simplicity:

1. Different structures: like the difference among identifiers, various
literals (number, list, dict, string), indentation delimited blocks,
function arguments.

2. Allowed members within a structure: like which function names are legal,
which operators are binary, which functions can be overloaded.

To keep the first kind of simplicity we need to restrict number of things
allowed. But to keep simplicity of the second kind we need to remove
arbitrary restrictions.

For example, I had included a file aux.py in the MatPy package which caused
a great deal of headache for Windows users. It turned out that Windows do
not allow file name to be aux because it's a device name. This kind of
unreadonable restrictions represent complexity, not simplicity.

Python already provides both function names and binary operators, so the
first level issue is not there. However, while it gives almost unlimited
supply of function names that can be overridden, there is only a handful of
binary operators which have deep rooted meanings and not enough for
overloading. This limit is largely arbitrary, and is therefore complexity.
Unfortunately, the current lack of appropriate notation makes these
problems very difficult to code clearly.
Every domain of computing would be enhanced with special notation. Text
processing, XML, COM, databases, Web programming etc.
Haven't we already talked this through? Text processing already got its
special syntax, even of the first level, which is quoted string. Within a
quoted string you could put in any text sequence. In this specific domain
it happens that only very limited number of binary operators are required,
and they are duly provided, like string + string, string % string, or string
* number. All the other things you mentioned could be built on top of this.
This domain is not even as mature as matrix computation - in many earlier
languages it was though that special syntax is needed for printing, formats
and regular expressions, which turned out to be just ordinary string
operations and functions, as python shows.

On the other hand, for proper matrix operation, there is not much need for
any additional first level structure, but there does exist a great need for
a larger supply of binary operators. What we are saying is that extending
the number of operators overridable by applications represents a much
smaller risk of incompatability than giving everyone a complete parser.
With the given operators, all the fields like scientific computation,
graphics, statistical analysis and artificial intelligence could also be
built on top of this.

Before you dismiss numerical computation as just another domain, why not try
a few packages and get a feeling of how large the domain is?


Huaiyu
Charles Boncelet
2000-07-17 20:03:20 UTC
Permalink
- Python is a general purpose language, and as such it can't
support special case syntax for Matrix/cgi/xml/db programming.
(special syntax has previously been requested for both cgi and
db programming).
Not trying to be argumentative, but why not? Why not allow an
additional, overloadable, operator?
- The proposal is to add a handful of operators that would only
have meaning in this one domain.
- the criteria for addition to the core is something that is
generally useful for a large segment of the community.
(and it's your job to convince us of it, not ours to
convince you that it isn't -- many more people would like
to see Stackless in the core, but that's not going to happen
anytime soon either...)
I'd love to see stackless and += added.
- that many problems can be reduced to matrix operations is
a non-argument, since the same is true of functional/
procedural/oo/predicate programming.
I agree, but there is a big userbase waiting for an alternative
to the $$ Matlab.
- There are allready ways of performing the required tasks in
Python, so there is no absolute need to add this to the core.
The same can be said of any simplification. There is no need for
it, but adding it may make life a lot easier.
- Other straight forward solutions has been proposed including
list comprehensions and Moshe Zadka's elementwise class
approach.
This I must object to. Linear algebra often involves big objects.
These operations want to call a carefully written C function. Any
time you use Python to loop over matrix objects, you are dead in
a big problem. As far as I understand (and I could be wrong)
neither list comprehensions nor the elementwise approach would be
able to call the underlying C functions without python loops.
On the other hand, alternative arguments based on analysis of functionality,
overall design, history of evolution and possible future extension, etc,
would carry some real persuasive weight.
If you really want to convince people, I would like to see examples of
how adding these operators would make working in other domains easier
(directly, not through translation through linear algebra).
This may be Hauiyu's argument, but it is not mine. I'll let the
people working in other domains to give the examples for their
domains. My argument is that there is a very large potential user
group Python could address if it were improved slightly (for that
domain.)
--
Charles Boncelet 302-831-8008
Dept of Electrical and Computer Engineering 302-831-4316 (fax)
University of Delaware boncelet at eecis.udel.edu
http://www.eecis.udel.edu/~boncelet/
Paul Prescod
2000-07-17 23:18:59 UTC
Permalink
Post by Charles Boncelet
...
This I must object to. Linear algebra often involves big objects.
These operations want to call a carefully written C function. Any
time you use Python to loop over matrix objects, you are dead in
a big problem. As far as I understand (and I could be wrong)
neither list comprehensions nor the elementwise approach would be
able to call the underlying C functions without python loops.
You are wrong about the .Element or .Element() approach. It is just a
syntactic approach, not a new computational model. .Element returns an
object that knows to use element-wise multiplication instead of
matrix-wise multiplcation. I thought it was a pretty elegant,
lightweight solution.
--
Paul Prescod - Not encumbered by corporate consensus
It's difficult to extract sense from strings, but they're the only
communication coin we can count on.
- http://www.cs.yale.edu/~perlis-alan/quotes.html
Bjorn Pettersen
2000-07-17 19:24:30 UTC
Permalink
Huaiyu Zhu wrote:

[snip]
As to the claim that additional operators for linear algebra is somehow
comparable to the special syntaxes/quirks of various programming languages,
no real argument has been presented so far. It's more like: If I don't care
and don't use such things, they must belong to a special domain and be
somehow comparable to some other things that I do know and dislike.
On the contrary. The argument is something like the following:

- Python is a general purpose language, and as such it can't
support special case syntax for Matrix/cgi/xml/db programming.
(special syntax has previously been requested for both cgi and
db programming).
- The proposal is to add a handful of operators that would only
have meaning in this one domain.
- the criteria for addition to the core is something that is
generally useful for a large segment of the community.
(and it's your job to convince us of it, not ours to
convince you that it isn't -- many more people would like
to see Stackless in the core, but that's not going to happen
anytime soon either...)
- that many problems can be reduced to matrix operations is
a non-argument, since the same is true of functional/
procedural/oo/predicate programming.
- There are allready ways of performing the required tasks in
Python, so there is no absolute need to add this to the core.
- Other straight forward solutions has been proposed including
list comprehensions and Moshe Zadka's elementwise class
approach.
On the other hand, alternative arguments based on analysis of functionality,
overall design, history of evolution and possible future extension, etc,
would carry some real persuasive weight.
If you really want to convince people, I would like to see examples of
how adding these operators would make working in other domains easier
(directly, not through translation through linear algebra).

-- bjorn
Paul Prescod
2000-07-17 19:54:57 UTC
Permalink
...
We can write a "MatrixPython compiler" (or maybe it would be a
pre-processor) that takes a file that uses Huaiyu's operators and spews out
"normal" Python code. The "compiler" would pass through all non-matrix
specific code and substitute matrix operators with function calls or
something.
Something like this has been proposed several times and is IMHO, the
best solution by far. Even if we agreed to add matrix ops. to Python,
experimentation would be needed in order to choose them.
--
Paul Prescod - Not encumbered by corporate consensus
It's difficult to extract sense from strings, but they're the only
communication coin we can count on.
- http://www.cs.yale.edu/~perlis-alan/quotes.html
Olivier Dagenais
2000-07-17 19:31:42 UTC
Permalink
I have been following this thread for a while, and I thought of something:

Maybe the solution isn't to modify Python (although the ability to overload
arbitrary operators might be cool), but to create a "solution" that
understands these new operators and can still run Python code.

We can write a "MatrixPython compiler" (or maybe it would be a
pre-processor) that takes a file that uses Huaiyu's operators and spews out
"normal" Python code. The "compiler" would pass through all non-matrix
specific code and substitute matrix operators with function calls or
something.

Just an idea...
--
----------------------------------------------------------------------
Olivier A. Dagenais - Carleton University - Computer Science III
Post by Bjorn Pettersen
[snip]
As to the claim that additional operators for linear algebra is somehow
comparable to the special syntaxes/quirks of various programming languages,
no real argument has been presented so far. It's more like: If I don't care
and don't use such things, they must belong to a special domain and be
somehow comparable to some other things that I do know and dislike.
- Python is a general purpose language, and as such it can't
support special case syntax for Matrix/cgi/xml/db programming.
(special syntax has previously been requested for both cgi and
db programming).
[snip]
Charles Boncelet
2000-07-17 19:44:19 UTC
Permalink
Perl, C++, Visual Basic, Java, and probably also Tcl are all more
popular than Python. Are you suggesting we should add their special
syntaxes/quirks just because a lot of people know them?
Not at all. Python has a clean, simple syntax and I don't want to
clutter
it the way Perl, for one, has. However, the Python community should
look at these other languages/domains and be willing to adopt the things

they have done right!

(The primary problem, as Huayiu keeps pointing out, is that linear
algebra
has two sets of operaters: those that work on elements and those that
work on whole matrices/vectors. The main need is to distinguish these
two for multiplication. If simple syntax for division--inversion--could

be defined, all the better.)

Why is it ordained that objects should have only two operations, "*" and
"+",
defined with simple operators? "+" on strings means something entirely

different than "+" on numbers. Why not add an "@" operator? With some
thought, I'd wager that we could define useful meanings for []@[],
{}@{},
etc. And if not and the only problem domain that needs/wants a "@"
operator
is linear algebra, then just how much clutter are we talking about? Then
make
it available only when "import Numeric" is done.

My argument is that linear algebra is a *big* problem domain. It should

not be dismissed as "just another problem."

Python could become the primary open source alternative to Matlab in
time
if a few changes were made: Incorporate numpy into the core distribution
(or
release a distribution with it already embedded), simplify the syntax
for
matrix operations, and improve the help facility at the interpreter.

Matlab, of course, comes with numerous toolboxes that are unavailable in

numpy. Early adoptors will have to write them--just as they do for
Matlab!
If you build it, they will come...

Python, because of its clean syntax, numpy, and existing
scientific/graphical tools
is better positioned than Perl, TCL, etc, to grab the linear algebra
users.

--
Charles Boncelet 302-831-8008
Dept of Electrical and Computer Engineering 302-831-4316 (fax)
University of Delaware boncelet at eecis.udel.edu
http://www.eecis.udel.edu/~boncelet/
Huaiyu Zhu
2000-07-18 00:47:07 UTC
Permalink
There are even techniques for making your
language work on the interpreter line. We can help with that.
Where is this? Is it also included in the references you mentioned? I don't
have time or expertise to examine these, but someone else might.

Huaiyu
Paul Prescod
2000-07-17 23:11:13 UTC
Permalink
Post by Charles Boncelet
....
Why is it ordained that objects should have only two operations, "*" and
"+",
defined with simple operators? "+" on strings means something entirely
Because 90% of Python programmers would not know what it means.

Look, if you took a poll of all programmers in the world, only a small
fraction use matrices very often. Therefore it is a niche. Most
programmers use numbers and strings every day, however.

Still, we all want you to succeed. We just disagree on the right
Post by Charles Boncelet
Python could become the primary open source alternative to Matlab in
time
if a few changes were made: Incorporate numpy into the core distribution
(or
release a distribution with it already embedded),
The process of creating a numpy enabled distribution is underway.
Post by Charles Boncelet
improve the help facility at the interpreter.
A module for that is under development.
Post by Charles Boncelet
simplify the syntax for matrix operations
You (matrix people) can do that by parsing your own Python-like syntax
and generating Python byte codes or Python source code. You don't need
any official blessing from Guido or anyone else. Several people have
written compilers for languages like Python IN Python and in other
languages. It is possible. There are even techniques for making your
language work on the interpreter line. We can help with that.
--
Paul Prescod - Not encumbered by corporate consensus
It's difficult to extract sense from strings, but they're the only
communication coin we can count on.
- http://www.cs.yale.edu/~perlis-alan/quotes.html
Huaiyu Zhu
2000-07-17 20:02:31 UTC
Permalink
Maybe you should consider how to scale back your syntactic request.
Perhaps a single keyword or symbol at the beginning of an expression
could make it element-wise or matrix-wise.
Well, that would be fine if it is workable, ie, when they don't appear in
the same expression.

Consider the proposal of having two classes, Matrixwise and Elementwise,
with methods to cast to each other. I don't know why

(a.E()*b.E()).M()*(c.E()*d.E()).M()

would be more preferable to

(a.*b)*(c.*d)

I chose python because most expressions I write I can visually parse at a
glance.

Please show an example of special xml syntax proposed that was rejected
because it was too special, and we'll see what kind of simplicity the
proposal represents.

Huaiyu
Bjorn Pettersen
2000-07-17 18:27:31 UTC
Permalink
(Huaiyu Zhu wrote a proposal for adding special linear algebra
operator to Python)
This proposal has been dismissed by many on this list (my
paraphrasing)
"because we don't want to pollute Python with new symbols/syntax
for just one problem domain." Some have dismissed linear algebra
as a small domain at that.
Let's get some facts (yes, I know we are not supposed to let facts
[severe case of non sequitur snipped]

Perl, C++, Visual Basic, Java, and probably also Tcl are all more
popular than Python. Are you suggesting we should add their special
syntaxes/quirks just because a lot of people know them?

hrmph!
-- bjorn
Paul Prescod
2000-07-17 19:12:02 UTC
Permalink
...
As to the claim that additional operators for linear algebra is somehow
comparable to the special syntaxes/quirks of various programming languages,
no real argument has been presented so far.
Okay, then, let me try.
It's more like: If I don't care
and don't use such things, they must belong to a special domain and be
somehow comparable to some other things that I do know and dislike.
Let me rephrase: "If MOST Python programmers don't care and don't use
such things, they must belong to a special domain." I think that's a
good operative definition of "domain specific". That's the crux of the
argument. Don't throw complex numbers back in my face because they
required *minimal new syntax*. There is already more "extra" syntax in
the language for matrices than for complex numbers.

I don't know why you have the impression that matrix operators have
been compared to anything that people dislike. Most people have compared
them to things that they *do* like, but must do through function syntax
because Python doesn't pander to my particular needs or your particular
needs, but rather those of most average programmers. I like XML
processing and I daresay there are more books sold on it than on
Matlab. But I've never asked for special, XML-specific syntax.

Maybe you should consider how to scale back your syntactic request.
Perhaps a single keyword or symbol at the beginning of an expression
could make it element-wise or matrix-wise.
--
Paul Prescod - Not encumbered by corporate consensus
It's difficult to extract sense from strings, but they're the only
communication coin we can count on.
- http://www.cs.yale.edu/~perlis-alan/quotes.html
Christopher Browne
2000-07-18 01:29:16 UTC
Permalink
Post by Paul Prescod
...
As to the claim that additional operators for linear algebra is
somehow comparable to the special syntaxes/quirks of various
programming languages, no real argument has been presented so far.
Okay, then, let me try.
It's more like: If I don't care
and don't use such things, they must belong to a special domain and be
somehow comparable to some other things that I do know and dislike.
Let me rephrase: "If MOST Python programmers don't care and don't use
such things, they must belong to a special domain." I think that's a
good operative definition of "domain specific". That's the crux of the
argument. Don't throw complex numbers back in my face because they
required *minimal new syntax*. There is already more "extra" syntax in
the language for matrices than for complex numbers.
I don't know why you have the impression that matrix operators have
been compared to anything that people dislike. Most people have compared
them to things that they *do* like, but must do through function syntax
because Python doesn't pander to my particular needs or your particular
needs, but rather those of most average programmers. I like XML
processing and I daresay there are more books sold on it than on
Matlab. But I've never asked for special, XML-specific syntax.
Maybe you should consider how to scale back your syntactic request.
Perhaps a single keyword or symbol at the beginning of an expression
could make it element-wise or matrix-wise.
Another approach would be to create some form of "macro rewriting"
system that would allow you to feed in expressions in some
_descriptive_ form that would then rewrite this into (possibly
optimized) Python that would execute this.

By far the best comparison I can think of is the Common Lisp "Series"
implementation, findable at <http://series.sourceforge.net/>.

CL Series provides a "language" in which you can represent sequential
descriptions; it is described thus:

"A series is a data structure much like a sequence, with similar
kinds of operations. The difference is that in many situations,
operations on series may be composed functionally and yet execute
iteratively, without the need to construct intermediate series
values explicitly. In this manner, series provide both the clarity
of a functional programming style and the efficiency of an iterative
programming style."

CL uses macro expansion to expand these into CL expressions, and this
expansion includes significant optimizations based on pipelining the
generation of series elements. You might compose several series
together, and the final result will be computed in an optimized
(perhaps optimal) manner.

The result is that you write your original code using a _descriptive_
series representation, and the system rewrites that into code that
_performs_ the series operations.

I would think the extension to what would be done in Python to be
"obvious;" the "Matrix Math" package would accept input in a modified
Python syntax that supports its matrix operators, and then rewrites
this to generate Python code that either:
a) Expresses it iteratively, in Python form, or
b) Expresses it using some compiled extensions that can make it Real
Fast.
--
cbbrowne at hex.net - <http://www.hex.net/~cbbrowne/>
Necessity is the mother of invention. Insanity is the mother of
straitjackets.
Paul Prescod
2000-07-14 13:43:48 UTC
Permalink
...
I personnaly consider that linear algebra is an extension of simple
arithmetic, almost on the same level as complex numbers (and usefull to
the same kind of people which could use complex numbers).
The fact that complex numbers are part of built-in python types and can
be manipulated using standard arithmetic operators plead for a similar
facility for linear algebra, imho.
That situation was entirely different. Complex numbers required very
little syntax and the object is built into Python. You are asking for a
lot of syntax but not proposing that your module go into Python. In
other words it is a lot of syntax that doesn't get used until you
install a third party module.
--
Paul Prescod - Not encumbered by corporate consensus
It's difficult to extract sense from strings, but they're the only
communication coin we can count on.
- http://www.cs.yale.edu/~perlis-alan/quotes.html
Paul Prescod
2000-07-15 10:45:29 UTC
Permalink
Post by hzhu
...
Python already provides both function names and binary operators, so the
first level issue is not there. However, while it gives almost unlimited
supply of function names that can be overridden, there is only a handful of
binary operators which have deep rooted meanings and not enough for
overloading. This limit is largely arbitrary, and is therefore complexity.
No, the set of operations is not arbitrary. They are the set of
operations that most people learn in high school and are basically the
same set in every other mainstream programming language in the universe.

By the way, if we are going to add a bunch of formally meaningless
operators to the language, are we going to add unary, binary, ternary
and quaternary ones?
Post by hzhu
Haven't we already talked this through? Text processing already got its
special syntax, even of the first level, which is quoted string.
You have got to be joking. Quoted strings are a "special syntax?" Then I
guess matrices got in their special syntax also:

[[5,4,3],[2,8,5],[9,7,1]]

In fact, it really is the case that there is special syntax in the
language for matrix processsing. But you are asking for a whole new
level.
Post by hzhu
Within a
quoted string you could put in any text sequence. In this specific domain
it happens that only very limited number of binary operators are required,
and they are duly provided, like string + string, string % string, or string
* number.
Not true at all. Perl provides a much, much richer set of operators for
working with strings. The most obvious binary operator Python is
"missing" is "does this string exist in that string". But text
processors learned to live with functional syntax (".find") and so can
matrix users. Python's core string operators are not really everythin
gyou need for "text processing" any more than they are everything you
need for matrix processing. Text processors just learned to survive with
functions and methods. Matrix processors will too. Moshe has some good
ideas in this vein. (.Element()*...
Post by hzhu
All the other things you mentioned could be built on top of this.
This domain is not even as mature as matrix computation - in many earlier
languages it was though that special syntax is needed for printing, formats
and regular expressions, which turned out to be just ordinary string
operations and functions, as python shows.
Perhaps that rather shows that matrix computation is not as mature as
string processing.

"In many earlier languages it ws thought that special syntax is needed
for element wise computation, which turned out to be just ordinary
matrix functions, as MatPy shows."

Anyhow, it isn't that Python showed that other string operators are not
important. It's that Python showed that moving those operations to a
library makes text processing *more verbose* but makes *Python simpler*.
The same holds for matrices.
Post by hzhu
On the other hand, for proper matrix operation, there is not much need for
any additional first level structure, but there does exist a great need for
a larger supply of binary operators. What we are saying is that extending
the number of operators overridable by applications represents a much
smaller risk of incompatability than giving everyone a complete parser.
A smaller risk of incompatibility but a larger risk of making Python
complex and reducing its long-term popularity.
Post by hzhu
With the given operators, all the fields like scientific computation,
graphics, statistical analysis and artificial intelligence could also be
built on top of this.
What if they want a completely different set of operators syntactically?
What if they want unary and ternary ones? Could I design the operators
with an eye to XML and then force you to make them fit matrix
processing?
Post by hzhu
Before you dismiss numerical computation as just another domain, why not try
a few packages and get a feeling of how large the domain is?
It doesn't matter how large the domain is. It is nevertheless just
another domain. Most people doing matrix computation with Python
acknowledge this and have been conservative in their requests on the
core. People have been doing numerical processing in Python for a long
time you know.
--
Paul Prescod - Not encumbered by corporate consensus
It's difficult to extract sense from strings, but they're the only
communication coin we can count on.
- http://www.cs.yale.edu/~perlis-alan/quotes.html
John Lull
2000-07-15 03:05:03 UTC
Permalink
Post by Paul Prescod
You are asking for a
lot of syntax but not proposing that your module go into Python. In
other words it is a lot of syntax that doesn't get used until you
install a third party module.
Well shoot, if that's the objection, then put it in the standard
distribution! :)

The problem is that Python provides no way for an add-on module to
define new operators. It's thus impossible to provide appropriate
notation *without* making it part of the language. If there were some
way to define, in the module, how to interpret specific new operators,
that should be adequate -- but that seems like a *far* more difficult
solution than what's needed here.

Unfortunately, the current lack of appropriate notation makes these
problems very difficult to code clearly.

Regards,
John
Paul Prescod
2000-07-15 04:00:14 UTC
Permalink
...
The problem is that Python provides no way for an add-on module to
define new operators.
But that's not really an accident. There are languages that allow you to
define new operators. REBOL is the most flexible example. Python
emphasizes syntactic *simplicity*.
Unfortunately, the current lack of appropriate notation makes these
problems very difficult to code clearly.
Every domain of computing would be enhanced with special notation. Text
processing, XML, COM, databases, Web programming etc.
--
Paul Prescod - Not encumbered by corporate consensus
It's difficult to extract sense from strings, but they're the only
communication coin we can count on.
- http://www.cs.yale.edu/~perlis-alan/quotes.html
Huaiyu Zhu
2000-07-15 06:06:24 UTC
Permalink
The problem is that Python provides no way for an add-on module to
define new operators.
But that's not really an accident. There are languages that allow you to
define new operators. REBOL is the most flexible example. Python
emphasizes syntactic *simplicity*.
Well, I think there are two levels of syntactic simplicity:

1. Different structures: like the difference among identifiers, various
literals (number, list, dict, string), indentation delimited blocks,
function arguments.

2. Allowed members within a structure: like which function names are legal,
which operators are binary, which functions can be overloaded.

To keep the first kind of simplicity we need to restrict number of things
allowed. But to keep simplicity of the second kind we need to remove
arbitrary restrictions.

For example, I had included a file aux.py in the MatPy package which caused
a great deal of headache for Windows users. It turned out that Windows do
not allow file name to be aux because it's a device name. This kind of
unreadonable restrictions represent complexity, not simplicity.

Python already provides both function names and binary operators, so the
first level issue is not there. However, while it gives almost unlimited
supply of function names that can be overridden, there is only a handful of
binary operators which have deep rooted meanings and not enough for
overloading. This limit is largely arbitrary, and is therefore complexity.
Unfortunately, the current lack of appropriate notation makes these
problems very difficult to code clearly.
Every domain of computing would be enhanced with special notation. Text
processing, XML, COM, databases, Web programming etc.
Haven't we already talked this through? Text processing already got its
special syntax, even of the first level, which is quoted string. Within a
quoted string you could put in any text sequence. In this specific domain
it happens that only very limited number of binary operators are required,
and they are duly provided, like string + string, string % string, or string
* number. All the other things you mentioned could be built on top of this.
This domain is not even as mature as matrix computation - in many earlier
languages it was though that special syntax is needed for printing, formats
and regular expressions, which turned out to be just ordinary string
operations and functions, as python shows.

On the other hand, for proper matrix operation, there is not much need for
any additional first level structure, but there does exist a great need for
a larger supply of binary operators. What we are saying is that extending
the number of operators overridable by applications represents a much
smaller risk of incompatability than giving everyone a complete parser.
With the given operators, all the fields like scientific computation,
graphics, statistical analysis and artificial intelligence could also be
built on top of this.

Before you dismiss numerical computation as just another domain, why not try
a few packages and get a feeling of how large the domain is?


Huaiyu
Bjorn Pettersen
2000-07-14 17:38:51 UTC
Permalink
On Thu, 13 Jul 2000 16:35:57 -0600, Bjorn Pettersen <bjorn at roguewave.com>
I fully understand your desire to make the syntax for your domain
specific notation as intuitive as possible. For people who don't know
matlab however, .+ et. al. have no pre-defined meaning. Since + has a
predefined meaning of addition, most people when overloading it will do
"additive" things with it, e.g. concatenating to sequences. Since .+
doesn't have a pre-defined meaning I'm afraid people will override it
with random semantics...
If you want to do matlab syntax, perhaps a better approach would be to
write your own expression parser?
Hmm, I see what you mean: If a certain syntax is not meaningful to all the
users, don't expose it to all of them lest they came up with random
incompatible usages. Sounds reasonable, but ...
Point 1. We _can_ assign a universal meaning to dot operators, as
"componentwise operators". For example
[1, 2] + [3, 4] # [1, 2, 3, 4]
[1, 2] .+ [3, 4] # [4, 6]
['a','b'] * 2 # ['a','b','a','b']
["a","b"] .* 2 # ['aa', 'bb']
{'a':1, 'b':1} .+ {'a':1, 'c':1} # {'a':2, 'b':1, 'c': 1}
'abc' .+ 'def' # exception: you must define string.__dot_add__
Well, this could actually be generally useful, but not with the .+
syntax (since the dot would interfer with methods on the sequence
object). If I had the ability to do elementwise computations, I would
want to do something like:

myList @foo() == map(lambda x:x.foo(), myList) == [x.foo(); for x in
myList]
[1,2] @+ 2 == map(lambda x:x+2, [1,2]) == [x+2; for x in
[1,2]]
[1,2] @+ [3,4] == ??

Reading "x@<something>" as distribute the <somthing> operation over the
elements in x. I think something like this has the potential to make
code more declarative (ie. shorter and easier to understand)...

-- bjorn
Huaiyu Zhu
2000-07-14 23:12:58 UTC
Permalink
On Fri, 14 Jul 2000 11:38:51 -0600, Bjorn Pettersen <bjorn at roguewave.com>
Well, this could actually be generally useful, but not with the .+
syntax (since the dot would interfer with methods on the sequence
object).
My impression from the python-dev list is that this is not the case. Some
say it is easy to distinguish

a. + b
a .+ b

Some say it is difficult. But the first is a syntax error anyway.

The only real danger is

3. + a
3 .+ a

But in this case pointwise operation does not make sense.

So I suppose the following rules would resolve all the ambiguities:

Dot binds with preceding number. Otherwise it binds with following
operator. Otherwise it is a member indicator. Otherwise it is syntax error.

Examples:

2.+b
a.+b <-- only this is new
a.b
a.3
--
Huaiyu Zhu hzhu at users.sourceforge.net
Matrix for Python Project http://MatPy.sourceforge.net
Huaiyu Zhu
2000-07-17 06:34:01 UTC
Permalink
On Sat, 15 Jul 2000 04:29:09 GMT, Huaiyu Zhu
That's the beauty of numerical computation, because all kinds of
applications, from animation on your screen to controlling satallite in
space to analysing molecular structures to calculating consumer preference
could all be expressed in the language of linear algebra. (Mathematicians
study spaces more abstract than linear spaces, but you wouldn't want to hear
about them before appreciating the usefulness of linear algebra.) For
example, all deterministic procedures are functions, and most functions we
see are simply points in an (infinite dimensional) space.
That's the beauty of procedural programming, because all kinds of
applications, from animation on your screen to controlling a satellite in
space to analyzing molecular structures to calculating consumer preference
could all be expressed in the language of procedural programming.
(Programmers study programming languages more abstract than functional
programming, but you wouldn't want to hear about them before appreciating
the usefulness of procedural programming.) For example, all deterministic
processes are expressible as Turing machines, and most turing machines
we see are simply expressible in procedural languages.
The first paragraph was a response to a particular argument. There are
problems that most people would not think of using linear algebra and ends
up with programs of hundreds of lines with slow for loops, but which could
be expressed in just a couple of math formula and, given the right syntax,
maps to less than a dozen lines of short clean code.

I'm not sure what the second paragraph is referring to. If it is telling
people that something that's written in assembly could be easily done in
procedural languages then it makes perfect sense, except for the reference
to Turing machines - if you use Turing machines as building blocks (as
opposed to computing engines), how many TMs do you expect to halt before the
program finishes?

not-that-this-is-on-topic-ly yr's

Huaiyu

PS. I'm sure someone would ask how you could complete the calculation of an
infinite dimensional vector. That is left as an exercise to the reader. :-)
Gordon McMillan
2000-07-18 03:01:25 UTC
Permalink
I don't see such arguments as any different from the claim that string
literals are sintactic sugar for the single domain of text processing
only (web and re and so on being subdomains). Since by such definition
text processing is a very large domain I do want string literals even
just for this only domain, even if it does not include everything.
Look at it this way: the implementation of Python is based on strings,
tuples, dicts and lists. So they came for free. The most exotic operators
Python currently has are probably the shift operators. That's really not a
good precedent for 8 new operators.

[bjorn suggest preprocessing...]
This could work if there is a hook so that
import mymodule
would automatically run
preprocessor < mymodule.mpy > mymodule.py
anywhere in the path. It should do this after examining the timestamp
just like current import does. Otherwise after a few surprises people
would keep .py instead of .mpy so it is just a helper for writing, but
not useful for extending or maintaining code,
Get Greg Stein's imputil.py from
http://www.lyra.org/greg/python/
(or wait for BeOpen's first release - it'll be in the std lib). It has a
hook for this.

-Gordon
Paul Prescod
2000-07-14 02:14:41 UTC
Permalink
....
Point 1. We _can_ assign a universal meaning to dot operators, as
"componentwise operators". For example
[1, 2] .+ [3, 4] # [4, 6]
[x+y; for x in [1,2], y in [3,4]]
["a","b"] .* 2 # ['aa', 'bb']
[2*x; for x in ['a','b']]
{'a':1, 'b':1} .+ {'a':1, 'c':1} # {'a':2, 'b':1, 'c': 1}
Addition isn't really defined for dictionaries.

Note that this feature is more general than a fixed list of operators:

[transpose(invert(x)); for x in ['a','b']]
Point 2. If users in completely disjoint domains override a certain type of
binary operators with incompatible meanings, is there great harm? Providing
a few operators for user adoptation might even prevent grotesque overriding
of more core operators. After all, there is almost endless supply of names
for classes, modules, function and so on, but there is almost no binary
operators free for adoption.
Most people prefer for Python code to be very visually consistent across
domains. Of course there is a tension with those who want to add
domain-specific features (as I have wanted in the past). Allowing new
grammars may be the best compromise.
--
Paul Prescod - Not encumbered by corporate consensus
Simplicity does not precede complexity, but follows it.
- http://www.cs.yale.edu/~perlis-alan/quotes.html
Huaiyu Zhu
2000-07-14 03:40:19 UTC
Permalink
Post by Paul Prescod
Point 1. We _can_ assign a universal meaning to dot operators, as
"componentwise operators". For example
[1, 2] .+ [3, 4] # [4, 6]
[x+y; for x in [1,2], y in [3,4]]
How about [x+y: x in [1,2], y in [3,4]]?

But this has nothing to do with matrices, because one of their main virtue
is that you do not need to consider the indices. How would you possibly
write A*B in this notation anyway? Just a random line from my code, like

s = tanh(A0*x+b0); y = A1*s + b1;

would take a dozen lines to do in the above way.
That might be true, but mathematicians have spent hundreds of years to
distill the concepts to a very small list of operators that are extremely
useful. Would you say that add(a,b) and mul(a,b) are more general type of
expressions than some special symbols like a+b and a*b? Writing in asembly
may be even more general than any high level language.

Learn some linear algebra and you'll find that you could do some incredible
things with it. It is not difficult (if the syntax is simple). For
starters, just download the current version of MatPy from
http://MatPy.sourceforge.net/, untar, and type make install, and see the
graphics flow across your screen.

Huaiyu
Paul Prescod
2000-07-14 18:09:41 UTC
Permalink
Post by Huaiyu Zhu
...
How about [x+y: x in [1,2], y in [3,4]]?
But this has nothing to do with matrices, because one of their main virtue
is that you do not need to consider the indices.
I know that it has nothing to do with matrices. My point was that there
is already a patch for Python to allow operations to be "elementwise"
and it is more general than doubling the number of operators in Python.
It allows any expression to be made elementwise (including function
calls and so forth).
--
Paul Prescod - Not encumbered by corporate consensus
It's difficult to extract sense from strings, but they're the only
communication coin we can count on.
- http://www.cs.yale.edu/~perlis-alan/quotes.html
John Lull
2000-07-14 13:29:02 UTC
Permalink
At the dawn of the third millenium (by the common reckoning), Gregory
Indeed, but it is the old choice between functional/operator notation...
For example, the second expression, b = (X'*X)\(X'*y), would be in
functional notation
something like b=rDiv(Mul(X.T(),X),Mul(X.T(),y))
This is ok, but imho far more error prone than operator notation,
because
- all linear algebra textbooks present expressions with operator
notation
- the operator notation is more natural to almost everybody when dealing
with arithmetic
Absolutely.
I personnaly consider that linear algebra is an extension of simple
arithmetic, almost on the same level as complex numbers (and usefull to
the same kind of people which could use complex numbers).
The fact that complex numbers are part of built-in python types and can
be manipulated using standard arithmetic operators plead for a similar
facility for linear algebra, imho.
Yes.

Regards,
John
Huaiyu Zhu
2000-07-15 22:25:08 UTC
Permalink
B*[sin(A*x+b).*(A*y)/3]/C
Is spelled
(Assume all matrices are originall matrix-wise)
# sin() already works element by element, unless you define
# sin(A) = A-(A^3/3!)+(A^5/5!)-....
B*(sin(A*x+b).Element()*(A*y).Element()/3)/C
Hmm, I can see one advantage of writing a.*b as

a.Element()*b.Element()

That is, instead of sinm(x) and sin(x) we can write

sin(x) and sin(x.Element())

But both functions still need to be implemented, and each function call
would involve a member lookup, an initializsation and a type comparison. So
overall it is perhaps disadvantageous.

BTW, the matrix sin function is equivalent to the Taylor expansion, but it
is calculated differently, using eigendecomposition.

Huaiyu
mfein
2000-07-13 12:40:03 UTC
Permalink
On Wed, 12 Jul 2000 19:32:32 GMT, hzhu at knowledgetrack.com (Huaiyu Zhu)
We are at a crucial juncture concerning introduction of new operators into
Python for matrix computation,
1. Experiences with Matlab show that different operators for matrix and
elementwise operators are very important
2. It is difficult to add .* and ./ as . is already a valid token. It seems
3. Gregory Lielens has just implemented a patch that could parse additional
a at b is equivalent to a*b, overloaded using __mmul__ and __rmmul__
He indicates similar constructions can be added easily.
We intend to add these operators together with Thomas Wouters's augmented
assignment operators (+=,*=, etc) to MatPy, but before that several
- Consistent with Matlab.
- Consistent with current MatPy.
- Convenient for matrix computations.
- Inconsistent with NumPy
- How to differentiate left and right div (matlab a\b and a/b)?
- Consistent with NumPy
- Can use a at b as inner product so that a at b works irrespective of whether a
and b are row or col operators.
- Inconsistent with current MatPy. Need great effort to switch.
- Using two symbol operator for matrix mul is cumbersome for long formulas.
- It kind of looks ugly.
3. Use a at b as matrix mul, and a*b as elementwise mul. This has most of the
pros and cons of choice 2, except
- Single symbol operators for matrix mul and element mul.
- Can't use a at b as inner product.
My own preference would be 'as consistent as possible with MATLAB,
with some caveats'-- this would mean option 1, with some thought about
changes in places where the current MATLAB syntax drops the ball
(IMO). I don't think MATLAB's inelegances should be preserved for the
sake of consistency. On the other hand, I think it's very important to
make the translation from MATLAB language to Python as automatic as
possible.

The main thing I'd think about in addition to standard MATLAB syntax
is a natural 'prolongation' syntax. In other words, contexts in which
the vector [1 2 3] is naturally expanded to [1 2 3;1 2 3;1 2 3;...].
This operation is part of one of the basic strategies in
vectorization-- prolongation, followed by some vectorized operation,
followed in turn by selection or contraction. Presently, MATLAB can do
this, but only in an idomatic and peculiar way. There are some dangers
in this route-- it encourages a tendency to syntactical trickiness--
the history of the APL language provides a case in point and a
warning.

One thing that MATLAB does correctly (again, IMO) is its relatively
relaxed attitude towards distinctions among scalars, 1x1 vectors &
matrices as well as among different kinds of nulls and NAN's. You can
test for these distinctions if you want to, but generally MATLAB will
just quietly do the right thing. There's a tendency to get wrapped up
in fine distinctions in cases where there's really no ambiguity about
what the programmer wants to do.

--
Matt Feinstein
mfein at aplcomm.jhuapl.edu
Organizational Department of Repeated
and Unnecessary Redundancy
Paul Prescod
2000-07-19 16:06:32 UTC
Permalink
...
On my soapbox: As you say, Python "isn't even close to the most popular
tool for its problem domain". And yet, the Python community refuses to
sully the language by adding things that might make it more popular (not
just more operators for numerical work, but stackless for palm pilots,
+=, ++, support for reloadable operators, typechecking, list
comprehensions, more elaborate iterators, to name a few.) There might
be arguments against each of these, but taken together it indicates an
unwillingness to change. Python is perfect as is, and we certainly
don't need to adopt the methods of the unwashed.
Python 2 will likely have += and list comprehensions. Typechecking is
scheduled for addition once the details are worked out.

If Python did not grow slowly and conservatively, I dare say that
neither you nor I would be using it today. It would be just another
overgrown language that caters to everyone's preferences.

Your paragraph implies that Python would be more popular if it attempted
to adopt everything that is in popular languages. I think that that is a
simplistic view of language evolution.
--
Paul Prescod - Not encumbered by corporate consensus
Just how compassionate can a Republican get before he has to leave the
GOP and join Vegans for Global Justice? ... One moment, George W. Bush
is holding a get-to-know-you meeting with a bunch of gay Republicans.
The next he is holding forth on education or the environment ... It is
enough to make a red-blooded conservative choke on his spotted-owl
drumstick. - April 29th, Economist
Thomas Wouters
2000-07-19 19:41:29 UTC
Permalink
I agree it should be selective about the features it adds. But
sometimes (no, *often*) I believe it is too selective and too slow
to change. "+=", for instance, should have been added years ago.
C had it in the 1970's; Perl had it in the 1980's. Python does
not yet have it. Stodginess like this puts off a lot of programmers.
Any idea why are += and friends still not implemented, after 5+ years of
Python development ? Guido and Tim both claim they wanted it years ago. Yet
noone came forward and implemented it, and Guido and Tim were both too busy
with more important things. And everyone else would have had to code up to
their standards, which is no small feat ;-)

Eventually it got coded. Michael Hudson wrote a simple proof of concept, and
that got me started on Python internals, which are really incredibly simple.
Using a single posting by Guido and a clarification from Tim, which Tim
claims hasn't changed significantly in the last year at least, it took me,
as a complete Python-internals newbie, a total of about 12 hours to rewrite
Michael's patch to one that did everything Guido wanted, and was only a
little buggy. And I'm not that special a programmer that noone else could've
done it, either.

So, what's the difference between Python and Perl ? Well, maybe the number
of programmers that also program C, and are comfortable with hacking a large
program like Python ? Or maybe Python programmers are generally more happy
with Python's limited featureset than Perl programmers are with Perl's ? :)
Probably a combination of both.

I discussed Perl/Python internals with our resident perl guru. I only heard
a small bit about Perl internals, but I heard enough to wonder how people
ever got new features added to Perl ;)
Python would be more popular. Witness Perl: it has adopted lots of
ideas from its userbase and has grown immensely as a result.
Why would people want another Perl ? There already is one. It already does
everything.
(IMHO, the main problem with Perl is not that it has adopted lots of
ideas, but that it didn't have a firm foundation to begin with. I.e.,
the core language is broken. Python's core language is much stronger
and Python would be improved with some additions.)
Probably, yes. But it wouldn't have a strong core if all those features
already were in there ;) Python has a strong core *because* Guido has always
been conservative in his changes. And in his coding style. And in a ton of
small things, that might not matter by themselves but all together they
damned well make the language what it is.

Which doesn't mean in the slightest bit that he won't change anything. He
just needs a good reason, and 'seems logical' can be a very good reason.
Which is why augmented assignment (+=), list comprehensions and range
literals are beign considered for 2.0: Guido literally asked for the last
one, himself.

(And to prove a point: he also asked for parallel iteration, literally, but
that patch isn't going in: he was out-voted ;) and instead it'll be a
builtin: zip)
--
Thomas Wouters <thomas at xs4all.net>

Hi! I'm a .signature virus! copy me into your .signature file to help me spread!
Andrew Kuchling
2000-07-22 13:41:17 UTC
Permalink
Post by Thomas Wouters
Any idea why are += and friends still not implemented, after 5+ years of
Python development ? Guido and Tim both claim they wanted it years ago. Yet
Probably because it posed some language design problems. When 'obj'
is some object, obj += 5 needs to call some method. What if you have
code like: 'a=1 ; a += obj'; is it an error? Do you call a separate
__r_addinplace__ method? Does 'a' transmogrify from an regular int to
an object just from a +=? Will users expect this?

--amk
Bjorn Pettersen
2000-07-19 17:22:51 UTC
Permalink
Post by Paul Prescod
...
On my soapbox: As you say, Python "isn't even close to the most popular
tool for its problem domain". And yet, the Python community refuses to
sully the language by adding things that might make it more popular (not
just more operators for numerical work, but stackless for palm pilots,
+=, ++, support for reloadable operators, typechecking, list
comprehensions, more elaborate iterators, to name a few.) There might
be arguments against each of these, but taken together it indicates an
unwillingness to change. Python is perfect as is, and we certainly
don't need to adopt the methods of the unwashed.
Python 2 will likely have += and list comprehensions. Typechecking is
scheduled for addition once the details are worked out.
And remember that many of these issues are _very_ hard once you dig
below the surface. E.g typechecking for languages like Python is a
_research_ area, and although I agree with the idea that it would be
nice to have, I really don't want it if we can't do it "right". (and the
Stackless semantics now has to be implemented for _three_ distinct
implementations of Python, not just CPython...)
Post by Paul Prescod
If Python did not grow slowly and conservatively, I dare say that
neither you nor I would be using it today. It would be just another
overgrown language that caters to everyone's preferences.
Your paragraph implies that Python would be more popular if it attempted
to adopt everything that is in popular languages. I think that that is a
simplistic view of language evolution.
I think Charles is probably correct that there might be a certain
"unwillingness to change" in the Python community. Sometimes, especially
when you think that the small little improvement that you'd like to add
would make life soo much easier for everyone, this can be quite
obnoxious. Most Python programmers is coming from other languages,
however, and it's not that we're adverse to change, it's just that we've
seen what happens when you start to add small 'neat' features (e.g. C++
and Perl, while great languages, do not have the syntactic or semantic
cleanliness of Python).

-- bjorn
Gregory Lielens
2000-07-14 09:31:55 UTC
Permalink
Post by John Lull
At the dawn of the third millenium (by the common reckoning),
hzhu at localhost.localdomain (Huaiyu Zhu) wrote (with possible
I think cleanness is one of the main virtue of python, but it is lacking in
numerical computation. To give an example of the difference it makes, I'll
quote from my original post asking for matrix in python (with corrections)
[in octave we write]
b = X\y # LMS solution of a linear equation y = X*b
b = (X'*X)\(X'*y) # or written out in more details
b = inv(X'*X)*(X'*y) # or in a less efficient form.
b = matrixmultiply(inverse(matrixmultiply(transpose(X), X)),
(matrixmultiply(transpose(X), y[:,NewAxis])))
b = rDiv(X, y)
if you simply had an appropriate rDiv() function. It's not nearly as
pretty as octave's notation, but it doesn't have to be nearly as
hideous as your example.
Indeed, but it is the old choice between functional/operator notation...
For example, the second expression, b = (X'*X)\(X'*y), would be in
functional notation
something like b=rDiv(Mul(X.T(),X),Mul(X.T(),y))
This is ok, but imho far more error prone than operator notation,
because
- all linear algebra textbooks present expressions with operator
notation
- the operator notation is more natural to almost everybody when dealing
with arithmetic

I personnaly consider that linear algebra is an extension of simple
arithmetic, almost on the same level as complex numbers (and usefull to
the same kind of people which could use complex numbers).
The fact that complex numbers are part of built-in python types and can
be manipulated using standard arithmetic operators plead for a similar
facility for linear algebra, imho.

But contrary to complex numbers, easy manipulation of matrices ideally
require more than the usual +,-,*,/, because of the lack of
commutativity (therefore the introduction of left and right divide) and
the usefullness of both elementwise and matrix operations.

Should something a "elementwise" complex multiplication
c=a*b=Complex(Real(a)*Real(b),Imag(a)*Imag(b)) (*)
have any usage, maybe the initial design of python would have included
two multiplication operators...


Greg.



(*) Please, never implement this horror!!!
Andrew Henshaw
2000-07-15 07:06:36 UTC
Permalink
...snip...
b = rDiv(X, y) >> if you simply had an appropriate rDiv() function.
..snip..
Indeed, but it is the old choice between functional/operator notation...
For example, the second expression, b = (X'*X)\(X'*y), would be in
functional notation
something like b=rDiv(Mul(X.T(),X),Mul(X.T(),y))
This is ok, but imho far more error prone than operator notation,
because
- all linear algebra textbooks present expressions with operator
notation
- the operator notation is more natural to almost everybody when dealing
with arithmetic
I wonder if some of these problems could be approached in a more general
manner. What if Python could support the definition of operators in the
same manner as functions? If that were the case then something like:

opr rDiv(X, y):

would define a new operator function that would work like:

b = X rDiv y

The big advantage would be that special purpose grammars could be easily
imported. The core language could be kept as simple as possible, but still
be extensible in a way that matters to a lot of people.

I suspect that whitespace would be required around these new 'operators',
although many people already do that with regular operators. Also, I'm not
sure how you'd specify an operator that wasn't valid as a function name, but
I can think of possibilities.
--
Andy Henshaw
Bjorn Pettersen
2000-07-16 17:24:41 UTC
Permalink
Post by Andrew Henshaw
...snip...
b = rDiv(X, y) >> if you simply had an appropriate rDiv() function.
..snip..
Indeed, but it is the old choice between functional/operator notation...
For example, the second expression, b = (X'*X)\(X'*y), would be in
functional notation
something like b=rDiv(Mul(X.T(),X),Mul(X.T(),y))
This is ok, but imho far more error prone than operator notation,
because
- all linear algebra textbooks present expressions with operator
notation
- the operator notation is more natural to almost everybody when dealing
with arithmetic
I wonder if some of these problems could be approached in a more general
manner. What if Python could support the definition of operators in the
b = X rDiv y
The big advantage would be that special purpose grammars could be easily
imported. The core language could be kept as simple as possible, but still
be extensible in a way that matters to a lot of people.
I suspect that whitespace would be required around these new 'operators',
although many people already do that with regular operators. Also, I'm not
sure how you'd specify an operator that wasn't valid as a function name, but
I can think of possibilities.
Prolog does this (you'll of course have to specify the precedence of the
operator also, and to solve the current perceived problem probably their
associativity too...)

It's something that works relatively well in Prolog, but then Prolog doesn't
have namespaces etc... If you think you can solve those problems, I would
encourage you to try to implement it and try your solution in a couple of
different domains (matrix-, db-, xml-, string- processing?) It could be useful,
and if it is, then we can discuss whether it should be added to the core.

Thankfully, Python doesn't add new ideas to the core before they have been tried
out sufficiently first. C++ did, and has ended up working around design problems
(how many people really know how Koenig lookup works...?)

python-the-lean-mean-fighting-machine-with-batteries-included'ly y'rs
-- bjorn
John Lull
2000-07-14 02:33:03 UTC
Permalink
At the dawn of the third millenium (by the common reckoning), Bjorn
It seems like you're trying to create a special purpose language here.
Ie. I don't see it as general enough to be worth putting into the core
unless you can come up with other use cases... Personally, I would much
prefer the ability to overload the relational operators (individually,
not through __cmp__).
I'd like to disagree here. Matrices & linear algebra are fundamental
tools in an extremely broad set of domains. Unfortunately, most
programming languages don't seem to recognize that.

Providing appropriate operators in the core is, IMO, as appropriate as
providing complex numbers. Providing an easy way to effectively add
them to the core when you install an appropriate add-on package is a
reasonable alternative. Their absence leads to really hard-to-read
code, and to me is a significant downside to Python.

Regards,
John
Bjorn Pettersen
2000-07-14 17:47:23 UTC
Permalink
Post by John Lull
At the dawn of the third millenium (by the common reckoning), Bjorn
It seems like you're trying to create a special purpose language here.
Ie. I don't see it as general enough to be worth putting into the core
unless you can come up with other use cases... Personally, I would much
prefer the ability to overload the relational operators (individually,
not through __cmp__).
I'd like to disagree here. Matrices & linear algebra are fundamental
tools in an extremely broad set of domains. Unfortunately, most
programming languages don't seem to recognize that.
Providing appropriate operators in the core is, IMO, as appropriate as
providing complex numbers. Providing an easy way to effectively add
them to the core when you install an appropriate add-on package is a
reasonable alternative. Their absence leads to really hard-to-read
code, and to me is a significant downside to Python.
That is the problem with a general purpose language. It can't
conveniently spell the common syntax for all possible special domains.
I'd be very hesitant to make Python's core more complex just to make it
easier to use in _one_ problem domain. (Note: I'm not saying I would be
against a proposal that would be more generally useful... but you'll
have to prove that first)

As a programmer that has never used complex numbers for anything useful,
I'd much rather remove them from Python than add special linear algebra
syntax <wink>

-- bjorn
Moshe Zadka
2000-07-15 07:28:00 UTC
Permalink
That's the beauty of numerical computation, because all kinds of
applications, from animation on your screen to controlling satallite in
space to analysing molecular structures to calculating consumer preference
could all be expressed in the language of linear algebra. (Mathematicians
study spaces more abstract than linear spaces, but you wouldn't want to hear
about them before appreciating the usefulness of linear algebra.) For
example, all deterministic procedures are functions, and most functions we
see are simply points in an (infinite dimensional) space.
So? You refuse to understand, so let me iterate this once more -- less
people are doing numeric computation than web programming. Python does
*not* cater to specific domain in the core, no matter the popularity.
Linear algebra is great, but I don't want Python to support it by growing
a mess of symbols only it would use.

Now that we have that clear, let's get something useful done. Here's how
to solve the element-wise/matrix-wise problem neatly:

define two classes:

class ElementWiseMatrix:

pass # all numeric operations are done element-wise

def Matrix(self):
return MatrixWiseMatrix(self.data)

class MatrixWiseMatrix:

pass # all numeric operations are done matrix-wise

def Element(self):
return ElementWiseMatrix(self.data)

(operations between the two are an error)

Now, your

B*[sin(A*x+b).*(A*y)/3]/C

Is spelled

(Assume all matrices are originall matrix-wise)

# sin() already works element by element, unless you define
# sin(A) = A-(A^3/3!)+(A^5/5!)-....
B*(sin(A*x+b).Element()*(A*y).Element()/3)/C

--
Moshe Zadka <moshez at math.huji.ac.il>
There is no GOD but Python, and HTTP is its prophet.
http://advogato.org/person/moshez
Paul Prescod
2000-07-19 17:23:20 UTC
Permalink
...
Well, I was making a broken assumption about the meaning of
multiple comprehension indices: namely, that
[(i,j) for i in [1,2], j in [1,2]]
would evaluate to [(1,1), (2,2)] rather than [(1,1), (1,2), (2,1), (2,2)].
If it's supposed to go the other way, then some of my other
assumptions stop working. :-)
For exactly this reason I have proposed the following syntax:

[for i in [1,2]: for j in [1,2]: i, j ]

Which I think is more clear that it is not parallel.
So [f(x) for x in collection] would turn into something like
indices = collection.valid_indices()
result = collection.clone()
result[index] = f(collection[index])
...easier to just require the "collection" type to have an append
operator...
...
With more than one collection being iterated over, as in
[blah blah blah for x in xs, y in ys], the simplest thing
would be to use the first collection mentioned as template
and source of valid indices.
It's somewhat arbitrary but maybe it would work.
--
Paul Prescod - Not encumbered by corporate consensus
Just how compassionate can a Republican get before he has to leave the
GOP and join Vegans for Global Justice? ... One moment, George W. Bush
is holding a get-to-know-you meeting with a bunch of gay Republicans.
The next he is holding forth on education or the environment ... It is
enough to make a red-blooded conservative choke on his spotted-owl
drumstick. - April 29th, Economist
Charles Boncelet
2000-07-17 17:24:45 UTC
Permalink
(Huaiyu Zhu wrote a proposal for adding special linear algebra operator to
Python)

This proposal has been dismissed by many on this list (my paraphrasing)
"because we don't want to pollute Python with new symbols/syntax
for just one problem domain." Some have dismissed linear algebra
as a small domain at that.

Let's get some facts (yes, I know we are not supposed to let facts
interfere with our arguments on usenet):

1. Amazon.com lists 117 book matches for "python", but most of these
are for the snake or Monte. A quick perusal indicates there are 13 books
currently available and another 7 on order for language. Amazon lists
179 matches for "matlab", of which 81 are currently available and 61 on order.

Verdict: there are approximately 7 times as many Matlab books as
Python books.

2. Alta Vista finds 4492 pages for "python language", and 489540 for
"matlab". Even the one word "python" search only finds 412030 pages
(which of course includes many references to the comedy troupe
and the snake).

Alltheweb finds 53378 for "python language" and 53368 for "python
program"; it finds 156525 for "matlab".

Verdict: There are 3-100 times as many web pages mentioning "matlab"
as "python language" or "python program".

3. At my university (which I assume is pretty typical), all the engineering
students use Matlab at some point in their studies. Most (perhaps all)
of the math, physics, and chemistry students use Matlab at some point.
Many of our ECE graduate students use Matlab extensively in doing
their dissertation research.

AFAIK, I am the only person using python for anything. (I am sure
there are others, but I don't know of anyone and there are no courses using
python.)

Vendict: at my university, Matlab is tens to hundreds of times more
popular than python.

Conclusion: please don't dismiss linear algebra as "just another
problem domain". If python incorporated numpy into its core
and added some support for linear algebra syntax, it could easily
double, triple, or more in popularity.

Remember, these people spend real money on Matlab. Even the
student edition is about $100.

Now to the specifics of the proposal: I'd like to see "@" for matrix
mulitplication and "*" for element-wise multiplication. This preserves
compatibility with numpy, although breaks it with the MatPy package.
It is more important, IMHO, to preserve compatibility with the existing
python numerical facilities than with Matlab. Any user switching over
will have to learn a lot of new things anyway. Distinguishing @ and *
should be easy enough.

Charlie Boncelet

--
Charles Boncelet 302-831-8008
Dept of Electrical and Computer Engineering 302-831-4316 (fax)
University of Delaware boncelet at eecis.udel.edu
http://www.eecis.udel.edu/~boncelet/


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20000717/c522aa04/attachment.html>
Eric Lorenzo
2000-07-17 21:27:10 UTC
Permalink
Let's get some facts (yes, I know we are not supposed to let facts
[Relative popularity measurements deleted.]

These metrics are meaningless. You're comparing the popularity of
Matlab, the most popular tool for its problem domain (numerical
computing), to Python, which (unfortunately) isn't even close to the
most popular tool for its problem domain (general-purpose scripting
and programming). I'd imagine that establishing that there is a high
level of interest in this domain would be a prerequisite for
convincing anyone to add the desired features. But your metrics don't
tell us anything at all about the relative level of interest in the
numerical computing domain, and are thus useless for your apparent
purpose. Compare Python+Perl+Tcl+Java+C+C++ to Matlab+(Any other
languages targeted towards the numerical computing problem domain.
Mathematica?), and you might have something half-worthwhile.

Eric
Huaiyu Zhu
2000-07-17 18:58:34 UTC
Permalink
Let me repeat a challenge I made to Huaiyu Zhu. If the only difference
between Matlab and Python is the syntax, then let's you and I make a
Matlab syntax for Python and sell it at half of Matlab's price. We could
make millions on a month's work!
Now look at the total number of users of matlab/octave, and ask: Is python
really so inferior that most of them wouldn't switch to python?
I have no idea. If the primary difference between expensive matrix
packages and Python is syntax, perhaps you and I should incorporate and
exploit that market inefficiency. :)
The market is efficient. Matlab does worth that much (or even more). It
does take that much human labor to get to that stage, so sadly we can't get
rich by following them. On the other hand, open source may beat them
easily, as long as

1. we are using a better language which has more potential
2. users have incentive to contribute because it's already useful
3. there's no big hurdle beyond what's already in Numerical Recipe
My strong feeling is that people don't just use Matlab for the syntax.
And the popularity of Matlab books is probably not proportional to the
popularity of Matlab. University students are forced to buy those books.
You feeling may be wrong, even if it is strong. Many students use Matlab
despite their adviser's urge to use other more "conventional" software - at
least in the earlier years. For all I know, the disproportionality is the
other way round - most matlab users never own a matlab book. (A personal
note which may not worth much: I've used matlab for ten years and don't own
a matlab book. I've used python for half a year and proudly own three
python books.)

Huaiyu
Paul Magwene
2000-07-15 17:17:37 UTC
Permalink
That's the beauty of numerical computation, because all kinds of
applications, from animation on your screen to controlling satallite in
space to analysing molecular structures to calculating consumer preference
could all be expressed in the language of linear algebra
Speaking as someone who has been analysing molecular structures for the
last 7 years and animating them for about 5 of those years, I can say
the lack of dot-wise elements, both in C++ and in Python, has not been
a great concern.
Andrew
dalke at acm.org
I agree with Andrew. The bread and butter of my programming activities
involve numerical computation, and in particular linear algebra. But I
DO NOT want to see python polluted with all sorts of special syntax just
for that purpose.
--
Paul Magwene
paul.magwene at yale.edu
Kirill Simonov
2000-07-14 06:16:49 UTC
Permalink
Doesn't this look like the other p language or lisp? Well, my original post
missed two parentheses and two matrixmultiply's and nobody even noticed it.
If one cannot even write X\y in one line, think about how to write a typical
formula like
B = inv(A) - A\U/(C+V/A*U)*V/A
You can use '%' for right division.
It has the same precedence as '/', and remainder operator
doesn't occur too often in linear algebra.

And don't forget about '~', '|', '^', and '&'.

--
Kirill
Huaiyu Zhu
2000-07-13 21:46:56 UTC
Permalink
2. It is difficult to add .* and ./ as . is already a valid token.
Irrespective of the rest of this post, this is not true. "**" is a
valid token depsite "*" being one, etc.
Oh, this is good news. I did not quite believe that either, but after being
told of this several times ...

Any way, if the dot can be used then we definitely would use it, which sort
of determines the choice to be matlab compatibility. The only ambiguity
would be expressions like 3./a, which should be 3. / a, as long as we let
the parser bind dot closer to the left whenever possible. Existing code
will not break since the new operator exists entirely within the area of
current "invalid syntax".

What is still left out is a\b, though.

Huaiyu
Moshe Zadka
2000-07-15 07:15:38 UTC
Permalink
How would you write this in list compresension (in less than 10 lines)?
B*(sin(A*x+b).*(A*y)/3)/C
B*[sin(a)*b/3; for a,b in transpose([A*x+b, A*y])]/C

--
Moshe Zadka <moshez at math.huji.ac.il>
There is no GOD but Python, and HTTP is its prophet.
http://advogato.org/person/moshez
Huaiyu Zhu
2000-07-15 20:13:20 UTC
Permalink
On Sat, 15 Jul 2000 10:15:38 +0300 (IDT), Moshe Zadka
Post by Moshe Zadka
How would you write this in list compresension (in less than 10 lines)?
B*(sin(A*x+b).*(A*y)/3)/C
B*[sin(a)*b/3; for a,b in transpose([A*x+b, A*y])]/C
Questions:

Presumably the [ ... ] is a double list. What does B*[...]/C mean? Maybe
you need a cast?

The x, b and y are matrices, so presumably 'for a, b in' contains loops
around all the indices?

Perhaps you meant 'for a, c in'? Do these two b's live in the same scope?

What would the error message look like for such errors?

How do you write something like B*(A(a.*b).*c).*d?

Huaiyu
Bjorn Pettersen
2000-07-13 19:18:37 UTC
Permalink
We are at a crucial juncture concerning introduction of new operators into
Python for matrix computation,
1. Experiences with Matlab show that different operators for matrix and
elementwise operators are very important
2. It is difficult to add .* and ./ as . is already a valid token. It seems
3. Gregory Lielens has just implemented a patch that could parse additional
a at b is equivalent to a*b, overloaded using __mmul__ and __rmmul__
He indicates similar constructions can be added easily.
It seems like you're trying to create a special purpose language here.
Ie. I don't see it as general enough to be worth putting into the core
unless you can come up with other use cases... Personally, I would much
prefer the ability to overload the relational operators (individually,
not through __cmp__).

-- bjorn
Huaiyu Zhu
2000-07-14 22:45:59 UTC
Permalink
John,

Thanks for your clear description of the importance of matrix in another
post. Are you aware of MatPy? (http://MatPy.sourceforge.net/)
Post by John Lull
[in octave we write]
b = X\y # LMS solution of a linear equation y = X*b
b = (X'*X)\(X'*y) # or written out in more details
b = inv(X'*X)*(X'*y) # or in a less efficient form.
b = matrixmultiply(inverse(matrixmultiply(transpose(X), X)),
(matrixmultiply(transpose(X), y[:,NewAxis])))
b = rDiv(X, y)
if you simply had an appropriate rDiv() function. It's not nearly as
pretty as octave's notation, but it doesn't have to be nearly as
hideous as your example.
Well, you are right. That quote was from a post written before MatPy
started, using NumPy which has a different idea of vectors tham matrices.
Now in MatPy these three are

solve(X,y)
solve(X.H()*X, X.H()*y)
(X.H()*X).I() * (X.H()*y)

This is almost as good or even better.

So why do we still need additional operators? Because we are now using * as
matrixmultiply, so there need to be another operator for elementwise *.

Huaiyu
Andrew Dalke
2000-07-15 07:41:01 UTC
Permalink
but outside of this thread, we've seen no great outcry of python
users bemoaning the lack of cryptic operators. changing the language
for this specific domain is not a good idea. putting in new operators
because they might be usefully overloaded for other specific domains
is little better.
That's the beauty of numerical computation, because all kinds of
applications, from animation on your screen to controlling satallite in
space to analysing molecular structures to calculating consumer preference
could all be expressed in the language of linear algebra
Speaking as someone who has been analysing molecular structures for the
last 7 years and animating them for about 5 of those years, I can say
the lack of dot-wise elements, both in C++ and in Python, has not been
a great concern.

Andrew
dalke at acm.org
Garry Hodgson
2000-07-14 20:24:16 UTC
Permalink
Point 1. We _can_ assign a universal meaning to dot operators, as
"componentwise operators". For example
[1, 2] + [3, 4] # [1, 2, 3, 4]
[1, 2] .+ [3, 4] # [4, 6]
['a','b'] * 2 # ['a','b','a','b']
["a","b"] .* 2 # ['aa', 'bb']
{'a':1, 'b':1} .+ {'a':1, 'c':1} # {'a':2, 'b':1, 'c': 1}
'abc' .+ 'def' # exception: you must define string.__dot_add__
This could be useful in all sorts of situations. Of course people can still
override it with incompatible meanings at their own discretion, just as they
could do to anything else.
Point 2. If users in completely disjoint domains override a certain type of
binary operators with incompatible meanings, is there great harm? Providing
a few operators for user adoptation might even prevent grotesque overriding
of more core operators. After all, there is almost endless supply of names
for classes, modules, function and so on, but there is almost no binary
operators free for adoption.
but outside of this thread, we've seen no great outcry of python
users bemoaning the lack of cryptic operators. changing the language
for this specific domain is not a good idea. putting in new operators
because they might be usefully overloaded for other specific domains
is little better.
--
Garry Hodgson Every night
garry at sage.att.com a child is born
Software Innovation Services is a Holy Night.
AT&T Labs - Sophia Lyon Fahs
Huaiyu Zhu
2000-07-14 00:31:58 UTC
Permalink
On Thu, 13 Jul 2000 16:35:57 -0600, Bjorn Pettersen <bjorn at roguewave.com>
I fully understand your desire to make the syntax for your domain
specific notation as intuitive as possible. For people who don't know
matlab however, .+ et. al. have no pre-defined meaning. Since + has a
predefined meaning of addition, most people when overloading it will do
"additive" things with it, e.g. concatenating to sequences. Since .+
doesn't have a pre-defined meaning I'm afraid people will override it
with random semantics...
If you want to do matlab syntax, perhaps a better approach would be to
write your own expression parser?
Hmm, I see what you mean: If a certain syntax is not meaningful to all the
users, don't expose it to all of them lest they came up with random
incompatible usages. Sounds reasonable, but ...

Point 1. We _can_ assign a universal meaning to dot operators, as
"componentwise operators". For example

[1, 2] + [3, 4] # [1, 2, 3, 4]
[1, 2] .+ [3, 4] # [4, 6]
['a','b'] * 2 # ['a','b','a','b']
["a","b"] .* 2 # ['aa', 'bb']
{'a':1, 'b':1} .+ {'a':1, 'c':1} # {'a':2, 'b':1, 'c': 1}
'abc' .+ 'def' # exception: you must define string.__dot_add__

This could be useful in all sorts of situations. Of course people can still
override it with incompatible meanings at their own discretion, just as they
could do to anything else.


Point 2. If users in completely disjoint domains override a certain type of
binary operators with incompatible meanings, is there great harm? Providing
a few operators for user adoptation might even prevent grotesque overriding
of more core operators. After all, there is almost endless supply of names
for classes, modules, function and so on, but there is almost no binary
operators free for adoption.


Point 3. A special parser could work, (and if the patch under discussion is
not accepted we'll just keep it around for use with matrix computation), as
long as it is made quite orthogonal to other parts of the language. This
way people using it will not be left behind other developments of the
language. However, I still think a unified parser with overridable
operators present a smaller risk of fragmentation.

Huaiyu
Bjorn Pettersen
2000-07-13 22:35:57 UTC
Permalink
On Thu, 13 Jul 2000 13:18:37 -0600, Bjorn Pettersen <bjorn at roguewave.com>
It seems like you're trying to create a special purpose language here.
Ie. I don't see it as general enough to be worth putting into the core
unless you can come up with other use cases... Personally, I would much
prefer the ability to overload the relational operators (individually,
not through __cmp__).
This is not a call for a special language for matrix only. But we do need
enough binary operators to override with. The additional operators might be
useful at other places as well.
In matlab the following operations are all different from each other
a+b a.+b
a-b a.-b
a*b a.*b
a/b a./b
a\b a.\b
a^b a.^b
What python operators can we override for them all? Just one additional
symbol for so many new binary operators is a good bargain, IMO.
[snip]

I fully understand your desire to make the syntax for your domain
specific notation as intuitive as possible. For people who don't know
matlab however, .+ et. al. have no pre-defined meaning. Since + has a
predefined meaning of addition, most people when overloading it will do
"additive" things with it, e.g. concatenating to sequences. Since .+
doesn't have a pre-defined meaning I'm afraid people will override it
with random semantics...

If you want to do matlab syntax, perhaps a better approach would be to
write your own expression parser?

-- bjorn
hzhu
2000-07-17 06:10:01 UTC
Permalink
How would you write this in list compresension (in less than 10 lines)?
B*(sin(A*x+b).*(A*y)/3)/C
Note that * is matrix multiplication and .* is elementwise. Note that C is
a matrix so the / is matrixwise. If you want to write everything as for
loops it takes at least 30 lines, without any decent error analysis.
B*[p*q/3 for p in A*x+b, q in A*y]/C
Someone else had already given a similar answer. But more work is needed
for such things to work:

The x, b and y could be matrices, so p and q need to be double loops.

The [ ... ] need to be a double lists. Is list comprehension defined for
this?

B*[..]/C would not work without a cast from double list to matrix.

For all these errors, what would the error messages look like? Do they
involve the dummy indices p and q? A previous answer also reused the name b
for the dummy variable, which would make the error even more obscure.

Besides, the main point of using matrix is to be free from specifying loops
over indices with dummy names. Compare this double loop with extra syntax
with a single operator .* and you may wonder why this is considered at all.

Since this is going way off original topic I'll stop here. I admit that I'm
at fault to a large extent.

As to the question of what's the precedence of the proposed .* like
operators, they are the same as their ordinary counterparts, because they
become identical when the operands are numbers or 1x1 matrices.


Huaiyu
Bjorn Pettersen
2000-07-19 16:50:15 UTC
Permalink
[I said:]
[snip]
Post by Paul Prescod
Today, the list comprehension syntax is syntactic sugar for
a=[]
for j in secondloop: ...
a.append( i, j )
I don't see any easy way to guess what type you want as "output" so it
Matrix( [...] )
I would be curious about ideas for allowing the output object to be
specified or inferred. What would the protocol be?
Well, I was making a broken assumption about the meaning of
multiple comprehension indices: namely, that
[(i,j) for i in [1,2], j in [1,2]]
would evaluate to [(1,1), (2,2)] rather than [(1,1), (1,2), (2,1), (2,2)].
If it's supposed to go the other way, then some of my other
assumptions stop working. :-)
Personally, I think the paralell iteration would be easier to explain
(which is why I would prefer that semantics to list-comprehensions with
cartesian product and zip for paralell iteration).
However: I had been thinking along the following lines.
[expr for var in val] should produce something of the same
type as val, with the property that result[i] == expr(val[i])
for each legal index i. (Or something of the sort.)
That would indeed be nice, and perhaps even doable for single
iteration...

[snip]
With more than one collection being iterated over, as in
[blah blah blah for x in xs, y in ys], the simplest thing
would be to use the first collection mentioned as template
and source of valid indices. (This is the thing that fails
totally if we're doing cartesian products rather than parallel
iteration.)
Nah, this won't work... The second collection would be just as valid for
a template, and -- "In the face of ambiguity, refuse the temptation to
guess."

-- bjorn
Moshe Zadka
2000-07-16 04:40:41 UTC
Permalink
Post by Huaiyu Zhu
That is, instead of sinm(x) and sin(x) we can write
sin(x) and sin(x.Element())
But both functions still need to be implemented, and each function call
would involve a member lookup, an initializsation and a type comparison.
Not if you implement

matpy.sin(x) as

x.__sin__()

--
Moshe Zadka <moshez at math.huji.ac.il>
There is no GOD but Python, and HTTP is its prophet.
http://advogato.org/person/moshez
Gareth McCaughan
2000-07-18 20:04:44 UTC
Permalink
Paul Prescod wrote:

[I said:]
Post by Paul Prescod
Post by gjm11
Only if you implement matrices as lists of lists, in which
case operations like * and / won't work anyway. I was assuming
that (1) you have a special Matrix class, and (2) the machinery
for list comprehensions is flexible enough to let it express
other kinds of mapping.
Today, the list comprehension syntax is syntactic sugar for
a=[]
for j in secondloop: ...
a.append( i, j )
I don't see any easy way to guess what type you want as "output" so it
Matrix( [...] )
I would be curious about ideas for allowing the output object to be
specified or inferred. What would the protocol be?
Well, I was making a broken assumption about the meaning of
multiple comprehension indices: namely, that
[(i,j) for i in [1,2], j in [1,2]]
would evaluate to [(1,1), (2,2)] rather than [(1,1), (1,2), (2,1), (2,2)].
If it's supposed to go the other way, then some of my other
assumptions stop working. :-)

However: I had been thinking along the following lines.
[expr for var in val] should produce something of the same
type as val, with the property that result[i] == expr(val[i])
for each legal index i. (Or something of the sort.)

One way to make this doable would be for each collection type
to define a "list-of-all-valid-indices" method, which (e.g.)
would return something like [0,1,2] for ["foo",23,[]]. Then
list comprehension could iterate over the result of that.
There'd also need to be a "make something new of the same
shape" method. (A "shallow copy" method would, of course,
do this just fine.)

So [f(x) for x in collection] would turn into something like

indices = collection.valid_indices()
result = collection.clone()
for index in indices:
result[index] = f(collection[index])

There might be a more efficient way to do this, of course.

With more than one collection being iterated over, as in
[blah blah blah for x in xs, y in ys], the simplest thing
would be to use the first collection mentioned as template
and source of valid indices. (This is the thing that fails
totally if we're doing cartesian products rather than parallel
iteration.)
--
Gareth McCaughan Gareth.McCaughan at pobox.com
sig under construction
Continue reading on narkive:
Loading...