From 5616e873137f4215c5700e9f6b4c476ac60230ad Mon Sep 17 00:00:00 2001 From: Jean-Philippe ARGAUD Date: Sun, 28 Feb 2021 13:13:43 +0100 Subject: [PATCH] Improvement and documentation of state initialization --- doc/en/snippets/InitializationPoint.rst | 6 +++--- doc/fr/snippets/InitializationPoint.rst | 6 +++--- src/daComposant/daAlgorithms/4DVAR.py | 10 +--------- .../daAlgorithms/NonLinearLeastSquares.py | 7 ++++++- .../daAlgorithms/QuantileRegression.py | 10 +--------- src/daComposant/daCore/BasicObjects.py | 13 +++++++++++++ src/daComposant/daCore/NumericObjects.py | 18 +++--------------- src/daComposant/daCore/Persistence.py | 18 +++++++++--------- 8 files changed, 39 insertions(+), 49 deletions(-) diff --git a/doc/en/snippets/InitializationPoint.rst b/doc/en/snippets/InitializationPoint.rst index 3c8f356..e9b1594 100644 --- a/doc/en/snippets/InitializationPoint.rst +++ b/doc/en/snippets/InitializationPoint.rst @@ -3,9 +3,9 @@ InitializationPoint *Vector*. The variable specifies one vector to be used as the initial state around which an iterative algorithm starts. By default, this initial state is - not required and is equal to the background :math:`\mathbf{x}^b`. If - provided, it replaces the background only for initialization. Its value must - allow to build a vector of the same size as the background. + not required and is equal to the background :math:`\mathbf{x}^b`. Its value + must allow to build a vector of the same size as the background. If provided, + it replaces the background only for initialization. Example : ``{"InitializationPoint":[1, 2, 3, 4, 5]}`` diff --git a/doc/fr/snippets/InitializationPoint.rst b/doc/fr/snippets/InitializationPoint.rst index 385df56..054826f 100644 --- a/doc/fr/snippets/InitializationPoint.rst +++ b/doc/fr/snippets/InitializationPoint.rst @@ -4,9 +4,9 @@ InitializationPoint *Vecteur*. La variable désigne un vecteur à utiliser comme l'état initial autour duquel démarre un algorithme itératif. Par défaut, cet état initial n'a pas besoin d'être fourni et il est égal à l'ébauche :math:`\mathbf{x}^b`. - Dans le cas où il est fourni, il ne remplace l'ébauche que pour - l'initialisation. Sa valeur doit permettre de construire un vecteur de taille - identique à l'ébauche. + Sa valeur doit permettre de construire un vecteur de taille identique à + l'ébauche. Dans le cas où il est fourni, il ne remplace l'ébauche que pour + l'initialisation. Exemple : ``{"InitializationPoint":[1, 2, 3, 4, 5]}`` diff --git a/src/daComposant/daAlgorithms/4DVAR.py b/src/daComposant/daAlgorithms/4DVAR.py index bf7bd8e..75aeff3 100644 --- a/src/daComposant/daAlgorithms/4DVAR.py +++ b/src/daComposant/daAlgorithms/4DVAR.py @@ -267,15 +267,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): # # Point de démarrage de l'optimisation # ------------------------------------ - if self._parameters["InitializationPoint"] is not None: - __ipt = numpy.ravel(self._parameters["InitializationPoint"]) - if __ipt.size != numpy.ravel(Xb).size: - raise ValueError("Incompatible size %i of forced initial point to replace the Xb of size %i" \ - %(__ipt.size,numpy.ravel(Xb).size)) - else: - Xini = __ipt - else: - Xini = numpy.ravel(Xb) + Xini = self._parameters["InitializationPoint"] # # Minimisation de la fonctionnelle # -------------------------------- diff --git a/src/daComposant/daAlgorithms/NonLinearLeastSquares.py b/src/daComposant/daAlgorithms/NonLinearLeastSquares.py index 54c0336..65b6fe4 100644 --- a/src/daComposant/daAlgorithms/NonLinearLeastSquares.py +++ b/src/daComposant/daAlgorithms/NonLinearLeastSquares.py @@ -101,6 +101,11 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "Bounds", message = "Liste des valeurs de bornes", ) + self.defineRequiredParameter( + name = "InitializationPoint", + typecast = numpy.ravel, + message = "État initial imposé (par défaut, c'est l'ébauche si None)", + ) self.requireInputArguments( mandatory= ("Xb", "Y", "HO", "R"), ) @@ -223,7 +228,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): # # Point de démarrage de l'optimisation : Xini = Xb # ------------------------------------ - Xini = numpy.ravel(Xb) + Xini = self._parameters["InitializationPoint"] # # Minimisation de la fonctionnelle # -------------------------------- diff --git a/src/daComposant/daAlgorithms/QuantileRegression.py b/src/daComposant/daAlgorithms/QuantileRegression.py index 36f4e06..37ea503 100644 --- a/src/daComposant/daAlgorithms/QuantileRegression.py +++ b/src/daComposant/daAlgorithms/QuantileRegression.py @@ -147,15 +147,7 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): # # Point de démarrage de l'optimisation # ------------------------------------ - if self._parameters["InitializationPoint"] is not None: - __ipt = numpy.ravel(self._parameters["InitializationPoint"]) - if __ipt.size != numpy.ravel(Xb).size: - raise ValueError("Incompatible size %i of forced initial point to replace the Xb of size %i" \ - %(__ipt.size,numpy.ravel(Xb).size)) - else: - Xini = __ipt - else: - Xini = numpy.ravel(Xb) + Xini = self._parameters["InitializationPoint"] # # Minimisation de la fonctionnelle # -------------------------------- diff --git a/src/daComposant/daCore/BasicObjects.py b/src/daComposant/daCore/BasicObjects.py index 3143c8b..66e9ab9 100644 --- a/src/daComposant/daCore/BasicObjects.py +++ b/src/daComposant/daCore/BasicObjects.py @@ -764,6 +764,19 @@ class Algorithm(object): else: self._parameters["Bounds"] = None # + # Corrections et compléments de l'initialisation en X + if "InitializationPoint" in self._parameters: + if Xb is not None: + if self._parameters["InitializationPoint"] is not None and hasattr(self._parameters["InitializationPoint"],'size'): + if self._parameters["InitializationPoint"].size != numpy.ravel(Xb).size: + raise ValueError("Incompatible size %i of forced initial point that have to replace the background of size %i" \ + %(self._parameters["InitializationPoint"].size,numpy.ravel(Xb).size)) + # Obtenu par typecast : numpy.ravel(self._parameters["InitializationPoint"]) + else: + self._parameters["InitializationPoint"] = numpy.ravel(Xb) + else: + if self._parameters["InitializationPoint"] is None: + raise ValueError("Forced initial point can not be set without any given Background or required value") if logging.getLogger().level < logging.WARNING: self._parameters["optiprint"], self._parameters["optdisp"] = 1, 1 if PlatformInfo.has_scipy: diff --git a/src/daComposant/daCore/NumericObjects.py b/src/daComposant/daCore/NumericObjects.py index 253e382..ba21836 100644 --- a/src/daComposant/daCore/NumericObjects.py +++ b/src/daComposant/daCore/NumericObjects.py @@ -684,13 +684,7 @@ def std3dvar(selfA, Xb, Y, U, HO, EM, CM, R, B, Q): # # Point de démarrage de l'optimisation # ------------------------------------ - if selfA._parameters["InitializationPoint"] is not None: - Xini = numpy.ravel(selfA._parameters["InitializationPoint"]) - if Xini.size != numpy.ravel(Xb).size: - raise ValueError("Incompatible size %i of forced initial point to replace the Xb of size %i" \ - %(Xini.size,numpy.ravel(Xb).size)) - else: - Xini = numpy.ravel(Xb) + Xini = selfA._parameters["InitializationPoint"] # # Définition de la fonction-coût # ------------------------------ @@ -1235,13 +1229,7 @@ def incr3dvar(selfA, Xb, Y, U, HO, EM, CM, R, B, Q): RI = R.getI() # # Point de démarrage de l'optimisation - if selfA._parameters["InitializationPoint"] is not None: - Xini = numpy.ravel(selfA._parameters["InitializationPoint"]) - if Xini.size != numpy.ravel(Xb).size: - raise ValueError("Incompatible size %i of forced initial point to replace the Xb of size %i" \ - %(Xini.size,numpy.ravel(Xb).size)) - else: - Xini = numpy.ravel(Xb) + Xini = selfA._parameters["InitializationPoint"] # HXb = numpy.asmatrix(numpy.ravel( Hm( Xb ) )).T Innovation = Y - HXb @@ -1251,7 +1239,7 @@ def incr3dvar(selfA, Xb, Y, U, HO, EM, CM, R, B, Q): iOuter = 0 J = 1./mpr DeltaJ = 1./mpr - Xr = Xini[:,None] + Xr = Xini.reshape((-1,1)) while abs(DeltaJ) >= selfA._parameters["CostDecrementTolerance"] and iOuter <= selfA._parameters["MaximumNumberOfSteps"]: # # Inner Loop diff --git a/src/daComposant/daCore/Persistence.py b/src/daComposant/daCore/Persistence.py index 0cf2b71..08a3a63 100644 --- a/src/daComposant/daCore/Persistence.py +++ b/src/daComposant/daCore/Persistence.py @@ -718,8 +718,8 @@ class OneMatrix(Persistence): class OneList(Persistence): """ - Classe de stockage d'une liste de valeurs hétérogènes (list) par pas. Ne pas - utiliser cette classe pour des données numériques homogènes, mais + Classe de stockage d'une liste de valeurs hétérogènes (list) par pas. Ne + pas utiliser cette classe pour des données numériques homogènes, mais "OneVector". """ def __init__(self, name="", unit="", basetype = list): @@ -733,8 +733,8 @@ class OneNoType(Persistence): """ Classe de stockage d'un objet sans modification (cast) de type. Attention, selon le véritable type de l'objet stocké à chaque pas, les opérations - arithmétiques à base de numpy peuvent être invalides ou donner des résultats - inattendus. Cette classe n'est donc à utiliser qu'à bon escient + arithmétiques à base de numpy peuvent être invalides ou donner des + résultats inattendus. Cette classe n'est donc à utiliser qu'à bon escient volontairement, et pas du tout par défaut. """ def __init__(self, name="", unit="", basetype = NoType): @@ -753,9 +753,9 @@ class CompositePersistence(object): """ name : nom courant - La gestion interne des données est exclusivement basée sur les variables - initialisées ici (qui ne sont pas accessibles depuis l'extérieur des - objets comme des attributs) : + La gestion interne des données est exclusivement basée sur les + variables initialisées ici (qui ne sont pas accessibles depuis + l'extérieur des objets comme des attributs) : __StoredObjects : objets de type persistence collectés dans cet objet """ self.__name = str(name) @@ -791,8 +791,8 @@ class CompositePersistence(object): def add_object(self, name=None, persistenceType=Persistence, basetype=None ): """ - Ajoute dans les objets stockables un nouvel objet défini par son nom, son - type de Persistence et son type de base à chaque pas. + Ajoute dans les objets stockables un nouvel objet défini par son nom, + son type de Persistence et son type de base à chaque pas. """ if name is None: raise ValueError("Object name is required for adding an object.") if name in self.__StoredObjects.keys(): -- 2.39.2