SOT
dds.h
1 
8 #ifndef SOT_DDS_H
9 #define SOT_DDS_H
10 
11 #include <iostream>
12 #include "common.h"
13 #include "utils.h"
14 #include <thread>
15 #include <mutex>
16 
18 namespace sot {
19 
21 
32  class DDS {
33  protected:
34  std::shared_ptr<Problem> mData;
35  std::shared_ptr<ExpDesign> mExpDes;
36  int mMaxEvals;
37  int mNumEvals;
39  int mDim;
42  std::string mName = "DDS";
44  int mEvalCount = 0;
45  std::mutex mMutex;
47 
52  void evalBatch(const mat &batch, vec &funVals) {
53  mMutex.lock();
54  int myEval = mEvalCount;
55  mEvalCount++;
56  mMutex.unlock();
57 
58  while(myEval < batch.n_cols) {
59  vec x = batch.col(myEval);
60  funVals[myEval] = mData->eval(x);
61 
62  mMutex.lock();
63  myEval = mEvalCount;
64  mEvalCount++;
65  mMutex.unlock();
66  }
67  }
68  public:
70 
75  DDS(std::shared_ptr<Problem>& data, std::shared_ptr<ExpDesign>& expDes, int maxEvals) {
76  mData = std::shared_ptr<Problem>(data);
77  mExpDes = std::shared_ptr<ExpDesign>(expDes);
78  mMaxEvals = maxEvals;
79  mNumEvals = 0;
80  mInitPoints = expDes->numPoints();
81  mDim = data->dim();
82  mxLow = data->lBounds();
83  mxUp = data->uBounds();
84  mName = "DDS";
85  mNumThreads = 1;
86  if(mMaxEvals < mInitPoints) {
87  throw std::logic_error("Experimental design larger than evaluation budget");
88  }
89  }
91 
97  DDS(std::shared_ptr<Problem>& data, std::shared_ptr<ExpDesign>& expDes, int maxEvals, int numThreads)
98  : DDS(data, expDes, maxEvals) {
99  mNumThreads = numThreads;
100  }
101 
103 
107  std::vector<std::thread> threads(mNumThreads);
108  Result res(mMaxEvals, mDim);
109  mNumEvals = 0;
110 
111  vec sigma = 0.2*(mxUp - mxLow);
112  mat initDes = fromUnitBox(mExpDes->generatePoints(), mxLow, mxUp);
113  vec initFunVal = arma::zeros(mInitPoints);
114 
115  if(mNumThreads > 1) { // Evaluate in synchronous parallel
116  mEvalCount = 0;
117  for(int i=0; i < mNumThreads; i++) {
118  threads[i] = std::thread(&sot::DDS::evalBatch, this,
119  std::ref(initDes), std::ref(initFunVal));
120  }
121 
122  for(int i=0; i < mNumThreads; i++) {
123  threads[i].join();
124  }
125  }
126  else { // Evaluate in serial
127  for(int i=0; i < mInitPoints; i++) {
128  vec x = initDes.col(i);
129  initFunVal(i) = mData->eval(x);
130  }
131  }
132 
133  res.addEvals(initDes, initFunVal);
134  mNumEvals += mInitPoints;
135 
136  while (mNumEvals < mMaxEvals) {
137 
139  double ddsProb = 1 - std::log((double)mNumEvals - mInitPoints)/
140  std::log((double)mMaxEvals - mInitPoints);
141  ddsProb = fmax(ddsProb, 1.0/mDim);
142 
143  int newEvals = std::min<int>(mNumThreads, mMaxEvals - mNumEvals);
144  mat batch = arma::zeros<mat>(mDim, newEvals);
145  vec batchVals = arma::zeros(newEvals);
146 
147  for(int i=0; i < newEvals; i++) {
148  vec cand = res.xBest();
149  int count = 0;
150  for(int j=0; j < mDim; j++) {
151  if(rand() < ddsProb) {
152  count++;
153  cand(j) += sigma(j) * randn();
154  if(cand(j) > mxUp(j)) {
155  cand(j) = fmax(2*mxUp(j) - cand(j), mxLow(j));
156  }
157  else if(cand(j) < mxLow(j)) {
158  cand(j) = fmin(2*mxLow(j) - cand(j), mxUp(j));
159  }
160  }
161  }
162  // If no index was perturbed we force one
163  if(count == 0) {
164  int ind = randi(mDim-1);
165  cand(ind) += sigma(ind) * randn();
166  if(cand(ind) > mxUp(ind)) {
167  cand(ind) = fmax(2*mxUp(ind) - cand(ind), mxLow(ind));
168  }
169  else if(cand(ind) < mxLow(ind)) {
170  cand(ind) = fmin(2*mxLow(ind) - cand(ind), mxUp(ind));
171  }
172  }
173  batch.col(i) = cand;
174  }
175 
176 
177  if(newEvals > 1) { // Evaluate in synchronous parallel
178  mEvalCount = 0;
179  for(int i=0; i < newEvals; i++) {
180  threads[i] = std::thread(&sot::DDS::evalBatch, this,
181  std::ref(batch), std::ref(batchVals));
182  }
183 
184  for(int i=0; i < newEvals; i++) {
185  threads[i].join();
186  }
187  }
188  else { // Evaluate in serial
189  batchVals(0) = mData->eval((vec)batch);
190  }
191 
192  // Update evaluation counter
193  mNumEvals += newEvals;
194  res.addEvals(batch, batchVals);
195  }
196 
197  return res;
198  }
199  };
200 }
201 
202 #endif
Optimization result class.
Definition: utils.h:138
void evalBatch(const mat &batch, vec &funVals)
Evalaute a batch of points in parallel.
Definition: dds.h:52
int mNumThreads
Definition: dds.h:43
Result run()
Runs the optimization algorithm.
Definition: dds.h:106
arma::vec vec
Default (column) vector class.
Definition: common.h:17
vec xBest() const
Method for getting the best solution found so far.
Definition: utils.h:204
void addEvals(const mat &X, const vec &funVals)
Method for adding a finished evaluations.
Definition: utils.h:245
int mNumEvals
Definition: dds.h:37
DDS(std::shared_ptr< Problem > &data, std::shared_ptr< ExpDesign > &expDes, int maxEvals, int numThreads)
Constructor.
Definition: dds.h:97
The Dynamically Dimensioned Search optimization algorithm.
Definition: dds.h:32
int mInitPoints
Definition: dds.h:38
double rand()
Generate a U[0,1] realization.
Definition: utils.h:386
int mMaxEvals
Definition: dds.h:36
double randi(int i)
Generate a random integer.
Definition: utils.h:364
std::shared_ptr< Problem > mData
Definition: dds.h:34
vec mxLow
Definition: dds.h:40
std::shared_ptr< ExpDesign > mExpDes
Definition: dds.h:35
vec fromUnitBox(const vec &x, const vec &xLow, const vec &xUp)
Map one point from the unit box to another hypercube.
Definition: utils.h:94
double randn()
Generate a N(0,1) realization.
Definition: utils.h:375
SOT namespace.
Definition: sot.h:27
std::mutex mMutex
Definition: dds.h:45
vec mxUp
Definition: dds.h:41
arma::mat mat
Default matrix class.
Definition: common.h:16
DDS(std::shared_ptr< Problem > &data, std::shared_ptr< ExpDesign > &expDes, int maxEvals)
Constructor.
Definition: dds.h:75
std::string mName
Definition: dds.h:42
int mEvalCount
Definition: dds.h:44
int mDim
Definition: dds.h:39