multiply a list by a constant

1,093 views
Skip to first unread message

pong

unread,
Oct 19, 2008, 12:22:39 AM10/19/08
to sage-support
Is there any bulit-in function of sage which can multiply each element
of a list of numbers by a constant?

e.g. I want 2*[3,4] = [6,8]

without calling pari/gp.

Thanks in advance

Alex Ghitza

unread,
Oct 19, 2008, 12:26:00 AM10/19/08
to sage-s...@googlegroups.com
I'm not sure this is what you're hoping for, but it does the trick:

sage: [2*_ for _ in [3,4]]
[6,8]


Best,
Alex
--
Alex Ghitza -- Lecturer in Mathematics -- The University of Melbourne -- Australia -- http://www.ms.unimelb.edu.au/~aghitza/

pong

unread,
Oct 19, 2008, 12:31:09 AM10/19/08
to sage-support
Hi Alex

Thanks for the quick reply. By _ you mean a variable? I tried your
syntax but it does not work.
However, [2*x for x in [3,4]] does work.


On Oct 18, 9:26 pm, "Alex Ghitza" <aghi...@gmail.com> wrote:
> I'm not sure this is what you're hoping for, but it does the trick:
>
> sage: [2*_ for _ in [3,4]]
> [6,8]
>
> Best,
> Alex
>

Alex Ghitza

unread,
Oct 19, 2008, 1:14:49 AM10/19/08
to sage-s...@googlegroups.com
Hmmm.  As far as I know you can use _ as a placeholder for a variable, and it's meant for this kind of use (where you don't really want to introduce a new variable name).  It's strange that it doesn't work for you.  Can you post the error message that you get?

I guess it's not a big deal since you can always use x as you did, but if it's really not working it might be a sign of other trouble.

Alex



On Sun, Oct 19, 2008 at 3:31 PM, pong <wypo...@gmail.com> wrote:

Hi Alex

   Thanks for the quick reply. By _ you mean a variable? I tried your
syntax but it does not work.
   However, [2*x for x in [3,4]] does work.
 

pong

unread,
Oct 19, 2008, 1:29:22 AM10/19/08
to sage-support
Hi Alex,

Sorry, it does work---it was a spacing problem. I should have copy-
and-paste yours.

Thanks
Pong

On Oct 18, 10:14 pm, "Alex Ghitza" <aghi...@gmail.com> wrote:
> Hmmm.  As far as I know you can use _ as a placeholder for a variable, and
> it's meant for this kind of use (where you don't really want to introduce a
> new variable name).  It's strange that it doesn't work for you.  Can you
> post the error message that you get?
>
> I guess it's not a big deal since you can always use x as you did, but if
> it's really not working it might be a sign of other trouble.
>
> Alex
>

Robert Bradshaw

unread,
Oct 19, 2008, 2:15:56 AM10/19/08
to sage-s...@googlegroups.com
On Oct 18, 2008, at 10:14 PM, Alex Ghitza wrote:

> Hmmm. As far as I know you can use _ as a placeholder for a
> variable, and it's meant for this kind of use (where you don't
> really want to introduce a new variable name). It's strange that
> it doesn't work for you. Can you post the error message that you get?

Actually, _ is an actual variable, though personally I find it a bit
harder to read than a normal letter. The one special thing about it
(in ipython at least) is that it constantly gets reassigned to the
last returned value, e.g.

sage: 1+2
3
sage: _
3

- Robert

Marshall Hampton

unread,
Oct 19, 2008, 10:27:52 AM10/19/08
to sage-support
Another option is to convert your list to a vector, and then convert
it back. This is more awkward for a single operation but if you are
doing lots of vector addition and scalar multiplication it can be the
way to go.
I.e. you can do:

sage: a = [3,4]
sage: a = list(2*vector(a))
sage: a
[6, 8]

-M. Hampton

On Oct 19, 1:15 am, Robert Bradshaw <rober...@math.washington.edu>
wrote:

pong

unread,
Oct 20, 2008, 5:06:19 PM10/20/08
to sage-support
Thanks Marshall. I have thought about that as well.
Since I want to optimize time. I want to see if your method is faster
then a for loop. However, I run into something puzzling:

vector( [k for k in range(10)]) results in an error. Sage compliant
about

TypeError: unable to find a common ring for all elements

But if you check each element of the list, I got <type 'int'>

So why SAGE is complaining?

William Stein

unread,
Oct 20, 2008, 5:09:47 PM10/20/08
to sage-s...@googlegroups.com
On Mon, Oct 20, 2008 at 2:06 PM, pong <wypo...@gmail.com> wrote:
>
> Thanks Marshall. I have thought about that as well.
> Since I want to optimize time. I want to see if your method is faster
> then a for loop. However, I run into something puzzling:
>
> vector( [k for k in range(10)]) results in an error. Sage compliant
> about
>
> TypeError: unable to find a common ring for all elements

I get

sage: vector( [k for k in range(10)])
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

Are you sure that's what you typed?

--
William Stein
Associate Professor of Mathematics
University of Washington
http://wstein.org

pong

unread,
Oct 20, 2008, 5:24:29 PM10/20/08
to sage-support
Yes, that's what I got. Maybe because I'm only using SAGE 3.1.1 or
there is something wrong with the installation.

sage: vector([k for k in range(10)])
-----------------------------------------------------------------------------------------------------------
TypeError Traceback (most recent call
last)

/home/pong/sage/<ipython console> in <module>()

/home/pong/sage/free_module_element.pyx in
sage.modules.free_module_element.vector (sage/modules/
free_module_element.c:2376)()

/home/pong/sage/free_module_element.pyx in
sage.modules.free_module_element.prepare (sage/modules/
free_module_element.c:2622)()

TypeError: unable to find a common ring for all elements


On Oct 20, 2:09 pm, "William Stein" <wst...@gmail.com> wrote:

William Stein

unread,
Oct 20, 2008, 5:36:00 PM10/20/08
to sage-s...@googlegroups.com
On Mon, Oct 20, 2008 at 2:24 PM, pong <wypo...@gmail.com> wrote:
>
> Yes, that's what I got. Maybe because I'm only using SAGE 3.1.1 or
> there is something wrong with the installation.

I bet that's the case. You should maybe upgrade. We'll be posting
binaries soon.

William

Jason Grout

unread,
Oct 20, 2008, 7:10:41 PM10/20/08
to sage-s...@googlegroups.com
William Stein wrote:
> On Mon, Oct 20, 2008 at 2:06 PM, pong <wypo...@gmail.com> wrote:
>> Thanks Marshall. I have thought about that as well.
>> Since I want to optimize time. I want to see if your method is faster
>> then a for loop. However, I run into something puzzling:
>>
>> vector( [k for k in range(10)]) results in an error. Sage compliant
>> about
>>
>> TypeError: unable to find a common ring for all elements
>
> I get
>
> sage: vector( [k for k in range(10)])
> (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
>
> Are you sure that's what you typed?


It seems like this error was fixed recently. Pong, what version of Sage
are you running?

Jason

Jason Grout

unread,
Oct 20, 2008, 8:42:30 PM10/20/08
to sage-s...@googlegroups.com
William Stein wrote:
> On Mon, Oct 20, 2008 at 2:24 PM, pong <wypo...@gmail.com> wrote:
>> Yes, that's what I got. Maybe because I'm only using SAGE 3.1.1 or
>> there is something wrong with the installation.
>
> I bet that's the case. You should maybe upgrade. We'll be posting
> binaries soon.


Yep, this was taken care of in 3.1.2:

http://trac.sagemath.org/sage_trac/ticket/3847

Sorry for my other delayed reply. Apparently gmane has a big delay in
mirroring responses.

Jason


pong

unread,
Oct 21, 2008, 10:50:32 AM10/21/08
to sage-support
Yes, Sage 3.1.2 fixes the problem.

It looks like Marshall's method of multiplying a list of numbers with
a constant is much faster then a for loop.
I wrote two list tests:

def test1():
for k in range(10^3):
v=[2*random() for j in range(10)]
else: pass

def test2():
for k in range(10^3):
v=list(2*vector([random() for j in range(10)]))
else: pass

It turns out that
time test1() gives around 8s CUP time while time test2() shows only
0.35s CUP time is used. Wow!


On Oct 20, 5:42 pm, Jason Grout <jason-s...@creativetrax.com> wrote:
> William Stein wrote:

Dan Drake

unread,
Oct 21, 2008, 7:09:43 PM10/21/08
to sage-s...@googlegroups.com
On Tue, 21 Oct 2008 at 07:50AM -0700, pong wrote:
> I wrote two list tests:
>
> def test1():
> for k in range(10^3):
> v=[2*random() for j in range(10)]
> else: pass
>
> def test2():
> for k in range(10^3):
> v=list(2*vector([random() for j in range(10)]))
> else: pass
>
> It turns out that
> time test1() gives around 8s CUP time while time test2() shows only
> 0.35s CUP time is used. Wow!

Also, instead of doing your own loops, you can use %timeit:

sage: %timeit [2*random() for j in range(10)]
100000 loops, best of 3: 6.87 µs per loop
sage: %timeit list(2*vector([random() for j in range(10)]))
10000 loops, best of 3: 112 µs per loop

Using list comprehensions is almost always a good choice in Sage/Python;
as I understand (and as we see above), they're very well-optimized.

Dan

--
--- Dan Drake <dr...@mathsci.kaist.ac.kr>
----- KAIST Department of Mathematical Sciences
------- http://mathsci.kaist.ac.kr/~drake

signature.asc

William Stein

unread,
Oct 21, 2008, 8:25:22 PM10/21/08
to sage-s...@googlegroups.com, Fernando Perez
On Tue, Oct 21, 2008 at 4:09 PM, Dan Drake <dr...@mathsci.kaist.ac.kr> wrote:
> On Tue, 21 Oct 2008 at 07:50AM -0700, pong wrote:
>> I wrote two list tests:
>>
>> def test1():
>> for k in range(10^3):
>> v=[2*random() for j in range(10)]
>> else: pass
>>
>> def test2():
>> for k in range(10^3):
>> v=list(2*vector([random() for j in range(10)]))
>> else: pass
>>
>> It turns out that
>> time test1() gives around 8s CUP time while time test2() shows only
>> 0.35s CUP time is used. Wow!
>
> Also, instead of doing your own loops, you can use %timeit:
>
> sage: %timeit [2*random() for j in range(10)]
> 100000 loops, best of 3: 6.87 µs per loop
> sage: %timeit list(2*vector([random() for j in range(10)]))
> 10000 loops, best of 3: 112 µs per loop
>
> Using list comprehensions is almost always a good choice in Sage/Python;
> as I understand (and as we see above), they're very well-optimized.

I also added a command called timeit, so you can do

sage: timeit(' [2*random() for j in range(10)]')

this has the advantage that the input is preparsed using
the Sage preparser, so might give a slightly more accurate
result, and work in some cases where %timeit doesn't work.
For example,

sage: %timeit R.<x> = QQ[]
------------------------------------------------------------
File "<magic-timeit>", line 6
R.<x> = QQ[]
^
SyntaxError: invalid syntax

sage: timeit('R.<x> = QQ[]')
625 loops, best of 3: 287 µs per loop

It would be reasonable to argue that the fact that %timeit doesn't
preparse its input is a bug in Sage (actually IPython), and that it
should. I've cc'd Fernando Perez (author of IPython) in case he has a
comment.

William

pong

unread,
Oct 22, 2008, 1:17:37 AM10/22/08
to sage-support
Thanks to both Dan and William. However, Dan's result puzzled me.
Aren't they suggested that the for loop is faster?

Here is what I got:

sage: timeit('list(2*vector([random() for j in range(10)]))')
625 loops, best of 3: 332 µs per loop
sage: timeit('[2*random() for j in range(10)]')
125 loops, best of 3: 8.3 ms per loop

which suggested otherwise. Also how does timeit determine how many
loops to perform in a test?
>  signature.asc
> < 1KViewDownload

Robert Bradshaw

unread,
Oct 22, 2008, 11:12:30 AM10/22/08
to sage-s...@googlegroups.com
On Oct 21, 2008, at 10:17 PM, pong wrote:

> Thanks to both Dan and William. However, Dan's result puzzled me.
> Aren't they suggested that the for loop is faster?
>
> Here is what I got:
>
> sage: timeit('list(2*vector([random() for j in range(10)]))')
> 625 loops, best of 3: 332 µs per loop
> sage: timeit('[2*random() for j in range(10)]')
> 125 loops, best of 3: 8.3 ms per loop

A more precise benchmark (ignoring vector/list creation) would
probably be:

sage: L = [random() for j in range(10)]
sage: v = vector(L)
sage: timeit("2*v")
625 loops, best of 3: 1.76 µs per loop
sage: timeit("[2*a for a in L]")
25 loops, best of 3: 29.2 ms per loop

To explain your timings, note

sage: parent(random())
<type 'float'>
sage: parent(vector([random() for j in range(10)]))
Vector space of dimension 10 over Real Double Field
sage: parent(2)
Integer Ring

In your first loop, it's creating a RDF vector and then multiplying
by 2 via

sage: cm = sage.structure.element.get_coercion_model()
sage: cm.explain(2, v)
Action discovered.
Left scalar multiplication by Integer Ring on Vector space of
dimension 10 over Real Double Field
Result lives in Vector space of dimension 10 over Real Double Field
Vector space of dimension 10 over Real Double Field

in other words, it turns "2" into an RDF, then multiplies every
element (in fast compiled code) of the RDF vector. In the second
case, it's having to re-discover the float-Integer operation each
time (as the result is a float) which happens to be the worst-case
scenario. Note with RDF rather than floats

sage: timeit("[2*a for a in v]")
625 loops, best of 3: 20.9 µs per loop

(still not the speed of a vector-element multiply, but much better).
There is a ticket or two related to improving this, e.g. #3938 and
#2898.

> which suggested otherwise. Also how does timeit determine how many
> loops to perform in a test?

In my experience (haven't looked at the code) it keeps timing until
it hits about a second, going by powers of 5.

>> Also, instead of doing your own loops, you can use %timeit:
>>
>> sage: %timeit [2*random() for j in range(10)]
>> 100000 loops, best of 3: 6.87 µs per loop
>> sage: %timeit list(2*vector([random() for j in range(10)]))
>> 10000 loops, best of 3: 112 µs per loop

Note that the 2 is not getting preparsed, and so one is doing python-
int * python-float. Also, in the second example, the bulk of the time
is in the conversion, not the multiply

sage: sage: %timeit list(2*vector([random() for j in range(10)]))
10000 loops, best of 3: 173 µs per loop
sage: %timeit list(vector([random() for j in range(10)]))
10000 loops, best of 3: 167 µs per loop

>> Using list comprehensions is almost always a good choice in Sage/
>> Python;
>> as I understand (and as we see above), they're very well-optimized.

Yes, though using vectors can be faster too, and if one's list really
is a vector than it can make much easier to read code than
manipulating lists.

- Robert

Reply all
Reply to author
Forward
0 new messages