From: Thomas Jollans on
On 07/31/2010 12:15 PM, Lawrence D'Oliveiro wrote:
>reduce(lambda a, b : a + b, (y * y for y in V), 0))
>

This is a lot more verbose than it has to be, and probably slower too.

firstly:

(lambda a,b: a+b) is equivalent to operator.add.

==>
reduce(operator.add, (y*y for y in V), 0)

However - reduce with operator.add ? we have a special name for this:

==>
sum(y*y for y in V)
From: Alain Ketterlin on
Lawrence D'Oliveiro <ldo(a)geek-central.gen.new_zealand> writes:

>>> What I don't like is having that intermediate variable L leftover after
>>> the computation.
>>
>> Well, it also guarantees that the square root is computed once.
>
> OK, this version should solve that problem, without requiring any new
> language features:
>
> V = tuple \
> (
> x
> /
> l
> for x in V
> for l in
> (math.sqrt(reduce(lambda a, b : a + b, (y * y for y in V), 0)),)
> )

You got the order wrong (it has to be for l ... for x ...)

You're kind of lucky here, because the arglist to tuple() provides a
scope that hides x and l. Be careful if you ever change tuple(...) to
[...], because x and l would leak to the outer scope (with python 2.*).
In the general case

for L in [...some-expr...]:
... whatever

doesn't hide L. Python doesn't provide a "let" construct (à la Lisp or
*ML).

-- Alain.
From: Tim Roberts on
Lawrence D'Oliveiro <ldo(a)geek-central.gen.new_zealand> wrote:
>
>Say a vector V is a tuple of 3 numbers, not all zero. You want to normalize
>it (scale all components by the same factor) so its magnitude is 1.
>
>The usual way is something like this:
>
> L = math.sqrt(V[0] * V[0] + V[1] * V[1] + V[2] * V[2])
> V = (V[0] / L, V[1] / L, V[2] / L)
>
>What I don�t like is having that intermediate variable L leftover after the
>computation. Here�s how to do it in one step:
>
> V = tuple \
> (
> x
> /
> math.sqrt
> (
> reduce(lambda a, b : a + b, (y * y for y in V), 0)
> )
> for x in V
> )
>
>which, incidentally, also works for vectors with dimensions other than 3.

What is the matter with having a temporary variable hang around? It's only
one double, and it far better performance than the one you posted. As far
as I know, Python doesn't do common subexpression elimination, which means
the version you posted is doing to run the entire magnitude computation
once for every element in V.

A better solution would be to put this in a function:

def Normalize(V):
L = math.sqrt( sum(a*a for a in V) )
return (a/L for a in V)

Now the temporary goes away at the end of the function.
--
Tim Roberts, timr(a)probo.com
Providenza & Boekelheide, Inc.
From: Lawrence D'Oliveiro on
In message <87sk2zhpcj.fsf(a)dpt-info.u-strasbg.fr>, Alain Ketterlin wrote:

> Lawrence D'Oliveiro <ldo(a)geek-central.gen.new_zealand> writes:
>
>> V = tuple \
>> (
>> x
>> /
>> l
>> for x in V
>> for l in
>> (math.sqrt(reduce(lambda a, b : a + b, (y * y for y in V),
>> 0)),)
>> )
>
> You got the order wrong (it has to be for l ... for x ...)

No, I deliberately put it in that order to ensure that the value for l can
only ever be evaulated once.

> You're kind of lucky here, because the arglist to tuple() provides a
> scope that hides x and l. Be careful if you ever change tuple(...) to
> [...], because x and l would leak to the outer scope (with python 2.*).

Interesting. However, using “list( ... )” instead of “[ ... ]” also prevents
the leakage.
From: Thomas Jollans on
On 08/01/2010 03:41 AM, Lawrence D'Oliveiro wrote:
> In message <87sk2zhpcj.fsf(a)dpt-info.u-strasbg.fr>, Alain Ketterlin wrote:
>
>> Lawrence D'Oliveiro <ldo(a)geek-central.gen.new_zealand> writes:
>>
>>> V = tuple \
>>> (
>>> x
>>> /
>>> l
>>> for x in V
>>> for l in
>>> (math.sqrt(reduce(lambda a, b : a + b, (y * y for y in V),
>>> 0)),)
>>> )
>>
>> You got the order wrong (it has to be for l ... for x ...)
>
> No, I deliberately put it in that order to ensure that the value for l can
> only ever be evaulated once.
>
>> You're kind of lucky here, because the arglist to tuple() provides a
>> scope that hides x and l. Be careful if you ever change tuple(...) to
>> [...], because x and l would leak to the outer scope (with python 2.*).
>
> Interesting. However, using “list( ... )” instead of “[ ... ]” also prevents
> the leakage.

Yes. That's because the variable leakage of list comprehensions was
never a good idea, and is kept in Python 2.x only for backwards
compatibility. When generator expressions where introduced, it was done
in such a way that the scope didn't leak (which probably wouldn't make
any sense anyway since there's no guarantee a generator expression is
executed at all before the next line)

In Python 3, list comprehensions don't leak names any more - they act
(nearly?) the same as like( ... expr ... ) now.