fix problem doc

This commit is contained in:
giovanni
2025-03-13 12:04:02 +01:00
committed by Nicola Demo
parent 3606d2ef10
commit 66b49ea438
10 changed files with 120 additions and 102 deletions

View File

@@ -1,4 +1,4 @@
"""Module for Problems.""" """Module for the Problems."""
__all__ = [ __all__ = [
"AbstractProblem", "AbstractProblem",

View File

@@ -1,4 +1,4 @@
"""Module for AbstractProblem class""" """Module for the AbstractProblem class"""
from abc import ABCMeta, abstractmethod from abc import ABCMeta, abstractmethod
from copy import deepcopy from copy import deepcopy
@@ -11,20 +11,16 @@ from ..utils import merge_tensors
class AbstractProblem(metaclass=ABCMeta): class AbstractProblem(metaclass=ABCMeta):
""" """
The abstract `AbstractProblem` class. All the class defining a PINA Problem Abstract base class for PINA problems. All specific problem types should
should be inherited from this class. inherit from this class.
In the definition of a PINA problem, the fundamental elements are: A PINA problem is defined by key components, which typically include output
the output variables, the condition(s), and the domain(s) where the variables, conditions, and domains over which the conditions are applied.
conditions are applied.
""" """
def __init__(self): def __init__(self):
""" """
TODO Initialization of the :class:`AbstractProblem` class.
:return: _description_
:rtype: _type_
""" """
self._discretised_domains = {} self._discretised_domains = {}
# create collector to manage problem data # create collector to manage problem data
@@ -48,20 +44,19 @@ class AbstractProblem(metaclass=ABCMeta):
@property @property
def batching_dimension(self): def batching_dimension(self):
""" """
TODO Get batching dimension.
:return: _description_ :return: The batching dimension.
:rtype: _type_ :rtype int
""" """
return self._batching_dimension return self._batching_dimension
@batching_dimension.setter @batching_dimension.setter
def batching_dimension(self, value): def batching_dimension(self, value):
""" """
TODO Set the batching dimension.
:return: _description_ :param int value: The batching dimension.
:rtype: _type_
""" """
self._batching_dimension = value self._batching_dimension = value
@@ -69,10 +64,11 @@ class AbstractProblem(metaclass=ABCMeta):
@property @property
def input_pts(self): def input_pts(self):
""" """
TODO Return a dictionary mapping condition names to their corresponding
input points.
:return: _description_ :return: The input points of the problem.
:rtype: _type_ :rtype: dict
""" """
to_return = {} to_return = {}
for cond_name, cond in self.conditions.items(): for cond_name, cond in self.conditions.items():
@@ -85,21 +81,21 @@ class AbstractProblem(metaclass=ABCMeta):
@property @property
def discretised_domains(self): def discretised_domains(self):
""" """
TODO Return a dictionary mapping domains to their corresponding sampled
points.
:return: _description_ :return: The discretised domains.
:rtype: _type_ :rtype dict
""" """
return self._discretised_domains return self._discretised_domains
def __deepcopy__(self, memo): def __deepcopy__(self, memo):
""" """
Implements deepcopy for the Perform a deep copy of the :class:`AbstractProblem` instance.
:class:`~pina.problem.abstract_problem.AbstractProblem` class.
:param dict memo: Memory dictionary, to avoid excess copy :param dict memo: A dictionary used to track objects already copied
:return: The deep copy of the during the deep copy process to prevent redundant copies.
:class:`~pina.problem.abstract_problem.AbstractProblem` class :return: A deep copy of the :class:`AbstractProblem` instance.
:rtype: AbstractProblem :rtype: AbstractProblem
""" """
cls = self.__class__ cls = self.__class__
@@ -114,7 +110,7 @@ class AbstractProblem(metaclass=ABCMeta):
""" """
Check if all the domains are discretised. Check if all the domains are discretised.
:return: True if all the domains are discretised, False otherwise :return: ``True`` if all domains are discretised, ``False`` otherwise.
:rtype: bool :rtype: bool
""" """
return all( return all(
@@ -124,12 +120,10 @@ class AbstractProblem(metaclass=ABCMeta):
@property @property
def input_variables(self): def input_variables(self):
""" """
The input variables of the AbstractProblem, whose type depends on the Get the input variables of the problem.
type of domain (spatial, temporal, and parameter).
:return: the input variables of self
:rtype: list
:return: The input variables of the problem.
:rtype: list[str]
""" """
variables = [] variables = []
@@ -144,20 +138,29 @@ class AbstractProblem(metaclass=ABCMeta):
@input_variables.setter @input_variables.setter
def input_variables(self, variables): def input_variables(self, variables):
"""
Set the input variables of the AbstractProblem.
:param list[str] variables: The input variables of the problem.
:raises RuntimeError: Not implemented.
"""
raise RuntimeError raise RuntimeError
@property @property
@abstractmethod @abstractmethod
def output_variables(self): def output_variables(self):
""" """
The output variables of the problem. Get the output variables of the problem.
""" """
@property @property
@abstractmethod @abstractmethod
def conditions(self): def conditions(self):
""" """
The conditions of the problem. Get the conditions of the problem.
:return: The conditions of the problem.
:rtype: dict
""" """
return self.conditions return self.conditions
@@ -165,30 +168,28 @@ class AbstractProblem(metaclass=ABCMeta):
self, n=None, mode="random", domains="all", sample_rules=None self, n=None, mode="random", domains="all", sample_rules=None
): ):
""" """
Generate a set of points to span the `Location` of all the conditions of Discretize the problem's domains by sampling a specified number of
the problem. points according to the selected sampling mode.
:param n: Number of points to sample, see Note below :param int n: The number of points to sample.
for reference. :param mode: The sampling method. Default is ``random``.
:type n: int
:param mode: Mode for sampling, defaults to ``random``.
Available modes include: random sampling, ``random``; Available modes include: random sampling, ``random``;
latin hypercube sampling, ``latin`` or ``lh``; latin hypercube sampling, ``latin`` or ``lh``;
chebyshev sampling, ``chebyshev``; grid sampling ``grid``. chebyshev sampling, ``chebyshev``; grid sampling ``grid``.
:param variables: variable(s) to sample, defaults to 'all'. :param domains: The domains from which to sample. Default is ``all``.
:type variables: str | list[str]
:param domains: Domain from where to sample, defaults to 'all'.
:type domains: str | list[str] :type domains: str | list[str]
:param dict sample_rules: A dictionary of custom sampling rules.
:raises RuntimeError: If both ``n`` and ``sample_rules`` are specified.
:raises RuntimeError: If neither ``n`` nor ``sample_rules`` are set.
:Example: :Example:
>>> pinn.discretise_domain(n=10, mode='grid') >>> problem.discretise_domain(n=10, mode='grid')
>>> pinn.discretise_domain(n=10, mode='grid', domain=['bound1']) >>> problem.discretise_domain(n=10, mode='grid', domains=['gamma1'])
>>> pinn.discretise_domain(n=10, mode='grid', variables=['x'])
.. warning:: .. warning::
``random`` is currently the only implemented ``mode`` for all ``random`` is currently the only implemented ``mode`` for all
geometries, i.e. ``EllipsoidDomain``, ``CartesianDomain``, geometries, i.e. ``EllipsoidDomain``, ``CartesianDomain``,
``SimplexDomain`` and the geometries compositions ``Union``, ``SimplexDomain``, and geometry compositions ``Union``,
``Difference``, ``Exclusion``, ``Intersection``. The ``Difference``, ``Exclusion``, ``Intersection``. The
modes ``latin`` or ``lh``, ``chebyshev``, ``grid`` are only modes ``latin`` or ``lh``, ``chebyshev``, ``grid`` are only
implemented for ``CartesianDomain``. implemented for ``CartesianDomain``.
@@ -218,12 +219,31 @@ class AbstractProblem(metaclass=ABCMeta):
raise RuntimeError("You have to specify either n or sample_rules.") raise RuntimeError("You have to specify either n or sample_rules.")
def _apply_default_discretization(self, n, mode, domains): def _apply_default_discretization(self, n, mode, domains):
"""
Apply default discretization to the problem's domains.
:param int n: The number of points to sample.
:param mode: The sampling method.
:param domains: The domains from which to sample.
:type domains: str | list[str]
"""
for domain in domains: for domain in domains:
self.discretised_domains[domain] = ( self.discretised_domains[domain] = (
self.domains[domain].sample(n, mode).sort_labels() self.domains[domain].sample(n, mode).sort_labels()
) )
def _apply_custom_discretization(self, sample_rules, domains): def _apply_custom_discretization(self, sample_rules, domains):
"""
Apply custom discretization to the problem's domains.
:param dict sample_rules: A dictionary of custom sampling rules.
:param domains: The domains from which to sample.
:type domains: str | list[str]
:raises RuntimeError: If the keys of the sample_rules dictionary are not
the same as the input variables.
:raises RuntimeError: If custom discretisation is applied on a domain
that is not a CartesianDomain.
"""
if sorted(list(sample_rules.keys())) != sorted(self.input_variables): if sorted(list(sample_rules.keys())) != sorted(self.input_variables):
raise RuntimeError( raise RuntimeError(
"The keys of the sample_rules dictionary must be the same as " "The keys of the sample_rules dictionary must be the same as "
@@ -247,10 +267,10 @@ class AbstractProblem(metaclass=ABCMeta):
def add_points(self, new_points_dict): def add_points(self, new_points_dict):
""" """
Add input points to a sampled condition Add new points to an already sampled domain.
:param new_points_dict: Dictionary of input points (condition_name:
LabelTensor) :param dict new_points_dict: The dictionary mapping new points to their
:raises RuntimeError: if at least one condition is not already sampled corresponding domain.
""" """
for k, v in new_points_dict.items(): for k, v in new_points_dict.items():
self.discretised_domains[k] = LabelTensor.vstack( self.discretised_domains[k] = LabelTensor.vstack(

View File

@@ -1,4 +1,4 @@
"""Module for the ParametricProblem class""" """Module for the InverseProblem class"""
from abc import abstractmethod from abc import abstractmethod
import torch import torch
@@ -7,19 +7,14 @@ from .abstract_problem import AbstractProblem
class InverseProblem(AbstractProblem): class InverseProblem(AbstractProblem):
""" """
The class for the definition of inverse problems, i.e., problems Class for defining inverse problems, where the objective is to determine
with unknown parameters that have to be learned during the training process unknown parameters through training, based on given data.
from given data.
Here's an example of a spatial inverse ODE problem, i.e., a spatial
ODE problem with an unknown parameter `alpha` as coefficient of the
derivative term.
:Example:
TODO
""" """
def __init__(self): def __init__(self):
"""
Initialization of the :class:`InverseProblem` class.
"""
super().__init__() super().__init__()
# storing unknown_parameters for optimization # storing unknown_parameters for optimization
self.unknown_parameters = {} self.unknown_parameters = {}
@@ -33,23 +28,34 @@ class InverseProblem(AbstractProblem):
@abstractmethod @abstractmethod
def unknown_parameter_domain(self): def unknown_parameter_domain(self):
""" """
The parameters' domain of the problem. The domain of the unknown parameters of the problem.
""" """
@property @property
def unknown_variables(self): def unknown_variables(self):
""" """
The parameters of the problem. Get the unknown variables of the problem.
:return: The unknown variables of the problem.
:rtype: list[str]
""" """
return self.unknown_parameter_domain.variables return self.unknown_parameter_domain.variables
@property @property
def unknown_parameters(self): def unknown_parameters(self):
""" """
The parameters of the problem. Get the unknown parameters of the problem.
:return: The unknown parameters of the problem.
:rtype: torch.nn.Parameter
""" """
return self.__unknown_parameters return self.__unknown_parameters
@unknown_parameters.setter @unknown_parameters.setter
def unknown_parameters(self, value): def unknown_parameters(self, value):
"""
Set the unknown parameters of the problem.
:param torch.nn.Parameter value: The unknown parameters of the problem.
"""
self.__unknown_parameters = value self.__unknown_parameters = value

View File

@@ -7,26 +7,23 @@ from .abstract_problem import AbstractProblem
class ParametricProblem(AbstractProblem): class ParametricProblem(AbstractProblem):
""" """
The class for the definition of parametric problems, i.e., problems Class for defining parametric problems, where certain input variables are
with parameters among the input variables. treated as parameters that can vary, allowing the model to adapt to
different scenarios based on the chosen parameters.
Here's an example of a spatial parametric ODE problem, i.e., a spatial
ODE problem with an additional parameter `alpha` as coefficient of the
derivative term.
:Example:
TODO
""" """
@abstractmethod @abstractmethod
def parameter_domain(self): def parameter_domain(self):
""" """
The parameters' domain of the problem. The domain of the parameters of the problem.
""" """
@property @property
def parameters(self): def parameters(self):
""" """
The parameters' variables of the problem. Get the parameters of the problem.
:return: The parameters of the problem.
:rtype: list[str]
""" """
return self.parameter_domain.variables return self.parameter_domain.variables

View File

@@ -7,13 +7,8 @@ from .abstract_problem import AbstractProblem
class SpatialProblem(AbstractProblem): class SpatialProblem(AbstractProblem):
""" """
The class for the definition of spatial problems, i.e., for problems Class for defining spatial problems, where the problem domain is defined in
with spatial input variables. terms of spatial variables.
Here's an example of a spatial 1-dimensional ODE problem.
:Example:
TODO
""" """
@abstractmethod @abstractmethod
@@ -25,6 +20,9 @@ class SpatialProblem(AbstractProblem):
@property @property
def spatial_variables(self): def spatial_variables(self):
""" """
The spatial input variables of the problem. Get the spatial input variables of the problem.
:return: The spatial input variables of the problem.
:rtype: list[str]
""" """
return self.spatial_domain.variables return self.spatial_domain.variables

View File

@@ -7,13 +7,8 @@ from .abstract_problem import AbstractProblem
class TimeDependentProblem(AbstractProblem): class TimeDependentProblem(AbstractProblem):
""" """
The class for the definition of time-dependent problems, i.e., for problems Class for defining time-dependent problems, where the system's behavior
depending on time. changes with respect to time.
Here's an example of a 1D wave problem.
:Example:
TODO
""" """
@abstractmethod @abstractmethod
@@ -25,6 +20,9 @@ class TimeDependentProblem(AbstractProblem):
@property @property
def temporal_variable(self): def temporal_variable(self):
""" """
The time variable of the problem. Get the time variable of the problem.
:return: The time variable of the problem.
:rtype: list[str]
""" """
return self.temporal_domain.variables return self.temporal_domain.variables

View File

@@ -1,4 +1,4 @@
"""TODO""" """Module for implemented problems."""
__all__ = [ __all__ = [
"SupervisedProblem", "SupervisedProblem",

View File

@@ -16,7 +16,7 @@ class AdvectionEquation(Equation):
def __init__(self, c): def __init__(self, c):
""" """
Initialize the advection equation. Initialization of the :class:`AdvectionEquation`.
:param c: The advection velocity parameter. :param c: The advection velocity parameter.
:type c: float | int :type c: float | int
@@ -80,7 +80,7 @@ class AdvectionProblem(SpatialProblem, TimeDependentProblem):
def __init__(self, c=1.0): def __init__(self, c=1.0):
""" """
Initialize the advection problem. Initialization of the :class:`AdvectionProblem`.
:param c: The advection velocity parameter. :param c: The advection velocity parameter.
:type c: float | int :type c: float | int

View File

@@ -16,7 +16,7 @@ class HelmholtzEquation(Equation):
def __init__(self, alpha): def __init__(self, alpha):
""" """
Initialize the Helmholtz equation. Initialization of the :class:`HelmholtzEquation` class.
:param alpha: Parameter of the forcing term. :param alpha: Parameter of the forcing term.
:type alpha: float | int :type alpha: float | int
@@ -75,7 +75,7 @@ class HelmholtzProblem(SpatialProblem):
def __init__(self, alpha=3.0): def __init__(self, alpha=3.0):
""" """
Initialize the Helmholtz problem. Initialization of the :class:`HelmholtzProblem` class.
:param alpha: Parameter of the forcing term. :param alpha: Parameter of the forcing term.
:type alpha: float | int :type alpha: float | int

View File

@@ -2,12 +2,11 @@
from ..abstract_problem import AbstractProblem from ..abstract_problem import AbstractProblem
from ... import Condition from ... import Condition
from ... import LabelTensor
class SupervisedProblem(AbstractProblem): class SupervisedProblem(AbstractProblem):
""" """
Definition of a supervised learning problem in PINA. Definition of a supervised-learning problem.
This class provides a simple way to define a supervised problem This class provides a simple way to define a supervised problem
using a single condition of type using a single condition of type
@@ -28,7 +27,7 @@ class SupervisedProblem(AbstractProblem):
self, input_, output_, input_variables=None, output_variables=None self, input_, output_, input_variables=None, output_variables=None
): ):
""" """
Initialize the SupervisedProblem class. Initialization of the :class:`SupervisedProblem` class.
:param input_: Input data of the problem. :param input_: Input data of the problem.
:type input_: torch.Tensor | LabelTensor | Graph | Data :type input_: torch.Tensor | LabelTensor | Graph | Data