On Mon, Aug 3, 2009 at 7:23 PM, Dan Shumow<shu...@gmail.com> wrote:
>> The above change is very sensible, since we know that outP is on
>> self.__E2, so should directly create a point on E2 and not check again
>> that our point is really on E2 (which is very expensive).
>
> I agree that we should make the change:
>
>       else:
>           outP = self.__E2(outP)
>
> to
>
>       else:
>           outP = self.__E2.point(outP,check=False)
>
>
> When I originally wrote the code I did not know that this problem
> existed.

And I didn't know about it until a half hour ago :-).

William

> I just wanted to map a pair of elements on a field to the
> elliptic curve point object associated to those coordinates.
>
> I created the ticket:
> http://trac.sagemath.org/sage_trac/ticket/6672
>
> and will fix this when I get home tonight (I'm at work right now.)

Thanks!!

> The fix is very easy, if someone else wants to grab it for now, that
> is fine.  But just be sure to set check = false in the other point
> coercion call as well (in the if block associated with this else
> block.)
>
> Thanks,
> Dan
>
>
>
> On Mon, Aug 3, 2009 at 7:00 PM, William Stein<wst...@gmail.com> wrote:
>> On Mon, Aug 3, 2009 at 6:10 PM, VictorMiller<victorsmil...@gmail.com> wrote:
>>>
>>> Sorry, here's the definition of Q:
>>>
>>> Q = E.random_element()
>>>
>>> Victor
>>>
>>> On Aug 3, 8:45 pm, Simon King <simon.k...@nuigalway.ie> wrote:
>>>> Hi!
>>>>
>>>> On 4 Aug., 02:31, VictorMiller <victorsmil...@gmail.com> wrote:
>>>>
>>>> > Here are the commands I used:
>>>>
>>>> > qq = [z for z in primes(100000,100000+100) if (z%12) == 11]
>>>> > E = EllipticCurve(j=GF(qq[0])(1728))
>>>> > # E has qq[0]+1 points over GF(qq[0])
>>>> > factor(qq[0]+1)
>>>> > P = ((qq[0]+1)//3)*E.random_element()
>>>> > K = [E(0),P,-P]
>>>> > phi = E.isogeny(K)
>>
>> There appears to be a memory leak -- or some sort of caching (!) -- in
>> the code to evaluate phi.  This is likely impacting the complexity of
>> the some code that is run during the computation of phi(P).  The log
>> below shows that memory usage increases upon evaluation of phi(P):
>>
>> sage: get_memory_usage()
>> 210.109375
>> sage: timeit('phi(P)')
>> 125 loops, best of 3: 7.13 ms per loop
>> sage: get_memory_usage()
>> 210.609375
>> sage: timeit('phi(P)')
>> 125 loops, best of 3: 7.3 ms per loop
>> sage: get_memory_usage()
>> 211.109375
>> sage: timeit('phi(P)')
>> 125 loops, best of 3: 7.49 ms per loop
>> sage: get_memory_usage()
>> 211.609375
>> sage: timeit('phi(P)')
>> 125 loops, best of 3: 7.69 ms per loop
>> sage: get_memory_usage()
>> 212.109375
>>
>> Now I looked at the source code for the function phi(P) =
>> phi.__call__(P) and bisected by putting early returns in.  If you
>> change
>>
>>        else:
>>            outP = self.__E2(outP)
>>
>> to
>>
>>        else:
>>            return outP
>>            outP = self.__E2(outP)
>>
>> in that function in ell_curve_isogeny.py (around line 875), then the
>> leak and slowdown vanishes.
>>
>> Thus the real problem is in the "trivial" line "self.__E2(outP)",
>> which by the way takes even in good cases like 10 times as long as the
>> rest of the whole function put together.  Indeed, coercing a point
>> into a curve is a horrendous disaster (this is the real problem,
>> forget the isogeny stuff):
>>
>> sage: get_memory_usage()
>> 195.81640625
>> sage: timeit('E(P)')
>> 625 loops, best of 3: 4.24 ms per loop
>> sage: get_memory_usage()
>> 201.31640625
>>
>> In fact, the function E.point is to blame, evidently:
>>
>> sage: timeit('E.point(P)')
>> 125 loops, best of 3: 4.13 ms per loop
>> sage: get_memory_usage()
>> 202.08984375
>> sage: timeit('E.point(P)')
>> 125 loops, best of 3: 4.4 ms per loop
>> sage: get_memory_usage()
>> 203.08984375
>>
>> ... but *ONLY* with check=True (the default):
>>
>> sage: timeit('E.point(P,check=False)')
>> 625 loops, best of 3: 8.26 µs per loop
>> sage: get_memory_usage()
>> 203.08984375
>> sage: timeit('E.point(P,check=False)')
>> 625 loops, best of 3: 7.29 µs per loop
>> sage: get_memory_usage()
>> 203.08984375
>>
>> I.e., we get a speedup of a factor of nearly 1000 by using
>> check=False, plus the leak goes away.    So in the check -- which
>> involves arithmetic -- maybe the coercion model is surely being
>> invoked at some point (I guess), and that is perhaps caching
>> information, thus memory usage goes up and performance goes down.  I
>> don't know, I'm not looking further.
>>
>> Going back to your original problem, if I change in ell_curve_isogeny.py
>>
>>        else:
>>            outP = self.__E2(outP)
>>
>> to
>>
>>        else:
>>            outP = self.__E2.point(outP,check=False)
>>
>> then we have the following, which is exactly what you would hope for
>> (things are fast,  no slowdown).
>>
>> sage: qq = [z for z in primes(100000,100000+100) if (z%12) == 11]
>> sage: E = EllipticCurve(j=GF(qq[0])(1728))
>> sage: # E has qq[0]+1 points over GF(qq[0])
>> sage: factor(qq[0]+1)
>> 2^2 * 3 * 5 * 1667
>> sage: P = ((qq[0]+1)//3)*E.random_element()
>> sage: K = [E(0),P,-P]
>> sage: phi = E.isogeny(K)
>> sage: get_memory_usage()
>> 190.56640625
>> sage: timeit('phi(P)')
>> 625 loops, best of 3: 69.8 µs per loop
>> sage: for i in xrange(20): timeit('phi(P)')
>>
>> ....:
>> 625 loops, best of 3: 69.3 µs per loop
>> 625 loops, best of 3: 69.3 µs per loop
>> 625 loops, best of 3: 69.6 µs per loop
>> 625 loops, best of 3: 69.9 µs per loop
>> 625 loops, best of 3: 69.8 µs per loop
>> 625 loops, best of 3: 70 µs per loop
>> 625 loops, best of 3: 71.2 µs per loop
>> 625 loops, best of 3: 69.3 µs per loop
>> 625 loops, best of 3: 70.8 µs per loop
>> 625 loops, best of 3: 69.2 µs per loop
>> 625 loops, best of 3: 70.2 µs per loop
>> 625 loops, best of 3: 70.7 µs per loop
>> 625 loops, best of 3: 70 µs per loop
>> 625 loops, best of 3: 71 µs per loop
>> 625 loops, best of 3: 70 µs per loop
>> 625 loops, best of 3: 70.2 µs per loop
>> 625 loops, best of 3: 70.1 µs per loop
>> 625 loops, best of 3: 70 µs per loop
>> 625 loops, best of 3: 70.1 µs per loop
>> 625 loops, best of 3: 70.1 µs per loop
>>
>> The above change is very sensible, since we know that outP is on
>> self.__E2, so should directly create a point on E2 and not check again
>> that our point is really on E2 (which is very expensive).
>>
>> I hope the above is helpful and that somebody opens a trac ticket and
>> submits a patch.    I have to get back to what I was doing...   I also
>> hope the above email provides some ideas as to how to quickly get to
>> the bottom of questions like this.  Note that I did all this in < 10
>> minutes by using ?? to see where relevant source code is, putting in
>> some return statements (often better than print statements), and
>> knowing that P(...) means P.__call__.
>>
>>  -- William
>>
>



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

--~--~---------~--~----~------------~-------~--~----~
To post to this group, send email to sage-support@googlegroups.com
To unsubscribe from this group, send email to 
sage-support-unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/sage-support
URLs: http://www.sagemath.org
-~----------~----~----~----~------~----~------~--~---

Reply via email to