indent
[oweals/gnunet.git] / src / ats / gnunet-service-ats-solver_ril.c
index 9104c4c0d6eaaa4599601a9ae1e27b677f76a148..3c7bc9be0b50097ea6777f121ed5bad3493c6224 100755 (executable)
@@ -1,22 +1,22 @@
 /*
    This file is part of GNUnet.
    (C) 2011 Christian Grothoff (and other contributing authors)
-
    GNUnet is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published
    by the Free Software Foundation; either version 3, or (at your
    option) any later version.
-
    GNUnet is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    General Public License for more details.
-
    You should have received a copy of the GNU General Public License
    along with GNUnet; see the file COPYING.  If not, write to the
    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
-*/
+ This file is part of GNUnet.
+ (C) 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING.  If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
 
 /**
  * @file ats/gnunet-service-ats-solver_ril.c
  * @author Matthias Wachs
  */
 #include "platform.h"
+#include "float.h"
 #include "gnunet_util_lib.h"
 #include "gnunet-service-ats_addresses.h"
 #include "gnunet_statistics_service.h"
 
 #define RIL_DEFAULT_STEP_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 3000)
+#define RIL_DEFAULT_ALGORITHM RIL_ALGO_Q
 #define RIL_DEFAULT_DISCOUNT_FACTOR 0.5
 #define RIL_DEFAULT_GRADIENT_STEP_SIZE 0.4
 #define RIL_DEFAULT_TRACE_DECAY 0.6
+#define RIL_EXPLORE_RATIO 0.1
 
 /**
  * ATS reinforcement learning solver
  * General description
  */
 
+enum RIL_Action_Type
+{
+  RIL_ACTION_BW_IN_DBL = 0,
+  RIL_ACTION_BW_OUT_DBL = 1,
+  RIL_ACTION_BW_IN_HLV = 2,
+  RIL_ACTION_BW_OUT_HLV = 3,
+  RIL_ACTION_TYPE_NUM = 4
+};
+//TODO! add the rest of the actions
+
+enum RIL_Algorithm
+{
+  RIL_ALGO_SARSA = 0,
+  RIL_ALGO_Q = 1
+};
+
+enum RIL_E_Modification
+{
+  RIL_E_SET, RIL_E_ZERO, RIL_E_ACCUMULATE, RIL_E_REPLACE
+};
+
 /**
  * Global learning parameters
  */
 struct RIL_Learning_Parameters
 {
-       /**
-        * Learning discount factor in the TD-update
-        */
-       float gamma;
-
-       /**
-        * Gradient-descent step-size
-        */
-       float alpha;
-
-       /**
-        * Trace-decay factor for eligibility traces
-        */
-       float lambda;
+  /**
+   * The TD-algorithm to use
+   */
+  enum RIL_Algorithm algorithm;
+
+  /**
+   * Learning discount factor in the TD-update
+   */
+  float gamma;
+
+  /**
+   * Gradient-descent step-size
+   */
+  float alpha;
+
+  /**
+   * Trace-decay factor for eligibility traces
+   */
+  float lambda;
 };
 
 struct RIL_Peer_Agent
 {
-       /**
-        * Next agent in solver's linked list
-        */
-       struct RIL_Peer_Agent *next;
-
-       /**
-        * Previous agent in solver's linked list
-        */
-       struct RIL_Peer_Agent *prev;
-
-       /**
-        * Peer ID
-        */
-       struct GNUNET_PeerIdentity peer;
-
-       /**
-        * Experience matrix W
-        */
-       double ** W;
-
-       /**
-        * Last perceived state feature vector
-        */
-       double * s_t;
-
-       /**
-        * Last chosen action
-        */
-       double * a_t;
-
-       /**
-        * Last eligibility trace vector
-        */
-       double * e_t;
+  /**
+   * Next agent in solver's linked list
+   */
+  struct RIL_Peer_Agent *next;
+
+  /**
+   * Previous agent in solver's linked list
+   */
+  struct RIL_Peer_Agent *prev;
+
+  /**
+   * Environment handle
+   */
+  struct GAS_RIL_Handle *envi;
+
+  /**
+   * Peer ID
+   */
+  struct GNUNET_PeerIdentity peer;
+
+  /**
+   * Whether the agent is active or not
+   */
+  int active;
+
+  /**
+   * Number of performed time-steps
+   */
+  unsigned long long step_count;
+
+  /**
+   * Experience matrix W
+   */
+  double ** W;
+
+  /**
+   * Number of rows of W / Number of state-vector features
+   */
+  int m;
+
+  /**
+   * Number of columns of W / Number of actions
+   */
+  int n;
+
+  /**
+   * Last perceived state feature vector
+   */
+  double * s_old;
+
+  /**
+   * Last chosen action
+   */
+  int a_old;
+
+  /**
+   * Eligibility trace vector
+   */
+  double * e;
+
+  /**
+   * Address in use
+   */
+  struct ATS_Address * address;
+
+  /**
+   * Inbound bandwidth assigned by the agent
+   */
+  unsigned long long bw_in;
+
+  /**
+   * Outbound bandwidth assigned by the agent
+   */
+  unsigned long long bw_out;
 };
 
 struct RIL_Network
 {
-         /**
-          * ATS network type
-          */
-         unsigned int type;
-
-         /**
-          * Network description
-          */
-         char *desc;
-
-         /**
-          * Total available inbound bandwidth
-          */
-         unsigned long long bw_in_available;
-
-         /**
-          * Total assigned outbound bandwidth
-          */
-         unsigned long long bw_in_assigned;
-
-         /**
-          * Total available outbound bandwidth
-          */
-         unsigned long long bw_out_available;
-
-         /**
-          * Total assigned outbound bandwidth
-          */
-         unsigned long long bw_out_assigned;
+  /**
+   * ATS network type
+   */
+  enum GNUNET_ATS_Network_Type type;
+
+  /**
+   * Total available inbound bandwidth
+   */
+  unsigned long long bw_in_available;
+
+  /**
+   * Total assigned outbound bandwidth
+   */
+  unsigned long long bw_in_assigned;
+
+  /**
+   * Total available outbound bandwidth
+   */
+  unsigned long long bw_out_available;
+
+  /**
+   * Total assigned outbound bandwidth
+   */
+  unsigned long long bw_out_assigned;
 };
 
 struct RIL_Callbacks
 {
-         /**
-          * Bandwidth changed callback
-          */
-         GAS_bandwidth_changed_cb bw_changed;
-
-         /**
-          * Bandwidth changed callback cls
-          */
-         void *bw_changed_cls;
-
-         /**
-          * ATS function to get preferences
-          */
-         GAS_get_preferences get_preferences;
-
-         /**
-          * Closure for ATS function to get preferences
-          */
-         void *get_preferences_cls;
-
-         /**
-          * ATS function to get properties
-          */
-         GAS_get_properties get_properties;
-
-         /**
-          * Closure for ATS function to get properties
-          */
-         void *get_properties_cls;
+  /**
+   * Bandwidth changed callback
+   */
+  GAS_bandwidth_changed_cb bw_changed;
+
+  /**
+   * Bandwidth changed callback cls
+   */
+  void *bw_changed_cls;
+
+  /**
+   * ATS function to get preferences
+   */
+  GAS_get_preferences get_preferences;
+
+  /**
+   * Closure for ATS function to get preferences
+   */
+  void *get_preferences_cls;
+
+  /**
+   * ATS function to get properties
+   */
+  GAS_get_properties get_properties;
+
+  /**
+   * Closure for ATS function to get properties
+   */
+  void *get_properties_cls;
 };
 
 /**
@@ -170,124 +234,557 @@ struct RIL_Callbacks
  */
 struct GAS_RIL_Handle
 {
-       /**
-       * Statistics handle
-       */
-       struct GNUNET_STATISTICS_Handle *stats;
-
-       /**
-       * Hashmap containing all valid addresses
-       */
-       const struct GNUNET_CONTAINER_MultiHashMap *addresses;
-
-       /**
-       * Callbacks for the solver
-       */
-       struct RIL_Callbacks callbacks;
-
-       /**
-       * Bulk lock
-       */
-       int bulk_lock;
-
-       /**
-       * Number of changes while solver was locked
-       */
-       int bulk_requests;
-
-       /**
-       * Number of performed time-steps
-       */
-       unsigned long long step_count;
-
-       /**
-       * Interval time between steps in milliseconds //TODO put in agent
-       */
-       struct GNUNET_TIME_Relative step_time;
-
-       /**
-       * Task identifier of the next time-step to be executed //TODO put in agent
-       */
-       GNUNET_SCHEDULER_TaskIdentifier next_step;
-
-       /**
-       * Learning parameters
-       */
-       struct RIL_Learning_Parameters parameters;
-
-       /**
-       * Array of networks with global assignment state
-       */
-       struct RIL_Network * network_entries;
-
-       /**
-       * Networks count
-       */
-       unsigned int networks_count;
-
-       /**
-       * List of active peer-agents
-       */
-       struct RIL_Peer_Agent * agents_active_head;
-       struct RIL_Peer_Agent * agents_active_tail;
-
-       /**
-       * List of paused peer-agents
-       */
-       struct RIL_Peer_Agent * agents_paused_head;
-       struct RIL_Peer_Agent * agents_paused_tail;
+  /**
+   * Statistics handle
+   */
+  struct GNUNET_STATISTICS_Handle *stats;
+
+  /**
+   * Hashmap containing all valid addresses
+   */
+  const struct GNUNET_CONTAINER_MultiHashMap *addresses;
+
+  /**
+   * Callbacks for the solver
+   */
+  struct RIL_Callbacks *callbacks;
+
+  /**
+   * Bulk lock
+   */
+  int bulk_lock;
+
+  /**
+   * Number of changes while solver was locked
+   */
+  int bulk_requests;
+
+  /**
+   * Number of performed time-steps
+   */
+  unsigned long long step_count;
+
+  /**
+   * Interval time between steps in milliseconds //TODO? put in agent
+   */
+  struct GNUNET_TIME_Relative step_time;
+
+  /**
+   * Task identifier of the next time-step to be executed //TODO? put in agent
+   */
+  GNUNET_SCHEDULER_TaskIdentifier next_step;
+
+  /**
+   * Learning parameters
+   */
+  struct RIL_Learning_Parameters parameters;
+
+  /**
+   * Array of networks with global assignment state
+   */
+  struct RIL_Network * network_entries;
+
+  /**
+   * Networks count
+   */
+  unsigned int networks_count;
+
+  /**
+   * List of active peer-agents
+   */
+  struct RIL_Peer_Agent * agents_head;
+  struct RIL_Peer_Agent * agents_tail;
 };
 
+/**
+ *  Private functions
+ *  ---------------------------
+ */
 
-enum Actions
+/**
+ * Estimate the current action-value for state s and action a
+ * @param agent agent performing the estimation
+ * @param state s
+ * @param action a
+ * @return estimation value
+ */
+static double
+agent_estimate_q (struct RIL_Peer_Agent *agent, double *state, int action)
 {
-       bw_dbl,
-       bw_hlv
-};
-//TODO add the rest of the actions
+  int i;
+  double result = 0;
+
+  for (i = 0; i < agent->m; i++)
+  {
+    result += state[i] * agent->W[action][i];
+  }
+
+  return result;
+}
 
 /**
- *  Private functions
- *  ---------------------------
+ * Decide whether to do exploration (i.e. taking a new action) or exploitation (i.e. taking the
+ * currently estimated best action) in the current step
+ * @param agent agent performing the step
+ * @return yes, if exploring
  */
+static int
+agent_decide_exploration (struct RIL_Peer_Agent *agent)
+{
+  double r = (double) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+      UINT32_MAX) / (double) UINT32_MAX;
+
+  if (r < RIL_EXPLORE_RATIO)
+  {
+    return GNUNET_YES;
+  }
+  return GNUNET_NO;
+}
 
-void
-agent_periodic_step (void *solver,
-                               const struct GNUNET_SCHEDULER_TaskContext *tc)
+/**
+ * Gets the action, with the maximal estimated Q-value (i.e. the one currently estimated to bring the
+ * most reward in the future)
+ * @param agent agent performing the calculation
+ * @param state the state from which to take the action
+ * @return the action promising most future reward
+ */
+static int
+agent_get_action_best (struct RIL_Peer_Agent *agent, double *state)
+{
+  int i;
+  int max_i = -1;
+  double cur_q;
+  double max_q = -DBL_MAX;
+
+  for (i = 0; i < agent->n; i++)
+  {
+    cur_q = agent_estimate_q (agent, state, i);
+    if (cur_q > max_q)
+    {
+      max_q = cur_q;
+      max_i = i;
+    }
+  }
+
+  GNUNET_assert(-1 != max_i);
+
+  return max_i;
+}
+
+/**
+ * Gets any action, to explore the action space from that state
+ * @param agent agent performing the calculation
+ * @param state the state from which to take the action
+ * @return any action
+ */
+static int
+agent_get_action_explore (struct RIL_Peer_Agent *agent, double *state)
 {
-       /*
-        * iterate over active agents and do a time step
-        */
-       struct GAS_RIL_Handle *s = solver;
+  return GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, agent->n);
+}
 
-       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "RIL step number %d\n", s->step_count);
+/**
+ * Updates the weights (i.e. coefficients) of the weight vector in matrix W for action a
+ * @param agent the agent performing the update
+ * @param reward the reward received for the last action
+ * @param s_next the new state, the last step got the agent into
+ * @param a_prime the new
+ */
+static void
+agent_update_weights (struct RIL_Peer_Agent *agent,
+    double reward,
+    double *s_next,
+    int a_prime)
+{
+  int i;
+  double delta;
+  double *theta = agent->W[agent->a_old];
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "agent_update_weights() MUH a_old = %d\n", agent->a_old);
+  delta = reward + agent_estimate_q (agent, s_next, a_prime)
+      - agent_estimate_q (agent, agent->s_old, agent->a_old);
+  for (i = 0; i < agent->m; i++)
+  {
+    theta[i] += agent->envi->parameters.alpha * delta * (agent->e)[i];
+  }
+}
+
+/**
+ * Changes the eligibility trace vector e in various manners:
+ * RIL_E_ACCUMULATE - adds 1 to each component as in accumulating eligibility traces
+ * RIL_E_REPLACE - resets each component to 1 as in replacing traces
+ * RIL_E_SET - multiplies e with gamma and lambda as in the update rule
+ * RIL_E_ZERO - sets e to 0 as in Watkin's Q-learning algorithm when exploring and when initializing
+ * @param agent
+ * @param mod
+ */
+static void
+agent_modify_eligibility (struct RIL_Peer_Agent *agent,
+    enum RIL_E_Modification mod)
+{
+  int i;
+  double *e = agent->e;
+  double gamma = agent->envi->parameters.gamma;
+  double lambda = agent->envi->parameters.lambda;
+
+  for (i = 0; i < agent->m; i++)
+  {
+    switch (mod)
+    {
+    case RIL_E_ACCUMULATE:
+      e[i] += 1;
+      break;
+    case RIL_E_REPLACE:
+      e[i] = 1;
+      break;
+    case RIL_E_SET:
+      e[i] = gamma * lambda;
+      break;
+    case RIL_E_ZERO:
+      e[i] = 0;
+      break;
+    }
+  }
+}
 
-       s->step_count += 1;
-       s->next_step = GNUNET_SCHEDULER_add_delayed (
-                       s->step_time,
-                       &agent_periodic_step,
-                       solver);
+/**
+ * Allocates a state vector and fills it with the features present
+ * @param solver the solver handle
+ * @return pointer to the state vector
+ */
+static double *
+envi_get_state (struct GAS_RIL_Handle *solver)
+{
+  int i;
+  struct RIL_Network *net;
+  double *state = GNUNET_malloc (sizeof (double) * solver->networks_count * 4);
+
+  for (i = 0; i < solver->networks_count; i++)
+  {
+    net = &solver->network_entries[i];
+    state[i*4 + 0] = (double) net->bw_in_assigned;
+    state[i*4 + 1] = (double) net->bw_in_available;
+    state[i*4 + 2] = (double) net->bw_out_assigned;
+    state[i*4 + 3] = (double) net->bw_out_available;
+  }
+
+  return state;
 }
 
 /**
- * Whether a peer already has an agent in a list
- * @param head of list
- * @param peer in question
+ * Gets the reward of the last performed step
+ * @param solver solver handle
+ * @return the reward
  */
-int
-list_contains_agent (struct RIL_Peer_Agent * head,
-                                       struct GNUNET_PeerIdentity * peer)
+static double
+envi_get_reward (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent *agent)
 {
-       struct RIL_Peer_Agent * cur;
+  //TODO! implement reward calculation
 
-       for (cur = head; NULL != cur; cur = cur->next)
-       {
-               if (!memcmp (&(cur->peer.hashPubKey), &peer->hashPubKey, sizeof(struct GNUNET_HashCode)))
-               {
-                       return GNUNET_YES;
-               }
-       }
-       return GNUNET_NO;
+  return (double) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+      UINT32_MAX) / (double) UINT32_MAX;
+}
+
+static void
+envi_action_bw_double (struct GAS_RIL_Handle *solver,
+    struct RIL_Peer_Agent *agent,
+    int direction_in)
+{
+  if (direction_in)
+  {
+    agent->bw_in *= 2;
+    agent->address->assigned_bw_in.value__ = htonl (agent->bw_in);
+    solver->callbacks->bw_changed (solver->callbacks->bw_changed_cls,
+        agent->address);
+  }
+  else
+  {
+    agent->bw_out *= 2;
+    agent->address->assigned_bw_out.value__ = htonl (agent->bw_out);
+    solver->callbacks->bw_changed (solver->callbacks->bw_changed_cls,
+        agent->address);
+  }
+}
+
+static void
+envi_action_bw_halven (struct GAS_RIL_Handle *solver,
+    struct RIL_Peer_Agent *agent,
+    int direction_in)
+{
+  if ((direction_in && 1 == agent->bw_in)
+      || (!direction_in && 1 == agent->bw_out))
+  {
+    return;
+  }
+  if (direction_in)
+  {
+    agent->bw_in /= 2;
+    agent->address->assigned_bw_in.value__ = htonl (agent->bw_in);
+    solver->callbacks->bw_changed (solver->callbacks->bw_changed_cls,
+        agent->address);
+  }
+  else
+  {
+    agent->bw_out /= 2;
+    agent->address->assigned_bw_out.value__ = htonl (agent->bw_out);
+    solver->callbacks->bw_changed (solver->callbacks->bw_changed_cls,
+        agent->address);
+  }
+}
+
+/**
+ * Puts the action into effect
+ * @param solver solver handle
+ * @param action action to perform by the solver
+ */
+static void
+envi_do_action (struct GAS_RIL_Handle *solver,
+    struct RIL_Peer_Agent *agent,
+    int action)
+{
+  switch (action)
+  {
+  case RIL_ACTION_BW_IN_DBL:
+    envi_action_bw_double (solver, agent, GNUNET_YES);
+    break;
+  case RIL_ACTION_BW_IN_HLV:
+    envi_action_bw_halven (solver, agent, GNUNET_YES);
+    break;
+  case RIL_ACTION_BW_OUT_DBL:
+    envi_action_bw_double (solver, agent, GNUNET_NO);
+    break;
+  case RIL_ACTION_BW_OUT_HLV:
+    envi_action_bw_halven (solver, agent, GNUNET_NO);
+    break;
+  }
+}
+
+/**
+ * Performs one step of the Markov Decision Process. Other than in the literature the step starts
+ * after having done the last action a_old. It observes the new state s_next and the reward
+ * received. Then the coefficient update is done according to the SARSA or Q-learning method. The
+ * next action is put into effect.
+ * @param agent the agent performing the step
+ */
+static void
+agent_step (struct RIL_Peer_Agent *agent)
+{
+  int a_next = -1;
+  double *s_next;
+  double reward;
+
+  s_next = envi_get_state (agent->envi);
+  reward = envi_get_reward (agent->envi, agent);
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "agent_step() with algorithm %s\n",
+      agent->envi->parameters.algorithm ? "Q" : "SARSA");
+
+  switch (agent->envi->parameters.algorithm)
+  {
+  case RIL_ALGO_SARSA:
+    agent_modify_eligibility (agent, RIL_E_SET);
+    if (agent_decide_exploration (agent))
+    {
+      a_next = agent_get_action_explore (agent, s_next);
+    }
+    else
+    {
+      a_next = agent_get_action_best (agent, s_next);
+    }
+    //updates weights with selected action (on-policy), if not first step
+    if (-1 != agent->a_old)
+      agent_update_weights (agent, reward, s_next, a_next);
+    break;
+
+  case RIL_ALGO_Q:
+    //updates weights with best action, disregarding actually selected action (off-policy), if not first step
+    a_next = agent_get_action_best (agent, s_next);
+    if (-1 != agent->a_old)
+      agent_update_weights (agent, reward, s_next, a_next);
+    if (agent_decide_exploration (agent))
+    {
+      a_next = agent_get_action_explore (agent, s_next);
+      agent_modify_eligibility (agent, RIL_E_ZERO);
+    }
+    else
+    {
+      a_next = agent_get_action_best (agent, s_next);
+      agent_modify_eligibility (agent, RIL_E_SET);
+    }
+    break;
+  }
+
+  GNUNET_assert(-1 != a_next);
+
+  agent_modify_eligibility (agent, RIL_E_ACCUMULATE);
+
+  envi_do_action (agent->envi, agent, a_next);
+
+  GNUNET_free(agent->s_old);
+  agent->s_old = s_next;
+  agent->a_old = a_next;
+
+  agent->step_count += 1;
+}
+
+/**
+ * Cycles through all agents and lets the active ones do a step. Schedules the next step.
+ * @param solver the solver handle
+ * @param tc task context for the scheduler
+ */
+static void
+ril_periodic_step (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct GAS_RIL_Handle *solver = cls;
+  struct RIL_Peer_Agent *cur;
+
+  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "RIL step number %d\n",
+      solver->step_count);
+
+  for (cur = solver->agents_head; NULL != cur; cur = cur->next)
+  {
+    if (cur->active)
+    {
+      agent_step (cur);
+    }
+  }
+
+  solver->step_count += 1;
+  solver->next_step = GNUNET_SCHEDULER_add_delayed (solver->step_time,
+      &ril_periodic_step, solver);
+}
+
+/**
+ * Initialize an agent without addresses and its knowledge base
+ * @param s ril solver
+ * @param peer the one in question
+ * @return handle to the new agent
+ */
+static struct RIL_Peer_Agent *
+agent_init (void *s, const struct GNUNET_PeerIdentity *peer)
+{
+  int i;
+  struct GAS_RIL_Handle * solver = s;
+  struct RIL_Peer_Agent * agent = GNUNET_malloc (sizeof (struct RIL_Peer_Agent));
+
+  agent->envi = solver;
+  agent->peer = *peer;
+  agent->step_count = 0;
+  agent->active = GNUNET_NO;
+  agent->s_old = envi_get_state (solver);
+  agent->n = RIL_ACTION_TYPE_NUM;
+  agent->m = solver->networks_count * 4;
+  agent->W = (double **) GNUNET_malloc (sizeof (double) * agent->n);
+  for (i = 0; i < agent->n; i++)
+  {
+    agent->W[i] = (double *) GNUNET_malloc (sizeof (double) * agent->m);
+  }
+  agent->a_old = -1;
+  agent->e = (double *) GNUNET_malloc (sizeof (double) * agent->m);
+  agent_modify_eligibility (agent, RIL_E_ZERO);
+
+  GNUNET_CONTAINER_DLL_insert_tail(solver->agents_head, solver->agents_tail,
+      agent);
+
+  return agent;
+}
+
+/**
+ * Deallocate agent
+ * @param s solver handle
+ * @param agent the agent to retire
+ */
+static void
+agent_die (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent *agent)
+{
+  int i;
+
+  for (i = 0; i < agent->n; i++)
+  {
+    GNUNET_free(agent->W[i]);
+  }
+  GNUNET_free(agent->W);
+  GNUNET_free(agent->e);
+  GNUNET_free(agent->s_old);
+}
+
+static void
+ril_remove_agent (struct GAS_RIL_Handle *s, struct RIL_Peer_Agent *agent)
+{
+  struct RIL_Peer_Agent *cur_agent;
+  struct RIL_Peer_Agent *next_agent;
+
+  cur_agent = s->agents_head;
+  while (NULL != cur_agent)
+  {
+    next_agent = cur_agent->next;
+
+    if (agent == cur_agent)
+      GNUNET_CONTAINER_DLL_remove(s->agents_head, s->agents_tail, cur_agent);
+      agent_die (s, cur_agent);
+
+    cur_agent = next_agent;
+  }
+}
+
+/**
+ * Counts the (active) agents
+ * @param solver solver handle
+ * @param active_only whether only active agents should be counted
+ * @return number of agents
+ */
+static int
+ril_count_agents (struct GAS_RIL_Handle *solver, int active_only)
+{
+  int c;
+  struct RIL_Peer_Agent *cur;
+
+  c = 0;
+  for (cur = solver->agents_head; NULL != cur; cur = cur->next)
+  {
+    if ((!active_only) || (active_only && cur->active))
+    {
+      c += 1;
+    }
+  }
+  return c;
+}
+
+/**
+ * Returns the agent for a peer
+ * @param s solver handle
+ * @param peer identity of the peer
+ * @param create whether to create an agent if none is allocated yet
+ * @return agent
+ */
+static struct RIL_Peer_Agent *
+ril_get_agent (struct GAS_RIL_Handle *solver,
+    const struct GNUNET_PeerIdentity *peer,
+    int create)
+{
+  struct RIL_Peer_Agent *cur;
+
+  for (cur = solver->agents_head; NULL != cur; cur = cur->next)
+  {
+    if (0 == GNUNET_CRYPTO_hash_cmp (&peer->hashPubKey, &cur->peer.hashPubKey))
+    {
+      return cur;
+    }
+  }
+
+  if (create)
+    return agent_init (solver, peer);
+  return NULL;
+}
+
+static int
+ril_network_is_active (struct RIL_Network *network)
+{
+  uint32_t min_bw = ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
+
+  if (network->bw_out_available < min_bw)
+    return GNUNET_NO;
+  return GNUNET_YES;
 }
 
 /**
@@ -298,27 +795,53 @@ list_contains_agent (struct RIL_Peer_Agent * head,
  * @param value address
  * @return whether iterator should continue
  */
-int
-init_agents_it (void *cls,
-                               const struct GNUNET_HashCode *key,
-                               void *value)
+static int
+ril_init_agents_it (void *cls, const struct GNUNET_HashCode *key, void *value)
 {
-       struct GAS_RIL_Handle *solver = cls;
-       struct ATS_Address *address = value;
-       struct RIL_Peer_Agent *agent;
-
-       if (!list_contains_agent (solver->agents_paused_head, &address->peer))
-       {
-               agent = GNUNET_malloc (sizeof (struct RIL_Peer_Agent));
-               agent->peer = address->peer;
-               GNUNET_CONTAINER_DLL_insert (solver->agents_paused_head, solver->agents_paused_tail, agent);
-       }
-
-       //TODO add address to agent
-       return GNUNET_YES;
+  struct GAS_RIL_Handle *solver = cls;
+  struct ATS_Address *address = value;
+  struct RIL_Peer_Agent *agent = NULL;
+  uint32_t min_bw = ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
+
+  if (ril_network_is_active(address->solver_information))
+  {
+    agent = ril_get_agent (solver, &address->peer, GNUNET_YES);
+
+    GNUNET_assert(NULL != agent);
+
+    if (NULL == agent->address)
+    {
+      agent->address = address;
+      agent->address->active = GNUNET_YES;
+      agent->bw_in = min_bw;
+      agent->address->assigned_bw_in.value__ = htonl (min_bw);
+      agent->bw_out = min_bw;
+      agent->address->assigned_bw_out.value__ = htonl (min_bw);
+    }
+  }
+  return GNUNET_YES;
 }
 
-
+/**
+ * Lookup network struct by type
+ *
+ * @param s the solver handle
+ * @param type the network type
+ * @return the network struct
+ */
+static struct RIL_Network *
+ril_get_network (struct GAS_RIL_Handle *s, uint32_t type)
+{
+  int i;
+
+  for (i = 0; i < s->networks_count; i++)
+  {
+    if (s->network_entries[i].type == type) {
+      return &s->network_entries[i];
+    }
+  }
+  return NULL;
+}
 
 /**
  *  Solver API functions
@@ -334,21 +857,19 @@ init_agents_it (void *cls,
  * @param pref_rel the normalized preference value for this kind over all clients
  */
 void
-GAS_ril_address_change_preference (void *solver,
-                                                                                       const struct GNUNET_PeerIdentity *peer,
-                                                                                       enum GNUNET_ATS_PreferenceKind kind,
-                                                                                       double pref_rel)
+GAS_ril_address_change_preference (void *s,
+    const struct GNUNET_PeerIdentity *peer,
+    enum GNUNET_ATS_PreferenceKind kind,
+    double pref_rel)
 {
-       //TODO implement
-
-       /*
-        * Probably nothing to do here. The preference is looked up during reward calculation and does
-        * not trigger anything
-        */
-       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ril_address_change_preference() has been called\n");
+  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
+      "API_address_change_preference() Preference `%s' for peer `%s' changed to %.2f \n",
+      GNUNET_ATS_print_preference_type (kind), GNUNET_i2s (peer), pref_rel);
+  /*
+   * Nothing to do here. Preferences are considered during reward calculation.
+   */
 }
 
-
 /**
  * Init the reinforcement learning problem solver
  *
@@ -380,97 +901,111 @@ GAS_ril_address_change_preference (void *solver,
  */
 void *
 GAS_ril_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                               const struct GNUNET_STATISTICS_Handle *stats,
-                               const struct GNUNET_CONTAINER_MultiHashMap *addresses,
-                               int *network,
-                               unsigned long long *out_quota,
-                               unsigned long long *in_quota,
-                               int dest_length,
-                               GAS_bandwidth_changed_cb bw_changed_cb,
-                               void *bw_changed_cb_cls,
-                               GAS_get_preferences get_preference,
-                               void *get_preference_cls,
-                               GAS_get_properties get_properties,
-                               void *get_properties_cls)
-{
-       //TODO implement
-       int c;
-       unsigned long long tmp;
-       struct RIL_Network * cur;
-       struct GAS_RIL_Handle *solver = GNUNET_malloc (sizeof (struct GAS_RIL_Handle));
-       char * net_str[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkTypeString;
-
-       GNUNET_assert (NULL != cfg);
-       GNUNET_assert (NULL != stats);
-       GNUNET_assert (NULL != network);
-       GNUNET_assert (NULL != bw_changed_cb);
-       GNUNET_assert (NULL != get_preference);
-       GNUNET_assert (NULL != get_properties);
-
-       if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time(cfg, "ats", "RIL_STEP_TIME", &solver->step_time))
-       {
-               solver->step_time = RIL_DEFAULT_STEP_TIME;
-       }
-       if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size(cfg, "ats", "RIL_DISCOUNT_FACTOR", &tmp))
-       {
-               solver->parameters.gamma = tmp;
-       }
-       else
-       {
-               solver->parameters.gamma = RIL_DEFAULT_DISCOUNT_FACTOR;
-       }
-       if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size(cfg, "ats", "RIL_GRADIENT_STEP_SIZE", &tmp))
-       {
-               solver->parameters.alpha = tmp;
-       }
-       else
-       {
-               solver->parameters.alpha = RIL_DEFAULT_GRADIENT_STEP_SIZE;
-       }
-       if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size(cfg, "ats", "RIL_TRACE_DECAY", &tmp))
-       {
-               solver->parameters.lambda = tmp;
-       }
-       else
-       {
-               solver->parameters.lambda = RIL_DEFAULT_TRACE_DECAY;
-       }
-
-       solver->stats = (struct GNUNET_STATISTICS_Handle *) stats;
-       solver->callbacks.bw_changed = bw_changed_cb;
-       solver->callbacks.bw_changed_cls = bw_changed_cb_cls;
-       solver->callbacks.get_preferences = get_preference;
-       solver->callbacks.get_preferences_cls = get_preference_cls;
-       solver->callbacks.get_properties = get_properties;
-       solver->callbacks.get_properties_cls = get_properties_cls;
-       solver->networks_count = dest_length;
-       solver->network_entries = GNUNET_malloc (dest_length * sizeof (struct RIL_Network));
-       solver->bulk_lock = GNUNET_NO;
-       solver->addresses = addresses;
-       solver->step_count = 0;
-
-       for (c = 0; c < dest_length; c++)
-       {
-               cur = &solver->network_entries[c];
-               cur->type = network[c];
-               cur->bw_in_available = in_quota[c];
-               cur->bw_in_assigned = 0;
-               cur->bw_out_available = out_quota[c];
-               cur->bw_out_assigned = 0;
-               cur->desc = net_str[c];
-       }
-
-       c = GNUNET_CONTAINER_multihashmap_iterate (addresses, &init_agents_it, solver);
-
-       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ril_init() has been called\n");
-       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "RIL number of addresses: %d\n", c);
-
-       solver->next_step = GNUNET_SCHEDULER_add_delayed (
-                               GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_millisecond_ (), 1000),
-                               &agent_periodic_step,
-                               solver);
-
-       return solver;
+    const struct GNUNET_STATISTICS_Handle *stats,
+    const struct GNUNET_CONTAINER_MultiHashMap *addresses,
+    int *network,
+    unsigned long long *out_quota,
+    unsigned long long *in_quota,
+    int dest_length,
+    GAS_bandwidth_changed_cb bw_changed_cb,
+    void *bw_changed_cb_cls,
+    GAS_get_preferences get_preference,
+    void *get_preference_cls,
+    GAS_get_properties get_properties,
+    void *get_properties_cls)
+{
+  int c;
+  unsigned long long tmp;
+  char *string;
+  struct RIL_Network * cur;
+  struct GAS_RIL_Handle *solver = GNUNET_malloc (sizeof (struct GAS_RIL_Handle));
+
+  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "API_init() Initializing RIL solver\n");
+
+  GNUNET_assert(NULL != cfg);
+  GNUNET_assert(NULL != stats);
+  GNUNET_assert(NULL != network);
+  GNUNET_assert(NULL != bw_changed_cb);
+  GNUNET_assert(NULL != get_preference);
+  GNUNET_assert(NULL != get_properties);
+
+  if (GNUNET_OK
+      != GNUNET_CONFIGURATION_get_value_time (cfg, "ats", "RIL_STEP_TIME",
+          &solver->step_time))
+  {
+    solver->step_time = RIL_DEFAULT_STEP_TIME;
+  }
+  if (GNUNET_OK
+      == GNUNET_CONFIGURATION_get_value_string (cfg, "ats", "RIL_ALGORITHM",
+          &string) && NULL != string && 0 == strcmp (string, "SARSA"))
+  {
+    solver->parameters.algorithm = RIL_ALGO_SARSA;
+  }
+  else
+  {
+    solver->parameters.algorithm = RIL_DEFAULT_ALGORITHM;
+  }
+  if (GNUNET_OK
+      == GNUNET_CONFIGURATION_get_value_size (cfg, "ats", "RIL_DISCOUNT_FACTOR",
+          &tmp))
+  {
+    solver->parameters.gamma = (double) tmp / 100;
+  }
+  else
+  {
+    solver->parameters.gamma = RIL_DEFAULT_DISCOUNT_FACTOR;
+  }
+  if (GNUNET_OK
+      == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
+          "RIL_GRADIENT_STEP_SIZE", &tmp))
+  {
+    solver->parameters.alpha = (double) tmp / 100;
+  }
+  else
+  {
+    solver->parameters.alpha = RIL_DEFAULT_GRADIENT_STEP_SIZE;
+  }
+  if (GNUNET_OK
+      == GNUNET_CONFIGURATION_get_value_size (cfg, "ats", "RIL_TRACE_DECAY",
+          &tmp))
+  {
+    solver->parameters.lambda = (double) tmp / 100;
+  }
+  else
+  {
+    solver->parameters.lambda = RIL_DEFAULT_TRACE_DECAY;
+  }
+
+  solver->stats = (struct GNUNET_STATISTICS_Handle *) stats;
+  solver->callbacks = GNUNET_malloc (sizeof (struct RIL_Callbacks));
+  solver->callbacks->bw_changed = bw_changed_cb;
+  solver->callbacks->bw_changed_cls = bw_changed_cb_cls;
+  solver->callbacks->get_preferences = get_preference;
+  solver->callbacks->get_preferences_cls = get_preference_cls;
+  solver->callbacks->get_properties = get_properties;
+  solver->callbacks->get_properties_cls = get_properties_cls;
+  solver->networks_count = dest_length;
+  solver->network_entries =
+      GNUNET_malloc (dest_length * sizeof (struct RIL_Network));
+  solver->bulk_lock = GNUNET_NO;
+  solver->addresses = addresses;
+  solver->step_count = 0;
+
+  for (c = 0; c < dest_length; c++)
+  {
+    cur = &solver->network_entries[c];
+    cur->type = network[c];
+    cur->bw_in_available = in_quota[c];
+    cur->bw_in_assigned = 0;
+    cur->bw_out_available = out_quota[c];
+    cur->bw_out_assigned = 0;
+  }
+
+  solver->next_step = GNUNET_SCHEDULER_add_delayed (
+      GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_millisecond_ (),
+          1000), &ril_periodic_step, solver);
+
+  return solver;
 }
 
 /**
@@ -481,17 +1016,27 @@ GAS_ril_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
 void
 GAS_ril_done (void * solver)
 {
-       //TODO implement
-       struct GAS_RIL_Handle *s = solver;
-
-       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ril_done() has been called\n");
-
-       GNUNET_SCHEDULER_cancel (s->next_step);
-       GNUNET_free (s->network_entries);
-       GNUNET_free (s);
+  struct GAS_RIL_Handle *s = solver;
+  struct RIL_Peer_Agent *cur_agent;
+  struct RIL_Peer_Agent *next_agent;
+
+  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "API_done() Shutting down RIL solver\n");
+
+  cur_agent = s->agents_head;
+  while (NULL != cur_agent)
+  {
+    next_agent = cur_agent->next;
+    GNUNET_CONTAINER_DLL_remove(s->agents_head, s->agents_tail, cur_agent);
+    agent_die (s, cur_agent);
+    cur_agent = next_agent;
+  }
+
+  GNUNET_SCHEDULER_cancel (s->next_step);
+  GNUNET_free(s->callbacks);
+  GNUNET_free(s->network_entries);
+  GNUNET_free(s);
 }
 
-
 /**
  * Add a single address within a network to the solver
  *
@@ -501,19 +1046,31 @@ GAS_ril_done (void * solver)
  */
 void
 GAS_ril_address_add (void *solver,
-                                                       struct ATS_Address *address,
-                                                       uint32_t network)
+    struct ATS_Address *address,
+    uint32_t network)
 {
-       //TODO implement
-       /*
-        * if (new peer)
-        *     initialize new agent
-        * Add address
-        * increase state vector
-        * knowledge matrix
-        * and action vector
-        */
-       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ril_address_add() has been called\n");
+  struct GAS_RIL_Handle *s = solver;
+  //TODO! implement solver address add
+  /*
+   * if (new peer)
+   *     initialize new agent
+   * Add address
+   * increase state vector
+   * knowledge matrix
+   * and action vector
+   */
+
+  address->solver_information = ril_get_network(s, network);
+
+  /*
+   * reiterate all addresses, create new agent if necessary and give the agent the address
+   */
+  GNUNET_CONTAINER_multihashmap_iterate (s->addresses, &ril_init_agents_it,
+      solver);
+
+  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
+      "API_address_add() Added %s address for peer '%s'\n", address->plugin,
+      GNUNET_i2s (&address->peer));
 }
 
 /**
@@ -525,19 +1082,47 @@ GAS_ril_address_add (void *solver,
  */
 void
 GAS_ril_address_delete (void *solver,
-    struct ATS_Address *address, int session_only)
+    struct ATS_Address *address,
+    int session_only)
 {
-       //TODO implement
-       /*
-        * remove address
-        * if (last address of peer)
-        *     remove agent
-        * else
-        *     decrease state vector
-        *     decrease knowledge matrix
-        *     decrease action vector
-        */
-       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ril_address_delete() has been called\n");
+  //TODO! implement solver address delete
+  //TODO! delete session only
+  /*
+   * remove address
+   * if (last address of peer)
+   *     remove agent
+   * else
+   *     decrease state vector
+   *     decrease knowledge matrix
+   *     decrease action vector
+   */
+  struct GAS_RIL_Handle *s = solver;
+  struct RIL_Peer_Agent *agent;
+
+  agent = ril_get_agent (s, &address->peer, GNUNET_NO);
+
+  if (NULL == agent)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "API_address_delete() deleting address for unallocated agent");
+    return;
+  }
+
+  if (0 == memcmp (agent->address->addr, address->addr, address->addr_len)) //if used address deleted
+  {
+    agent->address = NULL; //delete address
+    GNUNET_CONTAINER_multihashmap_iterate (s->addresses, &ril_init_agents_it,
+        solver); //put another address
+    if (NULL == agent->address) //no other address available
+    {
+      agent->active = GNUNET_NO;
+      ril_remove_agent (solver, agent);
+    }
+  }
+
+  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
+      "API_address_delete() Deleted %s%s address for peer '%s'\n",
+      session_only ? "session for " : "", address->plugin,
+      GNUNET_i2s (&address->peer));
 }
 
 /**
@@ -551,20 +1136,20 @@ GAS_ril_address_delete (void *solver,
  */
 void
 GAS_ril_address_property_changed (void *solver,
-                                                                                                                       struct ATS_Address *address,
-                                                                                                                       uint32_t type,
-                                                                                                                       uint32_t abs_value,
-                                                                                                                       double rel_value)
+    struct ATS_Address *address,
+    uint32_t type,
+    uint32_t abs_value,
+    double rel_value)
 {
-       //TODO implement
-       /*
-        * Like change_preference() not really interesting, since lookup happens anyway during reward
-        * calculation
-        */
-       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ril_address_property_changed() has been called\n");
+  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
+      "API_address_property_changed() Property `%s' for peer `%s' address %p changed "
+          "to %.2f \n", GNUNET_ATS_print_property_type (type),
+      GNUNET_i2s (&address->peer), address, rel_value);
+  /*
+   * Nothing to do here, properties are considered in every reward calculation
+   */
 }
 
-
 /**
  * Transport session for this address has changed
  *
@@ -577,18 +1162,17 @@ GAS_ril_address_property_changed (void *solver,
  */
 void
 GAS_ril_address_session_changed (void *solver,
-                                                                                                                       struct ATS_Address *address,
-                                                                                                                       uint32_t cur_session,
-                                                                                                                       uint32_t new_session)
+    struct ATS_Address *address,
+    uint32_t cur_session,
+    uint32_t new_session)
 {
-       //TODO implement
-       /*
-        * Potentially add session activity as a feature in state vector
-        */
-       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ril_address_session_changed() has been called\n");
+  //TODO? consider session changed in solver behaviour
+  /*
+   * Potentially add session activity as a feature in state vector
+   */
+  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "API_address_session_changed()\n");
 }
 
-
 /**
  * Usage for this address has changed
  *
@@ -600,14 +1184,17 @@ GAS_ril_address_session_changed (void *solver,
  */
 void
 GAS_ril_address_inuse_changed (void *solver,
-                                                                                                                       struct ATS_Address *address,
-                                                                                                                       int in_use)
+    struct ATS_Address *address,
+    int in_use)
 {
-       //TODO implement
-       /**
-        * See matthias' email
-        */
-       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ril_address_inuse_changed() has been called\n");
+  //TODO! consider address_inuse_changed according to matthias' email
+  /**
+   * See matthias' email
+   */
+  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
+      "API_address_inuse_changed() Usage for %s address of peer '%s' changed to %s\n",
+      address->plugin, GNUNET_i2s (&address->peer),
+      (GNUNET_YES == in_use) ? "USED" : "UNUSED");
 }
 
 /**
@@ -622,15 +1209,83 @@ GAS_ril_address_inuse_changed (void *solver,
  */
 void
 GAS_ril_address_change_network (void *solver,
-                                                                                                                                          struct ATS_Address *address,
-                                                                                                                                          uint32_t current_network,
-                                                                                                                                          uint32_t new_network)
+    struct ATS_Address *address,
+    uint32_t current_network,
+    uint32_t new_network)
 {
-       //TODO implement
-       /*
-        * update network
-        */
-       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ril_address_change_network() has been called\n");
+  struct GAS_RIL_Handle *s = solver;
+  struct RIL_Peer_Agent *agent;
+  struct RIL_Network *net;
+
+  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
+      "API_address_change_network() Network type changed, moving "
+          "%s address of peer %s from `%s' to `%s'\n",
+      (GNUNET_YES == address->active) ? "active" : "inactive",
+      GNUNET_i2s (&address->peer),
+      GNUNET_ATS_print_network_type (current_network),
+      GNUNET_ATS_print_network_type (new_network));
+
+  address->solver_information = ril_get_network(solver, new_network);
+
+  if (address->active)
+  {
+    agent = ril_get_agent(solver, &address->peer, GNUNET_NO);
+
+    //remove from old network
+    net = ril_get_network (s, current_network);
+    net->bw_in_assigned -= agent->bw_in;
+    net->bw_out_assigned -= agent->bw_out;
+
+    if (ril_network_is_active(ril_get_network(s, new_network)))
+    {
+      //add to new network
+      net = ril_get_network (s, new_network);
+      net->bw_in_assigned += agent->bw_in;
+      net->bw_out_assigned += agent->bw_out;
+
+      GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
+          "API_address_change_network() Moved %d inbound and %d "
+              "outbound\n", agent->bw_in, agent->bw_out);
+    }
+    else //new network for this address is not active => address must not be considered
+    {
+      address->active = GNUNET_NO;
+      agent->address = NULL; //delete address
+          GNUNET_CONTAINER_multihashmap_iterate (s->addresses, &ril_init_agents_it,
+              solver); //put another address
+      if (NULL == agent->address) //no other address available
+      {
+        agent->active = GNUNET_NO;
+        ril_remove_agent(s, agent);
+      }
+    }
+  }
+}
+
+/**
+ * Get application feedback for a peer
+ *
+ * @param solver the solver handle
+ * @param application the application
+ * @param peer the peer to change the preference for
+ * @param scope the time interval for this feedback: [now - scope .. now]
+ * @param kind the kind to change the preference
+ * @param score the score
+ */
+void
+GAS_ril_address_preference_feedback (void *solver,
+    void *application,
+    const struct GNUNET_PeerIdentity *peer,
+    const struct GNUNET_TIME_Relative scope,
+    enum GNUNET_ATS_PreferenceKind kind,
+    double score)
+{
+  //TODO! collect reward until next reward calculation
+  //TODO! Find out application
+  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
+      "API_address_preference_feedback() Peer '%s' got a feedback of %+.3f from application %s for "
+          "preference %s for %d seconds\n", GNUNET_i2s (peer), "UNKNOWN",
+      GNUNET_ATS_print_preference_type (kind), scope.rel_value_us / 1000000);
 }
 
 /**
@@ -641,27 +1296,28 @@ GAS_ril_address_change_network (void *solver,
 void
 GAS_ril_bulk_start (void *solver)
 {
-       //TODO implement
-       /*
-        * bulk counter up, but not really relevant, because there is no complete calculation of the
-        * bandwidth assignment triggered anyway. Therefore, changes to addresses can come and go as
-        * they want. Consideration: Step-pause during bulk-start-stop period...
-        */
-       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ril_bulk_start() has been called\n");
+  //TODO? consideration: keep bulk counter and stop agents during bulk
+  /*
+   * bulk counter up, but not really relevant, because there is no complete calculation of the
+   * bandwidth assignment triggered anyway. Therefore, changes to addresses can come and go as
+   * they want. Consideration: Step-pause during bulk-start-stop period...
+   */
+
+  //GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "API_bulk_start()\n");
 }
 
-
 /**
  * Bulk operation done
  */
 void
 GAS_ril_bulk_stop (void *solver)
 {
-       //TODO implement
-       /*
-        * bulk counter down, see bulk_start()
-        */
-       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ril_bulk_stop() has been called\n");
+  //TODO? consideration: keep bulk counter and stop agents during bulk
+  /*
+   * bulk counter down, see bulk_start()
+   */
+
+  //GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "API_bulk_stop()\n");
 }
 
 /**
@@ -672,23 +1328,30 @@ GAS_ril_bulk_stop (void *solver)
  */
 const struct ATS_Address *
 GAS_ril_get_preferred_address (void *solver,
-                               const struct GNUNET_PeerIdentity *peer)
+    const struct GNUNET_PeerIdentity *peer)
 {
-       //TODO implement
-       /*
-        * connect-only for requested peers, move agent to active list
-        */
-       struct GAS_RIL_Handle *s = solver;
+  /*
+   * activate agent, return currently chosen address
+   */
+  struct GAS_RIL_Handle *s = solver;
+  struct RIL_Peer_Agent *agent;
+
+  agent = ril_get_agent (s, peer, GNUNET_NO);
 
-       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ril_get_preferred_address() has been called\n");
+  if (NULL == agent)
+  {
+    return NULL;
+  }
 
-       if (0 == GNUNET_CONTAINER_multihashmap_contains(s->addresses, &peer->hashPubKey))
-       {
-               return GNUNET_CONTAINER_multihashmap_get(s->addresses, &peer->hashPubKey);
-       }
+  agent->active = GNUNET_YES;
 
-       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No address for peer in addresses\n");
-       return NULL;
+  GNUNET_assert(NULL != agent->address);
+
+  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
+      "API_get_preferred_address() Activated agent for peer '%s' with %s address\n",
+      GNUNET_i2s (peer), agent->address->plugin);
+
+  return agent->address;
 }
 
 /**
@@ -699,13 +1362,17 @@ GAS_ril_get_preferred_address (void *solver,
  */
 void
 GAS_ril_stop_get_preferred_address (void *solver,
-                                     const struct GNUNET_PeerIdentity *peer)
+    const struct GNUNET_PeerIdentity *peer)
 {
-       //TODO implement
-       /*
-        * connect-only for requested peers, move agent to paused list
-        */
-       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ril_stop_get_preferred_address() has been called\n");
+  struct GAS_RIL_Handle *s = solver;
+  struct RIL_Peer_Agent *agent;
+
+  agent = ril_get_agent (s, peer, GNUNET_NO);
+  agent->active = GNUNET_NO;
+
+  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
+      "API_stop_get_preferred_address() Paused agent for peer '%s' with %s address\n",
+      GNUNET_i2s (peer), agent->address->plugin);
 }
 
-/* end of gnunet-service-ats-solver_reinf.c */
+/* end of gnunet-service-ats-solver_ril.c */