Coverage for / home / jenkins / .local / lib / python3.10 / site-packages / hyper_parallel / core / shard / ops / parallel_chunk_view.py: 82%
51 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 ChunkView operator.
17"""
19from typing import Tuple
21from .parallel_ops import DistributedOp
24def _normalize_chunk_view_args(input_tensor, chunks, dim=0):
25 return (input_tensor, chunks, dim), {}
28class ChunkViewDistributedOp(DistributedOp):
29 """Distributed implementation for ChunkView operator."""
31 @staticmethod
32 def _calculate_output_count(dim_size, chunks):
33 """Calculate the number of output chunks based on dimension size."""
34 if dim_size == 0:
35 return chunks
36 split_size = (dim_size + chunks - 1) // chunks
37 output_num = max((dim_size + split_size - 1) // split_size, 1)
38 return min(output_num, chunks)
40 def preprocess(self, args: tuple, kwargs: dict) -> tuple:
41 """
42 Preprocess arguments for ChunkView operator.
44 Args:
45 args (tuple): Input arguments containing the input tensor, chunks, and dim.
46 kwargs (dict): Keyword arguments (none expected).
48 Returns:
49 tuple: (local_args, local_kwargs, cache_values)
50 """
51 args, kwargs = _normalize_chunk_view_args(*args, **kwargs)
52 input_tensor, chunks, dim = args
53 input_shape = input_tensor.shape
55 local_args = (input_tensor.to_local(), chunks, dim)
56 local_kwargs = {}
58 cache_values = [input_tensor.layout, chunks, dim, input_shape]
59 return local_args, local_kwargs, cache_values
61 def infer_layout(self, cache_values: list) -> Tuple[tuple, None]:
62 """
63 Infer output layouts for ChunkView operator.
65 Rules:
66 1. Input must not have Partial status.
67 2. Split dimension cannot be sharded (including StridedShard multi-axis mappings).
68 3. dim must be an integer within the valid range [-ndim, ndim-1].
69 4. Default: dim = 0 if not specified.
70 5. Output count may be less than chunks if dimension size < chunks.
71 6. All output layouts are identical to the input layout.
73 Args:
74 cache_values (list): [input_layout, chunks, dim, input_shape]
76 Returns:
77 tuple: ((output_layout_1, output_layout_2, ...), None)
79 Raises:
80 ValueError: If any rule above is violated.
81 TypeError: If chunks or dim is not an integer.
82 """
83 input_layout = cache_values[0]
84 chunks = cache_values[1]
85 dim = cache_values[2]
86 input_shape = cache_values[3]
88 if input_layout is None:
89 raise ValueError(
90 f"For {self.op_name}, input layout should not be None"
91 )
93 if not self._allow_partial_inputs:
94 self._check_partial_inputs([input_layout])
96 if not isinstance(chunks, int):
97 raise TypeError(
98 f"For {self.op_name}, chunks must be an integer, but got {type(chunks)}"
99 )
100 if chunks < 1:
101 raise ValueError(
102 f"For {self.op_name}, chunks must be greater than 0, but got {chunks}"
103 )
104 if not isinstance(dim, int):
105 raise TypeError(
106 f"For {self.op_name}, dim must be an integer, but got {type(dim)}"
107 )
109 alias_map = input_layout.alias_tensor_map
110 ndim = len(alias_map)
112 original_dim = dim
113 if dim < 0:
114 dim = ndim + dim
116 if not 0 <= dim < ndim:
117 raise ValueError(
118 f"For {self.op_name}, dimension out of range "
119 f"(expected to be in range of [{-ndim}, {ndim - 1}], but got {original_dim})"
120 )
122 mapping = alias_map[dim]
123 if isinstance(mapping, (list, tuple)):
124 is_sharded = any(m != "None" for m in mapping)
125 else:
126 is_sharded = mapping != "None"
128 if is_sharded:
129 raise ValueError(
130 f"For {self.op_name}, cannot split tensor at sharded axis[{dim}], "
131 f"layout: {input_layout}"
132 )
134 output_num = self._calculate_output_count(input_shape[dim], chunks)
136 output_layouts = (input_layout,) * output_num
137 return (output_layouts, None)