You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

math.py 31 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936
  1. # -*- coding: utf-8 -*-
  2. import collections
  3. import math
  4. from typing import Iterable, Optional, Sequence, Tuple, Union
  5. from ..core._imperative_rt.core2 import Const, apply
  6. from ..core._imperative_rt.ops import SubgraphBuilder as _SubgraphBuilder
  7. from ..core.ops import builtin
  8. from ..core.tensor.array_method import _matmul
  9. from ..core.tensor.utils import _normalize_axis
  10. from ..tensor import Tensor
  11. from ..utils.deprecation import deprecated_kwargs_default
  12. from .elemwise import _elemwise_multi_type, clip
  13. from .tensor import expand_dims, squeeze
  14. __all__ = [
  15. "argmax",
  16. "argmin",
  17. "argsort",
  18. "dot",
  19. "isinf",
  20. "isnan",
  21. "matinv",
  22. "matmul",
  23. "max",
  24. "mean",
  25. "min",
  26. "norm",
  27. "normalize",
  28. "prod",
  29. "sign",
  30. "sort",
  31. "std",
  32. "sum",
  33. "svd",
  34. "topk",
  35. "var",
  36. ]
  37. # TODO: Should be moved to elemwise - logical functions
  38. def isnan(inp: Tensor) -> Tensor:
  39. r"""Element-wise ``NaN`` check.
  40. Tests each element :math:`x_i` of the input tensor :math:`x` to determine whether the element is ``NaN``.
  41. Args:
  42. inp: input tensor. Should have a numeric data type.
  43. Returns:
  44. a tensor containing test results.
  45. An element out is ``True`` if :math:`x_i` is ``NaN`` and ``False`` otherwise.
  46. The returned array should have a data type of bool.
  47. Examples:
  48. >>> x = Tensor([1, float("nan"), 0])
  49. >>> F.isnan(x)
  50. Tensor([False True False], dtype=bool, device=xpux:0)
  51. """
  52. return _elemwise_multi_type(inp, mode="isnan", dtype="bool")
  53. def isinf(inp: Tensor) -> Tensor:
  54. r"""Element-wise ``infinity`` check.
  55. Tests each element :math:`x_i` of the input tensor :math:`x` to determine
  56. whether the element is if equal to positive or negative infinity.
  57. Args:
  58. inp: input tensor. Should have a numeric data type.
  59. Returns:
  60. a tensor containing test results.
  61. An element out is ``True`` if :math:`x_i` is either positive or negative infinity and ``False`` otherwise.
  62. The returned array should have a data type of bool.
  63. Examples:
  64. >>> x = Tensor([1, float("inf"), 0])
  65. >>> F.isinf(x)
  66. Tensor([False True False], dtype=bool, device=xpux:0)
  67. """
  68. return _elemwise_multi_type(inp, mode="isinf", dtype="bool")
  69. # TODO: Should be moved to elemwise - arithmetic operations
  70. def sign(x: Tensor):
  71. r"""Element-wise sign.
  72. Returns an indication of the sign of a number for each element :math:`x_i` of the input tensor :math:`x`.
  73. Args:
  74. inp: input tensor. Should have a numeric data type.
  75. Returns:
  76. a tensor containing the evaluated result for each element in :math:`x`.
  77. The returned array must have the same data type as :math:`x`.
  78. Examples:
  79. Element-wise sign:
  80. >>> x = Tensor([1, -1, 0])
  81. >>> F.sign(x)
  82. Tensor([ 1 -1 0], dtype=int32, device=xpux:0)
  83. """
  84. return (x > 0).astype(x.dtype) - (x < 0).astype(x.dtype)
  85. # statistical functions
  86. def sum(
  87. inp: Tensor,
  88. axis: Optional[Union[int, Sequence[int]]] = None,
  89. keepdims: bool = False,
  90. ) -> Tensor:
  91. r"""Calculates the sum of tensor elements over a given axis (or axes).
  92. Args:
  93. inp: input tensor. Should have a numeric data type.
  94. axis: axis or axes along which sums must be computed.
  95. By default, the sum must be computed over the entire tensor.
  96. If a sequence of integers, sums must be computed over multiple axes.
  97. keepdims: if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions,
  98. and, accordingly, the result must be compatible with the input tensor (see :ref:`broadcasting-rule`).
  99. Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result.
  100. Returns:
  101. if the sum was computed over the entire tensor, a zero-dimensional tensor containing the sum;
  102. otherwise, a tensor containing the sums.
  103. The returned tensor must have a data type determined by :ref:`dtype-promotion`.
  104. .. admonition:: Special Cases
  105. Let ``N`` equal the number of elements over which to compute the sum.
  106. * If ``N`` is 0, the sum is ``0`` (i.e., the empty sum).
  107. * If :math:`x_i` is ``NaN``, the sum is ``NaN`` (i.e., ``NaN`` values propagate).
  108. .. warning::
  109. If the accumulator is too small, overflow occurs:
  110. >>> x = F.ones(128, dtype="int8")
  111. >>> F.sum(x)
  112. Tensor(-128, dtype=int8, device=xpux:0)
  113. Examples:
  114. The sum of an empty tensor is the neutral element 0:
  115. >>> F.sum(Tensor([]))
  116. Tensor(0.0, device=xpux:0)
  117. Normal case:
  118. >>> F.sum(Tensor([1, 2, 3]))
  119. Tensor(6, dtype=int32, device=xpux:0)
  120. >>> F.sum(Tensor([0.5, 1.5]))
  121. Tensor(2.0, device=xpux:0)
  122. Along an axis:
  123. >>> F.sum(Tensor([[1, 2, 3], [4, 5, 6]]), axis=0)
  124. Tensor([5 7 9], dtype=int32, device=xpux:0)
  125. >>> F.sum(Tensor([[1, 2, 3], [4, 5, 6]]), axis=1)
  126. Tensor([ 6 15], dtype=int32, device=xpux:0)
  127. """
  128. return inp.sum(axis=axis, keepdims=keepdims)
  129. def prod(
  130. inp: Tensor, axis: Optional[Union[int, Sequence[int]]] = None, keepdims=False
  131. ) -> Tensor:
  132. r"""Calculates the product of tensor elements over a given axis (or axes).
  133. Args:
  134. inp: input tensor. Should have a numeric data type.
  135. axis: axis or axes along which products must be computed.
  136. By default, the product must be computed over the entire tensor.
  137. If a sequence of integers, products must be computed over multiple axes.
  138. keepdims: if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions,
  139. and, accordingly, the result must be compatible with the input tensor (see :ref:`broadcasting-rule`).
  140. Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result.
  141. Returns:
  142. if the product was computed over the entire tensor, a zero-dimensional tensor containing the products;
  143. otherwise, a non-zero-dimensional tensor containing the products.
  144. The returned tensor must have a data type determined by :ref:`dtype-promotion`.
  145. .. admonition:: Special Cases
  146. Let ``N`` equal the number of elements over which to compute the product.
  147. * If ``N`` is 0, the product is ``1`` (i.e., the empty product).
  148. * If :math:`x_i` is ``NaN``, the product is ``NaN`` (i.e., ``NaN`` values propagate).
  149. .. warning::
  150. Arithmetic is modular when using integer types, and no error is raised on overflow:
  151. >>> x = Tensor([536870910, 536870910, 536870910, 536870910])
  152. >>> F.prod(x)
  153. Tensor(16, dtype=int32, device=xpux:0)
  154. Examples:
  155. The product of an empty tensor is the neutral element 1:
  156. >>> F.prod(Tensor([]))
  157. Tensor(1.0, device=xpux:0)
  158. Normal case:
  159. >>> F.prod(Tensor([1, 2, 3]))
  160. Tensor(6, dtype=int32, device=xpux:0)
  161. >>> F.prod(Tensor([0.5, 1.5]))
  162. Tensor(0.75, device=xpux:0)
  163. Along an axis:
  164. >>> F.prod(Tensor([[1, 2, 3], [4, 5, 6]]), axis=0)
  165. Tensor([ 4 10 18], dtype=int32, device=xpux:0)
  166. >>> F.prod(Tensor([[1, 2, 3], [4, 5, 6]]), axis=1)
  167. Tensor([ 6 120], dtype=int32, device=xpux:0)
  168. """
  169. return inp.prod(axis=axis, keepdims=keepdims)
  170. def mean(
  171. inp: Tensor,
  172. axis: Optional[Union[int, Sequence[int]]] = None,
  173. keepdims: bool = False,
  174. ) -> Tensor:
  175. r"""Calculates the mean of tensor elements over a given axis (or axes).
  176. Args:
  177. inp: input tensor. Should have a numeric data type.
  178. axis: axis or axes along which means must be computed.
  179. By default, the mean must be computed over the entire tensor.
  180. If a sequence of integers, means must be computed over multiple axes.
  181. keepdims: if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions,
  182. and, accordingly, the result must be compatible with the input tensor (see :ref:`broadcasting-rule`).
  183. Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result.
  184. Returns:
  185. if the mean was computed over the entire tensor, a zero-dimensional tensor containing the mean;
  186. otherwise, a non-zero-dimensional tensor containing the means.
  187. The returned tensor must have a data type determined by :ref:`dtype-promotion`.
  188. .. admonition:: Special Cases
  189. Let ``N`` equal the number of elements over which to compute the mean.
  190. * If ``N`` is 0, the mean is ``NaN``.
  191. * If :math:`x_i` is ``NaN``, the mean is ``NaN`` (i.e., ``NaN`` values propagate).
  192. Examples:
  193. >>> F.mean(Tensor([1, 2, 3]))
  194. Tensor(2.0, device=xpux:0)
  195. >>> import numpy as np
  196. >>> F.mean(Tensor([1, np.nan, 3]))
  197. Tensor(nan, device=xpux:0)
  198. Along an axis:
  199. >>> F.mean(Tensor([[1, 2, 3], [4, 5, 6]]), axis=0)
  200. Tensor([2.5 3.5 4.5], device=xpux:0)
  201. >>> F.mean(Tensor([[1, 2, 3], [4, 5, 6]]), axis=1)
  202. Tensor([2. 5.], device=xpux:0)
  203. """
  204. return inp.mean(axis=axis, keepdims=keepdims)
  205. def var(
  206. inp: Tensor,
  207. axis: Optional[Union[int, Sequence[int]]] = None,
  208. keepdims: bool = False,
  209. ) -> Tensor:
  210. r"""Calculates the variance of tensor elements over a given axis (or axes).
  211. Args:
  212. inp: input tensor. Should have a numeric data type.
  213. axis: axis or axes along which variances must be computed.
  214. By default, the variance must be computed over the entire tensor.
  215. If a sequence of integers, variances must be computed over multiple axes.
  216. keepdims: if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions,
  217. and, accordingly, the result must be compatible with the input tensor (see :ref:`broadcasting-rule`).
  218. Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result.
  219. Returns:
  220. if the variance was computed over the entire tensor, a zero-dimensional tensor containing the variance;
  221. otherwise, a non-zero-dimensional tensor containing the variances.
  222. The returned tensor must have a data type determined by :ref:`dtype-promotion`.
  223. .. note::
  224. The variance is the average of the squared deviations from the mean,
  225. i.e., ``var = mean(x)``, where ``x = abs(a - a.mean())**2``.
  226. Examples:
  227. >>> x = Tensor([[1, 2], [3, 4]])
  228. >>> F.var(x)
  229. Tensor(1.25, device=xpux:0)
  230. >>> x = Tensor([[14, 8, 11, 10], [7, 9, 10, 11], [10, 15, 5, 10]])
  231. >>> F.var(x)
  232. Tensor(6.8333335, device=xpux:0)
  233. """
  234. if axis is None:
  235. m = mean(inp, axis=axis, keepdims=False)
  236. else:
  237. m = mean(inp, axis=axis, keepdims=True)
  238. v = inp - m
  239. return mean(v ** 2, axis=axis, keepdims=keepdims)
  240. def std(
  241. inp: Tensor,
  242. axis: Optional[Union[int, Sequence[int]]] = None,
  243. keepdims: bool = False,
  244. ) -> Tensor:
  245. r"""Calculates the standard deviation of tensor elements over a given axis (or axes).
  246. Args:
  247. inp: input tensor. Should have a numeric data type.
  248. axis: axis or axes along which standard deviations must be computed.
  249. By default, the standard deviation must be computed over the entire tensor.
  250. If a sequence of integers, standard deviations must be computed over multiple axes.
  251. keepdims: if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions,
  252. and, accordingly, the result must be compatible with the input tensor (see :ref:`broadcasting-rule`).
  253. Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result.
  254. Returns:
  255. if the standard deviation was computed over the entire tensor, a zero-dimensional tensor containing the standard deviation;
  256. otherwise, a non-zero-dimensional tensor containing the standard deviations.
  257. .. note::
  258. The standard deviation is the square root of the average of the squared deviations from the mean,
  259. i.e., ``std = sqrt(mean(x))``, where ``x = abs(a - a.mean())**2``.
  260. Examples:
  261. >>> x = Tensor([[1, 2], [3, 4]])
  262. >>> F.std(x)
  263. Tensor(1.118034, device=xpux:0)
  264. >>> x = Tensor([[14, 8, 11, 10], [7, 9, 10, 11], [10, 15, 5, 10]])
  265. >>> F.std(x)
  266. Tensor(2.6140645, device=xpux:0)
  267. """
  268. return var(inp, axis=axis, keepdims=keepdims) ** 0.5
  269. def min(
  270. inp: Tensor,
  271. axis: Optional[Union[int, Sequence[int]]] = None,
  272. keepdims: bool = False,
  273. ) -> Tensor:
  274. r"""Calculates the minimum of tensor elements over a given axis (or axes).
  275. Args:
  276. inp: input tensor. Should have a numeric data type.
  277. axis: axis or axes along which minimums must be computed.
  278. By default, the minimum must be computed over the entire tensor.
  279. If a sequence of integers, minimums must be computed over multiple axes.
  280. keepdims: if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions,
  281. and, accordingly, the result must be compatible with the input tensor (see :ref:`broadcasting-rule`).
  282. Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result.
  283. Returns:
  284. if the minimum was computed over the entire tensor, a zero-dimensional tensor containing the minimum;
  285. otherwise, a non-zero-dimensional tensor containing the minimums.
  286. .. admonition:: Special Cases
  287. If :math:`x_i` is ``NaN``, the minimum is ``NaN`` (i.e., ``NaN`` values propagate).
  288. Examples:
  289. >>> x = Tensor([[1, 2], [3, 4]])
  290. >>> F.min(x)
  291. Tensor(1, dtype=int32, device=xpux:0)
  292. Along an axis:
  293. >>> F.min(x, axis=0)
  294. Tensor([1 2], dtype=int32, device=xpux:0)
  295. >>> F.min(x, axis=1)
  296. Tensor([1 3], dtype=int32, device=xpux:0)
  297. """
  298. return inp.min(axis=axis, keepdims=keepdims)
  299. def max(
  300. inp: Tensor,
  301. axis: Optional[Union[int, Sequence[int]]] = None,
  302. keepdims: bool = False,
  303. ) -> Tensor:
  304. r"""Calculates the maximum of tensor elements over a given axis (or axes).
  305. Args:
  306. inp: input tensor. Should have a numeric data type.
  307. axis: axis or axes along which maximums must be computed.
  308. By default, the maximum must be computed over the entire tensor.
  309. If a sequence of integers, maximums must be computed over multiple axes.
  310. keepdims: if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions,
  311. and, accordingly, the result must be compatible with the input tensor (see :ref:`broadcasting-rule`).
  312. Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result.
  313. Returns:
  314. if the maximum was computed over the entire tensor, a zero-dimensional tensor containing the maximum;
  315. otherwise, a non-zero-dimensional tensor containing the maximums.
  316. .. admonition:: Special Cases
  317. If :math:`x_i` is ``NaN``, the maximum is ``NaN`` (i.e., ``NaN`` values propagate).
  318. Examples:
  319. >>> x = Tensor([[1, 2], [3, 4]])
  320. >>> F.max(x)
  321. Tensor(4, dtype=int32, device=xpux:0)
  322. Along an axis:
  323. >>> F.max(x, axis=0)
  324. Tensor([3 4], dtype=int32, device=xpux:0)
  325. >>> F.max(x, axis=1)
  326. Tensor([2 4], dtype=int32, device=xpux:0)
  327. """
  328. return inp.max(axis=axis, keepdims=keepdims)
  329. # searching functions
  330. def argmin(
  331. inp: Tensor,
  332. axis: Optional[Union[int, Sequence[int]]] = None,
  333. keepdims: bool = False,
  334. ) -> Tensor:
  335. r"""Returns the indices of the minimum values along
  336. given axis. If axis is a list of dimensions,
  337. reduce over all of them.
  338. Args:
  339. inp: input tensor.
  340. axis: dimension to reduce. If None, all dimensions will be reduced. Default: None
  341. keepdims: whether the output tensor has axis retained or not. Default: False
  342. Returns:
  343. output tensor.
  344. Examples:
  345. >>> import numpy as np
  346. >>> x = Tensor(np.arange(1, 7, dtype=np.int32).reshape(2,3))
  347. >>> F.argmin(x)
  348. Tensor(0, dtype=int32, device=xpux:0)
  349. """
  350. if axis is None:
  351. assert not keepdims, "can not set axis=None and keepdims=True"
  352. inp = inp.flatten()
  353. axis = 0
  354. axis = _normalize_axis(inp.ndim, axis, reverse=True)
  355. if isinstance(axis, collections.abc.Iterable):
  356. for ai in axis:
  357. op = builtin.Argmin(axis=ai)
  358. (inp,) = apply(op, inp)
  359. if not keepdims:
  360. inp = squeeze(inp, ai)
  361. return inp
  362. op = builtin.Argmin(axis=axis)
  363. (result,) = apply(op, inp)
  364. if not keepdims:
  365. result = squeeze(result, axis)
  366. return result
  367. def argmax(
  368. inp: Tensor,
  369. axis: Optional[Union[int, Sequence[int]]] = None,
  370. keepdims: bool = False,
  371. ) -> Tensor:
  372. r"""Returns the indices of the maximum values along
  373. given axis. If axis is a list of dimensions,
  374. reduce over all of them.
  375. Args:
  376. inp: input tensor.
  377. axis: dimension to reduce. If None, all dimensions will be reduced. Default: None
  378. keepdims: whether the output tensor has axis retained or not. Default: False
  379. Returns:
  380. output tensor.
  381. Examples:
  382. >>> import numpy as np
  383. >>> x = Tensor(np.arange(1, 7, dtype=np.int32).reshape(2,3))
  384. >>> F.argmax(x)
  385. Tensor(5, dtype=int32, device=xpux:0)
  386. """
  387. if axis is None:
  388. assert not keepdims, "can not set axis=None and keepdims=True"
  389. inp = inp.flatten()
  390. axis = 0
  391. axis = _normalize_axis(inp.ndim, axis, reverse=True)
  392. if isinstance(axis, collections.abc.Iterable):
  393. for ai in axis:
  394. op = builtin.Argmax(axis=ai)
  395. (inp,) = apply(op, inp)
  396. if not keepdims:
  397. inp = squeeze(inp, ai)
  398. return inp
  399. op = builtin.Argmax(axis=axis)
  400. (result,) = apply(op, inp)
  401. if not keepdims:
  402. result = squeeze(result, axis)
  403. return result
  404. # sorting functions
  405. def argsort(inp: Tensor, descending: bool = False) -> Tensor:
  406. r"""Returns the indices that would sort the input tensor.
  407. Args:
  408. inp: input tensor. If it's 2d, the result would be array of indices show how to sort each row in the input tensor.
  409. descending: sort in descending order, where the largest comes first. Default: False
  410. inp: Tensor:
  411. descending: bool:
  412. Returns:
  413. indices of int32 indicates how to sort the input.
  414. Examples:
  415. >>> import numpy as np
  416. >>> x = Tensor(np.array([1,2], dtype=np.float32))
  417. >>> F.argsort(x)
  418. Tensor([0 1], dtype=int32, device=xpux:0)
  419. """
  420. assert len(inp.shape) <= 2, "Input should be 1d or 2d"
  421. if descending:
  422. order = "descending"
  423. else:
  424. order = "ascending"
  425. op = builtin.Argsort(order=order)
  426. if len(inp.shape) == 1:
  427. inp = inp.reshape(1, -1)
  428. _, result = apply(op, inp)
  429. return result[0]
  430. _, result = apply(op, inp)
  431. return result
  432. def sort(inp: Tensor, descending: bool = False) -> Tuple[Tensor, Tensor]:
  433. r"""Returns sorted tensor and the indices would sort the input tensor.
  434. Args:
  435. inp: input tensor. If it's 2d, the result would be sorted by row.
  436. descending: sort in descending order, where the largest comes first. Default: False
  437. Returns:
  438. tuple of two tensors `(sorted_tensor, indices_of_int32)`.
  439. Examples:
  440. >>> import numpy as np
  441. >>> x = Tensor(np.array([1,2], dtype=np.float32))
  442. >>> out, indices = F.sort(x)
  443. >>> out.numpy()
  444. array([1., 2.], dtype=float32)
  445. """
  446. assert len(inp.shape) <= 2, "Input should be 1d or 2d"
  447. if descending:
  448. order = "descending"
  449. else:
  450. order = "ascending"
  451. op = builtin.Argsort(order=order)
  452. if len(inp.shape) == 1:
  453. inp = inp.reshape(1, -1)
  454. tns, ind = apply(op, inp)
  455. return tns[0], ind[0]
  456. tns, ind = apply(op, inp)
  457. return tns, ind
  458. @deprecated_kwargs_default("1.12", "descending", 3)
  459. def topk(
  460. inp: Tensor,
  461. k: int,
  462. descending: bool = False,
  463. kth_only: bool = False,
  464. no_sort: bool = False,
  465. ) -> Tuple[Tensor, Tensor]:
  466. r"""Selects the ``Top-K`` (by default) smallest elements of 2d matrix by row.
  467. Args:
  468. inp: input tensor. If input tensor is 2d, each row will be sorted.
  469. k: number of elements needed.
  470. descending: if True, return the largest elements instead. Default: False
  471. kth_only: if True, only the k-th element will be returned. Default: False
  472. no_sort: if True, the returned elements can be unordered. Default: False
  473. Returns:
  474. tuple of two tensors ``(topk_tensor, indices_of_int32)``
  475. Examples:
  476. >>> import numpy as np
  477. >>> x = Tensor(np.array([2, 4, 6, 8, 7, 5, 3, 1], dtype=np.float32))
  478. >>> top, indices = F.topk(x, 5, descending=False)
  479. >>> print(top.numpy(), indices.numpy())
  480. [1. 2. 3. 4. 5.] [7 0 6 1 5]
  481. """
  482. if descending:
  483. k = -k
  484. if kth_only:
  485. mode = "kth_only"
  486. elif no_sort:
  487. mode = "value_idx_nosort"
  488. else:
  489. mode = "value_idx_sorted"
  490. op = builtin.TopK(mode=mode)
  491. if not isinstance(k, Tensor):
  492. k = Const(k, "int32", inp.device)
  493. if len(inp.shape) == 1:
  494. if kth_only:
  495. (tns,) = apply(op, expand_dims(inp, 0), k)
  496. # FIXME:
  497. # could use a dedicated kernel
  498. # gradient may be routed to other indices if k-th value is not unique
  499. ind = argmax((tns == inp).astype("int8"))
  500. tns = squeeze(tns, 0)
  501. else:
  502. tns, ind = apply(op, expand_dims(inp, 0), k)
  503. tns = squeeze(tns, 0)
  504. ind = squeeze(ind, 0)
  505. else:
  506. if kth_only:
  507. (tns,) = apply(op, inp, k)
  508. # FIXME: same as above
  509. ind = argmax((expand_dims(tns, 1) == inp).astype("int8"), 1)
  510. else:
  511. tns, ind = apply(op, inp, k)
  512. return tns, ind
  513. # linear algebra functions
  514. def matinv(inp: Tensor) -> Tensor:
  515. r"""Computes the inverse of a batch of matrices; input must has shape [..., n, n].
  516. Args:
  517. inp: input tensor.
  518. Returns:
  519. output tensor.
  520. Examples:
  521. >>> import numpy as np
  522. >>> data = Tensor([[1.0, 0.0], [1.0, 1.0]])
  523. >>> out = F.matinv(data)
  524. >>> out.numpy()
  525. array([[ 1., 0.],
  526. [-1., 1.]], dtype=float32)
  527. """
  528. (result,) = apply(builtin.MatrixInverse(), inp)
  529. return result
  530. def matmul(
  531. inp1: Tensor,
  532. inp2: Tensor,
  533. transpose_a=False,
  534. transpose_b=False,
  535. compute_mode="default",
  536. ) -> Tensor:
  537. r"""Performs a matrix multiplication of the matrices ``inp1`` and ``inp2``.
  538. With different inputs dim, this function behaves differently:
  539. * Both 1-D tensor, simply forward to ``dot``.
  540. * Both 2-D tensor, normal matrix multiplication.
  541. * If one input tensor is 1-D, matrix vector multiplication.
  542. * If at least one tensor are 3-dimensional or >3-dimensional, the other tensor should have dim >= 2,
  543. the batched matrix-matrix is returned, and the tensor with smaller dimension will be broadcasted.
  544. For example:
  545. * inp1: `(n, k, m)`, inp2: `(n, m, p)`, return: `(n, k, p)`
  546. * inp1: `(n, k, m)`, inp2: `(m, p)`, return: `(n, k, p)`
  547. * inp1: `(n, j, k, m)`, inp2: `(n, j, m, p)`, return: `(n, j, k, p)`
  548. Args:
  549. inp1: first matrix to be multiplied.
  550. inp2: second matrix to be multiplied.
  551. Returns:
  552. output tensor.
  553. Examples:
  554. >>> import numpy as np
  555. >>> data1 = Tensor(np.arange(0, 6, dtype=np.float32).reshape(2, 3))
  556. >>> data2 = Tensor(np.arange(0, 6, dtype=np.float32).reshape(3, 2))
  557. >>> out = F.matmul(data1, data2)
  558. >>> out.numpy()
  559. array([[10., 13.],
  560. [28., 40.]], dtype=float32)
  561. """
  562. return _matmul(inp1, inp2, transpose_a, transpose_b, compute_mode)
  563. def dot(inp1: Tensor, inp2: Tensor) -> Tensor:
  564. r"""Computes dot-product of two vectors ``inp1`` and ``inp2``.
  565. inputs must be 1-dimensional or scalar. A scalar input is automatically broadcasted.
  566. Refer to :func:`~.matmul` for more general usage.
  567. Args:
  568. inp1: first vector.
  569. inp2: second vector.
  570. Returns:
  571. output value.
  572. Examples:
  573. >>> import numpy as np
  574. >>> data1 = Tensor(np.arange(0, 6, dtype=np.float32))
  575. >>> data2 = Tensor(np.arange(0, 6, dtype=np.float32))
  576. >>> out = F.dot(data1, data2)
  577. >>> out.numpy()
  578. array(55., dtype=float32)
  579. """
  580. op = builtin.Dot()
  581. assert (
  582. inp1.ndim <= 1 and inp2.ndim <= 1
  583. ), "Input tensors for dot must be 1-dimensional or scalar"
  584. (result,) = apply(op, inp1, inp2)
  585. return result
  586. def svd(inp: Tensor, full_matrices=False, compute_uv=True) -> Tensor:
  587. r"""Computes the singular value decomposition of a matrix (or a stack of matrices) ``inp``.
  588. Let :math:`X` be the input matrix (or a stack of input matrices), the output should satisfies:
  589. .. math::
  590. X = U * diag(S) * Vh
  591. where ``U`` is a matrix (or stack of vectors) with orthonormal columns, ``S`` is a vector of
  592. non-negative numbers (or stack of vectors), and ``Vh`` is a matrix (or a stack of matrices)
  593. with orthonormal rows.
  594. Args:
  595. inp (Tensor): A input real tensor having the shape ``(..., M, N)`` with ``inp.ndim >= 2`` .
  596. full_matrices (bool, optional): If ``False`` , ``U`` and ``Vh`` have the shapes ``(..., M, K)``
  597. and ``(..., K, N)`` , respectively, where ``K = min(M, N)`` . If ``True`` , the shapes
  598. are ``(..., M, M)`` and ``(..., N, N)`` , respectively. Default: ``False`` .
  599. compute_uv (bool, optional): Whether or not to compute ``U`` and ``Vh`` in addition to ``S`` . Default: ``True`` .
  600. Note:
  601. * naive does not support ``full_matrices`` and ``compute_uv`` as ``True`` .
  602. Returns:
  603. Returns a tuple ( ``U`` , ``S`` , ``Vh`` ), which are SVD factors ``U`` , ``S``, ``Vh`` of input matrix ``inp``.
  604. ( ``U`` , ``Vh`` only returned when ``compute_uv`` is True). ``U`` contains matrices orthonormal columns
  605. (i.e., the columns are left singular vectors). If ``full_matrices`` is ``True`` , the array must have shape
  606. ``(..., M, M)`` . If ``full_matrices`` is ``False`` , the array must have shape ``(..., M, K)`` , where ``K = min(M, N)`` .
  607. Examples:
  608. >>> import numpy as np
  609. >>> x = Tensor(np.random.randn(9, 6))
  610. >>> y = Tensor(np.random.randn(2, 7, 8, 3))
  611. >>> U, S, Vh = F.svd(x, full_matrices=False)
  612. >>> print(U._tuple_shape, S._tuple_shape, Vh._tuple_shape)
  613. (9, 6) (6,) (6, 6)
  614. >>> u, s, vh = F.svd(y, full_matrices=False)
  615. >>> print(u._tuple_shape, s._tuple_shape, vh._tuple_shape)
  616. (2, 7, 8, 3) (2, 7, 3) (2, 7, 3, 3)
  617. """
  618. op = builtin.SVD(full_matrices=full_matrices, compute_uv=compute_uv)
  619. U, S, Vh = apply(op, inp)
  620. return U, S, Vh
  621. def norm(
  622. inp: Tensor, ord: float = None, axis: int = None, keepdims=False,
  623. ):
  624. r"""Calculates the norm of tensor elements over a given axis.
  625. This function is able to return different matrix norms,
  626. or one of an infinite number of vector norms (described below), depending on the value of the ord parameter.
  627. Args:
  628. inp: input tensor. Should have a numeric data type.
  629. ord: Order of the norm (see table under Notes). If not specified, the default is 2.
  630. axis: Axis along which to compute vector norms.
  631. If axis is an integer, it specifies the axis of inp along which to compute the vector norms.
  632. keepdims: If this is set to ``True``,
  633. the axes which are normed over are left in the result as dimensions with size one.
  634. Returns:
  635. Norm of the matrix or vector(s).
  636. .. note::
  637. Now the following norms can be calculated:
  638. * inf: norm-:math:`\infty` (maximum of absolute values).
  639. * -inf: norm-:math:`-\infty` (minimum of absolute values).
  640. * 2: 2-norm (largest singluar value).
  641. The Frobenius norm is given by to ``sum(abs(x)**ord)**(1./ord)``:
  642. .. math::
  643. \|A\|_F=\left[\sum_{i, j} a b s\left(a_{i, j}\right)^2\right]^{1 / 2}
  644. .. seealso:: :func:`numpy.linalg.norm` / :func:`~.functional.normalize`
  645. Examples:
  646. >>> import math
  647. >>> x = Tensor([1, 2, 3])
  648. >>> F.norm(x, ord=math.inf)
  649. Tensor(3, dtype=int32, device=xpux:0)
  650. >>> F.norm(x, ord=-math.inf)
  651. Tensor(1, dtype=int32, device=xpux:0)
  652. >>> x = Tensor([[1, 2, 3], [4, 5, 6]])
  653. >>> F.norm(x, ord=2, axis=0)
  654. Tensor([4.1231 5.3852 6.7082], device=xpux:0)
  655. >>> F.norm(x, ord=2, axis=1)
  656. Tensor([3.7417 8.775 ], device=xpux:0)
  657. """
  658. if axis is None:
  659. if inp.ndim != 1:
  660. raise TypeError("axis is required unless input is a vector")
  661. if ord is None:
  662. ord = 2
  663. if ord == 0:
  664. return sum(inp != 0, axis=axis, keepdims=keepdims)
  665. if ord == math.inf:
  666. return max(abs(inp))
  667. if ord == -math.inf:
  668. return min(abs(inp))
  669. return sum(abs(inp) ** ord, axis=axis, keepdims=keepdims) ** (1.0 / ord)
  670. def normalize(
  671. inp: Tensor, ord: float = None, axis: int = None, eps: float = 1e-12,
  672. ) -> Tensor:
  673. r"""Performs :math:`L_p` normalization of input tensor along given axis.
  674. For a tensor of shape :math:`(n_0, ..., n_{dim}, ..., n_k)`,
  675. each :math:`n_{dim}` -element vector :math:`v` along dimension :attr:`axis` is transformed as:
  676. .. math::
  677. v = \frac{v}{\max(\lVert v \rVert_p, \epsilon)}.
  678. Args:
  679. inp: input tensor.
  680. ord: power of value applied to input tensor.
  681. axis: dimension to reduce.If None, input must be a vector.
  682. eps: a small value to avoid division by zero.
  683. Returns:
  684. normalized output tensor.
  685. seealso:: :func:`numpy.linalg.norm` / :func:`~.functional.norm`
  686. Examples:
  687. >>> x = Tensor([[1, 2, 3], [4, 5, 6]])
  688. >>> F.normalize(x, ord=2, axis=0)
  689. Tensor([[0.2425 0.3714 0.4472]
  690. [0.9701 0.9285 0.8944]], device=xpux:0)
  691. >>> F.normalize(x, ord=2, axis=1)
  692. Tensor([[0.2673 0.5345 0.8018]
  693. [0.4558 0.5698 0.6838]], device=xpux:0)
  694. """
  695. if axis is None:
  696. return inp / clip(norm(inp, ord, axis), lower=eps)
  697. else:
  698. return inp / clip(norm(inp, ord, axis, keepdims=True), lower=eps)
  699. def _check_non_finite(inps: Iterable[Tensor], scale=1.0) -> Tensor:
  700. r"""Check whether input contains infinite or nan value.
  701. Args:
  702. inps: tensors to be checked.
  703. Returns:
  704. a int32 scalar tensor, 0 for False and 1 for True.
  705. """
  706. if isinstance(inps, Tensor):
  707. inps = [inps]
  708. op = builtin.CheckNonFinite(scale=scale)
  709. oups = apply(op, *inps)
  710. out = oups[-1]
  711. for i in range(len(inps)):
  712. inps[i]._reset(oups[i])
  713. return out