1# Copyright 2022 Huawei Technologies Co., Ltd 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14# ============================================================================ 15"""SparseTensor implementation.""" 16from __future__ import absolute_import, annotations 17 18__all__ = ['RowTensorInner', 'RowTensor', 'SparseTensor', 'COOTensor', 'CSRTensor'] 19 20from typing import Tuple, Union 21 22from mindspore import log as logger 23from mindspore.common import dtype as mstype 24from mindspore.common._register_for_tensor import tensor_operator_registry 25from mindspore.common.tensor import Tensor 26from mindspore._c_expression import COOTensor as COOTensor_ 27from mindspore._c_expression import CSRTensor as CSRTensor_ 28from mindspore._c_expression import RowTensor as RowTensor_ 29from mindspore._c_expression import Tensor as Tensor_ 30from mindspore import _checkparam as validator 31from mindspore._checkparam import is_stub_tensor 32 33 34class RowTensorInner(RowTensor_): 35 """ 36 Implementation for RowTensor, for MindSpore developers only. 37 """ 38 39 def __init__(self, indices=None, values=None, shape=None, row_tensor=None): 40 """Init RowTensor""" 41 self.init_finished = False 42 # Directly init a RowTensor from another RowTensor 43 if row_tensor is not None: 44 if not isinstance(row_tensor, (RowTensor, RowTensor_)): 45 raise TypeError(f"Expect input `row_tensor` to be a RowTensor, but got {type(row_tensor)}") 46 if not (indices is None and values is None and shape is None): 47 raise TypeError("If input `row_tensor` is provided, `indices`, `values`, `shapes` should all be `None`") 48 RowTensor_.__init__(self, row_tensor) 49 # Init a RowTensor from indices, values and shape 50 else: 51 if is_stub_tensor(values): 52 values = values.stub_sync() 53 RowTensor_.__init__(self, indices, values, shape) 54 self.init_finished = True 55 56 def __repr__(self): 57 """Avoid PyTest Segfault when RowTensor is not initialized.""" 58 if self.init_finished: 59 return RowTensor_.__repr__(self) 60 return '' 61 62 @property 63 def indices(self): 64 """Return RowTensor's indices.""" 65 return Tensor(self._indices) 66 67 @property 68 def values(self): 69 """Return RowTensor's non-zero values.""" 70 return Tensor(self._values) 71 72 @property 73 def dense_shape(self): 74 """Return RowTensor's shape.""" 75 return self._shape 76 77 78class RowTensor(RowTensorInner): 79 """ 80 A sparse representation of a set of tensor slices at given indices. 81 82 When the `values` of a RowTensor has a shape of :math:`(d_0, d_1, ..., d_n)`, then this RowTensor is used to 83 represent a subset of a larger dense tensor of shape :math:`(l_0, d_1, ..., d_n)`, where :math:`d_i` is the size of 84 i-th axis in RowTensor, :math:`l_0` is the size of 0-th axis of dense tensor and it satisfies :math:`l_0 > d_0`. 85 86 The parameter `indices` is used to specify locations from which the `RowTensor` is sliced in the first dimension of 87 the dense tensor, which means the parameters `indices` and `values` have the following relationship 88 :math:`dense[indices[i], :, :, :, ...] = values[i, :, :, :, ...]`. 89 90 For example, if indices is [0], values is [[1, 2]], shape is 91 :math:`(3, 2)` , then the dense representation of the row tensor will be: 92 93 .. code-block:: 94 95 [[1, 2], 96 [0, 0], 97 [0, 0]] 98 99 .. warning:: 100 This is an experimental API that is subjected to change or deletion. 101 102 Args: 103 indices (Tensor): A 1-D integer Tensor of shape :math:`(d_0)` . Default: ``None``. 104 values (Tensor): A Tensor of any dtype of shape :math:`(d_0, d_1, ..., d_n)` . Default: ``None``. 105 shape (tuple(int)): An integer tuple which contains the shape 106 of the corresponding dense tensor. Default: ``None``. 107 row_tensor (RowTensor): A RowTensor object. Default: ``None``. 108 109 Returns: 110 RowTensor, composed of `indices`, `values`, and `shape`. 111 112 Examples: 113 >>> import mindspore as ms 114 >>> from mindspore import Tensor, RowTensor 115 >>> indices = Tensor([0]) 116 >>> values = Tensor([[1, 2]], dtype=ms.float32) 117 >>> shape = (3, 2) 118 >>> x = RowTensor(indices, values, shape) 119 >>> print(x.values) 120 [[1. 2.]] 121 >>> print(x.indices) 122 [0] 123 >>> print(x.dense_shape) 124 (3, 2) 125 """ 126 127 def __init__(self, indices=None, values=None, shape=None, row_tensor=None): 128 """Init RowTensor""" 129 logger.warning("'RowTensor' is deprecated from version 1.7 and will be removed in a future version.") 130 super().__init__(indices, values, shape, row_tensor) 131 132 133class SparseTensor(COOTensor_): 134 """ 135 A sparse representation of a set of nonzero elements from a tensor at given indices. 136 137 SparseTensor can only be used in the `Cell`'s construct method. 138 139 For a tensor dense, its SparseTensor(indices, values, dense_shape) has 140 `dense[indices[i]] = values[i]`. 141 142 For example, if indices is [[0, 1], [1, 2]], values is [1, 2], dense_shape is 143 (3, 4), then the dense representation of the sparse tensor will be: 144 145 .. code-block:: 146 147 [[0, 1, 0, 0], 148 [0, 0, 2, 0], 149 [0, 0, 0, 0]] 150 151 Note: 152 The interface is deprecated from version 1.7 and will be removed in a future version. 153 Please use :class:`mindspore.COOTensor` instead. 154 155 Args: 156 indices (Tensor): A 2-D integer Tensor of shape :math:`(N, ndims)`, 157 where N and ndims are the number of `values` and number of dimensions in 158 the SparseTensor, respectively. 159 values (Tensor): A 1-D tensor of any type and shape :math:`(N)`, which 160 supplies the values for each element in `indices`. 161 shape (tuple(int)): An integer tuple of size :math:`(ndims)`, 162 which specifies the shape of the sparse tensor. 163 164 Returns: 165 SparseTensor, composed of `indices`, `values`, and `shape`. 166 167 Examples: 168 >>> import mindspore as ms 169 >>> from mindspore import Tensor, SparseTensor 170 >>> indices = Tensor([[0, 1], [1, 2]]) 171 >>> values = Tensor([1, 2], dtype=ms.float32) 172 >>> shape = (3, 4) 173 >>> x = SparseTensor(indices, values, shape) 174 >>> print(x.values) 175 [1. 2.] 176 >>> print(x.indices) 177 [[0 1] 178 [1 2]] 179 >>> print(x.shape) 180 (3, 4) 181 """ 182 183 def __init__(self, indices, values, shape): 184 """Init COOTensor.""" 185 logger.warning("'SparseTensor' is deprecated from version 1.7 and will be removed in a future version. " + 186 "Please use 'COOTensor' instead.") 187 if not (isinstance(indices, Tensor) and isinstance(values, Tensor) and isinstance(shape, tuple)): 188 raise TypeError("Inputs must follow: COOTensor(indices, values, shape).") 189 if is_stub_tensor(indices): 190 indices = indices.stub_sync() 191 if is_stub_tensor(values): 192 values = values.stub_sync() 193 COOTensor_.__init__(self, indices, values, shape) 194 195 @property 196 def indices(self): 197 """Return SparseTensor's indices.""" 198 return Tensor(self._indices) 199 200 @property 201 def values(self): 202 """Return SparseTensor's non-zero values.""" 203 return Tensor(self._values) 204 205 @property 206 def shape(self): 207 """Return SparseTensor's shape.""" 208 return self._shape 209 210 211class COOTensor(COOTensor_): 212 """ 213 A sparse representation of a set of nonzero elements from a tensor at given indices. 214 215 For a tensor dense, its COOTensor(indices, values, shape) has 216 `dense[indices[i]] = values[i]`. 217 218 For example, if indices is [[0, 1], [1, 2]], values is [1, 2], shape is 219 (3, 4), then the dense representation of the sparse tensor will be: 220 221 .. code-block:: 222 223 [[0, 1, 0, 0], 224 [0, 0, 2, 0], 225 [0, 0, 0, 0]] 226 227 Common arithmetic operations include: addition (+), subtraction (-), multiplication (*), 228 and division (/). For details about operations supported by `COOTensor`, see 229 `operators <https://www.mindspore.cn/docs/en/master/note/static_graph_syntax_support.html#operators>`_. 230 231 .. warning:: 232 - This is an experimental API that is subject to change or deletion. 233 - Currently, duplicate coordinates in the indices will not be coalesced. 234 If the indices contain out-of-bound values, the result will be undefined. 235 236 Args: 237 indices (Tensor): A 2-D integer Tensor of shape :math:`(N, ndims)`, 238 where N and ndims are the number of `values` and number of dimensions in 239 the COOTensor, respectively. Currently, `ndims` must be 2. Default: ``None`` . 240 Please make sure that the indices are in range of the given shape. 241 values (Tensor): A 1-D tensor of any type and shape :math:`(N)`, which 242 supplies the values for each element in `indices`. Default: ``None`` . 243 shape (tuple(int)): An integer tuple of shape :math:`(ndims)`, 244 which specifies the dense_shape of the sparse tensor. Default: ``None`` . 245 coo_tensor (COOTensor): A COOTensor object. Default: ``None`` . 246 247 Returns: 248 COOTensor, composed of `indices`, `values`, and `shape`. 249 250 Examples: 251 >>> import mindspore as ms 252 >>> from mindspore import Tensor, COOTensor 253 >>> indices = Tensor([[0, 1], [1, 2]], dtype=ms.int32) 254 >>> values = Tensor([1, 2], dtype=ms.float32) 255 >>> shape = (3, 4) 256 >>> x = COOTensor(indices, values, shape) 257 >>> print(x.values) 258 [1. 2.] 259 >>> print(x.indices) 260 [[0 1] 261 [1 2]] 262 >>> print(x.shape) 263 (3, 4) 264 """ 265 266 def __init__(self, indices=None, values=None, shape=None, coo_tensor=None): 267 """Init COOTensor""" 268 self.init_finished = False 269 # Directly init a COOTensor from another COOTensor 270 if coo_tensor is not None: 271 if not isinstance(coo_tensor, (COOTensor, COOTensor_)): 272 raise TypeError(f"Expect input `coo_tensor` to be a COOTensor, but got {type(coo_tensor)}") 273 if not (indices is None and values is None and shape is None): 274 raise TypeError("If input `coo_tensor` is provided, `indices`, `values`, `shapes` should all be `None`") 275 COOTensor_.__init__(self, coo_tensor) 276 # Init a COOTensor from indices, values and shape 277 else: 278 validator.check_coo_tensor_input(indices, values, shape) 279 validator.check_coo_tensor_shape(indices.shape, values.shape, shape) 280 validator.check_coo_tensor_dtype(indices.dtype) 281 indices = tensor_operator_registry.get('stop_gradient')(indices) 282 if is_stub_tensor(indices): 283 indices = indices.stub_sync() 284 if is_stub_tensor(values): 285 values = values.stub_sync() 286 COOTensor_.__init__(self, indices, values, shape) 287 self.init_finished = True 288 289 def __repr__(self): 290 """Avoid PyTest Segfault when COOTensor is not initialized.""" 291 if self.init_finished: 292 return COOTensor_.__repr__(self) 293 return '' 294 295 def __neg__(self): 296 return COOTensor(self.indices, -self.values, self.shape) 297 298 def __add__(self, other): 299 if not self.shape == other.shape: 300 raise ValueError("Input tensors should have the same shape.") 301 if isinstance(other, Tensor): 302 return tensor_operator_registry.get("tensor_scatter_add")(other, self.indices, self.values) 303 if isinstance(other, COOTensor): 304 return tensor_operator_registry.get('coo_add')(self, other, Tensor(0, self.values.dtype)) 305 raise TypeError("COOTensor add with %s is not supported." % type(other)) 306 307 def __sub__(self, other): 308 if not self.shape == other.shape: 309 raise ValueError("Input tensors should have the same shape.") 310 if isinstance(other, Tensor): 311 return tensor_operator_registry.get("tensor_scatter_add")(-other, self.indices, self.values) 312 if isinstance(other, COOTensor): 313 return tensor_operator_registry.get('coo_add')( 314 self, -other, Tensor(0, self.values.dtype)) 315 raise TypeError("COOTensor subtract with %s is not supported." % type(other)) 316 317 def __mul__(self, other): 318 if not self.shape == other.shape: 319 raise ValueError("Input tensors should have the same shape.") 320 if isinstance(other, Tensor): 321 other_values = tensor_operator_registry.get("gather_nd")(other, self.indices) 322 return COOTensor(self.indices, self.values * other_values, self.shape) 323 raise TypeError("COOTensor multiply with %s is not supported." % type(other)) 324 325 def __div__(self, other): 326 if not self.shape == other.shape: 327 raise ValueError("Input tensors should have the same shape.") 328 if isinstance(other, Tensor): 329 logger.warning("For sparse divide, zero values in the dense tensor are ignored.") 330 other_values = tensor_operator_registry.get("gather_nd")(other, self.indices) 331 return COOTensor(self.indices, self.values / other_values, self.shape) 332 raise TypeError("COOTensor divide with %s is not supported." % type(other)) 333 334 def __truediv__(self, other): 335 return self.__div__(other) 336 337 @property 338 def indices(self) -> Tensor: 339 """Return COOTensor's indices.""" 340 return Tensor(self._indices) 341 342 @property 343 def values(self) -> Tensor: 344 """Return COOTensor's non-zero values.""" 345 return Tensor(self._values) 346 347 @property 348 def shape(self) -> Tuple[int, ...]: 349 """Return COOTensor's shape.""" 350 return self._shape 351 352 @property 353 def dtype(self) -> mstype: 354 """ 355 Return the dtype of the values of COOTensor (:class:`mindspore.dtype`). 356 357 Examples: 358 >>> import mindspore as ms 359 >>> from mindspore import Tensor, COOTensor 360 >>> indices = Tensor([[0, 1], [1, 2]], dtype=ms.int32) 361 >>> values = Tensor([1, 2], dtype=ms.float32) 362 >>> shape = (3, 4) 363 >>> coo_tensor = COOTensor(indices, values, shape) 364 >>> print(coo_tensor.dtype) 365 Float32 366 """ 367 return self._dtype 368 369 @property 370 def size(self) -> int: 371 """ 372 Return the number of non-zero values. 373 374 Examples: 375 >>> import mindspore as ms 376 >>> from mindspore import Tensor, COOTensor 377 >>> indices = Tensor([[0, 1, 2], [1, 0, 2]], dtype=ms.int32) 378 >>> values = Tensor([1, 5, 4], dtype=ms.float32) 379 >>> shape = (3, 3) 380 >>> coo_tensor = COOTensor(indices.transpose(), values, shape) 381 >>> print(coo_tensor.size) 382 3 383 """ 384 return self.values.size 385 386 @property 387 def itemsize(self) -> int: 388 """ 389 Return the length of one tensor element in bytes. 390 391 Examples: 392 >>> import mindspore as ms 393 >>> from mindspore import Tensor, COOTensor 394 >>> indices = Tensor([[0, 1], [1, 2]], dtype=ms.int32) 395 >>> values = Tensor([1, 2], dtype=ms.float64) 396 >>> shape = (3, 4) 397 >>> coo_tensor = COOTensor(indices, values, shape) 398 >>> print(coo_tensor.itemsize) 399 8 400 """ 401 return self.values.itemsize 402 403 @property 404 def ndim(self) -> int: 405 """ 406 Return the number of tensor dimensions. 407 408 Examples: 409 >>> import mindspore as ms 410 >>> from mindspore import Tensor, COOTensor 411 >>> indices = Tensor([[0, 1], [1, 2]], dtype=ms.int32) 412 >>> values = Tensor([1, 2], dtype=ms.float32) 413 >>> coo_tensor = COOTensor(indices, values, (3, 4)) 414 >>> print(coo_tensor.ndim) 415 2 416 """ 417 return len(self.shape) 418 419 def coalesce(self) -> COOTensor: 420 """ 421 Returns a coalesced copy of an uncoalesced sparse tensor. 422 423 Returns: 424 A COOTensor. 425 426 Supported Platforms: 427 ``GPU`` 428 429 Examples: 430 >>> import mindspore as ms 431 >>> from mindspore import Tensor, COOTensor 432 >>> x_indices = Tensor([[0, 0, 1], [1, 1, 2]], dtype=ms.int64) 433 >>> x_values = Tensor([1, 5, 4], dtype=ms.float32) 434 >>> x_shape = (3, 3) 435 >>> coo_tensor = COOTensor(x_indices.transpose(), x_values, x_shape) 436 >>> res = coo_tensor.coalesce() 437 >>> print(res) 438 COOTensor(shape=[3, 3], dtype=Float32, indices=Tensor(shape=[2, 2], dtype=Int64, 439 value=[[0 1] [1 2]]), values=Tensor(shape=[2], dtype=Float32, value=[6.00000000e+00 4.00000000e+00])) 440 """ 441 shape = Tensor(self.shape) 442 res_indices, res_values, _ = tensor_operator_registry.get("coalesce")(self.indices.transpose(), 443 self.values, shape) 444 return COOTensor(res_indices.transpose(), res_values, self.shape) 445 446 def to_csr(self) -> CSRTensor: 447 """ 448 Converts COOTensor to CSRTensor. 449 450 Note: 451 Currently only supports CPU backend with LLVM 12.0.1 installed. 452 453 Returns: 454 CSRTensor. 455 456 Supported Platforms: 457 ``GPU`` ``CPU`` 458 459 Examples: 460 >>> import mindspore as ms 461 >>> from mindspore import Tensor, COOTensor 462 >>> indices = Tensor([[0, 1], [1, 2]], dtype=ms.int32) 463 >>> values = Tensor([1, 2], dtype=ms.int32) 464 >>> shape = (3, 4) 465 >>> coo_tensor = COOTensor(indices, values, shape) 466 >>> print(coo_tensor.to_csr()) 467 CSRTensor(shape=[3, 4], dtype=Int32, indptr=Tensor(shape=[4], dtype=Int32, value=[0 1 2 2]), 468 indices=Tensor(shape=[2], dtype=Int32, value=[1 2]), values=Tensor(shape=[2], dtype=Int32, value=[1 2])) 469 """ 470 row_indices = self.indices[:, 0] 471 col_indices = self.indices[:, 1] 472 idx_dtype = self.indices.dtype 473 row_indices, sort_idx = tensor_operator_registry.get("sort")( 474 row_indices.astype(mstype.float32)) 475 row_indices = row_indices.astype(idx_dtype) 476 col_indices = col_indices[sort_idx] 477 values = self.values[sort_idx] 478 indptr = tensor_operator_registry.get("coo2csr")(row_indices, self.shape[0]) 479 return CSRTensor(indptr, col_indices, values, self.shape) 480 481 def to_dense(self) -> Tensor: 482 """ 483 Converts COOTensor to Dense Tensor. 484 485 Returns: 486 Tensor. 487 488 Supported Platforms: 489 ``GPU`` 490 491 Examples: 492 >>> import mindspore as ms 493 >>> from mindspore import Tensor, COOTensor 494 >>> indices = Tensor([[0, 1, 2], [1, 0, 2]], dtype=ms.int32) 495 >>> values = Tensor([1, 5, 4], dtype=ms.float32) 496 >>> shape = (3, 3) 497 >>> coo_tensor = COOTensor(indices.transpose(), values, shape) 498 >>> print(coo_tensor.to_dense()) 499 [[0. 1. 0.] 500 [5. 0. 0.] 501 [0. 0. 4.]] 502 """ 503 zeros_tensor = tensor_operator_registry.get("zeros")(self.shape, self.values.dtype) 504 return tensor_operator_registry.get("tensor_scatter_add")( 505 zeros_tensor, self.indices, self.values) 506 507 def astype(self, dtype: mstype) -> COOTensor: 508 """ 509 Return a copy of the COOTensor, cast its values to a specified type. 510 511 Args: 512 dtype (Union[:class:`mindspore.dtype`, numpy.dtype, str]): Designated tensor dtype. 513 514 Returns: 515 COOTensor. 516 517 Supported Platforms: 518 ``Ascend`` ``GPU`` ``CPU`` 519 520 Examples: 521 >>> import mindspore as ms 522 >>> from mindspore import Tensor, COOTensor 523 >>> indices = Tensor([[0, 1], [1, 2]], dtype=ms.int32) 524 >>> values = Tensor([1, 2], dtype=ms.float32) 525 >>> shape = (3, 4) 526 >>> coo_tensor = COOTensor(indices, values, shape) 527 >>> print(coo_tensor.astype(ms.float64).dtype) 528 Float64 529 """ 530 data = self.values.astype(dtype) 531 return COOTensor(self.indices, data, self.shape) 532 533 def to_tuple(self) -> Tuple[Tensor, Tensor, Tuple[int, ...]]: 534 """ 535 Return indices, values and shape as a tuple. 536 537 Returns: 538 Tuple. 539 540 Supported Platforms: 541 ``Ascend`` ``GPU`` ``CPU`` 542 543 Examples: 544 >>> import mindspore as ms 545 >>> from mindspore import Tensor, COOTensor 546 >>> indices = Tensor([[0, 1], [1, 2]], dtype=ms.int32) 547 >>> values = Tensor([1, 2], dtype=ms.float32) 548 >>> shape = (3, 4) 549 >>> coo_tensor = COOTensor(indices, values, shape) 550 >>> print(coo_tensor.to_tuple()) 551 (Tensor(shape=[2, 2], dtype=Int32, value= 552 [[0, 1], 553 [1, 2]]), Tensor(shape=[2], dtype=Float32, value= [ 1.00000000e+00, 2.00000000e+00]), (3, 4)) 554 """ 555 return self.indices, self.values, self.shape 556 557 def abs(self) -> COOTensor: 558 """ 559 Return absolute value element-wisely. 560 561 Returns: 562 COOTensor. 563 564 Supported Platforms: 565 ``Ascend`` ``GPU`` ``CPU`` 566 567 Examples: 568 >>> import mindspore as ms 569 >>> from mindspore import Tensor, COOTensor 570 >>> indices = Tensor([[0, 1, 2], [1, 0, 2]], dtype=ms.int32) 571 >>> values = Tensor([1, -5, -4], dtype=ms.float32) 572 >>> shape = (3, 3) 573 >>> coo_tensor = COOTensor(indices.transpose(), values, shape) 574 >>> res = coo_tensor.abs() 575 >>> print(res.values) 576 [1. 5. 4.] 577 """ 578 data = self.values.abs() 579 return COOTensor(self.indices, data, self.shape) 580 581 def add(self, other: COOTensor, thresh: Tensor) -> COOTensor: 582 """ 583 Return the sum with another COOTensor. 584 585 Args: 586 other(COOTensor): the second SparseTensor to sum. 587 thresh(Tensor): A 0-D Tensor, represents the magnitude threshold that determines 588 if an output value/index pair take space, Its dtype 589 should match that of the values if they are real. If output's 590 value is less than the `thresh`, it will vanish. 591 592 Returns: 593 COOTensor, representing the sum. 594 595 Raises: 596 ValueError: If any input(self/other)'s indices's dim is not equal to 2. 597 ValueError: If any input(self/other)'s values's dim is not equal to 1. 598 ValueError: If any input(self/other)'s shape's dim is not equal to 1. 599 ValueError: If thresh's dim is not equal to 0. 600 TypeError: If any input(self/other)'s indices's type is not equal to int64. 601 TypeError: If any input(self/other)'s shape's type is not equal to int64. 602 ValueError: If any input(self/other)'s indices's length is not equal to 603 its values's length. 604 TypeError: If any input(self/other)'s values's type is not equal to anf of 605 (int8/int16/int32/int64/float32/float64/complex64/complex128) 606 TypeError: If thresh's type is not equal to anf of 607 (int8/int16/int32/int64/float32/float64) 608 TypeError: If self's indices's type is not equal to other's indices's type 609 TypeError: If self's values's type is not equal to other's values's type 610 TypeError: If self's shape's type is not equal to other's shape's type 611 TypeError: If (self/other)'s value's type is not matched with thresh's type 612 613 Supported Platforms: 614 ``GPU`` ``CPU`` 615 616 Examples: 617 >>> from mindspore import Tensor, COOTensor 618 >>> from mindspore import dtype as mstype 619 >>> indics0 = Tensor([[0, 1], [1, 2]], dtype=mstype.int64) 620 >>> values0 = Tensor([1, 2], dtype=mstype.int32) 621 >>> shape0 = (3, 4) 622 >>> input0 = COOTensor(indics0, values0, shape0) 623 >>> indics1 = Tensor([[0, 0], [1, 1]], dtype=mstype.int64) 624 >>> values1 = Tensor([3, 4], dtype=mstype.int32) 625 >>> shape1 = (3, 4) 626 >>> input1 = COOTensor(indics1, values1, shape1) 627 >>> thres = Tensor(0, dtype=mstype.int32) 628 >>> out = input0.add(input1, thres) 629 >>> print(out) 630 COOTensor(shape=[3, 4], dtype=Int32, indices=Tensor(shape=[4, 2], dtype=Int64, value= 631 [[0 0] 632 [0 1] 633 [1 1] 634 [1 2]]), values=Tensor(shape=[4], dtype=Int32, value=[3 1 4 2])) 635 """ 636 return tensor_operator_registry.get('coo_add')(self, other, thresh) 637 638 639class CSRTensor(CSRTensor_): 640 r""" 641 Constructs a sparse tensor in CSR (Compressed Sparse Row) format, with specified 642 values indicated by `values` and row and column positions indicated by `indptr` 643 and `indices`. 644 645 For example, if indptr is [0, 2, 5, 6], indices is [0, 3, 1, 2, 4, 2], values is 646 [1., 2., 3., 4., 5., 6.], shape is (3, 5), then the dense representation of the sparse tensor will be: 647 648 .. code-block:: 649 [[1., 0., 0., 2., 0.], 650 [0., 3., 4., 0., 5.], 651 [0., 0., 6., 0., 0.]] 652 653 The length of `indptr` should equal to `shape[0]+1`, where the elements should be equal or monotonically 654 increasing and the maximum value should be equal to the number of non-zero values in the tensor. The length 655 of `indices` and `values` should be equal to the number of non-zero values in the tensor. To be concrete, get 656 the query indices of none-zero elements in every line according to `indptr`. Then get the column positions of 657 none-zero elements in every line by looking up query indices in `indices`. Finally, get the actual values of 658 none-zero elements in every line by looking up query indices in `values`. In the former example, 'indptr' of 659 [0, 2, 5, 6] represents that the indices of 0th row of the tensor origins from [0, 2), the indices of 660 the 1st row of the tensor origins from [2, 5) and the 2nd row of the tensor origins from [5, 6). For example, 661 the column positions of the non-zero elements of the 0th row in the tensor are provided by the [0, 2) elements in 662 `indices` (i.e. [0, 3]) and the corresponding values are provided by the [0, 2) elements in `values` 663 (i.e. [1., 2.]). The column positions of the non-zero elements of the 1st row in the tensor are provided by the 664 [2, 5) elements in `indices` (i.e. [1, 2, 4]) and the corresponding values are provided by the [2, 5) elements in 665 `values` (i.e. [3., 4., 5.]). The column positions of the non-zero elements of the 2nd row in the tensor are 666 provided by the [5, 6) elements in `indices` (i.e. [2]) and the corresponding values are provided by the [5, 6) 667 elements in `values` (i.e. [6.]). 668 669 Common arithmetic operations include: addition (+), subtraction (-), multiplication (*), 670 and division (/). For details about operations supported by `CSRTensor`, see 671 `operators <https://www.mindspore.cn/docs/en/master/note/static_graph_syntax_support.html#operators>`_. 672 673 .. warning:: 674 - This is an experimental API that is subjected to change. 675 - If the values given by `indptr` or `indices` are invalid, the results may be undefined. Invalid values include 676 when the length of `values` or `indices` exceeds the range indicated by `indptr`, and when the columns 677 indicated by `indices` are repeated on the same row. 678 679 Args: 680 indptr (Tensor): 1-D Tensor of shape :math:`(M)`, which equals to `shape[0] + 1`, which indicates the 681 start and end point for `values` in each row. Default: ``None``. If provided, 682 must be int16, int32 or int64. 683 indices (Tensor): 1-D Tensor of shape :math:`(N)`, which has the same length as `values`. `indices` 684 indicates the which column `values` should be placed. Default: ``None``. If provided, 685 must be int16, int32 or int64. 686 values (Tensor): Tensor, which has the same length as `indices` (values.shape[0] == indices.shape[0]). 687 `values` stores the data for CSRTensor. Default: ``None``. 688 shape (tuple(int)): An integer tuple of shape :math:`(ndims)`, and `shape[0]` must equal to `M - 1`, 689 which all equal to number of rows of the CSRTensor. Default: ``None``. 690 csr_tensor (CSRTensor): A CSRTensor object. Values' feature dimension should match with 691 CSRTensor's feature dimension :math:`(values.shape[1:] == csr\_tensor.shape[2:])` . Default: ``None``. 692 693 Outputs: 694 CSRTensor, with shape defined by `shape`, and dtype inferred from `value`. 695 696 Examples: 697 >>> import mindspore as ms 698 >>> from mindspore import Tensor, CSRTensor 699 >>> # initialize a csr_tensor with indptr, indices, values and shape 700 >>> indptr = Tensor([0, 1, 2], dtype=ms.int32) 701 >>> indices = Tensor([0, 1], dtype=ms.int32) 702 >>> values = Tensor([1, 2], dtype=ms.float32) 703 >>> shape = (2, 4) 704 >>> csr_tensor = CSRTensor(indptr, indices, values, shape) 705 >>> # access a data member of CSRTensor 706 >>> print(indptr == csr_tensor.indptr) 707 [ True True True] 708 """ 709 710 def __init__(self, indptr=None, indices=None, values=None, shape=None, csr_tensor=None): 711 "Init CSRTensor" 712 self.init_finished = False 713 # Directly init a CSRTensor from another CSRTensor 714 if csr_tensor is not None: 715 if not isinstance(csr_tensor, (CSRTensor, CSRTensor_)): 716 raise TypeError(f"Expect input `csr_tensor` to be a CSRTensor, but got {type(csr_tensor)}") 717 if not (indptr is None and indices is None and values is None and shape is None): 718 raise TypeError( 719 "If input `csr_tensor` is provided, `indptr`, `indices`, `values`, `shapes` should all be `None`") 720 CSRTensor_.__init__(self, csr_tensor) 721 # Init a CSRTensor from indptr, indices, values and shape 722 else: 723 validator.check_csr_tensor_input(indptr, indices, values, shape) 724 validator.check_csr_tensor_shape(indptr.shape, indices.shape, values.shape, shape) 725 validator.check_csr_tensor_dtype(indptr.dtype, indices.dtype) 726 indptr = tensor_operator_registry.get('stop_gradient')(indptr) 727 indices = tensor_operator_registry.get('stop_gradient')(indices) 728 if is_stub_tensor(indptr): 729 indptr = indptr.stub_sync() 730 if is_stub_tensor(values): 731 values = values.stub_sync() 732 if is_stub_tensor(indices): 733 indices = indices.stub_sync() 734 CSRTensor_.__init__(self, indptr, indices, values, shape) 735 self.init_finished = True 736 737 def __repr__(self): 738 """Avoid PyTest Segfault when CSRTensor is not initialized.""" 739 if self.init_finished: 740 return CSRTensor_.__repr__(self) 741 return '' 742 743 def __mul__(self, other): 744 return tensor_operator_registry.get('csr_mul')(self, other) 745 746 def __div__(self, other): 747 logger.warning("For CSR divide, zero values in the dense tensor are ignored.") 748 return tensor_operator_registry.get('csr_div')(self, other) 749 750 def __truediv__(self, other): 751 return self.__div__(other) 752 753 def __neg__(self): 754 return CSRTensor(self.indptr, self.indices, -self.values, self.shape) 755 756 def __add__(self, other): 757 if not self.shape == other.shape: 758 raise ValueError("Input tensors should have the same shape.") 759 if isinstance(other, CSRTensor): 760 return tensor_operator_registry.get('csr_add')( 761 self, other, Tensor(1, self.values.dtype), Tensor(1, self.values.dtype)) 762 raise TypeError("CSRTensor add with %s is not supported." % type(other)) 763 764 def __sub__(self, other): 765 if not self.shape == other.shape: 766 raise ValueError("Input tensors should have the same shape.") 767 if isinstance(other, CSRTensor): 768 return tensor_operator_registry.get('csr_add')( 769 self, other, Tensor(1, self.values.dtype), Tensor(-1, self.values.dtype)) 770 raise TypeError("CSRTensor subtract with %s is not supported." % type(other)) 771 772 @property 773 def indptr(self) -> Tensor: 774 """Return CSRTensor's row indices pointers.""" 775 return Tensor(self._indptr) 776 777 @property 778 def indices(self) -> Tensor: 779 """ 780 Return CSRTensor's column indices. 781 782 Examples: 783 >>> import mindspore as ms 784 >>> from mindspore import Tensor, CSRTensor 785 >>> indptr = Tensor([0, 1, 2], dtype=ms.int32) 786 >>> indices = Tensor([0, 1], dtype=ms.int32) 787 >>> values = Tensor([1, 2], dtype=ms.float32) 788 >>> shape = (2, 4) 789 >>> csr_tensor = CSRTensor(indptr, indices, values, shape) 790 >>> print(csr_tensor.indices) 791 [0 1] 792 """ 793 return Tensor(self._indices) 794 795 @property 796 def values(self) -> Tensor: 797 """ 798 Return CSRTensor's non-zero values. 799 800 Examples: 801 >>> import mindspore as ms 802 >>> from mindspore import Tensor, CSRTensor 803 >>> indptr = Tensor([0, 1, 2], dtype=ms.int32) 804 >>> indices = Tensor([0, 1], dtype=ms.int32) 805 >>> values = Tensor([1, 2], dtype=ms.float32) 806 >>> shape = (2, 4) 807 >>> csr_tensor = CSRTensor(indptr, indices, values, shape) 808 >>> print(csr_tensor.values) 809 [1. 2.] 810 """ 811 return Tensor(self._values) 812 813 @property 814 def shape(self) -> Tuple[int, ...]: 815 """ 816 Return CSRTensor's shape. 817 818 Examples: 819 >>> import mindspore as ms 820 >>> from mindspore import Tensor, CSRTensor 821 >>> indptr = Tensor([0, 1, 2], dtype=ms.int32) 822 >>> indices = Tensor([0, 1], dtype=ms.int32) 823 >>> values = Tensor([1, 2], dtype=ms.float32) 824 >>> shape = (2, 4) 825 >>> csr_tensor = CSRTensor(indptr, indices, values, shape) 826 >>> print(csr_tensor.shape) 827 (2, 4) 828 """ 829 return self._shape 830 831 @property 832 def dtype(self) -> mstype: 833 """ 834 Return the dtype of the values of CSRTensor (:class:`mindspore.dtype`). 835 836 Examples: 837 >>> import mindspore as ms 838 >>> from mindspore import Tensor, CSRTensor 839 >>> indptr = Tensor([0, 1, 2], dtype=ms.int32) 840 >>> indices = Tensor([0, 1], dtype=ms.int32) 841 >>> values = Tensor([1, 2], dtype=ms.float32) 842 >>> shape = (2, 4) 843 >>> csr_tensor = CSRTensor(indptr, indices, values, shape) 844 >>> print(csr_tensor.dtype) 845 Float32 846 """ 847 return self._dtype 848 849 @property 850 def size(self) -> int: 851 """ 852 Return the number of non-zero values. 853 854 Examples: 855 >>> import mindspore as ms 856 >>> from mindspore import Tensor, CSRTensor 857 >>> indptr = Tensor([0, 1, 2], dtype=ms.int32) 858 >>> indices = Tensor([0, 1], dtype=ms.int32) 859 >>> values = Tensor([1, 2], dtype=ms.float32) 860 >>> shape = (2, 4) 861 >>> csr_tensor = CSRTensor(indptr, indices, values, shape) 862 >>> print(csr_tensor.size) 863 2 864 """ 865 return self.values.size 866 867 @property 868 def itemsize(self) -> int: 869 """ 870 Return the length of one tensor element in bytes. 871 872 Examples: 873 >>> import mindspore as ms 874 >>> from mindspore import Tensor, CSRTensor 875 >>> indptr = Tensor([0, 1, 2], dtype=ms.int32) 876 >>> indices = Tensor([0, 1], dtype=ms.int32) 877 >>> values = Tensor([1, 2], dtype=ms.float64) 878 >>> shape = (2, 4) 879 >>> csr_tensor = CSRTensor(indptr, indices, values, shape) 880 >>> print(csr_tensor.itemsize) 881 8 882 """ 883 return self.values.itemsize 884 885 @property 886 def ndim(self) -> int: 887 """ 888 Return the number of tensor dimensions. 889 890 Examples: 891 >>> import mindspore as ms 892 >>> from mindspore import Tensor, CSRTensor 893 >>> indptr = Tensor([0, 1, 2], dtype=ms.int32) 894 >>> indices = Tensor([0, 1], dtype=ms.int32) 895 >>> values = Tensor([1, 2], dtype=ms.float32) 896 >>> shape = (2, 4) 897 >>> csr_tensor = CSRTensor(indptr, indices, values, shape) 898 >>> print(csr_tensor.ndim) 899 2 900 """ 901 return len(self.shape) 902 903 def to_tuple(self) -> Tuple[Tensor, Tensor, Tensor, Tuple[int, ...]]: 904 """ 905 Return indptr, indices, values and shape as a tuple. 906 907 Returns: 908 Tuple. 909 910 Supported Platforms: 911 ``Ascend`` ``GPU`` ``CPU`` 912 913 Examples: 914 >>> import mindspore as ms 915 >>> from mindspore import Tensor, CSRTensor 916 >>> indptr = Tensor([0, 1, 2], dtype=ms.int32) 917 >>> indices = Tensor([0, 1], dtype=ms.int32) 918 >>> values = Tensor([1, 2], dtype=ms.float32) 919 >>> shape = (2, 4) 920 >>> csr_tensor = CSRTensor(indptr, indices, values, shape) 921 >>> print(csr_tensor.to_tuple()) 922 (Tensor(shape=[3], dtype=Int32, value= [0, 1, 2]), Tensor(shape=[2], dtype=Int32, value= [0, 1]), 923 Tensor(shape=[2], dtype=Float32, value= [ 1.00000000e+00, 2.00000000e+00]), (2, 4)) 924 925 """ 926 return self.indptr, self.indices, self.values, self.shape 927 928 def to_coo(self) -> COOTensor: 929 """ 930 Converts CSRTensor to COOTensor. 931 932 Note: 933 Currently only supports CPU backend with LLVM 12.0.1 installed. 934 935 Returns: 936 COOTensor. 937 938 Supported Platforms: 939 ``GPU`` ``CPU`` 940 941 Examples: 942 >>> import mindspore as ms 943 >>> from mindspore import Tensor, CSRTensor 944 >>> indptr = Tensor([0, 1, 2], dtype=ms.int32) 945 >>> indices = Tensor([0, 1], dtype=ms.int32) 946 >>> values = Tensor([1, 2], dtype=ms.int32) 947 >>> shape = (2, 4) 948 >>> csr_tensor = CSRTensor(indptr, indices, values, shape) 949 >>> print(csr_tensor.to_coo()) 950 COOTensor(shape=[2, 4], dtype=Int32, indices=Tensor(shape=[2, 2], dtype=Int32, value= 951 [[0 0] 952 [1 1]]), values=Tensor(shape=[2], dtype=Int32, value=[1 2])) 953 """ 954 if self.ndim != 2: 955 raise ValueError("Currently only support 2-D CSRTensor when converting to COOTensor.") 956 row_indices = tensor_operator_registry.get("csr2coo")(self.indptr, self.values.shape[0]) 957 coo_indices = tensor_operator_registry.get("stack")((row_indices, self.indices), 1) 958 return COOTensor(coo_indices, self.values, self.shape) 959 960 def to_dense(self) -> Tensor: 961 """ 962 Converts CSRTensor to Dense Tensor. 963 964 Returns: 965 Tensor. 966 967 Supported Platforms: 968 ``GPU`` 969 970 Examples: 971 >>> import mindspore as ms 972 >>> from mindspore import Tensor, CSRTensor 973 >>> indptr = Tensor([0, 1, 2], dtype=ms.int32) 974 >>> indices = Tensor([0, 1], dtype=ms.int32) 975 >>> values = Tensor([1, 2], dtype=ms.float32) 976 >>> shape = (2, 4) 977 >>> csr_tensor = CSRTensor(indptr, indices, values, shape) 978 >>> print(csr_tensor.to_dense()) 979 [[1. 0. 0. 0.] 980 [0. 2. 0. 0.]] 981 """ 982 return tensor_operator_registry.get("csr_to_dense")(self) 983 984 def astype(self, dtype: mstype) -> CSRTensor: 985 """ 986 Return a copy of the CSRTensor, cast its values to a specified type. 987 988 Args: 989 dtype (Union[:class:`mindspore.dtype`, numpy.dtype, str]): Designated tensor dtype. 990 991 Returns: 992 CSRTensor. 993 994 Supported Platforms: 995 ``Ascend`` ``GPU`` ``CPU`` 996 997 Examples: 998 >>> import mindspore as ms 999 >>> from mindspore import Tensor, CSRTensor 1000 >>> indptr = Tensor([0, 1, 2], dtype=ms.int32) 1001 >>> indices = Tensor([0, 1], dtype=ms.int32) 1002 >>> values = Tensor([1, 2], dtype=ms.float32) 1003 >>> shape = (2, 4) 1004 >>> csr_tensor = CSRTensor(indptr, indices, values, shape) 1005 >>> print(csr_tensor.astype(ms.float64).dtype) 1006 Float64 1007 """ 1008 data = self.values.astype(dtype) 1009 return CSRTensor(self.indptr, self.indices, data, self.shape) 1010 1011 def mv(self, dense_vector: Tensor) -> Tensor: 1012 """ 1013 Return the matrix multiplication result of the right-multiply dense matrix of the CSRTensor. 1014 The CSRTensor with shape `[M, N]` needs to adapt the dense vector with shape `[N, 1]` 1015 to get the dense vector with result `[M, 1]`. 1016 1017 Note: 1018 Currently only supports CPU backend with LLVM 12.0.1 installed. 1019 1020 Args: 1021 dense_vector (Tensor): A dense Tensor, its shape must be (csr_tensor.shape[1], 1) 1022 1023 Returns: 1024 Tensor. 1025 1026 Supported Platforms: 1027 ``GPU`` ``CPU`` 1028 1029 Examples: 1030 >>> from mindspore import Tensor, CSRTensor 1031 >>> from mindspore import dtype as mstype 1032 >>> indptr = Tensor([0, 1, 2], dtype=mstype.int32) 1033 >>> indices = Tensor([0, 1], dtype=mstype.int32) 1034 >>> values = Tensor([2, 1], dtype=mstype.float32) 1035 >>> dense_shape = (2, 4) 1036 >>> csr_tensor = CSRTensor(indptr, indices, values, dense_shape) 1037 >>> dense = Tensor([[1], [1], [1], [1]], dtype=mstype.float32) 1038 >>> print(csr_tensor.mv(dense)) 1039 [[2.] 1040 [1.]] 1041 """ 1042 validator.check_value_type('dense_vector', dense_vector, (Tensor, Tensor_,), 'CSRTensor.mv') 1043 return tensor_operator_registry.get("csr_mv")(self, dense_vector) 1044 1045 def mm(self, matrix: Union[Tensor, CSRTensor]) -> Union[Tensor, CSRTensor]: 1046 """ 1047 Return the matrix multiplication result of the right-multiply matrix(dense or CSRTensor) of the CSRTensor. 1048 The CSRTensor with shape `[M, N]` needs to adapt the right matrix with shape `[N, K]` 1049 to get the dense matrix or CSRTensor with result `[M, K]`. 1050 1051 Note: 1052 If right matrix is CSRTensor, currently only supports GPU backend. 1053 If right matrix is Tensor, currently supports CPU backend with LLVM no lower than 12.0.1, and GPU backend. 1054 1055 Args: 1056 matrix (Tensor or CSRTensor): A dense Tensor or CSRTensor, 1057 its shape[0] should be equal to csr_tensor.shape[1] 1058 1059 Returns: 1060 Tensor or CSRTensor. 1061 1062 Supported Platforms: 1063 ``GPU`` ``CPU`` 1064 1065 Examples: 1066 >>> from mindspore import Tensor, CSRTensor 1067 >>> from mindspore import dtype as mstype 1068 >>> indptr = Tensor([0, 1, 2], dtype=mstype.int32) 1069 >>> indices = Tensor([0, 1], dtype=mstype.int32) 1070 >>> values = Tensor([2, 1], dtype=mstype.float32) 1071 >>> dense_shape = (2, 4) 1072 >>> csr_tensor = CSRTensor(indptr, indices, values, dense_shape) 1073 >>> dense_matrix = Tensor([[1., 2.], [1, 2.], [1, 2.], [1., 2.]], dtype=mstype.float32) 1074 >>> print(csr_tensor.mm(dense_matrix)) 1075 [[2. 4.] 1076 [1. 2.]] 1077 """ 1078 if isinstance(matrix, CSRTensor): 1079 return tensor_operator_registry.get("csr_mm")(self, matrix) 1080 validator.check_value_type('matrix', matrix, (Tensor, Tensor_,), 'CSRTensor.mm') 1081 return tensor_operator_registry.get("csr_mm_akg")()(self.indptr, self.indices, self.values, 1082 self.shape, matrix) 1083 1084 def sum(self, axis: int) -> Tensor: 1085 """ 1086 Reduces a dimension of a CSRTensor by summing all elements in the dimension. 1087 1088 Note: 1089 Currently only supports CPU backend with LLVM 12.0.1 installed. 1090 1091 Args: 1092 axis (int): The dimensions to reduce. 1093 1094 Returns: 1095 Tensor, the dtype is the same as `CSRTensor.values`. 1096 1097 Supported Platforms: 1098 ``GPU`` ``CPU`` 1099 1100 Examples: 1101 >>> from mindspore import Tensor, CSRTensor 1102 >>> from mindspore import dtype as mstype 1103 >>> indptr = Tensor([0, 1, 2], dtype=mstype.int32) 1104 >>> indices = Tensor([0, 1], dtype=mstype.int32) 1105 >>> values = Tensor([2, 1], dtype=mstype.float32) 1106 >>> dense_shape = (2, 4) 1107 >>> csr_tensor = CSRTensor(indptr, indices, values, dense_shape) 1108 >>> print(csr_tensor.sum(1)) 1109 [[2.] 1110 [1.]] 1111 """ 1112 return tensor_operator_registry.get("csr_reduce_sum")(self, axis) 1113 1114 def abs(self) -> CSRTensor: 1115 """ 1116 Return absolute value element-wisely. 1117 1118 Returns: 1119 CSRTensor, with all values being non-negative. 1120 1121 Supported Platforms: 1122 ``Ascend`` ``GPU`` ``CPU`` 1123 1124 Examples: 1125 >>> import mindspore as ms 1126 >>> from mindspore import Tensor, CSRTensor 1127 >>> indptr = Tensor([0, 1, 2], dtype=ms.int32) 1128 >>> indices = Tensor([0, 1], dtype=ms.int32) 1129 >>> values = Tensor([-1, -2], dtype=ms.float32) 1130 >>> shape = (2, 4) 1131 >>> csr_tensor = CSRTensor(indptr, indices, values, shape) 1132 >>> print(csr_tensor.abs().values) 1133 [1. 2.] 1134 """ 1135 data = self.values.abs() 1136 return CSRTensor(self.indptr, self.indices, data, self.shape) 1137 1138 def add(self, b: CSRTensor, alpha: Tensor, beta: Tensor) -> CSRTensor: 1139 """ 1140 Addition of two CSR Tensors : C = alpha * A + beta * B 1141 1142 Args: 1143 b (CSRTensor): Sparse CSR Tensor. 1144 alpha(Tensor): Dense Tensor, its shape must be able to broadcast to self. 1145 beta(Tensor): Dense Tensor, its shape must be able to broadcast to b. 1146 1147 Returns: 1148 CSRTensor. 1149 1150 Supported Platforms: 1151 ``GPU`` ``CPU`` 1152 1153 Examples: 1154 >>> from mindspore import Tensor, CSRTensor 1155 >>> import mindspore.common.dtype as mstype 1156 >>> indptr = Tensor([0, 1, 2], dtype=mstype.int32) 1157 >>> indices = Tensor([0, 1], dtype=mstype.int32) 1158 >>> values_a = Tensor([2, 1], dtype=mstype.float32) 1159 >>> values_b = Tensor([1, 2], dtype=mstype.float32) 1160 >>> dense_shape = (2, 4) 1161 >>> alpha = Tensor(1, mstype.float32) 1162 >>> beta = Tensor(1, mstype.float32) 1163 >>> a = CSRTensor(indptr, indices, values_a, dense_shape) 1164 >>> b = CSRTensor(indptr, indices, values_b, dense_shape) 1165 >>> print(a.add(b, alpha, beta)) 1166 CSRTensor(shape=[2, 4], dtype=Float32, 1167 indptr=Tensor(shape=[3], dtype=Int32, value=[0 1 2]), 1168 indices=Tensor(shape=[2], dtype=Int32, value=[0 1]), 1169 values=Tensor(shape=[2], dtype=Float32, value=[ 3.00000000e+00 3.00000000e+00])) 1170 """ 1171 return tensor_operator_registry.get('csr_add')(self, b, alpha, beta) 1172