#15820: Improve efficiency of the path semigroup
--------------------------------------------------+------------------------
       Reporter:  SimonKing                       |        Owner:
           Type:  enhancement                     |       Status:  new
       Priority:  major                           |    Milestone:  sage-6.2
      Component:  algebra                         |   Resolution:
       Keywords:  quiver path algebra efficiency  |    Merged in:
        Authors:                                  |    Reviewers:
Report Upstream:  N/A                             |  Work issues:
         Branch:                                  |       Commit:
   Dependencies:  #12630                          |     Stopgaps:
--------------------------------------------------+------------------------

Comment (by SimonKing):

 I have attached a toy (or proof-of-concept) implementation; see
 [attachment:path_test.pyx]. In a ''real'' implementation in
 compressed representation, it would be the job of a `PathSemigroup` to
 find
 out how many edges fit into one word. And of course, in the toy
 implementation
 I am not trying to translate an integer sequence into the string
 representation of an element of the path semigroup.

 What implementation would you suggest to use in "reality"? Is there
 another implementation of "sequences of bounded integers" that you would
 recommend? And would you enumerate the arrows of a quiver locally (i.e.,
 only number the outgoing edges at each vertex) or globally? The former
 will result in better compression, but would make it more difficult to
 test for paths p,q whether there are paths r,s with `p==r*q*s`.

 Now for the timings, and sorry for the long post...

 Here, I am timing concatenation, hash, comparison, comparing initial
 segments. In all examples, we use the following paths of various sizes.
 {{{
 p5 = Path(ZZ, 5, range(5), 1, 1)
 p25 = Path(ZZ, 25, range(25), 1, 1)
 p50 = Path(ZZ, 50, range(50), 1, 1)
 p100 = Path(ZZ, 100, range(100), 1, 1)
 p1000 = Path(ZZ, 1000, range(1000), 1, 1)
 q5 = Path(ZZ, 5, range(1,6), 1, 1)
 q25 = Path(ZZ, 25, range(1,26), 1, 1)
 q50 = Path(ZZ, 50, range(1,51), 1, 1)
 q100 = Path(ZZ, 100, range(1,101), 1, 1)
 q1000 = Path(ZZ, 1000, range(1,1001), 1, 1)
 r5 = Path(ZZ, 5, range(1,5)+[0], 1, 1)
 r25 = Path(ZZ, 25, range(1,25)+[0], 1, 1)
 r50 = Path(ZZ, 50, range(1,50)+[0], 1, 1)
 r100 = Path(ZZ, 100, range(1,100)+[0], 1, 1)
 r1000 = Path(ZZ, 1000, range(1,1000)+[0], 1, 1)
 s5 = Path(ZZ, 5, range(5), 1, 1)
 s25 = Path(ZZ, 25, range(25), 1, 1)
 s50 = Path(ZZ, 50, range(50), 1, 1)
 s100 = Path(ZZ, 100, range(100), 1, 1)
 s1000 = Path(ZZ, 1000, range(1000), 1, 1)
 }}}

 We are doing the following tests.

 Concatenation:
 {{{
 %timeit p5*q5
 %timeit p5*q25
 %timeit p25*q25
 %timeit p25*q50
 %timeit p50*q50
 %timeit p50*q100
 %timeit p100*q100
 %timeit p100*q1000
 %timeit p1000*q1000
 }}}

 Hash:
 {{{
 %timeit hash(p5)
 %timeit hash(p25)
 %timeit hash(p50)
 %timeit hash(p100)
 %timeit hash(p1000)
 }}}

 Comparison:
 1. equal
 {{{
 %timeit p5==s5
 %timeit p25==s25
 %timeit p50==s50
 %timeit p100==s100
 %timeit p1000==s1000
 }}}
 2. obviously different (first item differs)
 {{{
 %timeit p5==r5
 %timeit p25==r25
 %timeit p50==r50
 %timeit p100==r100
 %timeit p1000==r1000
 }}}
 3. less obviously different (only the last item differs)
 {{{
 %timeit q5==r5
 %timeit q25==r25
 %timeit q50==r50
 %timeit q100==r100
 %timeit q1000==r1000
 }}}

 Startswith:
 {{{
 %timeit q1000.startswith(q100)  # it does start with
 %timeit q1000.startswith(r100)  # it doesn't start with
 }}}

 '''__Uncompressed integer lists__'''

 Here, we define `Path=Path_v1` (see [attachment:path_test.pyx]).

 __Using `ctypedef unsigned long block`__

 {{{
 sage: %timeit p5*q5
 1000000 loops, best of 3: 739 ns per loop
 sage: %timeit p5*q25
 1000000 loops, best of 3: 769 ns per loop
 sage: %timeit p25*q25
 1000000 loops, best of 3: 801 ns per loop
 sage: %timeit p25*q50
 1000000 loops, best of 3: 810 ns per loop
 sage: %timeit p50*q50
 1000000 loops, best of 3: 885 ns per loop
 sage: %timeit p50*q100
 1000000 loops, best of 3: 959 ns per loop
 sage: %timeit p100*q100
 1000000 loops, best of 3: 1.02 us per loop
 sage: %timeit p100*q1000
 100000 loops, best of 3: 1.99 us per loop
 sage: %timeit p1000*q1000
 100000 loops, best of 3: 3.06 us per loop
 sage: %timeit hash(p5)
 10000000 loops, best of 3: 135 ns per loop
 sage: %timeit hash(p25)
 10000000 loops, best of 3: 166 ns per loop
 sage: %timeit hash(p50)
 1000000 loops, best of 3: 214 ns per loop
 sage: %timeit hash(p100)
 1000000 loops, best of 3: 333 ns per loop
 sage: %timeit hash(p1000)
 100000 loops, best of 3: 2.09 us per loop
 sage: %timeit p5==s5
 1000000 loops, best of 3: 1.63 us per loop
 sage: %timeit p25==s25
 100000 loops, best of 3: 5.91 us per loop
 sage: %timeit p50==s50
 100000 loops, best of 3: 11 us per loop
 sage: %timeit p100==s100
 10000 loops, best of 3: 23 us per loop
 sage: %timeit p1000==s1000
 1000 loops, best of 3: 212 us per loop
 sage: %timeit p5==r5
 1000000 loops, best of 3: 634 ns per loop
 sage: %timeit p25==r25
 1000000 loops, best of 3: 659 ns per loop
 sage: %timeit p50==r50
 1000000 loops, best of 3: 659 ns per loop
 sage: %timeit p100==r100
 1000000 loops, best of 3: 686 ns per loop
 sage: %timeit p1000==r1000
 1000000 loops, best of 3: 698 ns per loop
 sage: %timeit q5==r5
 1000000 loops, best of 3: 1.65 us per loop
 sage: %timeit q25==r25
 100000 loops, best of 3: 5.83 us per loop
 sage: %timeit q50==r50
 100000 loops, best of 3: 11.5 us per loop
 sage: %timeit q100==r100
 10000 loops, best of 3: 22 us per loop
 sage: %timeit q1000==r1000
 1000 loops, best of 3: 213 us per loop
 sage: %timeit q1000.startswith(q100)
 1000000 loops, best of 3: 325 ns per loop
 sage: %timeit q1000.startswith(r100)
 1000000 loops, best of 3: 311 ns per loop
 }}}

 __Using `ctypedef unsigned short block`__

 {{{
 sage: %timeit p5*q5
 1000000 loops, best of 3: 700 ns per loop
 sage: %timeit p5*q25
 1000000 loops, best of 3: 738 ns per loop
 sage: %timeit p25*q25
 1000000 loops, best of 3: 820 ns per loop
 sage: %timeit p25*q50
 1000000 loops, best of 3: 769 ns per loop
 sage: %timeit p50*q50
 1000000 loops, best of 3: 808 ns per loop
 sage: %timeit p50*q100
 1000000 loops, best of 3: 877 ns per loop
 sage: %timeit p100*q100
 1000000 loops, best of 3: 909 ns per loop
 sage: %timeit p100*q1000
 1000000 loops, best of 3: 1.49 us per loop
 sage: %timeit p1000*q1000
 100000 loops, best of 3: 2.13 us per loop
 sage: %timeit hash(p5)
 10000000 loops, best of 3: 138 ns per loop
 sage: %timeit hash(p25)
 10000000 loops, best of 3: 179 ns per loop
 sage: %timeit hash(p50)
 1000000 loops, best of 3: 236 ns per loop
 sage: %timeit hash(p100)
 1000000 loops, best of 3: 383 ns per loop
 sage: %timeit hash(p1000)
 100000 loops, best of 3: 2.61 us per loop
 sage: %timeit p5==s5
 1000000 loops, best of 3: 1.08 us per loop
 sage: %timeit p25==s25
 100000 loops, best of 3: 3.42 us per loop
 sage: %timeit p50==s50
 100000 loops, best of 3: 6.53 us per loop
 sage: %timeit p100==s100
 100000 loops, best of 3: 14.9 us per loop
 sage: %timeit p1000==s1000
 10000 loops, best of 3: 137 us per loop
 sage: %timeit p5==r5
 1000000 loops, best of 3: 613 ns per loop
 sage: %timeit p25==r25
 1000000 loops, best of 3: 591 ns per loop
 sage: %timeit p50==r50
 1000000 loops, best of 3: 602 ns per loop
 sage: %timeit p100==r100
 1000000 loops, best of 3: 603 ns per loop
 sage: %timeit p1000==r1000
 1000000 loops, best of 3: 635 ns per loop
 sage: %timeit q5==r5
 1000000 loops, best of 3: 1.15 us per loop
 sage: %timeit q25==r25
 100000 loops, best of 3: 3.63 us per loop
 sage: %timeit q50==r50
 100000 loops, best of 3: 6.45 us per loop
 sage: %timeit q100==r100
 100000 loops, best of 3: 12.8 us per loop
 sage: %timeit q1000==r1000
 10000 loops, best of 3: 140 us per loop
 sage: q1000.startswith(q100)
 True
 sage: %timeit q1000.startswith(q100)
 1000000 loops, best of 3: 336 ns per loop
 sage: q1000.startswith(r100)
 False
 sage: %timeit q1000.startswith(r100)
 1000000 loops, best of 3: 325 ns per loop
 }}}

 __Using `ctypedef unsigned char block`__

 {{{
 sage: %timeit p5*q5
 1000000 loops, best of 3: 679 ns per loop
 sage: %timeit p5*q25
 1000000 loops, best of 3: 693 ns per loop
 sage: %timeit p25*q25
 1000000 loops, best of 3: 725 ns per loop
 sage: %timeit p25*q50
 1000000 loops, best of 3: 760 ns per loop
 sage: %timeit p50*q50
 1000000 loops, best of 3: 772 ns per loop
 sage: %timeit p50*q100
 1000000 loops, best of 3: 761 ns per loop
 sage: %timeit p100*q100
 1000000 loops, best of 3: 790 ns per loop
 sage: %timeit p100*q1000
 1000000 loops, best of 3: 1.1 us per loop
 sage: %timeit p1000*q1000
 1000000 loops, best of 3: 1.31 us per loop
 sage: %timeit hash(p5)
 10000000 loops, best of 3: 133 ns per loop
 sage: %timeit hash(p25)
 10000000 loops, best of 3: 176 ns per loop
 sage: %timeit hash(p50)
 1000000 loops, best of 3: 234 ns per loop
 sage: %timeit hash(p100)
 1000000 loops, best of 3: 374 ns per loop
 sage: %timeit hash(p1000)
 100000 loops, best of 3: 2.53 us per loop
 sage: %timeit p5==s5
 1000000 loops, best of 3: 1.08 us per loop
 sage: %timeit p25==s25
 100000 loops, best of 3: 3.36 us per loop
 sage: %timeit p50==s50
 100000 loops, best of 3: 6.3 us per loop
 sage: %timeit p100==s100
 100000 loops, best of 3: 12.5 us per loop
 sage: %timeit p1000==s1000
 10000 loops, best of 3: 121 us per loop
 sage: %timeit p5==r5
 1000000 loops, best of 3: 581 ns per loop
 sage: %timeit p25==r25
 1000000 loops, best of 3: 589 ns per loop
 sage: %timeit p50==r50
 1000000 loops, best of 3: 599 ns per loop
 sage: %timeit p100==r100
 1000000 loops, best of 3: 599 ns per loop
 sage: %timeit p1000==r1000
 1000000 loops, best of 3: 636 ns per loop
 sage: %timeit q5==r5
 1000000 loops, best of 3: 1.06 us per loop
 sage: %timeit q25==r25
 100000 loops, best of 3: 3.46 us per loop
 sage: %timeit q50==r50
 100000 loops, best of 3: 6.51 us per loop
 sage: %timeit q100==r100
 100000 loops, best of 3: 12.7 us per loop
 sage: %timeit q1000==r1000
 10000 loops, best of 3: 121 us per loop
 sage: q1000.startswith(q100)
 True
 sage: %timeit q1000.startswith(q100)
 1000000 loops, best of 3: 324 ns per loop
 sage: %timeit q1000.startswith(r100)
 1000000 loops, best of 3: 315 ns per loop
 }}}

 '''__Compressed integer lists__'''

 Here, we define `Path=Path_v2` (see [attachment:path_test.pyx]), and do
 {{{
 sage: SizeManager.set_edge_number(27)
 }}}
 so that there is a total of only 27 edges (resp. 27 is the maximal number
 of
 outgoing arrows on a vertex). In particular, all integers in the sequences
 below are taken "mod 27". Since 27 has length 5 bits, a compressed
 representation using `unsigned char*` won't make sense. Hence, I am only
 testing long and short.

 __Using `ctypedef unsigned long block`__

 {{{
 sage: %timeit p5*q5
 1000000 loops, best of 3: 676 ns per loop
 sage: %timeit p5*q25
 1000000 loops, best of 3: 671 ns per loop
 sage: %timeit p25*q25
 1000000 loops, best of 3: 683 ns per loop
 sage: %timeit p25*q50
 1000000 loops, best of 3: 725 ns per loop
 sage: %timeit p50*q50
 1000000 loops, best of 3: 759 ns per loop
 sage: %timeit p50*q100
 1000000 loops, best of 3: 787 ns per loop
 sage: %timeit p100*q100
 1000000 loops, best of 3: 811 ns per loop
 sage: %timeit p100*q1000
 1000000 loops, best of 3: 1.44 us per loop
 sage: %timeit p1000*q1000
 1000000 loops, best of 3: 1.61 us per loop
 sage: %timeit hash(p5)
 10000000 loops, best of 3: 132 ns per loop
 sage: %timeit hash(p25)
 10000000 loops, best of 3: 134 ns per loop
 sage: %timeit hash(p50)
 10000000 loops, best of 3: 142 ns per loop
 sage: %timeit hash(p100)
 10000000 loops, best of 3: 155 ns per loop
 sage: %timeit hash(p1000)
 1000000 loops, best of 3: 466 ns per loop
 sage: %timeit p5==s5
 1000000 loops, best of 3: 710 ns per loop
 sage: %timeit p25==s25
 1000000 loops, best of 3: 1.71 us per loop
 sage: %timeit p50==s50
 100000 loops, best of 3: 2.6 us per loop
 sage: %timeit p100==s100
 100000 loops, best of 3: 4.4 us per loop
 sage: %timeit p1000==s1000
 10000 loops, best of 3: 38 us per loop
 sage: %timeit p5==r5
 1000000 loops, best of 3: 692 ns per loop
 sage: %timeit p25==r25
 1000000 loops, best of 3: 715 ns per loop
 sage: %timeit p50==r50
 1000000 loops, best of 3: 724 ns per loop
 sage: %timeit p100==r100
 1000000 loops, best of 3: 729 ns per loop
 sage: %timeit p1000==r1000
 1000000 loops, best of 3: 752 ns per loop
 sage: %timeit q5==r5
 1000000 loops, best of 3: 706 ns per loop
 sage: %timeit q25==r25
 1000000 loops, best of 3: 1.69 us per loop
 sage: %timeit q50==r50
 100000 loops, best of 3: 2.59 us per loop
 sage: %timeit q100==r100
 100000 loops, best of 3: 4.4 us per loop
 sage: %timeit q1000==r1000
 10000 loops, best of 3: 37.6 us per loop
 sage: %timeit q1000.startswith(q100)
 1000000 loops, best of 3: 272 ns per loop
 sage: %timeit q1000.startswith(r100)
 1000000 loops, best of 3: 257 ns per loop
 }}}

 __Using `ctypedef unsigned short block`__

 {{{
 sage: %timeit p5*q5
 1000000 loops, best of 3: 718 ns per loop
 sage: %timeit p5*q25
 1000000 loops, best of 3: 682 ns per loop
 sage: %timeit p25*q25
 1000000 loops, best of 3: 710 ns per loop
 sage: %timeit p25*q50
 1000000 loops, best of 3: 740 ns per loop
 sage: %timeit p50*q50
 1000000 loops, best of 3: 722 ns per loop
 sage: %timeit p50*q100
 1000000 loops, best of 3: 781 ns per loop
 sage: %timeit p100*q100
 1000000 loops, best of 3: 858 ns per loop
 sage: %timeit p100*q1000
 1000000 loops, best of 3: 1.98 us per loop
 sage: %timeit p1000*q1000
 100000 loops, best of 3: 2.17 us per loop
 sage: %timeit hash(p5)
 10000000 loops, best of 3: 132 ns per loop
 sage: %timeit hash(p25)
 10000000 loops, best of 3: 148 ns per loop
 sage: %timeit hash(p50)
 10000000 loops, best of 3: 168 ns per loop
 sage: %timeit hash(p100)
 1000000 loops, best of 3: 206 ns per loop
 sage: %timeit hash(p1000)
 1000000 loops, best of 3: 951 ns per loop
 sage: %timeit p5==s5
 1000000 loops, best of 3: 723 ns per loop
 sage: %timeit p25==s25
 1000000 loops, best of 3: 1.77 us per loop
 sage: %timeit p50==s50
 100000 loops, best of 3: 2.93 us per loop
 sage: %timeit p100==s100
 100000 loops, best of 3: 5.32 us per loop
 sage: %timeit p1000==s1000
 10000 loops, best of 3: 47.5 us per loop
 sage: %timeit p5==r5
 1000000 loops, best of 3: 577 ns per loop
 sage: %timeit p25==r25
 1000000 loops, best of 3: 586 ns per loop
 sage: %timeit p50==r50
 1000000 loops, best of 3: 599 ns per loop
 sage: %timeit p100==r100
 1000000 loops, best of 3: 588 ns per loop
 sage: %timeit p1000==r1000
 1000000 loops, best of 3: 607 ns per loop
 sage: %timeit q5==r5
 1000000 loops, best of 3: 754 ns per loop
 sage: %timeit q25==r25
 1000000 loops, best of 3: 1.87 us per loop
 sage: %timeit q50==r50
 100000 loops, best of 3: 2.89 us per loop
 sage: %timeit q100==r100
 100000 loops, best of 3: 5.28 us per loop
 sage: %timeit q1000==r1000
 10000 loops, best of 3: 47.3 us per loop
 sage: %timeit q1000.startswith(q100)
 1000000 loops, best of 3: 272 ns per loop
 sage: %timeit q1000.startswith(r100)
 1000000 loops, best of 3: 256 ns per loop
 }}}

--
Ticket URL: <http://trac.sagemath.org/ticket/15820#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/groups/opt_out.

Reply via email to