Closed videlec closed 8 years ago
Replying to @mantepse:
As a very casual user of words: I would expect
FiniteOrInfiniteWords
to beWords
...
One problem is that Words
is the name of the factory that dispatch to the actual classes FiniteWords
, InfiniteWords
, FiniteOrInfiniteWords
or Words_n
. Why do you care about the class names? You will never have to do
sage: FiniteOrInfiniteWords(my_alphabet)
OK, great, sorry for the noise!
The fourth item of my previous comment has not been answered.
Branch pushed to git repo; I updated commit sha1. New commits:
fa5ef78 | Trac 19619: remove useless code |
Replying to @seblabbe:
The fourth item of my previous comment has not been answered.
Indeed.
I think this comment inside FiniteWords._word_from_word
+ # this must be put first for the reason that CallableFromListOfWords
+ # inherits from tuple
is unnecessary and date from the time were one method was doing everything for the creation of a word. Then, data could be a tuple or a CallableFromListOfWords
which inherits from tuple explaining the reason we needed to test for isinstance(data, CallableFromListOfWords)
first.
Now, in that method, data is word (not a tuple neither a CallableFromListOfWords
) so the isinstance tests can be done in any order. Question: what is best to test first?
I tried to do my best for FiniteWords._word_from_word
. I also removed _word_from_callable
from FiniteOrInfiniteWords
and simplified its __call__
.
I looked at the code. It looks good. But I now get (also reported by the patchbots):
----------------------------------------------------------------------
sage -t --warn-long 31.0 permutation.py # 1 doctest failed
sage -t --warn-long 31.0 parking_functions.py # 62 doctests failed
----------------------------------------------------------------------
Branch pushed to git repo; I updated commit sha1. New commits:
13e989e | Trac 19619: fix wrong guessing |
Right. Permutations or parking functions are callable but should be considered as finite...
I would prefer if the code of FiniteOrInfiniteWords.__call__
be like the others FiniteWords.__call__
and InfiniteWords.__call__
in the sense that first the function does:
if datatype is not None:
#return directly the good word
if datatype in ['str', 'list', 'char', 'tuple']:
return etc...
else:
#guess the datatype, the length, etc.
if you agree. It makes the code easier to read and be convince anybody that it does the minimal and most efficient path in the function.
Doing what you do in InfiniteWords.__call__
essentially reverts ticket #17021 where that kind of guessing was done first. Note that to avoid duplication of code, it is possible that you will have to recreate _word_from_callable
because of that... or maybe not.
Replying to @seblabbe:
I would prefer if the code of
FiniteOrInfiniteWords.__call__
be like the othersFiniteWords.__call__
andInfiniteWords.__call__
in the sense that first the function does:
<SNIP>
if you agree. It makes the code easier to read and be convince anybody that it does the minimal and most efficient path in the function.
Doing what you do in
InfiniteWords.__call__
essentially reverts ticket #17021 where that kind of guessing was done first. Note that to avoid duplication of code, it is possible that you will have to recreate_word_from_callable
because of that... or maybe not.
If a user provides datatype
and length
there will be no guessing... And with what I changed the first step is to determine the length (in order to determine the parent). I do not see how to handle what you suggested without copy/paste.
Moreover, the length
guessing is based on what the user input as datatype
...
Some timings with the branch
sage: W = Words()
sage: FW = FiniteWords()
sage: L = range(1000)
sage: %timeit W(L, check=False)
100000 loops, best of 3: 2.54 µs per loop
sage: %timeit W(L, length="finite", check=False)
1000000 loops, best of 3: 1.58 µs per loop
sage: %timeit W(L, datatype="list", check=False)
100000 loops, best of 3: 1.75 µs per loop
sage: %timeit W(L, length="finite", datatype="list", check=False)
1000000 loops, best of 3: 1.49 µs per loop
sage: %timeit FW(L, check=False)
1000000 loops, best of 3: 823 ns per loop
Whereas we have on develop
sage: W = Words()
sage: %timeit W(L, check=False)
1000000 loops, best of 3: 800 ns per loop
It looks like the code in the branch is:
FiniteWords
Plenty of reasons: more inheritance, more function calls.Branch pushed to git repo; I updated commit sha1. New commits:
4fd6556 | Trac 19619: merge into 6.10.beta7 |
Good to go.
Great! Thanks for the review!
Changed branch from u/vdelecroix/19619 to 4fd6556
Currently we have too many parent for words:
Words_all
,Words_over_alphabet
,Words_over_OrderedAlphabet
)FiniteWords_over_OrderedAlphabet
)InfiniteWords_over_OrderedAlphabet
)FiniteWords_length_k_over_OrderedAlphabet
andWords_n
)This lead to subtle bug like
The proposal of this ticket is to have only four classes:
FiniteWords
Words_n
: words of lengthn
(as a slice of the one before)InfiniteWords
(orFullShift
)FiniteOrInfiniteWords
The parentFiniteWords
should hence have a method.shift()
that return the associated shift (e.gu ** Infinity
will belong there). Similarly, the parentInfiniteWords
should have a method.factors()
that return the set of factors (and finite slices will belong there).We also:
size_of_alphabet
andhas_letter
lyndon_word.py
Word_char
if possibleCC: @seblabbe
Component: combinatorics
Author: Vincent Delecroix
Branch/Commit:
4fd6556
Reviewer: Sébastien Labbé
Issue created by migration from https://trac.sagemath.org/ticket/19619