1 // Created on: 2014-07-18
2 // Created by: Alexander Malyshev
3 // Copyright (c) 2014-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #include <math_PSO.hxx>
18 #include <math_BullardGenerator.hxx>
19 #include <math_PSOParticlesPool.hxx>
21 const Standard_Real aBorderDivisor = 1.0e+4;
23 //=======================================================================
25 //purpose : Constructor
26 //=======================================================================
27 math_PSO::math_PSO(math_MultipleVarFunction* theFunc,
28 const math_Vector& theLowBorder,
29 const math_Vector& theUppBorder,
30 const math_Vector& theSteps,
31 const Standard_Integer theNbParticles,
32 const Standard_Integer theNbIter)
33 : myLowBorder(1, theFunc->NbVariables()),
34 myUppBorder(1, theFunc->NbVariables()),
35 mySteps(1, theFunc->NbVariables())
37 myN = theFunc->NbVariables();
38 myNbParticles = theNbParticles;
42 myLowBorder = theLowBorder;
43 myUppBorder = theUppBorder;
47 //=======================================================================
50 //=======================================================================
51 void math_PSO::Perform(math_PSOParticlesPool& theParticles,
52 Standard_Integer theNbParticles,
53 Standard_Real& theValue,
54 math_Vector& theOutPnt,
55 const Standard_Integer theNbIter)
57 performPSOWithGivenParticles(theParticles, theNbParticles, theValue, theOutPnt, theNbIter);
60 //=======================================================================
63 //=======================================================================
64 void math_PSO::Perform(const math_Vector& theSteps,
65 Standard_Real& theValue,
66 math_Vector& theOutPnt,
67 const Standard_Integer theNbIter)
70 math_Vector aMinUV(1, myN), aMaxUV(1, myN);
71 aMinUV = myLowBorder + (myUppBorder - myLowBorder) / aBorderDivisor;
72 aMaxUV = myUppBorder - (myUppBorder - myLowBorder) / aBorderDivisor;
76 // To generate initial distribution it is necessary to have grid steps.
77 math_PSOParticlesPool aPool(myNbParticles, myN);
79 // Generate initial particles distribution.
80 Standard_Boolean isRegularGridFinished = Standard_False;
81 Standard_Real aCurrValue;
82 math_Vector aCurrPoint(1, myN);
84 PSO_Particle* aParticle = aPool.GetWorstParticle();
88 myFunc->Value(aCurrPoint, aCurrValue);
90 if (aCurrValue < aParticle->Distance)
92 Standard_Integer aDimIdx;
93 for(aDimIdx = 0; aDimIdx < myN; ++aDimIdx)
95 aParticle->Position[aDimIdx] = aCurrPoint(aDimIdx + 1);
96 aParticle->BestPosition[aDimIdx] = aCurrPoint(aDimIdx + 1);
98 aParticle->Distance = aCurrValue;
99 aParticle->BestDistance = aCurrValue;
101 aParticle = aPool.GetWorstParticle();
105 aCurrPoint(1) += Max(mySteps(1), 1.0e-15); // Avoid too small step
106 for(Standard_Integer aDimIdx = 1; aDimIdx < myN; ++aDimIdx)
108 if(aCurrPoint(aDimIdx) > aMaxUV(aDimIdx))
110 aCurrPoint(aDimIdx) = aMinUV(aDimIdx);
111 aCurrPoint(aDimIdx + 1) += mySteps(aDimIdx + 1);
118 if(aCurrPoint(myN) > aMaxUV(myN))
119 isRegularGridFinished = Standard_True;
121 while(!isRegularGridFinished);
123 performPSOWithGivenParticles(aPool, myNbParticles, theValue, theOutPnt, theNbIter);
126 //=======================================================================
127 //function : math_PSO
129 //=======================================================================
130 void math_PSO::performPSOWithGivenParticles(math_PSOParticlesPool& theParticles,
131 Standard_Integer theNbParticles,
132 Standard_Real& theValue,
133 math_Vector& theOutPnt,
134 const Standard_Integer theNbIter)
136 math_Vector aMinUV(1, myN), aMaxUV(1, myN);
137 aMinUV = myLowBorder + (myUppBorder - myLowBorder) / aBorderDivisor;
138 aMaxUV = myUppBorder - (myUppBorder - myLowBorder) / aBorderDivisor;
139 myNbIter = theNbIter;
140 myNbParticles = theNbParticles;
141 math_PSOParticlesPool& aParticles = theParticles;
143 // Current particle data.
144 math_Vector aCurrPoint(1, myN);
145 math_Vector aBestGlobalPosition(1, myN);
146 PSO_Particle* aParticle = 0;
149 // Generate initial particle velocities.
150 math_BullardGenerator aRandom;
151 for (Standard_Integer aPartIdx = 1; aPartIdx <= myNbParticles; ++aPartIdx)
153 aParticle = aParticles.GetParticle(aPartIdx);
154 for(Standard_Integer aDimIdx = 1; aDimIdx <= myN; ++aDimIdx)
156 const Standard_Real aKsi = aRandom.NextReal();
157 aParticle->Velocity[aDimIdx - 1] = mySteps(aDimIdx) * (aKsi - 0.5) * 2.0;
161 aParticle = aParticles.GetBestParticle();
162 for(Standard_Integer aDimIdx = 0; aDimIdx < myN; ++aDimIdx)
163 aBestGlobalPosition(aDimIdx + 1) = aParticle->Position[aDimIdx];
164 Standard_Real aBestGlobalDistance = aParticle->Distance;
166 // This velocity is used for detecting stagnation state.
167 math_Vector aTerminationVelocity(1, myN);
168 aTerminationVelocity = mySteps / 2048.0;
169 // This velocity shows minimal velocity on current step.
170 math_Vector aMinimalVelocity(1, myN);
172 // Run PSO iterations
173 for (Standard_Integer aStep = 1; aStep < myNbIter; ++aStep)
175 aMinimalVelocity.Init(RealLast());
177 for (Standard_Integer aPartIdx = 1; aPartIdx <= myNbParticles; ++aPartIdx)
179 const Standard_Real aKsi1 = aRandom.NextReal();
180 const Standard_Real aKsi2 = aRandom.NextReal();
182 aParticle = aParticles.GetParticle(aPartIdx);
184 const Standard_Real aRetentWeight = 0.72900;
185 const Standard_Real aPersonWeight = 1.49445;
186 const Standard_Real aSocialWeight = 1.49445;
188 for(Standard_Integer aDimIdx = 0; aDimIdx < myN; ++aDimIdx)
190 aParticle->Velocity[aDimIdx] = aParticle->Velocity[aDimIdx] * aRetentWeight
191 + (aParticle->BestPosition[aDimIdx] - aParticle->Position[aDimIdx]) * (aPersonWeight * aKsi1)
192 + (aBestGlobalPosition(aDimIdx + 1) - aParticle->Position[aDimIdx]) * (aSocialWeight * aKsi2);
194 aParticle->Position[aDimIdx] += aParticle->Velocity[aDimIdx];
195 aParticle->Position[aDimIdx] = Min(Max(aParticle->Position[aDimIdx], aMinUV(aDimIdx + 1)),
196 aMaxUV(aDimIdx + 1));
197 aCurrPoint(aDimIdx + 1) = aParticle->Position[aDimIdx];
199 aMinimalVelocity(aDimIdx + 1) = Min(Abs(aParticle->Velocity[aDimIdx]),
200 aMinimalVelocity(aDimIdx + 1));
203 myFunc->Value(aCurrPoint, aParticle->Distance);
204 if(aParticle->Distance < aParticle->BestDistance)
206 aParticle->BestDistance = aParticle->Distance;
207 for(Standard_Integer aDimIdx = 0; aDimIdx < myN; ++aDimIdx)
208 aParticle->BestPosition[aDimIdx] = aParticle->Position[aDimIdx];
210 if(aParticle->Distance < aBestGlobalDistance)
212 aBestGlobalDistance = aParticle->Distance;
213 for(Standard_Integer aDimIdx = 0; aDimIdx < myN; ++aDimIdx)
214 aBestGlobalPosition(aDimIdx + 1) = aParticle->Position[aDimIdx];
219 Standard_Boolean isTerminalVelocityReached = Standard_True;
220 for(Standard_Integer aDimIdx = 1; aDimIdx <= myN; ++aDimIdx)
222 if(aMinimalVelocity(aDimIdx) > aTerminationVelocity(aDimIdx))
224 isTerminalVelocityReached = Standard_False;
229 if(isTerminalVelocityReached)
231 // Minimum number of steps
232 const Standard_Integer aMinSteps = 16;
234 if (aStep > aMinSteps)
239 for (Standard_Integer aPartIdx = 1; aPartIdx <= myNbParticles; ++aPartIdx)
241 const Standard_Real aKsi = aRandom.NextReal();
243 aParticle = aParticles.GetParticle(aPartIdx);
245 for(Standard_Integer aDimIdx = 0; aDimIdx < myN; ++aDimIdx)
247 if (aParticle->Position[aDimIdx] == aMinUV(aDimIdx + 1) ||
248 aParticle->Position[aDimIdx] == aMaxUV(aDimIdx + 1))
250 aParticle->Velocity[aDimIdx] = aParticle->Position[aDimIdx] == aMinUV(aDimIdx + 1) ?
251 mySteps(aDimIdx + 1) * aKsi : -mySteps(aDimIdx + 1) * aKsi;
255 aParticle->Velocity[aDimIdx] = mySteps(aDimIdx + 1) * (aKsi - 0.5) * 2.0;
261 theValue = aBestGlobalDistance;
262 theOutPnt = aBestGlobalPosition;