From: Thomas Jollans on 31 Jul 2010 06:44 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 31 Jul 2010 07:18 Lawrence D'Oliveiro 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 31 Jul 2010 15:45 Lawrence D'Oliveiro 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 31 Jul 2010 21:41 In message <87sk2zhpcj.fsf(a)dpt-info.u-strasbg.fr>, Alain Ketterlin wrote: > Lawrence D'Oliveiro 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 1 Aug 2010 06:32 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 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.