| 281 | |
| 282 | |
| 283 | |
| 284 | |
| 285 | ################################################################### |
| 286 | ### Test the ordering of operands ################################# |
| 287 | ################################################################### |
| 288 | |
| 289 | def 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 | |
| 371 | def 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 | |