def test_call_loopy_shape_inference(): from pytato.loopy import call_loopy from pytato.utils import are_shapes_equal import loopy as lp knl = lp.make_kernel( ["{[i, j]: 0<=i<(2*n + 3*m + 2) and 0<=j<(6*n + 4*m + 3)}", "{[ii, jj]: 0<=ii<m and 0<=jj<n}"], """ <> tmp = sum([i, j], A[i, j]) out[ii, jj] = tmp*(ii + jj) """, lang_version=(2018, 2)) # {{{ variant 1 A = pt.make_placeholder(name="x", shape=(20, 37), dtype=np.float64) # noqa: N806 y = call_loopy(knl, {"A": A})["out"] assert are_shapes_equal(y.shape, (4, 3)) # }}} # {{{ variant 2 n1 = pt.make_size_param("n1") n2 = pt.make_size_param("n2") A = pt.make_placeholder(name="x", # noqa: N806 shape=(4*n1 + 6*n2 + 2, 12*n1 + 8*n2 + 3), dtype=np.float64) y = call_loopy(knl, {"A": A})["out"] assert are_shapes_equal(y.shape, (2*n2, 2*n1))
def test_matmul_input_validation(): namespace = pt.Namespace() a = pt.make_placeholder(namespace, name="a", shape=(10, 10), dtype=np.float) b = pt.make_placeholder(namespace, name="b", shape=(20, 10), dtype=np.float) with pytest.raises(ValueError): a @ b c = pt.make_placeholder(namespace, name="c", shape=(), dtype=np.float) with pytest.raises(ValueError): c @ c pt.make_size_param(namespace, "n") d = pt.make_placeholder(namespace, name="d", shape="(n, n)", dtype=np.float) d @ d
def test_idx_lambda_to_hlo(): from pytato.raising import index_lambda_to_high_level_op from pytato.raising import (BinaryOp, BinaryOpType, FullOp, ReduceOp, C99CallOp, BroadcastOp) from pyrsistent import pmap from pytato.reductions import (SumReductionOperation, ProductReductionOperation) a = pt.make_placeholder("a", (10, 4), dtype=np.float64) b = pt.make_placeholder("b", (10, 4), dtype=np.float64) assert index_lambda_to_high_level_op(a + b) == BinaryOp(BinaryOpType.ADD, a, b) assert index_lambda_to_high_level_op(a / 42) == BinaryOp(BinaryOpType.TRUEDIV, a, 42) assert index_lambda_to_high_level_op(42 * a) == BinaryOp(BinaryOpType.MULT, 42, a) assert index_lambda_to_high_level_op(a ** b) == BinaryOp(BinaryOpType.POWER, a, b) assert index_lambda_to_high_level_op(a - b) == BinaryOp(BinaryOpType.SUB, a, b) assert (index_lambda_to_high_level_op(a & b) == BinaryOp(BinaryOpType.BITWISE_AND, a, b)) assert (index_lambda_to_high_level_op(a ^ b) == BinaryOp(BinaryOpType.BITWISE_XOR, a, b)) assert (index_lambda_to_high_level_op(a | b) == BinaryOp(BinaryOpType.BITWISE_OR, a, b)) assert (index_lambda_to_high_level_op(pt.equal(a, b)) == BinaryOp(BinaryOpType.EQUAL, a, b)) assert (index_lambda_to_high_level_op(pt.not_equal(a, b)) == BinaryOp(BinaryOpType.NOT_EQUAL, a, b)) assert (index_lambda_to_high_level_op(pt.less(a, b)) == BinaryOp(BinaryOpType.LESS, a, b)) assert (index_lambda_to_high_level_op(pt.less_equal(a, b)) == BinaryOp(BinaryOpType.LESS_EQUAL, a, b)) assert (index_lambda_to_high_level_op(pt.greater(a, b)) == BinaryOp(BinaryOpType.GREATER, a, b)) assert (index_lambda_to_high_level_op(pt.greater_equal(a, b)) == BinaryOp(BinaryOpType.GREATER_EQUAL, a, b)) assert index_lambda_to_high_level_op(pt.zeros(6)) == FullOp(0) assert (index_lambda_to_high_level_op(pt.sum(b, axis=1)) == ReduceOp(SumReductionOperation(), b, pmap({1: "_r0"}))) assert (index_lambda_to_high_level_op(pt.prod(a)) == ReduceOp(ProductReductionOperation(), a, {0: "_r0", 1: "_r1"})) assert index_lambda_to_high_level_op(pt.sinh(a)) == C99CallOp("sinh", (a,)) assert index_lambda_to_high_level_op(pt.arctan2(b, a)) == C99CallOp("atan2", (b, a)) assert (index_lambda_to_high_level_op(pt.broadcast_to(a, (100, 10, 4))) == BroadcastOp(a))
def test_size_param(ctx_factory): ctx = ctx_factory() queue = cl.CommandQueue(ctx) namespace = pt.Namespace() n = pt.make_size_param(namespace, name="n") pt.make_placeholder(namespace, name="x", shape="(n,)", dtype=np.int) prog = pt.generate_loopy(n, target=pt.PyOpenCLTarget(queue)) x_in = np.array([1, 2, 3, 4, 5]) _, (n_out, ) = prog(x=x_in) assert n_out == 5
def test_rec_get_user_nodes(): x1 = pt.make_placeholder("x1", shape=(10, 4), dtype=np.float64) x2 = pt.make_placeholder("x2", shape=(10, 4), dtype=np.float64) expr = pt.make_dict_of_named_arrays({"out1": 2 * x1, "out2": 7 * x1 + 3 * x2}) assert (pt.transform.rec_get_user_nodes(expr, x1) == frozenset({2 * x1, 7*x1, 7*x1 + 3 * x2, expr})) assert (pt.transform.rec_get_user_nodes(expr, x2) == frozenset({3 * x2, 7*x1 + 3 * x2, expr}))
def test_index_type_validation(): a = pt.make_placeholder(name="a", shape=(10,), dtype=np.float64) idx = pt.make_placeholder(name="idx", shape=(5,), dtype=np.int8) a[idx] idx = pt.make_placeholder(name="idx", shape=(5,), dtype=np.uint8) a[idx] idx = pt.make_placeholder(name="idx", shape=(5,), dtype=np.float64) with pytest.raises(IndexError): a[idx]
def test_same_placeholder_name_raises(): from pytato.diagnostic import NameClashError x = pt.make_placeholder(name="arr", shape=(10, 4), dtype=float) y = pt.make_placeholder(name="arr", shape=(10, 4), dtype=float) with pytest.raises(NameClashError): pt.generate_loopy(x+y) n1 = pt.make_size_param("n") n2 = pt.make_size_param("n") x = pt.make_placeholder(name="arr", shape=(n1, n2), dtype=float) with pytest.raises(NameClashError): pt.generate_loopy(2*x)
def test_matmul_input_validation(): a = pt.make_placeholder(name="a", shape=(10, 10), dtype=np.float64) b = pt.make_placeholder(name="b", shape=(20, 10), dtype=np.float64) with pytest.raises(ValueError): a @ b c = pt.make_placeholder(name="c", shape=(), dtype=np.float64) with pytest.raises(ValueError): c @ c n = pt.make_size_param("n") d = pt.make_placeholder(name="d", shape=(n, n), dtype=np.float64) d @ d
def main(): import pytato as pt import pyopencl as cl cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) nelements = 20 nnodes = 3 discr = DGDiscr1D(0, 2 * np.pi, nelements=nelements, nnodes=nnodes) ns = pt.Namespace() pt.make_size_param(ns, "nelements") pt.make_size_param(ns, "nnodes") u = pt.make_placeholder(ns, name="u", shape="(nelements, nnodes)", dtype=np.float64) op = AdvectionOperator(discr, c=1, flux_type="central", dg_ops=DGOps1D(discr, ns)) result = op.apply(u) prog = pt.generate_loopy(result, target=pt.PyOpenCLTarget(queue)) print(prog.program) u = np.sin(discr.nodes()) print(prog(u=u.reshape(nelements, nnodes))[1][0])
def test_einsum_is_similar_to_subscript(spec, argshapes): operands = [pt.make_placeholder(name=f"arg_{iarg}", shape=argshape, dtype=np.int32) for iarg, argshape in enumerate(argshapes)] expr = pt.einsum(spec, *operands) assert pt.analysis.is_einsum_similar_to_subscript(expr, spec)
def test_asciidag(): n = pt.make_size_param("n") array = pt.make_placeholder(name="array", shape=n, dtype=np.float64) stack = pt.stack([array, 2*array, array + 6]) y = stack @ stack.T from pytato import get_ascii_graph res = get_ascii_graph(y, use_color=False) ref_str = r"""* Inputs *-. Placeholder |\ \ * | | IndexLambda | |/ |/| | * IndexLambda |/ * Stack |\ * | AxisPermutation |/ * Einsum * Outputs """ assert res == ref_str
def test_userscollector(): from testlib import RandomDAGContext, make_random_dag from pytato.transform import UsersCollector, reverse_graph # Check that nodes without users are correctly reversed array = pt.make_placeholder(name="array", shape=1, dtype=np.int64) y = array+1 uc = UsersCollector() uc(y) rev_graph = reverse_graph(uc.node_to_users) rev_graph2 = reverse_graph(reverse_graph(rev_graph)) assert reverse_graph(rev_graph2) == uc.node_to_users # Test random DAGs axis_len = 5 for i in range(100): rdagc = RandomDAGContext(np.random.default_rng(seed=i), axis_len=axis_len, use_numpy=False) dag = make_random_dag(rdagc) uc = UsersCollector() uc(dag) rev_graph = reverse_graph(uc.node_to_users) rev_graph2 = reverse_graph(reverse_graph(rev_graph)) assert rev_graph2 == rev_graph
def test_advection_convergence(order, flux_type): errors = [] hs = [] import pytato as pt import pyopencl as cl cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) for nelements in (8, 12, 16, 20): discr = DGDiscr1D(0, 2 * np.pi, nelements=nelements, nnodes=order) dg_ops = DGOps1D(discr) u_initial = np.sin(discr.nodes()) u = pt.make_placeholder(name="u", shape=(dg_ops.nelements, dg_ops.nnodes), dtype=np.float64) op = AdvectionOperator(discr, c=1, flux_type=flux_type, dg_ops=dg_ops) result = op.apply(u) prog = pt.generate_loopy(result, cl_device=queue.device) u = rk4(lambda t, y: prog(queue, u=y.reshape(nelements, order))[1][0]. reshape(-1), u_initial, t_initial=0, t_final=np.pi, dt=0.01) u_ref = -u_initial hs.append(discr.h) errors.append(integrate(discr, (u - u_ref)**2)**0.5) eoc, _ = np.polyfit(np.log(hs), np.log(errors), 1) assert eoc >= order - 0.1, eoc
def test_accessing_dict_of_named_arrays_validation(): x = pt.make_placeholder(name="x", shape=10, dtype=float) y1y2 = pt.make_dict_of_named_arrays({"y1": 2*x, "y2": 3*x}) assert isinstance(y1y2["y1"], pt.array.NamedArray) assert y1y2["y1"].shape == (2*x).shape assert y1y2["y1"].dtype == (2*x).dtype
def test_make_placeholder_noname(): x = pt.make_placeholder("x", shape=(10, 4), dtype=float) y = 2*x knl = pt.generate_loopy(y).kernel assert x.name in knl.arg_dict assert x.name in knl.get_read_variables()
def test_zero_length_arrays(): x = pt.make_placeholder("x", shape=(0, 4), dtype=float) y = 2*x assert y.shape == (0, 4) knl = pt.generate_loopy(y).kernel assert all(dom.is_empty() for dom in knl.domains if dom.total_dim() != 0)
def test_einsum_error_handling(): with pytest.raises(ValueError): # operands not enough pt.einsum("ij,j->j", pt.make_placeholder("x", (2, 2), float)) with pytest.raises(ValueError): # double index use in the out spec. pt.einsum("ij,j->jj", ("a", "b"))
def test_stack_input_validation(): x = pt.make_placeholder(name="x", shape=(10, 10), dtype=np.float64) y = pt.make_placeholder(name="y", shape=(1, 10), dtype=np.float64) assert pt.stack((x, x, x), axis=0).shape == (3, 10, 10) pt.stack((x,), axis=0) pt.stack((x,), axis=1) with pytest.raises(ValueError): pt.stack(()) with pytest.raises(ValueError): pt.stack((x, y)) with pytest.raises(ValueError): pt.stack((x, x), axis=3)
def test_roll_input_validation(): a = pt.make_placeholder(name="a", shape=(10, 10), dtype=np.float64) pt.roll(a, 1, axis=0) with pytest.raises(ValueError): pt.roll(a, 1, axis=2) with pytest.raises(ValueError): pt.roll(a, 1, axis=-1)
def test_zero_length_arrays(): ns = pt.Namespace() x = pt.make_placeholder(ns, shape=(0, 4), dtype=float) y = 2 * x assert y.shape == (0, 4) knl = pt.generate_loopy(y).program assert all(dom.is_empty() for dom in knl.domains if dom.total_dim() != 0)
def construct_intestine_graph(depth=100, seed=0): rng = default_rng(seed) x = pt.make_placeholder("x", shape=(10,), dtype=float) for _ in range(depth): coeff1, coeff2 = rng.integers(0, 10, 2) x = coeff1 * x + coeff2 * x return x
def test_make_placeholder_noname(): ns = pt.Namespace() x = pt.make_placeholder(ns, shape=(10, 4), dtype=float) y = 2 * x knl = pt.generate_loopy(y).program assert x.name in knl.arg_dict assert x.name in knl.get_read_variables()
def test_dict_of_named_array_codegen_avoids_recomputation(): ns = pt.Namespace() x = pt.make_placeholder(ns, shape=(10, 4), dtype=float, name="x") y = 2 * x z = y + 4 * x yz = pt.DictOfNamedArrays({"y": y, "z": z}) knl = pt.generate_loopy(yz).program assert ("y" in knl.id_to_insn["z_store"].read_dependency_names())
def test_dict_of_named_arrays_comparison(): # See https://github.com/inducer/pytato/pull/137 x = pt.make_placeholder("x", (10, 4), float) dict1 = pt.make_dict_of_named_arrays({"out": 2 * x}) dict2 = pt.make_dict_of_named_arrays({"out": 2 * x}) dict3 = pt.make_dict_of_named_arrays({"not_out": 2 * x}) dict4 = pt.make_dict_of_named_arrays({"out": 3 * x}) assert dict1 == dict2 assert dict1 != dict3 assert dict1 != dict4
def test_reshape_input_validation(): x = pt.make_placeholder("x", shape=(3, 3, 4), dtype=np.float64) assert pt.reshape(x, (-1,)).shape == (36,) assert pt.reshape(x, (-1, 6)).shape == (6, 6) assert pt.reshape(x, (4, -1)).shape == (4, 9) assert pt.reshape(x, (36, -1)).shape == (36, 1) with pytest.raises(ValueError): # 36 not a multiple of 25 pt.reshape(x, (5, 5)) with pytest.raises(ValueError): # 2 unknown dimensions pt.reshape(x, (-1, -1, 3)) # Reporter by alexfikl # See https://github.com/inducer/pytato/issues/157 x = pt.make_placeholder("x", shape=(0,), dtype=np.float64) assert pt.reshape(x, (128, 0, 17)).shape == (128, 0, 17)
def test_tagging_array(): from pytools.tag import Tag class BestArrayTag(Tag): """ Best array known to humankind. """ x = pt.make_placeholder(shape=(42, 1729), dtype=float, name="x") y = x.tagged(BestArrayTag()) assert any(isinstance(tag, BestArrayTag) for tag in y.tags)
def test_concatenate_input_validation(): namespace = pt.Namespace() x = pt.make_placeholder(namespace, name="x", shape=(10, 10), dtype=np.float) y = pt.make_placeholder(namespace, name="y", shape=(1, 10), dtype=np.float) assert pt.concatenate((x, x, x), axis=0).shape == (30, 10) assert pt.concatenate((x, y), axis=0).shape == (11, 10) pt.concatenate((x,), axis=0) pt.concatenate((x,), axis=1) with pytest.raises(ValueError): pt.concatenate(()) with pytest.raises(ValueError): pt.concatenate((x, y), axis=1) with pytest.raises(ValueError): pt.concatenate((x, x), axis=3)
def construct_intestine_graph(depth=100, seed=0): from numpy.random import default_rng rng = default_rng(seed) x = pt.make_placeholder("x", shape=(10,), dtype=float) y = x for _ in range(depth): coeff1, coeff2 = rng.integers(0, 10, 2) y = coeff1 * y + coeff2 * y return y, x
def test_slice_input_validation(): a = pt.make_placeholder(name="a", shape=(10, 10, 10), dtype=np.float64) a[0] a[0, 0] a[0, 0, 0] with pytest.raises(IndexError): a[0, 0, 0, 0] with pytest.raises(IndexError): a[10]
def test_transpose_input_validation(): a = pt.make_placeholder(name="a", shape=(10, 10), dtype=np.float64) pt.transpose(a) with pytest.raises(ValueError): pt.transpose(a, (2, 0, 1)) with pytest.raises(ValueError): pt.transpose(a, (1, 1)) with pytest.raises(ValueError): pt.transpose(a, (0,))