Coverage for / home / jenkins / .local / lib / python3.10 / site-packages / hyper_parallel / core / shard / ops / parallel_nonzero.py: 97%
39 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-07-06 05:41 +0800
« prev ^ index » next coverage.py v7.13.1, created at 2026-07-06 05:41 +0800
1# Copyright 2026 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"""
16Distributed implementation for Nonzero operator.
17"""
19from typing import Tuple
21from hyper_parallel.core.dtensor.layout import Layout
22from .parallel_ops import DistributedOp
25def _normalize_nonzero_args(x, as_tuple=False):
26 return (x,), {'as_tuple': as_tuple}
29class NonzeroDistributedOp(DistributedOp):
30 """Distributed implementation for torch.nonzero."""
32 def preprocess(self, args: tuple, kwargs: dict) -> tuple:
33 """
34 Preprocess arguments for Nonzero operator.
36 Args:
37 args (tuple): Input arguments, first element is the input tensor.
38 kwargs (dict): Keyword arguments (as_tuple).
40 Returns:
41 tuple: (local_args, local_kwargs, cache_values)
42 """
43 args, kwargs = _normalize_nonzero_args(*args, **kwargs)
44 input_tensor = args[0]
45 as_tuple = kwargs['as_tuple']
47 local_args = (input_tensor.to_local(),)
48 local_kwargs = {'as_tuple': as_tuple}
50 cache_values = [input_tensor.layout, as_tuple]
51 return local_args, local_kwargs, cache_values
53 def infer_layout(self, cache_values: list) -> Tuple[tuple, None]:
54 """
55 Infer output layouts for Nonzero operator.
57 Rules:
58 1. Input must not have Partial status.
59 2. Input must be fully replicated (all dimensions mapped to "None").
60 nonzero produces data-dependent output shapes, which would differ
61 across sharded ranks.
62 3. If as_tuple=True: returns a tuple of 1D replicated layouts, one per
63 input dimension.
64 4. If as_tuple=False: returns a single 2D replicated layout.
66 Args:
67 cache_values (list): [input_layout, as_tuple]
69 Returns:
70 tuple: ((output_layout(s),), None)
72 Raises:
73 ValueError: If input has Partial status or is sharded.
74 """
75 input_layout = cache_values[0]
76 as_tuple = cache_values[1]
78 if input_layout is None:
79 raise ValueError(
80 f"For {self.op_name}, input_layout should be a valid Layout, but got None."
81 )
83 # Rule 1: Input must not have Partial status
84 if not self._allow_partial_inputs:
85 self._check_partial_inputs([input_layout])
87 if not isinstance(as_tuple, bool):
88 raise ValueError(
89 f"For {self.op_name}, as_tuple should be bool, but got {type(as_tuple)}."
90 )
92 alias_map = input_layout.alias_tensor_map
93 input_ndim = len(alias_map)
95 # Rule 2: Input must be fully replicated due to data-dependent dynamic shapes
96 for dim, dim_sharding in enumerate(alias_map):
97 if dim_sharding != "None":
98 raise ValueError(
99 f"For {self.op_name}, input tensor should be fully replicated, "
100 f"but got dim {dim} mapped to {dim_sharding}. "
101 f"nonzero produces dynamic shapes that depend on data values, "
102 f"which causes shape mismatches across ranks if the tensor is sharded."
103 )
105 mesh_shape = input_layout.mesh_shape
106 alias_name = input_layout.alias_name
107 rank_list = input_layout.rank_list
109 def _create_replicated_layout(ndim):
110 """Helper to create a fully replicated layout for a given dimension."""
111 layout = Layout(
112 mesh_shape=mesh_shape,
113 alias_name=alias_name,
114 rank_list=rank_list
115 )
116 alias_map = tuple("None" for _ in range(ndim))
117 return layout(*alias_map)
119 # Rule 3 & 4: Construct the return layout based on as_tuple flag
120 if as_tuple:
121 out_layout = _create_replicated_layout(1)
122 return (tuple(out_layout for _ in range(input_ndim)), None)
124 return ((_create_replicated_layout(2),), None)