Ticket #9880: trac_9880_randomized_testing.patch

File trac_9880_randomized_testing.patch, 7.9 KB (added by vbraun, 9 years ago)

Initial patch

  • sage/symbolic/random_tests.py

    # HG changeset patch
    # User Volker Braun <vbraun@stp.dias.ie>
    # Date 1308098188 25200
    # Node ID 5d5f4f7f4174d99926095700801dc8c6a9aa7e9c
    # Parent  6dad7491633ba5cae63f243b5ae79ecd5794d048
    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
    216from sage.ext.fast_callable import ExpressionTreeBuilder
    317import operator
     
    620import sage.symbolic.pynac
    721from sage.symbolic.constants import *
    822
     23
     24
     25
     26###################################################################
     27### Generate random expressions for doctests ######################
     28###################################################################
     29
    930def _mk_full_functions():
    1031    r"""
    1132    A simple function that returns a list of all Pynac functions of known
     
    162183        sage: random_integer_vector(100, 2)
    163184        [4, 96]
    164185        sage: random_integer_vector(10000, 20)
    165         [332, 529, 185, 738, 82, 964, 596, 892, 732, 134, 834, 765, 398, 608, 358, 300, 652, 249, 586, 66]
     186        [332, 529, 185, 738, 82, 964, 596, 892, 732, 134,
     187         834, 765, 398, 608, 358, 300, 652, 249, 586, 66]
    166188    """
    167189    if length == 0:
    168190        return []
     
    185207    EXAMPLES::
    186208
    187209        sage: from sage.symbolic.random_tests import *
    188         sage: random_expr_helper(9, [(0.5, operator.add, 2), (0.5, operator.neg, 1)], [(0.5, 1), (0.5, x)], True)
     210        sage: random_expr_helper(9, [(0.5, operator.add, 2),
     211        ...       (0.5, operator.neg, 1)], [(0.5, 1), (0.5, x)], True)
    189212        About to apply <built-in function add> to [1, x]
    190213        About to apply <built-in function add> to [x, x + 1]
    191214        About to apply <built-in function neg> to [1]
     
    209232            print "About to apply %r to %r" % (r[1], children)
    210233        return r[1](*children)
    211234
    212 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):
     235def random_expr(size, nvars=1, ncoeffs=None, var_frac=0.5,
     236                internal=full_internal,
     237                nullary=full_nullary, nullary_frac=0.2,
     238                coeff_generator=QQ.random_element, verbose=False):
    213239    r"""
    214240    Produce a random symbolic expression of the given size.  By
    215241    default, the expression involves (at most) one variable, an arbitrary
     
    252278    internal = normalize_prob_list(internal)
    253279
    254280    return random_expr_helper(size, internal, leaves, verbose)
     281
     282
     283
     284
     285###################################################################
     286### Test the ordering of operands #################################
     287###################################################################
     288
     289def assert_strict_weak_order(a,b,c, cmp_func):
     290    r"""
     291    Checks that ``cmp_func`` is a strict weak order.
     292
     293    A strict weak order is a binary relation ``<`` such that
     294
     295    * For all `x`, it is not the case that `x < x` (irreflexivity).
     296
     297    * For all `x\not=y`, if `x < y` then it is not the case that `y <
     298      x` (asymmetric).
     299
     300    * For all `x`, `y`, and `z`, if `x < y` and `y < z` then `x < z`
     301      (transitivity).
     302
     303    * For all `x`, `y`, and `z`, if x is incomparable with `y`, and
     304      `y` is incomparable with `z`, then `x` is incomparable with `z`
     305      (transitivity of equivalence).
     306
     307    INPUT:
     308   
     309    - ``a``, ``b``, ``c`` -- anything that can be compared by ``cmp_func``.
     310
     311    - ``cmp_func`` -- function of two arguments that returns their
     312      comparison (i.e. either ``True`` or ``False``).
     313
     314    OUTPUT:
     315
     316    Does not return anything. Raises a ``ValueError`` if ``cmp_func``
     317    is not a strict weak order on the three given elements.
     318
     319    REFERENCES:
     320
     321    http://en.wikipedia.org/wiki/Strict_weak_ordering
     322   
     323    EXAMPLES:
     324
     325    The usual ordering of integers is a strict weak order::
     326
     327        sage: from sage.symbolic.random_tests import assert_strict_weak_order
     328        sage: a, b, c = [ randint(-10,10) for i in range(0,3) ]
     329        sage: assert_strict_weak_order(a,b,c, lambda x,y: x<y)
     330
     331        sage: x = [SR(unsigned_infinity), SR(oo), -SR(oo)]
     332        sage: cmp = matrix(3,3)
     333        sage: indices = list(CartesianProduct(range(0,3),range(0,3)))
     334        sage: for i,j in CartesianProduct(range(0,3),range(0,3)):
     335        ...       cmp[i,j] = x[i].__cmp__(x[j])
     336        sage: cmp
     337        [ 0  1  1]
     338        [-1  0 -1]
     339        [-1  1  0]
     340    """
     341    from sage.matrix.constructor import matrix
     342    from sage.combinat.cartesian_product import CartesianProduct
     343    from sage.combinat.permutation import Permutations
     344    x = (a,b,c)
     345    cmp = matrix(3,3)
     346    indices = list(CartesianProduct(range(0,3),range(0,3)))
     347    for i,j in indices:
     348        cmp[i,j] = (cmp_func(x[i], x[j]) == 1)   # or -1, doesn't matter
     349    msg = 'The binary relation failed to be a strict weak order on the elements\n'
     350    msg += ' a = '+str(a)+'\n'
     351    msg += ' b = '+str(b)+'\n'
     352    msg += ' c = '+str(c)+'\n'
     353    msg += str(cmp)
     354
     355    for i in range(0,3):   # irreflexivity
     356        if cmp[i,i]: raise ValueError, msg
     357       
     358    for i,j in indices:    # asymmetric
     359        if i==j: continue
     360        #if x[i] == x[j]: continue
     361        if cmp[i,j] and cmp[j,i]: raise ValueError, msg
     362           
     363    for i,j,k in Permutations([0,1,2]):   # transitivity
     364        if cmp[i,j] and cmp[j,k] and not cmp[i,k]: raise ValueError, msg
     365
     366    def incomparable(i,j):
     367        return (not cmp[i,j]) and (not cmp[j,i])
     368    for i,j,k in Permutations([0,1,2]):   # transitivity of equivalence
     369        if incomparable(i,j) and incomparable(j,k) and not incomparable(i,k): raise ValueError, msg
     370
     371def test_symbolic_expression_order(repetitions=100):
     372    r"""
     373
     374    Tests whether the comparison of random symbolic expressions
     375    satisfies the strict weak order axioms.
     376
     377    This is important becasue the C++ extension class uses
     378    ``std::sort()`` which requires a strict weak order. See also
     379   
     380    http://trac.sagemath.org/sage_trac/ticket/9880
     381   
     382    EXAMPLES:
     383     
     384        sage: from sage.symbolic.random_tests import test_symbolic_expression_order
     385        sage: test_symbolic_expression_order(200)
     386        sage: test_symbolic_expression_order(10000)  # long time
     387    """
     388    rnd_length = 50
     389    nvars = 10
     390    ncoeffs = 10
     391    var_frac = 0.5
     392    nullary_frac = 0.05
     393
     394    def coeff_generator():
     395        return randint(-100,100)/randint(1,100)
     396
     397    def make_random_expr():
     398        while True:
     399            try:
     400                return sage.symbolic.random_tests.random_expr(
     401                    rnd_length, nvars=nvars, ncoeffs=ncoeffs, var_frac=var_frac,
     402                    nullary_frac=nullary_frac, coeff_generator=coeff_generator,
     403                    internal=sage.symbolic.random_tests.fast_nodes)
     404            except (ZeroDivisionError, ValueError):
     405                pass
     406   
     407    for rep in range(0, repetitions):
     408        a = make_random_expr()
     409        b = make_random_expr()
     410        c = make_random_expr()
     411        assert_strict_weak_order(a, b, c, lambda x,y: x._cmp_(y))
     412        assert_strict_weak_order(a, b, c, lambda x,y: x._cmp_add(y))
     413        assert_strict_weak_order(a, b, c, lambda x,y: x._cmp_mul(y))
     414
     415
     416
     417
     418
     419