fix doc domain

This commit is contained in:
giovanni
2025-03-12 15:27:06 +01:00
committed by FilippoOlivo
parent a76c1cda96
commit 06e6c4763d
10 changed files with 329 additions and 325 deletions

View File

@@ -1,6 +1,4 @@
"""
This module contains the domain classes.
"""
"""Modules to create and handle domains."""
__all__ = [
"DomainInterface",

View File

@@ -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
"""

View File

@@ -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)

View File

@@ -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``.
"""

View File

@@ -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 = []

View File

@@ -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(

View File

@@ -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(

View File

@@ -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:

View File

@@ -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":

View File

@@ -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)