/* *** SS:=fopen("/home/mc/Desktop/SunnySpell/SS_PSO.txt",Text): read(SS) */ /* SunnySpell Written for MuPAD+Scilab Maurice.Clerc@WriteMe.com First version: 2005-08-21 Last update:2005-08-27 N points Pi in the unit D-square S. Add a point Xm so that the distribution {P1, ..., PN,Xm} is as uniform/regular as possible. Method (explanation for dimension D=2 ------ For any point X(x1,x2) in S, let s(X) be the distance of X to S, i.e. s(X)=min(x1,1-x1,x2,1-x2) We define the "isolation" ("isolement" in French) function I(X)=min(min_i(norm(X-Pi))+ s(X)) We are looking for the point Xm where this function reaches its maximum. Note: You could think a Voronoï/Delaunay tesselation does the job. It is not the case for such a method don't take into account the infinite number of points on the "frontier" of the search space, so the result may be a point to near of this "frontier". Why "SunnySpell"? ---------------- Let's suppose each point on the frontier of S, and each Pi, is the center of a disc of radius r. Such a disc can be seen as a "cloud", and S is the "sky". A point X is "covered" if it belongs to at least one "cloud". As long as r>I(Xm), all points are covered (the sky is overcast) As soon as r0 => the same "randomness" for each run (but depending on the value of rand_type) WARNING: as DIGITS is necessarily limited, the float pseudo random numbers are still a bit different for each run -1 => different for each run */ F:=2: /* Kind of function to maximize 1 => min_distances(S, Pi) 2 => min_distances( Pi, sqrt(Dim) - to Pi) (virtual sphere) 3 => use ln(1/norm) repulsion function 4 => use 1/norm repulsion function */ Dim:=2: // Dimension of the search space S. // N:=10: // Number of random points in S delta:=0.1: /* Step to discretize S (mesh), for exhaustive search, and for plot. WARNING: Plots are just for Dim=2 or 3 */ /* //--- TEST DATA (Abhi's example) // WARNING: don't forget to "remove" the random generation of known points // (see below) Dim:=2: N:=3: Pt[1,1]:=0.4:Pt[2,1]:=0.4: Pt[1,2]:=0.5:Pt[2,2]:=0.4: Pt[1,3]:=0.5:Pt[2,3]:=0.5: //--- end TEST DATA */ //---------------------------------------------- END OF DATA // ------------Define pseudo randomness case rand_type of -1 do // Different for each run SEED:=rtime(): rt:=random(1..1000):// Procedure to generate a pseudo random integer rand_t:=rt(): for i from 1 to rand_t do wait(10): end_for: seed_:=rtime(): break: otherwise // The same for each run seed_:=rand_type: SEED:=rand_type: break: end_case: //------------------------- alea:=frandom(seed_): // Random generation of the known points // WARNING: of course, you have to "remove" this line if you use // predefined data (as Abhi's example) for i from 1 to Dim do for j from 1 to N do Pt[i,j]:=alea(): end_for:end_for: P:=matrix(Dim,N,Pt): //repeat //print("N",N);print("P",P); //--------------------EXHAUSTIVE SEARCH I_max:=0: I_list:=[]: // All points of the mesh pmax:=(round(1/delta)+1)^Dim: for p from 1 to pmax do p2x(Dim,delta,p): // "row" vector x Isol(x):// Compute isolation min_i I_list:=I_list.[[list_x,min_i]]: // Just for Isolation surface plotting // Exhaustive search on the mesh (choose the max) if min_i>I_max then Xm:=X: I_max:=min_i: end_if: end_for: print("Exhaustive search on mesh:",float((1/delta)^Dim)," evaluations"): print("Xm",Xm, "Value",I_max); // The "best" new point ... //=============================================== PSO SEARCH /* Just a very basic PSO version */ print("PSO search"): /* Search space = unit D-cube but in general it is a D-parallelepid WARNING: the fitness evaluation (ISOL) is written for the unit D-cube */ for d from 1 to Dim do xmin[d]:=0 : xmax[d]:=1: dx[d]:=xmax[d]-xmin[d]: end_for: swarm_size:=round(9.5+0.124*(Dim-9)): // Cf. Annexe of "Binary PSO" study c1:=float(1/(2*ln(2))): cmax:=float(c1+2*ln(2)-1): // Cf. "Stagnation Analysis" study h_size:=3: // Nb of random links/particle alea_rank:=random(1..swarm_size): // Procedure to generate a random integer // in [1, swarm_size]. Depends on SEED stop_eval:=max(2*swarm_size,300*Dim-500): /* Purely empirical. Note that we just are actually looking for a position that is "enough isolated". */ // INITIALISATION pos:=matrix(swarm_size,Dim): vel:=matrix(swarm_size,Dim): link:=matrix(swarm_size,swarm_size): for n from 1 to swarm_size do for d from 1 to Dim do pos[n,d]:=xmin[d]+alea()*dx[d]: vel[n,d]:=dx[d]*(-0.5+alea()): end_for: pbest:=pos: end_for: // Fitness evaluation z:=coerce(pos,DOM_LIST): for n from 1 to swarm_size do Isol(z[n]): // Compute Isolation f[n]:=float(min_i): // Store fitness end_for: // Find the (rank of the) best in the swarm best_swarm:=1: for n from 2 to swarm_size do if f[n]>f[best_swarm] then best_swarm:=n: end_if: end_for: f_best_swarm:=f[best_swarm]: line_best:=coerce(linalg::row(pos,best_swarm),DOM_LIST): // Just for plotting // At the beginning, best=currentb f_best_swarm_prev:=f_best_swarm: p_best:=pos: f_best:=f: nb_eval:=0: while nb_evalf_best[g_best] then g_best:=n2: end_if: end_for: //move for d from 1 to Dim do vel[n,d]:=c1*vel[n,d]+cmax*alea()*(pbest[n,d]-pos[n,d])+cmax*alea()*(p_best[g_best,d]-pos[n,d]): pos[n,d]:=pos[n,d]+vel[n,d]: end_for: // Keep in the box for d from 1 to Dim do if pos[n,d]xmax[d] then pos[n,d]:=xmax[d]: vel[n,d]:=0:end_if: end_if: end_for: //Evaluation of the new position z:=coerce(linalg::row(pos,n),DOM_LIST): Isol(z[1]): // Compute Isolation f[n]:=min_i: // Store fitness // If improvement, change pbest, // and possibly best_swarm and f_best_swarm if f[n]>f_best[n] then f_best[n]:=f[n]: for d from 1 to Dim do pbest[n,d]:=pos[n,d]: end_for: if f_best[n]>f_best_swarm then best_swarm:=n: f_best_swarm:=f_best[best_swarm]: line_best:=line_best.coerce(linalg::row(pos,best_swarm),DOM_LIST): end_if: end_if: end_for: f_best_swarm_prev:=f_best[best_swarm]: //print("Iter",iter," Best",f_best_swarm_prev): end_while: best_pos:=linalg::row(pbest,best_swarm): print("PSO search:",nb_eval," evaluations"): print("Best position",best_pos): print("Best value",f_best_swarm_prev): //Just for plotting Xm_pso:=linalg::transpose(best_pos): //===================================== PLOTTING case Dim of 2 do // The square A1:=[0,0]: A2:=[1,0]: A3:=[1,1]: A4:=[0,1]: S:=plot::Polygon2d([A1,A2,A3,A4]): // The Pi points pi:=plot::PointList2d([[P[1,i],P[2,i]] $ i=1..N]): // The "improvement line" line:=plot::Polygon2d(line_best): // The "best" new point xm:=plot::Point2d(Xm[1],Xm[2],PointSize=3*unit::mm,PointColor=RGB::Green): xm_pso:=plot::Point2d(Xm_pso[1],Xm_pso[2],PointSize=3*unit::mm,PointColor=RGB::Red): // Plots plot(S,pi,xm,line,xm_pso): // Square, Pi, Xm // Isolation surface // (OK, it is not the fastest method, but it is easy to code...) grid:=[]: mesh:=round(1/delta): // Normalize the "height" of the surface max_z:=0: for k from 1 to nops(I_list) do max_z:=max(max_z,I_list[k][3]): end_for: for k from 1 to nops(I_list) do I_list[k][3]:= I_list[k][3]/max_z: end_for: for k1 from 1 to mesh do for k2 from 1 to mesh do k:=round((mesh+1)*(k1-1) + k2): square:=I_list[k].I_list[k+1].I_list[k+2+mesh].I_list[k+1+mesh]: grid:=grid.[].square: end_for: end_for: Xm3:=plot::Sphere(0.02,[Xm[1],Xm[2],I_max],Color=RGB::Green): I_surface:=plot::SurfaceSet(grid,MeshListType=Quads): plot(I_surface,Xm3): break: of 3 do A[1]:=[0,0,0]:A[2]:=[1,0,0]: A[3]:=[0,1,0]:A[4]:=[0,0,1]: A[5]:=[1,1,0]:A[6]:=[0,1,1]: A[7]:=[1,0,1]:A[8]:=[1,1,1]: Cube:=plot::PointList3d([A[i] $ i=1..8],PointSize=0.01): // The Pi points pi:=plot::PointList3d([[P[1,i],P[2,i],P[3,i]] $ i=1..N]): // The "improvement line" line:=plot::Polygon3d(line_best): // The "best" new point Xm3:=plot::Point3d(Xm[1],Xm[2],Xm[3],PointSize=3*unit::mm,PointColor=RGB::Green): xm_pso:=plot::Point3d(Xm_pso[1],Xm_pso[2],Xm_pso[3],PointSize=3*unit::mm,PointColor=RGB::Red): //Xm3:=plot::Sphere(0.02,[Xm[1],Xm[2],Xm[3]],Color=RGB::Green): // Plots plot(Cube,pi,Xm3,line,xm_pso): // Square, Pi, Xm break: otherwise print("No plots for Dim=",Dim): break: end_case: