"""Contains information on how to translate different ufuncs for the CUDA target. It is a database of different ufuncs and how each of its loops maps to a function that implements the inner kernel of that ufunc (the inner kernel being the per-element function). Use get_ufunc_info() to get the information related to a ufunc. """ import math import numpy as np from functools import lru_cache from numba.core import typing from numba.cuda.mathimpl import (get_unary_impl_for_fn_and_ty, get_binary_impl_for_fn_and_ty) def get_ufunc_info(ufunc_key): return ufunc_db()[ufunc_key] @lru_cache def ufunc_db(): # Imports here are at function scope to avoid circular imports from numba.cpython import cmathimpl, mathimpl, numbers from numba.np import npyfuncs from numba.np.numpy_support import numpy_version def np_unary_impl(fn, context, builder, sig, args): npyfuncs._check_arity_and_homogeneity(sig, args, 1) impl = get_unary_impl_for_fn_and_ty(fn, sig.args[0]) return impl(context, builder, sig, args) def np_binary_impl(fn, context, builder, sig, args): npyfuncs._check_arity_and_homogeneity(sig, args, 2) impl = get_binary_impl_for_fn_and_ty(fn, sig.args[0]) return impl(context, builder, sig, args) def np_real_sin_impl(context, builder, sig, args): return np_unary_impl(math.sin, context, builder, sig, args) def np_real_cos_impl(context, builder, sig, args): return np_unary_impl(math.cos, context, builder, sig, args) def np_real_tan_impl(context, builder, sig, args): return np_unary_impl(math.tan, context, builder, sig, args) def np_real_asin_impl(context, builder, sig, args): return np_unary_impl(math.asin, context, builder, sig, args) def np_real_acos_impl(context, builder, sig, args): return np_unary_impl(math.acos, context, builder, sig, args) def np_real_atan_impl(context, builder, sig, args): return np_unary_impl(math.atan, context, builder, sig, args) def np_real_atan2_impl(context, builder, sig, args): return np_binary_impl(math.atan2, context, builder, sig, args) def np_real_hypot_impl(context, builder, sig, args): return np_binary_impl(math.hypot, context, builder, sig, args) def np_real_sinh_impl(context, builder, sig, args): return np_unary_impl(math.sinh, context, builder, sig, args) def np_complex_sinh_impl(context, builder, sig, args): # npymath does not provide a complex sinh. The code in funcs.inc.src # is translated here... npyfuncs._check_arity_and_homogeneity(sig, args, 1) ty = sig.args[0] fty = ty.underlying_float fsig1 = typing.signature(*[fty] * 2) x = context.make_complex(builder, ty, args[0]) out = context.make_complex(builder, ty) xr = x.real xi = x.imag sxi = np_real_sin_impl(context, builder, fsig1, [xi]) shxr = np_real_sinh_impl(context, builder, fsig1, [xr]) cxi = np_real_cos_impl(context, builder, fsig1, [xi]) chxr = np_real_cosh_impl(context, builder, fsig1, [xr]) out.real = builder.fmul(cxi, shxr) out.imag = builder.fmul(sxi, chxr) return out._getvalue() def np_real_cosh_impl(context, builder, sig, args): return np_unary_impl(math.cosh, context, builder, sig, args) def np_complex_cosh_impl(context, builder, sig, args): # npymath does not provide a complex cosh. The code in funcs.inc.src # is translated here... npyfuncs._check_arity_and_homogeneity(sig, args, 1) ty = sig.args[0] fty = ty.underlying_float fsig1 = typing.signature(*[fty] * 2) x = context.make_complex(builder, ty, args[0]) out = context.make_complex(builder, ty) xr = x.real xi = x.imag cxi = np_real_cos_impl(context, builder, fsig1, [xi]) chxr = np_real_cosh_impl(context, builder, fsig1, [xr]) sxi = np_real_sin_impl(context, builder, fsig1, [xi]) shxr = np_real_sinh_impl(context, builder, fsig1, [xr]) out.real = builder.fmul(cxi, chxr) out.imag = builder.fmul(sxi, shxr) return out._getvalue() def np_real_tanh_impl(context, builder, sig, args): return np_unary_impl(math.tanh, context, builder, sig, args) def np_complex_tanh_impl(context, builder, sig, args): # npymath does not provide complex tan functions. The code # in funcs.inc.src for tanh is translated here... npyfuncs._check_arity_and_homogeneity(sig, args, 1) ty = sig.args[0] fty = ty.underlying_float fsig1 = typing.signature(*[fty] * 2) ONE = context.get_constant(fty, 1.0) x = context.make_complex(builder, ty, args[0]) out = context.make_complex(builder, ty) xr = x.real xi = x.imag si = np_real_sin_impl(context, builder, fsig1, [xi]) ci = np_real_cos_impl(context, builder, fsig1, [xi]) shr = np_real_sinh_impl(context, builder, fsig1, [xr]) chr_ = np_real_cosh_impl(context, builder, fsig1, [xr]) rs = builder.fmul(ci, shr) is_ = builder.fmul(si, chr_) rc = builder.fmul(ci, chr_) # Note: opposite sign for `ic` from code in funcs.inc.src ic = builder.fmul(si, shr) sqr_rc = builder.fmul(rc, rc) sqr_ic = builder.fmul(ic, ic) d = builder.fadd(sqr_rc, sqr_ic) inv_d = builder.fdiv(ONE, d) rs_rc = builder.fmul(rs, rc) is_ic = builder.fmul(is_, ic) is_rc = builder.fmul(is_, rc) rs_ic = builder.fmul(rs, ic) numr = builder.fadd(rs_rc, is_ic) numi = builder.fsub(is_rc, rs_ic) out.real = builder.fmul(numr, inv_d) out.imag = builder.fmul(numi, inv_d) return out._getvalue() def np_real_asinh_impl(context, builder, sig, args): return np_unary_impl(math.asinh, context, builder, sig, args) def np_real_acosh_impl(context, builder, sig, args): return np_unary_impl(math.acosh, context, builder, sig, args) def np_real_atanh_impl(context, builder, sig, args): return np_unary_impl(math.atanh, context, builder, sig, args) db = {} db[np.sin] = { 'f->f': np_real_sin_impl, 'd->d': np_real_sin_impl, 'F->F': npyfuncs.np_complex_sin_impl, 'D->D': npyfuncs.np_complex_sin_impl, } db[np.cos] = { 'f->f': np_real_cos_impl, 'd->d': np_real_cos_impl, 'F->F': npyfuncs.np_complex_cos_impl, 'D->D': npyfuncs.np_complex_cos_impl, } db[np.tan] = { 'f->f': np_real_tan_impl, 'd->d': np_real_tan_impl, 'F->F': cmathimpl.tan_impl, 'D->D': cmathimpl.tan_impl, } db[np.arcsin] = { 'f->f': np_real_asin_impl, 'd->d': np_real_asin_impl, 'F->F': cmathimpl.asin_impl, 'D->D': cmathimpl.asin_impl, } db[np.arccos] = { 'f->f': np_real_acos_impl, 'd->d': np_real_acos_impl, 'F->F': cmathimpl.acos_impl, 'D->D': cmathimpl.acos_impl, } db[np.arctan] = { 'f->f': np_real_atan_impl, 'd->d': np_real_atan_impl, 'F->F': cmathimpl.atan_impl, 'D->D': cmathimpl.atan_impl, } db[np.arctan2] = { 'ff->f': np_real_atan2_impl, 'dd->d': np_real_atan2_impl, } db[np.hypot] = { 'ff->f': np_real_hypot_impl, 'dd->d': np_real_hypot_impl, } db[np.sinh] = { 'f->f': np_real_sinh_impl, 'd->d': np_real_sinh_impl, 'F->F': np_complex_sinh_impl, 'D->D': np_complex_sinh_impl, } db[np.cosh] = { 'f->f': np_real_cosh_impl, 'd->d': np_real_cosh_impl, 'F->F': np_complex_cosh_impl, 'D->D': np_complex_cosh_impl, } db[np.tanh] = { 'f->f': np_real_tanh_impl, 'd->d': np_real_tanh_impl, 'F->F': np_complex_tanh_impl, 'D->D': np_complex_tanh_impl, } db[np.arcsinh] = { 'f->f': np_real_asinh_impl, 'd->d': np_real_asinh_impl, 'F->F': cmathimpl.asinh_impl, 'D->D': cmathimpl.asinh_impl, } db[np.arccosh] = { 'f->f': np_real_acosh_impl, 'd->d': np_real_acosh_impl, 'F->F': npyfuncs.np_complex_acosh_impl, 'D->D': npyfuncs.np_complex_acosh_impl, } db[np.arctanh] = { 'f->f': np_real_atanh_impl, 'd->d': np_real_atanh_impl, 'F->F': cmathimpl.atanh_impl, 'D->D': cmathimpl.atanh_impl, } db[np.deg2rad] = { 'f->f': mathimpl.radians_float_impl, 'd->d': mathimpl.radians_float_impl, } db[np.radians] = db[np.deg2rad] db[np.rad2deg] = { 'f->f': mathimpl.degrees_float_impl, 'd->d': mathimpl.degrees_float_impl, } db[np.degrees] = db[np.rad2deg] db[np.greater] = { '??->?': numbers.int_ugt_impl, 'bb->?': numbers.int_sgt_impl, 'BB->?': numbers.int_ugt_impl, 'hh->?': numbers.int_sgt_impl, 'HH->?': numbers.int_ugt_impl, 'ii->?': numbers.int_sgt_impl, 'II->?': numbers.int_ugt_impl, 'll->?': numbers.int_sgt_impl, 'LL->?': numbers.int_ugt_impl, 'qq->?': numbers.int_sgt_impl, 'QQ->?': numbers.int_ugt_impl, 'ff->?': numbers.real_gt_impl, 'dd->?': numbers.real_gt_impl, 'FF->?': npyfuncs.np_complex_gt_impl, 'DD->?': npyfuncs.np_complex_gt_impl, } if numpy_version >= (1, 25): db[np.greater].update({ 'qQ->?': numbers.int_signed_unsigned_cmp('>'), 'Qq->?': numbers.int_unsigned_signed_cmp('>')}) db[np.greater_equal] = { '??->?': numbers.int_uge_impl, 'bb->?': numbers.int_sge_impl, 'BB->?': numbers.int_uge_impl, 'hh->?': numbers.int_sge_impl, 'HH->?': numbers.int_uge_impl, 'ii->?': numbers.int_sge_impl, 'II->?': numbers.int_uge_impl, 'll->?': numbers.int_sge_impl, 'LL->?': numbers.int_uge_impl, 'qq->?': numbers.int_sge_impl, 'QQ->?': numbers.int_uge_impl, 'ff->?': numbers.real_ge_impl, 'dd->?': numbers.real_ge_impl, 'FF->?': npyfuncs.np_complex_ge_impl, 'DD->?': npyfuncs.np_complex_ge_impl, } if numpy_version >= (1, 25): db[np.greater_equal].update({ 'qQ->?': numbers.int_signed_unsigned_cmp('>='), 'Qq->?': numbers.int_unsigned_signed_cmp('>=')}) db[np.less] = { '??->?': numbers.int_ult_impl, 'bb->?': numbers.int_slt_impl, 'BB->?': numbers.int_ult_impl, 'hh->?': numbers.int_slt_impl, 'HH->?': numbers.int_ult_impl, 'ii->?': numbers.int_slt_impl, 'II->?': numbers.int_ult_impl, 'll->?': numbers.int_slt_impl, 'LL->?': numbers.int_ult_impl, 'qq->?': numbers.int_slt_impl, 'QQ->?': numbers.int_ult_impl, 'ff->?': numbers.real_lt_impl, 'dd->?': numbers.real_lt_impl, 'FF->?': npyfuncs.np_complex_lt_impl, 'DD->?': npyfuncs.np_complex_lt_impl, } if numpy_version >= (1, 25): db[np.less].update({ 'qQ->?': numbers.int_signed_unsigned_cmp('<'), 'Qq->?': numbers.int_unsigned_signed_cmp('<')}) db[np.less_equal] = { '??->?': numbers.int_ule_impl, 'bb->?': numbers.int_sle_impl, 'BB->?': numbers.int_ule_impl, 'hh->?': numbers.int_sle_impl, 'HH->?': numbers.int_ule_impl, 'ii->?': numbers.int_sle_impl, 'II->?': numbers.int_ule_impl, 'll->?': numbers.int_sle_impl, 'LL->?': numbers.int_ule_impl, 'qq->?': numbers.int_sle_impl, 'QQ->?': numbers.int_ule_impl, 'ff->?': numbers.real_le_impl, 'dd->?': numbers.real_le_impl, 'FF->?': npyfuncs.np_complex_le_impl, 'DD->?': npyfuncs.np_complex_le_impl, } if numpy_version >= (1, 25): db[np.less_equal].update({ 'qQ->?': numbers.int_signed_unsigned_cmp('<='), 'Qq->?': numbers.int_unsigned_signed_cmp('<=')}) db[np.not_equal] = { '??->?': numbers.int_ne_impl, 'bb->?': numbers.int_ne_impl, 'BB->?': numbers.int_ne_impl, 'hh->?': numbers.int_ne_impl, 'HH->?': numbers.int_ne_impl, 'ii->?': numbers.int_ne_impl, 'II->?': numbers.int_ne_impl, 'll->?': numbers.int_ne_impl, 'LL->?': numbers.int_ne_impl, 'qq->?': numbers.int_ne_impl, 'QQ->?': numbers.int_ne_impl, 'ff->?': numbers.real_ne_impl, 'dd->?': numbers.real_ne_impl, 'FF->?': npyfuncs.np_complex_ne_impl, 'DD->?': npyfuncs.np_complex_ne_impl, } if numpy_version >= (1, 25): db[np.not_equal].update({ 'qQ->?': numbers.int_signed_unsigned_cmp('!='), 'Qq->?': numbers.int_unsigned_signed_cmp('!=')}) db[np.equal] = { '??->?': numbers.int_eq_impl, 'bb->?': numbers.int_eq_impl, 'BB->?': numbers.int_eq_impl, 'hh->?': numbers.int_eq_impl, 'HH->?': numbers.int_eq_impl, 'ii->?': numbers.int_eq_impl, 'II->?': numbers.int_eq_impl, 'll->?': numbers.int_eq_impl, 'LL->?': numbers.int_eq_impl, 'qq->?': numbers.int_eq_impl, 'QQ->?': numbers.int_eq_impl, 'ff->?': numbers.real_eq_impl, 'dd->?': numbers.real_eq_impl, 'FF->?': npyfuncs.np_complex_eq_impl, 'DD->?': npyfuncs.np_complex_eq_impl, } if numpy_version >= (1, 25): db[np.equal].update({ 'qQ->?': numbers.int_signed_unsigned_cmp('=='), 'Qq->?': numbers.int_unsigned_signed_cmp('==')}) db[np.logical_and] = { '??->?': npyfuncs.np_logical_and_impl, 'bb->?': npyfuncs.np_logical_and_impl, 'BB->?': npyfuncs.np_logical_and_impl, 'hh->?': npyfuncs.np_logical_and_impl, 'HH->?': npyfuncs.np_logical_and_impl, 'ii->?': npyfuncs.np_logical_and_impl, 'II->?': npyfuncs.np_logical_and_impl, 'll->?': npyfuncs.np_logical_and_impl, 'LL->?': npyfuncs.np_logical_and_impl, 'qq->?': npyfuncs.np_logical_and_impl, 'QQ->?': npyfuncs.np_logical_and_impl, 'ff->?': npyfuncs.np_logical_and_impl, 'dd->?': npyfuncs.np_logical_and_impl, 'FF->?': npyfuncs.np_complex_logical_and_impl, 'DD->?': npyfuncs.np_complex_logical_and_impl, } db[np.logical_or] = { '??->?': npyfuncs.np_logical_or_impl, 'bb->?': npyfuncs.np_logical_or_impl, 'BB->?': npyfuncs.np_logical_or_impl, 'hh->?': npyfuncs.np_logical_or_impl, 'HH->?': npyfuncs.np_logical_or_impl, 'ii->?': npyfuncs.np_logical_or_impl, 'II->?': npyfuncs.np_logical_or_impl, 'll->?': npyfuncs.np_logical_or_impl, 'LL->?': npyfuncs.np_logical_or_impl, 'qq->?': npyfuncs.np_logical_or_impl, 'QQ->?': npyfuncs.np_logical_or_impl, 'ff->?': npyfuncs.np_logical_or_impl, 'dd->?': npyfuncs.np_logical_or_impl, 'FF->?': npyfuncs.np_complex_logical_or_impl, 'DD->?': npyfuncs.np_complex_logical_or_impl, } db[np.logical_xor] = { '??->?': npyfuncs.np_logical_xor_impl, 'bb->?': npyfuncs.np_logical_xor_impl, 'BB->?': npyfuncs.np_logical_xor_impl, 'hh->?': npyfuncs.np_logical_xor_impl, 'HH->?': npyfuncs.np_logical_xor_impl, 'ii->?': npyfuncs.np_logical_xor_impl, 'II->?': npyfuncs.np_logical_xor_impl, 'll->?': npyfuncs.np_logical_xor_impl, 'LL->?': npyfuncs.np_logical_xor_impl, 'qq->?': npyfuncs.np_logical_xor_impl, 'QQ->?': npyfuncs.np_logical_xor_impl, 'ff->?': npyfuncs.np_logical_xor_impl, 'dd->?': npyfuncs.np_logical_xor_impl, 'FF->?': npyfuncs.np_complex_logical_xor_impl, 'DD->?': npyfuncs.np_complex_logical_xor_impl, } db[np.logical_not] = { '?->?': npyfuncs.np_logical_not_impl, 'b->?': npyfuncs.np_logical_not_impl, 'B->?': npyfuncs.np_logical_not_impl, 'h->?': npyfuncs.np_logical_not_impl, 'H->?': npyfuncs.np_logical_not_impl, 'i->?': npyfuncs.np_logical_not_impl, 'I->?': npyfuncs.np_logical_not_impl, 'l->?': npyfuncs.np_logical_not_impl, 'L->?': npyfuncs.np_logical_not_impl, 'q->?': npyfuncs.np_logical_not_impl, 'Q->?': npyfuncs.np_logical_not_impl, 'f->?': npyfuncs.np_logical_not_impl, 'd->?': npyfuncs.np_logical_not_impl, 'F->?': npyfuncs.np_complex_logical_not_impl, 'D->?': npyfuncs.np_complex_logical_not_impl, } db[np.maximum] = { '??->?': npyfuncs.np_logical_or_impl, 'bb->b': npyfuncs.np_int_smax_impl, 'BB->B': npyfuncs.np_int_umax_impl, 'hh->h': npyfuncs.np_int_smax_impl, 'HH->H': npyfuncs.np_int_umax_impl, 'ii->i': npyfuncs.np_int_smax_impl, 'II->I': npyfuncs.np_int_umax_impl, 'll->l': npyfuncs.np_int_smax_impl, 'LL->L': npyfuncs.np_int_umax_impl, 'qq->q': npyfuncs.np_int_smax_impl, 'QQ->Q': npyfuncs.np_int_umax_impl, 'ff->f': npyfuncs.np_real_maximum_impl, 'dd->d': npyfuncs.np_real_maximum_impl, 'FF->F': npyfuncs.np_complex_maximum_impl, 'DD->D': npyfuncs.np_complex_maximum_impl, } db[np.minimum] = { '??->?': npyfuncs.np_logical_and_impl, 'bb->b': npyfuncs.np_int_smin_impl, 'BB->B': npyfuncs.np_int_umin_impl, 'hh->h': npyfuncs.np_int_smin_impl, 'HH->H': npyfuncs.np_int_umin_impl, 'ii->i': npyfuncs.np_int_smin_impl, 'II->I': npyfuncs.np_int_umin_impl, 'll->l': npyfuncs.np_int_smin_impl, 'LL->L': npyfuncs.np_int_umin_impl, 'qq->q': npyfuncs.np_int_smin_impl, 'QQ->Q': npyfuncs.np_int_umin_impl, 'ff->f': npyfuncs.np_real_minimum_impl, 'dd->d': npyfuncs.np_real_minimum_impl, 'FF->F': npyfuncs.np_complex_minimum_impl, 'DD->D': npyfuncs.np_complex_minimum_impl, } db[np.fmax] = { '??->?': npyfuncs.np_logical_or_impl, 'bb->b': npyfuncs.np_int_smax_impl, 'BB->B': npyfuncs.np_int_umax_impl, 'hh->h': npyfuncs.np_int_smax_impl, 'HH->H': npyfuncs.np_int_umax_impl, 'ii->i': npyfuncs.np_int_smax_impl, 'II->I': npyfuncs.np_int_umax_impl, 'll->l': npyfuncs.np_int_smax_impl, 'LL->L': npyfuncs.np_int_umax_impl, 'qq->q': npyfuncs.np_int_smax_impl, 'QQ->Q': npyfuncs.np_int_umax_impl, 'ff->f': npyfuncs.np_real_fmax_impl, 'dd->d': npyfuncs.np_real_fmax_impl, 'FF->F': npyfuncs.np_complex_fmax_impl, 'DD->D': npyfuncs.np_complex_fmax_impl, } db[np.fmin] = { '??->?': npyfuncs.np_logical_and_impl, 'bb->b': npyfuncs.np_int_smin_impl, 'BB->B': npyfuncs.np_int_umin_impl, 'hh->h': npyfuncs.np_int_smin_impl, 'HH->H': npyfuncs.np_int_umin_impl, 'ii->i': npyfuncs.np_int_smin_impl, 'II->I': npyfuncs.np_int_umin_impl, 'll->l': npyfuncs.np_int_smin_impl, 'LL->L': npyfuncs.np_int_umin_impl, 'qq->q': npyfuncs.np_int_smin_impl, 'QQ->Q': npyfuncs.np_int_umin_impl, 'ff->f': npyfuncs.np_real_fmin_impl, 'dd->d': npyfuncs.np_real_fmin_impl, 'FF->F': npyfuncs.np_complex_fmin_impl, 'DD->D': npyfuncs.np_complex_fmin_impl, } db[np.bitwise_and] = { '??->?': numbers.int_and_impl, 'bb->b': numbers.int_and_impl, 'BB->B': numbers.int_and_impl, 'hh->h': numbers.int_and_impl, 'HH->H': numbers.int_and_impl, 'ii->i': numbers.int_and_impl, 'II->I': numbers.int_and_impl, 'll->l': numbers.int_and_impl, 'LL->L': numbers.int_and_impl, 'qq->q': numbers.int_and_impl, 'QQ->Q': numbers.int_and_impl, } db[np.bitwise_or] = { '??->?': numbers.int_or_impl, 'bb->b': numbers.int_or_impl, 'BB->B': numbers.int_or_impl, 'hh->h': numbers.int_or_impl, 'HH->H': numbers.int_or_impl, 'ii->i': numbers.int_or_impl, 'II->I': numbers.int_or_impl, 'll->l': numbers.int_or_impl, 'LL->L': numbers.int_or_impl, 'qq->q': numbers.int_or_impl, 'QQ->Q': numbers.int_or_impl, } db[np.bitwise_xor] = { '??->?': numbers.int_xor_impl, 'bb->b': numbers.int_xor_impl, 'BB->B': numbers.int_xor_impl, 'hh->h': numbers.int_xor_impl, 'HH->H': numbers.int_xor_impl, 'ii->i': numbers.int_xor_impl, 'II->I': numbers.int_xor_impl, 'll->l': numbers.int_xor_impl, 'LL->L': numbers.int_xor_impl, 'qq->q': numbers.int_xor_impl, 'QQ->Q': numbers.int_xor_impl, } db[np.invert] = { '?->?': numbers.int_invert_impl, 'b->b': numbers.int_invert_impl, 'B->B': numbers.int_invert_impl, 'h->h': numbers.int_invert_impl, 'H->H': numbers.int_invert_impl, 'i->i': numbers.int_invert_impl, 'I->I': numbers.int_invert_impl, 'l->l': numbers.int_invert_impl, 'L->L': numbers.int_invert_impl, 'q->q': numbers.int_invert_impl, 'Q->Q': numbers.int_invert_impl, } db[np.left_shift] = { 'bb->b': numbers.int_shl_impl, 'BB->B': numbers.int_shl_impl, 'hh->h': numbers.int_shl_impl, 'HH->H': numbers.int_shl_impl, 'ii->i': numbers.int_shl_impl, 'II->I': numbers.int_shl_impl, 'll->l': numbers.int_shl_impl, 'LL->L': numbers.int_shl_impl, 'qq->q': numbers.int_shl_impl, 'QQ->Q': numbers.int_shl_impl, } db[np.right_shift] = { 'bb->b': numbers.int_shr_impl, 'BB->B': numbers.int_shr_impl, 'hh->h': numbers.int_shr_impl, 'HH->H': numbers.int_shr_impl, 'ii->i': numbers.int_shr_impl, 'II->I': numbers.int_shr_impl, 'll->l': numbers.int_shr_impl, 'LL->L': numbers.int_shr_impl, 'qq->q': numbers.int_shr_impl, 'QQ->Q': numbers.int_shr_impl, } return db