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 32 kB

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