Discussion: new operators for numerical computation

Huaiyu Zhu hzhu at localhost.localdomain
Mon Jul 24 00:27:18 EDT 2000


On Sat, 22 Jul 2000 01:28:52 GMT, Tim Hochberg <tim.hochberg at ieee.org> wrote:

>At this point there seems to be main proposals. There are variations
>on these basic themes, but these two capture the main points:

This summary is excellent.

Since (op) has emerged as the clear winner, at least for now, without
sustaining much criticism, I'd like to play antagonist here and prepare some
dead chickens to be thrown on the windshield of this new aircraft.  :-)

>-----------------------------------------------------------------------
>
>Proposal two, which for lack of a better name I'll call Konrad's proposal:
>
>New Operators: (+), (-), (/), (*)[outer], (.)[dot], (|)[solve], (^)[power] 

Minor questions:

1. Is it necessary to distiguish inner and outer?  With Greg's indexing
   rules these are essentially the same.  Six would be enough.

2. What would be the meaning of | and ^ for matrices?  What's the meaning of
   (|) and (^) for numbers?

3. What are the forms of augmented assignments?  (op)= or (op=)

Major questions:

1. Is the justification of (op) form mainly on aesthetic?  Or is it an open
   door for more operator composition within bracket in the future?  If the
   former, is two extra char of bracket justified?  If the latter, do we
   need to discuss what the future extensions might be?

2. Most important: How do real formulas look like?  (See examples below.)

>
>NumPy and MatPy would have that same syntax: the new operators correspond to
>matrix operations in both MatPy and matrix operators in NumPy.

The pain of transition now looks to be smaller than it appeared. A quick
experiment with sed on the MatPy test suite produced this list of problems
(most visible ones):

original                after s/\*/(*)/g; s/\//(\/)/g

"-"*40                  "-"(*)40                # should this work?
from ... import *       from ... import (*)     # can auto correct
1*2*3                   1(*)2(*)3               # this still works
a*2                     a(*)2                   # should this work?
A**2                    a(*)(*)2                # can auto correct
norm(A*A*A/A/(A*A) - eye(3))
                        norm(A(*)A(*)A(/)A(/)(A(*)A) - eye(3))
                                                # works but kinda ugly
def test(a,b,*args)     def test(a,b,(*)args)   # auto correct?

Most of the wrong translations still work or can be avoided by better
translators. Major problem comes from strings (esp regular expressions), but
fortunately regex and matrix tend to live in different modules.  If the
translator can recognize strings it would be mostly fine.

But the main problem of these operators now appears to be that they do not
look as clean in long formulas as they appear indivitually.

Why?  In discussions, the () works as a nice delimiter so (op) appear quite
nice in the text.  But in real codes it interferes with visual parsing of
existing ().

A typical example is the matrix inversion formula, represented as (assuming
| for solve, .I for inverse)

b = a.I - a | u / (c.I + v/a*u) * v / a

b = a.I .- a .| u ./ (c.I .+ v./a.*u) .* v ./ a

b = a.I @- a @| u @/ (c.I @+ v@/a@*u) @* v @/ a

b = a.I (-) a (|) u (/) (c.I (+) v(/)a(*)u) (*) v (/) a

The last one appears least clear, because it is difficult to visually parse
the parenthesis used for precedence.  Fine tuning on spacing and case of
names may offer some relief but the main problem won't go away.

Although this formula might have a bit higher than average complexity,
similar types of formulas occur frequently in various applications.  They
cannot all be put into named functions because there are many variations.

As I see it, the main reason for introducing infix operators is because
otherwise we would have to use either op(a,b) or a.op(b), both of which
introduces parenthesis that clutters the code.  But a(op)b has similar
effects. Although (op) has a very short range, the () can't be readily
distinguished from other usages of () with much longer range.

So it appears ".op" and "(op)" share similar disadvantages:
     ".op"  because "." is numbers, class members, ...
     "(op)" because "()" is precendence (tuples), function arguments, ...
maybe we need to consider "@op" more seriously?

In a divergent thread there are discussions of using "@" as a generic meta
symbol to construct new operators.  I only wish there is another free symbol
that's not as dense.  Well, how about

b = a.I ~- a ~| u ~/ (c.I ~+ v~/a~*u) ~* v ~/ a

It looks the least troublesome to me at the moment.


>Disadvantages:	Unfamiliar Syntax for MatLab users.

This may not be a big problem as syntax can be learned.

More important is if old codes can be used.  If automatic translation can
work 90% of the time it could be more useful than retyping.  If a translator
is wided used its quality is likely to be improved fairly quickly as well.


Huaiyu



More information about the Python-list mailing list