From 06e6c4763db4fcb0a288217a582469ee8a105b26 Mon Sep 17 00:00:00 2001 From: giovanni Date: Wed, 12 Mar 2025 15:27:06 +0100 Subject: [PATCH] fix doc domain --- pina/domain/__init__.py | 4 +- pina/domain/cartesian.py | 55 +++++------ pina/domain/difference_domain.py | 65 ++++++------- pina/domain/domain_interface.py | 29 +++--- pina/domain/ellipsoid.py | 144 ++++++++++++++--------------- pina/domain/exclusion_domain.py | 62 ++++++------- pina/domain/intersection_domain.py | 62 ++++++------- pina/domain/operation_interface.py | 47 ++++++---- pina/domain/simplex.py | 119 ++++++++++++------------ pina/domain/union_domain.py | 67 +++++++------- 10 files changed, 329 insertions(+), 325 deletions(-) diff --git a/pina/domain/__init__.py b/pina/domain/__init__.py index 45aade7..fd32be6 100644 --- a/pina/domain/__init__.py +++ b/pina/domain/__init__.py @@ -1,6 +1,4 @@ -""" -This module contains the domain classes. -""" +"""Modules to create and handle domains.""" __all__ = [ "DomainInterface", diff --git a/pina/domain/cartesian.py b/pina/domain/cartesian.py index 82fccd0..9870a66 100644 --- a/pina/domain/cartesian.py +++ b/pina/domain/cartesian.py @@ -1,4 +1,4 @@ -"""Module for CartesianDomain class.""" +"""Module for the Cartesian Domain.""" import torch @@ -14,12 +14,12 @@ class CartesianDomain(DomainInterface): def __init__(self, cartesian_dict): """ - Initialize the :class:`~pina.domain.CartesianDomain` class. + Initialization of the :class:`CartesianDomain` class. - :param dict cartesian_dict: A dictionary where the keys are the - variable names and the values are the domain extrema. The domain - extrema can be either a list with two elements or a single number. - If the domain extrema is a single number, the variable is fixed to + :param dict cartesian_dict: A dictionary where the keys are the + variable names and the values are the domain extrema. The domain + extrema can be either a list with two elements or a single number. + If the domain extrema is a single number, the variable is fixed to that value. :Example: @@ -58,11 +58,10 @@ class CartesianDomain(DomainInterface): def update(self, new_domain): """ - Add new dimensions to an existing :class:`~pina.domain.CartesianDomain` - object. + Add new dimensions to an existing :class:`CartesianDomain` object. - :param :class:`~pina.domain.CartesianDomain` new_domain: New domain to - be added to an existing :class:`~pina.domain.CartesianDomain` object. + :param CartesianDomain new_domain: New domain to be added to an existing + :class:`CartesianDomain` object. :Example: >>> spatial_domain = CartesianDomain({'x': [0, 1], 'y': [0, 1]}) @@ -111,26 +110,25 @@ class CartesianDomain(DomainInterface): :param int n: Number of points to sample, see Note below for reference. :param str mode: Sampling method. Default is ``random``. - Available modes: random sampling, ``random``; - latin hypercube sampling, ``latin`` or ``lh``; + Available modes: random sampling, ``random``; + latin hypercube sampling, ``latin`` or ``lh``; chebyshev sampling, ``chebyshev``; grid sampling ``grid``. - :param variables: variables to be sampled. Default is ``all``. - :type variables: str | list[str] + :param list[str] variables: variables to be sampled. Default is ``all``. :return: Sampled points. :rtype: LabelTensor .. note:: - When multiple variables are involved, the total number of sampled - points may differ from ``n``, depending on the chosen ``mode``. - If ``mode`` is ``grid`` or ``chebyshev``, points are sampled - independently for each variable and then combined, resulting in a - total number of points equal to ``n`` raised to the power of the - number of variables. If 'mode' is 'random', ``lh`` or ``latin``, - all variables are sampled together, and the total number of points + When multiple variables are involved, the total number of sampled + points may differ from ``n``, depending on the chosen ``mode``. + If ``mode`` is ``grid`` or ``chebyshev``, points are sampled + independently for each variable and then combined, resulting in a + total number of points equal to ``n`` raised to the power of the + number of variables. If 'mode' is 'random', ``lh`` or ``latin``, + all variables are sampled together, and the total number of points remains ``n``. .. warning:: - The extrema of CartesianDomain are only sampled when using the + The extrema of CartesianDomain are only sampled when using the ``grid`` mode. :Example: @@ -165,8 +163,7 @@ class CartesianDomain(DomainInterface): :param int n: Number of points to sample. :param str mode: Sampling method. - :param variables: variables to be sampled. - :type variables: str | list[str] + :param list[str] variables: variables to be sampled. :return: Sampled points. :rtype: list[LabelTensor] """ @@ -203,8 +200,7 @@ class CartesianDomain(DomainInterface): :param int n: Number of points to sample. :param str mode: Sampling method. - :param variables: variables to be sampled. - :type variables: str | list[str] + :param list[str] variables: variables to be sampled. :return: Sampled points. :rtype: list[LabelTensor] """ @@ -232,8 +228,7 @@ class CartesianDomain(DomainInterface): Sample a single point in one dimension. :param int n: Number of points to sample. - :param variables: variables to be sampled. - :type variables: str | list[str] + :param list[str] variables: variables to be sampled. :return: Sampled points. :rtype: list[torch.Tensor] """ @@ -273,8 +268,8 @@ class CartesianDomain(DomainInterface): Check if a point is inside the hypercube. :param LabelTensor point: Point to be checked. - :param bool check_border: Determines whether to check if the point lies - on the boundary of the hypercube. Default is ``False``. + :param bool check_border: If ``True``, the border is considered inside + the hypercube. Default is ``False``. :return: ``True`` if the point is inside the domain, ``False`` otherwise. :rtype: bool """ diff --git a/pina/domain/difference_domain.py b/pina/domain/difference_domain.py index fc50563..573d736 100644 --- a/pina/domain/difference_domain.py +++ b/pina/domain/difference_domain.py @@ -1,4 +1,4 @@ -"""Module for Difference class.""" +"""Module for the Difference Operation.""" import torch from .operation_interface import OperationInterface @@ -6,45 +6,46 @@ from ..label_tensor import LabelTensor class Difference(OperationInterface): - """ - PINA implementation of Difference of Domains. + r""" + Implementation of the difference operation between of a list of domains. + + Given two sets :math:`A` and :math:`B`, define the difference of the two + sets as: + + .. math:: + A - B = \{x \mid x \in A \land x \not\in B\}, + + where :math:`x` is a point in :math:`\mathbb{R}^N`. """ def __init__(self, geometries): - r""" - Given two sets :math:`A` and :math:`B` then the - domain difference is defined as: + """ + Initialization of the :class:`Difference` class. - .. math:: - A - B = \{x \mid x \in A \land x \not\in B\}, - - with :math:`x` a point in :math:`\mathbb{R}^N` and :math:`N` - the dimension of the geometry space. - - :param list geometries: A list of geometries from ``pina.geometry`` - such as ``EllipsoidDomain`` or ``CartesianDomain``. The first - geometry in the list is the geometry from which points are - sampled. The rest of the geometries are the geometries that - are excluded from the first geometry to find the difference. + :param list[DomainInterface] geometries: A list of instances of the + :class:`~pina.domain.DomainInterface` class on which the difference + operation is performed. The first domain in the list serves as the + base from which points are sampled, while the remaining domains + define the regions to be excluded from the base domain to compute + the difference. :Example: >>> # Create two ellipsoid domains >>> ellipsoid1 = EllipsoidDomain({'x': [-1, 1], 'y': [-1, 1]}) >>> ellipsoid2 = EllipsoidDomain({'x': [0, 2], 'y': [0, 2]}) - >>> # Create a Difference of the ellipsoid domains + >>> # Define the difference between the domains >>> difference = Difference([ellipsoid1, ellipsoid2]) """ super().__init__(geometries) def is_inside(self, point, check_border=False): """ - Check if a point is inside the ``Difference`` domain. + Check if a point is inside the resulting domain. - :param point: Point to be checked. - :type point: torch.Tensor - :param bool check_border: If ``True``, the border is considered inside. - :return: ``True`` if the point is inside the Exclusion domain, - ``False`` otherwise. + :param LabelTensor point: Point to be checked. + :param bool check_border: If ``True``, the border is considered inside + the domain. Default is ``False``. + :return: ``True`` if the point is inside the domain, ``False`` otherwise. :rtype: bool """ for geometry in self.geometries[1:]: @@ -54,21 +55,21 @@ class Difference(OperationInterface): def sample(self, n, mode="random", variables="all"): """ - Sample routine for ``Difference`` domain. + Sampling routine. - :param int n: Number of points to sample in the shape. - :param str mode: Mode for sampling, defaults to ``random``. Available - modes include: ``random``. - :param variables: Variables to be sampled, defaults to ``all``. - :type variables: str | list[str] - :return: Returns ``LabelTensor`` of n sampled points. + :param int n: Number of points to sample. + :param str mode: Sampling method. Default is ``random``. + Available modes: random sampling, ``random``; + :param list[str] variables: variables to be sampled. Default is ``all``. + :raises NotImplementedError: If the sampling method is not implemented. + :return: Sampled points. :rtype: LabelTensor :Example: >>> # Create two Cartesian domains >>> cartesian1 = CartesianDomain({'x': [0, 2], 'y': [0, 2]}) >>> cartesian2 = CartesianDomain({'x': [1, 3], 'y': [1, 3]}) - >>> # Create a Difference of the ellipsoid domains + >>> # Define the difference between the domains >>> difference = Difference([cartesian1, cartesian2]) >>> # Sampling >>> difference.sample(n=5) diff --git a/pina/domain/domain_interface.py b/pina/domain/domain_interface.py index 2db6fe5..7f693e3 100644 --- a/pina/domain/domain_interface.py +++ b/pina/domain/domain_interface.py @@ -1,12 +1,12 @@ -"""Module for the DomainInterface class.""" +"""Module for the Domain Interface.""" from abc import ABCMeta, abstractmethod class DomainInterface(metaclass=ABCMeta): """ - Abstract Location class. - Any geometry entity should inherit from this class. + Abstract base class for geometric domains. All specific domain types should + inherit from this class. """ available_sampling_modes = ["random", "grid", "lh", "chebyshev", "latin"] @@ -15,20 +15,24 @@ class DomainInterface(metaclass=ABCMeta): @abstractmethod def sample_modes(self): """ - Abstract method returing available samples modes for the Domain. + Abstract method defining sampling methods. """ @property @abstractmethod def variables(self): """ - Abstract method returing Domain variables. + Abstract method returning the domain variables. """ @sample_modes.setter def sample_modes(self, values): """ - TODO + Setter for the sample_modes property. + + :param values: Sampling modes to be set. + :type values: str | list[str] + :raises TypeError: Invalid sampling mode. """ if not isinstance(values, (list, tuple)): values = [values] @@ -43,18 +47,15 @@ class DomainInterface(metaclass=ABCMeta): @abstractmethod def sample(self): """ - Abstract method for sampling a point from the location. To be - implemented in the child class. + Abstract method for the sampling routine. """ @abstractmethod def is_inside(self, point, check_border=False): """ - Abstract method for checking if a point is inside the location. To be - implemented in the child class. + Abstract method for checking if a point is inside the domain. - :param torch.Tensor point: A tensor point to be checked. - :param bool check_border: A boolean that determines whether the border - of the location is considered checked to be considered inside or - not. Defaults to ``False``. + :param LabelTensor point: Point to be checked. + :param bool check_border: If ``True``, the border is considered inside + the domain. Default is ``False``. """ diff --git a/pina/domain/ellipsoid.py b/pina/domain/ellipsoid.py index 120cbf6..a99d2b6 100644 --- a/pina/domain/ellipsoid.py +++ b/pina/domain/ellipsoid.py @@ -1,6 +1,4 @@ -""" -Module for the Ellipsoid domain. -""" +"""Module for the Ellipsoid Domain.""" import torch from .domain_interface import DomainInterface @@ -9,34 +7,35 @@ from ..utils import check_consistency class EllipsoidDomain(DomainInterface): - """PINA implementation of Ellipsoid domain.""" + """ + Implementation of the ellipsoid domain. + """ def __init__(self, ellipsoid_dict, sample_surface=False): - """PINA implementation of Ellipsoid domain. + """ + Initialization of the :class:`EllipsoidDomain` class. - :param ellipsoid_dict: A dictionary with dict-key a string representing - the input variables for the pinn, and dict-value a list with - the domain extrema. - :type ellipsoid_dict: dict - :param sample_surface: A variable for choosing sample strategies. If - ``sample_surface=True`` only samples on the ellipsoid surface - frontier are taken. If ``sample_surface=False`` only samples on - the ellipsoid interior are taken, defaults to ``False``. - :type sample_surface: bool + :param dict ellipsoid_dict: A dictionary where the keys are the variable + names and the values are the domain extrema. + :param bool sample_surface: A flag to choose the sampling strategy. + If ``True``, samples are taken only from the surface of the ellipsoid. + If ``False``, samples are taken from the interior of the ellipsoid. + Default is ``False``. + :raises TypeError: If the input dictionary is not correctly formatted. .. warning:: - Sampling for dimensions greater or equal to 10 could result - in a shrinking of the ellipsoid, which degrades the quality - of the samples. For dimensions higher than 10, other algorithms - for sampling should be used, such as: Dezert, Jean, and Christian - Musso. "An efficient method for generating points uniformly - distributed in hyperellipsoids." Proceedings of the Workshop on - Estimation, Tracking and Fusion: A Tribute to Yaakov Bar-Shalom. - Vol. 7. No. 8. 2001. + Sampling for dimensions greater or equal to 10 could result in a + shrinkage of the ellipsoid, which degrades the quality of the + samples. For dimensions higher than 10, use other sampling algorithms. + .. seealso:: + **Original reference**: Dezert, Jean, and Musso, Christian. + *An efficient method for generating points uniformly distributed + in hyperellipsoids.* + Proceedings of the Workshop on Estimation, Tracking and Fusion: + A Tribute to Yaakov Bar-Shalom. 2001. :Example: >>> spatial_domain = Ellipsoid({'x':[-1, 1], 'y':[-1,1]}) - """ self.fixed_ = {} self.range_ = {} @@ -75,34 +74,40 @@ class EllipsoidDomain(DomainInterface): @property def sample_modes(self): + """ + List of available sampling modes. + + :return: List of available sampling modes. + :rtype: list[str] + """ return ["random"] @property def variables(self): - """Spatial variables. + """ + List of variables of the domain. - :return: Spatial variables defined in '__init__()' + :return: List of variables of the domain. :rtype: list[str] """ return sorted(list(self.fixed_.keys()) + list(self.range_.keys())) def is_inside(self, point, check_border=False): - """Check if a point is inside the ellipsoid domain. + """ + Check if a point is inside the ellipsoid. + + :param LabelTensor point: Point to be checked. + :param bool check_border: If ``True``, the border is considered inside + the ellipsoid. Default is ``False``. + :raises ValueError: If the labels of the point are different from those + passed in the ``__init__`` method. + :return: ``True`` if the point is inside the domain, ``False`` otherwise. + :rtype: bool .. note:: - When ``sample_surface`` in the ``__init()__`` - is set to ``True``, then the method only checks - points on the surface, and not inside the domain. - - :param point: Point to be checked. - :type point: LabelTensor - :param check_border: Check if the point is also on the frontier - of the ellipsoid, default ``False``. - :type check_border: bool - :return: Returning True if the point is inside, ``False`` otherwise. - :rtype: bool + When ``sample_surface=True`` in the ``__init__`` method, this method + checks only those points lying on the surface of the ellipsoid. """ - # small check that point is labeltensor check_consistency(point, LabelTensor) @@ -142,15 +147,13 @@ class EllipsoidDomain(DomainInterface): return bool(eqn < 0) def _sample_range(self, n, mode, variables): - """Rescale the samples to the correct bounds. + """""" + """ + Rescale the samples to fit within the specified bounds. - :param n: Number of points to sample in the ellipsoid. - :type n: int - :param mode: Mode for sampling, defaults to ``random``. - Available modes include: random sampling, ``random``. - :type mode: str, optional - :param variables: Variables to be rescaled in the samples. - :type variables: torch.Tensor + :param int n: Number of points to sample. + :param str mode: Sampling method. Default is ``random``. + :param list[str] variables: variables whose samples must be rescaled. :return: Rescaled sample points. :rtype: torch.Tensor """ @@ -202,19 +205,20 @@ class EllipsoidDomain(DomainInterface): return pts def sample(self, n, mode="random", variables="all"): - """Sample routine. + """ + Sampling routine. - :param int n: Number of points to sample in the shape. - :param str mode: Mode for sampling, defaults to ``random``. - Available modes include: ``random``. - :param variables: Variables to be sampled, defaults to ``all``. - :type variables: str | list[str] - :return: Returns ``LabelTensor`` of n sampled points. + :param int n: Number of points to sample. + :param str mode: Sampling method. Default is ``random``. + Available modes: random sampling, ``random``. + :param list[str] variables: variables to be sampled. Default is ``all``. + :raises NotImplementedError: If the sampling mode is not implemented. + :return: Sampled points. :rtype: LabelTensor :Example: - >>> elips = Ellipsoid({'x':[1, 0], 'y':1}) - >>> elips.sample(n=6) + >>> ellipsoid = Ellipsoid({'x':[1, 0], 'y':1}) + >>> ellipsoid.sample(n=6) tensor([[0.4872, 1.0000], [0.2977, 1.0000], [0.0422, 1.0000], @@ -224,19 +228,14 @@ class EllipsoidDomain(DomainInterface): """ def _Nd_sampler(n, mode, variables): - """Sample all the variables together + """ + Sample all variables together. - :param n: Number of points to sample. - :type n: int - :param mode: Mode for sampling, defaults to ``random``. - Available modes include: random sampling, ``random``; - latin hypercube sampling, 'latin' or 'lh'; - chebyshev sampling, 'chebyshev'; grid sampling 'grid'. - :type mode: str, optional. - :param variables: pinn variable to be sampled, defaults to ``all``. - :type variables: str or list[str], optional. - :return: Sample points. - :rtype: list[torch.Tensor] + :param int n: Number of points to sample. + :param str mode: Sampling method. + :param list[str] variables: variables to be sampled. + :return: Sampled points. + :rtype: list[LabelTensor] """ pairs = [(k, v) for k, v in self.range_.items() if k in variables] keys, _ = map(list, zip(*pairs)) @@ -258,13 +257,12 @@ class EllipsoidDomain(DomainInterface): return result def _single_points_sample(n, variables): - """Sample a single point in one dimension. + """ + Sample a single point in one dimension. - :param n: Number of points to sample. - :type n: int - :param variables: Variables to sample from. - :type variables: list[str] - :return: Sample points. + :param int n: Number of points to sample. + :param list[str] variables: variables to be sampled. + :return: Sampled points. :rtype: list[torch.Tensor] """ tmp = [] diff --git a/pina/domain/exclusion_domain.py b/pina/domain/exclusion_domain.py index 0d25d73..c9d6692 100644 --- a/pina/domain/exclusion_domain.py +++ b/pina/domain/exclusion_domain.py @@ -1,4 +1,4 @@ -"""Module for Exclusion class.""" +"""Module for the Exclusion Operation.""" import random import torch @@ -7,43 +7,44 @@ from .operation_interface import OperationInterface class Exclusion(OperationInterface): - """ - PINA implementation of Exclusion of Domains. + r""" + Implementation of the exclusion operation between of a list of domains. + + Given two sets :math:`A` and :math:`B`, define the exclusion of the two + sets as: + + .. math:: + A \setminus B = \{x \mid x \in A \land x \in B \land + x \not\in(A \lor B)\}, + + where :math:`x` is a point in :math:`\mathbb{R}^N`. """ def __init__(self, geometries): - r""" - Given two sets :math:`A` and :math:`B` then the - domain difference is defined as: + """ + Initialization of the :class:`Exclusion` class. - .. math:: - A \setminus B = \{x \mid x \in A \land x \in B \land - x \not\in(A \lor B)\}, - - with :math:`x` a point in :math:`\mathbb{R}^N` and :math:`N` - the dimension of the geometry space. - - :param list geometries: A list of geometries from ``pina.geometry`` - such as ``EllipsoidDomain`` or ``CartesianDomain``. + :param list[DomainInterface] geometries: A list of instances of the + :class:`~pina.domain.DomainInterface` class on which the exclusion + operation is performed. :Example: >>> # Create two ellipsoid domains >>> ellipsoid1 = EllipsoidDomain({'x': [-1, 1], 'y': [-1, 1]}) >>> ellipsoid2 = EllipsoidDomain({'x': [0, 2], 'y': [0, 2]}) - >>> # Create a Exclusion of the ellipsoid domains + >>> # Define the exclusion between the domains >>> exclusion = Exclusion([ellipsoid1, ellipsoid2]) """ super().__init__(geometries) def is_inside(self, point, check_border=False): """ - Check if a point is inside the ``Exclusion`` domain. + Check if a point is inside the resulting domain. - :param point: Point to be checked. - :type point: torch.Tensor - :param bool check_border: If ``True``, the border is considered inside. - :return: ``True`` if the point is inside the Exclusion domain, - ``False`` otherwise. + :param LabelTensor point: Point to be checked. + :param bool check_border: If ``True``, the border is considered inside + the domain. Default is ``False``. + :return: ``True`` if the point is inside the domain, ``False`` otherwise. :rtype: bool """ flag = 0 @@ -54,21 +55,21 @@ class Exclusion(OperationInterface): def sample(self, n, mode="random", variables="all"): """ - Sample routine for ``Exclusion`` domain. + Sampling routine. - :param int n: Number of points to sample in the shape. - :param str mode: Mode for sampling, defaults to ``random``. Available - modes include: ``random``. - :param variables: Variables to be sampled, defaults to ``all``. - :type variables: str | list[str] - :return: Returns ``LabelTensor`` of n sampled points. + :param int n: Number of points to sample. + :param str mode: Sampling method. Default is ``random``. + Available modes: random sampling, ``random``; + :param list[str] variables: variables to be sampled. Default is ``all``. + :raises NotImplementedError: If the sampling method is not implemented. + :return: Sampled points. :rtype: LabelTensor :Example: >>> # Create two Cartesian domains >>> cartesian1 = CartesianDomain({'x': [0, 2], 'y': [0, 2]}) >>> cartesian2 = CartesianDomain({'x': [1, 3], 'y': [1, 3]}) - >>> # Create a Exclusion of the ellipsoid domains + >>> # Define the exclusion between the domains >>> Exclusion = Exclusion([cartesian1, cartesian2]) >>> # Sample >>> Exclusion.sample(n=5) @@ -79,7 +80,6 @@ class Exclusion(OperationInterface): [0.1978, 0.3526]]) >>> len(Exclusion.sample(n=5) 5 - """ if mode not in self.sample_modes: raise NotImplementedError( diff --git a/pina/domain/intersection_domain.py b/pina/domain/intersection_domain.py index 69388b0..e5ccc58 100644 --- a/pina/domain/intersection_domain.py +++ b/pina/domain/intersection_domain.py @@ -1,4 +1,4 @@ -"""Module for Intersection class.""" +"""Module for the Intersection Operation.""" import random import torch @@ -7,44 +7,43 @@ from .operation_interface import OperationInterface class Intersection(OperationInterface): - """ - PINA implementation of Intersection of Domains. + r""" + Implementation of the intersection operation between of a list of domains. + + Given two sets :math:`A` and :math:`B`, define the intersection of the two + sets as: + + .. math:: + A \cap B = \{x \mid x \in A \land x \in B\}, + + where :math:`x` is a point in :math:`\mathbb{R}^N`. """ def __init__(self, geometries): - r""" - Given two sets :math:`A` and :math:`B` then the - domain difference is defined as: + """ + Initialization of the :class:`Intersection` class. - .. math:: - A \cap B = \{x \mid x \in A \land x \in B\}, - - with :math:`x` a point in :math:`\mathbb{R}^N` and :math:`N` - the dimension of the geometry space. - - :param list geometries: A list of geometries from ``pina.geometry`` - such as ``EllipsoidDomain`` or ``CartesianDomain``. The intersection - will be taken between all the geometries in the list. The resulting - geometry will be the intersection of all the geometries in the list. + :param list[DomainInterface] geometries: A list of instances of the + :class:`~pina.domain.DomainInterface` class on which the intersection + operation is performed. :Example: >>> # Create two ellipsoid domains >>> ellipsoid1 = EllipsoidDomain({'x': [-1, 1], 'y': [-1, 1]}) >>> ellipsoid2 = EllipsoidDomain({'x': [0, 2], 'y': [0, 2]}) - >>> # Create a Intersection of the ellipsoid domains + >>> # Define the intersection of the domains >>> intersection = Intersection([ellipsoid1, ellipsoid2]) """ super().__init__(geometries) def is_inside(self, point, check_border=False): """ - Check if a point is inside the ``Intersection`` domain. + Check if a point is inside the resulting domain. - :param point: Point to be checked. - :type point: torch.Tensor - :param bool check_border: If ``True``, the border is considered inside. - :return: ``True`` if the point is inside the Intersection domain, - ``False`` otherwise. + :param LabelTensor point: Point to be checked. + :param bool check_border: If ``True``, the border is considered inside + the domain. Default is ``False``. + :return: ``True`` if the point is inside the domain, ``False`` otherwise. :rtype: bool """ flag = 0 @@ -55,21 +54,21 @@ class Intersection(OperationInterface): def sample(self, n, mode="random", variables="all"): """ - Sample routine for ``Intersection`` domain. + Sampling routine. - :param int n: Number of points to sample in the shape. - :param str mode: Mode for sampling, defaults to ``random``. Available - modes include: ``random``. - :param variables: Variables to be sampled, defaults to ``all``. - :type variables: str | list[str] - :return: Returns ``LabelTensor`` of n sampled points. + :param int n: Number of points to sample. + :param str mode: Sampling method. Default is ``random``. + Available modes: random sampling, ``random``; + :param list[str] variables: variables to be sampled. Default is ``all``. + :raises NotImplementedError: If the sampling method is not implemented. + :return: Sampled points. :rtype: LabelTensor :Example: >>> # Create two Cartesian domains >>> cartesian1 = CartesianDomain({'x': [0, 2], 'y': [0, 2]}) >>> cartesian2 = CartesianDomain({'x': [1, 3], 'y': [1, 3]}) - >>> # Create a Intersection of the ellipsoid domains + >>> # Define the intersection of the domains >>> intersection = Intersection([cartesian1, cartesian2]) >>> # Sample >>> intersection.sample(n=5) @@ -80,7 +79,6 @@ class Intersection(OperationInterface): [1.9902, 1.4458]]) >>> len(intersection.sample(n=5) 5 - """ if mode not in self.sample_modes: raise NotImplementedError( diff --git a/pina/domain/operation_interface.py b/pina/domain/operation_interface.py index 5a5c3c1..e8b8b6d 100644 --- a/pina/domain/operation_interface.py +++ b/pina/domain/operation_interface.py @@ -1,4 +1,4 @@ -"""Module for OperationInterface class.""" +"""Module for the Operation Interface.""" from abc import ABCMeta, abstractmethod from .domain_interface import DomainInterface @@ -7,15 +7,16 @@ from ..utils import check_consistency class OperationInterface(DomainInterface, metaclass=ABCMeta): """ - Abstract class for set domains operations. + Abstract class for set operations defined on geometric domains. """ def __init__(self, geometries): """ - Any geometry operation entity must inherit from this class. + Initialization of the :class:`OperationInterface` class. - :param list geometries: A list of geometries from ``pina.geometry`` - such as ``EllipsoidDomain`` or ``CartesianDomain``. + :param list[DomainInterface] geometries: A list of instances of the + :class:`~pina.domain.DomainInterface` class on which the set + operation is performed. """ # check consistency geometries check_consistency(geometries, DomainInterface) @@ -29,21 +30,30 @@ class OperationInterface(DomainInterface, metaclass=ABCMeta): @property def sample_modes(self): + """ + List of available sampling modes. + + :return: List of available sampling modes. + :rtype: list[str] + """ return ["random"] @property def geometries(self): """ - The geometries to perform set operation. + The domains on which to perform the set operation. + + :return: The domains on which to perform the set operation. + :rtype: list[DomainInterface] """ return self._geometries @property def variables(self): """ - Spatial variables of the domain. + List of variables of the domain. - :return: All the variables defined in ``__init__`` in order. + :return: List of variables of the domain. :rtype: list[str] """ variables = [] @@ -54,22 +64,23 @@ class OperationInterface(DomainInterface, metaclass=ABCMeta): @abstractmethod def is_inside(self, point, check_border=False): """ - Check if a point is inside the resulting domain after - a set operation is applied. + Abstract method to check if a point lies inside the resulting domain + after performing the set operation. - :param point: Point to be checked. - :type point: torch.Tensor - :param bool check_border: If ``True``, the border is considered inside. - :return: ``True`` if the point is inside the Intersection domain, - ``False`` otherwise. + :param LabelTensor point: Point to be checked. + :param bool check_border: If ``True``, the border is considered inside + the resulting domain. Default is ``False``. + :return: ``True`` if the point is inside the domain, ``False`` otherwise. :rtype: bool """ def _check_dimensions(self, geometries): - """Check if the dimensions of the geometries are consistent. + """ + Check if the dimensions of the geometries are consistent. - :param geometries: Geometries to be checked. - :type geometries: list[Location] + :param list[DomainInterface] geometries: Domains to be checked. + :raises NotImplementedError: If the dimensions of the geometries are not + consistent. """ for geometry in geometries: if geometry.variables != geometries[0].variables: diff --git a/pina/domain/simplex.py b/pina/domain/simplex.py index 7c1deee..4c4d616 100644 --- a/pina/domain/simplex.py +++ b/pina/domain/simplex.py @@ -1,6 +1,4 @@ -""" -Module for Simplex Domain. -""" +"""Module for the Simplex Domain.""" import torch from .domain_interface import DomainInterface @@ -10,27 +8,28 @@ from ..utils import check_consistency class SimplexDomain(DomainInterface): - """PINA implementation of a Simplex.""" + """ + Implementation of the simplex domain. + """ def __init__(self, simplex_matrix, sample_surface=False): """ - :param simplex_matrix: A matrix of LabelTensor objects representing - a vertex of the simplex (a tensor), and the coordinates of the - point (a list of labels). + Initialization of the :class:`SimplexDomain` class. - :type simplex_matrix: list[LabelTensor] - :param sample_surface: A variable for choosing sample strategies. If - ``sample_surface=True`` only samples on the Simplex surface - frontier are taken. If ``sample_surface=False``, no such criteria - is followed. - - :type sample_surface: bool + :param list[LabelTensor] simplex_matrix: A matrix representing the + vertices of the simplex. + :param bool sample_surface: A flag to choose the sampling strategy. + If ``True``, samples are taken only from the surface of the simplex. + If ``False``, samples are taken from the interior of the simplex. + Default is ``False``. + :raises ValueError: If the labels of the vertices don't match. + :raises ValueError: If the number of vertices is not equal to the + dimension of the simplex plus one. .. warning:: - Sampling for dimensions greater or equal to 10 could result - in a shrinking of the simplex, which degrades the quality - of the samples. For dimensions higher than 10, other algorithms - for sampling should be used. + Sampling for dimensions greater or equal to 10 could result in a + shrinkage of the simplex, which degrades the quality of the samples. + For dimensions higher than 10, use other sampling algorithms. :Example: >>> spatial_domain = SimplexDomain( @@ -77,18 +76,30 @@ class SimplexDomain(DomainInterface): @property def sample_modes(self): + """ + List of available sampling modes. + + :return: List of available sampling modes. + :rtype: list[str] + """ return ["random"] @property def variables(self): + """ + List of variables of the domain. + + :return: List of variables of the domain. + :rtype: list[str] + """ return sorted(self._vertices_matrix.labels) def _build_cartesian(self, vertices): """ - Build Cartesian border for Simplex domain to be used in sampling. - :param vertex_matrix: matrix of vertices - :type vertices: list[list] - :return: Cartesian border for triangular domain + Build the cartesian border for a simplex domain to be used in sampling. + + :param list[LabelTensor] vertices: Matrix of vertices defining the domain. + :return: The cartesian border for the simplex domain. :rtype: CartesianDomain """ @@ -105,22 +116,16 @@ class SimplexDomain(DomainInterface): def is_inside(self, point, check_border=False): """ - Check if a point is inside the simplex. - Uses the algorithm described involving barycentric coordinates: - https://en.wikipedia.org/wiki/Barycentric_coordinate_system. + Check if a point is inside the simplex. It uses an algorithm involving + barycentric coordinates. - :param point: Point to be checked. - :type point: LabelTensor - :param check_border: Check if the point is also on the frontier - of the simplex, default ``False``. - :type check_border: bool - :return: Returning ``True`` if the point is inside, ``False`` otherwise. + :param LabelTensor point: Point to be checked. + :param check_border: If ``True``, the border is considered inside + the simplex. Default is ``False``. + :raises ValueError: If the labels of the point are different from those + passed in the ``__init__`` method. + :return: ``True`` if the point is inside the domain, ``False`` otherwise. :rtype: bool - - .. note:: - When ``sample_surface`` in the ``__init()__`` - is set to ``True``, then the method only checks - points on the surface, and not inside the domain. """ if not all(label in self.variables for label in point.labels): @@ -134,7 +139,6 @@ class SimplexDomain(DomainInterface): point_shift = point_shift.tensor.reshape(-1, 1) # compute barycentric coordinates - lambda_ = torch.linalg.solve( self._vectors_shifted * 1.0, point_shift * 1.0 ) @@ -151,13 +155,13 @@ class SimplexDomain(DomainInterface): def _sample_interior_randomly(self, n, variables): """ - Randomly sample points inside a simplex of arbitrary - dimension, without the boundary. - :param int n: Number of points to sample in the shape. - :param variables: pinn variable to be sampled, defaults to ``all``. - :type variables: str or list[str], optional - :return: Returns tensor of n sampled points. - :rtype: torch.Tensor + Sample at random points from the interior of the simplex. Boundaries are + excluded from this sampling routine. + + :param int n: Number of points to sample. + :param list[str] variables: variables to be sampled. + :return: Sampled points. + :rtype: list[torch.Tensor] """ # =============== For Developers ================ # @@ -182,10 +186,10 @@ class SimplexDomain(DomainInterface): def _sample_boundary_randomly(self, n): """ - Randomly sample points on the boundary of a simplex - of arbitrary dimensions. - :param int n: Number of points to sample in the shape. - :return: Returns tensor of n sampled points + Sample at random points from the boundary of the simplex. + + :param int n: Number of points to sample. + :return: Sampled points. :rtype: torch.Tensor """ @@ -221,20 +225,19 @@ class SimplexDomain(DomainInterface): def sample(self, n, mode="random", variables="all"): """ - Sample n points from Simplex domain. + Sampling routine. - :param int n: Number of points to sample in the shape. - :param str mode: Mode for sampling, defaults to ``random``. Available - modes include: ``random``. - :param variables: Variables to be sampled, defaults to ``all``. - :type variables: str | list[str] - :return: Returns ``LabelTensor`` of n sampled points. + :param int n: Number of points to sample. + :param str mode: Sampling method. Default is ``random``. + Available modes: random sampling, ``random``. + :param list[str] variables: variables to be sampled. Default is ``all``. + :raises NotImplementedError: If the sampling method is not implemented. + :return: Sampled points. :rtype: LabelTensor .. warning:: - When ``sample_surface = True`` in the initialization, all - the variables are sampled, despite passing different once - in ``variables``. + When ``sample_surface=True``, all variables are sampled, + ignoring the ``variables`` parameter. """ if variables == "all": diff --git a/pina/domain/union_domain.py b/pina/domain/union_domain.py index ecf6c63..b3c1426 100644 --- a/pina/domain/union_domain.py +++ b/pina/domain/union_domain.py @@ -1,4 +1,4 @@ -"""Module for Union class.""" +"""Module for the Union Operation.""" import random import torch @@ -7,51 +7,51 @@ from ..label_tensor import LabelTensor class Union(OperationInterface): - """ - Union of Domains. + r""" + Implementation of the union operation between of a list of domains. + + Given two sets :math:`A` and :math:`B`, define the union of the two sets as: + + .. math:: + A \cup B = \{x \mid x \in A \lor x \in B\}, + + where :math:`x` is a point in :math:`\mathbb{R}^N`. """ def __init__(self, geometries): - r""" - PINA implementation of Unions of Domains. - Given two sets :math:`A` and :math:`B` then the - domain difference is defined as: + """ + Initialization of the :class:`Union` class. - .. math:: - A \cup B = \{x \mid x \in A \lor x \in B\}, - - with :math:`x` a point in :math:`\mathbb{R}^N` and :math:`N` - the dimension of the geometry space. - - :param list geometries: A list of geometries from ``pina.geometry`` - such as ``EllipsoidDomain`` or ``CartesianDomain``. + :param list[DomainInterface] geometries: A list of instances of the + :class:`~pina.domain.DomainInterface` class on which the union + operation is performed. :Example: >>> # Create two ellipsoid domains >>> ellipsoid1 = EllipsoidDomain({'x': [-1, 1], 'y': [-1, 1]}) >>> ellipsoid2 = EllipsoidDomain({'x': [0, 2], 'y': [0, 2]}) - >>> # Create a union of the ellipsoid domains - >>> union = GeometryUnion([ellipsoid1, ellipsoid2]) - + >>> # Define the union of the domains + >>> union = Union([ellipsoid1, ellipsoid2]) """ super().__init__(geometries) @property def sample_modes(self): + """ + List of available sampling modes. + """ self.sample_modes = list( set(geom.sample_modes for geom in self.geometries) ) def is_inside(self, point, check_border=False): """ - Check if a point is inside the ``Union`` domain. + Check if a point is inside the resulting domain. - :param point: Point to be checked. - :type point: LabelTensor - :param check_border: Check if the point is also on the frontier - of the ellipsoid, default ``False``. - :type check_border: bool - :return: Returning ``True`` if the point is inside, ``False`` otherwise. + :param LabelTensor point: Point to be checked. + :param bool check_border: If ``True``, the border is considered inside + the domain. Default is ``False``. + :return: ``True`` if the point is inside the domain, ``False`` otherwise. :rtype: bool """ for geometry in self.geometries: @@ -61,21 +61,20 @@ class Union(OperationInterface): def sample(self, n, mode="random", variables="all"): """ - Sample routine for ``Union`` domain. + Sampling routine. - :param int n: Number of points to sample in the shape. - :param str mode: Mode for sampling, defaults to ``random``. Available - modes include: ``random``. - :param variables: Variables to be sampled, defaults to ``all``. - :type variables: str | list[str] - :return: Returns ``LabelTensor`` of n sampled points. + :param int n: Number of points to sample. + :param str mode: Sampling method. Default is ``random``. + Available modes: random sampling, ``random``; + :param list[str] variables: variables to be sampled. Default is ``all``. + :return: Sampled points. :rtype: LabelTensor :Example: - >>> # Create two ellipsoid domains + >>> # Create two cartesian domains >>> cartesian1 = CartesianDomain({'x': [0, 2], 'y': [0, 2]}) >>> cartesian2 = CartesianDomain({'x': [1, 3], 'y': [1, 3]}) - >>> # Create a union of the ellipsoid domains + >>> # Define the union of the domains >>> union = Union([cartesian1, cartesian2]) >>> # Sample >>> union.sample(n=5)