sensor: update to gaussian model + optimized parameters
[oweals/gnunet.git] / src / sensor / plugin_sensor_model_gaussian.c
1 /*
2  * This file is part of GNUnet
3  * (C) 2013 Christian Grothoff (and other contributing authors)
4  *
5  * GNUnet is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published
7  * by the Free Software Foundation; either version 3, or (at your
8  * option) any later version.
9  *
10  * GNUnet is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with GNUnet; see the file COPYING.  If not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /**
22  * @file sensor/plugin_sensor_model_gaussian.c
23  * @brief Gaussian model for sensor analysis
24  * @author Omar Tarabai
25  */
26
27 #include "platform.h"
28 #include "gnunet_sensor_model_plugin.h"
29 #include "gnunet_sensor_service.h"
30 #include "sensor.h"
31
32 #define LOG(kind,...) GNUNET_log_from (kind, "sensor-model-gaussian", __VA_ARGS__)
33
34 /**
35  * Plugin state information
36  */
37 struct Plugin
38 {
39
40   /**
41    * Configuration handle
42    */
43   const struct GNUNET_CONFIGURATION_Handle *cfg;
44
45   /**
46    * Number of initial readings to be used for training only
47    */
48   int training_window;
49
50   /**
51    * Number of standard deviations considered within "normal"
52    */
53   int confidence_interval;
54
55   /**
56    * Increase in weight with each reading
57    */
58   float weight_inc;
59
60 };
61
62 /**
63  * State of single model instance
64  */
65 struct Model
66 {
67
68   /**
69    * Pointer to the plugin state
70    */
71   struct Plugin *plugin;
72
73   /**
74    * Gaussian sums
75    */
76   long double s[3];
77
78   /**
79    * Number of readings so far
80    */
81   int n;
82
83   /**
84    * Weight to be used for the next reading
85    */
86   double w;
87
88 };
89
90 /**
91  * Update local sums of model with a new value.
92  *
93  * @param model Targe model
94  * @param val New value
95  */
96 static void
97 update_sums (struct Model *model, double val)
98 {
99   int i;
100
101   for (i = 0; i < 3; i++)
102     model->s[i] += model->w * pow (val, (double) i);
103   model->w += model->plugin->weight_inc;
104   model->n++;
105 }
106
107
108 /**
109  * Feed a new value to a model
110  *
111  * @param cls closure (model state)
112  * @param val value to be fed to the model
113  * @return #GNUNET_YES in case of a detected outlier, #GNUNET_NO otherwise
114  */
115 static int
116 sensor_gaussian_model_feed (void *cls, double val)
117 {
118   struct Model *model = cls;
119   struct Plugin *plugin = model->plugin;
120   long double mean;
121   long double stddev;
122   long double allowed_variance;
123
124   if (model->n < plugin->training_window)
125   {
126     update_sums (model, val);
127     return GNUNET_NO;
128   }
129   if (model->n == plugin->training_window)
130     LOG (GNUNET_ERROR_TYPE_DEBUG, "Gaussian model out of training period.\n");
131   mean = model->s[1] / model->s[0];
132   stddev =
133       (model->s[0] * model->s[2] -
134        model->s[1] * model->s[1]) / (model->s[0] * (model->s[0] - 1));
135   if (stddev < 0)               /* Value can be slightly less than 0 due to rounding errors */
136     stddev = 0;
137   stddev = sqrt (stddev);
138   LOG (GNUNET_ERROR_TYPE_DEBUG, "Mean: %Lf, Stddev: %Lf\n", mean, stddev);
139   allowed_variance = (plugin->confidence_interval * stddev);
140   if ((val < (mean - allowed_variance)) || (val > (mean + allowed_variance)))
141     return GNUNET_YES;
142   update_sums (model, val);
143   return GNUNET_NO;
144 }
145
146
147 /**
148  * Destroy a model instance
149  *
150  * @param cls closure (model state)
151  */
152 static void
153 sensor_gaussian_model_destroy_model (void *cls)
154 {
155   struct Model *model = cls;
156
157   GNUNET_free (model);
158 }
159
160
161 /**
162  * Create a model instance
163  *
164  * @param cls closure (plugin state)
165  * @return model state to be used for later calls
166  */
167 static void *
168 sensor_gaussian_model_create_model (void *cls)
169 {
170   struct Plugin *plugin = cls;
171   struct Model *model;
172
173   model = GNUNET_new (struct Model);
174
175   model->plugin = plugin;
176   model->w = 1;
177   return model;
178 }
179
180
181 /**
182  * Entry point for the plugin.
183  *
184  * @param cls The struct GNUNET_CONFIGURATION_Handle.
185  * @return NULL on error, otherwise the plugin context
186  */
187 void *
188 libgnunet_plugin_sensor_model_gaussian_init (void *cls)
189 {
190   static struct Plugin plugin;
191   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
192   struct GNUNET_SENSOR_ModelFunctions *api;
193   unsigned long long num;
194
195   if (NULL != plugin.cfg)
196     return NULL;                /* can only initialize once! */
197   memset (&plugin, 0, sizeof (struct Plugin));
198   plugin.cfg = cfg;
199   if (GNUNET_OK !=
200       GNUNET_CONFIGURATION_get_value_number (cfg, "sensor-model-gaussian",
201                                              "TRAINING_WINDOW", &num))
202   {
203     LOG (GNUNET_ERROR_TYPE_ERROR,
204          _("Missing `TRAINING_WINDOW' value in configuration.\n"));
205     return NULL;
206   }
207   if (num < 1)
208   {
209     LOG (GNUNET_ERROR_TYPE_WARNING,
210          "Minimum training window invalid (<1), setting to 1.\n");
211     plugin.training_window = 1;
212   }
213   else
214   {
215     plugin.training_window = (int) num;
216   }
217   if (GNUNET_OK !=
218       GNUNET_CONFIGURATION_get_value_number (cfg, "sensor-model-gaussian",
219                                              "CONFIDENCE_INTERVAL", &num))
220   {
221     LOG (GNUNET_ERROR_TYPE_ERROR,
222          _("Missing `CONFIDENCE_INTERVAL' value in configuration.\n"));
223     return NULL;
224   }
225   if (GNUNET_OK !=
226       GNUNET_CONFIGURATION_get_value_float (cfg, "sensor-model-gaussian",
227                                             "WEIGHT_INC", &plugin.weight_inc))
228   {
229     LOG (GNUNET_ERROR_TYPE_ERROR,
230          _("Missing `WEIGHT_INC' value in configuration.\n"));
231     return NULL;
232   }
233   plugin.confidence_interval = (int) num;
234   api = GNUNET_new (struct GNUNET_SENSOR_ModelFunctions);
235
236   api->cls = &plugin;
237   api->create_model = &sensor_gaussian_model_create_model;
238   api->destroy_model = &sensor_gaussian_model_destroy_model;
239   api->feed_model = &sensor_gaussian_model_feed;
240   LOG (GNUNET_ERROR_TYPE_DEBUG, "Gaussian model plugin is running.\n");
241   return api;
242 }
243
244
245 /**
246  * Exit point from the plugin.
247  *
248  * @param cls The plugin context (as returned by "init")
249  * @return Always NULL
250  */
251 void *
252 libgnunet_plugin_sensor_model_gaussian_done (void *cls)
253 {
254   struct GNUNET_SENSOR_ModelFunctions *api = cls;
255   struct Plugin *plugin = api->cls;
256
257   plugin->cfg = NULL;
258   GNUNET_free (api);
259   LOG (GNUNET_ERROR_TYPE_DEBUG, "Guassian model plugin is finished\n");
260   return NULL;
261
262 }
263
264 /* end of plugin_sensor_model_gaussian.c */