Skip to content

Commit 9646d5f

Browse files
committed
improved randD() and new TSP instance
1 parent a2d74a3 commit 9646d5f

4 files changed

Lines changed: 166 additions & 47 deletions

File tree

GA/Genetic.h

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@ This file is part of OptimTemplates.
2424
#include <list>
2525
#include <tuple>
2626
#include <cmath>
27+
#include <random>
2728
#include <algorithm>
2829

29-
#ifdef OptimT_OUTPUT
30+
#ifndef OptimT_NO_OUTPUT
3031
#include <iostream>
3132
#endif
3233
namespace OptimT {
@@ -35,9 +36,12 @@ namespace OptimT {
3536

3637
namespace OptimT
3738
{
38-
///uniform random number in range [0,1]
39+
///uniform random number in range [0,1)
3940
double randD() {
40-
return (std::rand()%RAND_MAX)/double(RAND_MAX);
41+
static std::uniform_real_distribution<double> rnd(0,1);
42+
static std::mt19937 mt(std::rand());
43+
return rnd.operator()(mt);
44+
//return (std::rand()%RAND_MAX)/double(RAND_MAX);
4145
}
4246
///uniform random number in range [min,max]
4347
double randD(const double min,const double max) {
@@ -152,18 +156,18 @@ class GA {
152156
select();
153157
_recording.emplace_back(_eliteIt->fitness());
154158
if(_generation>_option.maxGenerations) {
155-
#ifdef OptimT_OUTPUT
159+
#ifndef OptimT_NO_OUTPUT
156160
std::cout<<"Terminated by max generation limit"<<std::endl;
157161
#endif
158162
break;
159163
}
160164
if(_option.maxFailTimes>0&&_failTimes>_option.maxFailTimes) {
161-
#ifdef OptimT_OUTPUT
165+
#ifndef OptimT_NO_OUTPUT
162166
std::cout<<"Terminated by max failTime limit"<<std::endl;
163167
#endif
164168
break;
165169
}
166-
#ifdef OptimT_OUTPUT
170+
#ifndef OptimT_NO_OUTPUT
167171
std::cout<<"Generation "<<_generation<<" , elite fitness="<<_eliteIt->fitness()<<std::endl;
168172
#endif
169173
_otherOptFun(&_args,&_population,_generation,_failTimes,&_option);

test/def_TestingFuns.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,13 @@ This file is part of OptimTemplates.
2121
#define DEF_TESTINGFUNS_H
2222

2323
void testSingleNumber();
24+
2425
///Using libEigen with OptimTemplates
2526
void testWithEigenLib();
27+
2628
///Ackely function
2729
void testAckley();
30+
2831
///TSP problem
29-
void testTSP();
32+
void testTSP(const unsigned int pointNum=10);
3033
#endif // DEF_TESTINGFUNS_H

test/imp_TestingFuns.cpp

Lines changed: 151 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -29,52 +29,52 @@ void testAckley() {
2929
opt.maxGenerations=1000;
3030
opt.maxFailTimes=100;
3131
static const uint8_t MinIdx=0,MaxIdx=1,LrIdx=2;
32-
GA<std::array<double,2>,false,std::array<double,2>,std::array<double,2>,double> algo;
32+
GA<array<double,2>,false,array<double,2>,array<double,2>,double> algo;
3333

34-
std::tuple<std::array<double,2>,std::array<double,2>,double> args;
35-
std::get<MinIdx>(args)={-5,-5};
36-
std::get<MaxIdx>(args)={5,5};
37-
std::get<LrIdx>(args)=0.05;
34+
tuple<array<double,2>,array<double,2>,double> args;
35+
get<MinIdx>(args)={-5,-5};
36+
get<MaxIdx>(args)={5,5};
37+
get<LrIdx>(args)=0.05;
3838

3939
algo.initialize(
40-
//initializer for std::array<double,2>
41-
[](std::array<double,2>* x,const typeof(args) * a) {
40+
//initializer for array<double,2>
41+
[](array<double,2>* x,const typeof(args) * a) {
4242
for(uint32_t idx=0;idx<x->size();idx++) {
43-
x->operator[](idx)=randD(std::get<MinIdx>(*a)[idx],std::get<MaxIdx>(*a)[idx]);
43+
x->operator[](idx)=randD(get<MinIdx>(*a)[idx],get<MaxIdx>(*a)[idx]);
4444
}},
4545
//Ackely function
46-
[](const std::array<double,2>* _x,const typeof(args) *) {
46+
[](const array<double,2>* _x,const typeof(args) *) {
4747
double x=_x->operator[](0),y=_x->operator[](1);
4848
return -20*exp(-0.2*sqrt(0.5*(x*x+y*y)))
4949
-exp(0.5*(cos(M_2_PI*x)+cos(M_2_PI*y)))
5050
+20+M_E;},
5151
//crossover
52-
[](const std::array<double,2>* x,const std::array<double,2>* y,
53-
std::array<double,2> *X,std::array<double,2>*Y,
52+
[](const array<double,2>* x,const array<double,2>* y,
53+
array<double,2> *X,array<double,2>*Y,
5454
const typeof(args) *) {
55-
const std::array<double,2> &copyx=*x,&copyy=*y;
55+
const array<double,2> &copyx=*x,&copyy=*y;
5656
for(uint32_t idx=0;idx<x->size();idx++) {
57-
if(std::rand()%2)
57+
if(rand()%2)
5858
X->operator[](idx)=copyy[idx];
5959
else {
6060
X->operator[](idx)=copyx[idx];
6161
}
62-
if(std::rand()%2)
62+
if(rand()%2)
6363
Y->operator[](idx)=copyx[idx];
6464
else {
6565
Y->operator[](idx)=copyy[idx];
6666
}
6767
}},
6868
//mutate
69-
[](std::array<double,2>* x,const typeof(args) * a) {
70-
uint8_t mutateIdx=std::rand()%x->size();
71-
x->operator[](mutateIdx)+=std::get<LrIdx>(*a)*randD(-1,1);
72-
if(std::rand()%2)
69+
[](array<double,2>* x,const typeof(args) * a) {
70+
uint8_t mutateIdx=rand()%x->size();
71+
x->operator[](mutateIdx)+=get<LrIdx>(*a)*randD(-1,1);
72+
if(rand()%2)
7373
x->operator[](mutateIdx)*=-1;
7474
for(uint32_t idx=0;idx<x->size();idx++) {
7575
auto & var=x->operator[](idx);
76-
var=std::min(var,std::get<MaxIdx>(*a)[idx]);
77-
var=std::max(var,std::get<MinIdx>(*a)[idx]);
76+
var=min(var,get<MaxIdx>(*a)[idx]);
77+
var=max(var,get<MinIdx>(*a)[idx]);
7878
}
7979
},
8080
//no other options
@@ -100,16 +100,16 @@ void testSingleNumber() {
100100
opt.maxGenerations=3000;
101101
algo.initialize(
102102
[](double * x,const tuple<>*){*x=randD();},
103-
[](const double * x,const tuple<>*){return 1.0/(std::abs(*x-3.0)+1e-8);},
103+
[](const double * x,const tuple<>*){return 1.0/(abs(*x-3.0)+1e-8);},
104104
[](const double * x,const double *y,double *X,double *Y,const tuple<>*)
105105
{double mean=(*x+*y)/2;*X=(*x+mean)/2;*Y=(*y+mean)/2;},
106106
[](double * x,const tuple<>*)
107107
{
108-
//if(std::rand()%2)*x*=-1;
108+
//if(rand()%2)*x*=-1;
109109
*x+=randD(-1,1)*0.5;},
110110
nullptr,
111111
opt,
112-
std::tuple<>()
112+
tuple<>()
113113
);
114114

115115
cout << "Start" << endl;
@@ -131,41 +131,41 @@ void testWithEigenLib() {
131131

132132
GA<Eigen::Array4d,true,Eigen::Array4d,Eigen::Array4d,Eigen::Array4d,double> algo;
133133
//val min max learning_rate
134-
std::tuple<Eigen::Array4d,Eigen::Array4d,Eigen::Array4d,double> Arg;
134+
tuple<Eigen::Array4d,Eigen::Array4d,Eigen::Array4d,double> Arg;
135135
static const uint8_t TargetOffset=0,MinOffset=1,MaxOffset=2,LROffset=3;
136-
std::get<TargetOffset>(Arg)=target;
137-
std::get<MinOffset>(Arg).setConstant(-1);
138-
std::get<MaxOffset>(Arg).setConstant(2);
139-
std::get<LROffset>(Arg)=0.01;
136+
get<TargetOffset>(Arg)=target;
137+
get<MinOffset>(Arg).setConstant(-1);
138+
get<MaxOffset>(Arg).setConstant(2);
139+
get<LROffset>(Arg)=0.01;
140140

141141
//typeof(Arg)
142142

143143

144144
algo.initialize(
145145
[](Eigen::Array4d* x,const typeof(Arg)*){x->setRandom();},
146146
[](const Eigen::Array4d* x,const typeof(Arg)* arg){
147-
return -(*x-std::get<TargetOffset>(*arg)).square().maxCoeff();
147+
return -(*x-get<TargetOffset>(*arg)).square().maxCoeff();
148148
},
149149
[](const Eigen::Array4d*x,const Eigen::Array4d*y,
150150
Eigen::Array4d*X,Eigen::Array4d*Y,
151151
const typeof(Arg)*) {
152152
for(uint32_t i=0;i<4;i++) {
153153
X->operator()(i)=
154-
(std::rand()%2)?
154+
(rand()%2)?
155155
x->operator()(i):y->operator()(i);
156156
Y->operator()(i)=
157-
(std::rand()%2)?
157+
(rand()%2)?
158158
x->operator()(i):y->operator()(i);
159159
}},
160160
[](Eigen::Array4d*x,const typeof(Arg)* arg) {
161-
uint32_t idx=std::rand()%4;
162-
x->operator()(idx)+=randD(-1,1)*std::get<LROffset>(*arg);
161+
uint32_t idx=rand()%4;
162+
x->operator()(idx)+=randD(-1,1)*get<LROffset>(*arg);
163163

164-
if(x->operator()(idx)>std::get<MaxOffset>(*arg)(idx)) {
165-
x->operator()(idx)=std::get<MaxOffset>(*arg)(idx);
164+
if(x->operator()(idx)>get<MaxOffset>(*arg)(idx)) {
165+
x->operator()(idx)=get<MaxOffset>(*arg)(idx);
166166
}
167-
if(x->operator()(idx)<std::get<MinOffset>(*arg)(idx)) {
168-
x->operator()(idx)=std::get<MinOffset>(*arg)(idx);
167+
if(x->operator()(idx)<get<MinOffset>(*arg)(idx)) {
168+
x->operator()(idx)=get<MinOffset>(*arg)(idx);
169169
}},
170170
nullptr,
171171
opt,
@@ -177,9 +177,120 @@ void testWithEigenLib() {
177177
cout<<"Result = "<<algo.result().transpose()<<endl;
178178
}
179179

180+
void testTSP(const uint32_t PointNum) {
181+
static const uint8_t DIM=2;
182+
//static const double LengthBase=100;
183+
typedef array<double,DIM> Point_t;
184+
vector<Point_t> points;
185+
points.clear();
186+
points.reserve(PointNum);
187+
for(uint32_t i=0;i<PointNum;i++) {
188+
points.emplace_back();
189+
for(auto & i : points.back()) {
190+
i=randD();
191+
}
192+
}
193+
cout<<"Generated random points :"<<endl;
194+
for(const auto & i : points) {
195+
cout<<'(';
196+
for(auto j : i) {
197+
cout<<j<<" , ";
198+
}
199+
cout<<")"<<endl;
200+
}
201+
typedef pair<double,uint32_t> permUnit;
202+
203+
//typedef vector<permUnit> permulation;
204+
// var, less=better, data src
205+
GA<vector<double>,false,const vector<Point_t>*> algo;
206+
static const uint8_t dataIdx=0;
207+
typedef tuple<const vector<Point_t>*> Args_t;
208+
Args_t args;//=make_tuple(PointNum,points.data());
209+
get<dataIdx>(args)=&points;
210+
//initialize function
211+
212+
auto initializeFun=[](vector<double> * x,const Args_t* args) {
213+
const uint32_t permL=get<dataIdx>(*args)->size();
214+
x->resize(permL);
215+
for(uint32_t i=0;i<permL;i++) {
216+
x->at(i)=OptimT::randD();
217+
}
218+
};
219+
220+
//calculate fitness
221+
auto calculateFun=[](const vector<double> *x,const Args_t* args) {
222+
const uint32_t permL=x->size();
223+
vector<permUnit> perm(permL);
224+
for(uint32_t i=0;i<permL;i++) {
225+
perm[i].first=x->at(i);
226+
perm[i].second=i;
227+
}
228+
std::sort(perm.begin(),perm.end(),
229+
//compare function for std::sort
230+
[](const permUnit &a,const permUnit &b)
231+
{ return a.first>b.first;});
232+
double L=0;
233+
for(uint32_t i=1;i<permL;i++) {
234+
const Point_t &prev=get<dataIdx>(*args)->at(perm[i-1].second);
235+
const Point_t &cur=get<dataIdx>(*args)->at(perm[i].second);
236+
double curL=0;
237+
for(uint8_t d=0;d<DIM;d++) {
238+
curL+=(prev[d]-cur[d])*(prev[d]-cur[d]);
239+
}
240+
L+=curL;
241+
} return L;};
242+
243+
//calculate natural perm pathL
244+
{
245+
vector<double> natural(PointNum);
246+
for(uint32_t i=0;i<PointNum;i++) {
247+
natural[i]=double(i)/PointNum;
248+
}
249+
double naturalPathL=calculateFun(&natural,&args);
250+
cout<<"default pathL = "<<naturalPathL<<endl;
251+
}
252+
253+
auto crossoverFun=[](const vector<double>*p1,const vector<double>*p2,
254+
vector<double>*c1,vector<double>*c2,const Args_t*) {
255+
const uint32_t permL=p1->size();
256+
c1->resize(permL);c2->resize(permL);
257+
for(uint32_t i=0;i<permL;i++) {
258+
c1->at(i)=(std::rand()%2)?p1->at(i):p2->at(i);
259+
c2->at(i)=(std::rand()%2)?p1->at(i):p2->at(i);
260+
}
261+
};
262+
263+
auto mutateFun=[](vector<double>*x,const Args_t*) {
264+
const uint32_t permL=x->size();
265+
if(randD()<0.5) {//modify one element's value
266+
double & v=x->at(std::rand()%permL);
267+
v+=randD(-0.01,0.01);
268+
v=min(v,1.0);
269+
v=max(v,0.0);
270+
}
271+
else {
272+
const uint32_t flipB=std::rand()%(permL-1);
273+
const uint32_t flipE=std::rand()%(permL-flipB-1)+flipB+1;
274+
//cout<<"flipB="<<flipB<<" , flipE"<<flipE<<endl;
275+
const uint32_t flipN=flipE-flipB+1;
276+
for(uint32_t flipped=0;flipped*2<=flipN;flipped++) {
277+
swap(x->at(flipB+flipped),x->at(flipE-flipped));
278+
}
279+
}
280+
};
281+
282+
283+
GAOption opt;
284+
opt.maxGenerations=30*PointNum;
285+
algo.initialize(initializeFun,calculateFun,crossoverFun,mutateFun,nullptr,
286+
opt,args);
287+
288+
cout<<"run!"<<endl;
289+
algo.run();
290+
cout<<"finished with "<<algo.generation()<<" generations\n";
291+
cout<<"result fitness = "<<algo.eliteIt()->fitness()<<endl;
292+
293+
180294

181-
void testTSP() {
182-
typedef std::array<double,2> Point_t;
183-
std::vector<Point_t> points;
184295
}
185296

test/main.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ void initializeSrand();
2929
int main()
3030
{
3131
initializeSrand();
32+
testTSP(20);
3233
return 0;
3334
}
3435

0 commit comments

Comments
 (0)