11063e0132288b41c6fab6da938d04db6250cc9f
[sort-networks.git] / src / sn_population.c
1 #define _ISOC99_SOURCE
2 #define _POSIX_C_SOURCE 200112L
3
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <stdint.h>
7 #include <string.h>
8 #include <assert.h>
9 #include <pthread.h>
10
11 #include "sn_population.h"
12 #include "sn_network.h"
13 #include "sn_random.h"
14
15 struct sn_population_s
16 {
17   uint32_t size;
18
19   sn_network_t **networks;
20   int *ratings;
21   uint32_t networks_num;
22
23   pthread_mutex_t lock;
24 };
25
26 static int rate_network (const sn_network_t *n)
27 {
28   int rate;
29   int i;
30
31   rate = SN_NETWORK_STAGE_NUM (n) * SN_NETWORK_INPUT_NUM (n);
32   for (i = 0; i < SN_NETWORK_STAGE_NUM (n); i++)
33   {
34     sn_stage_t *s = SN_NETWORK_STAGE_GET (n, i);
35     rate += SN_STAGE_COMP_NUM (s);
36   }
37
38   return (rate);
39 } /* int rate_network */
40
41 sn_population_t *sn_population_create (uint32_t size)
42 {
43   sn_population_t *p;
44   int status;
45
46   p = (sn_population_t *) malloc (sizeof (sn_population_t));
47   if (p == NULL)
48     return (NULL);
49   memset (p, 0, sizeof (sn_population_t));
50   p->size = size;
51
52   p->networks = (sn_network_t **) calloc ((size_t) size,
53       sizeof (sn_network_t *));
54   if (p->networks == NULL)
55   {
56     free (p);
57     return (NULL);
58   }
59
60   p->ratings = (int *) calloc ((size_t) size, sizeof (int));
61   if (p->ratings == NULL)
62   {
63     free (p->networks);
64     free (p);
65     return (NULL);
66   }
67
68   status = pthread_mutex_init (&p->lock, /* attr = */ NULL);
69   if (status != 0)
70   {
71     fprintf (stderr, "sn_population_create: pthread_mutex_init failed: %i\n",
72         status);
73     free (p->ratings);
74     free (p->networks);
75     free (p);
76     return (NULL);
77   }
78
79   return (p);
80 } /* sn_population_t *sn_population_create */
81
82 void sn_population_destroy (sn_population_t *p)
83 {
84   uint32_t i;
85
86   if (p == NULL)
87     return;
88
89   for (i = 0; i < p->size; i++)
90     if (p->networks[i] != NULL)
91       sn_network_destroy (p->networks[i]);
92
93   pthread_mutex_destroy (&p->lock);
94
95   free (p->ratings);
96   free (p->networks);
97   free (p);
98 } /* void sn_population_destroy */
99
100 int sn_population_push (sn_population_t *p, sn_network_t *n)
101 {
102   sn_network_t *n_copy;
103   int rating;
104
105   n_copy = sn_network_clone (n);
106   if (n_copy == NULL)
107   {
108     fprintf (stderr, "sn_population_push: sn_network_clone failed.\n");
109     return (-1);
110   }
111
112   rating = rate_network (n_copy);
113
114   pthread_mutex_lock (&p->lock);
115
116   if (p->networks_num < p->size)
117   {
118     p->networks[p->networks_num] = n_copy;
119     p->ratings[p->networks_num] = rating;
120     p->networks_num++;
121   }
122   else
123   {
124     int index;
125     sn_network_t *n_removed = n_copy;
126     int i;
127
128     for (i = 0; i < (1 + (p->networks_num / 16)); i++)
129     {
130       index = sn_bounded_random (0, p->networks_num - 1);
131       if (p->ratings[index] < rating)
132         continue;
133
134       n_removed = p->networks[index];
135       p->networks[index] = n_copy;
136       p->ratings[index] = rating;
137       break;
138     }
139
140     sn_network_destroy (n_removed);
141   }
142
143   pthread_mutex_unlock (&p->lock);
144
145   return (0);
146 } /* int sn_population_push */
147
148 sn_network_t *sn_population_pop (sn_population_t *p)
149 {
150   int index;
151   sn_network_t *n_copy;
152
153   pthread_mutex_lock (&p->lock);
154
155   if (p->networks_num <= 0)
156   {
157     pthread_mutex_unlock (&p->lock);
158     return (NULL);
159   }
160
161   index = sn_bounded_random (0, p->networks_num - 1);
162   n_copy = sn_network_clone (p->networks[index]);
163
164   pthread_mutex_unlock (&p->lock);
165
166   return (n_copy);
167 } /* sn_population_t *sn_population_pop */
168
169 sn_network_t *sn_population_best (sn_population_t *p)
170 {
171   uint32_t i;
172
173   uint32_t index = 0;
174   int rating = -1;
175   sn_network_t *n_copy;
176
177   if (p == NULL)
178     return (NULL);
179
180   pthread_mutex_lock (&p->lock);
181
182   if (p->networks_num <= 0)
183   {
184     pthread_mutex_unlock (&p->lock);
185     return (NULL);
186   }
187
188   for (i = 0; i < p->networks_num; i++)
189   {
190     if ((p->ratings[i] < rating) || (rating < 0))
191     {
192       rating = p->ratings[i];
193       index = i;
194     }
195   }
196
197   n_copy = sn_network_clone (p->networks[index]);
198
199   pthread_mutex_unlock (&p->lock);
200
201   return (n_copy);
202 } /* sn_network_t *sn_population_best */
203
204 int sn_population_best_rating (sn_population_t *p)
205 {
206   uint32_t i;
207   int rating = -1;
208
209   pthread_mutex_lock (&p->lock);
210
211   if (p->networks_num <= 0)
212   {
213     pthread_mutex_unlock (&p->lock);
214     return (-1);
215   }
216
217   for (i = 0; i < p->networks_num; i++)
218     if ((p->ratings[i] < rating) || (rating < 0))
219       rating = p->ratings[i];
220
221   pthread_mutex_unlock (&p->lock);
222
223   return (rating);
224 } /* int sn_population_best_rating */
225
226 /* vim: set shiftwidth=2 softtabstop=2 : */