chiark / gitweb /
add nlopt_get_errmsg(opt) for more informative error messages; automatically used...
[nlopt.git] / esch / esch.c
1 /* Copyright (c) 2008-2013 Carlos Henrique da Silva Santos
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining
4  * a copy of this software and associated documentation files (the
5  * "Software"), to deal in the Software without restriction, including
6  * without limitation the rights to use, copy, modify, merge, publish,
7  * distribute, sublicense, and/or sell copies of the Software, and to
8  * permit persons to whom the Software is furnished to do so, subject to
9  * the following conditions:
10  * 
11  * The above copyright notice and this permission notice shall be
12  * included in all copies or substantial portions of the Software.
13  * 
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
21  */
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include "esch.h"
26
27 // ---------------------------------------------------------------------------
28 // Cauchy random number distribution
29 static double randcauchy(const double params[7]) {
30      /* double min, double max, double mi, double t, double band */
31      double na_unif, cauchy_mit, limit_inf, limit_sup;
32      double valor;
33      double min = params[1], max = params[2], mi = params[3],
34           t = params[4], band = params[5];
35      limit_inf = mi - (band*0.5);
36      limit_sup = mi + (band*0.5);
37      do {
38           na_unif = nlopt_urand(0,1); // ran2(0,1);
39           cauchy_mit = t*tan((na_unif-0.5)*3.14159265358979323846) + mi;
40      } while ( (cauchy_mit<limit_inf) || (cauchy_mit>limit_sup) );   
41      
42      if (cauchy_mit < 0)
43           cauchy_mit = -cauchy_mit;
44      else
45           cauchy_mit = cauchy_mit + (band*0.5);
46      valor  = cauchy_mit/band;
47      valor = min+(max-min)*valor;   
48      return valor;  
49 }
50
51 // ---------------------------------------------------------------------------
52
53 // main Individual representation type
54 typedef struct IndividualStructure {
55      double * parameters;
56      double fitness;
57 } Individual; 
58
59 static int CompareIndividuals(void *unused, const void *a_, const void *b_) {
60      // (void) unused;
61      const Individual *a = (const Individual *) a_;
62      const Individual *b = (const Individual *) b_;
63      return a->fitness < b->fitness ? -1 : (a->fitness > b->fitness ? +1 : 0);
64 }
65
66 nlopt_result chevolutionarystrategy( 
67      unsigned nparameters, /* Number of input parameters */
68      nlopt_func f,      /* Recursive Objective Funtion Call */
69      void * data_f,     /* Data to Objective Function */
70      const double* lb,                  /* Lower bound values */
71      const double* ub,                  /* Upper bound values */
72      double* x,                         /*in: initial guess, out: minimizer */
73      double* minf,
74      nlopt_stopping* stop,              /* nlopt stop condition */
75      unsigned np,                       /* Number of Parents */ 
76      unsigned no) {                     /* Number of Offsprings */
77
78      // variables from nlopt
79      nlopt_result ret = NLOPT_SUCCESS;
80      double vetor[8];
81      unsigned  i, id, item;
82      int  parent1, parent2;
83      unsigned crosspoint;  // crossover parameteres
84      int  contmutation, totalmutation;  // mutation parameters
85      int  idoffmutation, paramoffmutation;      // mutation parameters
86      Individual * esparents;                    // Parents population
87      Individual * esoffsprings;         // Offsprings population
88      Individual * estotal;// copy containing Parents and Offsprings pops
89      /* It is interesting to maintain the parents and offsprings
90       * populations stablished and sorted; when the final iterations
91       * is achieved, they are ranked and updated. */
92
93      // -------------------------------
94      // controling the population size
95      // -------------------------------
96      if (!np) np = 40;
97      if (!no) no = 60;     
98      if ((np < 1)||(no<1)) {
99          nlopt_stop_msg(stop, "populations %d, %d are too small", np, no);
100          return NLOPT_INVALID_ARGS;
101      }
102      esparents    = (Individual*) malloc(sizeof(Individual) * np);
103      esoffsprings = (Individual*) malloc(sizeof(Individual) * no);
104      estotal     = (Individual*) malloc(sizeof(Individual) * (np+no));
105      if ((!esparents)||(!esoffsprings)||(!estotal)) { 
106           free(esparents); free(esoffsprings); free(estotal); 
107           return NLOPT_OUT_OF_MEMORY;
108      }
109      for (id=0; id < np; id++) esparents[id].parameters = NULL;
110      for (id=0; id < no; id++) esoffsprings[id].parameters = NULL;
111      // From here the population is initialized 
112      /* we don't handle unbounded search regions;
113         this check is unnecessary since it is performed in nlopt_optimize.
114         for (j = 0; j < nparameters; ++j) 
115           if (nlopt_isinf(low[j]) || nlopt_isinf(up[j]))
116             return NLOPT_INVALID_ARGS;
117      */
118      // main vector of parameters to randcauchy
119      vetor[0] = 4; // ignored
120      vetor[3] = 0;
121      vetor[4] = 1;
122      vetor[5] = 10;
123      vetor[6] = 1;      
124      vetor[7] = 0; // ignored
125      // ------------------------------------
126      // Initializing parents population
127      // ------------------------------------
128      for (id=0; id < np; id++) {
129           esparents[id].parameters = 
130                (double*) malloc(sizeof(double) * nparameters);
131           if (!esparents[id].parameters) {
132                ret = NLOPT_OUT_OF_MEMORY;
133                goto done;
134           }
135           for (item=0; item<nparameters; item++) {
136                vetor[1] = lb[item];     
137                vetor[2] = ub[item];
138                vetor[7]=vetor[7]+1;
139                esparents[id].parameters[item] = randcauchy(vetor);
140           }
141      }
142      memcpy(esparents[0].parameters, x, nparameters * sizeof(double));
143
144      // ------------------------------------
145      // Initializing offsprings population
146      // ------------------------------------
147      for (id=0; id < no; id++) {
148           esoffsprings[id].parameters = 
149                (double*) malloc(sizeof(double) * nparameters);
150           if (!esoffsprings[id].parameters) {
151                ret = NLOPT_OUT_OF_MEMORY;
152                goto done;
153           }
154           for (item=0; item<nparameters; item++) {
155                vetor[1] = lb[item];     
156                vetor[2] = ub[item];
157                vetor[7]=vetor[7]+1;
158                esoffsprings[id].parameters[item] = randcauchy(vetor);
159           }
160      }
161      // ------------------------------------
162      // Parents fitness evaluation  
163      // ------------------------------------
164      for (id=0; id < np; id++) { 
165           esparents[id].fitness = 
166                f(nparameters, esparents[id].parameters, NULL, data_f);
167           estotal[id].fitness = esparents[id].fitness;
168           stop->nevals++;
169           if (*minf > esparents[id].fitness) {
170                *minf = esparents[id].fitness;
171                memcpy(x, esparents[id].parameters, 
172                       nparameters * sizeof(double));
173           }
174           if (nlopt_stop_forced(stop)) ret = NLOPT_FORCED_STOP;
175           else if (*minf < stop->minf_max) ret = NLOPT_MINF_MAX_REACHED;
176           else if (nlopt_stop_evals(stop)) ret = NLOPT_MAXEVAL_REACHED;
177           else if (nlopt_stop_time(stop)) ret = NLOPT_MAXTIME_REACHED;
178           if (ret != NLOPT_SUCCESS) goto done;
179      }
180      // ------------------------------------
181      // Main Loop - Generations
182      // ------------------------------------
183      while (1) {
184           // ------------------------------------
185           // Crossover 
186           // ------------------------------------
187           for (id=0; id < no; id++)
188           {
189                parent1  = nlopt_iurand((int) np);
190                parent2  = nlopt_iurand((int) np);
191                crosspoint = (unsigned) nlopt_iurand((int) nparameters);
192                for (item=0; item < crosspoint; item++)
193                     esoffsprings[id].parameters[item] 
194                          = esparents[parent1].parameters[item]; 
195                for (item=crosspoint; item < nparameters; item++)
196                     esoffsprings[id].parameters[item] 
197                          = esparents[parent2].parameters[item]; 
198           }
199           // ------------------------------------
200           // Gaussian Mutation 
201           // ------------------------------------
202           totalmutation = (int) ((no * nparameters) / 10);
203           if (totalmutation < 1) totalmutation = 1;
204           for (contmutation=0; contmutation < totalmutation;
205                contmutation++) {
206                idoffmutation = nlopt_iurand((int) no);
207                paramoffmutation = nlopt_iurand((int) nparameters);
208                vetor[1] = lb[paramoffmutation]; 
209                vetor[2] = ub[paramoffmutation];
210                vetor[7] = vetor[7]+contmutation;
211                esoffsprings[idoffmutation].parameters[paramoffmutation] 
212                     = randcauchy(vetor);
213           }
214           // ------------------------------------
215           // Offsprings fitness evaluation 
216           // ------------------------------------
217           for (id=0; id < no; id++){ 
218                //esoffsprings[id].fitness = (double)fitness(esoffsprings[id].parameters, nparameters,fittype);
219                esoffsprings[id].fitness = f(nparameters, esoffsprings[id].parameters, NULL, data_f);
220                estotal[id+np].fitness = esoffsprings[id].fitness;
221                stop->nevals++;
222                if (*minf > esoffsprings[id].fitness) {
223                     *minf = esoffsprings[id].fitness;
224                     memcpy(x, esoffsprings[id].parameters, 
225                            nparameters * sizeof(double));
226                }
227                if (nlopt_stop_forced(stop)) ret = NLOPT_FORCED_STOP;
228                else if (*minf < stop->minf_max) 
229                     ret = NLOPT_MINF_MAX_REACHED;
230                else if (nlopt_stop_evals(stop)) ret = NLOPT_MAXEVAL_REACHED;
231                else if (nlopt_stop_time(stop)) ret = NLOPT_MAXTIME_REACHED;
232                if (ret != NLOPT_SUCCESS) goto done;
233           }
234           // ------------------------------------
235           // Individual selection
236           // ------------------------------------
237           // all the individuals are copied to one vector to easily identify best solutions             
238           for (i=0; i < np; i++)
239                estotal[i] = esparents[i];
240           for (i=0; i < no; i++)
241                estotal[np+i] = esoffsprings[i];
242           // Sorting
243           nlopt_qsort_r(estotal, no+np, sizeof(Individual), NULL,
244                         CompareIndividuals);
245           // copy after sorting:
246           for (i=0; i < no+np; i++) {
247                if (i<np)
248                     esparents[i] = estotal[i];
249                else
250                     esoffsprings[i-np] = estotal[i];
251           }
252      } // generations loop
253      
254 done:
255      for (id=0; id < np; id++) free(esparents[id].parameters);
256      for (id=0; id < no; id++) free(esoffsprings[id].parameters);
257      
258      if (esparents)     free(esparents);
259      if (esoffsprings)  free(esoffsprings);
260      if (estotal)               free(estotal);
261      return ret;
262 }