xnd 0.2.0dev6 → 0.2.0dev7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -0
  3. data/Rakefile +1 -1
  4. data/ext/ruby_xnd/GPATH +0 -0
  5. data/ext/ruby_xnd/GRTAGS +0 -0
  6. data/ext/ruby_xnd/GTAGS +0 -0
  7. data/ext/ruby_xnd/extconf.rb +8 -5
  8. data/ext/ruby_xnd/gc_guard.c +53 -2
  9. data/ext/ruby_xnd/gc_guard.h +8 -2
  10. data/ext/ruby_xnd/include/overflow.h +147 -0
  11. data/ext/ruby_xnd/include/ruby_xnd.h +62 -0
  12. data/ext/ruby_xnd/include/xnd.h +590 -0
  13. data/ext/ruby_xnd/lib/libxnd.a +0 -0
  14. data/ext/ruby_xnd/lib/libxnd.so +1 -0
  15. data/ext/ruby_xnd/lib/libxnd.so.0 +1 -0
  16. data/ext/ruby_xnd/lib/libxnd.so.0.2.0dev3 +0 -0
  17. data/ext/ruby_xnd/ruby_xnd.c +556 -47
  18. data/ext/ruby_xnd/ruby_xnd.h +2 -1
  19. data/ext/ruby_xnd/xnd/Makefile +80 -0
  20. data/ext/ruby_xnd/xnd/config.h +26 -0
  21. data/ext/ruby_xnd/xnd/config.h.in +3 -0
  22. data/ext/ruby_xnd/xnd/config.log +421 -0
  23. data/ext/ruby_xnd/xnd/config.status +1023 -0
  24. data/ext/ruby_xnd/xnd/configure +376 -8
  25. data/ext/ruby_xnd/xnd/configure.ac +48 -7
  26. data/ext/ruby_xnd/xnd/doc/xnd/index.rst +3 -1
  27. data/ext/ruby_xnd/xnd/doc/xnd/{types.rst → xnd.rst} +3 -18
  28. data/ext/ruby_xnd/xnd/libxnd/Makefile +142 -0
  29. data/ext/ruby_xnd/xnd/libxnd/Makefile.in +43 -3
  30. data/ext/ruby_xnd/xnd/libxnd/Makefile.vc +19 -3
  31. data/ext/ruby_xnd/xnd/libxnd/bitmaps.c +42 -3
  32. data/ext/ruby_xnd/xnd/libxnd/bitmaps.o +0 -0
  33. data/ext/ruby_xnd/xnd/libxnd/bounds.c +366 -0
  34. data/ext/ruby_xnd/xnd/libxnd/bounds.o +0 -0
  35. data/ext/ruby_xnd/xnd/libxnd/contrib.h +98 -0
  36. data/ext/ruby_xnd/xnd/libxnd/contrib/bfloat16.h +213 -0
  37. data/ext/ruby_xnd/xnd/libxnd/copy.c +155 -4
  38. data/ext/ruby_xnd/xnd/libxnd/copy.o +0 -0
  39. data/ext/ruby_xnd/xnd/libxnd/cuda/cuda_memory.cu +121 -0
  40. data/ext/ruby_xnd/xnd/libxnd/cuda/cuda_memory.h +58 -0
  41. data/ext/ruby_xnd/xnd/libxnd/equal.c +195 -7
  42. data/ext/ruby_xnd/xnd/libxnd/equal.o +0 -0
  43. data/ext/ruby_xnd/xnd/libxnd/inline.h +32 -0
  44. data/ext/ruby_xnd/xnd/libxnd/libxnd.a +0 -0
  45. data/ext/ruby_xnd/xnd/libxnd/libxnd.so +1 -0
  46. data/ext/ruby_xnd/xnd/libxnd/libxnd.so.0 +1 -0
  47. data/ext/ruby_xnd/xnd/libxnd/libxnd.so.0.2.0dev3 +0 -0
  48. data/ext/ruby_xnd/xnd/libxnd/shape.c +207 -0
  49. data/ext/ruby_xnd/xnd/libxnd/shape.o +0 -0
  50. data/ext/ruby_xnd/xnd/libxnd/split.c +2 -2
  51. data/ext/ruby_xnd/xnd/libxnd/split.o +0 -0
  52. data/ext/ruby_xnd/xnd/libxnd/tests/Makefile +39 -0
  53. data/ext/ruby_xnd/xnd/libxnd/xnd.c +613 -91
  54. data/ext/ruby_xnd/xnd/libxnd/xnd.h +145 -4
  55. data/ext/ruby_xnd/xnd/libxnd/xnd.o +0 -0
  56. data/ext/ruby_xnd/xnd/python/test_xnd.py +1125 -50
  57. data/ext/ruby_xnd/xnd/python/xnd/__init__.py +609 -124
  58. data/ext/ruby_xnd/xnd/python/xnd/_version.py +1 -0
  59. data/ext/ruby_xnd/xnd/python/xnd/_xnd.c +1652 -101
  60. data/ext/ruby_xnd/xnd/python/xnd/libxnd.a +0 -0
  61. data/ext/ruby_xnd/xnd/python/xnd/libxnd.so +1 -0
  62. data/ext/ruby_xnd/xnd/python/xnd/libxnd.so.0 +1 -0
  63. data/ext/ruby_xnd/xnd/python/xnd/libxnd.so.0.2.0dev3 +0 -0
  64. data/ext/ruby_xnd/xnd/python/xnd/pyxnd.h +1 -1
  65. data/ext/ruby_xnd/xnd/python/xnd/util.h +25 -0
  66. data/ext/ruby_xnd/xnd/python/xnd/xnd.h +590 -0
  67. data/ext/ruby_xnd/xnd/python/xnd_randvalue.py +106 -6
  68. data/ext/ruby_xnd/xnd/python/xnd_support.py +4 -0
  69. data/ext/ruby_xnd/xnd/setup.py +46 -4
  70. data/lib/ruby_xnd.so +0 -0
  71. data/lib/xnd.rb +39 -3
  72. data/lib/xnd/version.rb +2 -2
  73. data/xnd.gemspec +2 -1
  74. metadata +58 -5
@@ -43,14 +43,14 @@ data.
43
43
  Importing PEP-3118 buffers is supported.
44
44
  """
45
45
 
46
+ from ._version import __version__
46
47
 
47
48
  # Ensure that libndtypes is loaded and initialized.
48
49
  from ndtypes import ndt, instantiate, MAX_DIM
49
- from ._xnd import Xnd, XndEllipsis
50
- from itertools import accumulate
50
+ from ._xnd import Xnd, XndEllipsis, data_shapes, _typeof
51
51
  from .contrib.pretty import pretty
52
52
 
53
- __all__ = ['xnd', 'XndEllipsis', 'typeof', '_typeof']
53
+ __all__ = ['xnd', 'array', 'XndEllipsis', 'typeof']
54
54
 
55
55
 
56
56
  # ======================================================================
@@ -99,7 +99,7 @@ class xnd(Xnd):
99
99
  """
100
100
 
101
101
  def __new__(cls, value, *, type=None, dtype=None, levels=None,
102
- typedef=None, dtypedef=None):
102
+ typedef=None, dtypedef=None, device=None):
103
103
  if (type, dtype, levels, typedef, dtypedef).count(None) < 2:
104
104
  raise TypeError(
105
105
  "the 'type', 'dtype', 'levels' and 'typedef' arguments are "
@@ -124,7 +124,13 @@ class xnd(Xnd):
124
124
  type = typeof(value, dtype=dtype)
125
125
  else:
126
126
  type = typeof(value)
127
- return super().__new__(cls, type=type, value=value)
127
+
128
+ if device is not None:
129
+ name, no = device.split(":")
130
+ no = -1 if no == "managed" else int(no)
131
+ device = (name, no)
132
+
133
+ return super().__new__(cls, type=type, value=value, device=device)
128
134
 
129
135
  def __repr__(self):
130
136
  value = self.short_value(maxshape=10)
@@ -134,157 +140,636 @@ class xnd(Xnd):
134
140
  fmt = fmt.replace("\n", "\n ")
135
141
  return "xnd%s" % fmt
136
142
 
143
+ def __reduce__(self):
144
+ b = self.serialize()
145
+ return (xnd.deserialize, (b,))
146
+
147
+ def copy_contiguous(self, dtype=None):
148
+ if isinstance(dtype, str):
149
+ dtype = ndt(dtype)
150
+ return super().copy_contiguous(dtype=dtype)
151
+
152
+ def reshape(self, *args, order=None):
153
+ return super()._reshape(args, order=order)
154
+
155
+ def serialize(self):
156
+ if not self.type.is_c_contiguous() and \
157
+ not self.type.is_f_contiguous() and \
158
+ not self.type.is_var_contiguous():
159
+ self = self.copy_contiguous()
160
+ return self._serialize()
161
+
137
162
  @classmethod
138
- def unsafe_from_data(cls, obj=None, type=None):
163
+ def empty(cls, type=None, device=None):
164
+ if device is not None:
165
+ name, no = device.split(":")
166
+ no = -1 if no == "managed" else no
167
+ device = (name, int(no))
168
+
169
+ return super(xnd, cls).empty(type, device)
170
+
171
+ @classmethod
172
+ def from_buffer_and_type(cls, obj=None, type=None):
139
173
  """Return an xnd object that obtains memory from 'obj' via the
140
- buffer protocol. The buffer protocol's type is overridden by
141
- 'type'. No safety checks are performed, the user is responsible
142
- for passing a suitable type.
174
+ buffer protocol. 'obj' must be a simple writable buffer with
175
+ format 'B'. The xnd object uses the provided type, which must
176
+ have the same data size as 'obj'.
143
177
  """
144
178
  if isinstance(type, str):
145
179
  type = ndt(type)
146
- return cls._unsafe_from_data(obj, type)
180
+ return super().from_buffer_and_type(obj, type)
181
+
182
+ def typeof(v, dtype=None):
183
+ if isinstance(dtype, str):
184
+ dtype = ndt(dtype)
185
+ return _typeof(v, dtype=dtype, shortcut=True)
147
186
 
148
187
 
149
188
  # ======================================================================
150
- # Type inference
189
+ # array object
151
190
  # ======================================================================
152
191
 
153
- def typeof(value, *, dtype=None):
154
- return ndt(_typeof(value, dtype=dtype))
192
+ def _convert_smallest(v, device=None):
193
+ """Inefficient hack to make dask work (this needs to be in _typeof)."""
194
+ try:
195
+ return array.from_buffer(v)
196
+ except (TypeError, BufferError):
197
+ pass
198
+ x = array(v, device=device)
199
+ if x.type.hidden_dtype == ndt("int64"):
200
+ for dtype in ("int8", "int16", "int32"):
201
+ try:
202
+ return array(v, dtype=dtype, device=device)
203
+ except:
204
+ continue
205
+ return x
206
+
207
+ class array(xnd):
208
+ """Extended array type that relies on gumath for the array functions."""
209
+
210
+ _functions = None
211
+ _cuda = None
212
+ _np = None
213
+
214
+ @property
215
+ def shape(self):
216
+ return self.type.shape
217
+
218
+ @property
219
+ def strides(self):
220
+ return self.type.strides
221
+
222
+ @property
223
+ def T(self):
224
+ return self.transpose()
225
+
226
+ def tolist(self):
227
+ return self.value
228
+
229
+ def _get_module(self):
230
+ if self.device == "cuda:managed":
231
+ if array._cuda is None:
232
+ import gumath.cuda
233
+ array._cuda = gumath.cuda
234
+ return array._cuda
235
+ else:
236
+ if array._functions is None:
237
+ import gumath.functions
238
+ array._functions = gumath.functions
239
+ return array._functions
240
+
241
+ def _get_numpy(self):
242
+ if array._np is None:
243
+ import numpy
244
+ array._np = numpy
245
+ return array._np
246
+
247
+ def _convert(self, other, raiseit=False):
248
+ if isinstance(other, array):
249
+ if other.device != self.device:
250
+ raise NotImplementedError("arrays must be on the same device")
251
+ return other
252
+ try:
253
+ return _convert_smallest(other, device=self.device)
254
+ except TypeError:
255
+ if raiseit:
256
+ raise TypeError("unable to convert %s to array" % other)
257
+ return NotImplemented
258
+
259
+ def _call_unary(self, name, out=None):
260
+ m = self._get_module()
261
+ return getattr(m, name)(self, out=out, cls=array)
262
+
263
+ def _call_binary(self, name, other, out=None, raiseit=False):
264
+ other = self._convert(other, raiseit)
265
+ m = self._get_module()
266
+ return getattr(m, name)(self, other, out=out, cls=array)
267
+
268
+ def _call_binary_np(self, name, other, out=None, raiseit=False):
269
+ """redirect unimplemented binary methods"""
270
+ np = self._get_numpy()
271
+ other = self._convert(other, raiseit)
272
+ x = getattr(np, name)(self, other, out=out)
273
+ if out is not None:
274
+ return out
275
+ return array.from_buffer(x)
276
+
277
+ __array_priority__ = 1000
278
+
279
+ @property
280
+ def __array_interface__(self):
281
+ shape = self.shape
282
+ typestr = ndt.to_format(self.dtype)
283
+ return dict(shape=shape, typestr=typestr, version=3)
284
+
285
+ def __array__(self, dtype=None):
286
+ if dtype is not None:
287
+ np = self._get_numpy()
288
+ x = np.array([], dtype=dtype)
289
+ t = ndt.from_format(memoryview(x).format)
290
+ return self.copy(dtype=t)
291
+ return self
292
+
293
+ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
294
+ np = self._get_numpy()
295
+
296
+ def conv_args(t):
297
+ if isinstance(t, tuple):
298
+ return tuple(conv_args(v) for v in t)
299
+ if isinstance(t, list):
300
+ return list(conv_args(v) for v in t)
301
+ elif isinstance(t, array):
302
+ return np.array(t, copy=False)
303
+ elif isinstance(t, np.ndarray):
304
+ return t
305
+ else:
306
+ raise NotImplementedError
307
+
308
+ np_self = np.array(self, copy=False)
309
+ try:
310
+ np_inputs = conv_args(inputs)
311
+ except NotImplementedError:
312
+ return NotImplemented
313
+
314
+ np_kwargs = kwargs.copy()
315
+ out = np_kwargs.pop("out", None)
316
+ if out is not None:
317
+ try:
318
+ np_out = conv_args(out)
319
+ except NotImplementedError:
320
+ return NotImplemented
321
+ np_kwargs["out"] = np_out
322
+
323
+ np_res = np_self.__array_ufunc__(ufunc, method, *np_inputs, **np_kwargs)
324
+ if np_res is NotImplemented:
325
+ return NotImplemented
326
+
327
+ if out is None:
328
+ if isinstance(np_res, tuple):
329
+ out = tuple(array.from_buffer(v) for v in np_res)
330
+ elif isinstance(np_res, list):
331
+ out = list(array.from_buffer(v) for v in np_res)
332
+ else:
333
+ out = array.from_buffer(np_res)
155
334
 
156
- def _choose_dtype(lst):
157
- for x in lst:
158
- if x is not None:
159
- return _typeof(x)
160
- return "float64"
335
+ return out
161
336
 
162
- def _typeof(value, *, dtype=None):
163
- """Infer the type of a Python value. Only a subset of Datashape is
164
- supported. In general, types need to be explicitly specified when
165
- creating xnd objects.
166
- """
167
- if isinstance(value, list):
168
- data, shapes = data_shapes(value)
169
- opt = None in data
337
+ def __array_function__(self, func, types, args, kwargs):
338
+ np = self._get_numpy()
170
339
 
171
- if dtype is None:
172
- if not data:
173
- dtype = 'float64'
340
+ def conv_types(t):
341
+ if isinstance(t, tuple):
342
+ return tuple(conv_types(v) for v in t)
343
+ if isinstance(t, list):
344
+ return list(conv_types(v) for v in t)
345
+ elif issubclass(t, (array, np.ndarray)):
346
+ return np.ndarray
347
+ else:
348
+ raise NotImplementedError
349
+
350
+ def conv_args(t, allow_ndarray=True):
351
+ if isinstance(t, tuple):
352
+ return tuple(conv_args(v) for v in t)
353
+ if isinstance(t, list):
354
+ return list(conv_args(v) for v in t)
355
+ elif isinstance(t, array):
356
+ return np.array(t, copy=False)
357
+ elif isinstance(t, np.ndarray):
358
+ return t if allow_ndarray else NotImplemented
174
359
  else:
175
- dtype = _choose_dtype(data)
176
- for x in data:
177
- if x is not None:
178
- t = _typeof(x)
179
- if t != dtype:
180
- raise ValueError("dtype mismatch: have %s and %s" % (dtype, t))
360
+ return t
361
+
362
+ def conv_res(t):
363
+ if isinstance(t, tuple):
364
+ return tuple(conv_res(v) for v in t)
365
+ if isinstance(t, list):
366
+ return list(conv_res(v) for v in t)
367
+ elif isinstance(t, np.ndarray):
368
+ return array.from_buffer(t)
369
+ else:
370
+ try:
371
+ return array.from_buffer(memoryview(t))
372
+ except TypeError:
373
+ return t
374
+
375
+ np_self = np.array(self, copy=False)
376
+ try:
377
+ np_types = conv_types(types)
378
+ except NotImplementedError:
379
+ return NotImplemented
380
+
381
+ try:
382
+ np_args = conv_args(args)
383
+ except NotImplementedError:
384
+ return NotImplemented
385
+
386
+ np_kwargs = kwargs.copy()
387
+ out = np_kwargs.pop("out", None)
388
+ if out is not None:
389
+ try:
390
+ np_out = conv_args(out, allow_ndarray=False)
391
+ except NotImplementedError:
392
+ return NotImplemented
393
+ np_kwargs["out"] = np_out
394
+
395
+ np_res = np_self.__array_function__(func, np_types, np_args, np_kwargs)
396
+ if np_res is NotImplemented:
397
+ return NotImplemented
398
+
399
+ if out is None:
400
+ return conv_res(np_res)
401
+ else:
402
+ return out
181
403
 
182
- if opt:
183
- dtype = '?' + dtype
404
+ def __repr__(self):
405
+ value = self.short_value(maxshape=10)
406
+ fmt = pretty((value, "@type='%s'@" % self.type), max_width=120)
407
+ fmt = fmt.replace('"@', "")
408
+ fmt = fmt.replace('@"', "")
409
+ fmt = fmt.replace("\n", "\n ")
410
+ return "array%s" % fmt
184
411
 
185
- t = dtype
186
- var = any(len(set(lst)) > 1 or None in lst for lst in shapes)
187
- for lst in shapes:
188
- opt = None in lst
189
- lst = [0 if x is None else x for x in lst]
190
- t = add_dim(opt=opt, shapes=lst, typ=t, use_var=var)
412
+ def __copy__(self):
413
+ return self.copy()
191
414
 
192
- return t
415
+ def __deepcopy__(self, memo):
416
+ return self.copy()
193
417
 
194
- elif dtype is not None:
195
- raise TypeError("dtype argument is only supported for arrays")
418
+ def __bool__(self):
419
+ np = self._get_numpy()
420
+ return bool(np.array(self, copy=False))
196
421
 
197
- elif isinstance(value, tuple):
198
- return "(" + ", ".join([_typeof(x) for x in value]) + ")"
422
+ def __neg__(self):
423
+ return self._call_unary("negative")
199
424
 
200
- elif isinstance(value, dict):
201
- if all(isinstance(k, str) for k in value):
202
- return "{" + ", ".join(["%s: %s" % (k, _typeof(v)) for k, v in value.items()]) + "}"
203
- raise ValueError("all dict keys must be strings")
425
+ def __pos__(self):
426
+ return self.copy()
204
427
 
205
- elif value is None:
206
- return '?float64'
428
+ def __abs__(self):
429
+ return self._call_unary("abs")
207
430
 
208
- elif isinstance(value, float):
209
- return 'float64'
431
+ def __invert__(self):
432
+ return self._call_unary("invert")
210
433
 
211
- elif isinstance(value, complex):
212
- return 'complex128'
434
+ def __complex__(self):
435
+ np = self._get_numpy()
436
+ return complex(np.array(self, copy=False))
213
437
 
214
- elif isinstance(value, int):
215
- return 'int64'
438
+ def __int__(self):
439
+ np = self._get_numpy()
440
+ return int(np.array(self, copy=False))
216
441
 
217
- elif isinstance(value, str):
218
- return 'string'
442
+ def __oct__(self):
443
+ np = self._get_numpy()
444
+ return oct(np.array(self, copy=False))
219
445
 
220
- elif isinstance(value, bytes):
221
- return 'bytes'
446
+ def __hex__(self):
447
+ np = self._get_numpy()
448
+ return hex(np.array(self, copy=False))
222
449
 
223
- else:
224
- raise ValueError("cannot infer type for %r" % value)
450
+ def __float__(self):
451
+ np = self._get_numpy()
452
+ return float(np.array(self, copy=False))
225
453
 
454
+ def __index__(self):
455
+ np = self._get_numpy()
456
+ return np.array(self, copy=False).__index__()
226
457
 
227
- def add_dim(*, opt=False, shapes=None, typ=None, use_var=False):
228
- """Construct a new dimension type based on the list of 'shapes' that
229
- are present in a dimension.
230
- """
231
- if use_var:
232
- offsets = [0] + list(accumulate(shapes))
233
- return "%svar(offsets=%s) * %s" % ('?' if opt else '', offsets, typ)
234
- else:
235
- n = len(set(shapes))
236
- assert n <= 1 and not None in shapes
237
- shape = 0 if n == 0 else shapes[0]
238
- return "%d * %s" % (shape, typ)
239
-
240
- def data_shapes(tree):
241
- """Extract array data and dimension shapes from a nested list. The
242
- list may contain None for missing data or dimensions.
243
-
244
- >>> data_shapes([[0, 1], [2, 3, 4], [5, 6, 7, 8]])
245
- ([0, 1, 2, 3, 4, 5, 6, 7, 8], [[2, 3, 4], [3]])
246
- ^ ^ ^
247
- | | `--- ndim=2: single shape 3
248
- | `-- ndim=1: shapes 2, 3, 4
249
- `--- ndim=0: extracted array data
250
- """
251
- acc = [[] for _ in range(MAX_DIM+1)]
252
- min_level = MAX_DIM + 1
253
- max_level = 0
254
-
255
- def search(level, a):
256
- nonlocal min_level, max_level
257
-
258
- if level > MAX_DIM:
259
- raise ValueError("too many dimensions")
260
-
261
- current = acc[level]
262
- if a is None:
263
- current.append(a)
264
- elif isinstance(a, list):
265
- current.append(len(a))
266
- next_level = level + 1
267
- max_level = max(next_level, max_level)
268
- if not a:
269
- min_level = min(next_level, min_level)
270
- else:
271
- for item in a:
272
- search(level+1, item)
273
- else:
274
- acc[max_level].append(a)
275
- min_level = min(level, min_level)
458
+ def __floor__(self):
459
+ np = self._get_numpy()
460
+ return np.array(self, copy=False).__floor__()
461
+
462
+ def __ceil__(self):
463
+ np = self._get_numpy()
464
+ return np.array(self, copy=False).__ceil__()
465
+
466
+ def __eq__(self, other):
467
+ other = self._convert(other)
468
+ if other is NotImplemented:
469
+ return other
470
+
471
+ return self._call_binary("equal", other)
472
+
473
+ def __ne__(self, other):
474
+ other = self._convert(other)
475
+ if other is NotImplemented:
476
+ return other
477
+
478
+ return self._call_binary("not_equal", other)
479
+
480
+ def __lt__(self, other):
481
+ other = self._convert(other)
482
+ if other is NotImplemented:
483
+ return other
484
+
485
+ return self._call_binary("less", other)
486
+
487
+ def __le__(self, other):
488
+ other = self._convert(other)
489
+ if other is NotImplemented:
490
+ return other
491
+
492
+ return self._call_binary("less_equal", other)
493
+
494
+ def __ge__(self, other):
495
+ other = self._convert(other)
496
+ if other is NotImplemented:
497
+ return other
498
+
499
+ return self._call_binary("greater_equal", other)
500
+
501
+ def __gt__(self, other):
502
+ other = self._convert(other)
503
+ if other is NotImplemented:
504
+ return other
505
+
506
+ return self._call_binary("greater", other)
507
+
508
+ def __add__(self, other):
509
+ return self._call_binary("add", other)
510
+
511
+ def __radd__(self, other):
512
+ other = self._convert(other)
513
+ if other is NotImplemented:
514
+ return other
515
+
516
+ return other._call_binary("add", self)
517
+
518
+ def __sub__(self, other):
519
+ return self._call_binary("subtract", other)
520
+
521
+ def __rsub__(self, other):
522
+ other = self._convert(other)
523
+ if other is NotImplemented:
524
+ return other
525
+
526
+ return other._call_binary("subtract", self)
527
+
528
+ def __mul__(self, other):
529
+ return self._call_binary("multiply", other)
530
+
531
+ def __rmul__(self, other):
532
+ other = self._convert(other)
533
+ if other is NotImplemented:
534
+ return other
535
+
536
+ return other._call_binary("multiply", self)
537
+
538
+ def __matmul__(self, other):
539
+ return self._call_binary_np("matmul", other)
540
+
541
+ def __rmatmul__(self, other):
542
+ other = self._convert(other)
543
+ if other is NotImplemented:
544
+ return other
545
+
546
+ return other._call_binary_np("matmul", self)
547
+
548
+ def __truediv__(self, other):
549
+ return self._call_binary("divide", other)
550
+
551
+ def __rtruediv__(self, other):
552
+ other = self._convert(other)
553
+ if other is NotImplemented:
554
+ return other
555
+
556
+ return other._call_binary("divide", self)
557
+
558
+ def __floordiv__(self, other):
559
+ return self._call_binary("floor_divide", other)
560
+
561
+ def __rfloordiv__(self, other):
562
+ other = self._convert(other)
563
+ if other is NotImplemented:
564
+ return other
565
+
566
+ return other._call_binary("floor_divide", self)
567
+
568
+ def __mod__(self, other):
569
+ return self._call_binary("remainder", other)
570
+
571
+ def __rmod__(self, other):
572
+ other = self._convert(other)
573
+ if other is NotImplemented:
574
+ return other
575
+
576
+ return other._call_binary("remainder", self)
577
+
578
+ def __divmod__(self, other):
579
+ return self._call_binary("divmod", other)
580
+
581
+ def __rdivmod__(self, other):
582
+ other = self._convert(other)
583
+ if other is NotImplemented:
584
+ return other
585
+
586
+ return other._call_binary("divmod", self)
587
+
588
+ def __pow__(self, other):
589
+ return self._call_binary("power", other)
590
+
591
+ def __rpow__(self, other):
592
+ other = self._convert(other)
593
+ if other is NotImplemented:
594
+ return other
595
+
596
+ return other._call_binary("power", self)
597
+
598
+ def __lshift__(self, other):
599
+ return self._call_binary_np("left_shift", other)
600
+
601
+ def __rlshift__(self, other):
602
+ other = self._convert(other)
603
+ if other is NotImplemented:
604
+ return other
605
+
606
+ return other._call_binary_np("left_shift", self)
607
+
608
+ def __rshift__(self, other):
609
+ return self._call_binary_np("right_shift", other)
610
+
611
+ def __rrshift__(self, other):
612
+ other = self._convert(other)
613
+ if other is NotImplemented:
614
+ return other
615
+
616
+ return other._call_binary_np("right_shift", self)
617
+
618
+ def __and__(self, other):
619
+ return self._call_binary("bitwise_and", other)
620
+
621
+ def __rand__(self, other):
622
+ other = self._convert(other)
623
+ if other is NotImplemented:
624
+ return other
625
+
626
+ return other._call_binary("bitwise_and", self)
627
+
628
+ def __or__(self, other):
629
+ return self._call_binary("bitwise_or", other)
630
+
631
+ def __ror__(self, other):
632
+ other = self._convert(other)
633
+ if other is NotImplemented:
634
+ return other
635
+
636
+ return other._call_binary("bitwise_or", self)
637
+
638
+ def __xor__(self, other):
639
+ return self._call_binary("bitwise_xor", other)
640
+
641
+ def __rxor__(self, other):
642
+ other = self._convert(other)
643
+ if other is NotImplemented:
644
+ return other
645
+
646
+ return other._call_binary("bitwise_xor", self)
647
+
648
+ def __iadd__(self, other):
649
+ return self._call_binary("add", other, out=self)
650
+
651
+ def __isub__(self, other):
652
+ return self._call_binary("subtract", other, out=self)
653
+
654
+ def __imul__(self, other):
655
+ return self._call_binary("multiply", other, out=self)
656
+
657
+ def __imatmul__(self, other):
658
+ return self._call_binary_np("matmul", other, out=self)
659
+
660
+ def __itruediv__(self, other):
661
+ return self._call_binary("divide", other, out=self)
662
+
663
+ def __ifloordiv__(self, other):
664
+ return self._call_binary("floor_divide", other, out=self)
665
+
666
+ def __imod__(self, other):
667
+ return self._call_binary("remainder", other, out=self)
668
+
669
+ def __ipow__(self, other):
670
+ return self._call_binary("power", other, out=self)
671
+
672
+ def __ilshift__(self, other):
673
+ return self._call_binary_np("left_shift", other, out=self)
674
+
675
+ def __irshift__(self, other):
676
+ return self._call_binary_np("right_shift", other, out=self)
677
+
678
+ def __iand__(self, other):
679
+ return self._call_binary("bitwise_and", other, out=self)
680
+
681
+ def __ior__(self, other):
682
+ return self._call_binary("bitwise_or", other, out=self)
683
+
684
+ def __ixor__(self, other):
685
+ return self._call_binary("bitwise_xor", other, out=self)
686
+
687
+ def copy(self, out=None):
688
+ return self._call_unary("copy", out=out)
689
+
690
+ def acos(self, out=None):
691
+ return self._call_unary("acos", out=out)
692
+
693
+ def acosh(self, out=None):
694
+ return self._call_unary("acosh", out=out)
695
+
696
+ def asin(self, out=None):
697
+ return self._call_unary("asin", out=out)
698
+
699
+ def asinh(self, out=None):
700
+ return self._call_unary("asinh", out=out)
701
+
702
+ def atan(self, out=None):
703
+ return self._call_unary("atan", out=out)
704
+
705
+ def atanh(self, out=None):
706
+ return self._call_unary("atanh", out=out)
707
+
708
+ def cbrt(self, out=None):
709
+ return self._call_unary("cbrt", out=out)
710
+
711
+ def cos(self, out=None):
712
+ return self._call_unary("cos", out=out)
713
+
714
+ def cosh(self, out=None):
715
+ return self._call_unary("cosh", out=out)
716
+
717
+ def erf(self, out=None):
718
+ return self._call_unary("erf", out=out)
719
+
720
+ def erfc(self, out=None):
721
+ return self._call_unary("erfc", out=out)
722
+
723
+ def exp(self, out=None):
724
+ return self._call_unary("exp", out=out)
725
+
726
+ def exp2(self, out=None):
727
+ return self._call_unary("exp2", out=out)
728
+
729
+ def expm1(self, out=None):
730
+ return self._call_unary("expm1", out=out)
731
+
732
+ def fabs(self, out=None):
733
+ return self._call_unary("fabs", out=out)
734
+
735
+ def lgamma(self, out=None):
736
+ return self._call_unary("lgamma", out=out)
737
+
738
+ def log(self, out=None):
739
+ return self._call_unary("log", out=out)
740
+
741
+ def log10(self, out=None):
742
+ return self._call_unary("log10", out=out)
743
+
744
+ def log1p(self, out=None):
745
+ return self._call_unary("log1p", out=out)
746
+
747
+ def log2(self, out=None):
748
+ return self._call_unary("log2", out=out)
749
+
750
+ def logb(self, out=None):
751
+ return self._call_unary("logb", out=out)
752
+
753
+ def nearbyint(self, out=None):
754
+ return self._call_unary("nearbyint", out=out)
755
+
756
+ def sin(self, out=None):
757
+ return self._call_unary("sin", out=out)
276
758
 
277
- search(max_level, tree)
278
- if acc[max_level] and all(x is None for x in acc[max_level]):
279
- pass # min_level is not set in this special case, hence the check.
280
- elif min_level != max_level:
281
- raise ValueError("unbalanced tree: min depth: %d max depth: %d" %
282
- (min_level, max_level))
759
+ def sinh(self, out=None):
760
+ return self._call_unary("sinh", out=out)
283
761
 
284
- data = acc[max_level]
285
- shapes = list(reversed(acc[0:max_level]))
762
+ def sqrt(self, out=None):
763
+ return self._call_unary("sqrt", out=out)
286
764
 
287
- return data, shapes
765
+ def tan(self, out=None):
766
+ return self._call_unary("tan", out=out)
288
767
 
768
+ def tanh(self, out=None):
769
+ return self._call_unary("tanh", out=out)
289
770
 
771
+ def tanh(self, out=None):
772
+ return self._call_unary("tgamma", out=out)
290
773
 
774
+ def equaln(self, other, out=None):
775
+ return self._call_binary("equaln", other, out=out, raiseit=True)