docstrings test failures for randomised computations

0 views
Skip to first unread message

Dima Pasechnik

unread,
Jan 29, 2010, 12:59:08 AM1/29/10
to sage-devel
as discussed recently here in connection with GAP interface, the
following looks like an obvious deficiency of docstrings testing: a
computation returns a list in some unpredictable order, and docstrings
are in another order, even though the corresponding sets are the same.

Just sorting the list in Sage does not work, as the object in question
has a state maintained by an external program (e.g. GAP), and messing
up this order is no fun at all.
(well, yes, one can think of maintaining the permutation used for the
sorting, etc etc, but this looks like an unnecessary kludge)

It seems to me that the right way to deal with this is to extend the
capabilities of the testing scheme so that it is able to handle sets,
not only lists.

John H Palmieri

unread,
Jan 29, 2010, 1:06:35 AM1/29/10
to sage-devel

Maybe you can write doctests in one of these forms

sage: set([output from function...]) == set([what the output is
supposed to be])
True

(or use Set instead of set?)

sage: (some known element) in [output from function]
True

sage: convert output to string and do some string comparisons on it

--
John

William Stein

unread,
Jan 29, 2010, 1:09:23 AM1/29/10
to sage-...@googlegroups.com

+1 to John's suggestion to rewrite your tests so that the lists are
sorted in a sensible way. There are many ways to do so as he pointed
out. If we can avoid it, we shouldn't change the Python doctest
framework any more than we already have (which is very minimal).

We could add a function to Sage for testing purposes, such as:

sage: strsort(v)

which would takes it input (any iterable), convert all entries to
strings, then sort, then output the result as a list. Then your
doctests would display that output.

It's good to keep in mind that doctests are meant to be viewed by
people, so tests like the above that maybe aren't so human readable
should go in the

TESTS::

section instead of the EXAMPLES:: section.

-- William

Robert Bradshaw

unread,
Jan 29, 2010, 1:11:47 AM1/29/10
to sage-...@googlegroups.com

The testing scheme (the doctests part at least) is text-based. What
about

sage: tested_function() # random order
set([1, 5, 7, -3, 2, 6])
sage: tested_function() == set([1, 5, 7, -3, 2, 6])
True

- Robert

Nick Alexander

unread,
Jan 29, 2010, 1:17:20 AM1/29/10
to sage-...@googlegroups.com
>> It seems to me that the right way to deal with this is to extend the
>> capabilities of the testing scheme so that it is able to handle sets,
>> not only lists.

-1

> The testing scheme (the doctests part at least) is text-based. What
> about
>
> sage: tested_function() # random order
> set([1, 5, 7, -3, 2, 6])
> sage: tested_function() == set([1, 5, 7, -3, 2, 6])
> True

+1

Nick

Dima Pasechnik

unread,
Jan 30, 2010, 12:27:45 AM1/30/10
to sage-devel
William,
I think TESTS:: would be a good idea!
Having an optional part TESTS:: where one can put more or less any
Sage code; if TESTS:: is present,
EXAMPLES:: is ignored, and otherwise EXAMPLES:: play the role of
TESTS::

Indeed, without this it is impossible to really test, say, a function
that
produces a matrix that is only known up to (unknown) permutations of
rows and columns.
An example of a test that is basically not possible to make
consistently, is
values()
sage/groups/class_function.py
(this function basically returns such a matrix, namely a character
table of a group, for which the
order of conj. classes etc is a priori not known)

Dima

Robert Bradshaw

unread,
Jan 30, 2010, 12:46:10 AM1/30/10
to sage-...@googlegroups.com
On Jan 29, 2010, at 9:27 PM, Dima Pasechnik wrote:

> William,
> I think TESTS:: would be a good idea!
> Having an optional part TESTS:: where one can put more or less any
> Sage code; if TESTS:: is present,
> EXAMPLES:: is ignored, and otherwise EXAMPLES:: play the role of
> TESTS::

We already use TESTS blocks. Both should be tested if both exist.

> Indeed, without this it is impossible to really test, say, a function
> that
> produces a matrix that is only known up to (unknown) permutations of
> rows and columns.
> An example of a test that is basically not possible to make
> consistently, is
> values()
> sage/groups/class_function.py
> (this function basically returns such a matrix, namely a character
> table of a group, for which the
> order of conj. classes etc is a priori not known)

The thing to do here is something like

sage: M = x.values(); M # random permutation
[your matrix here]

then demonstrate that M has the right properties (not sure what they
are in your case, but there should be something you can do that tests
correct matrices from incorrect ones, and as well as making good tests
this kind of thing is mathematically instructive as well).

- Robert

Dima Pasechnik

unread,
Jan 31, 2010, 12:10:34 AM1/31/10
to sage-devel

On Jan 30, 1:46 pm, Robert Bradshaw <rober...@math.washington.edu>
wrote:


> On Jan 29, 2010, at 9:27 PM, Dima Pasechnik wrote:
>
> > William,
> > I think TESTS:: would be a good idea!
> > Having an optional part TESTS:: where one can put more or less any
> > Sage code; if TESTS:: is present,
> > EXAMPLES:: is ignored, and otherwise EXAMPLES:: play the role of
> > TESTS::
>
> We already use TESTS blocks. Both should be tested if both exist.

Is there a docstrings-like option to use in order to tell the system
not to test things in EXAMPLES:: ?

Dima

William Stein

unread,
Jan 31, 2010, 12:15:02 AM1/31/10
to sage-devel
On Sat, Jan 30, 2010 at 9:10 PM, Dima Pasechnik <dim...@gmail.com> wrote:
>
>
> On Jan 30, 1:46 pm, Robert Bradshaw <rober...@math.washington.edu>
> wrote:
>> On Jan 29, 2010, at 9:27 PM, Dima Pasechnik wrote:
>>
>> > William,
>> > I think TESTS:: would be a good idea!
>> > Having an optional part TESTS:: where one can put more or less any
>> > Sage code; if TESTS:: is present,
>> > EXAMPLES:: is ignored, and otherwise EXAMPLES:: play the role of
>> > TESTS::
>>
>> We already use TESTS blocks. Both should be tested if both exist.
>
> Is there a docstrings-like option to use in order to tell the system
> not to test things in EXAMPLES:: ?
>
> Dima

Put "# not tested" as a comment.

That said, unless there is a very, very, very good reason, everything
in EXAMPLES should get tested. It's absolutely terrible to have
examples that don't work precisely the way we say they do in the
documentation. I would definitely not positively review any code
that makes frivolous use of "# not tested".

There is also a "# random" marker that one can put on doctests. It
also should be avoided...

William

Dima Pasechnik

unread,
Feb 2, 2010, 7:07:44 AM2/2/10
to sage-devel

On Jan 31, 1:15 pm, William Stein <wst...@gmail.com> wrote:


> On Sat, Jan 30, 2010 at 9:10 PM, Dima Pasechnik <dimp...@gmail.com> wrote:
>
> > On Jan 30, 1:46 pm, Robert Bradshaw <rober...@math.washington.edu>
> > wrote:
> >> On Jan 29, 2010, at 9:27 PM, Dima Pasechnik wrote:
>
> >> > William,
> >> > I think TESTS:: would be a good idea!
> >> > Having an optional part TESTS:: where one can put more or less any
> >> > Sage code; if TESTS:: is present,
> >> > EXAMPLES:: is ignored, and otherwise EXAMPLES:: play the role of
> >> > TESTS::
>
> >> We already use TESTS blocks. Both should be tested if both exist.
>
> > Is there a docstrings-like option to use in order to tell the system
> > not to test things in EXAMPLES:: ?
>
> > Dima
>
> Put "# not tested" as a comment.
>
> That said, unless there is a very, very, very good reason, everything
> in EXAMPLES should get tested.   It's absolutely terrible to have
> examples that don't work precisely the way we say they do in the
> documentation.    I would definitely not positively review any code
> that makes frivolous use of "# not tested".
>

well, I just test what is in EXAMPLES in TESTS (as string comparison
fails here, I have to write a bit of code to test properly)
It's a bit ugly, but it's a limitation of docstinsg that is impossible
to overcome.

(Please see http://trac.sagemath.org/sage_trac/ticket/8150 for the
corresponding patch)

Dmitrii

YannLC

unread,
Feb 2, 2010, 7:54:31 AM2/2/10
to sage-devel
Why don't you use something like this e.g.:

sage: A.<a,b,c,d,e> = AbelianGroup(5,[4, 5, 5, 7, 8])
sage: b1 = a^3*b*c*d^2*e^5
sage: b2 = a^2*b*c^2*d^3*e^3
sage: b3 = a^7*b^3*c^5*d^4*e^4
sage: b4 = a^3*b^2*c^2*d^3*e^5
sage: b5 = a^2*b^4*c^2*d^4*e^5
sage: word_problem([b1,b2,b3,b4,b5],e) #random order
[[a^3*b*c*d^2*e^5, 1], [a^2*b*c^2*d^3*e^3, 1], [a^3*b^3*d^4*e^4, 3],
[a^2*b^4*c^2*d^4*e^5, 1]]
sage: ans_dict = {a^3*b*c*d^2*e^5: 1, a^2*b*c^2*d^3*e^3: 1,
a^3*b^3*d^4*e^4: 3, a^2*b^4*c^2*d^4*e^5: 1}
sage: dict( word_problem([b1,b2,b3,b4,b5],e) ) == ans_dict # we use
dict to avoid ordering problems
True

(remark: It would make sense for the function word_problem to return a
dict. This would allow:
sage: w = word_problem([b1,b2,b3,b4,b5],e)
sage: w[b3]
3
end of the remark)

Dima Pasechnik

unread,
Feb 2, 2010, 8:25:26 AM2/2/10
to sage-devel

On Feb 2, 8:54 pm, YannLC <yannlaiglecha...@gmail.com> wrote:
> Why don't you use something like this e.g.:
>
> sage: A.<a,b,c,d,e> = AbelianGroup(5,[4, 5, 5, 7, 8])
> sage: b1 = a^3*b*c*d^2*e^5
> sage: b2 = a^2*b*c^2*d^3*e^3
> sage: b3 = a^7*b^3*c^5*d^4*e^4
> sage: b4 = a^3*b^2*c^2*d^3*e^5
> sage: b5 = a^2*b^4*c^2*d^4*e^5
> sage:  word_problem([b1,b2,b3,b4,b5],e) #random order
> [[a^3*b*c*d^2*e^5, 1], [a^2*b*c^2*d^3*e^3, 1], [a^3*b^3*d^4*e^4, 3],
> [a^2*b^4*c^2*d^4*e^5, 1]]
> sage: ans_dict = {a^3*b*c*d^2*e^5: 1, a^2*b*c^2*d^3*e^3: 1,
> a^3*b^3*d^4*e^4: 3, a^2*b^4*c^2*d^4*e^5: 1}
> sage: dict( word_problem([b1,b2,b3,b4,b5],e) ) == ans_dict  # we use
> dict to avoid ordering problems
> True
>

As always, a better working solution only comes after at least one
working solution has been already presented :-)

Yes, indeed, it makes perfect sense to use dictionaries here.

Unfortunately for irreducible characters (see groups/
class_function.py patch)
reduce seems to be the only way so far :-(


> (remark: It would make sense for the function word_problem to return a
> dict. This would allow:
> sage: w = word_problem([b1,b2,b3,b4,b5],e)
> sage: w[b3]
> 3
> end of the remark)
>

yes, this is a good idea.

YannLC

unread,
Feb 2, 2010, 9:01:08 AM2/2/10
to sage-devel
Maybe just using sets:

sage: G = GL(2,3)
sage: k.<zeta8> = CyclotomicField(8)
sage: expected = set([(3, 0, 3, 0, -1, 1, 1, -1), (1, 1, 1, 1, 1, 1,
1, 1), (1, 1, 1, 1, 1, -1, -1, -1), (2, -1, 2, -1, 2, 0, 0, 0), (4,
-1, -4, 1, 0, 0, 0, 0), (2, 1, -2, -1, 0, zeta8^3 + zeta8, -zeta8^3 -
zeta8, 0), (2, 1, -2, -1, 0, -zeta8^3 - zeta8, zeta8^3 + zeta8, 0),
(3, 0, 3, 0, -1, -1, -1, 1)])
sage: set([tuple(x.values()) for x in G.irreducible_characters()]) ==
expected
True

Dima Pasechnik

unread,
Feb 2, 2010, 9:50:33 AM2/2/10
to sage-devel
G.irreducible_characters() is a list of lists, not a list of tuples,
so one cannot just
take set() of them.

YannLC

unread,
Feb 2, 2010, 9:53:24 AM2/2/10
to sage-devel
Read again my proposal

sage: set([tuple(x.values()) for x in G.irreducible_characters()]) ==
expected

you need tuple... just add it!

Dima Pasechnik

unread,
Feb 2, 2010, 10:25:08 AM2/2/10
to sage-devel
yeah, you're right, sorry --- my workday started 14 hours ago...
OK, I'll follow your hint, thanks!

Robert Bradshaw

unread,
Feb 2, 2010, 12:46:18 PM2/2/10
to sage-...@googlegroups.com
On Feb 2, 2010, at 6:50 AM, Dima Pasechnik wrote:

> G.irreducible_characters() is a list of lists, not a list of tuples,
> so one cannot just take set() of them.

On another note, for both this and word problem, you might want to
consider whether a list of tuples would be better to return than a
list of lists... do they need to be mutable?

- Robert

>
> On Feb 2, 10:01 pm, YannLC <yannlaiglecha...@gmail.com> wrote:
>> Maybe just using sets:
>>
>> sage: G = GL(2,3)
>> sage: k.<zeta8> = CyclotomicField(8)
>> sage: expected = set([(3, 0, 3, 0, -1, 1, 1, -1), (1, 1, 1, 1, 1, 1,
>> 1, 1), (1, 1, 1, 1, 1, -1, -1, -1), (2, -1, 2, -1, 2, 0, 0, 0), (4,
>> -1, -4, 1, 0, 0, 0, 0), (2, 1, -2, -1, 0, zeta8^3 + zeta8, -zeta8^3 -
>> zeta8, 0), (2, 1, -2, -1, 0, -zeta8^3 - zeta8, zeta8^3 + zeta8, 0),
>> (3, 0, 3, 0, -1, -1, -1, 1)])
>> sage: set([tuple(x.values()) for x in G.irreducible_characters()]) ==
>> expected
>> True
>>
>> On Feb 2, 2:25 pm, Dima Pasechnik <dimp...@gmail.com> wrote:
>>
>>
>>
>>> On Feb 2, 8:54 pm, YannLC <yannlaiglecha...@gmail.com> wrote:
>>> Unfortunately for irreducible characters (see groups/
>>> class_function.py patch)
>>> reduce seems to be the only way so far :-(
>

> --
> To post to this group, send an email to sage-...@googlegroups.com
> To unsubscribe from this group, send an email to sage-devel+...@googlegroups.com
> For more options, visit this group at http://groups.google.com/group/sage-devel
> URL: http://www.sagemath.org

Reply all
Reply to author
Forward
0 new messages