prompt: 
  We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Add missing NumPy ufuncs: `abs`, `left_shift`, `right_shift`, `positive`
  Add these to `dask.array` for consistency with both `numpy` and the Array API (https://github.com/dask/community/issues/109).
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  
  --- BEGIN FILE ---
  ```
  ### dask/array/ufunc.py
  from functools import partial
  from operator import getitem
  
  import numpy as np
  
  from dask import core
  from dask.array.core import Array, apply_infer_dtype, asarray, blockwise, elemwise
  from dask.base import is_dask_collection, normalize_function
  from dask.highlevelgraph import HighLevelGraph
  from dask.utils import derived_from, funcname
  
  
  def wrap_elemwise(numpy_ufunc, source=np):
      """Wrap up numpy function into dask.array"""
  
      def wrapped(*args, **kwargs):
          dsk = [arg for arg in args if hasattr(arg, "_elemwise")]
          if len(dsk) > 0:
              return dsk[0]._elemwise(numpy_ufunc, *args, **kwargs)
          else:
              return numpy_ufunc(*args, **kwargs)
  
      # functools.wraps cannot wrap ufunc in Python 2.x
      wrapped.__name__ = numpy_ufunc.__name__
      return derived_from(source)(wrapped)
  
  
  class da_frompyfunc:
      """A serializable `frompyfunc` object"""
  
      def __init__(self, func, nin, nout):
          self._ufunc = np.frompyfunc(func, nin, nout)
          self._func = func
          self.nin = nin
          self.nout = nout
          self._name = funcname(func)
          self.__name__ = "frompyfunc-%s" % self._name
  
      def __repr__(self):
          return "da.frompyfunc<%s, %d, %d>" % (self._name, self.nin, self.nout)
  
      def __dask_tokenize__(self):
          return (normalize_function(self._func), self.nin, self.nout)
  
      def __reduce__(self):
          return (da_frompyfunc, (self._func, self.nin, self.nout))
  
      def __call__(self, *args, **kwargs):
          return self._ufunc(*args, **kwargs)
  
      def __getattr__(self, a):
          if not a.startswith("_"):
              return getattr(self._ufunc, a)
          raise AttributeError(f"{type(self).__name__!r} object has no attribute {a!r}")
  
      def __dir__(self):
          o = set(dir(type(self)))
          o.update(self.__dict__)
          o.update(dir(self._ufunc))
          return list(o)
  
  
  @derived_from(np)
  def frompyfunc(func, nin, nout):
      if nout > 1:
          raise NotImplementedError("frompyfunc with more than one output")
      return ufunc(da_frompyfunc(func, nin, nout))
  
  
  class ufunc:
      _forward_attrs = {
          "nin",
          "nargs",
          "nout",
          "ntypes",
          "identity",
          "signature",
          "types",
      }
  
      def __init__(self, ufunc):
          if not isinstance(ufunc, (np.ufunc, da_frompyfunc)):
              raise TypeError(
                  "must be an instance of `ufunc` or "
                  "`da_frompyfunc`, got `%s" % type(ufunc).__name__
              )
          self._ufunc = ufunc
          self.__name__ = ufunc.__name__
          if isinstance(ufunc, np.ufunc):
              derived_from(np)(self)
  
      def __getattr__(self, key):
          if key in self._forward_attrs:
              return getattr(self._ufunc, key)
          raise AttributeError(f"{type(self).__name__!r} object has no attribute {key!r}")
  
      def __dir__(self):
          return list(self._forward_attrs.union(dir(type(self)), self.__dict__))
  
      def __repr__(self):
          return repr(self._ufunc)
  
      def __call__(self, *args, **kwargs):
          dsks = [arg for arg in args if hasattr(arg, "_elemwise")]
          if len(dsks) > 0:
              for dsk in dsks:
                  result = dsk._elemwise(self._ufunc, *args, **kwargs)
                  if type(result) != type(NotImplemented):
                      return result
              raise TypeError(
                  "Parameters of such types are not supported by " + self.__name__
              )
          else:
              return self._ufunc(*args, **kwargs)
  
      @derived_from(np.ufunc)
      def outer(self, A, B, **kwargs):
          if self.nin != 2:
              raise ValueError("outer product only supported for binary functions")
          if "out" in kwargs:
              raise ValueError("`out` kwarg not supported")
  
          A_is_dask = is_dask_collection(A)
          B_is_dask = is_dask_collection(B)
          if not A_is_dask and not B_is_dask:
              return self._ufunc.outer(A, B, **kwargs)
          elif (
              A_is_dask
              and not isinstance(A, Array)
              or B_is_dask
              and not isinstance(B, Array)
          ):
              raise NotImplementedError(
                  "Dask objects besides `dask.array.Array` "
                  "are not supported at this time."
              )
  
          A = asarray(A)
          B = asarray(B)
          ndim = A.ndim + B.ndim
          out_inds = tuple(range(ndim))
          A_inds = out_inds[: A.ndim]
          B_inds = out_inds[A.ndim :]
  
          dtype = apply_infer_dtype(
              self._ufunc.outer, [A, B], kwargs, "ufunc.outer", suggest_dtype=False
          )
  
          if "dtype" in kwargs:
              func = partial(self._ufunc.outer, dtype=kwargs.pop("dtype"))
          else:
              func = self._ufunc.outer
  
          return blockwise(
              func,
              out_inds,
              A,
              A_inds,
              B,
              B_inds,
              dtype=dtype,
              token=self.__name__ + ".outer",
              **kwargs,
          )
  
  
  # ufuncs, copied from this page:
  # https://docs.scipy.org/doc/numpy/reference/ufuncs.html
  
  # math operations
  add = ufunc(np.add)
  subtract = ufunc(np.subtract)
  multiply = ufunc(np.multiply)
  divide = ufunc(np.divide)
  logaddexp = ufunc(np.logaddexp)
  logaddexp2 = ufunc(np.logaddexp2)
  true_divide = ufunc(np.true_divide)
  floor_divide = ufunc(np.floor_divide)
  negative = ufunc(np.negative)
  power = ufunc(np.power)
  float_power = ufunc(np.float_power)
  remainder = ufunc(np.remainder)
  mod = ufunc(np.mod)
  # fmod: see below
  conj = conjugate = ufunc(np.conjugate)
  exp = ufunc(np.exp)
  exp2 = ufunc(np.exp2)
  log = ufunc(np.log)
  log2 = ufunc(np.log2)
  log10 = ufunc(np.log10)
  log1p = ufunc(np.log1p)
  expm1 = ufunc(np.expm1)
  sqrt = ufunc(np.sqrt)
  square = ufunc(np.square)
  cbrt = ufunc(np.cbrt)
  reciprocal = ufunc(np.reciprocal)
  
  # trigonometric functions
  sin = ufunc(np.sin)
  cos = ufunc(np.cos)
  tan = ufunc(np.tan)
  arcsin = ufunc(np.arcsin)
  arccos = ufunc(np.arccos)
  arctan = ufunc(np.arctan)
  arctan2 = ufunc(np.arctan2)
  hypot = ufunc(np.hypot)
  sinh = ufunc(np.sinh)
  cosh = ufunc(np.cosh)
  tanh = ufunc(np.tanh)
  arcsinh = ufunc(np.arcsinh)
  arccosh = ufunc(np.arccosh)
  arctanh = ufunc(np.arctanh)
  deg2rad = ufunc(np.deg2rad)
  rad2deg = ufunc(np.rad2deg)
  
  # comparison functions
  greater = ufunc(np.greater)
  greater_equal = ufunc(np.greater_equal)
  less = ufunc(np.less)
  less_equal = ufunc(np.less_equal)
  not_equal = ufunc(np.not_equal)
  equal = ufunc(np.equal)
  isneginf = partial(equal, -np.inf)
  isposinf = partial(equal, np.inf)
  logical_and = ufunc(np.logical_and)
  logical_or = ufunc(np.logical_or)
  logical_xor = ufunc(np.logical_xor)
  logical_not = ufunc(np.logical_not)
  maximum = ufunc(np.maximum)
  minimum = ufunc(np.minimum)
  fmax = ufunc(np.fmax)
  fmin = ufunc(np.fmin)
  
  # bitwise functions
  bitwise_and = ufunc(np.bitwise_and)
  bitwise_or = ufunc(np.bitwise_or)
  bitwise_xor = ufunc(np.bitwise_xor)
  bitwise_not = ufunc(np.bitwise_not)
  invert = bitwise_not
  
  # floating functions
  isfinite = ufunc(np.isfinite)
  isinf = ufunc(np.isinf)
  isnan = ufunc(np.isnan)
  signbit = ufunc(np.signbit)
  copysign = ufunc(np.copysign)
  nextafter = ufunc(np.nextafter)
  spacing = ufunc(np.spacing)
  # modf: see below
  ldexp = ufunc(np.ldexp)
  # frexp: see below
  fmod = ufunc(np.fmod)
  floor = ufunc(np.floor)
  ceil = ufunc(np.ceil)
  trunc = ufunc(np.trunc)
  
  # more math routines, from this page:
  # https://docs.scipy.org/doc/numpy/reference/routines.math.html
  degrees = ufunc(np.degrees)
  radians = ufunc(np.radians)
  rint = ufunc(np.rint)
  fabs = ufunc(np.fabs)
  sign = ufunc(np.sign)
  absolute = ufunc(np.absolute)
  
  # non-ufunc elementwise functions
  clip = wrap_elemwise(np.clip)
  isreal = wrap_elemwise(np.isreal)
  iscomplex = wrap_elemwise(np.iscomplex)
  real = wrap_elemwise(np.real)
  imag = wrap_elemwise(np.imag)
  fix = wrap_elemwise(np.fix)
  i0 = wrap_elemwise(np.i0)
  sinc = wrap_elemwise(np.sinc)
  nan_to_num = wrap_elemwise(np.nan_to_num)
  
  
  @derived_from(np)
  def angle(x, deg=0):
      deg = bool(deg)
      if hasattr(x, "_elemwise"):
          return x._elemwise(np.angle, x, deg)
      return np.angle(x, deg=deg)
  
  
  @derived_from(np)
  def frexp(x):
      # Not actually object dtype, just need to specify something
      tmp = elemwise(np.frexp, x, dtype=object)
      left = "mantissa-" + tmp.name
      right = "exponent-" + tmp.name
      ldsk = {
          (left,) + key[1:]: (getitem, key, 0)
          for key in core.flatten(tmp.__dask_keys__())
      }
      rdsk = {
          (right,) + key[1:]: (getitem, key, 1)
          for key in core.flatten(tmp.__dask_keys__())
      }
  
      a = np.empty_like(getattr(x, "_meta", x), shape=(1,) * x.ndim, dtype=x.dtype)
      l, r = np.frexp(a)
  
      graph = HighLevelGraph.from_collections(left, ldsk, dependencies=[tmp])
      L = Array(graph, left, chunks=tmp.chunks, meta=l)
      graph = HighLevelGraph.from_collections(right, rdsk, dependencies=[tmp])
      R = Array(graph, right, chunks=tmp.chunks, meta=r)
      return L, R
  
  
  @derived_from(np)
  def modf(x):
      # Not actually object dtype, just need to specify something
      tmp = elemwise(np.modf, x, dtype=object)
      left = "modf1-" + tmp.name
      right = "modf2-" + tmp.name
      ldsk = {
          (left,) + key[1:]: (getitem, key, 0)
          for key in core.flatten(tmp.__dask_keys__())
      }
      rdsk = {
          (right,) + key[1:]: (getitem, key, 1)
          for key in core.flatten(tmp.__dask_keys__())
      }
  
      a = np.empty_like(getattr(x, "_meta", x), shape=(1,) * x.ndim, dtype=x.dtype)
      l, r = np.modf(a)
  
      graph = HighLevelGraph.from_collections(left, ldsk, dependencies=[tmp])
      L = Array(graph, left, chunks=tmp.chunks, meta=l)
      graph = HighLevelGraph.from_collections(right, rdsk, dependencies=[tmp])
      R = Array(graph, right, chunks=tmp.chunks, meta=r)
      return L, R
  
  
  @derived_from(np)
  def divmod(x, y):
      res1 = x // y
      res2 = x % y
      return res1, res2
  
  
  ### dask/array/__init__.py
  try:
      from dask.array import backends, fft, lib, linalg, ma, overlap, random
      from dask.array.blockwise import atop, blockwise
      from dask.array.chunk_types import register_chunk_type
      from dask.array.core import (
          Array,
          PerformanceWarning,
          asanyarray,
          asarray,
          block,
          broadcast_arrays,
          broadcast_to,
          concatenate,
          from_array,
          from_delayed,
          from_npy_stack,
          from_zarr,
          map_blocks,
          stack,
          store,
          to_hdf5,
          to_npy_stack,
          to_zarr,
          unify_chunks,
      )
      from dask.array.creation import (
          arange,
          diag,
          diagonal,
          empty_like,
          eye,
          fromfunction,
          full_like,
          indices,
          linspace,
          meshgrid,
          ones_like,
          pad,
          repeat,
          tile,
          tri,
          zeros_like,
      )
      from dask.array.gufunc import apply_gufunc, as_gufunc, gufunc
      from dask.array.numpy_compat import moveaxis, rollaxis
      from dask.array.optimization import optimize
      from dask.array.overlap import map_overlap
      from dask.array.percentile import percentile
      from dask.array.rechunk import rechunk
      from dask.array.reductions import (
          all,
          any,
          argmax,
          argmin,
          argtopk,
          cumprod,
          cumsum,
          max,
          mean,
          median,
          min,
          moment,
          nanargmax,
          nanargmin,
          nancumprod,
          nancumsum,
          nanmax,
          nanmean,
          nanmedian,
          nanmin,
          nanprod,
          nanstd,
          nansum,
          nanvar,
          prod,
          reduction,
          std,
          sum,
          topk,
          trace,
          var,
      )
      from dask.array.reshape import reshape
      from dask.array.routines import (
          allclose,
          append,
          apply_along_axis,
          apply_over_axes,
          argwhere,
          around,
          array,
          atleast_1d,
          atleast_2d,
          atleast_3d,
          average,
          bincount,
          choose,
          coarsen,
          compress,
          corrcoef,
          count_nonzero,
          cov,
          delete,
          diff,
          digitize,
          dot,
          dstack,
          ediff1d,
          einsum,
          expand_dims,
          extract,
          flatnonzero,
          flip,
          fliplr,
          flipud,
          gradient,
          histogram,
          histogram2d,
          histogramdd,
          hstack,
          insert,
          isclose,
          isin,
          isnull,
          matmul,
          ndim,
          nonzero,
          notnull,
          outer,
          piecewise,
          ptp,
          ravel,
          ravel_multi_index,
          result_type,
          roll,
          rot90,
          round,
          searchsorted,
          select,
          shape,
          squeeze,
          swapaxes,
          take,
          tensordot,
          transpose,
          tril,
          tril_indices,
          tril_indices_from,
          triu,
          triu_indices,
          triu_indices_from,
          union1d,
          unique,
          unravel_index,
          vdot,
          vstack,
          where,
      )
      from dask.array.tiledb_io import from_tiledb, to_tiledb
      from dask.array.ufunc import (
          absolute,
          add,
          angle,
          arccos,
          arccosh,
          arcsin,
          arcsinh,
          arctan,
          arctan2,
          arctanh,
          bitwise_and,
          bitwise_not,
          bitwise_or,
          bitwise_xor,
          cbrt,
          ceil,
          clip,
          conj,
          copysign,
          cos,
          cosh,
          deg2rad,
          degrees,
          divide,
          divmod,
          equal,
          exp,
          exp2,
          expm1,
          fabs,
          fix,
          float_power,
          floor,
          floor_divide,
          fmax,
          fmin,
          fmod,
          frexp,
          frompyfunc,
          greater,
          greater_equal,
          hypot,
          i0,
          imag,
          invert,
          iscomplex,
          isfinite,
          isinf,
          isnan,
          isneginf,
          isposinf,
          isreal,
          ldexp,
          less,
          less_equal,
          log,
          log1p,
          log2,
          log10,
          logaddexp,
          logaddexp2,
          logical_and,
          logical_not,
          logical_or,
          logical_xor,
          maximum,
          minimum,
          mod,
          modf,
          multiply,
          nan_to_num,
          negative,
          nextafter,
          not_equal,
          power,
          rad2deg,
          radians,
          real,
          reciprocal,
          remainder,
          rint,
          sign,
          signbit,
          sin,
          sinc,
          sinh,
          spacing,
          sqrt,
          square,
          subtract,
          tan,
          tanh,
          true_divide,
          trunc,
      )
      from dask.array.utils import assert_eq
      from dask.array.wrap import empty, full, ones, zeros
      from dask.base import compute
  
  except ImportError as e:
      msg = (
          "Dask array requirements are not installed.\n\n"
          "Please either conda or pip install as follows:\n\n"
          "  conda install dask                 # either conda install\n"
          '  python -m pip install "dask[array]" --upgrade  # or python -m pip install'
      )
      raise ImportError(str(e) + "\n\n" + msg) from e
  
  ```
  --- END FILE ---
  
  Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.
  
  Every *SEARCH/REPLACE* edit must use this format:
  1. The file path
  2. The start of search block: <<<<<<< SEARCH
  3. A contiguous chunk of lines to search for in the existing source code
  4. The dividing line: =======
  5. The lines to replace into the source code
  6. The end of the replace block: >>>>>>> REPLACE
  
  Here is an example:
  
  ```python
  ### mathweb/flask/app.py
  <<<<<<< SEARCH
  from flask import Flask
  =======
  import math
  from flask import Flask
  >>>>>>> REPLACE
  ```
  
  Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
  Wrap the *SEARCH/REPLACE* edit in blocks ```python...```.
  
instance: {"FAIL_TO_PASS": ["dask/array/tests/test_ufunc.py::test_unary_ufunc[abs]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[positive]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[right_shift]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[left_shift]"], "PASS_TO_PASS": ["dask/array/tests/test_ufunc.py::test_ufunc_where[True-True-True-None]", "dask/array/tests/test_ufunc.py::test_complex[iscomplex]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[fabs]", "dask/array/tests/test_ufunc.py::test_ufunc_where_broadcasts[True-True-False]", "dask/array/tests/test_ufunc.py::test_ufunc_meta[log]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[log1p]", "dask/array/tests/test_ufunc.py::test_array_ufunc", "dask/array/tests/test_ufunc.py::test_unary_ufunc[arccosh]", "dask/array/tests/test_ufunc.py::test_ufunc_where[numpy-True-True-None]", "dask/array/tests/test_ufunc.py::test_ufunc_where[dask-True-True-f8]", "dask/array/tests/test_ufunc.py::test_out_shape_mismatch", "dask/array/tests/test_ufunc.py::test_binary_ufunc[bitwise_or]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[log2]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[fmin]", "dask/array/tests/test_ufunc.py::test_ufunc_where[numpy-False-True-f8]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[minimum]", "dask/array/tests/test_ufunc.py::test_divmod", "dask/array/tests/test_ufunc.py::test_ufunc_meta[modf]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[floor]", "dask/array/tests/test_ufunc.py::test_clip", "dask/array/tests/test_ufunc.py::test_ufunc_where[False-True-False-f8]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[isfinite]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[spacing]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[square]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[greater_equal]", "dask/array/tests/test_ufunc.py::test_ufunc_where[numpy-True-True-f8]", "dask/array/tests/test_ufunc.py::test_ufunc_where_broadcasts[False-False-True]", "dask/array/tests/test_ufunc.py::test_ufunc_where[False-True-True-f8]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[exp2]", "dask/array/tests/test_ufunc.py::test_out_numpy", "dask/array/tests/test_ufunc.py::test_unary_ufunc[arcsin]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[fmax]", "dask/array/tests/test_ufunc.py::test_complex[imag]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[floor_divide]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[isinf]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[float_power]", "dask/array/tests/test_ufunc.py::test_ufunc_where[dask-False-False-f8]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[fmod]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[radians]", "dask/array/tests/test_ufunc.py::test_ufunc_where[True-True-True-f8]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[ceil]", "dask/array/tests/test_ufunc.py::test_ufunc_where[True-True-False-None]", "dask/array/tests/test_ufunc.py::test_frompyfunc", "dask/array/tests/test_ufunc.py::test_unary_ufunc[tanh]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[remainder]", "dask/array/tests/test_ufunc.py::test_ufunc_where[True-False-True-None]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[arccos]", "dask/array/tests/test_ufunc.py::test_ufunc_where[False-False-True-None]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[exp]", "dask/array/tests/test_ufunc.py::test_ufunc_where_doesnt_mutate_out", "dask/array/tests/test_ufunc.py::test_binary_ufunc[bitwise_and]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[sqrt]", "dask/array/tests/test_ufunc.py::test_ufunc_where[False-True-False-None]", "dask/array/tests/test_ufunc.py::test_ufunc_where[dask-True-False-None]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[rint]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[absolute]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[trunc]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[expm1]", "dask/array/tests/test_ufunc.py::test_ufunc_where_broadcasts[True-True-True]", "dask/array/tests/test_ufunc.py::test_ufunc_2results[frexp]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[bitwise_xor]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[logical_not]", "dask/array/tests/test_ufunc.py::test_ufunc_where[True-False-False-None]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[arctanh]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[cos]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[nextafter]", "dask/array/tests/test_ufunc.py::test_dtype_kwarg[float32]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[less_equal]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[true_divide]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[sign]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[sin]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[logical_xor]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[logical_or]", "dask/array/tests/test_ufunc.py::test_ufunc_where_broadcasts[True-False-True]", "dask/array/tests/test_ufunc.py::test_issignedinf", "dask/array/tests/test_ufunc.py::test_ufunc_where[False-False-False-f8]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[divide]", "dask/array/tests/test_ufunc.py::test_array_ufunc_binop", "dask/array/tests/test_ufunc.py::test_ufunc_where[dask-True-True-None]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[tan]", "dask/array/tests/test_ufunc.py::test_ufunc_where_no_out", "dask/array/tests/test_ufunc.py::test_dtype_kwarg[int64]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[bitwise_not]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[arctan]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[isnan]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[less]", "dask/array/tests/test_ufunc.py::test_ufunc_where[False-True-True-None]", "dask/array/tests/test_ufunc.py::test_angle", "dask/array/tests/test_ufunc.py::test_non_ufunc_others[nan_to_num]", "dask/array/tests/test_ufunc.py::test_complex[real]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[log10]", "dask/array/tests/test_ufunc.py::test_ufunc_where[numpy-False-False-f8]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[mod]", "dask/array/tests/test_ufunc.py::test_ufunc_where_broadcasts[False-True-True]", "dask/array/tests/test_ufunc.py::test_non_ufunc_others[sinc]", "dask/array/tests/test_ufunc.py::test_ufunc_where[True-False-True-f8]", "dask/array/tests/test_ufunc.py::test_dtype_kwarg[int32]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[cosh]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[copysign]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[logical_and]", "dask/array/tests/test_ufunc.py::test_ufunc_where[dask-False-True-f8]", "dask/array/tests/test_ufunc.py::test_ufunc_where_broadcasts[True-False-False]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[maximum]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[deg2rad]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[reciprocal]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[signbit]", "dask/array/tests/test_ufunc.py::test_ufunc_meta[frexp]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[add]", "dask/array/tests/test_ufunc.py::test_ufunc", "dask/array/tests/test_ufunc.py::test_binary_ufunc[greater]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[negative]", "dask/array/tests/test_ufunc.py::test_ufunc_2results[modf]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[not_equal]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[multiply]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[degrees]", "dask/array/tests/test_ufunc.py::test_ufunc_where[dask-False-True-None]", "dask/array/tests/test_ufunc.py::test_ufunc_where[dask-True-False-f8]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[logaddexp2]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[sinh]", "dask/array/tests/test_ufunc.py::test_frompyfunc_wrapper", "dask/array/tests/test_ufunc.py::test_ufunc_outer", "dask/array/tests/test_ufunc.py::test_binary_ufunc[hypot]", "dask/array/tests/test_ufunc.py::test_non_ufunc_others[i0]", "dask/array/tests/test_ufunc.py::test_ufunc_where[dask-False-False-None]", "dask/array/tests/test_ufunc.py::test_array_ufunc_out", "dask/array/tests/test_ufunc.py::test_dtype_kwarg[float64]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[arcsinh]", "dask/array/tests/test_ufunc.py::test_ufunc_where_broadcasts[False-True-False]", "dask/array/tests/test_ufunc.py::test_ufunc_where[numpy-True-False-None]", "dask/array/tests/test_ufunc.py::test_complex[isreal]", "dask/array/tests/test_ufunc.py::test_ufunc_where[False-False-False-None]", "dask/array/tests/test_ufunc.py::test_ufunc_where[numpy-True-False-f8]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[arctan2]", "dask/array/tests/test_ufunc.py::test_unsupported_ufunc_methods", "dask/array/tests/test_ufunc.py::test_unary_ufunc[conj]", "dask/array/tests/test_ufunc.py::test_ufunc_where[True-False-False-f8]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[equal]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[logaddexp]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[power]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[subtract]", "dask/array/tests/test_ufunc.py::test_ufunc_where[numpy-False-False-None]", "dask/array/tests/test_ufunc.py::test_ufunc_where[True-True-False-f8]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[cbrt]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[invert]", "dask/array/tests/test_ufunc.py::test_ufunc_where_broadcasts[False-False-False]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[rad2deg]", "dask/array/tests/test_ufunc.py::test_ufunc_where[numpy-False-True-None]", "dask/array/tests/test_ufunc.py::test_ufunc_where[False-False-True-f8]", "dask/array/tests/test_ufunc.py::test_binary_ufunc[ldexp]", "dask/array/tests/test_ufunc.py::test_unary_ufunc[log]"], "base_commit": "723e0d223c2921e30d4324cac60d2256ad13386b", "created_at": "2022-04-13T10:35:58Z", "hints_text": "", "instance_id": "dask__dask-8920", "patch": "diff --git a/dask/array/__init__.py b/dask/array/__init__.py\n--- a/dask/array/__init__.py\n+++ b/dask/array/__init__.py\n@@ -158,6 +158,7 @@\n     )\n     from dask.array.tiledb_io import from_tiledb, to_tiledb\n     from dask.array.ufunc import (\n+        abs,\n         absolute,\n         add,\n         angle,\n@@ -211,6 +212,7 @@\n         isposinf,\n         isreal,\n         ldexp,\n+        left_shift,\n         less,\n         less_equal,\n         log,\n@@ -232,12 +234,14 @@\n         negative,\n         nextafter,\n         not_equal,\n+        positive,\n         power,\n         rad2deg,\n         radians,\n         real,\n         reciprocal,\n         remainder,\n+        right_shift,\n         rint,\n         sign,\n         signbit,\ndiff --git a/dask/array/ufunc.py b/dask/array/ufunc.py\n--- a/dask/array/ufunc.py\n+++ b/dask/array/ufunc.py\n@@ -177,6 +177,7 @@ def outer(self, A, B, **kwargs):\n true_divide = ufunc(np.true_divide)\n floor_divide = ufunc(np.floor_divide)\n negative = ufunc(np.negative)\n+positive = ufunc(np.positive)\n power = ufunc(np.power)\n float_power = ufunc(np.float_power)\n remainder = ufunc(np.remainder)\n@@ -237,6 +238,8 @@ def outer(self, A, B, **kwargs):\n bitwise_xor = ufunc(np.bitwise_xor)\n bitwise_not = ufunc(np.bitwise_not)\n invert = bitwise_not\n+left_shift = ufunc(np.left_shift)\n+right_shift = ufunc(np.right_shift)\n \n # floating functions\n isfinite = ufunc(np.isfinite)\n@@ -262,6 +265,7 @@ def outer(self, A, B, **kwargs):\n fabs = ufunc(np.fabs)\n sign = ufunc(np.sign)\n absolute = ufunc(np.absolute)\n+abs = absolute\n \n # non-ufunc elementwise functions\n clip = wrap_elemwise(np.clip)\n", "problem_statement": "Add missing NumPy ufuncs: `abs`, `left_shift`, `right_shift`, `positive`\nAdd these to `dask.array` for consistency with both `numpy` and the Array API (https://github.com/dask/community/issues/109).\r\n\n", "repo": "dask/dask", "test_patch": "diff --git a/dask/array/tests/test_ufunc.py b/dask/array/tests/test_ufunc.py\n--- a/dask/array/tests/test_ufunc.py\n+++ b/dask/array/tests/test_ufunc.py\n@@ -62,6 +62,7 @@ def test_ufunc():\n     \"greater_equal\",\n     \"hypot\",\n     \"ldexp\",\n+    \"left_shift\",\n     \"less\",\n     \"less_equal\",\n     \"logaddexp\",\n@@ -77,12 +78,14 @@ def test_ufunc():\n     \"not_equal\",\n     \"power\",\n     \"remainder\",\n+    \"right_shift\",\n     \"subtract\",\n     \"true_divide\",\n     \"float_power\",\n ]\n \n unary_ufuncs = [\n+    \"abs\",\n     \"absolute\",\n     \"arccos\",\n     \"arccosh\",\n@@ -114,6 +117,7 @@ def test_ufunc():\n     \"log2\",\n     \"logical_not\",\n     \"negative\",\n+    \"positive\",\n     \"rad2deg\",\n     \"radians\",\n     \"reciprocal\",\n", "version": "2022.04"}
parsed_commit_content: {"file_diffs":[{"old_file_content":"try:\n    from dask.array import backends, fft, lib, linalg, ma, overlap, random\n    from dask.array.blockwise import atop, blockwise\n    from dask.array.chunk_types import register_chunk_type\n    from dask.array.core import (\n        Array,\n        PerformanceWarning,\n        asanyarray,\n        asarray,\n        block,\n        broadcast_arrays,\n        broadcast_to,\n        concatenate,\n        from_array,\n        from_delayed,\n        from_npy_stack,\n        from_zarr,\n        map_blocks,\n        stack,\n        store,\n        to_hdf5,\n        to_npy_stack,\n        to_zarr,\n        unify_chunks,\n    )\n    from dask.array.creation import (\n        arange,\n        diag,\n        diagonal,\n        empty_like,\n        eye,\n        fromfunction,\n        full_like,\n        indices,\n        linspace,\n        meshgrid,\n        ones_like,\n        pad,\n        repeat,\n        tile,\n        tri,\n        zeros_like,\n    )\n    from dask.array.gufunc import apply_gufunc, as_gufunc, gufunc\n    from dask.array.numpy_compat import moveaxis, rollaxis\n    from dask.array.optimization import optimize\n    from dask.array.overlap import map_overlap\n    from dask.array.percentile import percentile\n    from dask.array.rechunk import rechunk\n    from dask.array.reductions import (\n        all,\n        any,\n        argmax,\n        argmin,\n        argtopk,\n        cumprod,\n        cumsum,\n        max,\n        mean,\n        median,\n        min,\n        moment,\n        nanargmax,\n        nanargmin,\n        nancumprod,\n        nancumsum,\n        nanmax,\n        nanmean,\n        nanmedian,\n        nanmin,\n        nanprod,\n        nanstd,\n        nansum,\n        nanvar,\n        prod,\n        reduction,\n        std,\n        sum,\n        topk,\n        trace,\n        var,\n    )\n    from dask.array.reshape import reshape\n    from dask.array.routines import (\n        allclose,\n        append,\n        apply_along_axis,\n        apply_over_axes,\n        argwhere,\n        around,\n        array,\n        atleast_1d,\n        atleast_2d,\n        atleast_3d,\n        average,\n        bincount,\n        choose,\n        coarsen,\n        compress,\n        corrcoef,\n        count_nonzero,\n        cov,\n        delete,\n        diff,\n        digitize,\n        dot,\n        dstack,\n        ediff1d,\n        einsum,\n        expand_dims,\n        extract,\n        flatnonzero,\n        flip,\n        fliplr,\n        flipud,\n        gradient,\n        histogram,\n        histogram2d,\n        histogramdd,\n        hstack,\n        insert,\n        isclose,\n        isin,\n        isnull,\n        matmul,\n        ndim,\n        nonzero,\n        notnull,\n        outer,\n        piecewise,\n        ptp,\n        ravel,\n        ravel_multi_index,\n        result_type,\n        roll,\n        rot90,\n        round,\n        searchsorted,\n        select,\n        shape,\n        squeeze,\n        swapaxes,\n        take,\n        tensordot,\n        transpose,\n        tril,\n        tril_indices,\n        tril_indices_from,\n        triu,\n        triu_indices,\n        triu_indices_from,\n        union1d,\n        unique,\n        unravel_index,\n        vdot,\n        vstack,\n        where,\n    )\n    from dask.array.tiledb_io import from_tiledb, to_tiledb\n    from dask.array.ufunc import (\n        absolute,\n        add,\n        angle,\n        arccos,\n        arccosh,\n        arcsin,\n        arcsinh,\n        arctan,\n        arctan2,\n        arctanh,\n        bitwise_and,\n        bitwise_not,\n        bitwise_or,\n        bitwise_xor,\n        cbrt,\n        ceil,\n        clip,\n        conj,\n        copysign,\n        cos,\n        cosh,\n        deg2rad,\n        degrees,\n        divide,\n        divmod,\n        equal,\n        exp,\n        exp2,\n        expm1,\n        fabs,\n        fix,\n        float_power,\n        floor,\n        floor_divide,\n        fmax,\n        fmin,\n        fmod,\n        frexp,\n        frompyfunc,\n        greater,\n        greater_equal,\n        hypot,\n        i0,\n        imag,\n        invert,\n        iscomplex,\n        isfinite,\n        isinf,\n        isnan,\n        isneginf,\n        isposinf,\n        isreal,\n        ldexp,\n        less,\n        less_equal,\n        log,\n        log1p,\n        log2,\n        log10,\n        logaddexp,\n        logaddexp2,\n        logical_and,\n        logical_not,\n        logical_or,\n        logical_xor,\n        maximum,\n        minimum,\n        mod,\n        modf,\n        multiply,\n        nan_to_num,\n        negative,\n        nextafter,\n        not_equal,\n        power,\n        rad2deg,\n        radians,\n        real,\n        reciprocal,\n        remainder,\n        rint,\n        sign,\n        signbit,\n        sin,\n        sinc,\n        sinh,\n        spacing,\n        sqrt,\n        square,\n        subtract,\n        tan,\n        tanh,\n        true_divide,\n        trunc,\n    )\n    from dask.array.utils import assert_eq\n    from dask.array.wrap import empty, full, ones, zeros\n    from dask.base import compute\n\nexcept ImportError as e:\n    msg = (\n        \"Dask array requirements are not installed.\\n\\n\"\n        \"Please either conda or pip install as follows:\\n\\n\"\n        \"  conda install dask                 # either conda install\\n\"\n        '  python -m pip install \"dask[array]\" --upgrade  # or python -m pip install'\n    )\n    raise ImportError(str(e) + \"\\n\\n\" + msg) from e\n","new_file_content":"try:\n    from dask.array import backends, fft, lib, linalg, ma, overlap, random\n    from dask.array.blockwise import atop, blockwise\n    from dask.array.chunk_types import register_chunk_type\n    from dask.array.core import (\n        Array,\n        PerformanceWarning,\n        asanyarray,\n        asarray,\n        block,\n        broadcast_arrays,\n        broadcast_to,\n        concatenate,\n        from_array,\n        from_delayed,\n        from_npy_stack,\n        from_zarr,\n        map_blocks,\n        stack,\n        store,\n        to_hdf5,\n        to_npy_stack,\n        to_zarr,\n        unify_chunks,\n    )\n    from dask.array.creation import (\n        arange,\n        diag,\n        diagonal,\n        empty_like,\n        eye,\n        fromfunction,\n        full_like,\n        indices,\n        linspace,\n        meshgrid,\n        ones_like,\n        pad,\n        repeat,\n        tile,\n        tri,\n        zeros_like,\n    )\n    from dask.array.gufunc import apply_gufunc, as_gufunc, gufunc\n    from dask.array.numpy_compat import moveaxis, rollaxis\n    from dask.array.optimization import optimize\n    from dask.array.overlap import map_overlap\n    from dask.array.percentile import percentile\n    from dask.array.rechunk import rechunk\n    from dask.array.reductions import (\n        all,\n        any,\n        argmax,\n        argmin,\n        argtopk,\n        cumprod,\n        cumsum,\n        max,\n        mean,\n        median,\n        min,\n        moment,\n        nanargmax,\n        nanargmin,\n        nancumprod,\n        nancumsum,\n        nanmax,\n        nanmean,\n        nanmedian,\n        nanmin,\n        nanprod,\n        nanstd,\n        nansum,\n        nanvar,\n        prod,\n        reduction,\n        std,\n        sum,\n        topk,\n        trace,\n        var,\n    )\n    from dask.array.reshape import reshape\n    from dask.array.routines import (\n        allclose,\n        append,\n        apply_along_axis,\n        apply_over_axes,\n        argwhere,\n        around,\n        array,\n        atleast_1d,\n        atleast_2d,\n        atleast_3d,\n        average,\n        bincount,\n        choose,\n        coarsen,\n        compress,\n        corrcoef,\n        count_nonzero,\n        cov,\n        delete,\n        diff,\n        digitize,\n        dot,\n        dstack,\n        ediff1d,\n        einsum,\n        expand_dims,\n        extract,\n        flatnonzero,\n        flip,\n        fliplr,\n        flipud,\n        gradient,\n        histogram,\n        histogram2d,\n        histogramdd,\n        hstack,\n        insert,\n        isclose,\n        isin,\n        isnull,\n        matmul,\n        ndim,\n        nonzero,\n        notnull,\n        outer,\n        piecewise,\n        ptp,\n        ravel,\n        ravel_multi_index,\n        result_type,\n        roll,\n        rot90,\n        round,\n        searchsorted,\n        select,\n        shape,\n        squeeze,\n        swapaxes,\n        take,\n        tensordot,\n        transpose,\n        tril,\n        tril_indices,\n        tril_indices_from,\n        triu,\n        triu_indices,\n        triu_indices_from,\n        union1d,\n        unique,\n        unravel_index,\n        vdot,\n        vstack,\n        where,\n    )\n    from dask.array.tiledb_io import from_tiledb, to_tiledb\n    from dask.array.ufunc import (\n        abs,\n        absolute,\n        add,\n        angle,\n        arccos,\n        arccosh,\n        arcsin,\n        arcsinh,\n        arctan,\n        arctan2,\n        arctanh,\n        bitwise_and,\n        bitwise_not,\n        bitwise_or,\n        bitwise_xor,\n        cbrt,\n        ceil,\n        clip,\n        conj,\n        copysign,\n        cos,\n        cosh,\n        deg2rad,\n        degrees,\n        divide,\n        divmod,\n        equal,\n        exp,\n        exp2,\n        expm1,\n        fabs,\n        fix,\n        float_power,\n        floor,\n        floor_divide,\n        fmax,\n        fmin,\n        fmod,\n        frexp,\n        frompyfunc,\n        greater,\n        greater_equal,\n        hypot,\n        i0,\n        imag,\n        invert,\n        iscomplex,\n        isfinite,\n        isinf,\n        isnan,\n        isneginf,\n        isposinf,\n        isreal,\n        ldexp,\n        left_shift,\n        less,\n        less_equal,\n        log,\n        log1p,\n        log2,\n        log10,\n        logaddexp,\n        logaddexp2,\n        logical_and,\n        logical_not,\n        logical_or,\n        logical_xor,\n        maximum,\n        minimum,\n        mod,\n        modf,\n        multiply,\n        nan_to_num,\n        negative,\n        nextafter,\n        not_equal,\n        positive,\n        power,\n        rad2deg,\n        radians,\n        real,\n        reciprocal,\n        remainder,\n        right_shift,\n        rint,\n        sign,\n        signbit,\n        sin,\n        sinc,\n        sinh,\n        spacing,\n        sqrt,\n        square,\n        subtract,\n        tan,\n        tanh,\n        true_divide,\n        trunc,\n    )\n    from dask.array.utils import assert_eq\n    from dask.array.wrap import empty, full, ones, zeros\n    from dask.base import compute\n\nexcept ImportError as e:\n    msg = (\n        \"Dask array requirements are not installed.\\n\\n\"\n        \"Please either conda or pip install as follows:\\n\\n\"\n        \"  conda install dask                 # either conda install\\n\"\n        '  python -m pip install \"dask[array]\" --upgrade  # or python -m pip install'\n    )\n    raise ImportError(str(e) + \"\\n\\n\" + msg) from e\n","header":{"file":{"path":"dask/array/__init__.py"},"misc_line":null},"index_line":null,"is_binary_file":false,"binary_line":null,"minus_file":{"path":"a/dask/array/__init__.py"},"plus_file":{"path":"b/dask/array/__init__.py"},"hunks":[{"descriptor":{"old_range":{"start":158,"length":6},"new_range":{"start":158,"length":7},"section":""},"line_group":{"all_lines":[{"content":"    )","type":"context"},{"content":"    from dask.array.tiledb_io import from_tiledb, to_tiledb","type":"context"},{"content":"    from dask.array.ufunc import (","type":"context"},{"content":"        abs,","type":"added"},{"content":"        absolute,","type":"context"},{"content":"        add,","type":"context"},{"content":"        angle,","type":"context"}]},"modified_entities":[],"added_entities":[],"deleted_entities":[]},{"descriptor":{"old_range":{"start":211,"length":6},"new_range":{"start":212,"length":7},"section":""},"line_group":{"all_lines":[{"content":"        isposinf,","type":"context"},{"content":"        isreal,","type":"context"},{"content":"        ldexp,","type":"context"},{"content":"        left_shift,","type":"added"},{"content":"        less,","type":"context"},{"content":"        less_equal,","type":"context"},{"content":"        log,","type":"context"}]},"modified_entities":[],"added_entities":[],"deleted_entities":[]},{"descriptor":{"old_range":{"start":232,"length":12},"new_range":{"start":234,"length":14},"section":""},"line_group":{"all_lines":[{"content":"        negative,","type":"context"},{"content":"        nextafter,","type":"context"},{"content":"        not_equal,","type":"context"},{"content":"        positive,","type":"added"},{"content":"        power,","type":"context"},{"content":"        rad2deg,","type":"context"},{"content":"        radians,","type":"context"},{"content":"        real,","type":"context"},{"content":"        reciprocal,","type":"context"},{"content":"        remainder,","type":"context"},{"content":"        right_shift,","type":"added"},{"content":"        rint,","type":"context"},{"content":"        sign,","type":"context"},{"content":"        signbit,","type":"context"}]},"modified_entities":[],"added_entities":[],"deleted_entities":[]}]},{"old_file_content":"from functools import partial\nfrom operator import getitem\n\nimport numpy as np\n\nfrom dask import core\nfrom dask.array.core import Array, apply_infer_dtype, asarray, blockwise, elemwise\nfrom dask.base import is_dask_collection, normalize_function\nfrom dask.highlevelgraph import HighLevelGraph\nfrom dask.utils import derived_from, funcname\n\n\ndef wrap_elemwise(numpy_ufunc, source=np):\n    \"\"\"Wrap up numpy function into dask.array\"\"\"\n\n    def wrapped(*args, **kwargs):\n        dsk = [arg for arg in args if hasattr(arg, \"_elemwise\")]\n        if len(dsk) > 0:\n            return dsk[0]._elemwise(numpy_ufunc, *args, **kwargs)\n        else:\n            return numpy_ufunc(*args, **kwargs)\n\n    # functools.wraps cannot wrap ufunc in Python 2.x\n    wrapped.__name__ = numpy_ufunc.__name__\n    return derived_from(source)(wrapped)\n\n\nclass da_frompyfunc:\n    \"\"\"A serializable `frompyfunc` object\"\"\"\n\n    def __init__(self, func, nin, nout):\n        self._ufunc = np.frompyfunc(func, nin, nout)\n        self._func = func\n        self.nin = nin\n        self.nout = nout\n        self._name = funcname(func)\n        self.__name__ = \"frompyfunc-%s\" % self._name\n\n    def __repr__(self):\n        return \"da.frompyfunc<%s, %d, %d>\" % (self._name, self.nin, self.nout)\n\n    def __dask_tokenize__(self):\n        return (normalize_function(self._func), self.nin, self.nout)\n\n    def __reduce__(self):\n        return (da_frompyfunc, (self._func, self.nin, self.nout))\n\n    def __call__(self, *args, **kwargs):\n        return self._ufunc(*args, **kwargs)\n\n    def __getattr__(self, a):\n        if not a.startswith(\"_\"):\n            return getattr(self._ufunc, a)\n        raise AttributeError(f\"{type(self).__name__!r} object has no attribute {a!r}\")\n\n    def __dir__(self):\n        o = set(dir(type(self)))\n        o.update(self.__dict__)\n        o.update(dir(self._ufunc))\n        return list(o)\n\n\n@derived_from(np)\ndef frompyfunc(func, nin, nout):\n    if nout > 1:\n        raise NotImplementedError(\"frompyfunc with more than one output\")\n    return ufunc(da_frompyfunc(func, nin, nout))\n\n\nclass ufunc:\n    _forward_attrs = {\n        \"nin\",\n        \"nargs\",\n        \"nout\",\n        \"ntypes\",\n        \"identity\",\n        \"signature\",\n        \"types\",\n    }\n\n    def __init__(self, ufunc):\n        if not isinstance(ufunc, (np.ufunc, da_frompyfunc)):\n            raise TypeError(\n                \"must be an instance of `ufunc` or \"\n                \"`da_frompyfunc`, got `%s\" % type(ufunc).__name__\n            )\n        self._ufunc = ufunc\n        self.__name__ = ufunc.__name__\n        if isinstance(ufunc, np.ufunc):\n            derived_from(np)(self)\n\n    def __getattr__(self, key):\n        if key in self._forward_attrs:\n            return getattr(self._ufunc, key)\n        raise AttributeError(f\"{type(self).__name__!r} object has no attribute {key!r}\")\n\n    def __dir__(self):\n        return list(self._forward_attrs.union(dir(type(self)), self.__dict__))\n\n    def __repr__(self):\n        return repr(self._ufunc)\n\n    def __call__(self, *args, **kwargs):\n        dsks = [arg for arg in args if hasattr(arg, \"_elemwise\")]\n        if len(dsks) > 0:\n            for dsk in dsks:\n                result = dsk._elemwise(self._ufunc, *args, **kwargs)\n                if type(result) != type(NotImplemented):\n                    return result\n            raise TypeError(\n                \"Parameters of such types are not supported by \" + self.__name__\n            )\n        else:\n            return self._ufunc(*args, **kwargs)\n\n    @derived_from(np.ufunc)\n    def outer(self, A, B, **kwargs):\n        if self.nin != 2:\n            raise ValueError(\"outer product only supported for binary functions\")\n        if \"out\" in kwargs:\n            raise ValueError(\"`out` kwarg not supported\")\n\n        A_is_dask = is_dask_collection(A)\n        B_is_dask = is_dask_collection(B)\n        if not A_is_dask and not B_is_dask:\n            return self._ufunc.outer(A, B, **kwargs)\n        elif (\n            A_is_dask\n            and not isinstance(A, Array)\n            or B_is_dask\n            and not isinstance(B, Array)\n        ):\n            raise NotImplementedError(\n                \"Dask objects besides `dask.array.Array` \"\n                \"are not supported at this time.\"\n            )\n\n        A = asarray(A)\n        B = asarray(B)\n        ndim = A.ndim + B.ndim\n        out_inds = tuple(range(ndim))\n        A_inds = out_inds[: A.ndim]\n        B_inds = out_inds[A.ndim :]\n\n        dtype = apply_infer_dtype(\n            self._ufunc.outer, [A, B], kwargs, \"ufunc.outer\", suggest_dtype=False\n        )\n\n        if \"dtype\" in kwargs:\n            func = partial(self._ufunc.outer, dtype=kwargs.pop(\"dtype\"))\n        else:\n            func = self._ufunc.outer\n\n        return blockwise(\n            func,\n            out_inds,\n            A,\n            A_inds,\n            B,\n            B_inds,\n            dtype=dtype,\n            token=self.__name__ + \".outer\",\n            **kwargs,\n        )\n\n\n# ufuncs, copied from this page:\n# https://docs.scipy.org/doc/numpy/reference/ufuncs.html\n\n# math operations\nadd = ufunc(np.add)\nsubtract = ufunc(np.subtract)\nmultiply = ufunc(np.multiply)\ndivide = ufunc(np.divide)\nlogaddexp = ufunc(np.logaddexp)\nlogaddexp2 = ufunc(np.logaddexp2)\ntrue_divide = ufunc(np.true_divide)\nfloor_divide = ufunc(np.floor_divide)\nnegative = ufunc(np.negative)\npower = ufunc(np.power)\nfloat_power = ufunc(np.float_power)\nremainder = ufunc(np.remainder)\nmod = ufunc(np.mod)\n# fmod: see below\nconj = conjugate = ufunc(np.conjugate)\nexp = ufunc(np.exp)\nexp2 = ufunc(np.exp2)\nlog = ufunc(np.log)\nlog2 = ufunc(np.log2)\nlog10 = ufunc(np.log10)\nlog1p = ufunc(np.log1p)\nexpm1 = ufunc(np.expm1)\nsqrt = ufunc(np.sqrt)\nsquare = ufunc(np.square)\ncbrt = ufunc(np.cbrt)\nreciprocal = ufunc(np.reciprocal)\n\n# trigonometric functions\nsin = ufunc(np.sin)\ncos = ufunc(np.cos)\ntan = ufunc(np.tan)\narcsin = ufunc(np.arcsin)\narccos = ufunc(np.arccos)\narctan = ufunc(np.arctan)\narctan2 = ufunc(np.arctan2)\nhypot = ufunc(np.hypot)\nsinh = ufunc(np.sinh)\ncosh = ufunc(np.cosh)\ntanh = ufunc(np.tanh)\narcsinh = ufunc(np.arcsinh)\narccosh = ufunc(np.arccosh)\narctanh = ufunc(np.arctanh)\ndeg2rad = ufunc(np.deg2rad)\nrad2deg = ufunc(np.rad2deg)\n\n# comparison functions\ngreater = ufunc(np.greater)\ngreater_equal = ufunc(np.greater_equal)\nless = ufunc(np.less)\nless_equal = ufunc(np.less_equal)\nnot_equal = ufunc(np.not_equal)\nequal = ufunc(np.equal)\nisneginf = partial(equal, -np.inf)\nisposinf = partial(equal, np.inf)\nlogical_and = ufunc(np.logical_and)\nlogical_or = ufunc(np.logical_or)\nlogical_xor = ufunc(np.logical_xor)\nlogical_not = ufunc(np.logical_not)\nmaximum = ufunc(np.maximum)\nminimum = ufunc(np.minimum)\nfmax = ufunc(np.fmax)\nfmin = ufunc(np.fmin)\n\n# bitwise functions\nbitwise_and = ufunc(np.bitwise_and)\nbitwise_or = ufunc(np.bitwise_or)\nbitwise_xor = ufunc(np.bitwise_xor)\nbitwise_not = ufunc(np.bitwise_not)\ninvert = bitwise_not\n\n# floating functions\nisfinite = ufunc(np.isfinite)\nisinf = ufunc(np.isinf)\nisnan = ufunc(np.isnan)\nsignbit = ufunc(np.signbit)\ncopysign = ufunc(np.copysign)\nnextafter = ufunc(np.nextafter)\nspacing = ufunc(np.spacing)\n# modf: see below\nldexp = ufunc(np.ldexp)\n# frexp: see below\nfmod = ufunc(np.fmod)\nfloor = ufunc(np.floor)\nceil = ufunc(np.ceil)\ntrunc = ufunc(np.trunc)\n\n# more math routines, from this page:\n# https://docs.scipy.org/doc/numpy/reference/routines.math.html\ndegrees = ufunc(np.degrees)\nradians = ufunc(np.radians)\nrint = ufunc(np.rint)\nfabs = ufunc(np.fabs)\nsign = ufunc(np.sign)\nabsolute = ufunc(np.absolute)\n\n# non-ufunc elementwise functions\nclip = wrap_elemwise(np.clip)\nisreal = wrap_elemwise(np.isreal)\niscomplex = wrap_elemwise(np.iscomplex)\nreal = wrap_elemwise(np.real)\nimag = wrap_elemwise(np.imag)\nfix = wrap_elemwise(np.fix)\ni0 = wrap_elemwise(np.i0)\nsinc = wrap_elemwise(np.sinc)\nnan_to_num = wrap_elemwise(np.nan_to_num)\n\n\n@derived_from(np)\ndef angle(x, deg=0):\n    deg = bool(deg)\n    if hasattr(x, \"_elemwise\"):\n        return x._elemwise(np.angle, x, deg)\n    return np.angle(x, deg=deg)\n\n\n@derived_from(np)\ndef frexp(x):\n    # Not actually object dtype, just need to specify something\n    tmp = elemwise(np.frexp, x, dtype=object)\n    left = \"mantissa-\" + tmp.name\n    right = \"exponent-\" + tmp.name\n    ldsk = {\n        (left,) + key[1:]: (getitem, key, 0)\n        for key in core.flatten(tmp.__dask_keys__())\n    }\n    rdsk = {\n        (right,) + key[1:]: (getitem, key, 1)\n        for key in core.flatten(tmp.__dask_keys__())\n    }\n\n    a = np.empty_like(getattr(x, \"_meta\", x), shape=(1,) * x.ndim, dtype=x.dtype)\n    l, r = np.frexp(a)\n\n    graph = HighLevelGraph.from_collections(left, ldsk, dependencies=[tmp])\n    L = Array(graph, left, chunks=tmp.chunks, meta=l)\n    graph = HighLevelGraph.from_collections(right, rdsk, dependencies=[tmp])\n    R = Array(graph, right, chunks=tmp.chunks, meta=r)\n    return L, R\n\n\n@derived_from(np)\ndef modf(x):\n    # Not actually object dtype, just need to specify something\n    tmp = elemwise(np.modf, x, dtype=object)\n    left = \"modf1-\" + tmp.name\n    right = \"modf2-\" + tmp.name\n    ldsk = {\n        (left,) + key[1:]: (getitem, key, 0)\n        for key in core.flatten(tmp.__dask_keys__())\n    }\n    rdsk = {\n        (right,) + key[1:]: (getitem, key, 1)\n        for key in core.flatten(tmp.__dask_keys__())\n    }\n\n    a = np.empty_like(getattr(x, \"_meta\", x), shape=(1,) * x.ndim, dtype=x.dtype)\n    l, r = np.modf(a)\n\n    graph = HighLevelGraph.from_collections(left, ldsk, dependencies=[tmp])\n    L = Array(graph, left, chunks=tmp.chunks, meta=l)\n    graph = HighLevelGraph.from_collections(right, rdsk, dependencies=[tmp])\n    R = Array(graph, right, chunks=tmp.chunks, meta=r)\n    return L, R\n\n\n@derived_from(np)\ndef divmod(x, y):\n    res1 = x // y\n    res2 = x % y\n    return res1, res2\n","new_file_content":"from functools import partial\nfrom operator import getitem\n\nimport numpy as np\n\nfrom dask import core\nfrom dask.array.core import Array, apply_infer_dtype, asarray, blockwise, elemwise\nfrom dask.base import is_dask_collection, normalize_function\nfrom dask.highlevelgraph import HighLevelGraph\nfrom dask.utils import derived_from, funcname\n\n\ndef wrap_elemwise(numpy_ufunc, source=np):\n    \"\"\"Wrap up numpy function into dask.array\"\"\"\n\n    def wrapped(*args, **kwargs):\n        dsk = [arg for arg in args if hasattr(arg, \"_elemwise\")]\n        if len(dsk) > 0:\n            return dsk[0]._elemwise(numpy_ufunc, *args, **kwargs)\n        else:\n            return numpy_ufunc(*args, **kwargs)\n\n    # functools.wraps cannot wrap ufunc in Python 2.x\n    wrapped.__name__ = numpy_ufunc.__name__\n    return derived_from(source)(wrapped)\n\n\nclass da_frompyfunc:\n    \"\"\"A serializable `frompyfunc` object\"\"\"\n\n    def __init__(self, func, nin, nout):\n        self._ufunc = np.frompyfunc(func, nin, nout)\n        self._func = func\n        self.nin = nin\n        self.nout = nout\n        self._name = funcname(func)\n        self.__name__ = \"frompyfunc-%s\" % self._name\n\n    def __repr__(self):\n        return \"da.frompyfunc<%s, %d, %d>\" % (self._name, self.nin, self.nout)\n\n    def __dask_tokenize__(self):\n        return (normalize_function(self._func), self.nin, self.nout)\n\n    def __reduce__(self):\n        return (da_frompyfunc, (self._func, self.nin, self.nout))\n\n    def __call__(self, *args, **kwargs):\n        return self._ufunc(*args, **kwargs)\n\n    def __getattr__(self, a):\n        if not a.startswith(\"_\"):\n            return getattr(self._ufunc, a)\n        raise AttributeError(f\"{type(self).__name__!r} object has no attribute {a!r}\")\n\n    def __dir__(self):\n        o = set(dir(type(self)))\n        o.update(self.__dict__)\n        o.update(dir(self._ufunc))\n        return list(o)\n\n\n@derived_from(np)\ndef frompyfunc(func, nin, nout):\n    if nout > 1:\n        raise NotImplementedError(\"frompyfunc with more than one output\")\n    return ufunc(da_frompyfunc(func, nin, nout))\n\n\nclass ufunc:\n    _forward_attrs = {\n        \"nin\",\n        \"nargs\",\n        \"nout\",\n        \"ntypes\",\n        \"identity\",\n        \"signature\",\n        \"types\",\n    }\n\n    def __init__(self, ufunc):\n        if not isinstance(ufunc, (np.ufunc, da_frompyfunc)):\n            raise TypeError(\n                \"must be an instance of `ufunc` or \"\n                \"`da_frompyfunc`, got `%s\" % type(ufunc).__name__\n            )\n        self._ufunc = ufunc\n        self.__name__ = ufunc.__name__\n        if isinstance(ufunc, np.ufunc):\n            derived_from(np)(self)\n\n    def __getattr__(self, key):\n        if key in self._forward_attrs:\n            return getattr(self._ufunc, key)\n        raise AttributeError(f\"{type(self).__name__!r} object has no attribute {key!r}\")\n\n    def __dir__(self):\n        return list(self._forward_attrs.union(dir(type(self)), self.__dict__))\n\n    def __repr__(self):\n        return repr(self._ufunc)\n\n    def __call__(self, *args, **kwargs):\n        dsks = [arg for arg in args if hasattr(arg, \"_elemwise\")]\n        if len(dsks) > 0:\n            for dsk in dsks:\n                result = dsk._elemwise(self._ufunc, *args, **kwargs)\n                if type(result) != type(NotImplemented):\n                    return result\n            raise TypeError(\n                \"Parameters of such types are not supported by \" + self.__name__\n            )\n        else:\n            return self._ufunc(*args, **kwargs)\n\n    @derived_from(np.ufunc)\n    def outer(self, A, B, **kwargs):\n        if self.nin != 2:\n            raise ValueError(\"outer product only supported for binary functions\")\n        if \"out\" in kwargs:\n            raise ValueError(\"`out` kwarg not supported\")\n\n        A_is_dask = is_dask_collection(A)\n        B_is_dask = is_dask_collection(B)\n        if not A_is_dask and not B_is_dask:\n            return self._ufunc.outer(A, B, **kwargs)\n        elif (\n            A_is_dask\n            and not isinstance(A, Array)\n            or B_is_dask\n            and not isinstance(B, Array)\n        ):\n            raise NotImplementedError(\n                \"Dask objects besides `dask.array.Array` \"\n                \"are not supported at this time.\"\n            )\n\n        A = asarray(A)\n        B = asarray(B)\n        ndim = A.ndim + B.ndim\n        out_inds = tuple(range(ndim))\n        A_inds = out_inds[: A.ndim]\n        B_inds = out_inds[A.ndim :]\n\n        dtype = apply_infer_dtype(\n            self._ufunc.outer, [A, B], kwargs, \"ufunc.outer\", suggest_dtype=False\n        )\n\n        if \"dtype\" in kwargs:\n            func = partial(self._ufunc.outer, dtype=kwargs.pop(\"dtype\"))\n        else:\n            func = self._ufunc.outer\n\n        return blockwise(\n            func,\n            out_inds,\n            A,\n            A_inds,\n            B,\n            B_inds,\n            dtype=dtype,\n            token=self.__name__ + \".outer\",\n            **kwargs,\n        )\n\n\n# ufuncs, copied from this page:\n# https://docs.scipy.org/doc/numpy/reference/ufuncs.html\n\n# math operations\nadd = ufunc(np.add)\nsubtract = ufunc(np.subtract)\nmultiply = ufunc(np.multiply)\ndivide = ufunc(np.divide)\nlogaddexp = ufunc(np.logaddexp)\nlogaddexp2 = ufunc(np.logaddexp2)\ntrue_divide = ufunc(np.true_divide)\nfloor_divide = ufunc(np.floor_divide)\nnegative = ufunc(np.negative)\npositive = ufunc(np.positive)\npower = ufunc(np.power)\nfloat_power = ufunc(np.float_power)\nremainder = ufunc(np.remainder)\nmod = ufunc(np.mod)\n# fmod: see below\nconj = conjugate = ufunc(np.conjugate)\nexp = ufunc(np.exp)\nexp2 = ufunc(np.exp2)\nlog = ufunc(np.log)\nlog2 = ufunc(np.log2)\nlog10 = ufunc(np.log10)\nlog1p = ufunc(np.log1p)\nexpm1 = ufunc(np.expm1)\nsqrt = ufunc(np.sqrt)\nsquare = ufunc(np.square)\ncbrt = ufunc(np.cbrt)\nreciprocal = ufunc(np.reciprocal)\n\n# trigonometric functions\nsin = ufunc(np.sin)\ncos = ufunc(np.cos)\ntan = ufunc(np.tan)\narcsin = ufunc(np.arcsin)\narccos = ufunc(np.arccos)\narctan = ufunc(np.arctan)\narctan2 = ufunc(np.arctan2)\nhypot = ufunc(np.hypot)\nsinh = ufunc(np.sinh)\ncosh = ufunc(np.cosh)\ntanh = ufunc(np.tanh)\narcsinh = ufunc(np.arcsinh)\narccosh = ufunc(np.arccosh)\narctanh = ufunc(np.arctanh)\ndeg2rad = ufunc(np.deg2rad)\nrad2deg = ufunc(np.rad2deg)\n\n# comparison functions\ngreater = ufunc(np.greater)\ngreater_equal = ufunc(np.greater_equal)\nless = ufunc(np.less)\nless_equal = ufunc(np.less_equal)\nnot_equal = ufunc(np.not_equal)\nequal = ufunc(np.equal)\nisneginf = partial(equal, -np.inf)\nisposinf = partial(equal, np.inf)\nlogical_and = ufunc(np.logical_and)\nlogical_or = ufunc(np.logical_or)\nlogical_xor = ufunc(np.logical_xor)\nlogical_not = ufunc(np.logical_not)\nmaximum = ufunc(np.maximum)\nminimum = ufunc(np.minimum)\nfmax = ufunc(np.fmax)\nfmin = ufunc(np.fmin)\n\n# bitwise functions\nbitwise_and = ufunc(np.bitwise_and)\nbitwise_or = ufunc(np.bitwise_or)\nbitwise_xor = ufunc(np.bitwise_xor)\nbitwise_not = ufunc(np.bitwise_not)\ninvert = bitwise_not\nleft_shift = ufunc(np.left_shift)\nright_shift = ufunc(np.right_shift)\n\n# floating functions\nisfinite = ufunc(np.isfinite)\nisinf = ufunc(np.isinf)\nisnan = ufunc(np.isnan)\nsignbit = ufunc(np.signbit)\ncopysign = ufunc(np.copysign)\nnextafter = ufunc(np.nextafter)\nspacing = ufunc(np.spacing)\n# modf: see below\nldexp = ufunc(np.ldexp)\n# frexp: see below\nfmod = ufunc(np.fmod)\nfloor = ufunc(np.floor)\nceil = ufunc(np.ceil)\ntrunc = ufunc(np.trunc)\n\n# more math routines, from this page:\n# https://docs.scipy.org/doc/numpy/reference/routines.math.html\ndegrees = ufunc(np.degrees)\nradians = ufunc(np.radians)\nrint = ufunc(np.rint)\nfabs = ufunc(np.fabs)\nsign = ufunc(np.sign)\nabsolute = ufunc(np.absolute)\nabs = absolute\n\n# non-ufunc elementwise functions\nclip = wrap_elemwise(np.clip)\nisreal = wrap_elemwise(np.isreal)\niscomplex = wrap_elemwise(np.iscomplex)\nreal = wrap_elemwise(np.real)\nimag = wrap_elemwise(np.imag)\nfix = wrap_elemwise(np.fix)\ni0 = wrap_elemwise(np.i0)\nsinc = wrap_elemwise(np.sinc)\nnan_to_num = wrap_elemwise(np.nan_to_num)\n\n\n@derived_from(np)\ndef angle(x, deg=0):\n    deg = bool(deg)\n    if hasattr(x, \"_elemwise\"):\n        return x._elemwise(np.angle, x, deg)\n    return np.angle(x, deg=deg)\n\n\n@derived_from(np)\ndef frexp(x):\n    # Not actually object dtype, just need to specify something\n    tmp = elemwise(np.frexp, x, dtype=object)\n    left = \"mantissa-\" + tmp.name\n    right = \"exponent-\" + tmp.name\n    ldsk = {\n        (left,) + key[1:]: (getitem, key, 0)\n        for key in core.flatten(tmp.__dask_keys__())\n    }\n    rdsk = {\n        (right,) + key[1:]: (getitem, key, 1)\n        for key in core.flatten(tmp.__dask_keys__())\n    }\n\n    a = np.empty_like(getattr(x, \"_meta\", x), shape=(1,) * x.ndim, dtype=x.dtype)\n    l, r = np.frexp(a)\n\n    graph = HighLevelGraph.from_collections(left, ldsk, dependencies=[tmp])\n    L = Array(graph, left, chunks=tmp.chunks, meta=l)\n    graph = HighLevelGraph.from_collections(right, rdsk, dependencies=[tmp])\n    R = Array(graph, right, chunks=tmp.chunks, meta=r)\n    return L, R\n\n\n@derived_from(np)\ndef modf(x):\n    # Not actually object dtype, just need to specify something\n    tmp = elemwise(np.modf, x, dtype=object)\n    left = \"modf1-\" + tmp.name\n    right = \"modf2-\" + tmp.name\n    ldsk = {\n        (left,) + key[1:]: (getitem, key, 0)\n        for key in core.flatten(tmp.__dask_keys__())\n    }\n    rdsk = {\n        (right,) + key[1:]: (getitem, key, 1)\n        for key in core.flatten(tmp.__dask_keys__())\n    }\n\n    a = np.empty_like(getattr(x, \"_meta\", x), shape=(1,) * x.ndim, dtype=x.dtype)\n    l, r = np.modf(a)\n\n    graph = HighLevelGraph.from_collections(left, ldsk, dependencies=[tmp])\n    L = Array(graph, left, chunks=tmp.chunks, meta=l)\n    graph = HighLevelGraph.from_collections(right, rdsk, dependencies=[tmp])\n    R = Array(graph, right, chunks=tmp.chunks, meta=r)\n    return L, R\n\n\n@derived_from(np)\ndef divmod(x, y):\n    res1 = x // y\n    res2 = x % y\n    return res1, res2\n","header":{"file":{"path":"dask/array/ufunc.py"},"misc_line":null},"index_line":null,"is_binary_file":false,"binary_line":null,"minus_file":{"path":"a/dask/array/ufunc.py"},"plus_file":{"path":"b/dask/array/ufunc.py"},"hunks":[{"descriptor":{"old_range":{"start":177,"length":6},"new_range":{"start":177,"length":7},"section":"def outer(self, A, B, **kwargs):"},"line_group":{"all_lines":[{"content":"true_divide = ufunc(np.true_divide)","type":"context"},{"content":"floor_divide = ufunc(np.floor_divide)","type":"context"},{"content":"negative = ufunc(np.negative)","type":"context"},{"content":"positive = ufunc(np.positive)","type":"added"},{"content":"power = ufunc(np.power)","type":"context"},{"content":"float_power = ufunc(np.float_power)","type":"context"},{"content":"remainder = ufunc(np.remainder)","type":"context"}]},"modified_entities":[],"added_entities":[],"deleted_entities":[]},{"descriptor":{"old_range":{"start":237,"length":6},"new_range":{"start":238,"length":8},"section":"def outer(self, A, B, **kwargs):"},"line_group":{"all_lines":[{"content":"bitwise_xor = ufunc(np.bitwise_xor)","type":"context"},{"content":"bitwise_not = ufunc(np.bitwise_not)","type":"context"},{"content":"invert = bitwise_not","type":"context"},{"content":"left_shift = ufunc(np.left_shift)","type":"added"},{"content":"right_shift = ufunc(np.right_shift)","type":"added"},{"content":"","type":"context"},{"content":"# floating functions","type":"context"},{"content":"isfinite = ufunc(np.isfinite)","type":"context"}]},"modified_entities":[],"added_entities":[],"deleted_entities":[]},{"descriptor":{"old_range":{"start":262,"length":6},"new_range":{"start":265,"length":7},"section":"def outer(self, A, B, **kwargs):"},"line_group":{"all_lines":[{"content":"fabs = ufunc(np.fabs)","type":"context"},{"content":"sign = ufunc(np.sign)","type":"context"},{"content":"absolute = ufunc(np.absolute)","type":"context"},{"content":"abs = absolute","type":"added"},{"content":"","type":"context"},{"content":"# non-ufunc elementwise functions","type":"context"},{"content":"clip = wrap_elemwise(np.clip)","type":"context"},{"content":"","type":"context"}]},"modified_entities":[],"added_entities":[],"deleted_entities":[]}]}],"old_commit_hash":"723e0d223c2921e30d4324cac60d2256ad13386b","new_commit_hash":"1684a7695f2d5fdd7b3793e29f35ad6a5c552412","commit_message":"Add missing NumPy ufuncs to documentation.","commit_date":"2022-04-13T16:52:18+01:00","metadata":{}}
problem_statement: Add missing NumPy ufuncs: `abs`, `left_shift`, `right_shift`, `positive`
  Add these to `dask.array` for consistency with both `numpy` and the Array API (https://github.com/dask/community/issues/109).
  
  
patch: diff --git a/dask/array/__init__.py b/dask/array/__init__.py
  --- a/dask/array/__init__.py
  +++ b/dask/array/__init__.py
  @@ -158,6 +158,7 @@
       )
       from dask.array.tiledb_io import from_tiledb, to_tiledb
       from dask.array.ufunc import (
  +        abs,
           absolute,
           add,
           angle,
  @@ -211,6 +212,7 @@
           isposinf,
           isreal,
           ldexp,
  +        left_shift,
           less,
           less_equal,
           log,
  @@ -232,12 +234,14 @@
           negative,
           nextafter,
           not_equal,
  +        positive,
           power,
           rad2deg,
           radians,
           real,
           reciprocal,
           remainder,
  +        right_shift,
           rint,
           sign,
           signbit,
  diff --git a/dask/array/ufunc.py b/dask/array/ufunc.py
  --- a/dask/array/ufunc.py
  +++ b/dask/array/ufunc.py
  @@ -177,6 +177,7 @@ def outer(self, A, B, **kwargs):
   true_divide = ufunc(np.true_divide)
   floor_divide = ufunc(np.floor_divide)
   negative = ufunc(np.negative)
  +positive = ufunc(np.positive)
   power = ufunc(np.power)
   float_power = ufunc(np.float_power)
   remainder = ufunc(np.remainder)
  @@ -237,6 +238,8 @@ def outer(self, A, B, **kwargs):
   bitwise_xor = ufunc(np.bitwise_xor)
   bitwise_not = ufunc(np.bitwise_not)
   invert = bitwise_not
  +left_shift = ufunc(np.left_shift)
  +right_shift = ufunc(np.right_shift)
   
   # floating functions
   isfinite = ufunc(np.isfinite)
  @@ -262,6 +265,7 @@ def outer(self, A, B, **kwargs):
   fabs = ufunc(np.fabs)
   sign = ufunc(np.sign)
   absolute = ufunc(np.absolute)
  +abs = absolute
   
   # non-ufunc elementwise functions
   clip = wrap_elemwise(np.clip)
   
  
file_context: {"dask/array/__init__.py": "try:\n    from dask.array import backends, fft, lib, linalg, ma, overlap, random\n    from dask.array.blockwise import atop, blockwise\n    from dask.array.chunk_types import register_chunk_type\n    from dask.array.core import (\n        Array,\n        PerformanceWarning,\n        asanyarray,\n        asarray,\n        block,\n        broadcast_arrays,\n        broadcast_to,\n        concatenate,\n        from_array,\n        from_delayed,\n        from_npy_stack,\n        from_zarr,\n        map_blocks,\n        stack,\n        store,\n        to_hdf5,\n        to_npy_stack,\n        to_zarr,\n        unify_chunks,\n    )\n    from dask.array.creation import (\n        arange,\n        diag,\n        diagonal,\n        empty_like,\n        eye,\n        fromfunction,\n        full_like,\n        indices,\n        linspace,\n        meshgrid,\n        ones_like,\n        pad,\n        repeat,\n        tile,\n        tri,\n        zeros_like,\n    )\n    from dask.array.gufunc import apply_gufunc, as_gufunc, gufunc\n    from dask.array.numpy_compat import moveaxis, rollaxis\n    from dask.array.optimization import optimize\n    from dask.array.overlap import map_overlap\n    from dask.array.percentile import percentile\n    from dask.array.rechunk import rechunk\n    from dask.array.reductions import (\n        all,\n        any,\n        argmax,\n        argmin,\n        argtopk,\n        cumprod,\n        cumsum,\n        max,\n        mean,\n        median,\n        min,\n        moment,\n        nanargmax,\n        nanargmin,\n        nancumprod,\n        nancumsum,\n        nanmax,\n        nanmean,\n        nanmedian,\n        nanmin,\n        nanprod,\n        nanstd,\n        nansum,\n        nanvar,\n        prod,\n        reduction,\n        std,\n        sum,\n        topk,\n        trace,\n        var,\n    )\n    from dask.array.reshape import reshape\n    from dask.array.routines import (\n        allclose,\n        append,\n        apply_along_axis,\n        apply_over_axes,\n        argwhere,\n        around,\n        array,\n        atleast_1d,\n        atleast_2d,\n        atleast_3d,\n        average,\n        bincount,\n        choose,\n        coarsen,\n        compress,\n        corrcoef,\n        count_nonzero,\n        cov,\n        delete,\n        diff,\n        digitize,\n        dot,\n        dstack,\n        ediff1d,\n        einsum,\n        expand_dims,\n        extract,\n        flatnonzero,\n        flip,\n        fliplr,\n        flipud,\n        gradient,\n        histogram,\n        histogram2d,\n        histogramdd,\n        hstack,\n        insert,\n        isclose,\n        isin,\n        isnull,\n        matmul,\n        ndim,\n        nonzero,\n        notnull,\n        outer,\n        piecewise,\n        ptp,\n        ravel,\n        ravel_multi_index,\n        result_type,\n        roll,\n        rot90,\n        round,\n        searchsorted,\n        select,\n        shape,\n        squeeze,\n        swapaxes,\n        take,\n        tensordot,\n        transpose,\n        tril,\n        tril_indices,\n        tril_indices_from,\n        triu,\n        triu_indices,\n        triu_indices_from,\n        union1d,\n        unique,\n        unravel_index,\n        vdot,\n        vstack,\n        where,\n    )\n    from dask.array.tiledb_io import from_tiledb, to_tiledb\n    from dask.array.ufunc import (\n        absolute,\n        add,\n        angle,\n        arccos,\n        arccosh,\n        arcsin,\n        arcsinh,\n        arctan,\n        arctan2,\n        arctanh,\n        bitwise_and,\n        bitwise_not,\n        bitwise_or,\n        bitwise_xor,\n        cbrt,\n        ceil,\n        clip,\n        conj,\n        copysign,\n        cos,\n        cosh,\n        deg2rad,\n        degrees,\n        divide,\n        divmod,\n        equal,\n        exp,\n        exp2,\n        expm1,\n        fabs,\n        fix,\n        float_power,\n        floor,\n        floor_divide,\n        fmax,\n        fmin,\n        fmod,\n        frexp,\n        frompyfunc,\n        greater,\n        greater_equal,\n        hypot,\n        i0,\n        imag,\n        invert,\n        iscomplex,\n        isfinite,\n        isinf,\n        isnan,\n        isneginf,\n        isposinf,\n        isreal,\n        ldexp,\n        less,\n        less_equal,\n        log,\n        log1p,\n        log2,\n        log10,\n        logaddexp,\n        logaddexp2,\n        logical_and,\n        logical_not,\n        logical_or,\n        logical_xor,\n        maximum,\n        minimum,\n        mod,\n        modf,\n        multiply,\n        nan_to_num,\n        negative,\n        nextafter,\n        not_equal,\n        power,\n        rad2deg,\n        radians,\n        real,\n        reciprocal,\n        remainder,\n        rint,\n        sign,\n        signbit,\n        sin,\n        sinc,\n        sinh,\n        spacing,\n        sqrt,\n        square,\n        subtract,\n        tan,\n        tanh,\n        true_divide,\n        trunc,\n    )\n    from dask.array.utils import assert_eq\n    from dask.array.wrap import empty, full, ones, zeros\n    from dask.base import compute\n\nexcept ImportError as e:\n    msg = (\n        \"Dask array requirements are not installed.\\n\\n\"\n        \"Please either conda or pip install as follows:\\n\\n\"\n        \"  conda install dask                 # either conda install\\n\"\n        '  python -m pip install \"dask[array]\" --upgrade  # or python -m pip install'\n    )\n    raise ImportError(str(e) + \"\\n\\n\" + msg) from e\n", "dask/array/ufunc.py": "from functools import partial\nfrom operator import getitem\n\nimport numpy as np\n\nfrom dask import core\nfrom dask.array.core import Array, apply_infer_dtype, asarray, blockwise, elemwise\nfrom dask.base import is_dask_collection, normalize_function\nfrom dask.highlevelgraph import HighLevelGraph\nfrom dask.utils import derived_from, funcname\n\n\ndef wrap_elemwise(numpy_ufunc, source=np):\n    \"\"\"Wrap up numpy function into dask.array\"\"\"\n\n    def wrapped(*args, **kwargs):\n        dsk = [arg for arg in args if hasattr(arg, \"_elemwise\")]\n        if len(dsk) > 0:\n            return dsk[0]._elemwise(numpy_ufunc, *args, **kwargs)\n        else:\n            return numpy_ufunc(*args, **kwargs)\n\n    # functools.wraps cannot wrap ufunc in Python 2.x\n    wrapped.__name__ = numpy_ufunc.__name__\n    return derived_from(source)(wrapped)\n\n\nclass da_frompyfunc:\n    \"\"\"A serializable `frompyfunc` object\"\"\"\n\n    def __init__(self, func, nin, nout):\n        self._ufunc = np.frompyfunc(func, nin, nout)\n        self._func = func\n        self.nin = nin\n        self.nout = nout\n        self._name = funcname(func)\n        self.__name__ = \"frompyfunc-%s\" % self._name\n\n    def __repr__(self):\n        return \"da.frompyfunc<%s, %d, %d>\" % (self._name, self.nin, self.nout)\n\n    def __dask_tokenize__(self):\n        return (normalize_function(self._func), self.nin, self.nout)\n\n    def __reduce__(self):\n        return (da_frompyfunc, (self._func, self.nin, self.nout))\n\n    def __call__(self, *args, **kwargs):\n        return self._ufunc(*args, **kwargs)\n\n    def __getattr__(self, a):\n        if not a.startswith(\"_\"):\n            return getattr(self._ufunc, a)\n        raise AttributeError(f\"{type(self).__name__!r} object has no attribute {a!r}\")\n\n    def __dir__(self):\n        o = set(dir(type(self)))\n        o.update(self.__dict__)\n        o.update(dir(self._ufunc))\n        return list(o)\n\n\n@derived_from(np)\ndef frompyfunc(func, nin, nout):\n    if nout > 1:\n        raise NotImplementedError(\"frompyfunc with more than one output\")\n    return ufunc(da_frompyfunc(func, nin, nout))\n\n\nclass ufunc:\n    _forward_attrs = {\n        \"nin\",\n        \"nargs\",\n        \"nout\",\n        \"ntypes\",\n        \"identity\",\n        \"signature\",\n        \"types\",\n    }\n\n    def __init__(self, ufunc):\n        if not isinstance(ufunc, (np.ufunc, da_frompyfunc)):\n            raise TypeError(\n                \"must be an instance of `ufunc` or \"\n                \"`da_frompyfunc`, got `%s\" % type(ufunc).__name__\n            )\n        self._ufunc = ufunc\n        self.__name__ = ufunc.__name__\n        if isinstance(ufunc, np.ufunc):\n            derived_from(np)(self)\n\n    def __getattr__(self, key):\n        if key in self._forward_attrs:\n            return getattr(self._ufunc, key)\n        raise AttributeError(f\"{type(self).__name__!r} object has no attribute {key!r}\")\n\n    def __dir__(self):\n        return list(self._forward_attrs.union(dir(type(self)), self.__dict__))\n\n    def __repr__(self):\n        return repr(self._ufunc)\n\n    def __call__(self, *args, **kwargs):\n        dsks = [arg for arg in args if hasattr(arg, \"_elemwise\")]\n        if len(dsks) > 0:\n            for dsk in dsks:\n                result = dsk._elemwise(self._ufunc, *args, **kwargs)\n                if type(result) != type(NotImplemented):\n                    return result\n            raise TypeError(\n                \"Parameters of such types are not supported by \" + self.__name__\n            )\n        else:\n            return self._ufunc(*args, **kwargs)\n\n    @derived_from(np.ufunc)\n    def outer(self, A, B, **kwargs):\n        if self.nin != 2:\n            raise ValueError(\"outer product only supported for binary functions\")\n        if \"out\" in kwargs:\n            raise ValueError(\"`out` kwarg not supported\")\n\n        A_is_dask = is_dask_collection(A)\n        B_is_dask = is_dask_collection(B)\n        if not A_is_dask and not B_is_dask:\n            return self._ufunc.outer(A, B, **kwargs)\n        elif (\n            A_is_dask\n            and not isinstance(A, Array)\n            or B_is_dask\n            and not isinstance(B, Array)\n        ):\n            raise NotImplementedError(\n                \"Dask objects besides `dask.array.Array` \"\n                \"are not supported at this time.\"\n            )\n\n        A = asarray(A)\n        B = asarray(B)\n        ndim = A.ndim + B.ndim\n        out_inds = tuple(range(ndim))\n        A_inds = out_inds[: A.ndim]\n        B_inds = out_inds[A.ndim :]\n\n        dtype = apply_infer_dtype(\n            self._ufunc.outer, [A, B], kwargs, \"ufunc.outer\", suggest_dtype=False\n        )\n\n        if \"dtype\" in kwargs:\n            func = partial(self._ufunc.outer, dtype=kwargs.pop(\"dtype\"))\n        else:\n            func = self._ufunc.outer\n\n        return blockwise(\n            func,\n            out_inds,\n            A,\n            A_inds,\n            B,\n            B_inds,\n            dtype=dtype,\n            token=self.__name__ + \".outer\",\n            **kwargs,\n        )\n\n\n# ufuncs, copied from this page:\n# https://docs.scipy.org/doc/numpy/reference/ufuncs.html\n\n# math operations\nadd = ufunc(np.add)\nsubtract = ufunc(np.subtract)\nmultiply = ufunc(np.multiply)\ndivide = ufunc(np.divide)\nlogaddexp = ufunc(np.logaddexp)\nlogaddexp2 = ufunc(np.logaddexp2)\ntrue_divide = ufunc(np.true_divide)\nfloor_divide = ufunc(np.floor_divide)\nnegative = ufunc(np.negative)\npower = ufunc(np.power)\nfloat_power = ufunc(np.float_power)\nremainder = ufunc(np.remainder)\nmod = ufunc(np.mod)\n# fmod: see below\nconj = conjugate = ufunc(np.conjugate)\nexp = ufunc(np.exp)\nexp2 = ufunc(np.exp2)\nlog = ufunc(np.log)\nlog2 = ufunc(np.log2)\nlog10 = ufunc(np.log10)\nlog1p = ufunc(np.log1p)\nexpm1 = ufunc(np.expm1)\nsqrt = ufunc(np.sqrt)\nsquare = ufunc(np.square)\ncbrt = ufunc(np.cbrt)\nreciprocal = ufunc(np.reciprocal)\n\n# trigonometric functions\nsin = ufunc(np.sin)\ncos = ufunc(np.cos)\ntan = ufunc(np.tan)\narcsin = ufunc(np.arcsin)\narccos = ufunc(np.arccos)\narctan = ufunc(np.arctan)\narctan2 = ufunc(np.arctan2)\nhypot = ufunc(np.hypot)\nsinh = ufunc(np.sinh)\ncosh = ufunc(np.cosh)\ntanh = ufunc(np.tanh)\narcsinh = ufunc(np.arcsinh)\narccosh = ufunc(np.arccosh)\narctanh = ufunc(np.arctanh)\ndeg2rad = ufunc(np.deg2rad)\nrad2deg = ufunc(np.rad2deg)\n\n# comparison functions\ngreater = ufunc(np.greater)\ngreater_equal = ufunc(np.greater_equal)\nless = ufunc(np.less)\nless_equal = ufunc(np.less_equal)\nnot_equal = ufunc(np.not_equal)\nequal = ufunc(np.equal)\nisneginf = partial(equal, -np.inf)\nisposinf = partial(equal, np.inf)\nlogical_and = ufunc(np.logical_and)\nlogical_or = ufunc(np.logical_or)\nlogical_xor = ufunc(np.logical_xor)\nlogical_not = ufunc(np.logical_not)\nmaximum = ufunc(np.maximum)\nminimum = ufunc(np.minimum)\nfmax = ufunc(np.fmax)\nfmin = ufunc(np.fmin)\n\n# bitwise functions\nbitwise_and = ufunc(np.bitwise_and)\nbitwise_or = ufunc(np.bitwise_or)\nbitwise_xor = ufunc(np.bitwise_xor)\nbitwise_not = ufunc(np.bitwise_not)\ninvert = bitwise_not\n\n# floating functions\nisfinite = ufunc(np.isfinite)\nisinf = ufunc(np.isinf)\nisnan = ufunc(np.isnan)\nsignbit = ufunc(np.signbit)\ncopysign = ufunc(np.copysign)\nnextafter = ufunc(np.nextafter)\nspacing = ufunc(np.spacing)\n# modf: see below\nldexp = ufunc(np.ldexp)\n# frexp: see below\nfmod = ufunc(np.fmod)\nfloor = ufunc(np.floor)\nceil = ufunc(np.ceil)\ntrunc = ufunc(np.trunc)\n\n# more math routines, from this page:\n# https://docs.scipy.org/doc/numpy/reference/routines.math.html\ndegrees = ufunc(np.degrees)\nradians = ufunc(np.radians)\nrint = ufunc(np.rint)\nfabs = ufunc(np.fabs)\nsign = ufunc(np.sign)\nabsolute = ufunc(np.absolute)\n\n# non-ufunc elementwise functions\nclip = wrap_elemwise(np.clip)\nisreal = wrap_elemwise(np.isreal)\niscomplex = wrap_elemwise(np.iscomplex)\nreal = wrap_elemwise(np.real)\nimag = wrap_elemwise(np.imag)\nfix = wrap_elemwise(np.fix)\ni0 = wrap_elemwise(np.i0)\nsinc = wrap_elemwise(np.sinc)\nnan_to_num = wrap_elemwise(np.nan_to_num)\n\n\n@derived_from(np)\ndef angle(x, deg=0):\n    deg = bool(deg)\n    if hasattr(x, \"_elemwise\"):\n        return x._elemwise(np.angle, x, deg)\n    return np.angle(x, deg=deg)\n\n\n@derived_from(np)\ndef frexp(x):\n    # Not actually object dtype, just need to specify something\n    tmp = elemwise(np.frexp, x, dtype=object)\n    left = \"mantissa-\" + tmp.name\n    right = \"exponent-\" + tmp.name\n    ldsk = {\n        (left,) + key[1:]: (getitem, key, 0)\n        for key in core.flatten(tmp.__dask_keys__())\n    }\n    rdsk = {\n        (right,) + key[1:]: (getitem, key, 1)\n        for key in core.flatten(tmp.__dask_keys__())\n    }\n\n    a = np.empty_like(getattr(x, \"_meta\", x), shape=(1,) * x.ndim, dtype=x.dtype)\n    l, r = np.frexp(a)\n\n    graph = HighLevelGraph.from_collections(left, ldsk, dependencies=[tmp])\n    L = Array(graph, left, chunks=tmp.chunks, meta=l)\n    graph = HighLevelGraph.from_collections(right, rdsk, dependencies=[tmp])\n    R = Array(graph, right, chunks=tmp.chunks, meta=r)\n    return L, R\n\n\n@derived_from(np)\ndef modf(x):\n    # Not actually object dtype, just need to specify something\n    tmp = elemwise(np.modf, x, dtype=object)\n    left = \"modf1-\" + tmp.name\n    right = \"modf2-\" + tmp.name\n    ldsk = {\n        (left,) + key[1:]: (getitem, key, 0)\n        for key in core.flatten(tmp.__dask_keys__())\n    }\n    rdsk = {\n        (right,) + key[1:]: (getitem, key, 1)\n        for key in core.flatten(tmp.__dask_keys__())\n    }\n\n    a = np.empty_like(getattr(x, \"_meta\", x), shape=(1,) * x.ndim, dtype=x.dtype)\n    l, r = np.modf(a)\n\n    graph = HighLevelGraph.from_collections(left, ldsk, dependencies=[tmp])\n    L = Array(graph, left, chunks=tmp.chunks, meta=l)\n    graph = HighLevelGraph.from_collections(right, rdsk, dependencies=[tmp])\n    R = Array(graph, right, chunks=tmp.chunks, meta=r)\n    return L, R\n\n\n@derived_from(np)\ndef divmod(x, y):\n    res1 = x // y\n    res2 = x % y\n    return res1, res2\n"}
filelevel_patches: {"dask/array/__init__.py": "@@ -158,6 +158,7 @@\n     )\n     from dask.array.tiledb_io import from_tiledb, to_tiledb\n     from dask.array.ufunc import (\n+        abs,\n         absolute,\n         add,\n         angle,\n@@ -211,6 +212,7 @@\n         isposinf,\n         isreal,\n         ldexp,\n+        left_shift,\n         less,\n         less_equal,\n         log,\n@@ -232,12 +234,14 @@\n         negative,\n         nextafter,\n         not_equal,\n+        positive,\n         power,\n         rad2deg,\n         radians,\n         real,\n         reciprocal,\n         remainder,\n+        right_shift,\n         rint,\n         sign,\n         signbit,", "dask/array/ufunc.py": "@@ -177,6 +177,7 @@ def outer(self, A, B, **kwargs):\n true_divide = ufunc(np.true_divide)\n floor_divide = ufunc(np.floor_divide)\n negative = ufunc(np.negative)\n+positive = ufunc(np.positive)\n power = ufunc(np.power)\n float_power = ufunc(np.float_power)\n remainder = ufunc(np.remainder)\n@@ -237,6 +238,8 @@ def outer(self, A, B, **kwargs):\n bitwise_xor = ufunc(np.bitwise_xor)\n bitwise_not = ufunc(np.bitwise_not)\n invert = bitwise_not\n+left_shift = ufunc(np.left_shift)\n+right_shift = ufunc(np.right_shift)\n \n # floating functions\n isfinite = ufunc(np.isfinite)\n@@ -262,6 +265,7 @@ def outer(self, A, B, **kwargs):\n fabs = ufunc(np.fabs)\n sign = ufunc(np.sign)\n absolute = ufunc(np.absolute)\n+abs = absolute\n \n # non-ufunc elementwise functions\n clip = wrap_elemwise(np.clip)"}
messages.content: 
  We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Add missing NumPy ufuncs: `abs`, `left_shift`, `right_shift`, `positive`
  Add these to `dask.array` for consistency with both `numpy` and the Array API (https://github.com/dask/community/issues/109).
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  
  --- BEGIN FILE ---
  ```
  ### dask/array/ufunc.py
  from functools import partial
  from operator import getitem
  
  import numpy as np
  
  from dask import core
  from dask.array.core import Array, apply_infer_dtype, asarray, blockwise, elemwise
  from dask.base import is_dask_collection, normalize_function
  from dask.highlevelgraph import HighLevelGraph
  from dask.utils import derived_from, funcname
  
  
  def wrap_elemwise(numpy_ufunc, source=np):
      """Wrap up numpy function into dask.array"""
  
      def wrapped(*args, **kwargs):
          dsk = [arg for arg in args if hasattr(arg, "_elemwise")]
          if len(dsk) > 0:
              return dsk[0]._elemwise(numpy_ufunc, *args, **kwargs)
          else:
              return numpy_ufunc(*args, **kwargs)
  
      # functools.wraps cannot wrap ufunc in Python 2.x
      wrapped.__name__ = numpy_ufunc.__name__
      return derived_from(source)(wrapped)
  
  
  class da_frompyfunc:
      """A serializable `frompyfunc` object"""
  
      def __init__(self, func, nin, nout):
          self._ufunc = np.frompyfunc(func, nin, nout)
          self._func = func
          self.nin = nin
          self.nout = nout
          self._name = funcname(func)
          self.__name__ = "frompyfunc-%s" % self._name
  
      def __repr__(self):
          return "da.frompyfunc<%s, %d, %d>" % (self._name, self.nin, self.nout)
  
      def __dask_tokenize__(self):
          return (normalize_function(self._func), self.nin, self.nout)
  
      def __reduce__(self):
          return (da_frompyfunc, (self._func, self.nin, self.nout))
  
      def __call__(self, *args, **kwargs):
          return self._ufunc(*args, **kwargs)
  
      def __getattr__(self, a):
          if not a.startswith("_"):
              return getattr(self._ufunc, a)
          raise AttributeError(f"{type(self).__name__!r} object has no attribute {a!r}")
  
      def __dir__(self):
          o = set(dir(type(self)))
          o.update(self.__dict__)
          o.update(dir(self._ufunc))
          return list(o)
  
  
  @derived_from(np)
  def frompyfunc(func, nin, nout):
      if nout > 1:
          raise NotImplementedError("frompyfunc with more than one output")
      return ufunc(da_frompyfunc(func, nin, nout))
  
  
  class ufunc:
      _forward_attrs = {
          "nin",
          "nargs",
          "nout",
          "ntypes",
          "identity",
          "signature",
          "types",
      }
  
      def __init__(self, ufunc):
          if not isinstance(ufunc, (np.ufunc, da_frompyfunc)):
              raise TypeError(
                  "must be an instance of `ufunc` or "
                  "`da_frompyfunc`, got `%s" % type(ufunc).__name__
              )
          self._ufunc = ufunc
          self.__name__ = ufunc.__name__
          if isinstance(ufunc, np.ufunc):
              derived_from(np)(self)
  
      def __getattr__(self, key):
          if key in self._forward_attrs:
              return getattr(self._ufunc, key)
          raise AttributeError(f"{type(self).__name__!r} object has no attribute {key!r}")
  
      def __dir__(self):
          return list(self._forward_attrs.union(dir(type(self)), self.__dict__))
  
      def __repr__(self):
          return repr(self._ufunc)
  
      def __call__(self, *args, **kwargs):
          dsks = [arg for arg in args if hasattr(arg, "_elemwise")]
          if len(dsks) > 0:
              for dsk in dsks:
                  result = dsk._elemwise(self._ufunc, *args, **kwargs)
                  if type(result) != type(NotImplemented):
                      return result
              raise TypeError(
                  "Parameters of such types are not supported by " + self.__name__
              )
          else:
              return self._ufunc(*args, **kwargs)
  
      @derived_from(np.ufunc)
      def outer(self, A, B, **kwargs):
          if self.nin != 2:
              raise ValueError("outer product only supported for binary functions")
          if "out" in kwargs:
              raise ValueError("`out` kwarg not supported")
  
          A_is_dask = is_dask_collection(A)
          B_is_dask = is_dask_collection(B)
          if not A_is_dask and not B_is_dask:
              return self._ufunc.outer(A, B, **kwargs)
          elif (
              A_is_dask
              and not isinstance(A, Array)
              or B_is_dask
              and not isinstance(B, Array)
          ):
              raise NotImplementedError(
                  "Dask objects besides `dask.array.Array` "
                  "are not supported at this time."
              )
  
          A = asarray(A)
          B = asarray(B)
          ndim = A.ndim + B.ndim
          out_inds = tuple(range(ndim))
          A_inds = out_inds[: A.ndim]
          B_inds = out_inds[A.ndim :]
  
          dtype = apply_infer_dtype(
              self._ufunc.outer, [A, B], kwargs, "ufunc.outer", suggest_dtype=False
          )
  
          if "dtype" in kwargs:
              func = partial(self._ufunc.outer, dtype=kwargs.pop("dtype"))
          else:
              func = self._ufunc.outer
  
          return blockwise(
              func,
              out_inds,
              A,
              A_inds,
              B,
              B_inds,
              dtype=dtype,
              token=self.__name__ + ".outer",
              **kwargs,
          )
  
  
  # ufuncs, copied from this page:
  # https://docs.scipy.org/doc/numpy/reference/ufuncs.html
  
  # math operations
  add = ufunc(np.add)
  subtract = ufunc(np.subtract)
  multiply = ufunc(np.multiply)
  divide = ufunc(np.divide)
  logaddexp = ufunc(np.logaddexp)
  logaddexp2 = ufunc(np.logaddexp2)
  true_divide = ufunc(np.true_divide)
  floor_divide = ufunc(np.floor_divide)
  negative = ufunc(np.negative)
  power = ufunc(np.power)
  float_power = ufunc(np.float_power)
  remainder = ufunc(np.remainder)
  mod = ufunc(np.mod)
  # fmod: see below
  conj = conjugate = ufunc(np.conjugate)
  exp = ufunc(np.exp)
  exp2 = ufunc(np.exp2)
  log = ufunc(np.log)
  log2 = ufunc(np.log2)
  log10 = ufunc(np.log10)
  log1p = ufunc(np.log1p)
  expm1 = ufunc(np.expm1)
  sqrt = ufunc(np.sqrt)
  square = ufunc(np.square)
  cbrt = ufunc(np.cbrt)
  reciprocal = ufunc(np.reciprocal)
  
  # trigonometric functions
  sin = ufunc(np.sin)
  cos = ufunc(np.cos)
  tan = ufunc(np.tan)
  arcsin = ufunc(np.arcsin)
  arccos = ufunc(np.arccos)
  arctan = ufunc(np.arctan)
  arctan2 = ufunc(np.arctan2)
  hypot = ufunc(np.hypot)
  sinh = ufunc(np.sinh)
  cosh = ufunc(np.cosh)
  tanh = ufunc(np.tanh)
  arcsinh = ufunc(np.arcsinh)
  arccosh = ufunc(np.arccosh)
  arctanh = ufunc(np.arctanh)
  deg2rad = ufunc(np.deg2rad)
  rad2deg = ufunc(np.rad2deg)
  
  # comparison functions
  greater = ufunc(np.greater)
  greater_equal = ufunc(np.greater_equal)
  less = ufunc(np.less)
  less_equal = ufunc(np.less_equal)
  not_equal = ufunc(np.not_equal)
  equal = ufunc(np.equal)
  isneginf = partial(equal, -np.inf)
  isposinf = partial(equal, np.inf)
  logical_and = ufunc(np.logical_and)
  logical_or = ufunc(np.logical_or)
  logical_xor = ufunc(np.logical_xor)
  logical_not = ufunc(np.logical_not)
  maximum = ufunc(np.maximum)
  minimum = ufunc(np.minimum)
  fmax = ufunc(np.fmax)
  fmin = ufunc(np.fmin)
  
  # bitwise functions
  bitwise_and = ufunc(np.bitwise_and)
  bitwise_or = ufunc(np.bitwise_or)
  bitwise_xor = ufunc(np.bitwise_xor)
  bitwise_not = ufunc(np.bitwise_not)
  invert = bitwise_not
  
  # floating functions
  isfinite = ufunc(np.isfinite)
  isinf = ufunc(np.isinf)
  isnan = ufunc(np.isnan)
  signbit = ufunc(np.signbit)
  copysign = ufunc(np.copysign)
  nextafter = ufunc(np.nextafter)
  spacing = ufunc(np.spacing)
  # modf: see below
  ldexp = ufunc(np.ldexp)
  # frexp: see below
  fmod = ufunc(np.fmod)
  floor = ufunc(np.floor)
  ceil = ufunc(np.ceil)
  trunc = ufunc(np.trunc)
  
  # more math routines, from this page:
  # https://docs.scipy.org/doc/numpy/reference/routines.math.html
  degrees = ufunc(np.degrees)
  radians = ufunc(np.radians)
  rint = ufunc(np.rint)
  fabs = ufunc(np.fabs)
  sign = ufunc(np.sign)
  absolute = ufunc(np.absolute)
  
  # non-ufunc elementwise functions
  clip = wrap_elemwise(np.clip)
  isreal = wrap_elemwise(np.isreal)
  iscomplex = wrap_elemwise(np.iscomplex)
  real = wrap_elemwise(np.real)
  imag = wrap_elemwise(np.imag)
  fix = wrap_elemwise(np.fix)
  i0 = wrap_elemwise(np.i0)
  sinc = wrap_elemwise(np.sinc)
  nan_to_num = wrap_elemwise(np.nan_to_num)
  
  
  @derived_from(np)
  def angle(x, deg=0):
      deg = bool(deg)
      if hasattr(x, "_elemwise"):
          return x._elemwise(np.angle, x, deg)
      return np.angle(x, deg=deg)
  
  
  @derived_from(np)
  def frexp(x):
      # Not actually object dtype, just need to specify something
      tmp = elemwise(np.frexp, x, dtype=object)
      left = "mantissa-" + tmp.name
      right = "exponent-" + tmp.name
      ldsk = {
          (left,) + key[1:]: (getitem, key, 0)
          for key in core.flatten(tmp.__dask_keys__())
      }
      rdsk = {
          (right,) + key[1:]: (getitem, key, 1)
          for key in core.flatten(tmp.__dask_keys__())
      }
  
      a = np.empty_like(getattr(x, "_meta", x), shape=(1,) * x.ndim, dtype=x.dtype)
      l, r = np.frexp(a)
  
      graph = HighLevelGraph.from_collections(left, ldsk, dependencies=[tmp])
      L = Array(graph, left, chunks=tmp.chunks, meta=l)
      graph = HighLevelGraph.from_collections(right, rdsk, dependencies=[tmp])
      R = Array(graph, right, chunks=tmp.chunks, meta=r)
      return L, R
  
  
  @derived_from(np)
  def modf(x):
      # Not actually object dtype, just need to specify something
      tmp = elemwise(np.modf, x, dtype=object)
      left = "modf1-" + tmp.name
      right = "modf2-" + tmp.name
      ldsk = {
          (left,) + key[1:]: (getitem, key, 0)
          for key in core.flatten(tmp.__dask_keys__())
      }
      rdsk = {
          (right,) + key[1:]: (getitem, key, 1)
          for key in core.flatten(tmp.__dask_keys__())
      }
  
      a = np.empty_like(getattr(x, "_meta", x), shape=(1,) * x.ndim, dtype=x.dtype)
      l, r = np.modf(a)
  
      graph = HighLevelGraph.from_collections(left, ldsk, dependencies=[tmp])
      L = Array(graph, left, chunks=tmp.chunks, meta=l)
      graph = HighLevelGraph.from_collections(right, rdsk, dependencies=[tmp])
      R = Array(graph, right, chunks=tmp.chunks, meta=r)
      return L, R
  
  
  @derived_from(np)
  def divmod(x, y):
      res1 = x // y
      res2 = x % y
      return res1, res2
  
  
  ### dask/array/__init__.py
  try:
      from dask.array import backends, fft, lib, linalg, ma, overlap, random
      from dask.array.blockwise import atop, blockwise
      from dask.array.chunk_types import register_chunk_type
      from dask.array.core import (
          Array,
          PerformanceWarning,
          asanyarray,
          asarray,
          block,
          broadcast_arrays,
          broadcast_to,
          concatenate,
          from_array,
          from_delayed,
          from_npy_stack,
          from_zarr,
          map_blocks,
          stack,
          store,
          to_hdf5,
          to_npy_stack,
          to_zarr,
          unify_chunks,
      )
      from dask.array.creation import (
          arange,
          diag,
          diagonal,
          empty_like,
          eye,
          fromfunction,
          full_like,
          indices,
          linspace,
          meshgrid,
          ones_like,
          pad,
          repeat,
          tile,
          tri,
          zeros_like,
      )
      from dask.array.gufunc import apply_gufunc, as_gufunc, gufunc
      from dask.array.numpy_compat import moveaxis, rollaxis
      from dask.array.optimization import optimize
      from dask.array.overlap import map_overlap
      from dask.array.percentile import percentile
      from dask.array.rechunk import rechunk
      from dask.array.reductions import (
          all,
          any,
          argmax,
          argmin,
          argtopk,
          cumprod,
          cumsum,
          max,
          mean,
          median,
          min,
          moment,
          nanargmax,
          nanargmin,
          nancumprod,
          nancumsum,
          nanmax,
          nanmean,
          nanmedian,
          nanmin,
          nanprod,
          nanstd,
          nansum,
          nanvar,
          prod,
          reduction,
          std,
          sum,
          topk,
          trace,
          var,
      )
      from dask.array.reshape import reshape
      from dask.array.routines import (
          allclose,
          append,
          apply_along_axis,
          apply_over_axes,
          argwhere,
          around,
          array,
          atleast_1d,
          atleast_2d,
          atleast_3d,
          average,
          bincount,
          choose,
          coarsen,
          compress,
          corrcoef,
          count_nonzero,
          cov,
          delete,
          diff,
          digitize,
          dot,
          dstack,
          ediff1d,
          einsum,
          expand_dims,
          extract,
          flatnonzero,
          flip,
          fliplr,
          flipud,
          gradient,
          histogram,
          histogram2d,
          histogramdd,
          hstack,
          insert,
          isclose,
          isin,
          isnull,
          matmul,
          ndim,
          nonzero,
          notnull,
          outer,
          piecewise,
          ptp,
          ravel,
          ravel_multi_index,
          result_type,
          roll,
          rot90,
          round,
          searchsorted,
          select,
          shape,
          squeeze,
          swapaxes,
          take,
          tensordot,
          transpose,
          tril,
          tril_indices,
          tril_indices_from,
          triu,
          triu_indices,
          triu_indices_from,
          union1d,
          unique,
          unravel_index,
          vdot,
          vstack,
          where,
      )
      from dask.array.tiledb_io import from_tiledb, to_tiledb
      from dask.array.ufunc import (
          absolute,
          add,
          angle,
          arccos,
          arccosh,
          arcsin,
          arcsinh,
          arctan,
          arctan2,
          arctanh,
          bitwise_and,
          bitwise_not,
          bitwise_or,
          bitwise_xor,
          cbrt,
          ceil,
          clip,
          conj,
          copysign,
          cos,
          cosh,
          deg2rad,
          degrees,
          divide,
          divmod,
          equal,
          exp,
          exp2,
          expm1,
          fabs,
          fix,
          float_power,
          floor,
          floor_divide,
          fmax,
          fmin,
          fmod,
          frexp,
          frompyfunc,
          greater,
          greater_equal,
          hypot,
          i0,
          imag,
          invert,
          iscomplex,
          isfinite,
          isinf,
          isnan,
          isneginf,
          isposinf,
          isreal,
          ldexp,
          less,
          less_equal,
          log,
          log1p,
          log2,
          log10,
          logaddexp,
          logaddexp2,
          logical_and,
          logical_not,
          logical_or,
          logical_xor,
          maximum,
          minimum,
          mod,
          modf,
          multiply,
          nan_to_num,
          negative,
          nextafter,
          not_equal,
          power,
          rad2deg,
          radians,
          real,
          reciprocal,
          remainder,
          rint,
          sign,
          signbit,
          sin,
          sinc,
          sinh,
          spacing,
          sqrt,
          square,
          subtract,
          tan,
          tanh,
          true_divide,
          trunc,
      )
      from dask.array.utils import assert_eq
      from dask.array.wrap import empty, full, ones, zeros
      from dask.base import compute
  
  except ImportError as e:
      msg = (
          "Dask array requirements are not installed.\n\n"
          "Please either conda or pip install as follows:\n\n"
          "  conda install dask                 # either conda install\n"
          '  python -m pip install "dask[array]" --upgrade  # or python -m pip install'
      )
      raise ImportError(str(e) + "\n\n" + msg) from e
  
  ```
  --- END FILE ---
  
  Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.
  
  Every *SEARCH/REPLACE* edit must use this format:
  1. The file path
  2. The start of search block: <<<<<<< SEARCH
  3. A contiguous chunk of lines to search for in the existing source code
  4. The dividing line: =======
  5. The lines to replace into the source code
  6. The end of the replace block: >>>>>>> REPLACE
  
  Here is an example:
  
  ```python
  ### mathweb/flask/app.py
  <<<<<<< SEARCH
  from flask import Flask
  =======
  import math
  from flask import Flask
  >>>>>>> REPLACE
  ```
  
  Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
  Wrap the *SEARCH/REPLACE* edit in blocks ```python...```.
  
messages.role: user
verification_info: {"file_context": {"dask/array/__init__.py": "try:\n    from dask.array import backends, fft, lib, linalg, ma, overlap, random\n    from dask.array.blockwise import atop, blockwise\n    from dask.array.chunk_types import register_chunk_type\n    from dask.array.core import (\n        Array,\n        PerformanceWarning,\n        asanyarray,\n        asarray,\n        block,\n        broadcast_arrays,\n        broadcast_to,\n        concatenate,\n        from_array,\n        from_delayed,\n        from_npy_stack,\n        from_zarr,\n        map_blocks,\n        stack,\n        store,\n        to_hdf5,\n        to_npy_stack,\n        to_zarr,\n        unify_chunks,\n    )\n    from dask.array.creation import (\n        arange,\n        diag,\n        diagonal,\n        empty_like,\n        eye,\n        fromfunction,\n        full_like,\n        indices,\n        linspace,\n        meshgrid,\n        ones_like,\n        pad,\n        repeat,\n        tile,\n        tri,\n        zeros_like,\n    )\n    from dask.array.gufunc import apply_gufunc, as_gufunc, gufunc\n    from dask.array.numpy_compat import moveaxis, rollaxis\n    from dask.array.optimization import optimize\n    from dask.array.overlap import map_overlap\n    from dask.array.percentile import percentile\n    from dask.array.rechunk import rechunk\n    from dask.array.reductions import (\n        all,\n        any,\n        argmax,\n        argmin,\n        argtopk,\n        cumprod,\n        cumsum,\n        max,\n        mean,\n        median,\n        min,\n        moment,\n        nanargmax,\n        nanargmin,\n        nancumprod,\n        nancumsum,\n        nanmax,\n        nanmean,\n        nanmedian,\n        nanmin,\n        nanprod,\n        nanstd,\n        nansum,\n        nanvar,\n        prod,\n        reduction,\n        std,\n        sum,\n        topk,\n        trace,\n        var,\n    )\n    from dask.array.reshape import reshape\n    from dask.array.routines import (\n        allclose,\n        append,\n        apply_along_axis,\n        apply_over_axes,\n        argwhere,\n        around,\n        array,\n        atleast_1d,\n        atleast_2d,\n        atleast_3d,\n        average,\n        bincount,\n        choose,\n        coarsen,\n        compress,\n        corrcoef,\n        count_nonzero,\n        cov,\n        delete,\n        diff,\n        digitize,\n        dot,\n        dstack,\n        ediff1d,\n        einsum,\n        expand_dims,\n        extract,\n        flatnonzero,\n        flip,\n        fliplr,\n        flipud,\n        gradient,\n        histogram,\n        histogram2d,\n        histogramdd,\n        hstack,\n        insert,\n        isclose,\n        isin,\n        isnull,\n        matmul,\n        ndim,\n        nonzero,\n        notnull,\n        outer,\n        piecewise,\n        ptp,\n        ravel,\n        ravel_multi_index,\n        result_type,\n        roll,\n        rot90,\n        round,\n        searchsorted,\n        select,\n        shape,\n        squeeze,\n        swapaxes,\n        take,\n        tensordot,\n        transpose,\n        tril,\n        tril_indices,\n        tril_indices_from,\n        triu,\n        triu_indices,\n        triu_indices_from,\n        union1d,\n        unique,\n        unravel_index,\n        vdot,\n        vstack,\n        where,\n    )\n    from dask.array.tiledb_io import from_tiledb, to_tiledb\n    from dask.array.ufunc import (\n        absolute,\n        add,\n        angle,\n        arccos,\n        arccosh,\n        arcsin,\n        arcsinh,\n        arctan,\n        arctan2,\n        arctanh,\n        bitwise_and,\n        bitwise_not,\n        bitwise_or,\n        bitwise_xor,\n        cbrt,\n        ceil,\n        clip,\n        conj,\n        copysign,\n        cos,\n        cosh,\n        deg2rad,\n        degrees,\n        divide,\n        divmod,\n        equal,\n        exp,\n        exp2,\n        expm1,\n        fabs,\n        fix,\n        float_power,\n        floor,\n        floor_divide,\n        fmax,\n        fmin,\n        fmod,\n        frexp,\n        frompyfunc,\n        greater,\n        greater_equal,\n        hypot,\n        i0,\n        imag,\n        invert,\n        iscomplex,\n        isfinite,\n        isinf,\n        isnan,\n        isneginf,\n        isposinf,\n        isreal,\n        ldexp,\n        less,\n        less_equal,\n        log,\n        log1p,\n        log2,\n        log10,\n        logaddexp,\n        logaddexp2,\n        logical_and,\n        logical_not,\n        logical_or,\n        logical_xor,\n        maximum,\n        minimum,\n        mod,\n        modf,\n        multiply,\n        nan_to_num,\n        negative,\n        nextafter,\n        not_equal,\n        power,\n        rad2deg,\n        radians,\n        real,\n        reciprocal,\n        remainder,\n        rint,\n        sign,\n        signbit,\n        sin,\n        sinc,\n        sinh,\n        spacing,\n        sqrt,\n        square,\n        subtract,\n        tan,\n        tanh,\n        true_divide,\n        trunc,\n    )\n    from dask.array.utils import assert_eq\n    from dask.array.wrap import empty, full, ones, zeros\n    from dask.base import compute\n\nexcept ImportError as e:\n    msg = (\n        \"Dask array requirements are not installed.\\n\\n\"\n        \"Please either conda or pip install as follows:\\n\\n\"\n        \"  conda install dask                 # either conda install\\n\"\n        '  python -m pip install \"dask[array]\" --upgrade  # or python -m pip install'\n    )\n    raise ImportError(str(e) + \"\\n\\n\" + msg) from e\n", "dask/array/ufunc.py": "from functools import partial\nfrom operator import getitem\n\nimport numpy as np\n\nfrom dask import core\nfrom dask.array.core import Array, apply_infer_dtype, asarray, blockwise, elemwise\nfrom dask.base import is_dask_collection, normalize_function\nfrom dask.highlevelgraph import HighLevelGraph\nfrom dask.utils import derived_from, funcname\n\n\ndef wrap_elemwise(numpy_ufunc, source=np):\n    \"\"\"Wrap up numpy function into dask.array\"\"\"\n\n    def wrapped(*args, **kwargs):\n        dsk = [arg for arg in args if hasattr(arg, \"_elemwise\")]\n        if len(dsk) > 0:\n            return dsk[0]._elemwise(numpy_ufunc, *args, **kwargs)\n        else:\n            return numpy_ufunc(*args, **kwargs)\n\n    # functools.wraps cannot wrap ufunc in Python 2.x\n    wrapped.__name__ = numpy_ufunc.__name__\n    return derived_from(source)(wrapped)\n\n\nclass da_frompyfunc:\n    \"\"\"A serializable `frompyfunc` object\"\"\"\n\n    def __init__(self, func, nin, nout):\n        self._ufunc = np.frompyfunc(func, nin, nout)\n        self._func = func\n        self.nin = nin\n        self.nout = nout\n        self._name = funcname(func)\n        self.__name__ = \"frompyfunc-%s\" % self._name\n\n    def __repr__(self):\n        return \"da.frompyfunc<%s, %d, %d>\" % (self._name, self.nin, self.nout)\n\n    def __dask_tokenize__(self):\n        return (normalize_function(self._func), self.nin, self.nout)\n\n    def __reduce__(self):\n        return (da_frompyfunc, (self._func, self.nin, self.nout))\n\n    def __call__(self, *args, **kwargs):\n        return self._ufunc(*args, **kwargs)\n\n    def __getattr__(self, a):\n        if not a.startswith(\"_\"):\n            return getattr(self._ufunc, a)\n        raise AttributeError(f\"{type(self).__name__!r} object has no attribute {a!r}\")\n\n    def __dir__(self):\n        o = set(dir(type(self)))\n        o.update(self.__dict__)\n        o.update(dir(self._ufunc))\n        return list(o)\n\n\n@derived_from(np)\ndef frompyfunc(func, nin, nout):\n    if nout > 1:\n        raise NotImplementedError(\"frompyfunc with more than one output\")\n    return ufunc(da_frompyfunc(func, nin, nout))\n\n\nclass ufunc:\n    _forward_attrs = {\n        \"nin\",\n        \"nargs\",\n        \"nout\",\n        \"ntypes\",\n        \"identity\",\n        \"signature\",\n        \"types\",\n    }\n\n    def __init__(self, ufunc):\n        if not isinstance(ufunc, (np.ufunc, da_frompyfunc)):\n            raise TypeError(\n                \"must be an instance of `ufunc` or \"\n                \"`da_frompyfunc`, got `%s\" % type(ufunc).__name__\n            )\n        self._ufunc = ufunc\n        self.__name__ = ufunc.__name__\n        if isinstance(ufunc, np.ufunc):\n            derived_from(np)(self)\n\n    def __getattr__(self, key):\n        if key in self._forward_attrs:\n            return getattr(self._ufunc, key)\n        raise AttributeError(f\"{type(self).__name__!r} object has no attribute {key!r}\")\n\n    def __dir__(self):\n        return list(self._forward_attrs.union(dir(type(self)), self.__dict__))\n\n    def __repr__(self):\n        return repr(self._ufunc)\n\n    def __call__(self, *args, **kwargs):\n        dsks = [arg for arg in args if hasattr(arg, \"_elemwise\")]\n        if len(dsks) > 0:\n            for dsk in dsks:\n                result = dsk._elemwise(self._ufunc, *args, **kwargs)\n                if type(result) != type(NotImplemented):\n                    return result\n            raise TypeError(\n                \"Parameters of such types are not supported by \" + self.__name__\n            )\n        else:\n            return self._ufunc(*args, **kwargs)\n\n    @derived_from(np.ufunc)\n    def outer(self, A, B, **kwargs):\n        if self.nin != 2:\n            raise ValueError(\"outer product only supported for binary functions\")\n        if \"out\" in kwargs:\n            raise ValueError(\"`out` kwarg not supported\")\n\n        A_is_dask = is_dask_collection(A)\n        B_is_dask = is_dask_collection(B)\n        if not A_is_dask and not B_is_dask:\n            return self._ufunc.outer(A, B, **kwargs)\n        elif (\n            A_is_dask\n            and not isinstance(A, Array)\n            or B_is_dask\n            and not isinstance(B, Array)\n        ):\n            raise NotImplementedError(\n                \"Dask objects besides `dask.array.Array` \"\n                \"are not supported at this time.\"\n            )\n\n        A = asarray(A)\n        B = asarray(B)\n        ndim = A.ndim + B.ndim\n        out_inds = tuple(range(ndim))\n        A_inds = out_inds[: A.ndim]\n        B_inds = out_inds[A.ndim :]\n\n        dtype = apply_infer_dtype(\n            self._ufunc.outer, [A, B], kwargs, \"ufunc.outer\", suggest_dtype=False\n        )\n\n        if \"dtype\" in kwargs:\n            func = partial(self._ufunc.outer, dtype=kwargs.pop(\"dtype\"))\n        else:\n            func = self._ufunc.outer\n\n        return blockwise(\n            func,\n            out_inds,\n            A,\n            A_inds,\n            B,\n            B_inds,\n            dtype=dtype,\n            token=self.__name__ + \".outer\",\n            **kwargs,\n        )\n\n\n# ufuncs, copied from this page:\n# https://docs.scipy.org/doc/numpy/reference/ufuncs.html\n\n# math operations\nadd = ufunc(np.add)\nsubtract = ufunc(np.subtract)\nmultiply = ufunc(np.multiply)\ndivide = ufunc(np.divide)\nlogaddexp = ufunc(np.logaddexp)\nlogaddexp2 = ufunc(np.logaddexp2)\ntrue_divide = ufunc(np.true_divide)\nfloor_divide = ufunc(np.floor_divide)\nnegative = ufunc(np.negative)\npower = ufunc(np.power)\nfloat_power = ufunc(np.float_power)\nremainder = ufunc(np.remainder)\nmod = ufunc(np.mod)\n# fmod: see below\nconj = conjugate = ufunc(np.conjugate)\nexp = ufunc(np.exp)\nexp2 = ufunc(np.exp2)\nlog = ufunc(np.log)\nlog2 = ufunc(np.log2)\nlog10 = ufunc(np.log10)\nlog1p = ufunc(np.log1p)\nexpm1 = ufunc(np.expm1)\nsqrt = ufunc(np.sqrt)\nsquare = ufunc(np.square)\ncbrt = ufunc(np.cbrt)\nreciprocal = ufunc(np.reciprocal)\n\n# trigonometric functions\nsin = ufunc(np.sin)\ncos = ufunc(np.cos)\ntan = ufunc(np.tan)\narcsin = ufunc(np.arcsin)\narccos = ufunc(np.arccos)\narctan = ufunc(np.arctan)\narctan2 = ufunc(np.arctan2)\nhypot = ufunc(np.hypot)\nsinh = ufunc(np.sinh)\ncosh = ufunc(np.cosh)\ntanh = ufunc(np.tanh)\narcsinh = ufunc(np.arcsinh)\narccosh = ufunc(np.arccosh)\narctanh = ufunc(np.arctanh)\ndeg2rad = ufunc(np.deg2rad)\nrad2deg = ufunc(np.rad2deg)\n\n# comparison functions\ngreater = ufunc(np.greater)\ngreater_equal = ufunc(np.greater_equal)\nless = ufunc(np.less)\nless_equal = ufunc(np.less_equal)\nnot_equal = ufunc(np.not_equal)\nequal = ufunc(np.equal)\nisneginf = partial(equal, -np.inf)\nisposinf = partial(equal, np.inf)\nlogical_and = ufunc(np.logical_and)\nlogical_or = ufunc(np.logical_or)\nlogical_xor = ufunc(np.logical_xor)\nlogical_not = ufunc(np.logical_not)\nmaximum = ufunc(np.maximum)\nminimum = ufunc(np.minimum)\nfmax = ufunc(np.fmax)\nfmin = ufunc(np.fmin)\n\n# bitwise functions\nbitwise_and = ufunc(np.bitwise_and)\nbitwise_or = ufunc(np.bitwise_or)\nbitwise_xor = ufunc(np.bitwise_xor)\nbitwise_not = ufunc(np.bitwise_not)\ninvert = bitwise_not\n\n# floating functions\nisfinite = ufunc(np.isfinite)\nisinf = ufunc(np.isinf)\nisnan = ufunc(np.isnan)\nsignbit = ufunc(np.signbit)\ncopysign = ufunc(np.copysign)\nnextafter = ufunc(np.nextafter)\nspacing = ufunc(np.spacing)\n# modf: see below\nldexp = ufunc(np.ldexp)\n# frexp: see below\nfmod = ufunc(np.fmod)\nfloor = ufunc(np.floor)\nceil = ufunc(np.ceil)\ntrunc = ufunc(np.trunc)\n\n# more math routines, from this page:\n# https://docs.scipy.org/doc/numpy/reference/routines.math.html\ndegrees = ufunc(np.degrees)\nradians = ufunc(np.radians)\nrint = ufunc(np.rint)\nfabs = ufunc(np.fabs)\nsign = ufunc(np.sign)\nabsolute = ufunc(np.absolute)\n\n# non-ufunc elementwise functions\nclip = wrap_elemwise(np.clip)\nisreal = wrap_elemwise(np.isreal)\niscomplex = wrap_elemwise(np.iscomplex)\nreal = wrap_elemwise(np.real)\nimag = wrap_elemwise(np.imag)\nfix = wrap_elemwise(np.fix)\ni0 = wrap_elemwise(np.i0)\nsinc = wrap_elemwise(np.sinc)\nnan_to_num = wrap_elemwise(np.nan_to_num)\n\n\n@derived_from(np)\ndef angle(x, deg=0):\n    deg = bool(deg)\n    if hasattr(x, \"_elemwise\"):\n        return x._elemwise(np.angle, x, deg)\n    return np.angle(x, deg=deg)\n\n\n@derived_from(np)\ndef frexp(x):\n    # Not actually object dtype, just need to specify something\n    tmp = elemwise(np.frexp, x, dtype=object)\n    left = \"mantissa-\" + tmp.name\n    right = \"exponent-\" + tmp.name\n    ldsk = {\n        (left,) + key[1:]: (getitem, key, 0)\n        for key in core.flatten(tmp.__dask_keys__())\n    }\n    rdsk = {\n        (right,) + key[1:]: (getitem, key, 1)\n        for key in core.flatten(tmp.__dask_keys__())\n    }\n\n    a = np.empty_like(getattr(x, \"_meta\", x), shape=(1,) * x.ndim, dtype=x.dtype)\n    l, r = np.frexp(a)\n\n    graph = HighLevelGraph.from_collections(left, ldsk, dependencies=[tmp])\n    L = Array(graph, left, chunks=tmp.chunks, meta=l)\n    graph = HighLevelGraph.from_collections(right, rdsk, dependencies=[tmp])\n    R = Array(graph, right, chunks=tmp.chunks, meta=r)\n    return L, R\n\n\n@derived_from(np)\ndef modf(x):\n    # Not actually object dtype, just need to specify something\n    tmp = elemwise(np.modf, x, dtype=object)\n    left = \"modf1-\" + tmp.name\n    right = \"modf2-\" + tmp.name\n    ldsk = {\n        (left,) + key[1:]: (getitem, key, 0)\n        for key in core.flatten(tmp.__dask_keys__())\n    }\n    rdsk = {\n        (right,) + key[1:]: (getitem, key, 1)\n        for key in core.flatten(tmp.__dask_keys__())\n    }\n\n    a = np.empty_like(getattr(x, \"_meta\", x), shape=(1,) * x.ndim, dtype=x.dtype)\n    l, r = np.modf(a)\n\n    graph = HighLevelGraph.from_collections(left, ldsk, dependencies=[tmp])\n    L = Array(graph, left, chunks=tmp.chunks, meta=l)\n    graph = HighLevelGraph.from_collections(right, rdsk, dependencies=[tmp])\n    R = Array(graph, right, chunks=tmp.chunks, meta=r)\n    return L, R\n\n\n@derived_from(np)\ndef divmod(x, y):\n    res1 = x // y\n    res2 = x % y\n    return res1, res2\n"}, "filelevel_patches": {"dask/array/__init__.py": "@@ -158,6 +158,7 @@\n     )\n     from dask.array.tiledb_io import from_tiledb, to_tiledb\n     from dask.array.ufunc import (\n+        abs,\n         absolute,\n         add,\n         angle,\n@@ -211,6 +212,7 @@\n         isposinf,\n         isreal,\n         ldexp,\n+        left_shift,\n         less,\n         less_equal,\n         log,\n@@ -232,12 +234,14 @@\n         negative,\n         nextafter,\n         not_equal,\n+        positive,\n         power,\n         rad2deg,\n         radians,\n         real,\n         reciprocal,\n         remainder,\n+        right_shift,\n         rint,\n         sign,\n         signbit,", "dask/array/ufunc.py": "@@ -177,6 +177,7 @@ def outer(self, A, B, **kwargs):\n true_divide = ufunc(np.true_divide)\n floor_divide = ufunc(np.floor_divide)\n negative = ufunc(np.negative)\n+positive = ufunc(np.positive)\n power = ufunc(np.power)\n float_power = ufunc(np.float_power)\n remainder = ufunc(np.remainder)\n@@ -237,6 +238,8 @@ def outer(self, A, B, **kwargs):\n bitwise_xor = ufunc(np.bitwise_xor)\n bitwise_not = ufunc(np.bitwise_not)\n invert = bitwise_not\n+left_shift = ufunc(np.left_shift)\n+right_shift = ufunc(np.right_shift)\n \n # floating functions\n isfinite = ufunc(np.isfinite)\n@@ -262,6 +265,7 @@ def outer(self, A, B, **kwargs):\n fabs = ufunc(np.fabs)\n sign = ufunc(np.sign)\n absolute = ufunc(np.absolute)\n+abs = absolute\n \n # non-ufunc elementwise functions\n clip = wrap_elemwise(np.clip)"}}