-fixing source port randomization for DNS service
[oweals/gnunet.git] / src / ats / gnunet-service-ats_addresses_mlp.c
index c7b1ee75cfce31dd42cbabfe3f3945b3f1a1f403..602925e1f5ab3b0a954d243b4455bae9207bead0 100644 (file)
 #include "gnunet-service-ats_addresses.h"
 #include "gnunet-service-ats_addresses_mlp.h"
 #include "gnunet_statistics_service.h"
-#if HAVE_LIBGLPK
 #include "glpk.h"
-#endif
-#include "float.h"
 
-#define DEBUG_ATS GNUNET_YES
-/* A very big value */
-#define M DBL_MAX
+#define WRITE_MLP GNUNET_NO
+#define DEBUG_ATS GNUNET_NO
+#define VERBOSE_GLPK GNUNET_NO
 
 /**
  * Translate glpk solver error codes to text
@@ -150,6 +147,70 @@ mlp_status_to_string (int retcode)
   return "unknown error";
 }
 
+/**
+ * Translate ATS properties to text
+ * Just intended for debugging
+ *
+ * @param retcode return code
+ * @return string with result
+ */
+const char *
+mlp_ats_to_string (int ats_index)
+{
+  switch (ats_index) {
+    case GNUNET_ATS_ARRAY_TERMINATOR:
+      return "GNUNET_ATS_ARRAY_TERMINATOR";
+      break;
+    case GNUNET_ATS_UTILIZATION_UP:
+      return "GNUNET_ATS_UTILIZATION_UP";
+      break;
+    case GNUNET_ATS_UTILIZATION_DOWN:
+      return "GNUNET_ATS_UTILIZATION_DOWN";
+      break;
+    case GNUNET_ATS_COST_LAN:
+      return "GNUNET_ATS_COST_LAN";
+      break;
+    case GNUNET_ATS_COST_WAN:
+      return "GNUNET_ATS_COST_LAN";
+      break;
+    case GNUNET_ATS_COST_WLAN:
+      return "GNUNET_ATS_COST_WLAN";
+      break;
+    case GNUNET_ATS_NETWORK_TYPE:
+      return "GNUNET_ATS_NETWORK_TYPE";
+      break;
+    case GNUNET_ATS_QUALITY_NET_DELAY:
+      return "GNUNET_ATS_QUALITY_NET_DELAY";
+      break;
+    case GNUNET_ATS_QUALITY_NET_DISTANCE:
+      return "GNUNET_ATS_QUALITY_NET_DISTANCE";
+      break;
+    default:
+      return "unknown";
+      break;
+  }
+  GNUNET_break (0);
+  return "unknown error";
+}
+
+/**
+ * Find a peer in the DLL
+ * @param the peer to find
+ * @return the peer struct
+ */
+static struct ATS_Peer *
+mlp_find_peer (struct GAS_MLP_Handle *mlp, const struct GNUNET_PeerIdentity *peer)
+{
+  struct ATS_Peer *res = mlp->peer_head;
+  while (res != NULL)
+  {
+    if (0 == memcmp (peer, &res->id, sizeof (struct GNUNET_PeerIdentity)))
+      break;
+    res = res->next;
+  }
+  return res;
+}
+
 /**
  * Intercept GLPK terminal output
  * @param info the mlp handle
@@ -181,7 +242,7 @@ mlp_delete_problem (struct GAS_MLP_Handle *mlp)
     if (mlp->ia != NULL)
     {
       GNUNET_free (mlp->ia);
-      mlp->ja = NULL;
+      mlp->ia = NULL;
     }
 
     /* delete column index */
@@ -219,6 +280,7 @@ create_constraint_it (void *cls, const GNUNET_HashCode * key, void *value)
   struct ATS_Address *address = value;
   struct MLP_information *mlpi;
   unsigned int row_index;
+  char *name;
 
   GNUNET_assert (address->mlp_information != NULL);
   mlpi = (struct MLP_information *) address->mlp_information;
@@ -228,17 +290,20 @@ create_constraint_it (void *cls, const GNUNET_HashCode * key, void *value)
    */
   row_index = glp_add_rows (mlp->prob, 1);
   mlpi->r_c1 = row_index;
+  /* set row name */
+  GNUNET_asprintf(&name, "c1_%s_%s", GNUNET_i2s(&address->peer), address->plugin);
+  glp_set_row_name (mlp->prob, row_index, name);
+  GNUNET_free (name);
   /* set row bounds: <= 0 */
   glp_set_row_bnds (mlp->prob, row_index, GLP_UP, 0.0, 0.0);
-
   mlp->ia[mlp->ci] = row_index;
   mlp->ja[mlp->ci] = mlpi->c_b;
   mlp->ar[mlp->ci] = 1;
   mlp->ci++;
 
   mlp->ia[mlp->ci] = row_index;
-  mlp->ja[mlp->ci] = mlpi->c_b;
-  mlp->ar[mlp->ci] = -M;
+  mlp->ja[mlp->ci] = mlpi->c_n;
+  mlp->ar[mlp->ci] = -mlp->BIG_M;
   mlp->ci++;
 
   /* c 3) minimum bandwidth
@@ -246,6 +311,10 @@ create_constraint_it (void *cls, const GNUNET_HashCode * key, void *value)
    */
 
   row_index = glp_add_rows (mlp->prob, 1);
+  /* set row name */
+  GNUNET_asprintf(&name, "c3_%s_%s", GNUNET_i2s(&address->peer), address->plugin);
+  glp_set_row_name (mlp->prob, row_index, name);
+  GNUNET_free (name);
   mlpi->r_c3 = row_index;
   /* set row bounds: >= 0 */
   glp_set_row_bnds (mlp->prob, row_index, GLP_LO, 0.0, 0.0);
@@ -256,8 +325,8 @@ create_constraint_it (void *cls, const GNUNET_HashCode * key, void *value)
   mlp->ci++;
 
   mlp->ia[mlp->ci] = row_index;
-  mlp->ja[mlp->ci] = mlpi->c_b;
-  mlp->ar[mlp->ci] = -mlp->b_min;
+  mlp->ja[mlp->ci] = mlpi->c_n;
+  mlp->ar[mlp->ci] = - (double) mlp->b_min;
   mlp->ci++;
 
   /* c 4) minimum connections
@@ -268,9 +337,45 @@ create_constraint_it (void *cls, const GNUNET_HashCode * key, void *value)
   mlp->ar[mlp->ci] = 1;
   mlp->ci++;
 
+  /* c 6) maximize diversity
+   * (1)*n_1 + ... + (1)*n_m - d == 0
+   */
+  mlp->ia[mlp->ci] = mlp->r_c6;
+  mlp->ja[mlp->ci] = mlpi->c_n;
+  mlp->ar[mlp->ci] = 1;
+  mlp->ci++;
+
   return GNUNET_OK;
 }
 
+/**
+ * Find the required ATS information for an address
+ *
+ * @param addr the address
+ * @param ats_index the desired ATS index
+ *
+ * @return the index on success, otherwise GNUNET_SYSERR
+ */
+
+static int
+mlp_lookup_ats (struct ATS_Address *addr, int ats_index)
+{
+  struct GNUNET_ATS_Information * ats = addr->ats;
+  int c;
+  int found = GNUNET_NO;
+  for (c = 0; c < addr->ats_count; c++)
+  {
+    if (ats[c].type == ats_index)
+    {
+      found = GNUNET_YES;
+      break;
+    }
+  }
+  if (found == GNUNET_YES)
+    return c;
+  else
+    return GNUNET_SYSERR;
+}
 
 /**
  * Adds the problem constraints for all addresses
@@ -283,7 +388,8 @@ static void
 mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses)
 {
   unsigned int n_addresses;
-  int row_index;
+  int c;
+  char *name;
 
   /* Problem matrix*/
   n_addresses = GNUNET_CONTAINER_multihashmap_size(addresses);
@@ -317,12 +423,28 @@ mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CON
    * #indices: 7 * |n_addresses|
    *
    * optimality constraints:
-   * tbc
+   *
+   * c 6) diversity
+   * #rows: 1
+   * #indices: |n_addresses| + 1
+   *
+   * c 7) quality
+   * #rows: |quality properties|
+   * #indices: |n_addresses| + |quality properties|
+   *
+   * c 8) utilization
+   * #rows: 1
+   * #indices: |n_addresses| + 1
+   *
+   * c 9) relativity
+   * #rows: |peers|
+   * #indices: |n_addresses| + |peers|
    * */
 
-  int pi = (7 * n_addresses);
+  /* last +1 caused by glpk index starting with one */
+  int pi = ((7 * n_addresses) + (4 * n_addresses +  mlp->m_q + mlp->c_p + 2) + 1);
   mlp->cm_size = pi;
-  mlp->ci = 0;
+  mlp->ci = 1;
 
   /* row index */
   int *ia = GNUNET_malloc (pi * sizeof (int));
@@ -343,9 +465,27 @@ mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CON
    * c 1) bandwidth capping
    * c 3) minimum bandwidth
    * c 4) minimum number of connections
+   * c 6) maximize diversity
    */
+
+  int min = mlp->n_min;
+  if (mlp->n_min > mlp->c_p)
+    min = mlp->c_p;
+
   mlp->r_c4 = glp_add_rows (mlp->prob, 1);
-  glp_set_row_bnds (mlp->prob, mlp->r_c4, GLP_LO, mlp->n_min, 0.0);
+  glp_set_row_name (mlp->prob, mlp->r_c4, "c4");
+  glp_set_row_bnds (mlp->prob, mlp->r_c4, GLP_LO, min, min);
+
+  /* Add row for c6) */
+
+  mlp->r_c6 = glp_add_rows (mlp->prob, 1);
+  /* Set type type to fix */
+  glp_set_row_bnds (mlp->prob, mlp->r_c6, GLP_FX, 0.0, 0.0);
+  /* Setting -D */
+  ia[mlp->ci] = mlp->r_c6 ;
+  ja[mlp->ci] = mlp->c_d;
+  ar[mlp->ci] = -1;
+  mlp->ci++;
 
   GNUNET_CONTAINER_multihashmap_iterate (addresses, create_constraint_it, mlp);
 
@@ -355,32 +495,135 @@ mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CON
    *
    * c 2) 1 address per peer
    * sum (n_p1_1 + ... + n_p1_n) = 1
-   */
+   *
+   * c 8) utilization
+   * sum (f_p * b_p1_1 + ... + f_p * b_p1_n) - u = 0
+   *
+   * c 9) relativity
+   * V p : sum (bt_1 + ... +bt_n) - f_p * r = 0
+   * */
 
-  /* Adding rows for c 2) */
-  row_index = glp_add_rows (mlp->prob, mlp->c_p);
+  /* Adding rows for c 8) */
+  mlp->r_c8 = glp_add_rows (mlp->prob, mlp->c_p);
+  glp_set_row_name (mlp->prob, mlp->r_c8, "c8");
+  /* Set row bound == 0 */
+  glp_set_row_bnds (mlp->prob, mlp->r_c8, GLP_FX, 0.0, 0.0);
+  /* -u */
+  ia[mlp->ci] = mlp->r_c8;
+  ja[mlp->ci] = mlp->c_u;
+  ar[mlp->ci] = -1;
+  mlp->ci++;
 
   struct ATS_Peer * peer = mlp->peer_head;
   while (peer != NULL)
   {
     struct ATS_Address *addr = peer->head;
-    struct MLP_information *mlpi = (struct MLP_information *) addr->mlp_information;
-    /* Adding row for c 2) */
+    struct MLP_information *mlpi = NULL;
+
+    /* Adding rows for c 2) */
+    peer->r_c2 = glp_add_rows (mlp->prob, 1);
+    GNUNET_asprintf(&name, "c2_%s", GNUNET_i2s(&peer->id));
+    glp_set_row_name (mlp->prob, peer->r_c2, name);
+    GNUNET_free (name);
     /* Set row bound == 1 */
-    glp_set_row_bnds (mlp->prob, row_index, GLP_FX, 1.0, 1.0);
+    glp_set_row_bnds (mlp->prob, peer->r_c2, GLP_FX, 1.0, 1.0);
+
+    /* Adding rows for c 9) */
+    peer->r_c9 = glp_add_rows (mlp->prob, 1);
+    GNUNET_asprintf(&name, "c9_%s", GNUNET_i2s(&peer->id));
+    glp_set_row_name (mlp->prob, peer->r_c9, name);
+    GNUNET_free (name);
+    /* Set row bound == 0 */
+    glp_set_row_bnds (mlp->prob, peer->r_c9, GLP_LO, 0.0, 0.0);
+
+    /* Set -r */
+    ia[mlp->ci] = peer->r_c9;
+    ja[mlp->ci] = mlp->c_r;
+    ar[mlp->ci] = -1;
+    mlp->ci++;
 
     while (addr != NULL)
     {
-      ia[mlp->ci] = row_index;
+      mlpi = (struct MLP_information *) addr->mlp_information;
+
+      ia[mlp->ci] = peer->r_c2;
       ja[mlp->ci] = mlpi->c_n;
       ar[mlp->ci] = 1;
       mlp->ci++;
 
+      ia[mlp->ci] = mlp->r_c8;
+      ja[mlp->ci] = mlpi->c_b;
+      ar[mlp->ci] = peer->f;
+      mlp->ci++;
+
+      ia[mlp->ci] = peer->r_c9;
+      ja[mlp->ci] = mlpi->c_b;
+      ar[mlp->ci] = 1;
+      mlp->ci++;
+
       addr = addr->next;
     }
-
     peer = peer->next;
   }
+
+  /* c 7) For all quality metrics */
+
+  for (c = 0; c < mlp->m_q; c++)
+  {
+    struct ATS_Peer *p = mlp->peer_head;
+    struct ATS_Address *addr = p->head;
+    struct MLP_information * mlpi;
+    double value = 1.0;
+
+    while (p != NULL)
+    {
+      /* Adding rows for c 7) */
+      mlp->r_q[c] = glp_add_rows (mlp->prob, 1);
+      GNUNET_asprintf(&name, "c7_q%i_atsi_%i", c, mlp->q[c]);
+      glp_set_row_name (mlp->prob, mlp->r_q[c], name);
+      GNUNET_free (name);
+      /* Set row bound == 0 */
+      glp_set_row_bnds (mlp->prob, mlp->r_q[c], GLP_LO, 0.0, 0.0);
+
+      /* Set -q_m */
+      ia[mlp->ci] = mlp->r_q[c];
+      ja[mlp->ci] = mlp->c_q[c];
+      ar[mlp->ci] = -1;
+      mlp->ci++;
+
+      while (addr != NULL)
+      {
+        mlpi = addr->mlp_information;
+        /* lookup ATS information */
+        int index = mlp_lookup_ats(addr, mlp->q[c]);
+
+        if (index != GNUNET_SYSERR)
+        {
+          value = (double) addr->ats[index].value;
+#if DEBUG_ATS
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Quality %i with ATS property `%s' has index %i in addresses ats information has value %f\n", c,  mlp_ats_to_string(mlp->q[c]), index, (double) addr->ats[index].value);
+#endif
+        }
+#if DEBUG_ATS
+        else
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Quality %i with ATS property `%s' not existing\n", c,  mlp_ats_to_string(mlp->q[c]), index);
+#endif
+        mlpi = addr->mlp_information;
+
+        mlpi->r_q[c] = mlp->r_q[c];
+        mlpi->c_q[c] = mlpi->c_b;
+        mlpi->q[c] = value;
+
+        ia[mlp->ci] = mlp->r_q[c];
+        ja[mlp->ci] = mlpi->c_b;
+        ar[mlp->ci] = p->f * value;
+        mlp->ci++;
+
+        addr = addr->next;
+      }
+      p = p->next;
+    }
+  }
 }
 
 
@@ -420,6 +663,7 @@ create_columns_it (void *cls, const GNUNET_HashCode * key, void *value)
   /* Objective function coefficient == 0 */
   glp_set_obj_coef (mlp->prob, mlpi->c_b , 0);
 
+
   /* Add usage column */
   GNUNET_asprintf (&name, "n_%s_%s", GNUNET_i2s (&address->peer), address->plugin);
   glp_set_col_name (mlp->prob, mlpi->c_n, name);
@@ -450,6 +694,10 @@ mlp_create_problem (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHas
   int c;
   char *name;
 
+  GNUNET_assert (mlp->prob == NULL);
+
+  /* create the glpk problem */
+  mlp->prob = glp_create_prob ();
 
   /* Set a problem name */
   glp_set_prob_name (mlp->prob, "gnunet ats bandwidth distribution");
@@ -492,8 +740,8 @@ mlp_create_problem (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHas
   glp_set_col_bnds (mlp->prob, col, GLP_LO, 0.0, 0.0);
 
   /* Quality metric columns */
-  col = glp_add_cols(mlp->prob, mlp->m);
-  for (c = 0; c < mlp->m; c++)
+  col = glp_add_cols(mlp->prob, mlp->m_q);
+  for (c = 0; c < mlp->m_q; c++)
   {
     mlp->c_q[c] = col + c;
     GNUNET_asprintf (&name, "q_%u", mlp->q[c]);
@@ -511,6 +759,9 @@ mlp_create_problem (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHas
   /* Add constraints */
   mlp_add_constraints_all_addresses (mlp, addresses);
 
+  /* Load the matrix */
+  glp_load_matrix(mlp->prob, (mlp->ci-1), mlp->ia, mlp->ja, mlp->ar);
+
   return res;
 }
 
@@ -566,7 +817,7 @@ lp_solv:
       /* Problem was ill-defined, no way to handle that */
       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
           "ats-mlp",
-          "Solving LP problem failed:  %s\n", mlp_solve_to_string(res));
+          "Solving LP problem failed: %i %s\n", res, mlp_solve_to_string(res));
       return GNUNET_SYSERR;
     }
   }
@@ -678,7 +929,7 @@ mlp_solve_mlp_problem (struct GAS_MLP_Handle *mlp)
   return GNUNET_OK;
 }
 
-int mlp_solve_problem (struct GAS_MLP_Handle *mlp);
+int GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp);
 
 static void
 mlp_scheduler (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
@@ -694,7 +945,7 @@ mlp_scheduler (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Scheduled problem solving\n");
 #endif
   if (mlp->addr_in_problem != 0)
-    mlp_solve_problem(mlp);
+    GAS_mlp_solve_problem(mlp);
 }
 
 
@@ -705,14 +956,57 @@ mlp_scheduler (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
  */
 int
-mlp_solve_problem (struct GAS_MLP_Handle *mlp)
+GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp)
 {
   int res;
   mlp->last_execution = GNUNET_TIME_absolute_get ();
+#if DEBUG_ATS
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Problem solving\n");
+#endif
+
+#if WRITE_MLP
+  char * name;
+  static int i;
+  i++;
+  GNUNET_asprintf(&name, "problem_%i", i);
+  glp_write_lp (mlp->prob, 0, name);
+  GNUNET_free (name);
+# endif
+
   res = mlp_solve_lp_problem (mlp);
-  if (res == GNUNET_OK)
-    res = mlp_solve_mlp_problem (mlp);
 
+#if WRITE_MLP
+  GNUNET_asprintf(&name, "problem_%i_lp_solution", i);
+  glp_print_sol (mlp->prob,  name);
+  GNUNET_free (name);
+# endif
+
+  if (res != GNUNET_OK)
+  {
+#if DEBUG_ATS
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "LP Problem solving failed\n");
+#endif
+    return GNUNET_SYSERR;
+  }
+
+  res = mlp_solve_mlp_problem (mlp);
+
+#if WRITE_MLP
+  GNUNET_asprintf(&name, "problem_%i_mlp_solution", i);
+  glp_print_mip (mlp->prob, name);
+  GNUNET_free (name);
+# endif
+  if (res != GNUNET_OK)
+  {
+#if DEBUG_ATS
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MLP Problem solving failed\n");
+#endif
+    return GNUNET_SYSERR;
+  }
+
+#if DEBUG_ATS
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Problem solved\n");
+#endif
 
   /* Process result */
 
@@ -839,13 +1133,14 @@ GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
   mlp->stats = (struct GNUNET_STATISTICS_Handle *) stats;
   mlp->max_iterations = max_iterations;
   mlp->max_exec_duration = max_duration;
+  mlp->auto_solve = GNUNET_YES;
 
   /* Redirect GLPK output to GNUnet logging */
   glp_error_hook((void *) mlp, &mlp_term_hook);
 
   /* Init LP solving parameters */
   glp_init_smcp(&mlp->control_param_lp);
-#if DEBUG_MLP
+#if VERBOSE_GLPK
   mlp->control_param_lp.msg_lev = GLP_MSG_ALL;
 #else
   mlp->control_param_lp.msg_lev = GLP_MSG_OFF;
@@ -855,7 +1150,7 @@ GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
 
   /* Init MLP solving parameters */
   glp_init_iocp(&mlp->control_param_mlp);
-#if DEBUG_MLP
+#if VERBOSE_GLPK
   mlp->control_param_mlp.msg_lev = GLP_MSG_ALL;
 #else
   mlp->control_param_mlp.msg_lev = GLP_MSG_OFF;
@@ -864,16 +1159,19 @@ GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
 
   mlp->last_execution = GNUNET_TIME_absolute_get_forever();
 
+
+  mlp->BIG_M = (double) UINT32_MAX;
   mlp->co_D = D;
   mlp->co_R = R;
   mlp->co_U = U;
   mlp->b_min = b_min;
   mlp->n_min = n_min;
-  mlp->m = GNUNET_ATS_QualityPropertiesCount;
+  mlp->m_q = GNUNET_ATS_QualityPropertiesCount;
 
   return mlp;
 }
 
+
 /**
  * Updates a single address in the MLP problem
  *
@@ -906,25 +1204,37 @@ GAS_mlp_address_update (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_Mult
   if (new == GNUNET_YES)
   {
     mlpi = GNUNET_malloc (sizeof (struct MLP_information));
+
+    int c;
+    for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
+    {
+      mlpi->c_q[c] = 0;
+      mlpi->r_q[c] = 0;
+      mlpi->q[c] = 0.0;
+    }
+
     address->mlp_information = mlpi;
     mlp->addr_in_problem ++;
 
     /* Check for and add peer */
-    struct ATS_Peer *peer = mlp->peer_head;
-    while (peer != NULL)
-    {
-      if (0 == memcmp (&address->peer, &peer->id, sizeof (struct GNUNET_PeerIdentity)))
-        break;
-      peer = peer->next;
-    }
+    struct ATS_Peer *peer = mlp_find_peer (mlp, &address->peer);
     if (peer == NULL)
     {
 #if DEBUG_ATS
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Adding new peer `%s'\n", GNUNET_i2s (&address->peer));
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Adding new peer `%s'\n",
+          GNUNET_i2s (&address->peer));
 #endif
       peer = GNUNET_malloc (sizeof (struct ATS_Peer));
       peer->head = NULL;
       peer->tail = NULL;
+
+      int c;
+      for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
+      {
+        peer->f_q[c] = 1.0;
+      }
+      peer->f = 1.0;
+
       memcpy (&peer->id, &address->peer, sizeof (struct GNUNET_PeerIdentity));
       GNUNET_assert(address->prev == NULL);
       GNUNET_assert(address->next == NULL);
@@ -935,7 +1245,8 @@ GAS_mlp_address_update (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_Mult
     else
     {
 #if DEBUG_ATS
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Adding address to peer `%s'\n", GNUNET_i2s (&address->peer));
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Adding address to peer `%s'\n",
+          GNUNET_i2s (&address->peer));
 #endif
       GNUNET_CONTAINER_DLL_insert (peer->head, peer->tail, address);
     }
@@ -943,14 +1254,82 @@ GAS_mlp_address_update (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_Mult
   else
   {
 #if DEBUG_ATS
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating existing address to peer `%s'\n", GNUNET_i2s (&address->peer));
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating existing address to peer `%s'\n",
+        GNUNET_i2s (&address->peer));
+#endif
+    mlpi = address->mlp_information;
+    int c;
+    for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
+    {
+      int index = mlp_lookup_ats(address, mlp->q[c]);
+      if ((index != GNUNET_SYSERR) && (mlpi->c_q[c] != 0) && (mlpi->r_q[c] != 0))
+      {
+        if (mlpi->q[c] == (double) address->ats[index].value)
+          break;
+#if DEBUG_ATS
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating address for peer `%s' value `%s'from %f to %f\n",
+            GNUNET_i2s (&address->peer),
+            mlp_ats_to_string(mlp->q[c]),
+            mlpi->q[c],
+            (double) address->ats[index].value);
+#endif
+        switch (mlp->q[c])
+        {
+          case GNUNET_ATS_QUALITY_NET_DELAY:
+            mlpi->q[c] = (double) address->ats[index].value;
+            break;
+          case GNUNET_ATS_QUALITY_NET_DISTANCE:
+            mlpi->q[c] = (double) address->ats[index].value;
+            break;
+          default:
+            break;
+        }
+
+        /* Get current number of columns */
+        int cols = glp_get_num_cols(mlp->prob);
+        int *ind = GNUNET_malloc (cols * sizeof (int));
+        double *val = GNUNET_malloc (cols * sizeof (double));
+
+        /* Get the matrix row of quality */
+        cols = glp_get_mat_row(mlp->prob, mlp->r_q[c], ind, val);
+
+        int c2;
+        /* Get the index if matrix row of quality */
+        for (c2 = 1; c2 <= cols; c2++ )
+        {
+#if DEBUG_ATS
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Existing element column %i : %f\n",
+            ind[c2], val[c2]);
 #endif
+          if ((mlpi->c_b == ind[c2]) && (val[c2] != mlpi->q[c]))
+          {
+            /* Update the value */
+            val[c2] = mlpi->q[c];
+#if DEBUG_ATS
+            GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "New element column %i : %f\n",
+                ind[c2], val[c2]);
+#endif
+        }
+      }
+
+      /* Get the index if matrix row of quality */
+      glp_set_mat_row (mlp->prob, mlpi->r_q[c], cols, ind, val);
+
+      GNUNET_free (ind);
+      GNUNET_free (val);
+      }
+    }
   }
 
   /* Recalculate */
   if (new == GNUNET_YES)
+  {
+    mlp_delete_problem (mlp);
+    mlp_create_problem (mlp, addresses);
     mlp->presolver_required = GNUNET_YES;
-  mlp_solve_problem (mlp);
+  }
+  if (mlp->auto_solve == GNUNET_YES)
+    GAS_mlp_solve_problem (mlp);
 }
 
 /**
@@ -978,13 +1357,7 @@ GAS_mlp_address_delete (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_Mult
   }
 
   /* Remove from peer list */
-  struct ATS_Peer *head = mlp->peer_head;
-  while (head != NULL)
-  {
-    if (0 == memcmp (&address->peer, &head->id, sizeof (struct GNUNET_PeerIdentity)))
-      break;
-    head = head->next;
-  }
+  struct ATS_Peer *head = mlp_find_peer (mlp, &address->peer);
   GNUNET_assert (head != NULL);
 #if DEBUG_ATS
   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Deleting address for `%s'\n", GNUNET_i2s (&address->peer));
@@ -1005,28 +1378,34 @@ GAS_mlp_address_delete (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_Mult
   mlp_delete_problem (mlp);
   if ((GNUNET_CONTAINER_multihashmap_size (addresses) > 0) && (mlp->c_p > 0))
   {
-#if DEBUG_ATS
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "mlp_create_problem %i\n",__LINE__);
-#endif
     mlp_create_problem (mlp, addresses);
 
     /* Recalculate */
     mlp->presolver_required = GNUNET_YES;
-    mlp_solve_problem (mlp);
+    if (mlp->auto_solve == GNUNET_YES)
+      GAS_mlp_solve_problem (mlp);
   }
 }
 
 /**
- * Deletes a single address in the MLP problem
+ * Changes the preferences for a peer in the MLP problem
  *
  * @param mlp the MLP Handle
- * @param addresses the address hashmap
- * @param address the address to change the preference
+ * @param peer the peer
+ * @param kind the kind to change the preference
+ * @param float the score
  */
 void
-GAS_mlp_address_change_preference (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
+GAS_mlp_address_change_preference (struct GAS_MLP_Handle *mlp,
+                                   const struct GNUNET_PeerIdentity *peer,
+                                   enum GNUNET_ATS_PreferenceKind kind,
+                                   float score)
 {
   GNUNET_STATISTICS_update (mlp->stats,"# LP address preference changes", 1, GNUNET_NO);
+
+  struct ATS_Peer *p = mlp_find_peer (mlp, peer);
+  p = p;
+  /* Here we have to do the matching */
 }
 
 /**
@@ -1039,6 +1418,8 @@ GAS_mlp_done (struct GAS_MLP_Handle *mlp)
   struct ATS_Peer * peer;
   struct ATS_Peer * tmp;
 
+  GNUNET_assert (mlp != NULL);
+
   if (mlp->mlp_task != GNUNET_SCHEDULER_NO_TASK)
   {
     GNUNET_SCHEDULER_cancel(mlp->mlp_task);
@@ -1046,16 +1427,13 @@ GAS_mlp_done (struct GAS_MLP_Handle *mlp)
   }
 
   /* clean up peer list */
-  if (mlp != NULL)
+  peer = mlp->peer_head;
+  while (peer != NULL)
   {
-    peer = mlp->peer_head;
-    while (peer != NULL)
-    {
-      GNUNET_CONTAINER_DLL_remove(mlp->peer_head, mlp->peer_tail, peer);
-      tmp = peer->next;
-      GNUNET_free (peer);
-      peer = tmp;
-    }
+    GNUNET_CONTAINER_DLL_remove(mlp->peer_head, mlp->peer_tail, peer);
+    tmp = peer->next;
+    GNUNET_free (peer);
+    peer = tmp;
   }
   mlp_delete_problem (mlp);