+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_ats_service.h"
+#include "gnunet_ats_plugin.h"
+#include "gnunet-service-ats_addresses.h"
+#include "gnunet_statistics_service.h"
+#include <float.h>
+#include <glpk.h>
+
+
+#define BIG_M_VALUE (UINT32_MAX) /10
+#define BIG_M_STRING "unlimited"
+
+#define MLP_AVERAGING_QUEUE_LENGTH 3
+
+#define MLP_MAX_EXEC_DURATION GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 10)
+#define MLP_MAX_ITERATIONS 4096
+
+#define MLP_DEFAULT_D 1.0
+#define MLP_DEFAULT_R 1.0
+#define MLP_DEFAULT_U 1.0
+#define MLP_DEFAULT_QUALITY 1.0
+#define MLP_DEFAULT_MIN_CONNECTIONS 4
+#define MLP_DEFAULT_PEER_PREFERENCE 1.0
+
+#define MLP_NaN -1
+#define MLP_UNDEFINED 0
+#define GLP_YES 1.0
+#define GLP_NO 0.0
+
+enum MLP_Output_Format
+{
+ MLP_MPS,
+ MLP_CPLEX,
+ MLP_GLPK
+};
+
+
+enum QualityMetrics
+{
+ RQ_QUALITY_METRIC_DELAY = 0,
+ RQ_QUALITY_METRIC_DISTANCE = 1,
+ RQ_QUALITY_METRIC_COUNT = 2
+};
+
+
+static const char *
+print_quality_type (enum QualityMetrics qm)
+{
+ switch (qm){
+ case RQ_QUALITY_METRIC_DELAY:
+ return "delay";
+ case RQ_QUALITY_METRIC_DISTANCE:
+ return "distance";
+ default:
+ GNUNET_break (0);
+ return NULL;
+ }
+}
+
+
+struct MLP_Solution
+{
+ int lp_res;
+ int lp_presolv;
+ int mip_res;
+ int mip_presolv;
+
+ double lp_objective_value;
+ double mlp_objective_value;
+ double mlp_gap;
+ double lp_mlp_gap;
+
+ int p_elements;
+ int p_cols;
+ int p_rows;
+
+ int n_peers;
+ int n_addresses;
+
+};
+
+struct ATS_Peer
+{
+ struct GNUNET_PeerIdentity id;
+
+ /* Was this peer already added to the current problem? */
+ int processed;
+
+ /* constraint 2: 1 address per peer*/
+ unsigned int r_c2;
+
+ /* constraint 9: relativity */
+ unsigned int r_c9;
+
+ /* Legacy preference value */
+ double f;
+};
+
+struct MLP_Problem
+{
+ /**
+ * GLPK (MLP) problem object
+ */
+ glp_prob *prob;
+
+ /* Number of addresses in problem */
+ unsigned int num_addresses;
+ /* Number of peers in problem */
+ unsigned int num_peers;
+ /* Number of elements in problem matrix */
+ unsigned int num_elements;
+
+ /* Row index constraint 2: */
+ unsigned int r_c2;
+ /* Row index constraint 4: minimum connections */
+ unsigned int r_c4;
+ /* Row index constraint 6: maximize diversity */
+ unsigned int r_c6;
+ /* Row index constraint 8: utilization*/
+ unsigned int r_c8;
+ /* Row index constraint 9: relativity*/
+ unsigned int r_c9;
+ /* Row indices quality metrics */
+ int r_q[RQ_QUALITY_METRIC_COUNT];
+ /* Row indices ATS network quotas */
+ int r_quota[GNUNET_NT_COUNT];
+
+ /* Column index Diversity (D) column */
+ int c_d;
+ /* Column index Utilization (U) column */
+ int c_u;
+ /* Column index Proportionality (R) column */
+ int c_r;
+ /* Column index quality metrics */
+ int c_q[RQ_QUALITY_METRIC_COUNT];
+
+ /* Problem matrix */
+ /* Current index */
+ unsigned int ci;
+ /* Row index array */
+ int *ia;
+ /* Column index array */
+ int *ja;
+ /* Column index value */
+ double *ar;
+
+};
+
+struct MLP_Variables
+{
+ /* Big M value for bandwidth capping */
+ double BIG_M;
+
+ /* MIP Gap */
+ double mip_gap;
+
+ /* LP MIP Gap */
+ double lp_mip_gap;
+
+ /* Number of quality metrics @deprecated, use RQ_QUALITY_METRIC_COUNT */
+ int m_q;
+
+ /* Number of quality metrics */
+ int m_rc;
+
+ /* Quality metric coefficients*/
+ double co_Q[RQ_QUALITY_METRIC_COUNT];
+
+ /* Ressource costs coefficients*/
+ double co_RC[RQ_QUALITY_METRIC_COUNT];
+
+ /* Diversity coefficient */
+ double co_D;
+
+ /* Utility coefficient */
+ double co_U;
+
+ /* Relativity coefficient */
+ double co_R;
+
+ /* Minimum bandwidth assigned to an address */
+ unsigned int b_min;
+
+ /* Minimum number of addresses with bandwidth assigned */
+ unsigned int n_min;
+
+ /* Quotas */
+ /* Array mapping array index to ATS network */
+ int quota_index[GNUNET_NT_COUNT];
+ /* Outbound quotas */
+ unsigned long long quota_out[GNUNET_NT_COUNT];
+ /* Inbound quotas */
+
+ unsigned long long quota_in[GNUNET_NT_COUNT];
+
+ /* ATS ressource costs
+ * array with GNUNET_ATS_QualityPropertiesCount elements
+ * contains mapping to GNUNET_ATS_Property
+ * */
+ int rc[RQ_QUALITY_METRIC_COUNT];
+
+};
+
+/**
+ * MLP Handle
+ */
+struct GAS_MLP_Handle
+{
+ struct GNUNET_ATS_PluginEnvironment *env;
+
+ /**
+ * Exclude peer from next result propagation
+ */
+ const struct GNUNET_PeerIdentity *exclude_peer;
+
+ /**
+ * Encapsulation for the MLP problem
+ */
+ struct MLP_Problem p;
+
+ /**
+ * Encapsulation for the MLP problem variables
+ */
+ struct MLP_Variables pv;
+
+ /**
+ * Encapsulation for the MLP solution
+ */
+ struct MLP_Solution ps;
+
+ /**
+ * Bulk lock
+ */
+ int stat_bulk_lock;
+
+ /**
+ * Number of changes while solver was locked
+ */
+ int stat_bulk_requests;
+
+ /**
+ * GLPK LP control parameter
+ */
+ glp_smcp control_param_lp;
+
+ /**
+ * GLPK LP control parameter
+ */
+ glp_iocp control_param_mlp;
+
+ /**
+ * Peers with pending address requests
+ */
+ struct GNUNET_CONTAINER_MultiPeerMap *requested_peers;
+
+ /**
+ * Was the problem updated since last solution
+ */
+ int stat_mlp_prob_updated;
+
+ /**
+ * Has the problem size changed since last solution
+ */
+ int stat_mlp_prob_changed;
+
+ /**
+ * Solve the problem automatically when updates occur?
+ * Default: GNUNET_YES
+ * Can be disabled for test and measurements
+ */
+ int opt_mlp_auto_solve;
+
+ /**
+ * Write all MILP problems to a MPS file
+ */
+ int opt_dump_problem_all;
+
+ /**
+ * Write all MILP problem solutions to a file
+ */
+ int opt_dump_solution_all;
+
+ /**
+ * Write MILP problems to a MPS file when solver fails
+ */
+ int opt_dump_problem_on_fail;
+
+ /**
+ * Write MILP problem solutions to a file when solver fails
+ */
+ int opt_dump_solution_on_fail;
+
+ /**
+ * solve feasibility only
+ */
+ int opt_dbg_feasibility_only;
+
+ /**
+ * solve autoscale the problem
+ */
+ int opt_dbg_autoscale_problem;
+
+ /**
+ * use the intopt presolver instead of simplex
+ */
+ int opt_dbg_intopt_presolver;
+
+ /**
+ * Print GLPK output
+ */
+ int opt_dbg_glpk_verbose;
+
+ /**
+ * solve autoscale the problem
+ */
+ int opt_dbg_optimize_relativity;
+
+ /**
+ * solve autoscale the problem
+ */
+ int opt_dbg_optimize_diversity;
+
+ /**
+ * solve autoscale the problem
+ */
+ int opt_dbg_optimize_quality;
+
+ /**
+ * solve autoscale the problem
+ */
+ int opt_dbg_optimize_utility;
+
+
+ /**
+ * Output format
+ */
+ enum MLP_Output_Format opt_log_format;
+};
+
+/**
+ * Address specific MLP information
+ */
+struct MLP_information
+{
+
+ /**
+ * Bandwidth assigned outbound
+ */
+ uint32_t b_out;
+
+ /**
+ * Bandwidth assigned inbound
+ */
+ uint32_t b_in;
+
+ /**
+ * Address selected
+ */
+ int n;
+
+ /**
+ * bandwidth column index
+ */
+ signed int c_b;
+
+ /**
+ * address usage column
+ */
+ signed int c_n;
+
+ /* row indexes */
+
+ /**
+ * constraint 1: bandwidth capping
+ */
+ unsigned int r_c1;
+
+ /**
+ * constraint 3: minimum bandwidth
+ */
+ unsigned int r_c3;
+};