Ticket #9880: trac_9880_randomized_testing-sage_5_10_beta2.patch

File trac_9880_randomized_testing-sage_5_10_beta2.patch, 7.8 KB (added by burcin, 8 years ago)
  • sage/symbolic/random_tests.py

    # HG changeset patch
    # User Volker Braun <vbraun@stp.dias.ie>
    # Date 1308098188 25200
    # Node ID a28c161b3e1d64e11db6025e51b8169a932cf06f
    # Parent  7df8578a7485990d3c6dbb49b94c16b352c5781d
    Trac #9880: Randomized testing of the PyNaC sort order.
    
    This patch adds a test that the PyNaC sort order is a
    strict weak ordering.
    
    diff --git a/sage/symbolic/random_tests.py b/sage/symbolic/random_tests.py
    a b  
     1"""
     2Randomized tests of GiNaC / PyNaC.
     3"""
     4
     5###############################################################################
     6#   Sage: Open Source Mathematical Software
     7#       Copyright (C) 2008 William Stein <wstein@gmail.com>
     8#       Copyright (C) 2008 Burcin Erocal <burcin@erocal.org>
     9#  Distributed under the terms of the GNU General Public License (GPL),
     10#  version 2 or any later version.  The full text of the GPL is available at:
     11#                  http://www.gnu.org/licenses/
     12###############################################################################
     13
     14
    115from sage.misc.prandom import randint, random
    216import operator
    317from sage.rings.all import QQ
     
    519import sage.symbolic.pynac
    620from sage.symbolic.constants import *
    721
     22
     23###################################################################
     24### Generate random expressions for doctests ######################
     25###################################################################
     26
    827def _mk_full_functions():
    928    r"""
    1029    A simple function that returns a list of all Pynac functions of known
     
    161180        sage: random_integer_vector(100, 2)
    162181        [4, 96]
    163182        sage: random_integer_vector(10000, 20)
    164         [332, 529, 185, 738, 82, 964, 596, 892, 732, 134, 834, 765, 398, 608, 358, 300, 652, 249, 586, 66]
     183        [332, 529, 185, 738, 82, 964, 596, 892, 732, 134,
     184         834, 765, 398, 608, 358, 300, 652, 249, 586, 66]
    165185    """
    166186    if length == 0:
    167187        return []
     
    184204    EXAMPLES::
    185205
    186206        sage: from sage.symbolic.random_tests import *
    187         sage: random_expr_helper(9, [(0.5, operator.add, 2), (0.5, operator.neg, 1)], [(0.5, 1), (0.5, x)], True)
     207        sage: random_expr_helper(9, [(0.5, operator.add, 2),
     208        ...       (0.5, operator.neg, 1)], [(0.5, 1), (0.5, x)], True)
    188209        About to apply <built-in function add> to [1, x]
    189210        About to apply <built-in function add> to [x, x + 1]
    190211        About to apply <built-in function neg> to [1]
     
    208229            print "About to apply %r to %r" % (r[1], children)
    209230        return r[1](*children)
    210231
    211 def random_expr(size, nvars=1, ncoeffs=None, var_frac=0.5, internal=full_internal, nullary=full_nullary, nullary_frac=0.2, coeff_generator=QQ.random_element, verbose=False):
     232def random_expr(size, nvars=1, ncoeffs=None, var_frac=0.5,
     233                internal=full_internal,
     234                nullary=full_nullary, nullary_frac=0.2,
     235                coeff_generator=QQ.random_element, verbose=False):
    212236    r"""
    213237    Produce a random symbolic expression of the given size.  By
    214238    default, the expression involves (at most) one variable, an arbitrary
     
    257281    internal = normalize_prob_list(internal)
    258282
    259283    return random_expr_helper(size, internal, leaves, verbose)
     284
     285
     286###################################################################
     287### Test the ordering of operands #################################
     288###################################################################
     289
     290def assert_strict_weak_order(a,b,c, cmp_func):
     291    r"""
     292    Checks that ``cmp_func`` is a strict weak order.
     293
     294    A strict weak order is a binary relation ``<`` such that
     295
     296    * For all `x`, it is not the case that `x < x` (irreflexivity).
     297
     298    * For all `x\not=y`, if `x < y` then it is not the case that `y <
     299      x` (asymmetric).
     300
     301    * For all `x`, `y`, and `z`, if `x < y` and `y < z` then `x < z`
     302      (transitivity).
     303
     304    * For all `x`, `y`, and `z`, if x is incomparable with `y`, and
     305      `y` is incomparable with `z`, then `x` is incomparable with `z`
     306      (transitivity of equivalence).
     307
     308    INPUT:
     309
     310    - ``a``, ``b``, ``c`` -- anything that can be compared by ``cmp_func``.
     311
     312    - ``cmp_func`` -- function of two arguments that returns their
     313      comparison (i.e. either ``True`` or ``False``).
     314
     315    OUTPUT:
     316
     317    Does not return anything. Raises a ``ValueError`` if ``cmp_func``
     318    is not a strict weak order on the three given elements.
     319
     320    REFERENCES:
     321
     322    http://en.wikipedia.org/wiki/Strict_weak_ordering
     323
     324    EXAMPLES:
     325
     326    The usual ordering of integers is a strict weak order::
     327
     328        sage: from sage.symbolic.random_tests import assert_strict_weak_order
     329        sage: a, b, c = [ randint(-10,10) for i in range(0,3) ]
     330        sage: assert_strict_weak_order(a,b,c, lambda x,y: x<y)
     331
     332        sage: x = [SR(unsigned_infinity), SR(oo), -SR(oo)]
     333        sage: cmp = matrix(3,3)
     334        sage: indices = list(CartesianProduct(range(0,3),range(0,3)))
     335        sage: for i,j in CartesianProduct(range(0,3),range(0,3)):
     336        ...       cmp[i,j] = x[i].__cmp__(x[j])
     337        sage: cmp
     338        [ 0  1  1]
     339        [-1  0 -1]
     340        [-1  1  0]
     341    """
     342    from sage.matrix.constructor import matrix
     343    from sage.combinat.cartesian_product import CartesianProduct
     344    from sage.combinat.permutation import Permutations
     345    x = (a,b,c)
     346    cmp = matrix(3,3)
     347    indices = list(CartesianProduct(range(0,3),range(0,3)))
     348    for i,j in indices:
     349        cmp[i,j] = (cmp_func(x[i], x[j]) == 1)   # or -1, doesn't matter
     350    msg = 'The binary relation failed to be a strict weak order on the elements\n'
     351    msg += ' a = '+str(a)+'\n'
     352    msg += ' b = '+str(b)+'\n'
     353    msg += ' c = '+str(c)+'\n'
     354    msg += str(cmp)
     355
     356    for i in range(0,3):   # irreflexivity
     357        if cmp[i,i]: raise ValueError, msg
     358
     359    for i,j in indices:    # asymmetric
     360        if i==j: continue
     361        #if x[i] == x[j]: continue
     362        if cmp[i,j] and cmp[j,i]: raise ValueError, msg
     363
     364    for i,j,k in Permutations([0,1,2]):   # transitivity
     365        if cmp[i,j] and cmp[j,k] and not cmp[i,k]: raise ValueError, msg
     366
     367    def incomparable(i,j):
     368        return (not cmp[i,j]) and (not cmp[j,i])
     369    for i,j,k in Permutations([0,1,2]):   # transitivity of equivalence
     370        if incomparable(i,j) and incomparable(j,k) and not incomparable(i,k): raise ValueError, msg
     371
     372def test_symbolic_expression_order(repetitions=100):
     373    r"""
     374    Tests whether the comparison of random symbolic expressions
     375    satisfies the strict weak order axioms.
     376
     377    This is important because the C++ extension class uses
     378    ``std::sort()`` which requires a strict weak order. See also
     379    :trac:`9880`.
     380
     381    EXAMPLES::
     382
     383        sage: from sage.symbolic.random_tests import test_symbolic_expression_order
     384        sage: test_symbolic_expression_order(200)
     385        sage: test_symbolic_expression_order(10000)  # long time
     386    """
     387    rnd_length = 50
     388    nvars = 10
     389    ncoeffs = 10
     390    var_frac = 0.5
     391    nullary_frac = 0.05
     392
     393    def coeff_generator():
     394        return randint(-100,100)/randint(1,100)
     395
     396    def make_random_expr():
     397        while True:
     398            try:
     399                return sage.symbolic.random_tests.random_expr(
     400                    rnd_length, nvars=nvars, ncoeffs=ncoeffs, var_frac=var_frac,
     401                    nullary_frac=nullary_frac, coeff_generator=coeff_generator,
     402                    internal=sage.symbolic.random_tests.fast_nodes)
     403            except (ZeroDivisionError, ValueError):
     404                pass
     405
     406    for rep in range(0, repetitions):
     407        a = make_random_expr()
     408        b = make_random_expr()
     409        c = make_random_expr()
     410        assert_strict_weak_order(a, b, c, lambda x,y: x._cmp_(y))
     411        assert_strict_weak_order(a, b, c, lambda x,y: x._cmp_add(y))
     412        assert_strict_weak_order(a, b, c, lambda x,y: x._cmp_mul(y))