diff --git a/docs/articles_en/documentation/openvino-ir-format/operation-sets/operation-specs/movement/scatter-nd-update-15.rst b/docs/articles_en/documentation/openvino-ir-format/operation-sets/operation-specs/movement/scatter-nd-update-15.rst new file mode 100644 index 00000000000000..283779d6368caa --- /dev/null +++ b/docs/articles_en/documentation/openvino-ir-format/operation-sets/operation-specs/movement/scatter-nd-update-15.rst @@ -0,0 +1,230 @@ +.. {#openvino_docs_ops_movement_ScatterNDUpdate_15} + +ScatterNDUpdate +=============== + + +.. meta:: + :description: Learn about ScatterNDUpdate-15 - a data movement operation, which can be + performed on three required input tensors. + +**Versioned name**: *ScatterNDUpdate-15* + +**Category**: *Data movement* + +**Short description**: Creates a copy of the ``data`` input tensor with updates for elements specified by ``indices`` by elements from ``updates`` according to *reduction* attribute. + +**Detailed description**: The operation produces a copy of ``data`` tensor and updates its value using logic from ``reduction`` attribute, using values specified +by ``updates`` at specific index positions specified by ``indices``. The output shape is the same as the shape of ``data``. +Input ``indices`` can contain duplicated index values, however, in case when *reduction* is set to ``none``, only last update for given duplicated index is used. + +The last dimension of ``indices`` corresponds to indices into elements if ``indices.shape[-1]`` = ``data.shape.rank`` or slices +if ``indices.shape[-1]`` < ``data.shape.rank``. +Input ``updates`` is a tensor with shape ``indices.shape[:-1] + data.shape[indices.shape[-1]:]``. + +The operation to perform between the corresponding elements is specified by reduction attribute, by default the elements of data tensor are simply overwritten by the values from updates input. + +Operator ScatterNDUpdate-15 is an equivalent to following NumPy snippet: + +.. code-block:: py + + def scatter_nd_update_15(data, indices, updates, reduction=None): + func = lambda x, y: y + if reduction == "sum": + func = lambda x, y: x + y + elif reduction == "sub": + func = lambda x, y: x - y + elif reduction == "prod": + func = lambda x, y: x * y + elif reduction == "max": + func = max + elif reduction == "min": + func = min + out = np.copy(data) + for ndidx in np.ndindex(indices.shape[:-1]): + out[indices[ndidx]] = func(out[indices[ndidx]], updates[ndidx]) + return out + +Example 1 that shows simple case of update with *reduction* set to ``none``.: + +.. code-block:: cpp + + data = [1, 2, 3, 4, 5, 6, 7, 8] + indices = [[4], [3], [1], [7], [-2], [-4]] + updates = [9, 10, 11, 12, 13, 14] + output = [1, 11, 3, 10, 14, 6, 13, 12] + + +Example that shows update of two slices of ``4x4`` shape in ``data``, with *reduction* set to ``none``: + +.. code-block:: cpp + + data = [[[1, 2, 3, 4], [5, 6, 7, 8], [8, 7, 6, 5], [4, 3, 2, 1]], + [[1, 2, 3, 4], [5, 6, 7, 8], [8, 7, 6, 5], [4, 3, 2, 1]], + [[8, 7, 6, 5], [4, 3, 2, 1], [1, 2, 3, 4], [5, 6, 7, 8]], + [[8, 7, 6, 5], [4, 3, 2, 1], [1, 2, 3, 4], [5, 6, 7, 8]]] + indices = [[0], [2]] + updates = [[[5, 5, 5, 5], [6, 6, 6, 6], [7, 7, 7, 7], [8, 8, 8, 8]], + [[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3], [4, 4, 4, 4]]] + output = [[[5, 5, 5, 5], [6, 6, 6, 6], [7, 7, 7, 7], [8, 8, 8, 8]], + [[1, 2, 3, 4], [5, 6, 7, 8], [8, 7, 6, 5], [4, 3, 2, 1]], + [[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3], [4, 4, 4, 4]], + [[8, 7, 6, 5], [4, 3, 2, 1], [1, 2, 3, 4], [5, 6, 7, 8]]] + + + +**Attributes**: + +* *reduction* + + * **Description**: The type of operation to perform on the inputs. + * **Range of values**: one of ``none``, ``sum``, ``sub``, ``prod``, ``min``, ``max`` + * **Type**: `string` + * **Default value**: ``none`` + * **Required**: *no* + +**Inputs**: + +* **1**: ``data`` tensor of arbitrary rank ``r`` >= 1 and of type *T*. **Required.** + +* **2**: ``indices`` tensor with indices of arbitrary rank ``q`` >= 1 and of type *T_IND*. All index values ``i_j`` in index entry ``(i_0, i_1, ...,i_k)`` (where ``k = indices.shape[-1]``) must be within bounds ``[-s_j, s_j - 1]`` where ``s_j = data.shape[j]``. ``k`` must be at most ``r``. If multiple indices point to the same output location then values will be updated in order of their occurrence. Negative value of index means reverse indexing and will be normalized to value ``len(data.shape[j] + index)``. If an index points to non-existing element then exception is raised. **Required.** + +* **3**: ``updates`` tensor of rank ``r - indices.shape[-1] + q - 1`` of type *T*. If expected ``updates`` rank is 0D it can be a tensor with single element. **Required.** + +**Outputs**: + +* **1**: tensor with shape equal to ``data`` tensor of the type *T*. + +**Types** + +* *T*: any numeric type. For boolean type, reduction sum, sub, prod behaves like logical OR, XOR, AND accordingly. + +* *T_IND*: ``int32`` or ``int64`` + +**Example** + +*Example 1* + +.. code-block:: xml + + + + + 4 + + + 5 + + + 5 + + + + + 4 + + + + +*Example 2* + +.. code-block:: xml + + + + + 4 + + + 5 + + + 5 + + + + + 4 + + + + +*Example 3* + +.. code-block:: xml + + + + + 4 + + + 5 + + + 5 + + + + + 4 + + + + +*Example 4* + +.. code-block:: xml + + + + + 4 + + + 5 + + + 5 + + + + + 4 + + + + +*Example 5* + +.. code-block:: xml + :force: + + + + + 1000 + 256 + 10 + 15 + + + 25 + 125 + 3 + + + 25 + 125 + 15 + + + + + 1000 + 256 + 10 + 15 + + +