def statement_evaluate(leaf, ctx): expr = leaf.expression if isinstance(expr, gem.ListTensor): ops = [] var, index = ctx.pymbolic_variable_and_destruct(expr) for multiindex, value in numpy.ndenumerate(expr.array): ops.append( lp.Assignment(p.Subscript(var, index + multiindex), expression(value, ctx), within_inames=ctx.active_inames())) return ops elif isinstance(expr, gem.Constant): return [] elif isinstance(expr, gem.ComponentTensor): idx = ctx.gem_to_pym_multiindex(expr.multiindex) var, sub_idx = ctx.pymbolic_variable_and_destruct(expr) lhs = p.Subscript(var, idx + sub_idx) with active_indices(dict(zip(expr.multiindex, idx)), ctx) as ctx_active: return [ lp.Assignment(lhs, expression(expr.children[0], ctx_active), within_inames=ctx_active.active_inames()) ] elif isinstance(expr, gem.Inverse): idx = ctx.pymbolic_multiindex(expr.shape) var = ctx.pymbolic_variable(expr) lhs = (SubArrayRef(idx, p.Subscript(var, idx)), ) idx_reads = ctx.pymbolic_multiindex(expr.children[0].shape) var_reads = ctx.pymbolic_variable(expr.children[0]) reads = (SubArrayRef(idx_reads, p.Subscript(var_reads, idx_reads)), ) rhs = p.Call(p.Variable("inverse"), reads) return [ lp.CallInstruction(lhs, rhs, within_inames=ctx.active_inames()) ] elif isinstance(expr, gem.Solve): idx = ctx.pymbolic_multiindex(expr.shape) var = ctx.pymbolic_variable(expr) lhs = (SubArrayRef(idx, p.Subscript(var, idx)), ) reads = [] for child in expr.children: idx_reads = ctx.pymbolic_multiindex(child.shape) var_reads = ctx.pymbolic_variable(child) reads.append( SubArrayRef(idx_reads, p.Subscript(var_reads, idx_reads))) rhs = p.Call(p.Variable("solve"), tuple(reads)) return [ lp.CallInstruction(lhs, rhs, within_inames=ctx.active_inames()) ] else: return [ lp.Assignment(ctx.pymbolic_variable(expr), expression(expr, ctx, top=True), within_inames=ctx.active_inames()) ]
def _apply_elem_wise_func(x: Array, func_name: str) -> IndexLambda: if x.dtype.kind != "f": raise ValueError(f"'{func_name}' does not support '{x.dtype}' arrays.") expr = prim.Call(var(f"pytato.c99.{func_name}"), (prim.Subscript( var("in"), tuple(var(f"_{i}") for i in range(len(x.shape)))), )) return IndexLambda(x.namespace, expr, x.shape, x.dtype, {"in": x})
def slate_call(self, kernel): # Slate kernel call call = pym.Call(pym.Variable(kernel.name), tuple()) output_var = pym.Variable(kernel.args[0].name) slate_kernel_call_output = self.generate_lhs(self.expression, output_var) insn = loopy.CallInstruction((slate_kernel_call_output,), call, id="slate_kernel_call") return [insn]
def generate_tsfc_calls(self, terminal, loopy_tensor): """A setup method to initialize all the local assembly kernels generated by TSFC. This function also collects any information regarding orientations and extra include directories. """ cxt_kernels = self.tsfc_cxt_kernels(terminal) for cxt_kernel in cxt_kernels: for tsfc_kernel in cxt_kernel.tsfc_kernels: integral_type = cxt_kernel.original_integral_type slate_tensor = cxt_kernel.tensor mesh = slate_tensor.ufl_domain() kinfo = tsfc_kernel.kinfo reads = [] inames_dep = [] if integral_type not in self.supported_integral_types: raise ValueError("Integral type '%s' not recognized" % integral_type) # Prepare lhs and args for call to tsfc kernel output_var = pym.Variable(loopy_tensor.name) reads.append(output_var) output = self.generate_lhs(slate_tensor, output_var) kernel_data = self.collect_tsfc_kernel_data( mesh, cxt_kernel.coefficients, self.bag.coefficients, kinfo) reads.extend(self.loopify_tsfc_kernel_data(kernel_data)) # Generate predicates for different integral types if self.is_integral_type(integral_type, "cell_integral"): predicates = None if kinfo.subdomain_id != "otherwise": raise NotImplementedError( "No subdomain markers for cells yet") elif self.is_integral_type(integral_type, "facet_integral"): predicates, fidx, facet_arg = self.facet_integral_predicates( mesh, integral_type, kinfo) reads.append(facet_arg) inames_dep.append(fidx[0].name) elif self.is_integral_type(integral_type, "layer_integral"): predicates = self.layer_integral_predicates( slate_tensor, integral_type) else: raise ValueError( "Unhandled integral type {}".format(integral_type)) # TSFC kernel call key = self.bag.call_name_generator(integral_type) call = pym.Call(pym.Variable(kinfo.kernel.name), tuple(reads)) insn = loopy.CallInstruction( (output, ), call, within_inames=frozenset(inames_dep), predicates=predicates, id=key) yield insn, kinfo.kernel.code
def map_Call(self, expr): # noqa # (expr func, expr* args, keyword* keywords) func = self.rec(expr.func) args = tuple(self.rec(arg) for arg in expr.args) if expr.keywords: return p.CallWithKwargs( func, args, dict((kw.arg, self.rec(kw.value)) for kw in expr.keywords)) else: return p.Call(func, args)
def map_call(self, expr: prim.Call, expr_context: LoopyExpressionContext) -> ScalarExpression: if isinstance(expr.function, prim.Variable) and ( expr.function.name.startswith("pytato.c99.")): name_in_loopy = expr.function.name[11:] return prim.Call(prim.Variable(name_in_loopy), self.rec(expr.parameters, expr_context)) return super().map_call(expr, expr_context)
def map_call(self, expr: prim.Call, prstnt_ctx: PersistentExpressionContext, local_ctx: LocalExpressionContext) -> ScalarExpression: if isinstance(expr.function, prim.Variable) and ( expr.function.name.startswith("pytato.c99.")): name_in_loopy = expr.function.name[11:] return prim.Call(prim.Variable(name_in_loopy), self.rec(expr.parameters, prstnt_ctx, local_ctx)) return super().map_call(expr, prstnt_ctx, local_ctx)
def slate_call(self, kernel, temporaries): # Slate kernel call reads = [] for t in temporaries: shape = t.shape name = t.name idx = self.bag.index_creator(shape) reads.append(SubArrayRef(idx, pym.Subscript(pym.Variable(name), idx))) call = pym.Call(pym.Variable(kernel.name), tuple(reads)) output_var = pym.Variable(kernel.args[0].name) slate_kernel_call_output = self.generate_lhs(self.expression, output_var) insn = loopy.CallInstruction((slate_kernel_call_output,), call, id="slate_kernel_call") return insn
def test_call_with_no_returned_value(ctx_factory): import pymbolic.primitives as p ctx = ctx_factory() queue = cl.CommandQueue(ctx) knl = lp.make_kernel("{:}", [lp.CallInstruction((), p.Call(p.Variable("f"), ()))]) from library_for_test import no_ret_f_mangler, no_ret_f_preamble_gen knl = lp.register_function_manglers(knl, [no_ret_f_mangler]) knl = lp.register_preamble_generators(knl, [no_ret_f_preamble_gen]) evt, _ = knl(queue)
def _apply_elem_wise_func(inputs: Tuple[ArrayOrScalar, ...], func_name: str, ret_dtype: Optional[_dtype_any] = None, np_func_name: Optional[str] = None ) -> ArrayOrScalar: if all(isinstance(x, SCALAR_CLASSES) for x in inputs): if np_func_name is None: np_func_name = func_name np_func = getattr(np, np_func_name) return np_func(*inputs) # type: ignore if not inputs: raise ValueError("at least one argument must be present") shape = None sym_args = [] bindings = {} for index, inp in enumerate(inputs): if isinstance(inp, Array): if inp.dtype.kind not in ["f", "c"]: raise ValueError("only floating-point or complex " "arguments supported") if shape is None: shape = inp.shape elif inp.shape != shape: # FIXME: merge this logic with arithmetic, so that broadcasting # is implemented properly raise NotImplementedError("broadcasting in function application") if ret_dtype is None: ret_dtype = inp.dtype bindings[f"in_{index}"] = inp sym_args.append( prim.Subscript(var(f"in_{index}"), tuple(var(f"_{i}") for i in range(len(shape))))) else: sym_args.append(inp) assert shape is not None assert ret_dtype is not None return IndexLambda( prim.Call(var(f"pytato.c99.{func_name}"), tuple(sym_args)), shape, ret_dtype, bindings, axes=_get_default_axes(len(shape)))
def statement_functioncall(expr, context): parameters = context.parameters free_indices = set(i.name for i in expr.free_indices) writes = [] reads = [] for access, child in zip(expr.access, expr.children): var = expression(child, parameters) if isinstance(var, pym.Subscript): # tensor argument indices = [] sweeping_indices = [] for index in var.index_tuple: indices.append(index) if isinstance(index, pym.Variable) and index.name in free_indices: sweeping_indices.append(index) arg = SubArrayRef(tuple(sweeping_indices), var) else: # scalar argument or constant arg = var if access is READ or (isinstance(child, Argument) and isinstance(child.dtype, OpaqueType)): reads.append(arg) else: writes.append(arg) within_inames = context.within_inames[expr] predicates = frozenset(context.conditions) id, depends_on = context.instruction_dependencies[expr] call = pym.Call(pym.Variable(expr.name), tuple(reads)) return loopy.CallInstruction(tuple(writes), call, within_inames=within_inames, predicates=predicates, id=id, depends_on=depends_on, depends_on_is_final=True)
def sqrt(x): return primitives.Call( primitives.Lookup(primitives.Variable("math"), "sqrt"), (x,))
def exp(x): return primitives.Call( primitives.Lookup(primitives.Variable("math"), "exp"), (x, ))
def parse_postfix(self, pstate, min_precedence, left_exp): import pymbolic.primitives as primitives import pymbolic.parser as p did_something = False next_tag = pstate.next_tag() if next_tag is p._openpar and p._PREC_CALL > min_precedence: pstate.advance() pstate.expect_not_end() if next_tag is p._closepar: pstate.advance() left_exp = primitives.Call(left_exp, ()) else: args = self.parse_expression(pstate) if not isinstance(args, tuple): args = (args, ) pstate.expect(p._closepar) pstate.advance() if left_exp == primitives.Variable("matrix"): left_exp = np.array(list(list(row) for row in args)) else: left_exp = primitives.Call(left_exp, args) did_something = True elif next_tag is p._openbracket and p._PREC_CALL > min_precedence: pstate.advance() pstate.expect_not_end() left_exp = primitives.Subscript(left_exp, self.parse_expression(pstate)) pstate.expect(p._closebracket) pstate.advance() did_something = True elif next_tag is p._dot and p._PREC_CALL > min_precedence: pstate.advance() pstate.expect(p._identifier) left_exp = primitives.Lookup(left_exp, pstate.next_str()) pstate.advance() did_something = True elif next_tag is p._plus and p._PREC_PLUS > min_precedence: pstate.advance() left_exp += self.parse_expression(pstate, p._PREC_PLUS) did_something = True elif next_tag is p._minus and p._PREC_PLUS > min_precedence: pstate.advance() left_exp -= self.parse_expression(pstate, p._PREC_PLUS) did_something = True elif next_tag is p._times and p._PREC_TIMES > min_precedence: pstate.advance() left_exp *= self.parse_expression(pstate, p._PREC_TIMES) did_something = True elif next_tag is p._over and p._PREC_TIMES > min_precedence: pstate.advance() from pymbolic.primitives import Quotient left_exp = Quotient(left_exp, self.parse_expression(pstate, p._PREC_TIMES)) did_something = True elif next_tag is self.power_sym and p._PREC_POWER > min_precedence: pstate.advance() exponent = self.parse_expression(pstate, p._PREC_POWER) if left_exp == np.e: from pymbolic.primitives import Call, Variable left_exp = Call(Variable("exp"), (exponent, )) else: left_exp **= exponent did_something = True elif next_tag is p._comma and p._PREC_COMMA > min_precedence: # The precedence makes the comma left-associative. pstate.advance() if pstate.is_at_end() or pstate.next_tag() is p._closepar: left_exp = (left_exp, ) else: new_el = self.parse_expression(pstate, p._PREC_COMMA) if isinstance(left_exp, tuple) \ and not isinstance(left_exp, FinalizedTuple): left_exp = left_exp + (new_el, ) else: left_exp = (left_exp, new_el) did_something = True return left_exp, did_something
def fabs(x): return p.Call(p.Lookup(p.Variable("math"), "fabs"), (x, ))
def sign(x): return p.Call(p.Lookup(p.Variable("math"), "copysign"), ( 1, x, ))
def tanh(x): return p.Call(p.Lookup(p.Variable("math"), "tanh"), (x, ))
def expm1(x): return p.Call(p.Lookup(p.Variable("math"), "expm1"), (x, ))
def log(x): return p.Call(p.Lookup(p.Variable("math"), "log"), (x, ))
def cosh(x): return p.Call(p.Lookup(p.Variable("math"), "cosh"), (x, ))
def sin(x): return p.Call(p.Lookup(p.Variable("math"), "sin"), (x, ))
def cos(x): return primitives.Call( primitives.Lookup(primitives.Variable("math"), "cos"), (x, ))
def log(x): return primitives.Call( primitives.Lookup(primitives.Variable("math"), "log"), (x, ))
def parse_postfix(self, pstate, min_precedence, left_exp): import pymbolic.primitives as primitives did_something = False next_tag = pstate.next_tag() if next_tag is _openpar and _PREC_CALL > min_precedence: pstate.advance() args, kwargs = self.parse_arglist(pstate) if kwargs: left_exp = primitives.CallWithKwargs(left_exp, args, kwargs) else: left_exp = primitives.Call(left_exp, args) did_something = True elif next_tag is _openbracket and _PREC_CALL > min_precedence: pstate.advance() pstate.expect_not_end() left_exp = primitives.Subscript(left_exp, self.parse_expression(pstate)) pstate.expect(_closebracket) pstate.advance() did_something = True elif next_tag is _dot and _PREC_CALL > min_precedence: pstate.advance() pstate.expect(_identifier) left_exp = primitives.Lookup(left_exp, pstate.next_str()) pstate.advance() did_something = True elif next_tag is _plus and _PREC_PLUS > min_precedence: pstate.advance() left_exp += self.parse_expression(pstate, _PREC_PLUS) did_something = True elif next_tag is _minus and _PREC_PLUS > min_precedence: pstate.advance() left_exp -= self.parse_expression(pstate, _PREC_PLUS) did_something = True elif next_tag is _times and _PREC_TIMES > min_precedence: pstate.advance() left_exp *= self.parse_expression(pstate, _PREC_TIMES) did_something = True elif next_tag is _floordiv and _PREC_TIMES > min_precedence: pstate.advance() left_exp //= self.parse_expression(pstate, _PREC_TIMES) did_something = True elif next_tag is _over and _PREC_TIMES > min_precedence: pstate.advance() left_exp /= self.parse_expression(pstate, _PREC_TIMES) did_something = True elif next_tag is _modulo and _PREC_TIMES > min_precedence: pstate.advance() left_exp %= self.parse_expression(pstate, _PREC_TIMES) did_something = True elif next_tag is _power and _PREC_POWER > min_precedence: pstate.advance() left_exp **= self.parse_expression(pstate, _PREC_POWER) did_something = True elif next_tag is _and and _PREC_LOGICAL_AND > min_precedence: pstate.advance() from pymbolic.primitives import LogicalAnd left_exp = LogicalAnd( (left_exp, self.parse_expression(pstate, _PREC_LOGICAL_AND))) did_something = True elif next_tag is _or and _PREC_LOGICAL_OR > min_precedence: pstate.advance() from pymbolic.primitives import LogicalOr left_exp = LogicalOr( (left_exp, self.parse_expression(pstate, _PREC_LOGICAL_OR))) did_something = True elif next_tag is _bitwiseor and _PREC_BITWISE_OR > min_precedence: pstate.advance() from pymbolic.primitives import BitwiseOr left_exp = BitwiseOr( (left_exp, self.parse_expression(pstate, _PREC_BITWISE_OR))) did_something = True elif next_tag is _bitwisexor and _PREC_BITWISE_XOR > min_precedence: pstate.advance() from pymbolic.primitives import BitwiseXor left_exp = BitwiseXor( (left_exp, self.parse_expression(pstate, _PREC_BITWISE_XOR))) did_something = True elif next_tag is _bitwiseand and _PREC_BITWISE_AND > min_precedence: pstate.advance() from pymbolic.primitives import BitwiseAnd left_exp = BitwiseAnd( (left_exp, self.parse_expression(pstate, _PREC_BITWISE_AND))) did_something = True elif next_tag is _rightshift and _PREC_SHIFT > min_precedence: pstate.advance() from pymbolic.primitives import RightShift left_exp = RightShift(left_exp, self.parse_expression(pstate, _PREC_SHIFT)) did_something = True elif next_tag is _leftshift and _PREC_SHIFT > min_precedence: pstate.advance() from pymbolic.primitives import LeftShift left_exp = LeftShift(left_exp, self.parse_expression(pstate, _PREC_SHIFT)) did_something = True elif next_tag in self._COMP_TABLE and _PREC_COMPARISON > min_precedence: pstate.advance() from pymbolic.primitives import Comparison left_exp = Comparison( left_exp, self._COMP_TABLE[next_tag], self.parse_expression(pstate, _PREC_COMPARISON)) did_something = True elif next_tag is _colon and _PREC_SLICE >= min_precedence: pstate.advance() expr_pstate = pstate.copy() assert not isinstance(left_exp, primitives.Slice) from pytools.lex import ParseError try: next_expr = self.parse_expression(expr_pstate, _PREC_SLICE) except ParseError: # no expression follows, too bad. left_exp = primitives.Slice(( left_exp, None, )) else: left_exp = _join_to_slice(left_exp, next_expr) pstate.assign(expr_pstate) elif next_tag is _comma and _PREC_COMMA > min_precedence: # The precedence makes the comma left-associative. pstate.advance() if pstate.is_at_end() or pstate.next_tag() is _closepar: left_exp = (left_exp, ) else: new_el = self.parse_expression(pstate, _PREC_COMMA) if isinstance(left_exp, tuple) \ and not isinstance(left_exp, FinalizedTuple): left_exp = left_exp + (new_el, ) else: left_exp = (left_exp, new_el) did_something = True return left_exp, did_something
def parse_postfix(self, pstate, min_precedence, left_exp): import pymbolic.primitives as primitives did_something = False next_tag = pstate.next_tag() if next_tag is _openpar and _PREC_CALL > min_precedence: pstate.advance() args, kwargs = self.parse_arglist(pstate) if kwargs: left_exp = primitives.CallWithKwargs(left_exp, args, kwargs) else: left_exp = primitives.Call(left_exp, args) did_something = True elif next_tag is _openbracket and _PREC_CALL > min_precedence: pstate.advance() pstate.expect_not_end() left_exp = primitives.Subscript(left_exp, self.parse_expression(pstate)) pstate.expect(_closebracket) pstate.advance() did_something = True elif next_tag is _if and _PREC_IF > min_precedence: from pymbolic.primitives import If then_expr = left_exp pstate.advance() pstate.expect_not_end() condition = self.parse_expression(pstate, _PREC_LOGICAL_OR) pstate.expect(_else) pstate.advance() else_expr = self.parse_expression(pstate) left_exp = If(condition, then_expr, else_expr) did_something = True elif next_tag is _dot and _PREC_CALL > min_precedence: pstate.advance() pstate.expect(_identifier) left_exp = primitives.Lookup(left_exp, pstate.next_str()) pstate.advance() did_something = True elif next_tag is _plus and _PREC_PLUS > min_precedence: pstate.advance() right_exp = self.parse_expression(pstate, _PREC_PLUS) if isinstance(left_exp, primitives.Sum): left_exp = primitives.Sum(left_exp.children + (right_exp,)) else: left_exp = primitives.Sum((left_exp, right_exp)) did_something = True elif next_tag is _minus and _PREC_PLUS > min_precedence: pstate.advance() right_exp = self.parse_expression(pstate, _PREC_PLUS) if isinstance(left_exp, primitives.Sum): left_exp = primitives.Sum(left_exp.children + ((-right_exp),)) # noqa pylint:disable=invalid-unary-operand-type else: left_exp = primitives.Sum((left_exp, -right_exp)) # noqa pylint:disable=invalid-unary-operand-type did_something = True elif next_tag is _times and _PREC_TIMES > min_precedence: pstate.advance() right_exp = self.parse_expression(pstate, _PREC_PLUS) if isinstance(left_exp, primitives.Product): left_exp = primitives.Product(left_exp.children + (right_exp,)) else: left_exp = primitives.Product((left_exp, right_exp)) did_something = True elif next_tag is _floordiv and _PREC_TIMES > min_precedence: pstate.advance() left_exp = primitives.FloorDiv( left_exp, self.parse_expression(pstate, _PREC_TIMES)) did_something = True elif next_tag is _over and _PREC_TIMES > min_precedence: pstate.advance() left_exp = primitives.Quotient( left_exp, self.parse_expression(pstate, _PREC_TIMES)) did_something = True elif next_tag is _modulo and _PREC_TIMES > min_precedence: pstate.advance() left_exp = primitives.Remainder( left_exp, self.parse_expression(pstate, _PREC_TIMES)) did_something = True elif next_tag is _power and _PREC_POWER > min_precedence: pstate.advance() left_exp = primitives.Power( left_exp, self.parse_expression(pstate, _PREC_TIMES)) did_something = True elif next_tag is _and and _PREC_LOGICAL_AND > min_precedence: pstate.advance() from pymbolic.primitives import LogicalAnd left_exp = LogicalAnd(( left_exp, self.parse_expression(pstate, _PREC_LOGICAL_AND))) did_something = True elif next_tag is _or and _PREC_LOGICAL_OR > min_precedence: pstate.advance() from pymbolic.primitives import LogicalOr left_exp = LogicalOr(( left_exp, self.parse_expression(pstate, _PREC_LOGICAL_OR))) did_something = True elif next_tag is _bitwiseor and _PREC_BITWISE_OR > min_precedence: pstate.advance() from pymbolic.primitives import BitwiseOr left_exp = BitwiseOr(( left_exp, self.parse_expression(pstate, _PREC_BITWISE_OR))) did_something = True elif next_tag is _bitwisexor and _PREC_BITWISE_XOR > min_precedence: pstate.advance() from pymbolic.primitives import BitwiseXor left_exp = BitwiseXor(( left_exp, self.parse_expression(pstate, _PREC_BITWISE_XOR))) did_something = True elif next_tag is _bitwiseand and _PREC_BITWISE_AND > min_precedence: pstate.advance() from pymbolic.primitives import BitwiseAnd left_exp = BitwiseAnd(( left_exp, self.parse_expression(pstate, _PREC_BITWISE_AND))) did_something = True elif next_tag is _rightshift and _PREC_SHIFT > min_precedence: pstate.advance() from pymbolic.primitives import RightShift left_exp = RightShift( left_exp, self.parse_expression(pstate, _PREC_SHIFT)) did_something = True elif next_tag is _leftshift and _PREC_SHIFT > min_precedence: pstate.advance() from pymbolic.primitives import LeftShift left_exp = LeftShift( left_exp, self.parse_expression(pstate, _PREC_SHIFT)) did_something = True elif next_tag in self._COMP_TABLE and _PREC_COMPARISON > min_precedence: pstate.advance() from pymbolic.primitives import Comparison left_exp = Comparison( left_exp, self._COMP_TABLE[next_tag], self.parse_expression(pstate, _PREC_COMPARISON)) did_something = True elif next_tag is _colon and _PREC_SLICE >= min_precedence: pstate.advance() expr_pstate = pstate.copy() assert not isinstance(left_exp, primitives.Slice) from pytools.lex import ParseError try: next_expr = self.parse_expression(expr_pstate, _PREC_SLICE) except ParseError: # no expression follows, too bad. left_exp = primitives.Slice((left_exp, None,)) else: left_exp = _join_to_slice(left_exp, next_expr) pstate.assign(expr_pstate) did_something = True elif next_tag is _comma and _PREC_COMMA > min_precedence: # The precedence makes the comma left-associative. pstate.advance() if pstate.is_at_end() or pstate.next_tag() is _closepar: if isinstance(left_exp, (tuple, list)) \ and not isinstance(left_exp, FinalizedContainer): # left_expr is a container with trailing commas pass else: left_exp = (left_exp,) else: new_el = self.parse_expression(pstate, _PREC_COMMA) if isinstance(left_exp, (tuple, list)) \ and not isinstance(left_exp, FinalizedContainer): left_exp = left_exp + (new_el,) else: left_exp = (left_exp, new_el) did_something = True return left_exp, did_something
def acosh(x): return primitives.Call( primitives.Lookup(primitives.Variable("math"), "acosh"), (x,))
def tan(x): return primitives.Call( primitives.Lookup(primitives.Variable("math"), "tan"), (x, ))