RGA 為 Real-coded Genetic Algorithm, 也就是實數編碼基因演算法, 以下為平面四連桿機構, 令其移動桿三角形頂點通過特定的 10 個座標點的尺寸合成運算.
# https://github.com/flukeskywalker/PyRGA # 原始程式為 Python2 修改為 Python3 格式 # 除了原先的最大化適應值外, 增加最小化方法設定 import numpy as np import random from math import * # 請注意各代族群數必須為 4 的倍數 class GA: # popsize must be multiple of 4 def __init__(self, obj, dim, popsize, ngen, pc, pm, etac, etam, min): self.EPSILON = 10e-6 self.INFINITY = 10e6 self.pop = [] self.fits = [] self.obj = obj self.dim = dim self.popsize = popsize self.ngen = ngen self.pc = pc self.pm = pm self.etac = etac self.etam = etam # min = 1 表最小化, min = -1 表最大化 self.min = min self.RIGID = 0 self.lowb = -self.INFINITY*np.ones(self.dim) self.highb = self.INFINITY*np.ones(self.dim) self.tourneylist = range(0, self.popsize) self.tourneysize = 2 # works for 2 for now self.bestmemyet = np.zeros(self.dim) # 若是求最大值 if self.min == -1: self.bestfityet = -np.inf else: # 若是求最小值 self.bestfityet = np.inf self.pop_init() def pop_init(self): self.pop = [np.random.rand(self.dim) for _ in range(self.popsize)] for member in self.pop: for i in range(self.dim): member[i] = self.lowb[i] + member[i]*(self.highb[i]-self.lowb[i]) self.fits = [self.obj(member) for member in self.pop] #self.pop_print() return def setbounds(self, lows, highs): for i in range(self.dim): self.lowb[i] = lows[i] self.highb[i] = highs[i] self.pop_init() return def run(self): for gen in range(self.ngen): print("Generation ", gen) self.pop = self.getnewpop() self.eval_pop() #self.pop_print() return [self.bestmemyet, self.bestfityet] def getnewpop(self): newpop = [] #self.tourneylist = range(0, self.popsize) random.shuffle(list(self.tourneylist)) self.tourneypos = 0 for i in range(0, self.popsize, 2): [p1, p2] = self.getparents() #return parents, not just indices [c1, c2] = self.xover(p1, p2) #return children, not just indices c1 = self.mutate(c1) c2 = self.mutate(c2) newpop.append(c1) newpop.append(c2) return newpop def getparents(self): if (self.popsize - self.tourneypos) < self.tourneysize: random.shuffle(list(self.tourneylist)) self.tourneypos = 0 if self.min == -1: if (self.fits[self.tourneylist[self.tourneypos]]>self.fits[self.tourneylist[self.tourneypos+1]]): p1 = self.pop[self.tourneylist[self.tourneypos]] else: p1 = self.pop[self.tourneylist[self.tourneypos+1]] else: if (self.fits[self.tourneylist[self.tourneypos]]self.fits[self.tourneylist[self.tourneypos+1]]): p2 = self.pop[self.tourneylist[self.tourneypos]] else: p2 = self.pop[self.tourneylist[self.tourneypos+1]] else: if (self.fits[self.tourneylist[self.tourneypos]] p2: p1, p2 = p2, p1 # p1 must be smaller mean = (p1+p2)*0.5 diff = (p2-p1) dist = max(min(p1-low, high-p2), 0) if (self.RIGID and diff > self.EPSILON): alpha = 1.0 + (2.0*dist/diff) umax = 1.0 - (0.5/pow(alpha, (self.etac+1.0))) seed = umax*random.random() else: seed = random.random() beta = self.getbeta(seed) if (abs(diff*beta) > self.INFINITY): beta = self.INFINITY/diff c2 = mean + beta*0.5*diff c1 = mean - beta*0.5*diff c1 = max(low, min(c1, high)) c2 = max(low, min(c2, high)) return [c1, c2] def getbeta(self, seed): if (1 - seed) < self.EPSILON: seed = 1 - self.EPSILON seed = max(0.0, seed) if seed < 0.5: beta = pow(2.0*seed, (1.0/(self.etac+1.0))) else: beta = pow((0.5/(1.0-seed)), (1.0/(self.etac+1.0))) return beta def getdelta(self, seed, delta_low, delta_high): if seed >= 1.0 - (self.EPSILON/1e3): return delta_high if seed <= (self.EPSILON/1e3): return delta_low if seed <= 0.5: dummy = 2.0*seed + (1.0 - 2.0*seed)*pow((1+delta_low), (self.etam+1.0)) delta = pow(dummy, (1.0/(self.etam+1.0))) - 1.0 else: dummy = 2.0*(1.0 - seed) + 2.0*(seed - 0.5)*pow((1-delta_high), (self.etam+1.0)) delta = 1.0 - pow(dummy, (1.0/(self.etam+1.0))) return delta def mutate(self, member): mut_member = np.zeros_like(member) for i in range(member.size): low = self.lowb[i] high = self.highb[i] if random.random() <= self.pm: # pm is simply the prob of a variable to mutate if self.RIGID: value = member[i] delta_low = max((low-value)/(high-low), -1.0) delta_high = min((high-value)/(high-low), 1.0) if abs(delta_low) self.bestfityet: # 則將此最大適應值指為目前為止最佳適應值 self.bestfityet = bestfitness # 並且將最佳族群成員指向目前最佳成員 self.bestmemyet = bestmember else: if bestfitness < self.bestfityet: self.bestfityet = bestfitness self.bestmemyet = bestmember print("Current best: ", bestfitness, "Best yet: ", self.bestfityet) def pop_print(self): for i in range(self.popsize): print(self.pop[i], self.fits[i]) return # 若單獨存在則需導入 GA 所有方法 #import GA #from GA import * import numpy as np def square(x): term1 = (x[0]*x[0]+x[1]-11.0)*(x[0]*x[0]+x[1]-11.0) term2 = (x[0]+x[1]*x[1]- 7.0)*(x[0]+x[1]*x[1]- 7.0) term3 = term1+term2 return term3 # 最大化體積題目 def volume(x): surface = 80.0 z = (surface-x[0]*x[1])/(2.0*(x[0]+x[1])) volume = x[0]*x[1]*z return volume def miniex1(x): '''Minimizing Beale's function (optimal value f(3, 0.5) = 0): ga=GA(miniex1, dim=2, popsize=400, ngen=500, pc=0.9, pm=0.3, etac=2, etam=100, min=1) ga.setbounds(np.zeros(10), 10*np.ones(10)) ''' term1 = 1.5 - x[0] + x[0]*x[1] term2 = 2.25 - x[0] + x[0]*x[1]*x[1] term3 = 2.625 - x[0] + x[0]*x[1]*x[1]*x[1] return term1*term1 + term2*term2 + term3*term3 def miniex2(x): '''Schaffer function #2. Minimium at (0,0), equal to 0 ga=GA(miniex2, dim=2, popsize=100, ngen=50, pc=0.9, pm=0.1, etac=2, etam=100, min=1) ga.setbounds(np.zeros(10), 10*np.ones(10)) ''' return 0.5 + (pow(sin(x[0]*x[0]-x[1]*x[1]), 2) - 0.5)/pow(1+0.001*(x[0]*x[0]+x[1]*x[1]), 2) ''' 開始四連桿運算 ''' class Point(object): '''Creates a point on a coordinate plane with values x and y.''' def __init__(self, x, y): '''Defines x and y variables''' self.x = x self.y = y def triangletip_coord(x0, y0, R0, R1, x1, y1, localt): mech_loop = -1 tip_coord = Point(0,0) if (localt >= 0 and localt < pi): # 計算 tip 點的 x 座標 tip_coord.x = pow(sqrt(pow(y1-y0,2)+pow(x1-x0,2)),-1)*(mech_loop*(y1-y0)*sqrt(fabs(pow(R0,2)-pow(pow(y1-y0,2)+pow(x1-x0,2),-1)*pow(-pow(R1,2)+pow(R0,2)+pow(y1-y0,2)+pow(x1-x0,2),2)/4))+(x1-x0)*pow(sqrt(pow(y1-y0,2)+pow(x1-x0,2)),-1)*(-pow(R1,2)+pow(R0,2)+pow(y1-y0,2)+pow(x1-x0,2))/2)+x0 # 計算 tip 點的 y 座標 tip_coord.y = pow(sqrt(pow(y1-y0,2)+pow(x1-x0,2)),-1)*((y1-y0)*pow(sqrt(pow(y1-y0,2)+pow(x1-x0,2)),-1)*(-pow(R1,2)+pow(R0,2)+pow(y1-y0,2)+pow(x1-x0,2))/2-mech_loop*(x1-x0)*sqrt(fabs(pow(R0,2)-pow(pow(y1-y0,2)+pow(x1-x0,2),-1)*pow(-pow(R1,2)+pow(R0,2)+pow(y1-y0,2)+pow(x1-x0,2),2)/4)))+y0 else: # 計算 tip 點的 x 座標 tip_coord.x = pow(sqrt(pow(y1-y0,2)+pow(x1-x0,2)),-1)*(-mech_loop*(y1-y0)*sqrt(fabs(pow(R0,2)-pow(pow(y1-y0,2)+pow(x1-x0,2),-1)*pow(-pow(R1,2)+pow(R0,2)+pow(y1-y0,2)+pow(x1-x0,2),2)/4))+(x1-x0)*pow(sqrt(pow(y1-y0,2)+pow(x1-x0,2)),-1)*(-pow(R1,2)+pow(R0,2)+pow(y1-y0,2)+pow(x1-x0,2))/2)+x0 # 計算 tip 點的 y 座標 tip_coord.y = pow(sqrt(pow(y1-y0,2)+pow(x1-x0,2)),-1)*((y1-y0)*pow(sqrt(pow(y1-y0,2)+pow(x1-x0,2)),-1)*(-pow(R1,2)+pow(R0,2)+pow(y1-y0,2)+pow(x1-x0,2))/2+mech_loop*(x1-x0)*sqrt(fabs(pow(R0,2)-pow(pow(y1-y0,2)+pow(x1-x0,2),-1)*pow(-pow(R1,2)+pow(R0,2)+pow(y1-y0,2)+pow(x1-x0,2),2)/4)))+y0 return tip_coord def distance(x0, y0, x1, y1): return sqrt(pow((x1-x0),2) + pow((y1-y0),2)) def rr(L1, dd, theta): return sqrt(L1*L1+dd*dd-2*L1*dd*cos(theta)) # input_angles = [] 也就是必須為 list 且各樹為 NUM_OF_POINTS def mechanism(x0, y0, x1, y1, L1, L2, L3, L5, L6, input_angles): ''' mechanism(0,0,10,0,5,20,10,10,10,input_angles) x0 = 0.0; y0 = 0.0; x1 = 10.0; y1 = 0.0; L1 = 5.0; L2 = 10; L3 = 10; L5 = 10; L6 = 10; ''' link1_tip = Point(0,0) link2_tip = Point(0,0) output_points = list() degree = pi/180. NUM_OF_POINTS = 5 dd_length = distance(x0, y0, x1, y1) # 設法表示 triangle 所對應的 local 角度,表示為已知變數與 t 的函式 angle3 = acos((pow(L2,2)+pow(L5,2)-pow(L6,2))/(2*L2*L5)); for i in range(NUM_OF_POINTS): angle = input_angles[i]*degree rr_length = rr(L1, dd_length, angle) # 第一次三角形疊代 link1_tip = triangletip_coord(x0, y0, L1, rr_length, x1, y1, angle) #print(angle, rr_length, link1_tip.x, link1_tip.y) # 第二次三角形疊代 # 設法表示 link2 所對應的 local 角度,表示為已知變數與 t 的函式 angle2 = acos((pow(L2,2)+pow(rr_length,2)-pow(L3,2))/(2*L2*rr_length)) link2_tip = triangletip_coord(link1_tip.x, link1_tip.y, L2, L3, x1, y1, angle2) # 第三次三角形疊代 (改為以 finaltip_coord() 取值, 而非第三次疊代 ''' triangle_tip = triangletip_coord(link1_tip.x, link1_tip.y, L5, L6, link2_tip.x, link2_tip.y, angle3); output_points[i] = triangletip_coord(link1_tip.x, link1_tip.y, L5, L6, link2_tip.x, link2_tip.y, angle3); ''' # 這裡要嘗試利用 finaltip_coord() 求 tip3 座標, 而 L5 與 L6 可 0 可負 output_points.append(finaltip_coord(link1_tip, link2_tip, L5, L6)) return output_points def finaltip_coord(tip1_coord, tip2_coord, r1, r2): tip3_coord = Point(0,0) length3 = sqrt(pow(tip2_coord.x - tip1_coord.x,2) + pow(tip2_coord.y - tip1_coord.y,2)) length4 = sqrt(pow(r1,2) + pow(r2,2)) theta3 = acos((tip2_coord.x - tip1_coord.x) / length3) theta4 = acos(r1/length4) tip3_coord.x = tip1_coord.x + length4 * cos(theta3 + theta4) tip3_coord.y = tip1_coord.y + length4 * sin(theta3 + theta4) return tip3_coord # 誤差函式 def error_function(output_points, target_points): NUM_OF_POINTS = 5 error = 0 for i in range(NUM_OF_POINTS): error += fabs(distance(output_points[i].x, output_points[i].y, target_points[i].x, target_points[i].y)) return error # 組成機構的變數個樹 9 + 通過點數所對應的角度值, 若通過 5 點則共有 14 個變數 # mechanism(tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7], tmp[8], input_angles, output_points); def fourbar(x): PENALITY = 1000 NUM_OF_POINTS = 10 # x0 與 x1 點位於 -50 與 50 中間, 0, 1, 2, 3 for i in range(4): if(x[i] < -50 or x[i] > 50): return PENALITY # 三個連桿值, 一定要為正, 4, 5, 6, for i in range(4, 7): if(x[i] < 0 or x[i] >50): return PENALITY # L5 L6 可以為 0 或負值, 7, 8 for i in range(7, 9): if(x[i] < -50 or x[i] > 50): return PENALITY # 角度值一定要大於 0 for i in range(NUM_OF_POINTS): if(x[9+i] < 0): return PENALITY result = 0 target_points = list() output_points = list() input_angles = list() # 定義四連桿關鍵點所要通過的點 p1 = Point(1, 1) p2 = Point(2, 2) p3 = Point(3, 3) p4 = Point(4, 4) p5 = Point(5, 5) p6 = Point(6, 6) p7 = Point(7, 7) p8 = Point(8, 8) p9 = Point(9, 9) p10 = Point(10, 10) target_points = [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10] for i in range(9, 9+NUM_OF_POINTS): input_angles.append(x[i]) # 這裡要加入查驗各參數是否符合四連桿組成條件 try: output_points = mechanism(x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7],x[8],input_angles) except: return PENALITY result = error_function(output_points, target_points) return result #ga=GA(square, dim=2, popsize=40, ngen=50, pc=0.9, pm=0.1, etac=2, etam=100, min=-1) # min = -1 表示要最大化適應方程式的值, 若 min = 1 表示要最小化 #ga=GA(volume, dim=2, popsize=400, ngen=500, pc=0.9, pm=0.1, etac=2, etam=100, min=-1) # 請注意 popsize 必須為 4 的倍數 #ga=GA(miniex1, dim=2, popsize=12, ngen=50, pc=0.9, pm=0.1, etac=2, etam=100, min=1) ga=GA(fourbar, dim=19, popsize=120000, ngen=10000, pc=0.9, pm=0.5, etac=2, etam=100, min=1) #ga.setbounds(np.zeros(10), 10*np.ones(10)) #ga.setbounds(-10*np.ones(10), 10*np.ones(10)) ga.setbounds(-50*np.ones(20), 50*np.ones(20)) #ga.pop_init() print(ga.run())
利用 C 與 Differential Evolution 解上述相同問題的原始碼:
// 必須在演算過程中, 設法限制各變數的上下限!!! 否則演化非常容易發散?? /*************************************************************** ** ** ** D I F F E R E N T I A L E V O L U T I O N ** ** ** ** Program: de.c ** ** Version: 3.6 ** ** ** ** Authors: Dr. Rainer Storn ** ** c/o ICSI, 1947 Center Street, Suite 600 ** ** Berkeley, CA 94707 ** ** Tel.: 510-642-4274 (extension 192) ** ** Fax.: 510-643-7684 ** ** E-mail: storn@icsi.berkeley.edu ** ** WWW: http://http.icsi.berkeley.edu/~storn/ ** ** on leave from ** ** Siemens AG, ZFE T SN 2, Otto-Hahn Ring 6 ** ** D-81739 Muenchen, Germany ** ** Tel: 636-40502 ** ** Fax: 636-44577 ** ** E-mail: rainer.storn@zfe.siemens.de ** ** ** ** Kenneth Price ** ** 836 Owl Circle ** ** Vacaville, CA 95687 ** ** E-mail: kprice@solano.community.net ** ** ** ** This program implements some variants of Differential ** ** Evolution (DE) as described in part in the techreport ** ** tr-95-012.ps of ICSI. You can get this report either via ** ** ftp.icsi.berkeley.edu/pub/techreports/1995/tr-95-012.ps.Z ** ** or via WWW: http://http.icsi.berkeley.edu/~storn/litera.html* ** A more extended version of tr-95-012.ps is submitted for ** ** publication in the Journal Evolutionary Computation. ** ** ** ** You may use this program for any purpose, give it to any ** ** person or change it according to your needs as long as you ** ** are referring to Rainer Storn and Ken Price as the origi- ** ** nators of the the DE idea. ** ** If you have questions concerning DE feel free to contact ** ** us. We also will be happy to know about your experiences ** ** with DE and your suggestions of improvement. ** ** ** ***************************************************************/ /**H*O*C************************************************************** ** ** ** No.!Version! Date ! Request ! Modification ! Author ** ** ---+-------+------+---------+---------------------------+------- ** ** 1 + 3.1 +5/18/95+ - + strategy DE/rand-to-best/1+ Storn ** ** + + + + included + ** ** 1 + 3.2 +6/06/95+C.Fleiner+ change loops into memcpy + Storn ** ** 2 + 3.2 +6/06/95+ - + update comments + Storn ** ** 1 + 3.3 +6/15/95+ K.Price + strategy DE/best/2 incl. + Storn ** ** 2 + 3.3 +6/16/95+ - + comments and beautifying + Storn ** ** 3 + 3.3 +7/13/95+ - + upper and lower bound for + Storn ** ** + + + + initialization + ** ** 1 + 3.4 +2/12/96+ - + increased printout prec. + Storn ** ** 1 + 3.5 +5/28/96+ - + strategies revisited + Storn ** ** 2 + 3.5 +5/28/96+ - + strategy DE/rand/2 incl. + Storn ** ** 1 + 3.6 +8/06/96+ K.Price + Binomial Crossover added + Storn ** ** 2 + 3.6 +9/30/96+ K.Price + cost variance output + Storn ** ** 3 + 3.6 +9/30/96+ - + alternative to ASSIGND + Storn ** ** 4 + 3.6 +10/1/96+ - + variable checking inserted + Storn ** ** 5 + 3.6 +10/1/96+ - + strategy indic. improved + Storn ** ** ** ***H*O*C*E***********************************************************/ #include "stdio.h" #include "stdlib.h" #include "math.h" #include "memory.h" #include <time.h> // 最大族群數, NP #define MAXPOP 5000 // 最大向量維度, D #define MAXDIM 35 #define MAXIMAPROBLEM 0 #define PENALITY 1000 /*------Constants for rnd_uni()--------------------------------------------*/ #define IM1 2147483563 #define IM2 2147483399 #define AM (1.0/IM1) #define IMM1 (IM1-1) #define IA1 40014 #define IA2 40692 #define IQ1 53668 #define IQ2 52774 #define IR1 12211 #define IR2 3791 #define NTAB 32 #define NDIV (1+IMM1/NTAB) #define EPS 1.2e-7 #define RNMX (1.0-EPS) // 與機構合成相關的常數定義 #define PI 3.1415926 #define degree PI/180.0 #define mech_loop -1 #define NUM_OF_POINTS 10 /*------------------------Macros----------------------------------------*/ /*#define ASSIGND(a,b) memcpy((a),(b),sizeof(double)*D) */ /* quick copy by Claudio */ /* works only for small */ /* arrays, but is faster.*/ /*------------------------Globals---------------------------------------*/ long rnd_uni_init; /* serves as a seed for rnd_uni() */ double c[MAXPOP][MAXDIM], d[MAXPOP][MAXDIM]; double (*pold)[MAXPOP][MAXDIM], (*pnew)[MAXPOP][MAXDIM], (*pswap)[MAXPOP][MAXDIM]; /*---------Function declarations----------------------------------------*/ void assignd(int D, double a[], double b[]); double rnd_uni(long *idum); /* uniform pseudo random number generator */ double extern evaluate(int D, double tmp[], long *nfeval); /* obj. funct. */ // 與機構合成相關的函式宣告 double distance(double x0, double y0, double x1, double y1); double rr(double L1, double dd, double theta); struct Coord triangletip_coord( double x0, double y0, double R0, double R1, double x1, double y1, double localt); void mechanism(double x0, double y0, double x1, double y1, double L1, double L2, double L3, double L5, double L6, double input_angles[NUM_OF_POINTS], struct Coord output_points[NUM_OF_POINTS]); double error_function(struct Coord output_points[NUM_OF_POINTS], struct Coord target_points[NUM_OF_POINTS]); struct Coord finaltip_coord(struct Coord tip1_coord, struct Coord tip2_coord, double r1, double r2); /*---------Function definitions-----------------------------------------*/ // 指定向量 b 為 a void assignd(int D, double a[], double b[]) /**C*F**************************************************************** ** ** ** Assigns D-dimensional vector b to vector a. ** ** You might encounter problems with the macro ASSIGND on some ** ** machines. If yes, better use this function although it's slower. ** ** ** ***C*F*E*************************************************************/ { int j; for (j=0; j<D; j++) { a[j] = b[j]; } } // 產生 0 ~ 1 間的亂數 double rnd_uni(long *idum) /**C*F**************************************************************** ** ** ** SRC-FUNCTION :rnd_uni() ** ** LONG_NAME :random_uniform ** ** AUTHOR :(see below) ** ** ** ** DESCRIPTION :rnd_uni() generates an equally distributed ran- ** ** dom number in the interval [0,1]. For further ** ** reference see Press, W.H. et alii, Numerical ** ** Recipes in C, Cambridge University Press, 1992. ** ** ** ** FUNCTIONS :none ** ** ** ** GLOBALS :none ** ** ** ** PARAMETERS :*idum serves as a seed value ** ** ** ** PRECONDITIONS :*idum must be negative on the first call. ** ** ** ** POSTCONDITIONS :*idum will be changed ** ** ** ***C*F*E*************************************************************/ { long j; long k; static long idum2=123456789; static long iy=0; static long iv[NTAB]; double temp; if (*idum <= 0) { if (-(*idum) < 1) *idum=1; else *idum = -(*idum); idum2=(*idum); for (j=NTAB+7;j>=0;j--) { k=(*idum)/IQ1; *idum=IA1*(*idum-k*IQ1)-k*IR1; if (*idum < 0) *idum += IM1; if (j < NTAB) iv[j] = *idum; } iy=iv[0]; } k=(*idum)/IQ1; *idum=IA1*(*idum-k*IQ1)-k*IR1; if (*idum < 0) *idum += IM1; k=idum2/IQ2; idum2=IA2*(idum2-k*IQ2)-k*IR2; if (idum2 < 0) idum2 += IM2; j=iy/NDIV; iy=iv[j]-idum2; iv[j] = *idum; if (iy < 1) iy += IMM1; if ((temp=AM*iy) > RNMX) return RNMX; else return temp; }/*------End of rnd_uni()--------------------------*/ // 將上下限轉為全域變數 double inibound_h; /* upper parameter bound */ double inibound_l; /* lower parameter bound */ // 與機構合成相關的全域變數 // 宣告一個座標結構 struct Coord { double x; double y; // 這裡保留 double z; }; main(int argc, char *argv[]) /**C*F**************************************************************** ** ** ** SRC-FUNCTION :main() ** ** LONG_NAME :main program ** ** AUTHOR :Rainer Storn, Kenneth Price ** ** ** ** DESCRIPTION :driver program for differential evolution. ** ** ** ** FUNCTIONS :rnd_uni(), evaluate(), printf(), fprintf(), ** ** fopen(), fclose(), fscanf(). ** ** ** ** GLOBALS :rnd_uni_init input variable for rnd_uni() ** ** ** ** PARAMETERS :argc #arguments = 3 ** ** argv pointer to argument strings ** ** ** ** PRECONDITIONS :main must be called with three parameters ** ** e.g. like de1 <input-file> <output-file>, if ** ** the executable file is called de1. ** ** The input file must contain valid inputs accor- ** ** ding to the fscanf() section of main(). ** ** ** ** POSTCONDITIONS :main() produces consecutive console outputs and ** ** writes the final results in an output file if ** ** the program terminates without an error. ** ** ** ***C*F*E*************************************************************/ { char chr; /* y/n choice variable */ char *strat[] = /* strategy-indicator */ { "", "DE/best/1/exp", "DE/rand/1/exp", "DE/rand-to-best/1/exp", "DE/best/2/exp", "DE/rand/2/exp", "DE/best/1/bin", "DE/rand/1/bin", "DE/rand-to-best/1/bin", "DE/best/2/bin", "DE/rand/2/bin" }; int i, j, L, n; /* counting variables */ int r1, r2, r3, r4; /* placeholders for random indexes */ int r5; /* placeholders for random indexes */ int D; /* Dimension of parameter vector */ int NP; /* number of population members */ int imin; /* index to member with lowest energy */ int refresh; /* refresh rate of screen output */ int strategy; /* choice parameter for screen output */ int gen, genmax, seed; long nfeval; /* number of function evaluations */ double trial_cost; /* buffer variable */ // 將上下限轉為全域變數, 可能要根據各變數加以設定 //double inibound_h; /* upper parameter bound */ //double inibound_l; /* lower parameter bound */ double tmp[MAXDIM], best[MAXDIM], bestit[MAXDIM]; /* members */ double cost[MAXPOP]; /* obj. funct. values */ double cvar; /* computes the cost variance */ double cmean; /* mean cost */ double F,CR; /* control variables of DE */ double cmin; /* help variables */ FILE *fpin_ptr; FILE *fpout_ptr; // 計算執行過程所需時間起點, 需要導入 time.h clock_t start = clock(); /*------Initializations----------------------------*/ //if (argc != 3) /* number of arguments */ //{ //printf("\nUsage : de <input-file> <output-file>\n"); //exit(1); //} // 將結果寫入 out.dat fpout_ptr = fopen("out.dat","w"); /* open output file for reading, */ /* to see whether it already exists */ /* if ( fpout_ptr != NULL ) { printf("\nOutput file %s does already exist, \ntype y if you ",argv[2]); printf("want to overwrite it, \nanything else if you want to exit.\n"); chr = (char)getchar(); if ((chr != 'y') && (chr != 'Y')) { exit(1); } fclose(fpout_ptr); } */ /*-----Read input data------------------------------------------------*/ //fpin_ptr = fopen(argv[1],"r"); /* if (fpin_ptr == NULL) { printf("\nCannot open input file\n"); exit(1); }*/ //fscanf(fpin_ptr,"%d",&strategy); /*---choice of strategy-----------------*/ //fscanf(fpin_ptr,"%d",&genmax); /*---maximum number of generations------*/ //fscanf(fpin_ptr,"%d",&refresh); /*---output refresh cycle---------------*/ //fscanf(fpin_ptr,"%d",&D); /*---number of parameters---------------*/ //fscanf(fpin_ptr,"%d",&NP); /*---population size.-------------------*/ //fscanf(fpin_ptr,"%lf",&inibound_h); /*---upper parameter bound for init-----*/ //fscanf(fpin_ptr,"%lf",&inibound_l); /*---lower parameter bound for init-----*/ //fscanf(fpin_ptr,"%lf",&F); /*---weight factor----------------------*/ //fscanf(fpin_ptr,"%lf",&CR); /*---crossing over factor---------------*/ //fscanf(fpin_ptr,"%d",&seed); /*---random seed------------------------*/ // 目前已經採用 strategy 3 可以得到最佳結果 strategy = 3; genmax = 2000; refresh = 100; // 配合機構尺寸合成, 每一個體有 9 個機構尺寸值與 5 個通過點角度值 D = 19; NP = 200; inibound_h = 50.; inibound_l = 0.; /*得到最佳解 F = 0.85; CR 必須介於 0 to 1. 之間 CR = 1.; */ F = 0.85; CR = 1.; seed = 3; //fclose(fpin_ptr); /*-----Checking input variables for proper range----------------------------*/ if (D > MAXDIM) { printf("\nError! D=%d > MAXDIM=%d\n",D,MAXDIM); exit(1); } if (D <= 0) { printf("\nError! D=%d, should be > 0\n",D); exit(1); } if (NP > MAXPOP) { printf("\nError! NP=%d > MAXPOP=%d\n",NP,MAXPOP); exit(1); } if (NP <= 0) { printf("\nError! NP=%d, should be > 0\n",NP); exit(1); } if ((CR < 0) || (CR > 1.0)) { printf("\nError! CR=%f, should be ex [0,1]\n",CR); exit(1); } if (seed <= 0) { printf("\nError! seed=%d, should be > 0\n",seed); exit(1); } if (refresh <= 0) { printf("\nError! refresh=%d, should be > 0\n",refresh); exit(1); } if (genmax <= 0) { printf("\nError! genmax=%d, should be > 0\n",genmax); exit(1); } if ((strategy < 0) || (strategy > 10)) { printf("\nError! strategy=%d, should be ex {1,2,3,4,5,6,7,8,9,10}\n",strategy); exit(1); } if (inibound_h < inibound_l) { printf("\nError! inibound_h=%f < inibound_l=%f\n",inibound_h, inibound_l); exit(1); } /*-----Open output file-----------------------------------------------*/ //fpout_ptr = fopen(argv[2],"w"); /* open output file for writing */ //if (fpout_ptr == NULL) //{ //printf("\nCannot open output file\n"); //exit(1); //} /*-----Initialize random number generator-----------------------------*/ rnd_uni_init = -(long)seed; /* initialization of rnd_uni() */ nfeval = 0; /* reset number of function evaluations */ /*------Initialization------------------------------------------------*/ /*------Right now this part is kept fairly simple and just generates--*/ /*------random numbers in the range [-initfac, +initfac]. You might---*/ /*------want to extend the init part such that you can initialize-----*/ /*------each parameter separately.------------------------------------*/ for (i=0; i<NP; i++) { for (j=0; j<D; j++) /* spread initial population members */ { c[i][j] = inibound_l + rnd_uni(&rnd_uni_init)*(inibound_h - inibound_l); } cost[i] = evaluate(D,c[i],&nfeval); /* obj. funct. value */ } cmin = cost[0]; imin = 0; for (i=1; i<NP; i++) { if(MAXIMAPROBLEM == 1) { // 改為最大化 if (cost[i]>cmin) { cmin = cost[i]; imin = i; } } else { // 最小化問題 if (cost[i]<cmin) { cmin = cost[i]; imin = i; } } } assignd(D,best,c[imin]); /* save best member ever */ assignd(D,bestit,c[imin]); /* save best member of generation */ pold = &c; /* old population (generation G) */ pnew = &d; /* new population (generation G+1) */ /*=======================================================================*/ /*=========Iteration loop================================================*/ /*=======================================================================*/ gen = 0; /* generation counter reset */ while ((gen < genmax) /*&& (kbhit() == 0)*/) /* remove comments if conio.h */ { /* is accepted by compiler */ gen++; imin = 0; for (i=0; i<NP; i++) /* Start of loop through ensemble */ { do /* Pick a random population member */ { /* Endless loop for NP < 2 !!! */ r1 = (int)(rnd_uni(&rnd_uni_init)*NP); }while(r1==i); do /* Pick a random population member */ { /* Endless loop for NP < 3 !!! */ r2 = (int)(rnd_uni(&rnd_uni_init)*NP); }while((r2==i) || (r2==r1)); do /* Pick a random population member */ { /* Endless loop for NP < 4 !!! */ r3 = (int)(rnd_uni(&rnd_uni_init)*NP); }while((r3==i) || (r3==r1) || (r3==r2)); do /* Pick a random population member */ { /* Endless loop for NP < 5 !!! */ r4 = (int)(rnd_uni(&rnd_uni_init)*NP); }while((r4==i) || (r4==r1) || (r4==r2) || (r4==r3)); do /* Pick a random population member */ { /* Endless loop for NP < 6 !!! */ r5 = (int)(rnd_uni(&rnd_uni_init)*NP); }while((r5==i) || (r5==r1) || (r5==r2) || (r5==r3) || (r5==r4)); /*=======Choice of strategy===============================================================*/ /*=======We have tried to come up with a sensible naming-convention: DE/x/y/z=============*/ /*=======DE : stands for Differential Evolution==========================================*/ /*=======x : a string which denotes the vector to be perturbed==========================*/ /*=======y : number of difference vectors taken for perturbation of x===================*/ /*=======z : crossover method (exp = exponential, bin = binomial)=======================*/ /* */ /*=======There are some simple rules which are worth following:===========================*/ /*=======1) F is usually between 0.5 and 1 (in rare cases > 1)===========================*/ /*=======2) CR is between 0 and 1 with 0., 0.3, 0.7 and 1. being worth to be tried first=*/ /*=======3) To start off NP = 10*D is a reasonable choice. Increase NP if misconvergence=*/ /* happens. */ /*=======4) If you increase NP, F usually has to be decreased============================*/ /*=======5) When the DE/best... schemes fail DE/rand... usually works and vice versa=====*/ /*=======EXPONENTIAL CROSSOVER============================================================*/ /*-------DE/best/1/exp--------------------------------------------------------------------*/ /*-------Our oldest strategy but still not bad. However, we have found several------------*/ /*-------optimization problems where misconvergence occurs.-------------------------------*/ if (strategy == 1) /* strategy DE0 (not in our paper) */ { assignd(D,tmp,(*pold)[i]); n = (int)(rnd_uni(&rnd_uni_init)*D); L = 0; do { tmp[n] = bestit[n] + F*((*pold)[r2][n]-(*pold)[r3][n]); n = (n+1)%D; L++; }while((rnd_uni(&rnd_uni_init) < CR) && (L < D)); } /*-------DE/rand/1/exp-------------------------------------------------------------------*/ /*-------This is one of my favourite strategies. It works especially well when the-------*/ /*-------"bestit[]"-schemes experience misconvergence. Try e.g. F=0.7 and CR=0.5---------*/ /*-------as a first guess.---------------------------------------------------------------*/ else if (strategy == 2) /* strategy DE1 in the techreport */ { assignd(D,tmp,(*pold)[i]); n = (int)(rnd_uni(&rnd_uni_init)*D); L = 0; do { tmp[n] = (*pold)[r1][n] + F*((*pold)[r2][n]-(*pold)[r3][n]); n = (n+1)%D; L++; }while((rnd_uni(&rnd_uni_init) < CR) && (L < D)); } /*-------DE/rand-to-best/1/exp-----------------------------------------------------------*/ /*-------This strategy seems to be one of the best strategies. Try F=0.85 and CR=1.------*/ /*-------If you get misconvergence try to increase NP. If this doesn't help you----------*/ /*-------should play around with all three control variables.----------------------------*/ else if (strategy == 3) /* similiar to DE2 but generally better */ { assignd(D,tmp,(*pold)[i]); n = (int)(rnd_uni(&rnd_uni_init)*D); L = 0; do { tmp[n] = tmp[n] + F*(bestit[n] - tmp[n]) + F*((*pold)[r1][n]-(*pold)[r2][n]); n = (n+1)%D; L++; }while((rnd_uni(&rnd_uni_init) < CR) && (L < D)); } /*-------DE/best/2/exp is another powerful strategy worth trying--------------------------*/ else if (strategy == 4) { assignd(D,tmp,(*pold)[i]); n = (int)(rnd_uni(&rnd_uni_init)*D); L = 0; do { tmp[n] = bestit[n] + ((*pold)[r1][n]+(*pold)[r2][n]-(*pold)[r3][n]-(*pold)[r4][n])*F; n = (n+1)%D; L++; }while((rnd_uni(&rnd_uni_init) < CR) && (L < D)); } /*-------DE/rand/2/exp seems to be a robust optimizer for many functions-------------------*/ else if (strategy == 5) { assignd(D,tmp,(*pold)[i]); n = (int)(rnd_uni(&rnd_uni_init)*D); L = 0; do { tmp[n] = (*pold)[r5][n] + ((*pold)[r1][n]+(*pold)[r2][n]-(*pold)[r3][n]-(*pold)[r4][n])*F; n = (n+1)%D; L++; }while((rnd_uni(&rnd_uni_init) < CR) && (L < D)); } /*=======Essentially same strategies but BINOMIAL CROSSOVER===============================*/ /*-------DE/best/1/bin--------------------------------------------------------------------*/ else if (strategy == 6) { assignd(D,tmp,(*pold)[i]); n = (int)(rnd_uni(&rnd_uni_init)*D); for (L=0; L<D; L++) /* perform D binomial trials */ { if ((rnd_uni(&rnd_uni_init) < CR) || L == (D-1)) /* change at least one parameter */ { tmp[n] = bestit[n] + F*((*pold)[r2][n]-(*pold)[r3][n]); } n = (n+1)%D; } } /*-------DE/rand/1/bin-------------------------------------------------------------------*/ else if (strategy == 7) { assignd(D,tmp,(*pold)[i]); n = (int)(rnd_uni(&rnd_uni_init)*D); for (L=0; L<D; L++) /* perform D binomial trials */ { if ((rnd_uni(&rnd_uni_init) < CR) || L == (D-1)) /* change at least one parameter */ { tmp[n] = (*pold)[r1][n] + F*((*pold)[r2][n]-(*pold)[r3][n]); } n = (n+1)%D; } } /*-------DE/rand-to-best/1/bin-----------------------------------------------------------*/ else if (strategy == 8) { assignd(D,tmp,(*pold)[i]); n = (int)(rnd_uni(&rnd_uni_init)*D); for (L=0; L<D; L++) /* perform D binomial trials */ { if ((rnd_uni(&rnd_uni_init) < CR) || L == (D-1)) /* change at least one parameter */ { tmp[n] = tmp[n] + F*(bestit[n] - tmp[n]) + F*((*pold)[r1][n]-(*pold)[r2][n]); } n = (n+1)%D; } } /*-------DE/best/2/bin--------------------------------------------------------------------*/ else if (strategy == 9) { assignd(D,tmp,(*pold)[i]); n = (int)(rnd_uni(&rnd_uni_init)*D); for (L=0; L<D; L++) /* perform D binomial trials */ { if ((rnd_uni(&rnd_uni_init) < CR) || L == (D-1)) /* change at least one parameter */ { tmp[n] = bestit[n] + ((*pold)[r1][n]+(*pold)[r2][n]-(*pold)[r3][n]-(*pold)[r4][n])*F; } n = (n+1)%D; } } /*-------DE/rand/2/bin--------------------------------------------------------------------*/ else { assignd(D,tmp,(*pold)[i]); n = (int)(rnd_uni(&rnd_uni_init)*D); for (L=0; L<D; L++) /* perform D binomial trials */ { if ((rnd_uni(&rnd_uni_init) < CR) || L == (D-1)) /* change at least one parameter */ { tmp[n] = (*pold)[r5][n] + ((*pold)[r1][n]+(*pold)[r2][n]-(*pold)[r3][n]-(*pold)[r4][n])*F; } n = (n+1)%D; } } /*=======Trial mutation now in tmp[]. Test how good this choice really was.==================*/ trial_cost = evaluate(D,tmp,&nfeval); /* Evaluate new vector in tmp[] */ if(MAXIMAPROBLEM == 1) { // 改為最大化 if (trial_cost >= cost[i]) /* improved objective function value ? */ { cost[i]=trial_cost; assignd(D,(*pnew)[i],tmp); if (trial_cost>cmin) /* Was this a new minimum? */ { /* if so...*/ cmin=trial_cost; /* reset cmin to new low...*/ imin=i; assignd(D,best,tmp); } } else { assignd(D,(*pnew)[i],(*pold)[i]); /* replace target with old value */ } } else { // 最小化問題 if (trial_cost <= cost[i]) /* improved objective function value ? */ { cost[i]=trial_cost; assignd(D,(*pnew)[i],tmp); if (trial_cost<cmin) /* Was this a new minimum? */ { /* if so...*/ cmin=trial_cost; /* reset cmin to new low...*/ imin=i; assignd(D,best,tmp); } } else { assignd(D,(*pnew)[i],(*pold)[i]); /* replace target with old value */ } } } /* End mutation loop through pop. */ assignd(D,bestit,best); /* Save best population member of current iteration */ /* swap population arrays. New generation becomes old one */ pswap = pold; pold = pnew; pnew = pswap; /*----Compute the energy variance (just for monitoring purposes)-----------*/ cmean = 0.; /* compute the mean value first */ for (j=0; j<NP; j++) { cmean += cost[j]; } cmean = cmean/NP; cvar = 0.; /* now the variance */ for (j=0; j<NP; j++) { cvar += (cost[j] - cmean)*(cost[j] - cmean); } cvar = cvar/(NP-1); /*----Output part----------------------------------------------------------*/ if (gen%refresh==1) /* display after every refresh generations */ { /* ABORT works only if conio.h is accepted by your compiler */ printf("\n\n PRESS ANY KEY TO ABORT"); printf("\n\n\n Best-so-far cost funct. value=%-15.10g\n",cmin); for (j=0;j<D;j++) { printf("\n best[%d]=%-15.10g",j,best[j]); } printf("\n\n Generation=%d NFEs=%ld Strategy: %s ",gen,nfeval,strat[strategy]); printf("\n NP=%d F=%-4.2g CR=%-4.2g cost-variance=%-10.5g\n", NP,F,CR,cvar); } fprintf(fpout_ptr,"%ld %-15.10g\n",nfeval,cmin); } /*=======================================================================*/ /*=========End of iteration loop=========================================*/ /*=======================================================================*/ /*-------Final output in file-------------------------------------------*/ fprintf(fpout_ptr,"\n\n\n Best-so-far obj. funct. value = %-15.10g\n",cmin); for (j=0;j<D;j++) { fprintf(fpout_ptr,"\n best[%d]=%-15.10g",j,best[j]); } fprintf(fpout_ptr,"\n\n Generation=%d NFEs=%ld Strategy: %s ",gen,nfeval,strat[strategy]); fprintf(fpout_ptr,"\n NP=%d F=%-4.2g CR=%-4.2g cost-variance=%-10.5g\n", NP,F,CR,cvar); fclose(fpout_ptr); /* Code you want timed here */ printf("Time elapsed: %f\n", ((double)clock() - start) / CLOCKS_PER_SEC); return(0); } /*-----------End of main()------------------------------------------*/ // 適應函式 fittness function (cost function) double evaluate(int D, double tmp[], long *nfeval) { // 先處理通過 5 個點的四連桿問題 // x0, y0 為左方固定點座標, 必須在 0 ~ 100 間 - 設為 tmp[0], tmp[1] // x1, y1 為右方固定點座標, 必須在 0 ~ 100 間 - 設為 tmp[2], tmp[3] // L1 為第一桿件的長度, 必須 > 0, 且小於 100 - 設為 tmp[4] // L2 為第二桿件的長度, 必須 > 0, 且小於 100 - 設為 tmp[5] // L3 為第三桿件的長度, 必須 > 0, 且小於 100 - 設為 tmp[6] // L5, L6 與 L2 共同圍出可動桿 L2 對應的三角形, 關注的三角形頂點即 L5 與 L6 的交點, 而 angle3 則為 L6 之對應角(為固定值) // L5, L6 必須 > 0, 且小於 100 - 設為 tmp[7], tmp[8] // 以下的角度輸入值, 會隨著目標點數的增加而增加, 其索引值由 9 + 通過點數 - 1 決定, 5 點, 則索引至 13, 若通過 25 點, 則索引值為 9 + 24 = 33 // input_angles[] 為五的輸入的雙浮點數角度值,代表個體的角度向量值 - 分別設為 tmp[9], tmp[10], tmp[11], tmp[12], tmp[13] // output_points[] 則為與 input_angles[] 對應的五個三角形的頂點值, 為座標結構值, 分別有 x 與 y 分量值 // 當利用個體的向量值, 代入 mechanism 後所得到得 output_points[] 再與 target_points[] 進行 cost function 的誤差值最小化 /* void mechanism(double x0, double y0, double x1, double y1, double L1, double L2, double L3, double L5, double L6, double input_angles[NUM_OF_POINTS], struct Coord output_points[NUM_OF_POINTS])*/ struct Coord target_points[NUM_OF_POINTS], output_points[NUM_OF_POINTS]; double input_angles[NUM_OF_POINTS], result; int i; (*nfeval)++; target_points[0].x = 1.0; target_points[0].y = 1.0; target_points[1].x = 2.0; target_points[1].y = 2.0; target_points[2].x = 3.0; target_points[2].y = 3.0; target_points[3].x = 4.0; target_points[3].y = 4.0; target_points[4].x = 5.0; target_points[4].y = 5.0; target_points[5].x = 6.0; target_points[5].y = 6.0; target_points[6].x = 7.0; target_points[6].y = 7.0; target_points[7].x = 8.0; target_points[7].y = 8.0; target_points[8].x = 9.0; target_points[8].y = 9.0; target_points[9].x = 10.0; target_points[9].y = 10.0; // 輸入角度值與 tmp[] 的設定 for(i = 0; i < NUM_OF_POINTS; i++) { input_angles[i] = tmp[i + 9]; } // 呼叫 mechanism() 以便計算 output_points[] mechanism(tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7], tmp[8], input_angles, output_points); // for debug /* if(*nfeval%3000 == 0) { for(i = 0; i < NUM_OF_POINTS; i++) { printf("%-15.10g : %-15.10g\n", output_points[i].x, output_points[i].y); } printf("#####################################\n"); } */ // 利用 output_points[] 與 target_points 計算誤差值, 該誤差值就是 cost result = error_function(output_points, target_points); // 這裡要分別針對各變數的約束條件與範圍值來設定傳回 PENALITY 或 誤差值 result // x0 與 x1 點位於 -500 與 500 中間 for(i = 0; i < 4; i++) { if(tmp[i] < -50 || tmp[i] > 50){ return PENALITY; } } // 三個連桿值, 一定要為正 for(i = 4; i < 7; i++) { if(tmp[i] < 0 || tmp[i] > 50){ return PENALITY; } } // L5 L6 可以為 0 或負值 for(i = 7; i < 9; i++) { if(tmp[i] < -50 || tmp[i] > 50){ return PENALITY; } } // 角度值一定要大於 0 for(i = 1; i <= NUM_OF_POINTS; i++) { if((tmp[D-i] < 0)){ return PENALITY; } } return result; /* double result=0, surface = 80.0, z, volume, penality; (*nfeval)++; z = (surface-tmp[0]*tmp[1])/(2.0*(tmp[0]+tmp[1])); volume = tmp[0]*tmp[1]*z; if(volume <= 0){ return PENALITY; } if((tmp[0] <= inibound_l)|| (tmp[0] >inibound_h)){ return PENALITY; } if((tmp[1] <= inibound_l) || (tmp[1] >inibound_h)){ return PENALITY; } // volume must >0 and max volume // 目前為最小化問題 return 1+1/(volume*volume); */ } struct Coord triangletip_coord( double x0, double y0, double R0, double R1, double x1, double y1, double localt) { struct Coord tip_coord; if (localt>=0 && localt <PI) { // 目前蓋掉的式子為利用手動代換出來的版本 //x_value = ((x1-x0)*(-pow(R1,2)+pow(R0,2)+pow((y1-y0),2)+pow((x1-x0),2))/(2*sqrt(pow((y1-y0),2)+pow((x1-x0),2)))-(y1-y0)*(-mech_loop)*sqrt(fabs(pow(R0,2)-pow((-pow(R1,2)+pow(R0,2)+pow((y1-y0),2)+pow((x1-x0),2)),2)/(4*(pow((y1-y0),2)+pow((x1-x0),2))))))/sqrt(pow((y1-y0),2)+pow((x1-x0),2))+x0; // 以下的式子,先利用文字編輯器,將原先 stringout() 出來的 sqrt 替換成 sqrtt, 以防止被 maxima 中的 subst("^"=pow,expr) 所替換, subst 之後,再使用文字編輯器換回來,就可以得到正確的 C 對應碼. tip_coord.x = pow(sqrt(pow(y1-y0,2)+pow(x1-x0,2)),-1)*(mech_loop*(y1-y0)*sqrt(fabs(pow(R0,2)-pow(pow(y1-y0,2)+ pow(x1-x0,2),-1)*pow(-pow(R1,2)+pow(R0,2)+pow(y1-y0,2)+pow(x1-x0,2),2)/4))+(x1-x0)*pow(sqrt(pow(y1-y0,2)+ pow(x1-x0,2)),-1)*(-pow(R1,2)+pow(R0,2)+pow(y1-y0,2)+pow(x1-x0,2))/2)+x0; } else { // 目前蓋掉的式子為利用手動代換出來的版本 //x_value = ((x1-x0)*(-pow(R1,2)+pow(R0,2)+pow((y1-y0),2)+pow((x1-x0),2))/(2*sqrt(pow((y1-y0),2)+pow((x1-x0),2)))-(y1-y0)*(mech_loop)*sqrt(fabs(pow(R0,2)-pow((-pow(R1,2)+pow(R0,2)+pow((y1-y0),2)+pow((x1-x0),2)),2)/(4*(pow((y1-y0),2)+pow((x1-x0),2))))))/sqrt(pow((y1-y0),2)+pow((x1-x0),2))+x0; tip_coord.x = pow(sqrt(pow(y1-y0,2)+pow(x1-x0,2)),-1)*(-mech_loop*(y1-y0)*sqrt(fabs(pow(R0,2)-pow(pow(y1-y0,2)+ pow(x1-x0,2),-1)*pow(-pow(R1,2)+pow(R0,2)+pow(y1-y0,2)+pow(x1-x0,2),2)/4))+(x1-x0)*pow(sqrt(pow(y1-y0,2)+ pow(x1-x0,2)),-1)*(-pow(R1,2)+pow(R0,2)+pow(y1-y0,2)+ pow(x1-x0,2))/2)+x0; } // 請注意,與 Maxma 公式中的差異為,在 sqrt()中加入 fabs(),避免因為sqrt()中的負值而造成 NaN (Not a Number 問題. if (localt>=0 && localt <PI) { tip_coord.y = /*((x1-x0)*(-mech_loop)*sqrt( fabs(pow(R0,2)-pow((-pow(R1,2)+pow(R0,2)+pow((y1-y0),2)+pow((x1-x0),2)),2) /(4*(pow((y1-y0),2)+pow((x1-x0),2))) )) +(y1-y0)*(-pow(R1,2)+pow(R0,2)+pow((y1-y0),2)+pow((x1-x0),2))/(2*sqrt(pow((y1-y0),2)+pow((x1-x0),2))))/sqrt(pow((y1-y0),2)+pow((x1-x0),2)) +y0;*/ // 利用 sqrtt 居中進行代換所得到的式子 pow(sqrt(pow(y1-y0,2)+pow(x1-x0,2)),-1)*((y1-y0)*pow(sqrt(pow(y1-y0,2)+pow(x1-x0,2)),-1)*(-pow(R1,2)+ pow(R0,2)+pow(y1-y0,2)+pow(x1-x0,2))/2-mech_loop*(x1-x0)*sqrt(fabs(pow(R0,2)-pow(pow(y1-y0,2)+ pow(x1-x0,2),-1)*pow(-pow(R1,2)+pow(R0,2)+pow(y1-y0,2)+pow(x1-x0,2),2)/4)))+y0; } else { tip_coord.y = /*((x1-x0)*(mech_loop)*sqrt( fabs(pow(R0,2)-pow((-pow(R1,2)+pow(R0,2)+pow((y1-y0),2)+pow((x1-x0),2)),2) /(4*(pow((y1-y0),2)+pow((x1-x0),2))) )) +(y1-y0)*(-pow(R1,2)+pow(R0,2)+pow((y1-y0),2)+pow((x1-x0),2))/(2*sqrt(pow((y1-y0),2)+pow((x1-x0),2))))/sqrt(pow((y1-y0),2)+pow((x1-x0),2)) +y0;*/ pow(sqrt(pow(y1-y0,2)+pow(x1-x0,2)),-1)*((y1-y0)*pow(sqrt(pow(y1-y0,2)+pow(x1-x0,2)),-1)*(-pow(R1,2)+ pow(R0,2)+pow(y1-y0,2)+pow(x1-x0,2))/2+mech_loop*(x1-x0)*sqrt(fabs(pow(R0,2)-pow(pow(y1-y0,2)+ pow(x1-x0,2),-1)*pow(-pow(R1,2)+pow(R0,2)+pow(y1-y0,2)+pow(x1-x0,2),2)/4)))+y0; } return tip_coord; } double distance(double x0, double y0, double x1, double y1) { double distance_value; distance_value = sqrt(pow((x1-x0),2) + pow((y1-y0),2)); return distance_value; } double rr(double L1, double dd, double theta) { double rr_value; rr_value = sqrt(L1*L1+dd*dd-2*L1*dd*cos(theta)); return rr_value; } // 輸入每一個體的變數向量, 然後求各三角形頂點的座標陣列[NUM_OF_POINTS] void mechanism(double x0, double y0, double x1, double y1, double L1, double L2, double L3, double L5, double L6, double input_angles[NUM_OF_POINTS], struct Coord output_points[NUM_OF_POINTS]) { // 此函式要輸入控制變數, 然後計算機構尺寸合成的關注點座標位置 // 以下為可能的處理變數宣告 // 這裡希望能夠定義一個 struct 來處理座標點 double rr_length, dd_length, angle; struct Coord link1_tip, link2_tip, triangle_tip; double angle2, angle3; int i; // 開始進行三角形頂點座標的計算 // 以下變數由每一個體向量提供 /* x0 = 0.0; y0 = 0.0; x1 = 10.0; y1 = 0.0; L1 = 5.0; L2 = 20; L3 = 10; L5 = 10; L6 = 10; */ dd_length = distance(x0, y0, x1, y1); /* 設法表示 triangle 所對應的 local 角度,表示為已知變數與 t 的函式 */ angle3 = acos((pow(L2,2)+pow(L5,2)-pow(L6,2))/(2*L2*L5)); for(i = 0; i < NUM_OF_POINTS; i++) { // 先建立第一點座標, 即 i=0 者 // i=0; // angle = i*degree; /* // 利用角度增量進行運算, 相對於 input_angles[0] 作為基準 if(i > 0) { input_angles[i] = input_angles[i] + input_angles[i-1]; } */ angle = input_angles[i]*degree; rr_length = rr(L1, dd_length, angle); // 第一次三角形疊代 link1_tip = triangletip_coord(x0, y0, L1, rr_length, x1, y1, angle); // 第二次三角形疊代 /* 設法表示 link2 所對應的 local 角度,表示為已知變數與 t 的函式 */ angle2 = acos((pow(L2,2)+pow(rr_length,2)-pow(L3,2))/(2*L2*rr_length)); link2_tip = triangletip_coord(link1_tip.x, link1_tip.y, L2, L3, x1, y1, angle2); // 第三次三角形疊代 //triangle_tip = triangletip_coord(link1_tip.x, link1_tip.y, L5, L6, link2_tip.x, link2_tip.y, angle3); // output_points[i] = triangletip_coord(link1_tip.x, link1_tip.y, L5, L6, link2_tip.x, link2_tip.y, angle3); // 這裡要嘗試利用 finaltip_coord() 求 tip3 座標, 而 L5 與 L6 可 0 可負 output_points[i] = finaltip_coord(link1_tip, link2_tip, L5, L6); } } double error_function(struct Coord output_points[NUM_OF_POINTS], struct Coord target_points[NUM_OF_POINTS]) { double error = 0.0; int i; for(i = 0; i < NUM_OF_POINTS; i++) { error += fabs(distance(output_points[i].x, output_points[i].y, target_points[i].x, target_points[i].y)); } return error; } struct Coord finaltip_coord(struct Coord tip1_coord, struct Coord tip2_coord, double r1, double r2) { struct Coord tip3_coord; double theta3, theta4, length3, length4; length3 = sqrt(pow(tip2_coord.x - tip1_coord.x,2) + pow(tip2_coord.y - tip1_coord.y,2)); length4 = sqrt(pow(r1,2) + pow(r2,2)); theta3 = acos((tip2_coord.x - tip1_coord.x) / length3); theta4 = acos(r1 / length4); tip3_coord.x = tip1_coord.x + length4 * cos(theta3 + theta4); tip3_coord.y = tip1_coord.y + length4 * sin(theta3 + theta4); return tip3_coord; }
為了要讓 C 程式碼可以在 Pelican 網誌 Markdown 格式編輯模式下能夠與 highlight 套件結合, 首先程式碼中的所有大於與小於符號必須轉為 html special charactor 之外, 還要全部內縮, 否則內容將會在 Pelican 轉換過程中被視為 html 而自動加入錯誤的標註符號.
以下則為 de 25 點四連桿尺寸合成參考程式:
/*************************************************************** ** ** ** D I F F E R E N T I A L E V O L U T I O N ** ** ** ** Program: de.c ** ** Version: 3.6 ** ** ** ** Authors: Dr. Rainer Storn ** ** c/o ICSI, 1947 Center Street, Suite 600 ** ** Berkeley, CA 94707 ** ** Tel.: 510-642-4274 (extension 192) ** ** Fax.: 510-643-7684 ** ** E-mail: storn@icsi.berkeley.edu ** ** WWW: http://http.icsi.berkeley.edu/~storn/ ** ** on leave from ** ** Siemens AG, ZFE T SN 2, Otto-Hahn Ring 6 ** ** D-81739 Muenchen, Germany ** ** Tel: 636-40502 ** ** Fax: 636-44577 ** ** E-mail: rainer.storn@zfe.siemens.de ** ** ** ** Kenneth Price ** ** 836 Owl Circle ** ** Vacaville, CA 95687 ** ** E-mail: kprice@solano.community.net ** ** ** ** This program implements some variants of Differential ** ** Evolution (DE) as described in part in the techreport ** ** tr-95-012.ps of ICSI. You can get this report either via ** ** ftp.icsi.berkeley.edu/pub/techreports/1995/tr-95-012.ps.Z ** ** or via WWW: http://http.icsi.berkeley.edu/~storn/litera.html* ** A more extended version of tr-95-012.ps is submitted for ** ** publication in the Journal Evolutionary Computation. ** ** ** ** You may use this program for any purpose, give it to any ** ** person or change it according to your needs as long as you ** ** are referring to Rainer Storn and Ken Price as the origi- ** ** nators of the the DE idea. ** ** If you have questions concerning DE feel free to contact ** ** us. We also will be happy to know about your experiences ** ** with DE and your suggestions of improvement. ** ** ** ***************************************************************/ /**H*O*C************************************************************** ** ** ** No.!Version! Date ! Request ! Modification ! Author ** ** ---+-------+------+---------+---------------------------+------- ** ** 1 + 3.1 +5/18/95+ - + strategy DE/rand-to-best/1+ Storn ** ** + + + + included + ** ** 1 + 3.2 +6/06/95+C.Fleiner+ change loops into memcpy + Storn ** ** 2 + 3.2 +6/06/95+ - + update comments + Storn ** ** 1 + 3.3 +6/15/95+ K.Price + strategy DE/best/2 incl. + Storn ** ** 2 + 3.3 +6/16/95+ - + comments and beautifying + Storn ** ** 3 + 3.3 +7/13/95+ - + upper and lower bound for + Storn ** ** + + + + initialization + ** ** 1 + 3.4 +2/12/96+ - + increased printout prec. + Storn ** ** 1 + 3.5 +5/28/96+ - + strategies revisited + Storn ** ** 2 + 3.5 +5/28/96+ - + strategy DE/rand/2 incl. + Storn ** ** 1 + 3.6 +8/06/96+ K.Price + Binomial Crossover added + Storn ** ** 2 + 3.6 +9/30/96+ K.Price + cost variance output + Storn ** ** 3 + 3.6 +9/30/96+ - + alternative to ASSIGND + Storn ** ** 4 + 3.6 +10/1/96+ - + variable checking inserted + Storn ** ** 5 + 3.6 +10/1/96+ - + strategy indic. improved + Storn ** ** ** ***H*O*C*E***********************************************************/ #include "stdio.h" #include "stdlib.h" #include "math.h" #include "memory.h" #include <time.h> // 最大族群數, NP #define MAXPOP 5000 // 最大向量維度, D #define MAXDIM 60 // 1 為最大化問題, 0 為最小化問題 #define MAXIMAPROBLEM 0 // 可能要配合最大或最小化進行變號 #define PENALITY 1.0E20 /*------Constants for rnd_uni()--------------------------------------------*/ #define IM1 2147483563 #define IM2 2147483399 #define AM (1.0/IM1) #define IMM1 (IM1-1) #define IA1 40014 #define IA2 40692 #define IQ1 53668 #define IQ2 52774 #define IR1 12211 #define IR2 3791 #define NTAB 32 #define NDIV (1+IMM1/NTAB) #define EPS 1.2e-7 #define RNMX (1.0-EPS) // 與機構合成相關的常數定義 #define PI 3.1415926 #define degree PI/180.0 #define mech_loop -1 #define NUM_OF_POINTS 25 /*------------------------Macros----------------------------------------*/ /*#define ASSIGND(a,b) memcpy((a),(b),sizeof(double)*D) */ /* quick copy by Claudio */ /* works only for small */ /* arrays, but is faster.*/ /*------------------------Globals---------------------------------------*/ long rnd_uni_init; /* serves as a seed for rnd_uni() */ double c[MAXPOP][MAXDIM], d[MAXPOP][MAXDIM]; double (*pold)[MAXPOP][MAXDIM], (*pnew)[MAXPOP][MAXDIM], (*pswap)[MAXPOP][MAXDIM]; /*---------Function declarations----------------------------------------*/ void assignd(int D, double a[], double b[]); double rnd_uni(long *idum); /* uniform pseudo random number generator */ double extern evaluate(int D, double tmp[], long *nfeval); /* obj. funct. */ // 與機構合成相關的函式宣告 double distance(double x0, double y0, double x1, double y1); double rr(double L1, double dd, double theta); struct Coord triangletip_coord(double x0, double y0, double R0, double R1, double x1, double y1, double localt); void mechanism(double x0, double y0, double x1, double y1, double L1, double L2, double L3, double L5, double L6, double input_angles[NUM_OF_POINTS], struct Coord output_points[NUM_OF_POINTS]); double error_function(struct Coord output_points[NUM_OF_POINTS], struct Coord target_points[NUM_OF_POINTS]); // 用來利用 tip1 與 tip2 的座標, 以及 r1, r2 求最後的三角形頂點座標 struct Coord finaltip_coord(struct Coord tip1_coord, struct Coord tip2_coord, double r1, double r2); /*---------Function definitions-----------------------------------------*/ // 指定向量 b 為 a void assignd(int D, double a[], double b[]) /**C*F**************************************************************** ** ** ** Assigns D-dimensional vector b to vector a. ** ** You might encounter problems with the macro ASSIGND on some ** ** machines. If yes, better use this function although it's slower. ** ** ** ***C*F*E*************************************************************/ { int j; for (j=0; j<D; j++) { a[j] = b[j]; } } // 產生 0 ~ 1 間的亂數 double rnd_uni(long *idum) /**C*F**************************************************************** ** ** ** SRC-FUNCTION :rnd_uni() ** ** LONG_NAME :random_uniform ** ** AUTHOR :(see below) ** ** ** ** DESCRIPTION :rnd_uni() generates an equally distributed ran- ** ** dom number in the interval [0,1]. For further ** ** reference see Press, W.H. et alii, Numerical ** ** Recipes in C, Cambridge University Press, 1992. ** ** ** ** FUNCTIONS :none ** ** ** ** GLOBALS :none ** ** ** ** PARAMETERS :*idum serves as a seed value ** ** ** ** PRECONDITIONS :*idum must be negative on the first call. ** ** ** ** POSTCONDITIONS :*idum will be changed ** ** ** ***C*F*E*************************************************************/ { long j; long k; static long idum2=123456789; static long iy=0; static long iv[NTAB]; double temp; if (*idum <= 0) { if (-(*idum) < 1) *idum=1; else *idum = -(*idum); idum2=(*idum); for (j=NTAB+7;j>=0;j--) { k=(*idum)/IQ1; *idum=IA1*(*idum-k*IQ1)-k*IR1; if (*idum < 0) *idum += IM1; if (j < NTAB) iv[j] = *idum; } iy=iv[0]; } k=(*idum)/IQ1; *idum=IA1*(*idum-k*IQ1)-k*IR1; if (*idum < 0) *idum += IM1; k=idum2/IQ2; idum2=IA2*(idum2-k*IQ2)-k*IR2; if (idum2 < 0) idum2 += IM2; j=iy/NDIV; iy=iv[j]-idum2; iv[j] = *idum; if (iy < 1) iy += IMM1; if ((temp=AM*iy) > RNMX) return RNMX; else return temp; }/*------End of rnd_uni()--------------------------*/ // 將上下限轉為全域變數 double inibound_h; /* upper parameter bound */ double inibound_l; /* lower parameter bound */ // 與機構合成相關的全域變數 // 宣告一個座標結構 struct Coord { double x; double y; // 這裡保留 double z; }; int main(int argc, char *argv[]) /**C*F**************************************************************** ** ** ** SRC-FUNCTION :main() ** ** LONG_NAME :main program ** ** AUTHOR :Rainer Storn, Kenneth Price ** ** ** ** DESCRIPTION :driver program for differential evolution. ** ** ** ** FUNCTIONS :rnd_uni(), evaluate(), printf(), fprintf(), ** ** fopen(), fclose(), fscanf(). ** ** ** ** GLOBALS :rnd_uni_init input variable for rnd_uni() ** ** ** ** PARAMETERS :argc #arguments = 3 ** ** argv pointer to argument strings ** ** ** ** PRECONDITIONS :main must be called with three parameters ** ** e.g. like de1 <input-file> <output-file>, if ** ** the executable file is called de1. ** ** The input file must contain valid inputs accor- ** ** ding to the fscanf() section of main(). ** ** ** ** POSTCONDITIONS :main() produces consecutive console outputs and ** ** writes the final results in an output file if ** ** the program terminates without an error. ** ** ** ***C*F*E*************************************************************/ { char chr; /* y/n choice variable */ char *strat[] = /* strategy-indicator */ { "", "DE/best/1/exp", "DE/rand/1/exp", "DE/rand-to-best/1/exp", "DE/best/2/exp", "DE/rand/2/exp", "DE/best/1/bin", "DE/rand/1/bin", "DE/rand-to-best/1/bin", "DE/best/2/bin", "DE/rand/2/bin" }; int i, j, L, n; /* counting variables */ int r1, r2, r3, r4; /* placeholders for random indexes */ int r5; /* placeholders for random indexes */ int D; /* Dimension of parameter vector */ int NP; /* number of population members */ int imin; /* index to member with lowest energy */ int refresh; /* refresh rate of screen output */ int strategy; /* choice parameter for screen output */ int gen, genmax, seed; long nfeval; /* number of function evaluations */ double trial_cost; /* buffer variable */ // 將上下限轉為全域變數, 可能要根據各變數加以設定 //double inibound_h; /* upper parameter bound */ //double inibound_l; /* lower parameter bound */ double tmp[MAXDIM], best[MAXDIM], bestit[MAXDIM]; /* members */ double cost[MAXPOP]; /* obj. funct. values */ double cvar; /* computes the cost variance */ double cmean; /* mean cost */ double F,CR; /* control variables of DE */ double cmin; /* help variables */ FILE *fpin_ptr; FILE *fpout_ptr; // 計算執行過程所需時間起點, 需要導入 time.h clock_t start = clock(); /*------Initializations----------------------------*/ //if (argc != 3) /* number of arguments */ //{ //printf("\nUsage : de <input-file> <output-file>\n"); //exit(1); //} // 將結果寫入 out.dat fpout_ptr = fopen("out.dat","w"); /* open output file for reading, */ /* to see whether it already exists */ /* if ( fpout_ptr != NULL ) { printf("\nOutput file %s does already exist, \ntype y if you ",argv[2]); printf("want to overwrite it, \nanything else if you want to exit.\n"); chr = (char)getchar(); if ((chr != 'y') && (chr != 'Y')) { exit(1); } fclose(fpout_ptr); } */ /*-----Read input data------------------------------------------------*/ //fpin_ptr = fopen(argv[1],"r"); /* if (fpin_ptr == NULL) { printf("\nCannot open input file\n"); exit(1); }*/ //fscanf(fpin_ptr,"%d",&strategy); /*---choice of strategy-----------------*/ //fscanf(fpin_ptr,"%d",&genmax); /*---maximum number of generations------*/ //fscanf(fpin_ptr,"%d",&refresh); /*---output refresh cycle---------------*/ //fscanf(fpin_ptr,"%d",&D); /*---number of parameters---------------*/ //fscanf(fpin_ptr,"%d",&NP); /*---population size.-------------------*/ //fscanf(fpin_ptr,"%lf",&inibound_h); /*---upper parameter bound for init-----*/ //fscanf(fpin_ptr,"%lf",&inibound_l); /*---lower parameter bound for init-----*/ //fscanf(fpin_ptr,"%lf",&F); /*---weight factor----------------------*/ //fscanf(fpin_ptr,"%lf",&CR); /*---crossing over factor---------------*/ //fscanf(fpin_ptr,"%d",&seed); /*---random seed------------------------*/ strategy = 3; genmax = 200000; // refresh 為每幾筆運算後進行資料列印 refresh = 100; // 配合機構尺寸合成, 每一個體有 9 個機構尺寸值與 25 (NUM_OF_POINTS) 個通過點角度值 // tmp[0~8] 為機構尺寸, tmp[9~33] 為通過點角度值 D = 9 + NUM_OF_POINTS; NP = 200; // 機構變數值上限 inibound_h = 50.; // 機構變數值下限 inibound_l = 0.; // for strategy 1, F=0.9, CR = 1. // for strategy 2 F=0.7, CR=0.5 // 一個小時得到 9.7 的誤差 // 25 點的題目, 若 penality 只取 1000 則 F = 0.7 似乎為 最大 bound for strategy 1, CR = 1. F = 0.85; CR = 0.7; seed = 3; //fclose(fpin_ptr); /*-----Checking input variables for proper range----------------------------*/ if (D > MAXDIM) { printf("\nError! D=%d > MAXDIM=%d\n",D,MAXDIM); exit(1); } if (D <= 0) { printf("\nError! D=%d, should be > 0\n",D); exit(1); } if (NP > MAXPOP) { printf("\nError! NP=%d > MAXPOP=%d\n",NP,MAXPOP); exit(1); } if (NP <= 0) { printf("\nError! NP=%d, should be > 0\n",NP); exit(1); } if ((CR < 0) || (CR > 1.0)) { printf("\nError! CR=%f, should be ex [0,1]\n",CR); exit(1); } if (seed <= 0) { printf("\nError! seed=%d, should be > 0\n",seed); exit(1); } if (refresh <= 0) { printf("\nError! refresh=%d, should be > 0\n",refresh); exit(1); } if (genmax <= 0) { printf("\nError! genmax=%d, should be > 0\n",genmax); exit(1); } if ((strategy < 0) || (strategy > 10)) { printf("\nError! strategy=%d, should be ex {1,2,3,4,5,6,7,8,9,10}\n",strategy); exit(1); } if (inibound_h < inibound_l) { printf("\nError! inibound_h=%f < inibound_l=%f\n",inibound_h, inibound_l); exit(1); } /*-----Open output file-----------------------------------------------*/ //fpout_ptr = fopen(argv[2],"w"); /* open output file for writing */ //if (fpout_ptr == NULL) //{ //printf("\nCannot open output file\n"); //exit(1); //} /*-----Initialize random number generator-----------------------------*/ rnd_uni_init = -(long)seed; /* initialization of rnd_uni() */ nfeval = 0; /* reset number of function evaluations */ /*------Initialization------------------------------------------------*/ /*------Right now this part is kept fairly simple and just generates--*/ /*------random numbers in the range [-initfac, +initfac]. You might---*/ /*------want to extend the init part such that you can initialize-----*/ /*------each parameter separately.------------------------------------*/ for (i=0; i<NP; i++) { for (j=0; j<D; j++) /* spread initial population members */ { c[i][j] = inibound_l + rnd_uni(&rnd_uni_init)*(inibound_h - inibound_l); } cost[i] = evaluate(D,c[i],&nfeval); /* obj. funct. value */ } cmin = cost[0]; imin = 0; for (i=1; i<NP; i++) { if(MAXIMAPROBLEM == 1) { // 最大化問題 if (cost[i]>cmin) { cmin = cost[i]; imin = i; } } else { // 最小化問題 if (cost[i]<cmin) { cmin = cost[i]; imin = i; } } } assignd(D,best,c[imin]); /* save best member ever */ assignd(D,bestit,c[imin]); /* save best member of generation */ pold = &c; /* old population (generation G) */ pnew = &d; /* new population (generation G+1) */ /*=======================================================================*/ /*=========Iteration loop================================================*/ /*=======================================================================*/ gen = 0; /* generation counter reset */ while ((gen < genmax) /*&& (kbhit() == 0)*/) /* remove comments if conio.h */ { /* is accepted by compiler */ gen++; imin = 0; for (i=0; i<NP; i++) /* Start of loop through ensemble */ { do /* Pick a random population member */ { /* Endless loop for NP < 2 !!! */ r1 = (int)(rnd_uni(&rnd_uni_init)*NP); }while(r1==i); do /* Pick a random population member */ { /* Endless loop for NP < 3 !!! */ r2 = (int)(rnd_uni(&rnd_uni_init)*NP); }while((r2==i) || (r2==r1)); do /* Pick a random population member */ { /* Endless loop for NP < 4 !!! */ r3 = (int)(rnd_uni(&rnd_uni_init)*NP); }while((r3==i) || (r3==r1) || (r3==r2)); do /* Pick a random population member */ { /* Endless loop for NP < 5 !!! */ r4 = (int)(rnd_uni(&rnd_uni_init)*NP); }while((r4==i) || (r4==r1) || (r4==r2) || (r4==r3)); do /* Pick a random population member */ { /* Endless loop for NP < 6 !!! */ r5 = (int)(rnd_uni(&rnd_uni_init)*NP); }while((r5==i) || (r5==r1) || (r5==r2) || (r5==r3) || (r5==r4)); /*=======Choice of strategy===============================================================*/ /*=======We have tried to come up with a sensible naming-convention: DE/x/y/z=============*/ /*=======DE : stands for Differential Evolution==========================================*/ /*=======x : a string which denotes the vector to be perturbed==========================*/ /*=======y : number of difference vectors taken for perturbation of x===================*/ /*=======z : crossover method (exp = exponential, bin = binomial)=======================*/ /* */ /*=======There are some simple rules which are worth following:===========================*/ /*=======1) F is usually between 0.5 and 1 (in rare cases > 1)===========================*/ /*=======2) CR is between 0 and 1 with 0., 0.3, 0.7 and 1. being worth to be tried first=*/ /*=======3) To start off NP = 10*D is a reasonable choice. Increase NP if misconvergence=*/ /* happens. */ /*=======4) If you increase NP, F usually has to be decreased============================*/ /*=======5) When the DE/best... schemes fail DE/rand... usually works and vice versa=====*/ /*=======EXPONENTIAL CROSSOVER============================================================*/ /*-------DE/best/1/exp--------------------------------------------------------------------*/ /*-------Our oldest strategy but still not bad. However, we have found several------------*/ /*-------optimization problems where misconvergence occurs.-------------------------------*/ // 1 為最原始的解題邏輯方法 if (strategy == 1) /* strategy DE0 (not in our paper) */ { assignd(D,tmp,(*pold)[i]); n = (int)(rnd_uni(&rnd_uni_init)*D); L = 0; do { tmp[n] = bestit[n] + F*((*pold)[r2][n]-(*pold)[r3][n]); n = (n+1)%D; L++; }while((rnd_uni(&rnd_uni_init) < CR) && (L < D)); } /*-------DE/rand/1/exp-------------------------------------------------------------------*/ /*-------This is one of my favourite strategies. It works especially well when the-------*/ /*-------"bestit[]"-schemes experience misconvergence. Try e.g. F=0.7 and CR=0.5---------*/ /*-------as a first guess.---------------------------------------------------------------*/ // 配合邏輯方法 2 選用 R=0.7, CR=0.5 else if (strategy == 2) /* strategy DE1 in the techreport */ { assignd(D,tmp,(*pold)[i]); n = (int)(rnd_uni(&rnd_uni_init)*D); L = 0; do { tmp[n] = (*pold)[r1][n] + F*((*pold)[r2][n]-(*pold)[r3][n]); n = (n+1)%D; L++; }while((rnd_uni(&rnd_uni_init) < CR) && (L < D)); } /*-------DE/rand-to-best/1/exp-----------------------------------------------------------*/ /*-------This strategy seems to be one of the best strategies. Try F=0.85 and CR=1.------*/ /*-------If you get misconvergence try to increase NP. If this doesn't help you----------*/ /*-------should play around with all three control variables.----------------------------*/ // 方法 3 建議 F=0.85 CR=1. else if (strategy == 3) /* similiar to DE2 but generally better */ { assignd(D,tmp,(*pold)[i]); n = (int)(rnd_uni(&rnd_uni_init)*D); L = 0; do { tmp[n] = tmp[n] + F*(bestit[n] - tmp[n]) + F*((*pold)[r1][n]-(*pold)[r2][n]); n = (n+1)%D; L++; }while((rnd_uni(&rnd_uni_init) < CR) && (L < D)); } /*-------DE/best/2/exp is another powerful strategy worth trying--------------------------*/ else if (strategy == 4) { assignd(D,tmp,(*pold)[i]); n = (int)(rnd_uni(&rnd_uni_init)*D); L = 0; do { tmp[n] = bestit[n] + ((*pold)[r1][n]+(*pold)[r2][n]-(*pold)[r3][n]-(*pold)[r4][n])*F; n = (n+1)%D; L++; }while((rnd_uni(&rnd_uni_init) < CR) && (L < D)); } /*-------DE/rand/2/exp seems to be a robust optimizer for many functions-------------------*/ else if (strategy == 5) { assignd(D,tmp,(*pold)[i]); n = (int)(rnd_uni(&rnd_uni_init)*D); L = 0; do { tmp[n] = (*pold)[r5][n] + ((*pold)[r1][n]+(*pold)[r2][n]-(*pold)[r3][n]-(*pold)[r4][n])*F; n = (n+1)%D; L++; }while((rnd_uni(&rnd_uni_init) < CR) && (L < D)); } /*=======Essentially same strategies but BINOMIAL CROSSOVER===============================*/ /*-------DE/best/1/bin--------------------------------------------------------------------*/ else if (strategy == 6) { assignd(D,tmp,(*pold)[i]); n = (int)(rnd_uni(&rnd_uni_init)*D); for (L=0; L<D; L++) /* perform D binomial trials */ { if ((rnd_uni(&rnd_uni_init) < CR) || L == (D-1)) /* change at least one parameter */ { tmp[n] = bestit[n] + F*((*pold)[r2][n]-(*pold)[r3][n]); } n = (n+1)%D; } } /*-------DE/rand/1/bin-------------------------------------------------------------------*/ else if (strategy == 7) { assignd(D,tmp,(*pold)[i]); n = (int)(rnd_uni(&rnd_uni_init)*D); for (L=0; L<D; L++) /* perform D binomial trials */ { if ((rnd_uni(&rnd_uni_init) < CR) || L == (D-1)) /* change at least one parameter */ { tmp[n] = (*pold)[r1][n] + F*((*pold)[r2][n]-(*pold)[r3][n]); } n = (n+1)%D; } } /*-------DE/rand-to-best/1/bin-----------------------------------------------------------*/ else if (strategy == 8) { assignd(D,tmp,(*pold)[i]); n = (int)(rnd_uni(&rnd_uni_init)*D); for (L=0; L<D; L++) /* perform D binomial trials */ { if ((rnd_uni(&rnd_uni_init) < CR) || L == (D-1)) /* change at least one parameter */ { tmp[n] = tmp[n] + F*(bestit[n] - tmp[n]) + F*((*pold)[r1][n]-(*pold)[r2][n]); } n = (n+1)%D; } } /*-------DE/best/2/bin--------------------------------------------------------------------*/ else if (strategy == 9) { assignd(D,tmp,(*pold)[i]); n = (int)(rnd_uni(&rnd_uni_init)*D); for (L=0; L<D; L++) /* perform D binomial trials */ { if ((rnd_uni(&rnd_uni_init) < CR) || L == (D-1)) /* change at least one parameter */ { tmp[n] = bestit[n] + ((*pold)[r1][n]+(*pold)[r2][n]-(*pold)[r3][n]-(*pold)[r4][n])*F; } n = (n+1)%D; } } /*-------DE/rand/2/bin--------------------------------------------------------------------*/ else { assignd(D,tmp,(*pold)[i]); n = (int)(rnd_uni(&rnd_uni_init)*D); for (L=0; L<D; L++) /* perform D binomial trials */ { if ((rnd_uni(&rnd_uni_init) < CR) || L == (D-1)) /* change at least one parameter */ { tmp[n] = (*pold)[r5][n] + ((*pold)[r1][n]+(*pold)[r2][n]-(*pold)[r3][n]-(*pold)[r4][n])*F; } n = (n+1)%D; } } /*=======Trial mutation now in tmp[]. Test how good this choice really was.==================*/ trial_cost = evaluate(D,tmp,&nfeval); /* Evaluate new vector in tmp[] */ if(MAXIMAPROBLEM == 1) { // 改為最大化 if (trial_cost >= cost[i]) /* improved objective function value ? */ { cost[i]=trial_cost; assignd(D,(*pnew)[i],tmp); if (trial_cost>cmin) /* Was this a new minimum? */ { /* if so...*/ cmin=trial_cost; /* reset cmin to new low...*/ imin=i; assignd(D,best,tmp); } } else { assignd(D,(*pnew)[i],(*pold)[i]); /* replace target with old value */ } } else { // 最小化問題 if (trial_cost <= cost[i]) /* improved objective function value ? */ { cost[i]=trial_cost; assignd(D,(*pnew)[i],tmp); if (trial_cost<cmin) /* Was this a new minimum? */ { /* if so...*/ cmin=trial_cost; /* reset cmin to new low...*/ imin=i; assignd(D,best,tmp); } } else { assignd(D,(*pnew)[i],(*pold)[i]); /* replace target with old value */ } } } /* End mutation loop through pop. */ assignd(D,bestit,best); /* Save best population member of current iteration */ /* swap population arrays. New generation becomes old one */ pswap = pold; pold = pnew; pnew = pswap; /*----Compute the energy variance (just for monitoring purposes)-----------*/ cmean = 0.; /* compute the mean value first */ for (j=0; j<NP; j++) { cmean += cost[j]; } cmean = cmean/NP; cvar = 0.; /* now the variance */ for (j=0; j<NP; j++) { cvar += (cost[j] - cmean)*(cost[j] - cmean); } cvar = cvar/(NP-1); /*----Output part----------------------------------------------------------*/ if (gen%refresh==1) /* display after every refresh generations */ { /* ABORT works only if conio.h is accepted by your compiler */ printf("\n\n PRESS ANY KEY TO ABORT"); printf("\n\n\n Best-so-far cost funct. value=%-15.10g\n",cmin); for (j=0;j<D;j++) { printf("\n best[%d]=%-15.10g",j,best[j]); } printf("\n\n Generation=%d NFEs=%ld Strategy: %s ",gen,nfeval,strat[strategy]); printf("\n NP=%d F=%-4.2g CR=%-4.2g cost-variance=%-10.5g\n", NP,F,CR,cvar); } fprintf(fpout_ptr,"%ld %-15.10g\n",nfeval,cmin); } /*=======================================================================*/ /*=========End of iteration loop=========================================*/ /*=======================================================================*/ /*-------Final output in file-------------------------------------------*/ fprintf(fpout_ptr,"\n\n\n Best-so-far obj. funct. value = %-15.10g\n",cmin); for (j=0;j<D;j++) { fprintf(fpout_ptr,"\n best[%d]=%-15.10g",j,best[j]); } fprintf(fpout_ptr,"\n\n Generation=%d NFEs=%ld Strategy: %s ",gen,nfeval,strat[strategy]); fprintf(fpout_ptr,"\n NP=%d F=%-4.2g CR=%-4.2g cost-variance=%-10.5g\n", NP,F,CR,cvar); fclose(fpout_ptr); /* Code you want timed here */ printf("Time elapsed: %f\n", ((double)clock() - start) / CLOCKS_PER_SEC); return(0); } /*-----------End of main()------------------------------------------*/ // 適應函式 fittness function (cost function) double evaluate(int D, double tmp[], long *nfeval) { // 先處理通過 5 個點的四連桿問題 // x0, y0 為左方固定點座標, 必須在 0 ~ 100 間 - 設為 tmp[0], tmp[1] // x1, y1 為右方固定點座標, 必須在 0 ~ 100 間 - 設為 tmp[2], tmp[3] // L1 為第一桿件的長度, 必須 > 0, 且小於 100 - 設為 tmp[4] // L2 為第二桿件的長度, 必須 > 0, 且小於 100 - 設為 tmp[5] // L3 為第三桿件的長度, 必須 > 0, 且小於 100 - 設為 tmp[6] // L5, L6 與 L2 共同圍出可動桿 L2 對應的三角形, 關注的三角形頂點即 L5 與 L6 的交點, 而 angle3 則為 L6 之對應角(為固定值) // L5, L6 必須 > 0, 且小於 100 - 設為 tmp[7], tmp[8] // 以下的角度輸入值, 會隨著目標點數的增加而增加, 其索引值由 9 + 通過點數 - 1 決定, 5 點, 則索引至 13, 若通過 25 點, 則索引值為 9 + 24 = 33 // input_angles[] 為五的輸入的雙浮點數角度值,代表個體的角度向量值 - 分別設為 tmp[9], tmp[10], tmp[11], tmp[12], tmp[13] // 這裡的輸入角度值, 將採用以第一角度>0 作為起點, 隨後則為角度增量, 也都必須大於零 // output_points[] 則為與 input_angles[] 對應的五個三角形的頂點值, 為座標結構值, 分別有 x 與 y 分量值 // 當利用個體的向量值, 代入 mechanism 後所得到得 output_points[] 再與 target_points[] 進行 cost function 的誤差值最小化 /* void mechanism(double x0, double y0, double x1, double y1, double L1, double L2, double L3, double L5, double L6, double input_angles[NUM_OF_POINTS], struct Coord output_points[NUM_OF_POINTS])*/ struct Coord target_points[NUM_OF_POINTS], output_points[NUM_OF_POINTS]; double input_angles[NUM_OF_POINTS], result, total_angle; int i; (*nfeval)++; target_points[0].x = 4.5; target_points[0].y = 6.75; target_points[1].x = 5.07; target_points[1].y = 6.85; target_points[2].x = 5.45; target_points[2].y = 6.84; target_points[3].x = 5.89; target_points[3].y = 6.83; target_points[4].x = 6.41; target_points[4].y = 6.8; target_points[5].x = 6.92; target_points[5].y = 6.58; target_points[6].x = 7.03; target_points[6].y = 5.99; target_points[7].x = 6.95; target_points[7].y = 5.45; target_points[8].x = 6.77; target_points[8].y = 5.03; target_points[9].x = 6.4; target_points[9].y = 4.6; target_points[10].x = 5.91; target_points[10].y = 4.03; target_points[11].x = 5.43; target_points[11].y = 3.56; target_points[12].x = 4.93; target_points[12].y = 2.94; target_points[13].x = 4.67; target_points[13].y = 2.6; target_points[14].x = 4.38; target_points[14].y = 2.2; target_points[15].x = 4.04; target_points[15].y = 1.67; target_points[16].x = 3.76; target_points[16].y = 1.22; target_points[17].x = 3.76; target_points[17].y = 1.97; target_points[18].x = 3.76; target_points[18].y = 2.78; target_points[19].x = 3.76; target_points[19].y = 3.56; target_points[20].x = 3.76; target_points[20].y = 4.34; target_points[21].x = 3.76; target_points[21].y = 4.91; target_points[22].x = 3.76; target_points[22].y = 5.47; target_points[23].x = 3.8; target_points[23].y = 5.98; target_points[24].x = 4.07; target_points[24].y = 6.4; // 輸入角度值與 tmp[] 的設定 for(i = 0; i < NUM_OF_POINTS; i++) { input_angles[i] = tmp[i + 9]; } // 呼叫 mechanism() 以便計算 output_points[] mechanism(tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7], tmp[8], input_angles, output_points); // for debug /* if(*nfeval%5000 == 0) { for(i = 0; i < NUM_OF_POINTS; i++) { printf("%-15.10g : %-15.10g\n", output_points[i].x, output_points[i].y); } printf("#####################################\n"); } */ // 利用 output_points[] 與 target_points 計算誤差值, 該誤差值就是 cost result = error_function(output_points, target_points); // 這裡要分別針對各變數的約束條件與範圍值來設定傳回 PENALITY 或 誤差值 result // x0 與 x1 點位於 -50 與 50 中間 for(i = 0; i < 4; i++) { if(tmp[i] < -100 || tmp[i] > 100){ return PENALITY; } } // 三個連桿值, 一定要為正 for(i = 4; i < 7; i++) { if(tmp[i] < 0 || tmp[i] > 100){ return PENALITY; } } // L5 L6 可以為 0 或負值 for(i = 7; i < 9; i++) { if(tmp[i] < -100 || tmp[i] > 100){ return PENALITY; } } // 角度值不可以小於 0 for(i = 1; i <= NUM_OF_POINTS; i++) { if(tmp[D-i] < 0){ return PENALITY; } } /* for(i = 0; i < D - NUM_OF_POINTS; i++) { if((tmp[i] <= inibound_l)|| (tmp[i] >inibound_h)){ return PENALITY; } } for(i = 1; i <= NUM_OF_POINTS; i++) { if(tmp[D-i] < 0){ return PENALITY; } } */ return result; /* double result=0, surface = 80.0, z, volume, penality; (*nfeval)++; z = (surface-tmp[0]*tmp[1])/(2.0*(tmp[0]+tmp[1])); volume = tmp[0]*tmp[1]*z; if(volume <= 0){ return PENALITY; } if((tmp[0] <= inibound_l)|| (tmp[0] >inibound_h)){ return PENALITY; } if((tmp[1] <= inibound_l) || (tmp[1] >inibound_h)){ return PENALITY; } // volume must >0 and max volume // 目前為最小化問題 return 1+1/(volume*volume); */ } struct Coord triangletip_coord( double x0, double y0, double R0, double R1, double x1, double y1, double localt) { struct Coord tip_coord; if (localt>=0 && localt <PI) { // 目前蓋掉的式子為利用手動代換出來的版本 //x_value = ((x1-x0)*(-pow(R1,2)+pow(R0,2)+pow((y1-y0),2)+pow((x1-x0),2))/(2*sqrt(pow((y1-y0),2)+pow((x1-x0),2)))-(y1-y0)*(-mech_loop)*sqrt(fabs(pow(R0,2)-pow((-pow(R1,2)+pow(R0,2)+pow((y1-y0),2)+pow((x1-x0),2)),2)/(4*(pow((y1-y0),2)+pow((x1-x0),2))))))/sqrt(pow((y1-y0),2)+pow((x1-x0),2))+x0; // 以下的式子,先利用文字編輯器,將原先 stringout() 出來的 sqrt 替換成 sqrtt, 以防止被 maxima 中的 subst("^"=pow,expr) 所替換, subst 之後,再使用文字編輯器換回來,就可以得到正確的 C 對應碼. tip_coord.x = pow(sqrt(pow(y1-y0,2)+pow(x1-x0,2)),-1)*(mech_loop*(y1-y0)*sqrt(fabs(pow(R0,2)-pow(pow(y1-y0,2)+ pow(x1-x0,2),-1)*pow(-pow(R1,2)+pow(R0,2)+pow(y1-y0,2)+pow(x1-x0,2),2)/4))+(x1-x0)*pow(sqrt(pow(y1-y0,2)+ pow(x1-x0,2)),-1)*(-pow(R1,2)+pow(R0,2)+pow(y1-y0,2)+pow(x1-x0,2))/2)+x0; } else { // 目前蓋掉的式子為利用手動代換出來的版本 //x_value = ((x1-x0)*(-pow(R1,2)+pow(R0,2)+pow((y1-y0),2)+pow((x1-x0),2))/(2*sqrt(pow((y1-y0),2)+pow((x1-x0),2)))-(y1-y0)*(mech_loop)*sqrt(fabs(pow(R0,2)-pow((-pow(R1,2)+pow(R0,2)+pow((y1-y0),2)+pow((x1-x0),2)),2)/(4*(pow((y1-y0),2)+pow((x1-x0),2))))))/sqrt(pow((y1-y0),2)+pow((x1-x0),2))+x0; tip_coord.x = pow(sqrt(pow(y1-y0,2)+pow(x1-x0,2)),-1)*(-mech_loop*(y1-y0)*sqrt(fabs(pow(R0,2)-pow(pow(y1-y0,2)+ pow(x1-x0,2),-1)*pow(-pow(R1,2)+pow(R0,2)+pow(y1-y0,2)+pow(x1-x0,2),2)/4))+(x1-x0)*pow(sqrt(pow(y1-y0,2)+ pow(x1-x0,2)),-1)*(-pow(R1,2)+pow(R0,2)+pow(y1-y0,2)+ pow(x1-x0,2))/2)+x0; } // 請注意,與 Maxma 公式中的差異為,在 sqrt()中加入 fabs(),避免因為sqrt()中的負值而造成 NaN (Not a Number 問題. if (localt>=0 && localt <PI) { tip_coord.y = /*((x1-x0)*(-mech_loop)*sqrt( fabs(pow(R0,2)-pow((-pow(R1,2)+pow(R0,2)+pow((y1-y0),2)+pow((x1-x0),2)),2) /(4*(pow((y1-y0),2)+pow((x1-x0),2))) )) +(y1-y0)*(-pow(R1,2)+pow(R0,2)+pow((y1-y0),2)+pow((x1-x0),2))/(2*sqrt(pow((y1-y0),2)+pow((x1-x0),2))))/sqrt(pow((y1-y0),2)+pow((x1-x0),2)) +y0;*/ // 利用 sqrtt 居中進行代換所得到的式子 pow(sqrt(pow(y1-y0,2)+pow(x1-x0,2)),-1)*((y1-y0)*pow(sqrt(pow(y1-y0,2)+pow(x1-x0,2)),-1)*(-pow(R1,2)+ pow(R0,2)+pow(y1-y0,2)+pow(x1-x0,2))/2-mech_loop*(x1-x0)*sqrt(fabs(pow(R0,2)-pow(pow(y1-y0,2)+ pow(x1-x0,2),-1)*pow(-pow(R1,2)+pow(R0,2)+pow(y1-y0,2)+pow(x1-x0,2),2)/4)))+y0; } else { tip_coord.y = /*((x1-x0)*(mech_loop)*sqrt( fabs(pow(R0,2)-pow((-pow(R1,2)+pow(R0,2)+pow((y1-y0),2)+pow((x1-x0),2)),2) /(4*(pow((y1-y0),2)+pow((x1-x0),2))) )) +(y1-y0)*(-pow(R1,2)+pow(R0,2)+pow((y1-y0),2)+pow((x1-x0),2))/(2*sqrt(pow((y1-y0),2)+pow((x1-x0),2))))/sqrt(pow((y1-y0),2)+pow((x1-x0),2)) +y0;*/ pow(sqrt(pow(y1-y0,2)+pow(x1-x0,2)),-1)*((y1-y0)*pow(sqrt(pow(y1-y0,2)+pow(x1-x0,2)),-1)*(-pow(R1,2)+ pow(R0,2)+pow(y1-y0,2)+pow(x1-x0,2))/2+mech_loop*(x1-x0)*sqrt(fabs(pow(R0,2)-pow(pow(y1-y0,2)+ pow(x1-x0,2),-1)*pow(-pow(R1,2)+pow(R0,2)+pow(y1-y0,2)+pow(x1-x0,2),2)/4)))+y0; } return tip_coord; } double distance(double x0, double y0, double x1, double y1) { double distance_value; distance_value = sqrt(pow((x1-x0),2) + pow((y1-y0),2)); return distance_value; } double rr(double L1, double dd, double theta) { double rr_value; rr_value = sqrt(L1*L1+dd*dd - 2*L1*dd*cos(theta)); return rr_value; } // 輸入每一個體的變數向量, 然後求各三角形頂點的座標陣列[NUM_OF_POINTS] void mechanism(double x0, double y0, double x1, double y1, double L1, double L2, double L3, double L5, double L6, double input_angles[NUM_OF_POINTS], struct Coord output_points[NUM_OF_POINTS]) { // 這裡的輸入角度, 改採第一角度為起始角, 隨後的角度值則為增量值 // 此函式要輸入控制變數, 然後計算機構尺寸合成的關注點座標位置 // 以下為可能的處理變數宣告 // 這裡希望能夠定義一個 struct 來處理座標點 double rr_length, dd_length, angle; struct Coord link1_tip, link2_tip, triangle_tip; double angle2, angle3; int i; // 開始進行三角形頂點座標的計算 // 以下變數由每一個體向量提供 /* x0 = 0.0; y0 = 0.0; x1 = 10.0; y1 = 0.0; L1 = 5.0; L2 = 20; L3 = 10; L5 = 10; L6 = 10; */ dd_length = distance(x0, y0, x1, y1); /* 設法表示 triangle 所對應的 local 角度,表示為已知變數與 t 的函式 */ // 假如採用 finaltip_coord, 則不需要 angle3 angle3 = acos((pow(L2,2)+pow(L5,2)-pow(L6,2))/(2*L2*L5)); for(i = 0; i < NUM_OF_POINTS; i++) { // 先建立第一點座標, 即 i=0 者 // i=0; // angle = i*degree; /* // 利用角度增量進行運算, 相對於 input_angles[0] 作為基準 if(i > 0) { input_angles[i] = input_angles[i] + input_angles[i-1]; } */ angle = input_angles[i]*degree; rr_length = rr(L1, dd_length, angle); // 第一次三角形疊代 link1_tip = triangletip_coord(x0, y0, L1, rr_length, x1, y1, angle); // 第二次三角形疊代 /* 設法表示 link2 所對應的 local 角度,表示為已知變數與 t 的函式 */ angle2 = acos((pow(L2,2)+pow(rr_length,2)-pow(L3,2))/(2*L2*rr_length)); link2_tip = triangletip_coord(link1_tip.x, link1_tip.y, L2, L3, x1, y1, angle2); // 第三次三角形疊代 //triangle_tip = triangletip_coord(link1_tip.x, link1_tip.y, L5, L6, link2_tip.x, link2_tip.y, angle3); // output_points[i] = triangletip_coord(link1_tip.x, link1_tip.y, L5, L6, link2_tip.x, link2_tip.y, angle3); // 這裡要嘗試利用 finaltip_coord() 求 tip3 座標, 而 L5 與 L6 可 0 可負 output_points[i] = finaltip_coord(link1_tip, link2_tip, L5, L6); } } double error_function(struct Coord output_points[NUM_OF_POINTS], struct Coord target_points[NUM_OF_POINTS]) { double error = 0.0; int i; for(i = 0; i < NUM_OF_POINTS; i++) { error += fabs(distance(output_points[i].x, output_points[i].y, target_points[i].x, target_points[i].y)); } return error; } struct Coord finaltip_coord(struct Coord tip1_coord, struct Coord tip2_coord, double r1, double r2) { struct Coord tip3_coord; double theta3, theta4, length3, length4; length3 = sqrt(pow(tip2_coord.x - tip1_coord.x,2) + pow(tip2_coord.y - tip1_coord.y,2)); length4 = sqrt(pow(r1,2) + pow(r2,2)); theta3 = acos((tip2_coord.x - tip1_coord.x) / length3); theta4 = acos(r1 / length4); tip3_coord.x = tip1_coord.x + length4 * cos(theta3 + theta4); tip3_coord.y = tip1_coord.y + length4 * sin(theta3 + theta4); return tip3_coord; }
Comments
comments powered by Disqus