#18231: constructing matrices is very slow
-------------------------------------+-------------------------------------
       Reporter:  vdelecroix         |        Owner:
           Type:  defect             |       Status:  needs_review
       Priority:  major              |    Milestone:  sage-6.7
      Component:  linear algebra     |   Resolution:
       Keywords:                     |    Merged in:
        Authors:  Vincent Delecroix  |    Reviewers:
Report Upstream:  N/A                |  Work issues:
         Branch:                     |       Commit:
  u/vdelecroix/18231                 |  da310db9b3b4238121b1a1ad2c3d5e36a5e846b5
   Dependencies:                     |     Stopgaps:
-------------------------------------+-------------------------------------
Changes (by vdelecroix):

 * status:  needs_work => needs_review


Old description:

> The problem is in the code which looks like the following
> {{{
> def test1():
>     K = QuadraticField(2)
>     for _ in range(100):
>         i = randint(2,3)
>         j = randint(2,3)
>         m = matrix(K, i, j, range(i*j))
> }}}
> It causes the various matrix spaces to rebuilt almost each time! If we
> compare with
> {{{
> def test2():
>     K = QuadraticField(2)
>     M = {(i,j): MatrixSpace(K,i,j) for i in range(2,4) for j in
> range(2,4)}
>     for _ in range(100):
>         i = randint(2,3)
>         j = randint(2,3)
>         m = M[i,j](range(i*j))
> }}}
> then we got
> {{{
> sage: %timeit test1()
> 10 loops, best of 3: 55 ms per loop
> sage: %timeit test2()
> 100 loops, best of 3: 6.49 ms per loop
> }}}
>
> This is one of the reason why the creation of Polyhedron is so slow (see
> #18213).

New description:

 The problem is in the code which looks like the following
 {{{
 def test1():
     K = QuadraticField(2)
     for _ in range(100):
         i = randint(2,3)
         j = randint(2,3)
         m = matrix(K, i, j, range(i*j))
 }}}
 It causes the various matrix spaces to rebuilt almost each time! If we
 compare with
 {{{
 def test2():
     K = QuadraticField(2)
     M = {(i,j): MatrixSpace(K,i,j) for i in range(2,4) for j in
 range(2,4)}
     for _ in range(100):
         i = randint(2,3)
         j = randint(2,3)
         m = M[i,j](range(i*j))
 }}}
 then we got
 {{{
 sage: %timeit test1()
 10 loops, best of 3: 55 ms per loop
 sage: %timeit test2()
 100 loops, best of 3: 6.49 ms per loop
 }}}

 This is one of the reason why the creation of Polyhedron is so slow (see
 #18213).

 In the branch we:
 - replace some old Cython code in `matrix_generic_dense` and `matrix0` and
 do some optimization
 - move the function `_get_matrix_class` in `MatrixSpace` out of the class
 (as it depends only on the base ring and the sparseness)
 - In the class `MatrixSpace` the argument `__matrix_class` is now
 `_matrix_class`. That way, it is possible in other part of Sage to
 optimize the creation of matrices by calling directly
 {{{
 sage: M = MatrixSpace(ZZ,3,2)
 sage: M._matrix_class([1,5,3,-1,2,3], coerce=False, copy=False)
 }}}
 - we simplify the main element constructor of matrix, namely
 `MatrixSpace.matrix` and gain a significant speedup.

--

Comment:

 Hello Nathann,

 Thanks for having a look.

 Replying to [comment:3 ncohen]:
 > In this branch you create functions, remove others, and change a lot of
 code. There is still a lot of guessing to do on the reviewer's part.
 >

 > It would be really cool if you could be more verbose about what you do.
 Really.

 I made a big effort to separate the commit at least! It is now in the
 description of the ticket.

 > I began to read the first commit, and I have several more specific
 questions:
 >
 > - You modify a function which takes a `MonoidElement` as input, which
 you immeditely cast with `cdef Matrix right = _right`. Either it is a
 matrix and it should not read `MonoidElement` in the first place, or it is
 not a `Matrix` and you cannot cast it?..

 No choice. This is a cdef function defined in `structure.element.Element`
 and you can not change the signature in children classes. I thought it was
 more readable this way.

 > - This is cool and everything to gain miliseconds, but that's not a good
 way to write public code
 >   If the main constructor does not do what you want ty to change it.
 What if somebody adds a new parameter to matrix? The code has to be
 copy/pasted in every single function that did not want to call `__init__`?

 All right. But then there is something wrong in the docstring of
 `matrix0.Matrix`
 {{{
     def __init__(...):
         ...
         Subclasses of ``Matrix`` can safely skip calling
         ``Matrix.__init__`` provided they take care of initializing these
         attributes themselves.
         ...
 }}}

 > - Why?

 All this was just old Cython code at the time Cython was not able to
 understand `l[i]` when `l` is a `cdef list`.

--
Ticket URL: <http://trac.sagemath.org/ticket/18231#comment:4>
Sage <http://www.sagemath.org>
Sage: Creating a Viable Open Source Alternative to Magma, Maple, Mathematica, 
and MATLAB

-- 
You received this message because you are subscribed to the Google Groups 
"sage-trac" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sage-trac.
For more options, visit https://groups.google.com/d/optout.

Reply via email to