population_set_replacement_method: New function.
[libpopulation.git] / src / libpopulation.c
1 /**
2  * libpopulation - src/evolve.c
3  * Copyright (C) 2008,2009  Florian octo Forster
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; only version 2 of the License is applicable.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17  *
18  * Authors:
19  *   Florian octo Forster <octo at verplant.org>
20  **/
21
22 /*
23  * First tell the compiler to stick to the C99 and POSIX standards as close as
24  * possible.
25  */
26 #ifndef __STRICT_ANSI__ /* {{{ */
27 # define __STRICT_ANSI__
28 #endif
29
30 #ifndef _ISOC99_SOURCE
31 # define _ISOC99_SOURCE
32 #endif
33
34 #ifdef _POSIX_C_SOURCE
35 # undef _POSIX_C_SOURCE
36 #endif
37 #define _POSIX_C_SOURCE 200112L
38
39 /* Single UNIX needed for strdup. */
40 #if 0
41 #ifdef _XOPEN_SOURCE
42 # undef _XOPEN_SOURCE
43 #endif 
44 #define _XOPEN_SOURCE 500
45 #endif
46   
47 #ifndef _REENTRANT
48 # define _REENTRANT
49 #endif
50
51 #ifndef _THREAD_SAFE
52 # define _THREAD_SAFE
53 #endif 
54
55 #ifdef _GNU_SOURCE
56 # undef _GNU_SOURCE
57 #endif
58 /* }}} */
59
60 #include "config.h"
61 #include "population.h"
62
63 #include <stdlib.h>
64 #include <assert.h>
65 #include <errno.h>
66 #include <stdint.h>
67 #include <inttypes.h>
68 #include <string.h>
69 #include <stdio.h>
70 #include <limits.h>
71 #include <pthread.h>
72 #include <math.h>
73 #include <unistd.h>
74 #include <fcntl.h>
75 #include <sys/types.h>
76 #include <sys/socket.h>
77 #include <netdb.h>
78 #include <signal.h>
79
80 #define NETWORK_BUFFER_SIZE 1450
81
82 /*
83  * Data types
84  */
85 struct individual_s
86 {
87   void *ptr;
88   int rating;
89 };
90 typedef struct individual_s individual_t;
91
92 struct population_s
93 {
94   pthread_mutex_t lock;
95
96   /* Callback functions */
97   pi_rate_f rate;
98   pi_free_f free;
99   pi_copy_f copy;
100
101   /* Optional serialization */
102   pi_serialize_f serialize;
103   pi_unserialize_f unserialize;
104
105   int *peers;
106   size_t peers_num;
107
108 #define POPULATION_FLAG_LISTEN   0x01
109 #define POPULATION_FLAG_SHUTDOWN 0x02
110 #define POPULATION_FLAG_EXPLORE  0x10
111   int flags;
112   pthread_t listen_thread_id;
113
114   individual_t fittest;
115
116   individual_t *individuals;
117   size_t individuals_num;
118 };
119
120 struct listen_thread_args_s
121 {
122   population_t *population;
123   char *node;
124   char *service;
125 };
126 typedef struct listen_thread_args_s listen_thread_args_t;
127
128 /*
129  * Private functions
130  */
131 static char *population_strdup (const char *src)
132 {
133   size_t s;
134   char *ret;
135
136   if (src == NULL)
137     return (NULL);
138
139   s = strlen (src) + 1;
140   ret = (char *) malloc (s);
141   if (ret == NULL)
142     return (NULL);
143
144   memcpy (ret, src, s);
145   return (ret);
146 } /* char *population_strdup */
147
148 static int population_send_to_peer (population_t *p, void *pi) /* {{{ */
149 {
150   char buffer[NETWORK_BUFFER_SIZE];
151   size_t buffer_size;
152   size_t buffer_free;
153   char *buffer_ptr;
154
155   int fd;
156   int i;
157   int status;
158
159   if (p == NULL)
160     return (-1);
161
162   if (pi == NULL)
163     return (-1);
164
165   buffer_size = sizeof (buffer);
166   memset (buffer, 0, buffer_size);
167
168   pthread_mutex_lock (&p->lock);
169
170   if (p->serialize == NULL)
171   {
172     pthread_mutex_unlock (&p->lock);
173     fprintf (stderr, "population_send_to_peer: Cannot send to peer without "
174         "serialization function!\n");
175     return (-1);
176   }
177
178   i = (int) (((double) p->peers_num) * (rand() / (RAND_MAX + 1.0)));
179   fd = p->peers[i];
180
181   buffer_ptr = buffer;
182   buffer_free = sizeof (buffer);
183   status = p->serialize (pi, &buffer_ptr, &buffer_free);
184   if (status != 0)
185   {
186     pthread_mutex_unlock (&p->lock);
187     fprintf (stderr, "population_send_to_peer: p->serialize failed "
188         "with status %i.\n", status);
189     return (-1);
190   }
191
192   buffer_size = sizeof (buffer) - buffer_free;
193   if (buffer_size < 1)
194   {
195     pthread_mutex_unlock (&p->lock);
196     fprintf (stderr, "population_send_to_peer: p->serialize didn't put "
197         "anything into the buffer..\n");
198     return (-1);
199   }
200
201   /* write should not block - hopefully */
202   status = send (fd, buffer, buffer_size, MSG_DONTWAIT | MSG_NOSIGNAL);
203   if (status < 0)
204   {
205     pthread_mutex_unlock (&p->lock);
206     status = errno;
207     if (status != ECONNREFUSED)
208     {
209       fprintf (stderr, "population_send_to_peer: Writing to socket failed: "
210           "send(2) returned with error %i.\n", status);
211     }
212     return (-1);
213   }
214   else if (((size_t) status) != buffer_size)
215   {
216     pthread_mutex_unlock (&p->lock);
217     fprintf (stderr, "population_send_to_peer: Writing to socket failed: "
218         "send(2) returned %i (expected %zu).\n",
219         status, buffer_size);
220     return (-1);
221   }
222
223   pthread_mutex_unlock (&p->lock);
224
225 #if 0
226   printf ("population_send_to_peer: Sent individual with rating %i to peer #%i.\n",
227       p->rate (pi), i);
228 #endif
229
230   return (0);
231 } /* }}} int population_send_to_peer */
232
233 static void *listen_thread (void *data)
234 {
235   listen_thread_args_t *args;
236   population_t *p;
237   char *node;
238   char *service;
239   int status;
240   int fd;
241
242   struct addrinfo  ai_hints;
243   struct addrinfo *ai_list;
244   struct addrinfo *ai_ptr;
245
246   args    = (listen_thread_args_t *) data;
247   p       = args->population;
248   node    = args->node;
249   service = args->service;
250
251   ai_list = NULL;
252
253   memset (&ai_hints, 0, sizeof (ai_hints));
254   ai_hints.ai_flags = AI_PASSIVE;
255 #ifdef AI_ADDRCONFIG
256   ai_hints.ai_flags |= AI_ADDRCONFIG;
257 #endif
258   ai_hints.ai_family = AF_UNSPEC;
259   ai_hints.ai_socktype = SOCK_DGRAM;
260   ai_hints.ai_protocol = 0;
261
262   status = getaddrinfo (node, 
263       (service != NULL) ? service : POPULATION_DEFAULT_PORT,
264       &ai_hints, &ai_list);
265   if (status != 0)
266   {
267     fprintf (stderr, "listen_thread: getaddrinfo (%s) failed: %s\n",
268         (node != NULL) ? node : "NULL", gai_strerror (status));
269     return ((void *) -1);
270   }
271
272   fd = -1;
273   for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
274   {
275     fd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
276     if (fd < 0)
277       continue;
278
279     status = bind (fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
280     if (status != 0)
281     {
282       close (fd);
283       fd = -1;
284       continue;
285     }
286
287     break;
288   }
289
290   freeaddrinfo (ai_list);
291
292   if (fd < 0)
293   {
294     fprintf (stderr, "listen_thread: No socket could be opened.\n");
295     return ((void *) -1);
296   }
297
298   pthread_mutex_lock (&p->lock);
299   p->flags |= POPULATION_FLAG_LISTEN;
300   while ((p->flags & POPULATION_FLAG_SHUTDOWN) == 0)
301   {
302     /* Allocate one extra byte to null-terminate the data. */
303     char buffer[NETWORK_BUFFER_SIZE + 1];
304     void *pi;
305
306     pthread_mutex_unlock (&p->lock);
307
308     status = recvfrom (fd, buffer, sizeof (buffer) - 1, /* flags = */ 0,
309         /* from = */ NULL, /* fromlen = */ NULL);
310     if (status < 1)
311     {
312       fprintf (stderr, "listen_thread: recvfrom(2) failed: status = %i; "
313           "errno = %i;\n", status, errno);
314       pthread_mutex_lock (&p->lock);
315       continue;
316     }
317     assert (status < sizeof (buffer));
318     buffer[sizeof (buffer) - 1] = 0;
319
320     pi = p->unserialize (buffer, (size_t) status);
321     if (pi == NULL)
322     {
323       fprintf (stderr, "listen_thread: p->unserialize returned NULL.\n");
324       pthread_mutex_lock (&p->lock);
325       continue;
326     }
327
328 #if 0
329     printf ("listen_thread: Received individual with rating %i.\n",
330         p->rate (pi));
331 #endif
332
333     population_insert (p, pi);
334
335     p->free (pi);
336
337     pthread_mutex_lock (&p->lock);
338   } /* while (42) */
339
340   close (fd);
341   fd = -1;
342
343   /* clear the listen flag */
344   p->flags &= ~(POPULATION_FLAG_LISTEN);
345
346   pthread_mutex_unlock (&p->lock);
347   return ((void *) 0);
348 } /* void *listen_thread */
349
350 /*
351  * Constructor and destructor
352  */
353 population_t *population_create (pi_rate_f rate, pi_copy_f copy, /* {{{ */
354     pi_free_f f)
355 {
356   population_t *p;
357   size_t i;
358
359   p = (population_t *) malloc (sizeof (population_t));
360   if (p == NULL)
361     return (NULL);
362
363   memset (p, 0, sizeof (*p));
364   pthread_mutex_init (&p->lock, /* attr = */ NULL);
365
366   p->rate = rate;
367   p->copy = copy;
368   p->free = f;
369
370   p->fittest.ptr = NULL;
371   p->fittest.rating = -1;
372
373   p->individuals = malloc (32 * sizeof (p->individuals[0]));
374   if (p->individuals == NULL)
375   {
376     free (p);
377     return (NULL);
378   }
379   memset (p->individuals, 0, 32 * sizeof (p->individuals[0]));
380   p->individuals_num = 32;
381
382   for (i = 0; i < p->individuals_num; i++)
383   {
384     p->individuals[i].ptr = NULL;
385     p->individuals[i].rating = -1;
386   }
387
388   return (p);
389 } /* }}} population_t *population_create */
390
391 void population_destroy (population_t *p) /* {{{ */
392 {
393   if (p == NULL)
394     return;
395
396   pthread_mutex_lock (&p->lock);
397   p->flags |= POPULATION_FLAG_SHUTDOWN;
398   if ((p->flags & POPULATION_FLAG_LISTEN) != 0)
399   {
400     pthread_kill (p->listen_thread_id, SIGTERM);
401     pthread_mutex_unlock (&p->lock);
402     pthread_join (p->listen_thread_id, /* return = */ NULL);
403     pthread_mutex_lock (&p->lock);
404   }
405
406   if (p->fittest.ptr != NULL)
407     p->free (p->fittest.ptr);
408   p->fittest.ptr = NULL;
409   p->fittest.rating = -1;
410
411   if (p->individuals_num > 0)
412   {
413     size_t i;
414
415     for (i = 0; i < p->individuals_num; i++)
416     {
417       if (p->individuals[i].ptr != NULL)
418         p->free (p->individuals[i].ptr);
419       p->individuals[i].ptr = NULL;
420       p->individuals[i].rating = -1;
421     }
422
423     free (p->individuals);
424     p->individuals = NULL;
425     p->individuals_num = 0;
426   }
427
428   memset (p, 0, sizeof (*p));
429   free (p);
430 } /* }}} void population_destroy */
431
432 int population_set_size (population_t *p, /* {{{ */
433     size_t population_size)
434 {
435   size_t i;
436   individual_t *temp;
437
438   if (p == NULL)
439     return (-1);
440
441   pthread_mutex_lock (&p->lock);
442
443   if (p->individuals_num == population_size)
444   {
445     pthread_mutex_unlock (&p->lock);
446     return (0);
447   }
448
449   for (i = population_size; i < p->individuals_num; i++)
450   {
451     p->free (p->individuals[i].ptr);
452     p->individuals[i].ptr = NULL;
453     p->individuals[i].rating = -1;
454   }
455
456   temp = (individual_t *) realloc (p->individuals,
457       population_size * sizeof (p->individuals[0]));
458   if (temp == NULL)
459   {
460     pthread_mutex_unlock (&p->lock);
461     return (-1);
462   }
463   p->individuals = temp;
464
465   for (i = p->individuals_num; i < population_size; i++)
466   {
467     p->individuals[i].ptr = NULL;
468     p->individuals[i].rating = -1;
469   }
470
471   p->individuals_num = population_size;
472
473   pthread_mutex_unlock (&p->lock);
474
475   return (0);
476 } /* }}} */
477
478 int population_set_serialization (population_t *p, /* {{{ */
479     pi_serialize_f serialize, pi_unserialize_f unserialize)
480 {
481   if (p == NULL)
482     return (-1);
483
484   pthread_mutex_lock (&p->lock);
485
486   p->serialize = serialize;
487   p->unserialize = unserialize;
488
489   pthread_mutex_unlock (&p->lock);
490   return (0);
491 } /* }}} int population_set_serialization */
492
493 int population_set_replacement_method (population_t *p, int method) /* {{{ */
494 {
495   int status = 0;
496
497   if (p == NULL)
498     return (EINVAL);
499
500   pthread_mutex_lock (&p->lock);
501
502   if (method == POPULATION_REPLACEMENT_EXPLOIT)
503     p->flags &= ~POPULATION_FLAG_EXPLORE;
504   else if (method == POPULATION_REPLACEMENT_EXPLORE)
505     p->flags |= POPULATION_FLAG_EXPLORE;
506   else
507     status = EINVAL;
508
509   pthread_mutex_unlock (&p->lock);
510
511   return (0);
512 } /* }}} int population_set_replacement_method */
513
514 int population_add_peer (population_t *p, const char *node, /* {{{ */
515     const char *port)
516 {
517   struct addrinfo  ai_hints;
518   struct addrinfo *ai_list;
519   struct addrinfo *ai_ptr;
520   int status;
521
522   if (p == NULL)
523     return (-1);
524
525   if (node == NULL)
526     return (-1);
527
528   if (port == NULL)
529     port = POPULATION_DEFAULT_PORT;
530
531   ai_list = NULL;
532
533   memset (&ai_hints, 0, sizeof (ai_hints));
534   ai_hints.ai_flags = 0;
535 #ifdef AI_ADDRCONFIG
536   ai_hints.ai_flags |= AI_ADDRCONFIG;
537 #endif
538   ai_hints.ai_family = AF_UNSPEC;
539   ai_hints.ai_socktype = SOCK_DGRAM;
540   ai_hints.ai_protocol = 0;
541
542   status = getaddrinfo (node, port, &ai_hints, &ai_list);
543   if (status != 0)
544   {
545     fprintf (stderr, "population_add_peer: getaddrinfo (%s) failed: %s\n",
546         node, gai_strerror (status));
547     return (-1);
548   }
549
550   pthread_mutex_lock (&p->lock);
551
552   for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
553   {
554     int *temp;
555
556     temp = (int *) realloc (p->peers, sizeof (int) * (p->peers_num + 1));
557     if (temp == NULL)
558     {
559       fprintf (stderr, "population_add_peer: realloc failed.\n");
560       continue;
561     }
562     p->peers = temp;
563
564     p->peers[p->peers_num] = socket (ai_ptr->ai_family, ai_ptr->ai_socktype,
565         ai_ptr->ai_protocol);
566     if (p->peers[p->peers_num] < 0)
567       continue;
568
569     status = connect (p->peers[p->peers_num],
570         ai_ptr->ai_addr, ai_ptr->ai_addrlen);
571     if (status != 0)
572     {
573       fprintf (stderr, "population_add_peer: connect(2) failed.\n");
574       close (p->peers[p->peers_num]);
575       continue;
576     }
577
578     status = fcntl (p->peers[p->peers_num], F_SETFL, O_NONBLOCK);
579     if (status != 0)
580     {
581       fprintf (stderr, "population_add_peer: fcntl (F_SETFL, O_NONBLOCK) "
582           "failed. Will use the socket with blocking.\n");
583     }
584
585     p->peers_num++;
586
587     printf ("population_add_peer: Successfully added peer #%i.\n",
588         p->peers_num - 1);
589   }
590   pthread_mutex_unlock (&p->lock);
591
592   freeaddrinfo (ai_list);
593
594   return (0);
595 } /* }}} int population_add_peer */
596
597 int population_start_listen_thread (population_t *p, /* {{{ */
598     const char *node, const char *service)
599 {
600   listen_thread_args_t *args;
601
602   pthread_mutex_lock (&p->lock);
603   if ((p->flags & POPULATION_FLAG_LISTEN) != 0)
604   {
605     pthread_mutex_unlock (&p->lock);
606     fprintf (stderr, "population_start_listen_thread: "
607         "Listen thread already started.\n");
608     return (-EALREADY);
609   }
610
611   args = (listen_thread_args_t *) malloc (sizeof (listen_thread_args_t));
612   if (args == NULL)
613   {
614     fprintf (stderr, "population_start_listen_thread: malloc failed.\n");
615     return (-1);
616   }
617
618   memset (args, 0, sizeof (listen_thread_args_t));
619   args->population = p;
620   args->node = population_strdup (node);
621   args->service = population_strdup (service);
622
623   pthread_create (&p->listen_thread_id, /* attr = */ NULL,
624       listen_thread, (void *) args);
625
626   pthread_mutex_unlock (&p->lock);
627   return (0);
628 } /* }}} int population_start_listen_thread */
629
630 void *population_get_random (population_t *p) /* {{{ */
631 {
632   void *ret = NULL;
633   size_t i;
634
635   pthread_mutex_lock (&p->lock);
636
637   if (p->individuals_num < 1)
638   {
639     pthread_mutex_unlock (&p->lock);
640     return (NULL);
641   }
642
643   while (ret == NULL)
644   {
645     i = (size_t) (((double) p->individuals_num)
646         * (rand() / (RAND_MAX + 1.0)));
647     if (p->individuals[i].ptr == NULL)
648       continue;
649
650     ret = p->copy (p->individuals[i].ptr);
651   }
652
653   pthread_mutex_unlock (&p->lock);
654
655   return (ret);
656 } /* }}} void *population_pick_random */
657
658 void *population_get_fittest (population_t *p) /* {{{ */
659 {
660   void *ret = NULL;
661
662   if (p == NULL)
663     return (NULL);
664
665   pthread_mutex_lock (&p->lock);
666
667   if (p->fittest.ptr == NULL)
668   {
669     pthread_mutex_unlock (&p->lock);
670     return (NULL);
671   }
672
673   ret = p->copy (p->fittest.ptr);
674
675   pthread_mutex_unlock (&p->lock);
676
677   return (ret);
678 } /* }}} void *population_get_fittest */
679
680 int population_insert (population_t *p, void *pi_orig) /* {{{ */
681 {
682   void *pi;
683   int pi_rating;
684   int sent_to_peer;
685   int i;
686
687   if (p == NULL)
688     return (-1);
689
690   if (pi_orig == NULL)
691     return (-1);
692
693   pi = p->copy (pi_orig);
694   if (pi == NULL)
695   {
696     fprintf (stderr, "population_insert: p->copy failed.\n");
697     return (-1);
698   }
699
700   /*
701    * With a small chance, send this individual to somewhere else.
702    * `sent_to_peer = -1' is used to signal the following code that this
703    * individual has been sent to somewhere else and doesn't go into the local
704    * population.
705    */
706   sent_to_peer = 0;
707   if (p->peers_num > 0)
708   {
709     double prob;
710
711     prob = ((double) rand ()) / (((double) RAND_MAX) + 1.0);
712     if (prob <= 0.001)
713     {
714       population_send_to_peer (p, pi);
715       sent_to_peer = 1;
716     }
717   }
718
719   pi_rating = p->rate (pi);
720
721   pthread_mutex_lock (&p->lock);
722
723   /* Keep track of the all time best. */
724   if ((p->fittest.ptr == NULL) || (p->fittest.rating >= pi_rating))
725   {
726     void *temp;
727
728     temp = p->copy (pi);
729     if (temp != NULL)
730     {
731       if (p->fittest.ptr != NULL)
732         p->free (p->fittest.ptr);
733       p->fittest.ptr = temp;
734       p->fittest.rating = pi_rating;
735     }
736   }
737
738   if ((sent_to_peer != 0) || (p->individuals_num <= 0))
739   {
740     pthread_mutex_unlock (&p->lock);
741     p->free (pi);
742     return (0);
743   }
744
745   do
746   {
747     size_t j;
748
749     int chance_j;
750     int chance_pi;
751     int chance;
752
753     j = (size_t) (((double) p->individuals_num) * (rand() / (RAND_MAX + 1.0)));
754
755     if (p->individuals[j].ptr == NULL)
756     {
757       p->individuals[j].ptr = pi;
758       p->individuals[j].rating = pi_rating;
759       pi = NULL;
760       break;
761     }
762
763     /* large distance from fittest => high probability of losing. */
764     chance_j = 1 + p->individuals[j].rating - p->fittest.rating;
765     chance_pi = 1 + pi_rating - p->fittest.rating;
766
767     chance_j = chance_j * chance_j;
768     chance_pi = chance_pi * chance_pi;
769
770     chance = (int) (((double) (chance_j + chance_pi))
771         * (rand() / (RAND_MAX + 1.0)));
772
773     if (p->flags & POPULATION_FLAG_EXPLORE)
774       chance *= .5;
775
776     if (chance < chance_j) /* j looses ;) */
777     {
778       void *temp0;
779       int temp1;
780
781       temp0 = p->individuals[j].ptr;
782       p->individuals[j].ptr = pi;
783       pi = temp0;
784
785       temp1 = p->individuals[j].rating;
786       p->individuals[j].rating = pi_rating;
787       pi_rating = temp1;
788     }
789   } while (0);
790
791   pthread_mutex_unlock (&p->lock);
792
793   if (pi != NULL)
794     p->free (pi);
795
796   return (0);
797 } /* }}} int population_insert */
798
799 /* vim: set sw=2 sts=2 et fdm=marker : */
800