From b9ce2799e5e42ba9ede54e482c50f77542329865 Mon Sep 17 00:00:00 2001 From: Jean-Philippe ARGAUD Date: Wed, 5 May 2021 18:34:16 +0200 Subject: [PATCH] Minor corrections for state bounds internal treatment --- src/daComposant/daAlgorithms/3DVAR.py | 15 +++++++++-- src/daComposant/daAlgorithms/Blue.py | 13 ++++++++- src/daComposant/daAlgorithms/ExtendedBlue.py | 13 ++++++++- src/daComposant/daCore/BasicObjects.py | 11 +++++++- src/daComposant/daCore/NumericObjects.py | 28 +++++++++++++++++--- 5 files changed, 71 insertions(+), 9 deletions(-) diff --git a/src/daComposant/daAlgorithms/3DVAR.py b/src/daComposant/daAlgorithms/3DVAR.py index fa5e47c..3879f39 100644 --- a/src/daComposant/daAlgorithms/3DVAR.py +++ b/src/daComposant/daAlgorithms/3DVAR.py @@ -162,12 +162,23 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "SimulationForQuantiles", default = "Linear", typecast = str, - message = "Type de simulation pour l'estimation des quantiles", + message = "Type de simulation en estimation des quantiles", listval = ["Linear", "NonLinear"] ) self.defineRequiredParameter( # Pas de type name = "Bounds", - message = "Liste des valeurs de bornes", + message = "Liste des paires de bornes", + ) + self.defineRequiredParameter( # Pas de type + name = "QBounds", + message = "Liste des paires de bornes pour les états utilisés en estimation des quantiles", + ) + self.defineRequiredParameter( + name = "ConstrainedBy", + default = "EstimateProjection", + typecast = str, + message = "Prise en compte des contraintes", + listval = ["EstimateProjection"], ) self.defineRequiredParameter( name = "InitializationPoint", diff --git a/src/daComposant/daAlgorithms/Blue.py b/src/daComposant/daAlgorithms/Blue.py index 20d6626..006873e 100644 --- a/src/daComposant/daAlgorithms/Blue.py +++ b/src/daComposant/daAlgorithms/Blue.py @@ -92,9 +92,20 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "SimulationForQuantiles", default = "Linear", typecast = str, - message = "Type de simulation pour l'estimation des quantiles", + message = "Type de simulation en estimation des quantiles", listval = ["Linear", "NonLinear"] ) + self.defineRequiredParameter( # Pas de type + name = "QBounds", + message = "Liste des paires de bornes pour les états utilisés en estimation des quantiles", + ) + self.defineRequiredParameter( + name = "ConstrainedBy", + default = "EstimateProjection", + typecast = str, + message = "Prise en compte des contraintes", + listval = ["EstimateProjection"], + ) self.requireInputArguments( mandatory= ("Xb", "Y", "HO", "R", "B"), ) diff --git a/src/daComposant/daAlgorithms/ExtendedBlue.py b/src/daComposant/daAlgorithms/ExtendedBlue.py index 7690638..60aa9a4 100644 --- a/src/daComposant/daAlgorithms/ExtendedBlue.py +++ b/src/daComposant/daAlgorithms/ExtendedBlue.py @@ -92,9 +92,20 @@ class ElementaryAlgorithm(BasicObjects.Algorithm): name = "SimulationForQuantiles", default = "Linear", typecast = str, - message = "Type de simulation pour l'estimation des quantiles", + message = "Type de simulation en estimation des quantiles", listval = ["Linear", "NonLinear"] ) + self.defineRequiredParameter( # Pas de type + name = "QBounds", + message = "Liste des paires de bornes pour les états utilisés en estimation des quantiles", + ) + self.defineRequiredParameter( + name = "ConstrainedBy", + default = "EstimateProjection", + typecast = str, + message = "Prise en compte des contraintes", + listval = ["EstimateProjection"], + ) self.requireInputArguments( mandatory= ("Xb", "Y", "HO", "R", "B"), ) diff --git a/src/daComposant/daCore/BasicObjects.py b/src/daComposant/daCore/BasicObjects.py index 7b8953a..80d682d 100644 --- a/src/daComposant/daCore/BasicObjects.py +++ b/src/daComposant/daCore/BasicObjects.py @@ -765,9 +765,12 @@ class Algorithm(object): # # Corrections et compléments des bornes if ("Bounds" in self._parameters) and isinstance(self._parameters["Bounds"], (list, tuple)) and (len(self._parameters["Bounds"]) > 0): - logging.debug("%s Prise en compte des bornes effectuee"%(self._name,)) + logging.debug("%s Bounds taken into account"%(self._name,)) else: self._parameters["Bounds"] = None + if ("QBounds" in self._parameters) and isinstance(self._parameters["QBounds"], (list, tuple)) and (len(self._parameters["QBounds"]) > 0): + logging.debug("%s Bounds for quantiles states taken into account"%(self._name,)) + # Attention : contrairement à Bounds, pas de défaut à None, sinon on ne peut pas être sans bornes # # Corrections et compléments de l'initialisation en X if "InitializationPoint" in self._parameters: @@ -1395,6 +1398,12 @@ class AlgorithmAndParameters(object): raise ValueError("The number \"%s\" of bound pairs for the state (X) components is different of the size \"%s\" of the state itself." \ %(len(self.__P["Bounds"]),max(__Xb_shape))) # + if ("QBounds" in self.__P) \ + and (isinstance(self.__P["QBounds"], list) or isinstance(self.__P["QBounds"], tuple)) \ + and (len(self.__P["QBounds"]) != max(__Xb_shape)): + raise ValueError("The number \"%s\" of bound pairs for the quantile state (X) components is different of the size \"%s\" of the state itself." \ + %(len(self.__P["QBounds"]),max(__Xb_shape))) + # return 1 # ============================================================================== diff --git a/src/daComposant/daCore/NumericObjects.py b/src/daComposant/daCore/NumericObjects.py index 85d134a..737180a 100644 --- a/src/daComposant/daCore/NumericObjects.py +++ b/src/daComposant/daCore/NumericObjects.py @@ -649,20 +649,40 @@ def QuantilesEstimations(selfA, A, Xa, HXa = None, Hm = None, HtM = None): "Estimation des quantiles a posteriori (selfA est modifié)" nbsamples = selfA._parameters["NumberOfSamplesForQuantiles"] # + # Traitement des bornes + if "QBounds" in selfA._parameters: LBounds = selfA._parameters["QBounds"] # Prioritaire + else: LBounds = selfA._parameters["Bounds"] # Défaut raisonnable + if LBounds is not None: + def NoneRemove(paire): + bmin, bmax = paire + if bmin is None: bmin = numpy.finfo('float').min + if bmax is None: bmax = numpy.finfo('float').max + return [bmin, bmax] + LBounds = numpy.matrix( [NoneRemove(paire) for paire in LBounds] ) + # # Échantillonnage des états YfQ = None EXr = None - if selfA._parameters["SimulationForQuantiles"] == "Linear": + if selfA._parameters["SimulationForQuantiles"] == "Linear" and HXa is not None: HXa = numpy.matrix(numpy.ravel( HXa )).T for i in range(nbsamples): if selfA._parameters["SimulationForQuantiles"] == "Linear" and HtM is not None: - dXr = numpy.matrix(numpy.random.multivariate_normal(Xa.A1,A) - Xa.A1).T + dXr = numpy.matrix(numpy.random.multivariate_normal(numpy.ravel(Xa),A) - numpy.ravel(Xa)).T + if LBounds is not None and selfA._parameters["ConstrainedBy"] == "EstimateProjection": + dXr = numpy.max(numpy.hstack((dXr,LBounds[:,0]) - Xa),axis=1) + dXr = numpy.min(numpy.hstack((dXr,LBounds[:,1]) - Xa),axis=1) dYr = numpy.matrix(numpy.ravel( HtM * dXr )).T Yr = HXa + dYr - if selfA._toStore("SampledStateForQuantiles"): Xr = Xa+dXr + if selfA._toStore("SampledStateForQuantiles"): Xr = Xa + dXr elif selfA._parameters["SimulationForQuantiles"] == "NonLinear" and Hm is not None: - Xr = numpy.matrix(numpy.random.multivariate_normal(Xa.A1,A)).T + Xr = numpy.matrix(numpy.random.multivariate_normal(numpy.ravel(Xa),A)).T + if LBounds is not None and selfA._parameters["ConstrainedBy"] == "EstimateProjection": + Xr = numpy.max(numpy.hstack((Xr,LBounds[:,0])),axis=1) + Xr = numpy.min(numpy.hstack((Xr,LBounds[:,1])),axis=1) Yr = numpy.matrix(numpy.ravel( Hm( Xr ) )).T + else: + raise ValueError("Quantile simulations has only to be Linear or NonLinear.") + # if YfQ is None: YfQ = Yr if selfA._toStore("SampledStateForQuantiles"): EXr = numpy.ravel(Xr) -- 2.39.2