|
7 | 7 |
|
8 | 8 | from devito import ( # noqa |
9 | 9 | Abs, Conj, Constant, Dimension, Eq, Function, Ge, Grid, Gt, Imag, Le, Lt, Max, Min, |
10 | | - Operator, Real, SubDimension, SubDomain, TimeFunction, configuration, cos, norm, sin, |
11 | | - solve, switchconfig |
| 10 | + Operator, Real, SubDimension, SubDomain, TimeDimension, TimeFunction, configuration, |
| 11 | + cos, norm, sin, solve, switchconfig |
12 | 12 | ) |
13 | 13 | from devito.finite_differences.differentiable import Mul, SafeInv, Weights |
14 | 14 | from devito.ir import Expression, FindNodes, ccode |
|
17 | 17 | from devito.symbolics import ( # noqa |
18 | 18 | INT, BaseCast, CallFromPointer, Cast, DefFunction, FieldFromComposite, |
19 | 19 | FieldFromPointer, IntDiv, ListInitializer, Namespace, ReservedWord, RoundUp, Rvalue, |
20 | | - SizeOf, VectorAccess, evalrel, pow_to_mul, retrieve_derivatives, retrieve_functions, |
21 | | - retrieve_indexed, subs_if_composite, uxreplace, xreplace_indices |
| 20 | + SizeOf, VectorAccess, evalrel, pow_to_mul, q_negative, q_positive, |
| 21 | + retrieve_derivatives, retrieve_functions, retrieve_indexed, subs_if_composite, |
| 22 | + uxreplace, xreplace_indices |
22 | 23 | ) |
23 | 24 | from devito.tools import CustomDtype, as_tuple, dtypes_vector_mapper |
24 | 25 | from devito.types import ( |
@@ -385,6 +386,74 @@ def test_intdiv(): |
385 | 386 | assert ccode(v) == 'b*((a + b) / 2) + 3' |
386 | 387 |
|
387 | 388 |
|
| 389 | +def test_mod_printing(): |
| 390 | + a = dSymbol('a', dtype=np.int32) |
| 391 | + b = dSymbol('b', dtype=np.int32) |
| 392 | + p = Symbol('p', integer=True, nonnegative=True) |
| 393 | + |
| 394 | + assert ccode(sympy.Mod(a - b + 3, 4)) == '((a - b + 3) & 3)' |
| 395 | + assert ccode(sympy.Mod(a, 8)) == '(a & 7)' |
| 396 | + |
| 397 | + # Keep the existing remainder for known nonnegative dividends and other divisors |
| 398 | + assert ccode(sympy.Mod(p, 4)) == '(p)%(4)' |
| 399 | + assert ccode(sympy.Mod(a, 3)) == '(a)%(3)' |
| 400 | + assert ccode(sympy.Mod(a, b)) == '(a)%(b)' |
| 401 | + |
| 402 | + |
| 403 | +def test_mod_time_printing(): |
| 404 | + time = TimeDimension(name='time') |
| 405 | + shift = dSymbol('shift', dtype=np.int32) |
| 406 | + |
| 407 | + assert time.is_nonnegative is True |
| 408 | + assert time.is_positive is None |
| 409 | + assert ccode(sympy.Mod(time, 2)) == '(time)%(2)' |
| 410 | + assert ccode(sympy.Mod(time + 1, 2)) == '(time + 1)%(2)' |
| 411 | + |
| 412 | + # A shifted time index may still be negative |
| 413 | + assert ccode(sympy.Mod(time - shift, 4)) == '((time - shift) & 3)' |
| 414 | + |
| 415 | + |
| 416 | +@pytest.mark.parametrize('divisor', [4, 8]) |
| 417 | +def test_mod_negative(divisor): |
| 418 | + grid = Grid(shape=(65,)) |
| 419 | + x, = grid.dimensions |
| 420 | + |
| 421 | + f = Function(name='f', grid=grid, space_order=0, dtype=np.int32) |
| 422 | + shift = Constant(name='shift', dtype=np.int32, value=32) |
| 423 | + |
| 424 | + # Also exercise precedence when Mod is nested in arithmetic |
| 425 | + eq = Eq(f, 3*sympy.Mod(x - shift, divisor) + 1) |
| 426 | + |
| 427 | + op = Operator(eq, name='mod_negative', opt='noop') |
| 428 | + op.apply() |
| 429 | + |
| 430 | + expected = 3*((np.arange(65) - 32) % divisor) + 1 |
| 431 | + np.testing.assert_array_equal(np.asarray(f.data), expected) |
| 432 | + |
| 433 | + |
| 434 | +def test_sign_queries(): |
| 435 | + for v in (sympy.S.One, sympy.Rational(1, 2), sympy.Float(0.5)): |
| 436 | + assert q_positive(v) |
| 437 | + assert q_negative(-v) |
| 438 | + assert not q_positive(-v) |
| 439 | + assert not q_negative(v) |
| 440 | + |
| 441 | + assert not q_positive(sympy.S.Zero) |
| 442 | + assert not q_negative(sympy.S.Zero) |
| 443 | + |
| 444 | + a = dSymbol('a', dtype=np.int32) |
| 445 | + r = sympy.Mod(a, 4) |
| 446 | + |
| 447 | + assert q_positive(8 - r) |
| 448 | + assert q_positive(4 - r) |
| 449 | + assert q_negative(r - 8) |
| 450 | + # Zero and unknown signs must not be classified as strictly positive |
| 451 | + assert not q_positive(3 - r) |
| 452 | + assert not q_positive(r) |
| 453 | + assert not q_positive(a) |
| 454 | + assert not q_negative(a) |
| 455 | + |
| 456 | + |
388 | 457 | def test_safeinv(): |
389 | 458 | grid = Grid(shape=(11, 11)) |
390 | 459 | x, y = grid.dimensions |
|
0 commit comments