Dear all,

On Fri, Jan 23, 2009 at 12:41:31PM -0800, William Stein wrote:
> ... discussion about the right way of testing __hash__
>
> Doctesting of __hash__ should be done by a function:
> 
>    sage: test.hash(GF(3^4, 'a'))
>    'ok'  # or not raise exception
> 
> The advantages of doing this:
> 
>    (1) It is readable -- it's clear what is being done -- a function
> made for testing hashing is read.
> 
>    (2) it centralizes the design decision about what the actual test
> should be.  One huge objection to you changing all the doctests in
> your files, is that they are now inconsistent with the rest of sage,
> which is very jarring for readers (it certainly was for me).
> 
>    (3) it enables all kinds of interestings tests to be put in
> test.hash.  For example, suppose I wonder if there are any objects in
> Sage with the property that calling hash multiple times doesn't get
> "very fast" after the first call (e.g, the bug in your
> finite_field_givaro.pyx hash that I fixed). I can easily just change
> test.hash to test for that, run the test suite, and it will tell me
> everywhere this happens.   Or suppose I want to hunt for instances
> where hashing is inconsistent (doesn't always return the same thing on
> 10 calls say) -- again that's easy.   Suppose we decide that
> set([GF(3^4,'a'))]) is a good test -- we could trivially add that.

I just want to mention that I am precisely setting up a standardized
way in the category framework for setting up this kind of generic
tests. See in particular Sets? after installing the sage-combinat
patches. Comments, suggestions and reviews most welcome!

General idea: Imagine you have just implemented a parent P in the
category SemiGroups(). Here, I'll just take the example of semi-group
provided by the category:

    sage: P = SemiGroups().example()
    The trivial semigroup with a*b == a

(for the record, this line above is fake, but it will actually work
very soon; by the way: should this be called a_parent() or something else?)

Now, you want to run generic checks on P. You can just do:

    sage: P.check(verbose = True)
    running test_an_element ...
    running test_some_elements ...
    running test_pickling ...
    running test_element_pickling ...
    running test_associativity ...

If you want to run individual tests, you can do directly:

    sage: P.test_associativity()

In case something goes wrong (which is the case currently, bummer),
you get a traceback:

    sage: P.check()
    PicklingError                             Traceback (most recent call last)
    ...
    PicklingError: Can't pickle ...


Let's open the hood. Here is the default implementation for
test_associativity, which is provided by the SemiGroups category:

        def test_associativity(self, tester = trivial_tester):
            tester.assert_(all((x * y) * z == x * (y * z)
                               for x in self.some_elements()
                               for y in self.some_elements()
                               for z in self.some_elements()))


The tester gadget is a plugin mechanism so that in the long run one
will be able to ask for other treatment of errors, like issuing
warnings, counting the errors, or using the test case within a
standard testunit framework.

some_elements is a method, similar to an_element, which returns a
"good" collection of elements, typically to run tests upon. What
"good" means is left upon the parent implementer, but there are some
reasonable defaults (like returning all the elements for a finite
group, or all the basis elements for a finite dimensional vector
space). Of course, there should be an easy way for the user to specify
on which sets he wants to run the tests, so as to use this method for
proofs.


P.check() (should it be P.test()?) just calls every methods of the
parent called test* (parallel to what is done in testunit). So the
parent may very well add extra test cases, or override some of them
with more efficient ones.

To come back to __hash__, a sane default might be to check that
__hash__ at least returns something different for each element in
P.some_elements() (I am not sure about the specs of __hash__; should
we also check that __hash__ returns an int?).

Best regards,
                                Nicolas
--
Nicolas M. ThiƩry "Isil" <nthi...@users.sf.net>
http://Nicolas.Thiery.name/

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

Reply via email to