]> SALOME platform Git repositories - modules/adao.git/commitdiff
Salome HOME
Code review and update for PSO
authorJean-Philippe ARGAUD <jean-philippe.argaud@edf.fr>
Tue, 25 Apr 2023 09:16:48 +0000 (11:16 +0200)
committerJean-Philippe ARGAUD <jean-philippe.argaud@edf.fr>
Tue, 25 Apr 2023 09:16:48 +0000 (11:16 +0200)
src/daComposant/daAlgorithms/Atoms/ecwnpso.py
src/daComposant/daAlgorithms/Atoms/ecwopso.py
src/daComposant/daCore/Interfaces.py
src/daComposant/daCore/NumericObjects.py

index ef7c9d310c7096c16c707d4883b458cc0abcff05..7fc546ae227ee8c56620e4f9f9bf64030651d0b8 100644 (file)
 # Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D
 
 __doc__ = """
-    Standard Particle Swarm Optimization
+    Canonical Particle Swarm Optimization
 """
 __author__ = "Jean-Philippe ARGAUD"
 
 import numpy, logging, copy
-from daCore.NumericObjects import ApplyBounds, ForceNumericBounds
+from daCore.NumericObjects import ApplyBounds, VariablesAndIncrementsBounds
 from numpy.random import uniform as rand
 
 # ==============================================================================
 def ecwnpso(selfA, Xb, Y, HO, R, B):
-    #
-    if ("BoxBounds" in selfA._parameters) and isinstance(selfA._parameters["BoxBounds"], (list, tuple)) and (len(selfA._parameters["BoxBounds"]) > 0):
-        BoxBounds = selfA._parameters["BoxBounds"]
-        logging.debug("%s Prise en compte des bornes d'incréments de paramètres effectuée"%(selfA._name,))
-    else:
-        raise ValueError("Particle Swarm Optimization requires bounds on all variables increments to be truly given (BoxBounds).")
-    BoxBounds   = numpy.array(BoxBounds)
-    if numpy.isnan(BoxBounds).any():
-        raise ValueError("Particle Swarm Optimization requires bounds on all variables increments to be truly given (BoxBounds), \"None\" is not allowed. The actual increments bounds are:\n%s"%BoxBounds)
-    #
-    selfA._parameters["Bounds"] = ForceNumericBounds( selfA._parameters["Bounds"] )
     #
     Hm = HO["Direct"].appliedTo
     #
@@ -50,6 +39,13 @@ def ecwnpso(selfA, Xb, Y, HO, R, B):
     #
     Xini = selfA._parameters["InitializationPoint"]
     #
+    Bounds, BoxBounds = VariablesAndIncrementsBounds(
+        selfA._parameters["Bounds"],
+        selfA._parameters["BoxBounds"],
+        Xini,
+        selfA._name,
+        )
+    #
     def CostFunction(x, QualityMeasure="AugmentedWeightedLeastSquares"):
         _X  = numpy.asarray( x ).reshape((-1,1))
         _HX = numpy.asarray( Hm( _X ) ).reshape((-1,1))
@@ -104,16 +100,15 @@ def ecwnpso(selfA, Xb, Y, HO, R, B):
     #
     # Initialisation de l'essaim
     # --------------------------
-    LimitStep  = Xini.reshape((-1,1)) + BoxBounds
-    __dx = __vc * numpy.abs(BoxBounds[:,1]-BoxBounds[:,0])
-    LimitSpeed = numpy.vstack((-__dx,__dx)).T
+    LimitPlace = Bounds
+    LimitSpeed = 0.5 * BoxBounds # "1/2*([Xmin,Xmax]-Xini)"
     #
     NumberOfFunctionEvaluations = 1
     JXini, JbXini, JoXini = CostFunction(Xini,selfA._parameters["QualityCriterion"])
     #
     Swarm  = numpy.zeros((__nbI,3,__nbP)) # 3 car (x,v,xbest)
     for __p in range(__nbP) :
-        Swarm[:,0,__p] = rand( low=LimitStep[__p,0],  high=LimitStep[__p,1],  size=__nbI) # Position
+        Swarm[:,0,__p] = rand( low=LimitPlace[__p,0], high=LimitPlace[__p,1], size=__nbI) # Position
         Swarm[:,1,__p] = rand( low=LimitSpeed[__p,0], high=LimitSpeed[__p,1], size=__nbI) # Velocity
     logging.debug("%s Initialisation of the swarm with %i insects of size %i "%(selfA._name,Swarm.shape[0],Swarm.shape[2]))
     #
@@ -154,7 +149,7 @@ def ecwnpso(selfA, Xb, Y, HO, R, B):
             Swarm[__i,1,:] = ApplyBounds( __velins, LimitSpeed )
             # Position
             __velins  = Swarm[__i,0,:] + Swarm[__i,1,:]
-            Swarm[__i,0,:] = ApplyBounds( __velins, selfA._parameters["Bounds"] )
+            Swarm[__i,0,:] = ApplyBounds( __velins, LimitPlace )
             #
             NumberOfFunctionEvaluations += 1
             JTest, JbTest, JoTest = CostFunction(Swarm[__i,0,:],selfA._parameters["QualityCriterion"])
index 00e155f116432e72e02084ebab8fc78499eb1048..a1c7d1619834feb5f523b916a259aa6944c04f3f 100644 (file)
@@ -26,20 +26,12 @@ __doc__ = """
 __author__ = "Jean-Philippe ARGAUD"
 
 import numpy, logging, copy
+from daCore.NumericObjects import VariablesAndIncrementsBounds
 from numpy.random import uniform as rand
 
 # ==============================================================================
 def ecwopso(selfA, Xb, Y, HO, R, B):
     #
-    if ("BoxBounds" in selfA._parameters) and isinstance(selfA._parameters["BoxBounds"], (list, tuple)) and (len(selfA._parameters["BoxBounds"]) > 0):
-        BoxBounds = selfA._parameters["BoxBounds"]
-        logging.debug("%s Prise en compte des bornes d'incréments de paramètres effectuée"%(selfA._name,))
-    else:
-        raise ValueError("Particle Swarm Optimization requires bounds on all variables increments to be truly given (BoxBounds).")
-    BoxBounds   = numpy.array(BoxBounds)
-    if numpy.isnan(BoxBounds).any():
-        raise ValueError("Particle Swarm Optimization requires bounds on all variables increments to be truly given (BoxBounds), \"None\" is not allowed. The actual increments bounds are:\n%s"%BoxBounds)
-    #
     Hm = HO["Direct"].appliedTo
     #
     BI = B.getI()
@@ -47,6 +39,13 @@ def ecwopso(selfA, Xb, Y, HO, R, B):
     #
     Xini = selfA._parameters["InitializationPoint"]
     #
+    Bounds, BoxBounds = VariablesAndIncrementsBounds(
+        selfA._parameters["Bounds"],
+        selfA._parameters["BoxBounds"],
+        Xini,
+        selfA._name,
+        )
+    #
     def CostFunction(x, QualityMeasure="AugmentedWeightedLeastSquares"):
         _X  = numpy.asarray( x ).reshape((-1,1))
         _HX = numpy.asarray( Hm( _X ) ).reshape((-1,1))
@@ -101,16 +100,15 @@ def ecwopso(selfA, Xb, Y, HO, R, B):
     #
     # Initialisation de l'essaim
     # --------------------------
-    LimitStep  = Xini.reshape((-1,1)) + BoxBounds
-    __dx = __vc * numpy.abs(BoxBounds[:,1]-BoxBounds[:,0])
-    LimitSpeed = numpy.vstack((-__dx,__dx)).T
+    LimitPlace = Bounds
+    LimitSpeed = 0.5 * BoxBounds # "1/2*([Xmin,Xmax]-Xini)"
     #
     NumberOfFunctionEvaluations = 1
     JXini, JbXini, JoXini = CostFunction(Xini,selfA._parameters["QualityCriterion"])
     #
     Swarm  = numpy.zeros((__nbI,3,__nbP)) # 3 car (x,v,xbest)
     for __p in range(__nbP) :
-        Swarm[:,0,__p] = rand( low=LimitStep[__p,0],  high=LimitStep[__p,1],  size=__nbI) # Position
+        Swarm[:,0,__p] = rand( low=LimitPlace[__p,0], high=LimitPlace[__p,1], size=__nbI) # Position
         Swarm[:,1,__p] = rand( low=LimitSpeed[__p,0], high=LimitSpeed[__p,1], size=__nbI) # Velocity
     logging.debug("%s Initialisation of the swarm with %i insects of size %i "%(selfA._name,Swarm.shape[0],Swarm.shape[2]))
     #
index 5c2d66bb693d81a4a623bb5b385078239394b22c..0dbfbf4eac0304bbcf9e1b6827bc7ee867e025a2 100644 (file)
@@ -296,6 +296,8 @@ class _COMViewer(GenericCaseViewer):
                     __Dict.pop('Algorithm','')
                     __Dict.pop('Parameters','')
                     if 'SetSeed' in __Dict:__Dict['SetSeed'] = int(__Dict['SetSeed'])
+                    if 'Bounds' in __Dict and type(__Dict['Bounds']) is str:
+                        __Dict['Bounds'] = eval(__Dict['Bounds'])
                     if 'BoxBounds' in __Dict and type(__Dict['BoxBounds']) is str:
                         __Dict['BoxBounds'] = eval(__Dict['BoxBounds'])
                     if len(__Dict) > 0:
index ee25868730647af8b5a8a94d2774e4a9bc261675..2f1450369178cd6a411705f6bbc14845c139d3f0 100644 (file)
@@ -895,6 +895,20 @@ def ApplyBounds( __Vector, __Bounds, __newClip = True ):
     #
     return __Vector
 
+# ==============================================================================
+def VariablesAndIncrementsBounds( __Bounds, __BoxBounds, __Xini, __Name, __Multiplier = 1. ):
+    __Bounds    = ForceNumericBounds( __Bounds )
+    __BoxBounds = ForceNumericBounds( __BoxBounds )
+    if __Bounds is None and __BoxBounds is None:
+        raise ValueError("Algorithm %s requires bounds on all variables (by Bounds), or on all variables increments (by BoxBounds), or both, to be explicitly given."%(__Name,))
+    elif __Bounds is None and __BoxBounds is not None:
+        __Bounds    = __BoxBounds
+        logging.debug("%s Définition des bornes de paramètres à partir des bornes d'incréments courantes"%(__Name,))
+    elif __Bounds is not None and __BoxBounds is None:
+        __BoxBounds = __Multiplier * (__Bounds - __Xini.reshape((-1,1))) # "M * [Xmin,Xmax]-Xini"
+        logging.debug("%s Définition des bornes d'incréments de paramètres à partir des bornes courantes"%(__Name,))
+    return __Bounds, __BoxBounds
+
 # ==============================================================================
 def Apply3DVarRecentringOnEnsemble( __EnXn, __EnXf, __Ynpu, __HO, __R, __B, __SuppPars ):
     "Recentre l'ensemble Xn autour de l'analyse 3DVAR"