Sage: Ticket #6484: sage.combinat.ranker improvements
https://trac.sagemath.org/ticket/6484
<p>
sage.combinat.ranker needs improvements:
</p>
<ul><li> With:
<pre class="wiki">sage: f = sage.combinat.ranker.rank_from_list([...])
</pre></li></ul><blockquote>
<blockquote>
<p>
f uses <code>list.index</code>, and is therefore <code>O(n)</code>. This should be made <code>O(1)</code> with a hash table.
</p>
</blockquote>
</blockquote>
<p>
Further potential improvement (for a later ticket?):
</p>
<ul><li>make the rank / unrank objects produced by this library picklable.
</li></ul>en-usSagehttps://trac.sagemath.org/chrome/site/logo_sagemath_trac.png
https://trac.sagemath.org/ticket/6484
Trac 1.1.6jdemeyerTue, 13 Aug 2013 15:35:53 GMTmilestone changed
https://trac.sagemath.org/ticket/6484#comment:1
https://trac.sagemath.org/ticket/6484#comment:1
<ul>
<li><strong>milestone</strong>
changed from <em>sage-5.11</em> to <em>sage-5.12</em>
</li>
</ul>
Ticketvbraun_spamThu, 30 Jan 2014 21:20:52 GMTmilestone changed
https://trac.sagemath.org/ticket/6484#comment:2
https://trac.sagemath.org/ticket/6484#comment:2
<ul>
<li><strong>milestone</strong>
changed from <em>sage-6.1</em> to <em>sage-6.2</em>
</li>
</ul>
Ticketvbraun_spamTue, 06 May 2014 15:20:58 GMTmilestone changed
https://trac.sagemath.org/ticket/6484#comment:3
https://trac.sagemath.org/ticket/6484#comment:3
<ul>
<li><strong>milestone</strong>
changed from <em>sage-6.2</em> to <em>sage-6.3</em>
</li>
</ul>
Ticketvbraun_spamSun, 10 Aug 2014 16:51:03 GMTmilestone changed
https://trac.sagemath.org/ticket/6484#comment:4
https://trac.sagemath.org/ticket/6484#comment:4
<ul>
<li><strong>milestone</strong>
changed from <em>sage-6.3</em> to <em>sage-6.4</em>
</li>
</ul>
TicketnthieryMon, 27 Apr 2015 17:25:16 GMTbranch set
https://trac.sagemath.org/ticket/6484#comment:5
https://trac.sagemath.org/ticket/6484#comment:5
<ul>
<li><strong>branch</strong>
set to <em>u/nthiery/sage_combinat_ranker_improvements</em>
</li>
</ul>
TicketnthieryMon, 27 Apr 2015 17:27:17 GMTstatus, description changed; commit, upstream set
https://trac.sagemath.org/ticket/6484#comment:6
https://trac.sagemath.org/ticket/6484#comment:6
<ul>
<li><strong>status</strong>
changed from <em>new</em> to <em>needs_review</em>
</li>
<li><strong>commit</strong>
set to <em>32d5cea664e153895d663b5913e45d03b8c0a305</em>
</li>
<li><strong>description</strong>
modified (<a href="/ticket/6484?action=diff&version=6">diff</a>)
</li>
<li><strong>upstream</strong>
set to <em>N/A</em>
</li>
</ul>
<p>
New commits:
</p>
<table class="wiki">
<tr><td><a class="ext-link" href="http://git.sagemath.org/sage.git/commit/?id=32d5cea664e153895d663b5913e45d03b8c0a305"><span class="icon"></span>32d5cea</a></td><td><code>6484: implementation of sage.combinat.ranker.rank_from_list to be constant time</code>
</td></tr></table>
TicketnthieryMon, 27 Apr 2015 17:28:02 GMT
https://trac.sagemath.org/ticket/6484#comment:7
https://trac.sagemath.org/ticket/6484#comment:7
<p>
This is essentially <code></code>trac_6484-ranker-improvements-nt.patch<code></code> from the Sage-Combinat queue, with further cleanup and doc.
</p>
TicketnthieryMon, 27 Apr 2015 17:29:10 GMTdescription changed
https://trac.sagemath.org/ticket/6484#comment:8
https://trac.sagemath.org/ticket/6484#comment:8
<ul>
<li><strong>description</strong>
modified (<a href="/ticket/6484?action=diff&version=8">diff</a>)
</li>
</ul>
<p>
Should we worry about backward compatibility and revert to l.index if any of the object is not hashable?
</p>
TicketnthieryMon, 27 Apr 2015 17:32:27 GMT
https://trac.sagemath.org/ticket/6484#comment:9
https://trac.sagemath.org/ticket/6484#comment:9
<p>
How much do we care about picklability right now? I am not sure how to implement it. On the other hand, fast rank would be very useful for <a class="new ticket" href="https://trac.sagemath.org/ticket/18311" title="enhancement: Improve radical_basis and cartan_invariants_matrix for a finite ... (new)">#18311</a>, ...
</p>
TicketnthieryMon, 27 Apr 2015 17:32:56 GMTcc, author changed
https://trac.sagemath.org/ticket/6484#comment:10
https://trac.sagemath.org/ticket/6484#comment:10
<ul>
<li><strong>cc</strong>
<em>tscrim</em> <em>hivert</em> <em>virmaux</em> added
</li>
<li><strong>author</strong>
changed from <em>nthiery</em> to <em>Nicolas M. Thiéry</em>
</li>
</ul>
TickettscrimMon, 27 Apr 2015 17:46:56 GMT
https://trac.sagemath.org/ticket/6484#comment:11
https://trac.sagemath.org/ticket/6484#comment:11
<p>
I'm okay with the hashability as we assume all elements to be hashable, nor is picklability important to me. However this now makes <code>rank_from_list</code> to be the <code>O(n)</code> function, and the function itself is not cached. So for large lists (or worse, say for a crystal where iteration is relatively expensive), this could lead to a pretty large slowdown. How about we just return the original implementation of <code>rank</code> as a cached function?
</p>
TicketnthieryMon, 27 Apr 2015 20:06:46 GMT
https://trac.sagemath.org/ticket/6484#comment:12
https://trac.sagemath.org/ticket/6484#comment:12
<blockquote>
<p>
I Travis!
</p>
</blockquote>
<p>
Replying to <a class="ticket" href="https://trac.sagemath.org/ticket/6484#comment:11" title="Comment 11">tscrim</a>:
</p>
<blockquote class="citation">
<p>
I'm okay with the hashability as we assume all elements to be hashable
</p>
</blockquote>
<p>
Well, this hashabilitiy assumption was not there before this ticket. So technically speaking that's a backward incompatible change. I agree that in all use cases I can think of, the objects are hashable, so it probably is not a big deal.
</p>
<blockquote class="citation">
<p>
, nor is picklability important to me. However this now makes <code>rank_from_list</code> to be the <code>O(n)</code> function, and the function itself is not cached. So for large lists (or worse, say for a crystal where iteration is relatively expensive), this could lead to a pretty large slowdown. How about we just return the original implementation of <code>rank</code> as a cached function?
</p>
</blockquote>
<p>
When <code>rank_from_list</code> is called, that's usually with the intention of calling it intensively afterward; in particular the ranker is typically stored in the calling object for all later reuse. At least, that's the case in all the current calls in the Sage library.
</p>
<p>
Being completely lazy and implementhing <code>rank_from_list</code> as a cached function on top of <code>list.index</code> would imply an overhead of <code>O(n^2)</code> instead of <code>O(n)</code> before we reach the limit state where the complexity in <code>O(1)</code>; not great. We could introduce some partial lazyness, making sure that the first time an object <code>x</code> is looked up, the cache is set for all objects before <code>x</code> in the list. What do you think? Is it worth it?
</p>
<p>
A note: the name <code>from_list</code> makes it relatively explicit that the iterable will be expanded anyway.
</p>
<p>
Cheers,
</p>
<blockquote>
<p>
Nicolas
</p>
</blockquote>
TicketgitMon, 27 Apr 2015 20:22:15 GMTcommit changed
https://trac.sagemath.org/ticket/6484#comment:13
https://trac.sagemath.org/ticket/6484#comment:13
<ul>
<li><strong>commit</strong>
changed from <em>32d5cea664e153895d663b5913e45d03b8c0a305</em> to <em>220cf7c58941afb5e775842da73e2291a800e0d9</em>
</li>
</ul>
<p>
Branch pushed to git repo; I updated commit sha1. New commits:
</p>
<table class="wiki">
<tr><td><a class="ext-link" href="http://git.sagemath.org/sage.git/commit/?id=220cf7c58941afb5e775842da73e2291a800e0d9"><span class="icon"></span>220cf7c</a></td><td><code>6484: make rank_from_list's ValueError message for string objects identical to the previous one</code>
</td></tr></table>
TicketnthieryMon, 27 Apr 2015 20:23:38 GMT
https://trac.sagemath.org/ticket/6484#comment:14
https://trac.sagemath.org/ticket/6484#comment:14
<p>
This should fix the single error reported by the patchbot.
</p>
TickettscrimTue, 28 Apr 2015 04:59:57 GMT
https://trac.sagemath.org/ticket/6484#comment:15
https://trac.sagemath.org/ticket/6484#comment:15
<p>
True, that would end up being <code>O(n^2)</code>. Since this seems to only be used in 2 places, <code>combinat.free_module.py</code> and <code>sets.finite_set_maps.py</code>, and in both places, the resulting function is cached, I think this would be okay as is. However, would you mind putting a warning about repeatedly recreating the function?
</p>
TicketvdelecroixTue, 28 Apr 2015 21:18:04 GMT
https://trac.sagemath.org/ticket/6484#comment:16
https://trac.sagemath.org/ticket/6484#comment:16
<p>
You know that with <code>@cached_function</code> instead of a plain dictionary you are building a 2-tuple containg a tuple enclosing the object and an empty tuple?
</p>
<pre class="wiki">sage: r = rank_from_list(range(10))
sage: r.get_cache()
{((0,), ()): 0,
((1,), ()): 1,
((2,), ()): 2,
((3,), ()): 3,
((4,), ()): 4,
((5,), ()): 5,
((6,), ()): 6,
((7,), ()): 7,
((8,), ()): 8,
((9,), ()): 9}
</pre><p>
What is wrong with
</p>
<pre class="wiki">def rank_from_list(l):
my_dict = {j:i for i,j in enumerate(l)}
def rank(i):
return my_dict[i]
</pre><p>
It is not very clean, but at least cleaner. And also faster by the way.
</p>
<p>
Vincent
</p>
TicketnthieryThu, 30 Apr 2015 07:55:51 GMT
https://trac.sagemath.org/ticket/6484#comment:17
https://trac.sagemath.org/ticket/6484#comment:17
<p>
Ah, good point; I thought our cached functions had a special case for
one parameter functions. Other than that, using a cached function was
mostly a (failed) attempt at having something picklable as well.
</p>
<p>
So, let's see about speed with various implementations:
</p>
<pre class="wiki">sage: l = range(100);
sage: d = { x:i for i,x in enumerate(l) }
sage: @cached_function
....: def rank_cached(): pass
sage: for i,x in enumerate(l):
....: rank_cached.set_cache(i, x)
sage: def rank_dict(x):
....: return d[x]
sage: rank_dict_getitem = d.__getitem__
sage: cython("""
l = range(100);
d = { x:i for i,x in enumerate(l) }
cpdef int rank_dict_cython(x):
return d[x]
""")
sage: cython("""
l = range(100);
d = { x:i for i,x in enumerate(l) }
cpdef int rank_dict_cython_exception(x):
try:
return d[x]
except KeyError:
raise ValueError("%s is not blah blah blah"%x)
""")
sage: cython("""
cdef class RankFromList(dict):
def __call__(self, x):
try:
return self[x]
except KeyError:
raise ValueError("%s is not blah blah blah"%x)
""")
sage: rank_dict_cython_class = RankFromList((x,i) for i,x in enumerate(l))
</pre><p>
Here are the timings, in decreasing order:
</p>
<pre class="wiki">sage: sage: %timeit rank_cached(50)
The slowest run took 41.96 times longer than the fastest. This could mean that an intermediate result is being cached
1000000 loops, best of 3: 381 ns per loop
sage: sage: %timeit rank_dict(50)
The slowest run took 15.56 times longer than the fastest. This could mean that an intermediate result is being cached
1000000 loops, best of 3: 245 ns per loop
sage: sage: %timeit rank_dict_cython_class(50)
The slowest run took 22.12 times longer than the fastest. This could mean that an intermediate result is being cached
1000000 loops, best of 3: 226 ns per loop
sage: sage: %timeit rank_dict_cython_exception(50)
The slowest run took 36.63 times longer than the fastest. This could mean that an intermediate result is being cached
1000000 loops, best of 3: 195 ns per loop
sage: sage: %timeit rank_dict_cython(50)
The slowest run took 31.18 times longer than the fastest. This could mean that an intermediate result is being cached
1000000 loops, best of 3: 191 ns per loop
sage: sage: %timeit rank_dict_getitem(50)
The slowest run took 17.96 times longer than the fastest. This could mean that an intermediate result is being cached
1000000 loops, best of 3: 173 ns per loop
</pre><p>
Those timing seem to be consistent from one call to the other. Most of
the time this feature is used with non trivial objects where the
bottleneck is the computation of hash/equality of the objects. So we
don't necessarily need to optimize to the last bit.
</p>
<p>
In view of the above, the fastest is to return the <code>__getitem__</code>
method of the dictionary. The main caveat is that we don't have
control on the exception (a <code>KeyError</code> instead of a
<code>ValueError</code>). Maybe it is not so bad since a <code>KeyError</code> is a special
kind of <code>ValueError</code>.
</p>
<p>
The most flexible is to use a class. In particular, this would make
the ranker picklable (this can be useful: I have had cases where an
object would not pickle properly because one of it's attribute was a
ranker). This also opens the door for reintroducing laziness later
on. It's 30% slower than <code>getitem</code> which could be acceptable (I was in
fact expecting a smaller overhead; maybe I missed something in the
cythonization).
</p>
<p>
What do you think?
</p>
<p>
Cheers,
</p>
<blockquote>
<p>
Nicolas
</p>
</blockquote>
TicketvdelecroixThu, 30 Apr 2015 08:33:37 GMT
https://trac.sagemath.org/ticket/6484#comment:18
https://trac.sagemath.org/ticket/6484#comment:18
<p>
If pickling is an issue then I would go for <code>cdef class RankFromList</code> but with a more appropriated name. It is not possible to set <code>tp_getitem = tp_call</code> since the signatures are different.
</p>
<p>
If you create a Cython class, then please replace the <code>sage.combinat.words.morphism.CallableDict</code> with the new one.
</p>
<p>
Vincent
</p>
TicketgitSun, 03 May 2015 23:17:33 GMTcommit changed
https://trac.sagemath.org/ticket/6484#comment:19
https://trac.sagemath.org/ticket/6484#comment:19
<ul>
<li><strong>commit</strong>
changed from <em>220cf7c58941afb5e775842da73e2291a800e0d9</em> to <em>d50b0c5721d1ffc28be1eca451dd1e6a6786e84c</em>
</li>
</ul>
<p>
Branch pushed to git repo; I updated commit sha1. New commits:
</p>
<table class="wiki">
<tr><td><a class="ext-link" href="http://git.sagemath.org/sage.git/commit/?id=d50b0c5721d1ffc28be1eca451dd1e6a6786e84c"><span class="icon"></span>d50b0c5</a></td><td><code>6484: extract and Cythonize CallableDict from sage.combinat.words.morphism and use it in sage.combinat.ranker.rank_from_list</code>
</td></tr></table>
TicketgitSun, 03 May 2015 23:30:48 GMTcommit changed
https://trac.sagemath.org/ticket/6484#comment:20
https://trac.sagemath.org/ticket/6484#comment:20
<ul>
<li><strong>commit</strong>
changed from <em>d50b0c5721d1ffc28be1eca451dd1e6a6786e84c</em> to <em>584209beeb7a7785d78cd24ac89c0aff04499bb9</em>
</li>
</ul>
<p>
Branch pushed to git repo; I updated commit sha1. New commits:
</p>
<table class="wiki">
<tr><td><a class="ext-link" href="http://git.sagemath.org/sage.git/commit/?id=584209beeb7a7785d78cd24ac89c0aff04499bb9"><span class="icon"></span>584209b</a></td><td><code>6484: extract and Cythonize CallableDict from sage.combinat.words.morphism and use it in sage.combinat.ranker.rank_from_list</code>
</td></tr></table>
TicketgitSun, 03 May 2015 23:39:53 GMTcommit changed
https://trac.sagemath.org/ticket/6484#comment:21
https://trac.sagemath.org/ticket/6484#comment:21
<ul>
<li><strong>commit</strong>
changed from <em>584209beeb7a7785d78cd24ac89c0aff04499bb9</em> to <em>5adb28949227305b4ace3a15675549554f237a4b</em>
</li>
</ul>
<p>
Branch pushed to git repo; I updated commit sha1. New commits:
</p>
<table class="wiki">
<tr><td><a class="ext-link" href="http://git.sagemath.org/sage.git/commit/?id=5adb28949227305b4ace3a15675549554f237a4b"><span class="icon"></span>5adb289</a></td><td><code>Merge remote-tracking branch 'origin/develop' into combinat/rank_cached-6484</code>
</td></tr></table>
TicketvdelecroixMon, 04 May 2015 06:24:33 GMTstatus changed
https://trac.sagemath.org/ticket/6484#comment:22
https://trac.sagemath.org/ticket/6484#comment:22
<ul>
<li><strong>status</strong>
changed from <em>needs_review</em> to <em>needs_info</em>
</li>
</ul>
<p>
Hello,
</p>
<p>
The final picture looks good. One good thing would be to clean the git history.
</p>
<p>
The fastest way to create a dictionary from a list is
</p>
<pre class="wiki">cdef dict d = {x:i for i,x in enumerate(l)}
</pre><p>
I guess it avoids the creation of the pair <code>(i,x)</code>.
</p>
<p>
The documentation can be more precise
</p>
<pre class="wiki">No error is issued in case of duplicate value in ``l``. Instead,
the rank function returns the position of some of the duplicates::
</pre><p>
The rank of the <strong>last value</strong> is returned not just <strong>some</strong>. It would possible to use <code>PyDict_MergeFromSeq2</code> to return the first though. But it is not clear to me that it is what we want.
</p>
<p>
Sided note: I am pretty sure that with <a class="closed ticket" href="https://trac.sagemath.org/ticket/18330" title="defect: Metaclasses for Cython (closed: fixed)">#18330</a> that something better can be done so that <code>__call__</code> becomes as fast as <code>__getitem__</code> (up to a C function call). But not for this ticket.
</p>
<p>
Vincent
</p>
TicketgitMon, 04 May 2015 20:30:12 GMTcommit changed
https://trac.sagemath.org/ticket/6484#comment:23
https://trac.sagemath.org/ticket/6484#comment:23
<ul>
<li><strong>commit</strong>
changed from <em>5adb28949227305b4ace3a15675549554f237a4b</em> to <em>6fdc7e5e63016dadc4bab6bfbc47e5a5c0c0e662</em>
</li>
</ul>
<p>
Branch pushed to git repo; I updated commit sha1. New commits:
</p>
<table class="wiki">
<tr><td><a class="ext-link" href="http://git.sagemath.org/sage.git/commit/?id=6fdc7e5e63016dadc4bab6bfbc47e5a5c0c0e662"><span class="icon"></span>6fdc7e5</a></td><td><code>6484: minor documentation improvements</code>
</td></tr></table>
TicketnthieryMon, 04 May 2015 20:31:14 GMT
https://trac.sagemath.org/ticket/6484#comment:24
https://trac.sagemath.org/ticket/6484#comment:24
<p>
Replying to <a class="ticket" href="https://trac.sagemath.org/ticket/6484#comment:22" title="Comment 22">vdelecroix</a>:
</p>
<blockquote class="citation">
<p>
The fastest way to create a dictionary from a list is
</p>
<pre class="wiki">cdef dict d = {x:i for i,x in enumerate(l)}
</pre><p>
I guess it avoids the creation of the pair <code>(i,x)</code>.
</p>
</blockquote>
<p>
I hesitated about this; however we are creating a <code>CallableDict</code> not a
dict at the end. So using this notation means we are first
constructing a dictionary and then copying it into the <code>CallableDict</code>.
This is indeed slightly faster for lists of trivial objects:
</p>
<pre class="wiki">sage: l = range(1000)
sage: %timeit rank_from_list(l) # using generator expression
1000 loops, best of 3: 145 µs per loop
sage: %timeit rank_from_list(l) # using {...}
10000 loops, best of 3: 109 µs per loop
</pre><p>
But not anymore for lists of objects with non trivial hash/eq:
</p>
<pre class="wiki">sage: l = list(Permutations(8))
sage: %timeit rank_from_list(l) # using generator expression
The slowest run took 10.96 times longer than the fastest. This could mean that an intermediate result is being cached
1 loops, best of 3: 18.8 ms per loop
sage: %timeit rank_from_list(l) # using {..}
The slowest run took 10.08 times longer than the fastest. This could mean that an intermediate result is being cached
1 loops, best of 3: 21.7 ms per loop
</pre><p>
Note that we can hope for the generator expression to be optimized in
the long run when ranker.py will be cythonized.
</p>
<blockquote class="citation">
<p>
The documentation can be more precise
</p>
<pre class="wiki">No error is issued in case of duplicate value in ``l``. Instead,
the rank function returns the position of some of the duplicates::
</pre><p>
The rank of the <strong>last value</strong> is returned not just <strong>some</strong>.
</p>
</blockquote>
<p>
This is on purpose: I don't want to set this behavior in stone, in
order to leave room for future reimplementations. In any cases it's
explicitly said that this function is meant for lists without
duplicates.
</p>
<blockquote class="citation">
<p>
Sided note: I am pretty sure that with <a class="closed ticket" href="https://trac.sagemath.org/ticket/18330" title="defect: Metaclasses for Cython (closed: fixed)">#18330</a> that something better can be done so that <code>__call__</code> becomes as fast as <code>__getitem__</code> (up to a C function call). But not for this ticket.
</p>
</blockquote>
<p>
Great!
</p>
<hr />
<p>
New commits:
</p>
<table class="wiki">
<tr><td><a class="ext-link" href="http://git.sagemath.org/sage.git/commit/?id=6fdc7e5e63016dadc4bab6bfbc47e5a5c0c0e662"><span class="icon"></span>6fdc7e5</a></td><td><code>6484: minor documentation improvements</code>
</td></tr></table>
TicketvdelecroixTue, 05 May 2015 06:50:35 GMTstatus changed; reviewer set
https://trac.sagemath.org/ticket/6484#comment:25
https://trac.sagemath.org/ticket/6484#comment:25
<ul>
<li><strong>status</strong>
changed from <em>needs_info</em> to <em>needs_work</em>
</li>
<li><strong>reviewer</strong>
set to <em>Vincent Delecroix</em>
</li>
</ul>
<pre class="wiki">sage -t --long src/sage/sets/finite_set_map_cy.pyx
**********************************************************************
File "src/sage/sets/finite_set_map_cy.pyx", line 491,
in sage.sets.finite_set_map_cy.FiniteSetMap_Set.setimage
Failed example:
with fs.clone() as fs3:
fs3.setimage("z", 2)
Expected:
Traceback (most recent call last):
...
ValueError: 'z' is not in list
Got:
Traceback (most recent call last):
....
ValueError: 'z' is not in dict
**********************************************************************
File "src/sage/sets/finite_set_map_cy.pyx", line 497,
in sage.sets.finite_set_map_cy.FiniteSetMap_Set.setimage
Failed example:
with fs.clone() as fs3:
fs3.setimage(1, 4)
Expected:
Traceback (most recent call last):
...
ValueError: 1 is not in list
Got:
Traceback (most recent call last):
...
ValueError: 1 is not in dict
</pre>
TicketgitTue, 05 May 2015 08:25:07 GMTcommit changed
https://trac.sagemath.org/ticket/6484#comment:26
https://trac.sagemath.org/ticket/6484#comment:26
<ul>
<li><strong>commit</strong>
changed from <em>6fdc7e5e63016dadc4bab6bfbc47e5a5c0c0e662</em> to <em>27189ca136b4045619df60093647341119fc1098</em>
</li>
</ul>
<p>
Branch pushed to git repo; I updated commit sha1. New commits:
</p>
<table class="wiki">
<tr><td><a class="ext-link" href="http://git.sagemath.org/sage.git/commit/?id=27189ca136b4045619df60093647341119fc1098"><span class="icon"></span>27189ca</a></td><td><code>6484: trivial doctest update</code>
</td></tr></table>
TicketnthieryTue, 05 May 2015 08:27:50 GMTstatus changed
https://trac.sagemath.org/ticket/6484#comment:27
https://trac.sagemath.org/ticket/6484#comment:27
<ul>
<li><strong>status</strong>
changed from <em>needs_work</em> to <em>needs_review</em>
</li>
</ul>
<p>
Ah, shoot, I knew I had to update the doctests there ... Thanks for the report. Fixed!
</p>
<p>
Speaking of patchbot blues: do we care about lazy importing the module? Or should it be <code>words</code> and <code>ranker</code> that should be lazy imported in the first place? Also, I am surprised about the warning about non ascii character given that I declared the encoding of the file to be utf-8.
</p>
TicketnthieryTue, 05 May 2015 08:41:08 GMT
https://trac.sagemath.org/ticket/6484#comment:28
https://trac.sagemath.org/ticket/6484#comment:28
<p>
For the record: I opened an issue about the false positive report by the ascii plugin of the patchbot: <a class="ext-link" href="https://github.com/robertwb/sage-patchbot/issues/65"><span class="icon"></span>https://github.com/robertwb/sage-patchbot/issues/65</a>
</p>
TicketvdelecroixTue, 05 May 2015 14:16:07 GMTstatus changed
https://trac.sagemath.org/ticket/6484#comment:29
https://trac.sagemath.org/ticket/6484#comment:29
<ul>
<li><strong>status</strong>
changed from <em>needs_review</em> to <em>positive_review</em>
</li>
</ul>
TicketvbraunWed, 06 May 2015 21:03:26 GMTstatus, branch changed; resolution set
https://trac.sagemath.org/ticket/6484#comment:30
https://trac.sagemath.org/ticket/6484#comment:30
<ul>
<li><strong>status</strong>
changed from <em>positive_review</em> to <em>closed</em>
</li>
<li><strong>resolution</strong>
set to <em>fixed</em>
</li>
<li><strong>branch</strong>
changed from <em>u/nthiery/sage_combinat_ranker_improvements</em> to <em>27189ca136b4045619df60093647341119fc1098</em>
</li>
</ul>
Ticket