Discussion: new operators for numerical computation

Tim Hochberg tim.hochberg at ieee.org
Mon Jul 24 16:34:40 EDT 2000


hzhu at localhost.localdomain (Huaiyu Zhu) writes:

[...]

> On Sat, 22 Jul 2000 01:28:52 GMT, Tim Hochberg <tim.hochberg at ieee.org> wrote:
 
> 1. Is it necessary to distiguish inner and outer?  With Greg's indexing
>    rules these are essentially the same.  Six would be enough.

Someone (?) strongly requested outer. Since no syntax is really
_necessary_, it's just a question of balancing how large the demand for
shorthand versus the pain of adding it. I almost never user outer, so
I'll leave the lobying up to those who use this. 
 
> 2. What would be the meaning of | and ^ for matrices?  What's the meaning of
>    (|) and (^) for numbers?

For the proposed operator set proposed in the summary, [(+), (-), (/),
(*), (.), (|), (^)], | and ^ would be bitwise OR and XOR as they are
now for Numeric. That's admittedly a little dicey, which is why
another choice might be better. The natural choice for power is of
course (**), but I worry that it may be hard to visually parse. (!)
was suggested for solve, but it is too associated with factorial for
me to be happy with it. As for the meaning of (|) and (^), for
numbers; we were forbidden from assigning meanings of new matrix
operations on builtin types, so I refuse to speculate<0.5 wink>.

One of the reasons I keep looking for a symbol for solve is that it's
more or less symmetric to (/) [or @/, etc.] and I suspect as commonly
used, if not more so. It seems that it would be unfortunate to have
one of the pair have a symbol while the other does not. I'm not sure,
but I might rather see two forms of solve, one returning B=A(**)-1(*)C
and one returning A=C(*)B(**)-1, than having one have of the pair
being designated (/) and the other solve (or sol).

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

I'd say (op)=. This seems obvious to me. So obvious, that I can't
think of a good explanation for it. (Sigh).

> 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?

Aesthetics for the most part. I'm not concerned with people wearing
their fingers out typing on any of the proposed syntaxes, so I refuse
to worry about extra characters. I think the sole issue is how
readable it is in complicated expressions; some important points are
made about this below.

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

[Snip...]

 
> 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.

The first is definitely the best. This does give me some sympathy for
the reversing the sense of the operators in different packages
proposal. Not enough, I don't think, but some. I think the second one
is actually the worst: are you going to notice the difference between:

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

and 

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

It seems that accidentaly using matrix when elementwise was meant and
vise versa would be a huge problem.

The third is hard to parse because @ is so heavy, and the last case
has parentheses problems. Blech. I went ahead and tried the other
passible bracketing symbols:

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 [*] form looks a little better. The <*> form bugs me because <->
looks like and arrow, but otherwise looks better than I expected. The
{*} form looks no better than [*] form, and is less evocative of a
matrix operation.

> 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.

I think the comparison with op(a,b) is not really valid since it is
not infix notation. Most people prefer "A + B" to "+ A B" due to
familiarlity with infix notation in this context. When the later
becomes "plus(A,B)" it exacerbates the problem, but the main problem
is infix versus prefix notation.

That being said, a.op(b) is more or less a fair comparison. I don't
think parentheses are the only issue though, even here. One is the
lack of symmetry, which makes the connection with infix notation
harder to see. For example, when I abused call functionality to
provide matrix multiplication, people were much more likely to accept
(A)(B) then A(B) despite the increase in parentheses in the
former. Second is symbol length, A.add(B) use six symbols to spell
matrix add while A(+)B uses only two. 


> 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?

My opinion: ".op" should be killed; any more consideration of this
front should go to "@op" or "~op". "(op)" should probably also die and
be replaced by "[op]" or, maybe, "<op>" or "{op}".

I'm also starting to wonder if maybe there is no good, pythonic syntax
to be added here . Perhaps more consideration should go into using the
existing operators and making tranformations between elementwise array
objects and matrix objects convenient.

-tim



More information about the Python-list mailing list