Source code for sionna.phy.block

#
# SPDX-FileCopyrightText: Copyright (c) 2021-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
"""Definition of Sionna Block"""

from typing import Any, Optional
from .object import Object
from .config import Precision
import torch

__all__ = ["Block"]


[docs] class Block(Object): """Abstract class for Sionna PHY processing blocks. All Sionna PHY processing blocks inherit from this class. It provides automatic input casting to the block's precision, lazy building based on input shapes, and compatibility with ``torch.compile``. :param precision: Precision used for internal calculations and outputs. `None` (default) | ``"single"`` | ``"double"``. If `None`, :attr:`~sionna.phy.config.Config.precision` is used. Defaults to `None`. :param device: Device for computation (e.g., ``'cpu'``, ``'cuda:0'``). If `None`, :attr:`~sionna.phy.config.Config.device` is used. Defaults to `None`. """ def __init__( self, *args: Any, precision: Optional[Precision] = None, device: Optional[str] = None, **kwargs: Any, ) -> None: super().__init__(precision=precision, device=device) self._built = False @property def built(self) -> bool: """Indicates if the block's build function was called.""" return self._built
[docs] def build(self, *arg_shapes, **kwarg_shapes): r"""Initialize the block based on the inputs' shapes. Subclasses can override this method to create tensors or sub-blocks whose sizes depend on the input shapes. :param \*arg_shapes: Shapes of the positional arguments. Can be tuples (for tensors) or nested structures thereof (for lists/dicts of tensors). :param \*\*kwarg_shapes: Shapes of the keyword arguments. Can be tuples (for tensors) or nested structures thereof (for lists/dicts of tensors). """
def __call__(self, *args: Any, **kwargs: Any) -> Any: """Call the block, with setup code skipped during ``torch.compile`` tracing. When using ``torch.compile``, Dynamo traces this method and creates guards on state like ``_built``. To avoid recompilation when ``_built`` changes from `False` to `True` after the first call, the setup code (input conversion and lazy build) is skipped when being traced. This is detected using ``torch.compiler.is_compiling()``. The setup code runs in eager mode (when ``is_compiling()`` is `False`), ensuring inputs are properly converted and blocks are built before the compiled ``forward()`` executes. """ # Skip setup during Dynamo tracing to avoid guards on _built # Setup runs in eager mode on actual execution if not torch.compiler.is_compiling(): args = self._convert(args) kwargs = self._convert(kwargs) if not self._built: arg_shapes = self._get_shape(args) kwarg_shapes = self._get_shape(kwargs) self.build(*arg_shapes, **kwarg_shapes) self._built = True return super().__call__(*args, **kwargs)
[docs] def forward(self, *args: Any, **kwargs: Any) -> Any: """Delegates to :meth:`call`.""" return self.call(*args, **kwargs)
[docs] def call(self, *args: Any, **kwargs: Any) -> Any: """Process inputs. Must be implemented by subclasses.""" raise NotImplementedError("Subclasses must implement 'call'.")