plugin_ats_mlp.c 80 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2011-2014 Christian Grothoff (and other contributing authors)
  4. GNUnet is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published
  6. by the Free Software Foundation; either version 3, or (at your
  7. option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNUnet; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  15. Boston, MA 02111-1307, USA.
  16. */
  17. /**
  18. * @file ats/plugin_ats_mlp.c
  19. * @brief ats mlp problem solver
  20. * @author Matthias Wachs
  21. * @author Christian Grothoff
  22. */
  23. #include "platform.h"
  24. #include "gnunet_util_lib.h"
  25. #include "gnunet_ats_service.h"
  26. #include "gnunet_ats_plugin.h"
  27. #include "gnunet-service-ats_addresses.h"
  28. #include "gnunet_statistics_service.h"
  29. #include <float.h>
  30. #include <glpk.h>
  31. #define BIG_M_VALUE (UINT32_MAX) /10
  32. #define BIG_M_STRING "unlimited"
  33. #define MLP_AVERAGING_QUEUE_LENGTH 3
  34. #define MLP_MAX_EXEC_DURATION GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 10)
  35. #define MLP_MAX_ITERATIONS 4096
  36. #define MLP_DEFAULT_D 1.0
  37. #define MLP_DEFAULT_R 1.0
  38. #define MLP_DEFAULT_U 1.0
  39. #define MLP_DEFAULT_QUALITY 1.0
  40. #define MLP_DEFAULT_MIN_CONNECTIONS 4
  41. #define MLP_DEFAULT_PEER_PREFERENCE 1.0
  42. #define MLP_NaN -1
  43. #define MLP_UNDEFINED 0
  44. #define GLP_YES 1.0
  45. #define GLP_NO 0.0
  46. enum MLP_Output_Format
  47. {
  48. MLP_MPS,
  49. MLP_CPLEX,
  50. MLP_GLPK
  51. };
  52. enum QualityMetrics
  53. {
  54. RQ_QUALITY_METRIC_DELAY = 0,
  55. RQ_QUALITY_METRIC_DISTANCE = 1,
  56. RQ_QUALITY_METRIC_COUNT = 2
  57. };
  58. static const char *
  59. print_quality_type (enum QualityMetrics qm)
  60. {
  61. switch (qm){
  62. case RQ_QUALITY_METRIC_DELAY:
  63. return "delay";
  64. case RQ_QUALITY_METRIC_DISTANCE:
  65. return "distance";
  66. default:
  67. GNUNET_break (0);
  68. return NULL;
  69. }
  70. }
  71. struct MLP_Solution
  72. {
  73. int lp_res;
  74. int lp_presolv;
  75. int mip_res;
  76. int mip_presolv;
  77. double lp_objective_value;
  78. double mlp_objective_value;
  79. double mlp_gap;
  80. double lp_mlp_gap;
  81. int p_elements;
  82. int p_cols;
  83. int p_rows;
  84. int n_peers;
  85. int n_addresses;
  86. };
  87. struct ATS_Peer
  88. {
  89. struct GNUNET_PeerIdentity id;
  90. /* Was this peer already added to the current problem? */
  91. int processed;
  92. /* constraint 2: 1 address per peer*/
  93. unsigned int r_c2;
  94. /* constraint 9: relativity */
  95. unsigned int r_c9;
  96. /* Legacy preference value */
  97. double f;
  98. };
  99. struct MLP_Problem
  100. {
  101. /**
  102. * GLPK (MLP) problem object
  103. */
  104. glp_prob *prob;
  105. /* Number of addresses in problem */
  106. unsigned int num_addresses;
  107. /* Number of peers in problem */
  108. unsigned int num_peers;
  109. /* Number of elements in problem matrix */
  110. unsigned int num_elements;
  111. /* Row index constraint 2: */
  112. unsigned int r_c2;
  113. /* Row index constraint 4: minimum connections */
  114. unsigned int r_c4;
  115. /* Row index constraint 6: maximize diversity */
  116. unsigned int r_c6;
  117. /* Row index constraint 8: utilization*/
  118. unsigned int r_c8;
  119. /* Row index constraint 9: relativity*/
  120. unsigned int r_c9;
  121. /* Row indices quality metrics */
  122. int r_q[RQ_QUALITY_METRIC_COUNT];
  123. /* Row indices ATS network quotas */
  124. int r_quota[GNUNET_ATS_NetworkTypeCount];
  125. /* Column index Diversity (D) column */
  126. int c_d;
  127. /* Column index Utilization (U) column */
  128. int c_u;
  129. /* Column index Proportionality (R) column */
  130. int c_r;
  131. /* Column index quality metrics */
  132. int c_q[RQ_QUALITY_METRIC_COUNT];
  133. /* Problem matrix */
  134. /* Current index */
  135. unsigned int ci;
  136. /* Row index array */
  137. int *ia;
  138. /* Column index array */
  139. int *ja;
  140. /* Column index value */
  141. double *ar;
  142. };
  143. struct MLP_Variables
  144. {
  145. /* Big M value for bandwidth capping */
  146. double BIG_M;
  147. /* MIP Gap */
  148. double mip_gap;
  149. /* LP MIP Gap */
  150. double lp_mip_gap;
  151. /* Number of quality metrics @deprecated, use RQ_QUALITY_METRIC_COUNT */
  152. int m_q;
  153. /* Number of quality metrics */
  154. int m_rc;
  155. /* Quality metric coefficients*/
  156. double co_Q[RQ_QUALITY_METRIC_COUNT];
  157. /* Ressource costs coefficients*/
  158. double co_RC[RQ_QUALITY_METRIC_COUNT];
  159. /* Diversity coefficient */
  160. double co_D;
  161. /* Utility coefficient */
  162. double co_U;
  163. /* Relativity coefficient */
  164. double co_R;
  165. /* Minimum bandwidth assigned to an address */
  166. unsigned int b_min;
  167. /* Minimum number of addresses with bandwidth assigned */
  168. unsigned int n_min;
  169. /* Quotas */
  170. /* Array mapping array index to ATS network */
  171. int quota_index[GNUNET_ATS_NetworkTypeCount];
  172. /* Outbound quotas */
  173. unsigned long long quota_out[GNUNET_ATS_NetworkTypeCount];
  174. /* Inbound quotas */
  175. unsigned long long quota_in[GNUNET_ATS_NetworkTypeCount];
  176. /* ATS ressource costs
  177. * array with GNUNET_ATS_QualityPropertiesCount elements
  178. * contains mapping to GNUNET_ATS_Property
  179. * */
  180. int rc[RQ_QUALITY_METRIC_COUNT];
  181. };
  182. /**
  183. * MLP Handle
  184. */
  185. struct GAS_MLP_Handle
  186. {
  187. struct GNUNET_ATS_PluginEnvironment *env;
  188. /**
  189. * Exclude peer from next result propagation
  190. */
  191. const struct GNUNET_PeerIdentity *exclude_peer;
  192. /**
  193. * Encapsulation for the MLP problem
  194. */
  195. struct MLP_Problem p;
  196. /**
  197. * Encapsulation for the MLP problem variables
  198. */
  199. struct MLP_Variables pv;
  200. /**
  201. * Encapsulation for the MLP solution
  202. */
  203. struct MLP_Solution ps;
  204. /**
  205. * Bulk lock
  206. */
  207. int stat_bulk_lock;
  208. /**
  209. * Number of changes while solver was locked
  210. */
  211. int stat_bulk_requests;
  212. /**
  213. * GLPK LP control parameter
  214. */
  215. glp_smcp control_param_lp;
  216. /**
  217. * GLPK LP control parameter
  218. */
  219. glp_iocp control_param_mlp;
  220. /**
  221. * Peers with pending address requests
  222. */
  223. struct GNUNET_CONTAINER_MultiPeerMap *requested_peers;
  224. /**
  225. * Was the problem updated since last solution
  226. */
  227. int stat_mlp_prob_updated;
  228. /**
  229. * Has the problem size changed since last solution
  230. */
  231. int stat_mlp_prob_changed;
  232. /**
  233. * Solve the problem automatically when updates occur?
  234. * Default: GNUNET_YES
  235. * Can be disabled for test and measurements
  236. */
  237. int opt_mlp_auto_solve;
  238. /**
  239. * Write all MILP problems to a MPS file
  240. */
  241. int opt_dump_problem_all;
  242. /**
  243. * Write all MILP problem solutions to a file
  244. */
  245. int opt_dump_solution_all;
  246. /**
  247. * Write MILP problems to a MPS file when solver fails
  248. */
  249. int opt_dump_problem_on_fail;
  250. /**
  251. * Write MILP problem solutions to a file when solver fails
  252. */
  253. int opt_dump_solution_on_fail;
  254. /**
  255. * solve feasibility only
  256. */
  257. int opt_dbg_feasibility_only;
  258. /**
  259. * solve autoscale the problem
  260. */
  261. int opt_dbg_autoscale_problem;
  262. /**
  263. * use the intopt presolver instead of simplex
  264. */
  265. int opt_dbg_intopt_presolver;
  266. /**
  267. * Print GLPK output
  268. */
  269. int opt_dbg_glpk_verbose;
  270. /**
  271. * solve autoscale the problem
  272. */
  273. int opt_dbg_optimize_relativity;
  274. /**
  275. * solve autoscale the problem
  276. */
  277. int opt_dbg_optimize_diversity;
  278. /**
  279. * solve autoscale the problem
  280. */
  281. int opt_dbg_optimize_quality;
  282. /**
  283. * solve autoscale the problem
  284. */
  285. int opt_dbg_optimize_utility;
  286. /**
  287. * Output format
  288. */
  289. enum MLP_Output_Format opt_log_format;
  290. };
  291. /**
  292. * Address specific MLP information
  293. */
  294. struct MLP_information
  295. {
  296. /**
  297. * Bandwidth assigned outbound
  298. */
  299. uint32_t b_out;
  300. /**
  301. * Bandwidth assigned inbound
  302. */
  303. uint32_t b_in;
  304. /**
  305. * Address selected
  306. */
  307. int n;
  308. /**
  309. * bandwidth column index
  310. */
  311. signed int c_b;
  312. /**
  313. * address usage column
  314. */
  315. signed int c_n;
  316. /* row indexes */
  317. /**
  318. * constraint 1: bandwidth capping
  319. */
  320. unsigned int r_c1;
  321. /**
  322. * constraint 3: minimum bandwidth
  323. */
  324. unsigned int r_c3;
  325. };
  326. /**
  327. *
  328. * NOTE: Do not modify this documentation. This documentation is based on
  329. * gnunet.org:/vcs/fsnsg/ats-paper.git/tech-doku/ats-tech-guide.tex
  330. * use build_txt.sh to generate plaintext output
  331. *
  332. * The MLP solver (mlp) tries to finds an optimal bandwidth assignmentby
  333. * optimizing an mixed integer programming problem. The MLP solver uses a
  334. * number of constraints to find the best adddress for a peer and an optimal
  335. * bandwidth assignment. mlp uses the GNU Linear Programming Kit to solve the
  336. * MLP problem.
  337. *
  338. * We defined a constraint system to find an optimal bandwidth assignment.
  339. * This constraint system uses as an input data addresses, bandwidth quotas,
  340. * preferences and quality values. This constraint system is stored in an
  341. * matrix based equotation system.
  342. *
  343. * 5 Using GLPK
  344. *
  345. * A (M)LP problem consists of a target function to optimizes, constraints
  346. * and rows and columns. FIXME GLP uses three arrays to index the matrix: two
  347. * integer arrays storing the row and column indices in the matrix and an
  348. * float array to store the coeeficient.
  349. *
  350. * To solve the problem we first find an initial solution for the LP problem
  351. * using the LP solver and then find an MLP solution based on this solution
  352. * using the MLP solver.
  353. *
  354. * Solving (M)LP problems has the property that finding an initial solution
  355. * for the LP problem is computationally expensive and finding the MLP
  356. * solution is cheaper. This is especially interesting an existing LP
  357. * solution can be reused if only coefficients in the matrix have changed
  358. * (addresses updated). Only when the problem size changes (addresses added
  359. * or deleted) a new LP solution has to be found.
  360. *
  361. * Intended usage
  362. * The mlp solver solves the bandwidth assignment problem only on demand when
  363. * an address suggestion is requested. When an address is requested mlp the
  364. * solves the mlp problem and if the active address or the bandwidth assigned
  365. * changes it calls the callback to addresses. The mlp solver gets notified
  366. * about new addresses (adding sessions), removed addresses (address
  367. * deletions) and address updates. To benefit from the mlp properties
  368. * mentioned in section 5 the solver rembers if since the last solution
  369. * addresses were added or deleted (problem size changed, problem has to be
  370. * rebuild and solved from sratch) or if addresses were updated and the
  371. * existing solution can be reused.
  372. *
  373. * 5.1 Input data
  374. *
  375. * The quotas for each network segment are passed by addresses. MLP can be
  376. * adapted using configuration settings and uses the following parameters:
  377. * * MLP_MAX_DURATION:
  378. * Maximum duration for a MLP solution procees (default: 3 sec.)
  379. * * MLP_MAX_ITERATIONS:
  380. * Maximum number of iterations for a MLP solution process (default:
  381. * 1024)
  382. * * MLP_MIN_CONNECTIONS:
  383. * Minimum number of desired connections (default: 4)
  384. * * MLP_MIN_BANDWIDTH:
  385. * Minimum amount of bandwidth assigned to an address (default: 1024)
  386. * * MLP_COEFFICIENT_D:
  387. * Diversity coefficient (default: 1.0)
  388. * * MLP_COEFFICIENT_R:
  389. * Relativity coefficient (default: 1.0)
  390. * * MLP_COEFFICIENT_U:
  391. * Utilization coefficient (default: 1.0)
  392. * * MLP_COEFFICIENT_D:
  393. * Diversity coefficient (default: 1.0)
  394. * * MLP_COEFFICIENT_QUALITY_DELAY:
  395. * Quality delay coefficient (default: 1.0)
  396. * * MLP_COEFFICIENT_QUALITY_DISTANCE:
  397. * Quality distance coefficient (default: 1.0)
  398. * * MLP_COEFFICIENT_QUALITY_DISTANCE:
  399. * Quality distance coefficient (default: 1.0)
  400. * * MLP_COEFFICIENT_QUALITY_DISTANCE:
  401. * Quality distance coefficient (default: 1.0)
  402. * * MLP_COEFFICIENT_QUALITY_DISTANCE:
  403. * Quality distance coefficient (default: 1.0)
  404. *
  405. * 5.2 Data structures used
  406. *
  407. * mlp has for each known peer a struct ATS_Peer containing information about
  408. * a specific peer. The address field solver_information contains information
  409. * about the mlp properties of this address.
  410. *
  411. * 5.3 Initializing
  412. *
  413. * During initialization mlp initializes the GLPK libray used to solve the
  414. * MLP problem: it initializes the glpk environment and creates an initial LP
  415. * problem. Next it loads the configuration values from the configuration or
  416. * uses the default values configured in -addresses_mlp.h. The quotas used
  417. * are given by addresses but may have to be adjusted. mlp uses a upper limit
  418. * for the bandwidth assigned called BIG M and a minimum amount of bandwidth
  419. * an address gets assigned as well as a minium desired number of
  420. * connections. If the configured quota is bigger than BIG M, it is reduced
  421. * to BIG M. If the configured quota is smaller than MLP_MIN_CONNECTIONS
  422. * *MLP_MIN_BANDWIDTH it is increased to this value.
  423. *
  424. * 5.4 Shutdown
  425. */
  426. #define LOG(kind,...) GNUNET_log_from (kind, "ats-mlp",__VA_ARGS__)
  427. /**
  428. * Print debug output for mlp problem creation
  429. */
  430. #define DEBUG_MLP_PROBLEM_CREATION GNUNET_NO
  431. /**
  432. * Intercept GLPK terminal output
  433. * @param info the mlp handle
  434. * @param s the string to print
  435. * @return 0: glpk prints output on terminal, 0 != surpress output
  436. */
  437. static int
  438. mlp_term_hook (void *info, const char *s)
  439. {
  440. struct GAS_MLP_Handle *mlp = info;
  441. if (mlp->opt_dbg_glpk_verbose)
  442. LOG (GNUNET_ERROR_TYPE_ERROR, "%s", s);
  443. return 1;
  444. }
  445. /**
  446. * Reset peers for next problem creation
  447. *
  448. * @param cls not used
  449. * @param key the key
  450. * @param value ATS_Peer
  451. * @return #GNUNET_OK
  452. */
  453. static int
  454. reset_peers (void *cls,
  455. const struct GNUNET_PeerIdentity *key,
  456. void *value)
  457. {
  458. struct ATS_Peer *peer = value;
  459. peer->processed = GNUNET_NO;
  460. return GNUNET_OK;
  461. }
  462. /**
  463. * Delete the MLP problem and free the constrain matrix
  464. *
  465. * @param mlp the MLP handle
  466. */
  467. static void
  468. mlp_delete_problem (struct GAS_MLP_Handle *mlp)
  469. {
  470. int c;
  471. if (mlp == NULL)
  472. return;
  473. if (mlp->p.prob != NULL)
  474. {
  475. glp_delete_prob(mlp->p.prob);
  476. mlp->p.prob = NULL;
  477. }
  478. /* delete row index */
  479. if (mlp->p.ia != NULL)
  480. {
  481. GNUNET_free (mlp->p.ia);
  482. mlp->p.ia = NULL;
  483. }
  484. /* delete column index */
  485. if (mlp->p.ja != NULL)
  486. {
  487. GNUNET_free (mlp->p.ja);
  488. mlp->p.ja = NULL;
  489. }
  490. /* delete coefficients */
  491. if (mlp->p.ar != NULL)
  492. {
  493. GNUNET_free (mlp->p.ar);
  494. mlp->p.ar = NULL;
  495. }
  496. mlp->p.ci = 0;
  497. mlp->p.prob = NULL;
  498. mlp->p.c_d = MLP_UNDEFINED;
  499. mlp->p.c_r = MLP_UNDEFINED;
  500. mlp->p.r_c2 = MLP_UNDEFINED;
  501. mlp->p.r_c4 = MLP_UNDEFINED;
  502. mlp->p.r_c6 = MLP_UNDEFINED;
  503. mlp->p.r_c9 = MLP_UNDEFINED;
  504. for (c = 0; c < RQ_QUALITY_METRIC_COUNT ; c ++)
  505. mlp->p.r_q[c] = MLP_UNDEFINED;
  506. for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c ++)
  507. mlp->p.r_quota[c] = MLP_UNDEFINED;
  508. mlp->p.ci = MLP_UNDEFINED;
  509. GNUNET_CONTAINER_multipeermap_iterate (mlp->requested_peers,
  510. &reset_peers, NULL);
  511. }
  512. /**
  513. * Translate glpk status error codes to text
  514. * @param retcode return code
  515. * @return string with result
  516. */
  517. static const char *
  518. mlp_status_to_string (int retcode)
  519. {
  520. switch (retcode) {
  521. case GLP_UNDEF:
  522. return "solution is undefined";
  523. case GLP_FEAS:
  524. return "solution is feasible";
  525. case GLP_INFEAS:
  526. return "solution is infeasible";
  527. case GLP_NOFEAS:
  528. return "no feasible solution exists";
  529. case GLP_OPT:
  530. return "solution is optimal";
  531. case GLP_UNBND:
  532. return "solution is unbounded";
  533. default:
  534. GNUNET_break (0);
  535. return "unknown error";
  536. }
  537. }
  538. /**
  539. * Translate glpk solver error codes to text
  540. * @param retcode return code
  541. * @return string with result
  542. */
  543. static const char *
  544. mlp_solve_to_string (int retcode)
  545. {
  546. switch (retcode) {
  547. case 0:
  548. return "ok";
  549. case GLP_EBADB:
  550. return "invalid basis";
  551. case GLP_ESING:
  552. return "singular matrix";
  553. case GLP_ECOND:
  554. return "ill-conditioned matrix";
  555. case GLP_EBOUND:
  556. return "invalid bounds";
  557. case GLP_EFAIL:
  558. return "solver failed";
  559. case GLP_EOBJLL:
  560. return "objective lower limit reached";
  561. case GLP_EOBJUL:
  562. return "objective upper limit reached";
  563. case GLP_EITLIM:
  564. return "iteration limit exceeded";
  565. case GLP_ETMLIM:
  566. return "time limit exceeded";
  567. case GLP_ENOPFS:
  568. return "no primal feasible solution";
  569. case GLP_ENODFS:
  570. return "no dual feasible solution";
  571. case GLP_EROOT:
  572. return "root LP optimum not provided";
  573. case GLP_ESTOP:
  574. return "search terminated by application";
  575. case GLP_EMIPGAP:
  576. return "relative mip gap tolerance reached";
  577. case GLP_ENOFEAS:
  578. return "no dual feasible solution";
  579. case GLP_ENOCVG:
  580. return "no convergence";
  581. case GLP_EINSTAB:
  582. return "numerical instability";
  583. case GLP_EDATA:
  584. return "invalid data";
  585. case GLP_ERANGE:
  586. return "result out of range";
  587. default:
  588. GNUNET_break (0);
  589. return "unknown error";
  590. }
  591. }
  592. struct CountContext
  593. {
  594. const struct GNUNET_CONTAINER_MultiPeerMap *map;
  595. int result;
  596. };
  597. static int
  598. mlp_create_problem_count_addresses_it (void *cls,
  599. const struct GNUNET_PeerIdentity *key,
  600. void *value)
  601. {
  602. struct CountContext *cctx = cls;
  603. /* Check if we have to add this peer due to a pending request */
  604. if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (cctx->map, key))
  605. cctx->result++;
  606. return GNUNET_OK;
  607. }
  608. static int
  609. mlp_create_problem_count_addresses (const struct GNUNET_CONTAINER_MultiPeerMap *requested_peers,
  610. const struct GNUNET_CONTAINER_MultiPeerMap *addresses)
  611. {
  612. struct CountContext cctx;
  613. cctx.map = requested_peers;
  614. cctx.result = 0;
  615. GNUNET_CONTAINER_multipeermap_iterate (addresses,
  616. &mlp_create_problem_count_addresses_it, &cctx);
  617. return cctx.result;
  618. }
  619. static int
  620. mlp_create_problem_count_peers_it (void *cls,
  621. const struct GNUNET_PeerIdentity *key,
  622. void *value)
  623. {
  624. struct CountContext *cctx = cls;
  625. /* Check if we have to addresses for the requested peer */
  626. if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (cctx->map, key))
  627. cctx->result++;
  628. return GNUNET_OK;
  629. }
  630. static int
  631. mlp_create_problem_count_peers (const struct GNUNET_CONTAINER_MultiPeerMap *requested_peers,
  632. const struct GNUNET_CONTAINER_MultiPeerMap *addresses)
  633. {
  634. struct CountContext cctx;
  635. cctx.map = addresses;
  636. cctx.result = 0;
  637. GNUNET_CONTAINER_multipeermap_iterate (requested_peers,
  638. &mlp_create_problem_count_peers_it, &cctx);
  639. return cctx.result;
  640. }
  641. /**
  642. * Updates an existing value in the matrix
  643. *
  644. * Extract the row, updates the value and updates the row in the problem
  645. *
  646. * @param p the mlp problem
  647. * @param row the row to create the value in
  648. * @param col the column to create the value in
  649. * @param val the value to set
  650. * @param line calling line for debbuging
  651. * @return GNUNET_YES value changed, GNUNET_NO value did not change, GNUNET_SYSERR
  652. * on error
  653. */
  654. static int
  655. mlp_create_problem_update_value (struct MLP_Problem *p,
  656. int row, int col, double val,
  657. int line)
  658. {
  659. int c_cols;
  660. int c_elems;
  661. int c1;
  662. int res;
  663. int found;
  664. double *val_array;
  665. int *ind_array;
  666. GNUNET_assert (NULL != p);
  667. GNUNET_assert (NULL != p->prob);
  668. /* Get number of columns and prepare data structure */
  669. c_cols = glp_get_num_cols(p->prob);
  670. if (0 >= c_cols)
  671. return GNUNET_SYSERR;
  672. val_array = GNUNET_malloc ((c_cols +1)* sizeof (double));
  673. GNUNET_assert (NULL != val_array);
  674. ind_array = GNUNET_malloc ((c_cols+1) * sizeof (int));
  675. GNUNET_assert (NULL != ind_array);
  676. /* Extract the row */
  677. /* Update the value */
  678. c_elems = glp_get_mat_row (p->prob, row, ind_array, val_array);
  679. found = GNUNET_NO;
  680. for (c1 = 1; c1 < (c_elems+1); c1++)
  681. {
  682. if (ind_array[c1] == col)
  683. {
  684. found = GNUNET_YES;
  685. break;
  686. }
  687. }
  688. if (GNUNET_NO == found)
  689. {
  690. ind_array[c_elems+1] = col;
  691. val_array[c_elems+1] = val;
  692. LOG (GNUNET_ERROR_TYPE_DEBUG, "[P] Setting value in [%s : %s] to `%.2f'\n",
  693. glp_get_row_name (p->prob, row), glp_get_col_name (p->prob, col),
  694. val);
  695. glp_set_mat_row (p->prob, row, c_elems+1, ind_array, val_array);
  696. GNUNET_free (ind_array);
  697. GNUNET_free (val_array);
  698. return GNUNET_YES;
  699. }
  700. else
  701. {
  702. /* Update value */
  703. LOG (GNUNET_ERROR_TYPE_DEBUG, "[P] Updating value in [%s : %s] from `%.2f' to `%.2f'\n",
  704. glp_get_row_name (p->prob, row), glp_get_col_name (p->prob, col),
  705. val_array[c1], val);
  706. if (val != val_array[c1])
  707. res = GNUNET_YES;
  708. else
  709. res = GNUNET_NO;
  710. val_array[c1] = val;
  711. /* Update the row in the matrix */
  712. glp_set_mat_row (p->prob, row, c_elems, ind_array, val_array);
  713. }
  714. GNUNET_free (ind_array);
  715. GNUNET_free (val_array);
  716. return res;
  717. }
  718. /**
  719. * Creates a new value in the matrix
  720. *
  721. * Sets the row and column index in the problem array and increments the
  722. * position field
  723. *
  724. * @param p the mlp problem
  725. * @param row the row to create the value in
  726. * @param col the column to create the value in
  727. * @param val the value to set
  728. * @param line calling line for debbuging
  729. */
  730. static void
  731. mlp_create_problem_set_value (struct MLP_Problem *p,
  732. int row, int col, double val,
  733. int line)
  734. {
  735. if ((p->ci) >= p->num_elements)
  736. {
  737. LOG (GNUNET_ERROR_TYPE_DEBUG, "[P]: line %u: Request for index %u bigger than array size of %u\n",
  738. line, p->ci + 1, p->num_elements);
  739. GNUNET_break (0);
  740. return;
  741. }
  742. if ((0 == row) || (0 == col))
  743. {
  744. GNUNET_break (0);
  745. LOG (GNUNET_ERROR_TYPE_ERROR, "[P]: Invalid call from line %u: row = %u, col = %u\n",
  746. line, row, col);
  747. }
  748. p->ia[p->ci] = row ;
  749. p->ja[p->ci] = col;
  750. p->ar[p->ci] = val;
  751. #if DEBUG_MLP_PROBLEM_CREATION
  752. LOG (GNUNET_ERROR_TYPE_DEBUG, "[P]: line %u: Set value [%u,%u] in index %u == %.2f\n",
  753. line, p->ia[p->ci], p->ja[p->ci], p->ci, p->ar[p->ci]);
  754. #endif
  755. p->ci++;
  756. }
  757. static int
  758. mlp_create_problem_create_column (struct MLP_Problem *p, char *name,
  759. unsigned int type, unsigned int bound, double lb, double ub,
  760. double coef)
  761. {
  762. int col = glp_add_cols (p->prob, 1);
  763. glp_set_col_name (p->prob, col, name);
  764. glp_set_col_bnds (p->prob, col, bound, lb, ub);
  765. glp_set_col_kind (p->prob, col, type);
  766. glp_set_obj_coef (p->prob, col, coef);
  767. #if DEBUG_MLP_PROBLEM_CREATION
  768. LOG (GNUNET_ERROR_TYPE_DEBUG, "[P]: Added column [%u] `%s': %.2f\n",
  769. col, name, coef);
  770. #endif
  771. return col;
  772. }
  773. static int
  774. mlp_create_problem_create_constraint (struct MLP_Problem *p, char *name,
  775. unsigned int bound, double lb, double ub)
  776. {
  777. char * op;
  778. int row = glp_add_rows (p->prob, 1);
  779. /* set row name */
  780. glp_set_row_name (p->prob, row, name);
  781. /* set row bounds: <= 0 */
  782. glp_set_row_bnds (p->prob, row, bound, lb, ub);
  783. switch (bound)
  784. {
  785. case GLP_UP:
  786. GNUNET_asprintf(&op, "-inf <= x <= %.2f", ub);
  787. break;
  788. case GLP_DB:
  789. GNUNET_asprintf(&op, "%.2f <= x <= %.2f", lb, ub);
  790. break;
  791. case GLP_FX:
  792. GNUNET_asprintf(&op, "%.2f == x == %.2f", lb, ub);
  793. break;
  794. case GLP_LO:
  795. GNUNET_asprintf(&op, "%.2f <= x <= inf", lb);
  796. break;
  797. default:
  798. GNUNET_asprintf(&op, "ERROR");
  799. break;
  800. }
  801. #if DEBUG_MLP_PROBLEM_CREATION
  802. LOG (GNUNET_ERROR_TYPE_DEBUG, "[P]: Added row [%u] `%s': %s\n",
  803. row, name, op);
  804. #endif
  805. GNUNET_free (op);
  806. return row;
  807. }
  808. /**
  809. * Create the
  810. * - address columns b and n
  811. * - address dependent constraint rows c1, c3
  812. * - peer dependent rows c2 and c9
  813. * - Set address dependent entries in problem matrix as well
  814. */
  815. static int
  816. mlp_create_problem_add_address_information (void *cls,
  817. const struct GNUNET_PeerIdentity *key,
  818. void *value)
  819. {
  820. struct GAS_MLP_Handle *mlp = cls;
  821. struct MLP_Problem *p = &mlp->p;
  822. struct ATS_Address *address = value;
  823. struct ATS_Peer *peer;
  824. struct MLP_information *mlpi;
  825. char *name;
  826. double cur_bigm;
  827. uint32_t addr_net;
  828. uint32_t addr_net_index;
  829. unsigned long long max_quota;
  830. int c;
  831. /* Check if we have to add this peer due to a pending request */
  832. if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains(mlp->requested_peers, key))
  833. return GNUNET_OK;
  834. mlpi = address->solver_information;
  835. if (NULL == mlpi)
  836. {
  837. fprintf (stderr, "%s %p\n",GNUNET_i2s (&address->peer), address);
  838. GNUNET_break (0);
  839. return GNUNET_OK;
  840. }
  841. addr_net = address->properties.scope;
  842. for (addr_net_index = 0; addr_net_index < GNUNET_ATS_NetworkTypeCount; addr_net_index++)
  843. {
  844. if (mlp->pv.quota_index[addr_net_index] == addr_net)
  845. break;
  846. }
  847. if (addr_net_index >= GNUNET_ATS_NetworkTypeCount)
  848. {
  849. GNUNET_break (0);
  850. return GNUNET_OK;
  851. }
  852. max_quota = 0;
  853. for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
  854. {
  855. if (mlp->pv.quota_out[c] > max_quota)
  856. max_quota = mlp->pv.quota_out[c];
  857. if (mlp->pv.quota_in[c] > max_quota)
  858. max_quota = mlp->pv.quota_in[c];
  859. }
  860. if (max_quota > mlp->pv.BIG_M)
  861. cur_bigm = (double) mlp->pv.BIG_M;
  862. else
  863. cur_bigm = max_quota;
  864. /* Get peer */
  865. peer = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers, key);
  866. GNUNET_assert (NULL != peer);
  867. if (peer->processed == GNUNET_NO)
  868. {
  869. /* Add peer dependent constraints */
  870. /* Add c2) One address active per peer */
  871. GNUNET_asprintf(&name, "c2_%s", GNUNET_i2s(&address->peer));
  872. peer->r_c2 = mlp_create_problem_create_constraint (p, name, GLP_FX, 1.0, 1.0);
  873. GNUNET_free (name);
  874. if (GNUNET_NO == mlp->opt_dbg_feasibility_only)
  875. {
  876. if (GNUNET_YES == mlp->opt_dbg_optimize_relativity)
  877. {
  878. /* Add c9) Relativity */
  879. GNUNET_asprintf(&name, "c9_%s", GNUNET_i2s(&address->peer));
  880. peer->r_c9 = mlp_create_problem_create_constraint (p, name, GLP_LO, 0.0, 0.0);
  881. GNUNET_free (name);
  882. /* c9) set coefficient */
  883. mlp_create_problem_set_value (p, peer->r_c9, p->c_r, -peer->f , __LINE__);
  884. }
  885. }
  886. peer->processed = GNUNET_YES;
  887. }
  888. /* Reset addresses' solver information */
  889. mlpi->c_b = 0;
  890. mlpi->c_n = 0;
  891. mlpi->n = 0;
  892. mlpi->r_c1 = 0;
  893. mlpi->r_c3 = 0;
  894. /* Add bandwidth column */
  895. GNUNET_asprintf (&name, "b_%s_%s_%p", GNUNET_i2s (&address->peer), address->plugin, address);
  896. if (GNUNET_NO == mlp->opt_dbg_feasibility_only)
  897. {
  898. mlpi->c_b = mlp_create_problem_create_column (p, name, GLP_CV, GLP_LO, 0.0, 0.0, 0.0);
  899. }
  900. else
  901. {
  902. /* Maximize for bandwidth assignment in feasibility testing */
  903. mlpi->c_b = mlp_create_problem_create_column (p, name, GLP_CV, GLP_LO, 0.0, 0.0, 1.0);
  904. }
  905. GNUNET_free (name);
  906. /* Add address active column */
  907. GNUNET_asprintf (&name, "n_%s_%s_%p", GNUNET_i2s (&address->peer), address->plugin, address);
  908. mlpi->c_n = mlp_create_problem_create_column (p, name, GLP_IV, GLP_DB, 0.0, 1.0, 0.0);
  909. GNUNET_free (name);
  910. /* Add address dependent constraints */
  911. /* Add c1) bandwidth capping: b_t + (-M) * n_t <= 0 */
  912. GNUNET_asprintf(&name, "c1_%s_%s_%p", GNUNET_i2s(&address->peer), address->plugin, address);
  913. mlpi->r_c1 = mlp_create_problem_create_constraint (p, name, GLP_UP, 0.0, 0.0);
  914. GNUNET_free (name);
  915. /* c1) set b = 1 coefficient */
  916. mlp_create_problem_set_value (p, mlpi->r_c1, mlpi->c_b, 1, __LINE__);
  917. /* c1) set n = - min (M, quota) coefficient */
  918. cur_bigm = (double) mlp->pv.quota_out[addr_net_index];
  919. if (cur_bigm > mlp->pv.BIG_M)
  920. cur_bigm = (double) mlp->pv.BIG_M;
  921. mlp_create_problem_set_value (p, mlpi->r_c1, mlpi->c_n, -cur_bigm, __LINE__);
  922. /* Add constraint c 3) minimum bandwidth
  923. * b_t + (-n_t * b_min) >= 0
  924. * */
  925. GNUNET_asprintf(&name, "c3_%s_%s_%p", GNUNET_i2s(&address->peer), address->plugin, address);
  926. mlpi->r_c3 = mlp_create_problem_create_constraint (p, name, GLP_LO, 0.0, 0.0);
  927. GNUNET_free (name);
  928. /* c3) set b = 1 coefficient */
  929. mlp_create_problem_set_value (p, mlpi->r_c3, mlpi->c_b, 1, __LINE__);
  930. /* c3) set n = -b_min coefficient */
  931. mlp_create_problem_set_value (p, mlpi->r_c3, mlpi->c_n, - ((double )mlp->pv.b_min), __LINE__);
  932. /* Set coefficient entries in invariant rows */
  933. /* Feasbility */
  934. /* c 4) minimum connections */
  935. mlp_create_problem_set_value (p, p->r_c4, mlpi->c_n, 1, __LINE__);
  936. /* c 2) 1 address peer peer */
  937. mlp_create_problem_set_value (p, peer->r_c2, mlpi->c_n, 1, __LINE__);
  938. /* c 10) obey network specific quotas
  939. * (1)*b_1 + ... + (1)*b_m <= quota_n
  940. */
  941. mlp_create_problem_set_value (p, p->r_quota[addr_net_index], mlpi->c_b, 1, __LINE__);
  942. /* Optimality */
  943. if (GNUNET_NO == mlp->opt_dbg_feasibility_only)
  944. {
  945. /* c 6) maximize diversity */
  946. mlp_create_problem_set_value (p, p->r_c6, mlpi->c_n, 1, __LINE__);
  947. /* c 9) relativity */
  948. if (GNUNET_YES == mlp->opt_dbg_optimize_relativity)
  949. mlp_create_problem_set_value (p, peer->r_c9, mlpi->c_b, 1, __LINE__);
  950. /* c 8) utility */
  951. if (GNUNET_YES == mlp->opt_dbg_optimize_utility)
  952. mlp_create_problem_set_value (p, p->r_c8, mlpi->c_b, 1, __LINE__);
  953. /* c 7) Optimize quality */
  954. /* For all quality metrics, set quality of this address */
  955. if (GNUNET_YES == mlp->opt_dbg_optimize_quality)
  956. {
  957. mlp_create_problem_set_value (p,
  958. p->r_q[RQ_QUALITY_METRIC_DELAY],
  959. mlpi->c_b,
  960. address->norm_delay.norm,
  961. __LINE__);
  962. mlp_create_problem_set_value (p,
  963. p->r_q[RQ_QUALITY_METRIC_DISTANCE],
  964. mlpi->c_b,
  965. address->norm_distance.norm,
  966. __LINE__);
  967. }
  968. }
  969. return GNUNET_OK;
  970. }
  971. /**
  972. * Create the invariant columns c4, c6, c10, c8, c7
  973. */
  974. static void
  975. mlp_create_problem_add_invariant_rows (struct GAS_MLP_Handle *mlp, struct MLP_Problem *p)
  976. {
  977. int c;
  978. /* Feasibility */
  979. /* Row for c4) minimum connection */
  980. /* Number of minimum connections is min(|Peers|, n_min) */
  981. p->r_c4 = mlp_create_problem_create_constraint (p, "c4", GLP_LO, (mlp->pv.n_min > p->num_peers) ? p->num_peers : mlp->pv.n_min, 0.0);
  982. /* Rows for c 10) Enforce network quotas */
  983. for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
  984. {
  985. char * text;
  986. GNUNET_asprintf(&text, "c10_quota_ats_%s",
  987. GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]));
  988. p->r_quota[c] = mlp_create_problem_create_constraint (p, text, GLP_DB, 0.0, mlp->pv.quota_out[c]);
  989. GNUNET_free (text);
  990. }
  991. /* Optimality */
  992. if (GNUNET_NO == mlp->opt_dbg_feasibility_only)
  993. {
  994. char *name;
  995. /* Add row for c6) Maximize for diversity */
  996. if (GNUNET_YES == mlp->opt_dbg_optimize_diversity)
  997. {
  998. p->r_c6 = mlp_create_problem_create_constraint (p, "c6", GLP_FX, 0.0, 0.0);
  999. /* Set c6 ) Setting -D */
  1000. mlp_create_problem_set_value (p, p->r_c6, p->c_d, -1, __LINE__);
  1001. }
  1002. /* Adding rows for c 8) Maximize utility */
  1003. if (GNUNET_YES == mlp->opt_dbg_optimize_utility)
  1004. {
  1005. p->r_c8 = mlp_create_problem_create_constraint (p, "c8", GLP_FX, 0.0, 0.0);
  1006. /* -u */
  1007. mlp_create_problem_set_value (p, p->r_c8, p->c_u, -1, __LINE__);
  1008. }
  1009. /* For all quality metrics:
  1010. * c 7) Maximize quality, austerity */
  1011. if (GNUNET_YES == mlp->opt_dbg_optimize_quality)
  1012. {
  1013. for (c = 0; c < mlp->pv.m_q; c++)
  1014. {
  1015. GNUNET_asprintf (&name,
  1016. "c7_q%i_%s", c,
  1017. print_quality_type (c));
  1018. p->r_q[c] = mlp_create_problem_create_constraint (p, name, GLP_FX, 0.0, 0.0);
  1019. GNUNET_free (name);
  1020. mlp_create_problem_set_value (p,
  1021. p->r_q[c],
  1022. p->c_q[c], -1, __LINE__);
  1023. }
  1024. }
  1025. }
  1026. }
  1027. /**
  1028. * Create the invariant columns d, u, r, q0 ... qm
  1029. */
  1030. static void
  1031. mlp_create_problem_add_invariant_columns (struct GAS_MLP_Handle *mlp, struct MLP_Problem *p)
  1032. {
  1033. if (GNUNET_NO == mlp->opt_dbg_feasibility_only)
  1034. {
  1035. char *name;
  1036. int c;
  1037. /* Diversity d column */
  1038. if (GNUNET_YES == mlp->opt_dbg_optimize_diversity)
  1039. p->c_d = mlp_create_problem_create_column (p, "d", GLP_CV, GLP_LO, 0.0, 0.0, mlp->pv.co_D);
  1040. /* Utilization u column */
  1041. if (GNUNET_YES == mlp->opt_dbg_optimize_utility)
  1042. p->c_u = mlp_create_problem_create_column (p, "u", GLP_CV, GLP_LO, 0.0, 0.0, mlp->pv.co_U);
  1043. /* Relativity r column */
  1044. if (GNUNET_YES == mlp->opt_dbg_optimize_relativity)
  1045. p->c_r = mlp_create_problem_create_column (p, "r", GLP_CV, GLP_LO, 0.0, 0.0, mlp->pv.co_R);
  1046. /* Quality metric columns */
  1047. if (GNUNET_YES == mlp->opt_dbg_optimize_quality)
  1048. {
  1049. for (c = 0; c < mlp->pv.m_q; c++)
  1050. {
  1051. GNUNET_asprintf (&name, "q_%u", c);
  1052. p->c_q[c] = mlp_create_problem_create_column (p, name, GLP_CV, GLP_LO, 0.0, 0.0, mlp->pv.co_Q[c]);
  1053. GNUNET_free (name);
  1054. }
  1055. }
  1056. }
  1057. }
  1058. /**
  1059. * Create the MLP problem
  1060. *
  1061. * @param mlp the MLP handle
  1062. * @return #GNUNET_OK or #GNUNET_SYSERR
  1063. */
  1064. static int
  1065. mlp_create_problem (struct GAS_MLP_Handle *mlp)
  1066. {
  1067. struct MLP_Problem *p = &mlp->p;
  1068. int res = GNUNET_OK;
  1069. GNUNET_assert (p->prob == NULL);
  1070. GNUNET_assert (p->ia == NULL);
  1071. GNUNET_assert (p->ja == NULL);
  1072. GNUNET_assert (p->ar == NULL);
  1073. /* Reset MLP problem struct */
  1074. /* create the glpk problem */
  1075. p->prob = glp_create_prob ();
  1076. GNUNET_assert (NULL != p->prob);
  1077. p->num_peers = mlp_create_problem_count_peers (mlp->requested_peers, mlp->env->addresses);
  1078. p->num_addresses = mlp_create_problem_count_addresses (mlp->requested_peers,
  1079. mlp->env->addresses);
  1080. /* Create problem matrix: 10 * #addresses + #q * #addresses + #q, + #peer + 2 + 1 */
  1081. p->num_elements = (10 * p->num_addresses + mlp->pv.m_q * p->num_addresses +
  1082. mlp->pv.m_q + p->num_peers + 2 + 1);
  1083. LOG (GNUNET_ERROR_TYPE_DEBUG,
  1084. "Rebuilding problem for %u peer(s) and %u addresse(s) and %u quality metrics == %u elements\n",
  1085. p->num_peers,
  1086. p->num_addresses,
  1087. mlp->pv.m_q,
  1088. p->num_elements);
  1089. /* Set a problem name */
  1090. glp_set_prob_name (p->prob, "GNUnet ATS bandwidth distribution");
  1091. /* Set optimization direction to maximize */
  1092. glp_set_obj_dir (p->prob, GLP_MAX);
  1093. /* Create problem matrix */
  1094. /* last +1 caused by glpk index starting with one: [1..elements]*/
  1095. p->ci = 1;
  1096. /* row index */
  1097. p->ia = GNUNET_malloc (p->num_elements * sizeof (int));
  1098. /* column index */
  1099. p->ja = GNUNET_malloc (p->num_elements * sizeof (int));
  1100. /* coefficient */
  1101. p->ar = GNUNET_malloc (p->num_elements * sizeof (double));
  1102. if ((NULL == p->ia) || (NULL == p->ja) || (NULL == p->ar))
  1103. {
  1104. LOG (GNUNET_ERROR_TYPE_ERROR, _("Problem size too large, cannot allocate memory!\n"));
  1105. return GNUNET_SYSERR;
  1106. }
  1107. /* Adding invariant columns */
  1108. mlp_create_problem_add_invariant_columns (mlp, p);
  1109. /* Adding address independent constraint rows */
  1110. mlp_create_problem_add_invariant_rows (mlp, p);
  1111. /* Adding address dependent columns constraint rows */
  1112. GNUNET_CONTAINER_multipeermap_iterate (mlp->env->addresses,
  1113. &mlp_create_problem_add_address_information,
  1114. mlp);
  1115. /* Load the matrix */
  1116. LOG (GNUNET_ERROR_TYPE_DEBUG, "Loading matrix\n");
  1117. glp_load_matrix(p->prob, (p->ci)-1, p->ia, p->ja, p->ar);
  1118. if (GNUNET_YES == mlp->opt_dbg_autoscale_problem)
  1119. {
  1120. glp_scale_prob (p->prob, GLP_SF_AUTO);
  1121. }
  1122. return res;
  1123. }
  1124. /**
  1125. * Solves the LP problem
  1126. *
  1127. * @param mlp the MLP Handle
  1128. * @return #GNUNET_OK if could be solved, #GNUNET_SYSERR on failure
  1129. */
  1130. static int
  1131. mlp_solve_lp_problem (struct GAS_MLP_Handle *mlp)
  1132. {
  1133. int res = 0;
  1134. int res_status = 0;
  1135. res = glp_simplex(mlp->p.prob, &mlp->control_param_lp);
  1136. if (0 == res)
  1137. LOG(GNUNET_ERROR_TYPE_DEBUG, "Solving LP problem: %s\n",
  1138. mlp_solve_to_string (res));
  1139. else
  1140. LOG(GNUNET_ERROR_TYPE_DEBUG, "Solving LP problem failed: %s\n",
  1141. mlp_solve_to_string (res));
  1142. /* Analyze problem status */
  1143. res_status = glp_get_status (mlp->p.prob);
  1144. switch (res_status) {
  1145. case GLP_OPT: /* solution is optimal */
  1146. LOG (GNUNET_ERROR_TYPE_INFO,
  1147. "Solving LP problem: %s, %s\n",
  1148. mlp_solve_to_string(res),
  1149. mlp_status_to_string(res_status));
  1150. return GNUNET_OK;
  1151. default:
  1152. LOG (GNUNET_ERROR_TYPE_ERROR,
  1153. "Solving LP problem failed: %s %s\n",
  1154. mlp_solve_to_string(res),
  1155. mlp_status_to_string(res_status));
  1156. return GNUNET_SYSERR;
  1157. }
  1158. }
  1159. /**
  1160. * Propagates the results when MLP problem was solved
  1161. *
  1162. * @param cls the MLP handle
  1163. * @param key the peer identity
  1164. * @param value the address
  1165. * @return #GNUNET_OK to continue
  1166. */
  1167. static int
  1168. mlp_propagate_results (void *cls,
  1169. const struct GNUNET_PeerIdentity *key,
  1170. void *value)
  1171. {
  1172. struct GAS_MLP_Handle *mlp = cls;
  1173. struct ATS_Address *address;
  1174. struct MLP_information *mlpi;
  1175. double mlp_bw_in = MLP_NaN;
  1176. double mlp_bw_out = MLP_NaN;
  1177. double mlp_use = MLP_NaN;
  1178. /* Check if we have to add this peer due to a pending request */
  1179. if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (mlp->requested_peers,
  1180. key))
  1181. {
  1182. return GNUNET_OK;
  1183. }
  1184. address = value;
  1185. GNUNET_assert (address->solver_information != NULL);
  1186. mlpi = address->solver_information;
  1187. mlp_bw_in = glp_mip_col_val(mlp->p.prob, mlpi->c_b);/* FIXME */
  1188. if (mlp_bw_in > (double) UINT32_MAX)
  1189. {
  1190. LOG (GNUNET_ERROR_TYPE_DEBUG, "Overflow in assigned bandwidth, reducing ...\n" );
  1191. mlp_bw_in = (double) UINT32_MAX;
  1192. }
  1193. mlp_bw_out = glp_mip_col_val(mlp->p.prob, mlpi->c_b);
  1194. if (mlp_bw_out > (double) UINT32_MAX)
  1195. {
  1196. LOG (GNUNET_ERROR_TYPE_DEBUG, "Overflow in assigned bandwidth, reducing ...\n" );
  1197. mlp_bw_out = (double) UINT32_MAX;
  1198. }
  1199. mlp_use = glp_mip_col_val(mlp->p.prob, mlpi->c_n);
  1200. /*
  1201. * Debug: solution
  1202. * LOG (GNUNET_ERROR_TYPE_INFO, "MLP result address: `%s' `%s' length %u session %u, mlp use %.3f\n",
  1203. * GNUNET_i2s(&address->peer), address->plugin,
  1204. * address->addr_len, address->session_id);
  1205. */
  1206. if (GLP_YES == mlp_use)
  1207. {
  1208. /* This address was selected by the solver to be used */
  1209. mlpi->n = GNUNET_YES;
  1210. if (GNUNET_NO == address->active)
  1211. {
  1212. /* Address was not used before, enabling address */
  1213. LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : enabling address\n",
  1214. (1 == mlp_use) ? "[x]": "[ ]", mlp_bw_out);
  1215. address->active = GNUNET_YES;
  1216. address->assigned_bw_in = mlp_bw_in;
  1217. mlpi->b_in = mlp_bw_in;
  1218. address->assigned_bw_out = mlp_bw_out;
  1219. mlpi->b_out = mlp_bw_out;
  1220. if ((NULL == mlp->exclude_peer) || (0 != memcmp (&address->peer, mlp->exclude_peer, sizeof (address->peer))))
  1221. mlp->env->bandwidth_changed_cb (mlp->env->cls, address);
  1222. return GNUNET_OK;
  1223. }
  1224. else if (GNUNET_YES == address->active)
  1225. {
  1226. /* Address was used before, check for bandwidth change */
  1227. if ((mlp_bw_out != address->assigned_bw_out) ||
  1228. (mlp_bw_in != address->assigned_bw_in))
  1229. {
  1230. LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : bandwidth changed\n",
  1231. (1 == mlp_use) ? "[x]": "[ ]", mlp_bw_out);
  1232. address->assigned_bw_in = mlp_bw_in;
  1233. mlpi->b_in = mlp_bw_in;
  1234. address->assigned_bw_out = mlp_bw_out;
  1235. mlpi->b_out = mlp_bw_out;
  1236. if ((NULL == mlp->exclude_peer) || (0 != memcmp (&address->peer, mlp->exclude_peer, sizeof (address->peer))))
  1237. mlp->env->bandwidth_changed_cb (mlp->env->cls, address);
  1238. return GNUNET_OK;
  1239. }
  1240. }
  1241. else
  1242. GNUNET_break (0);
  1243. }
  1244. else if (GLP_NO == mlp_use)
  1245. {
  1246. /* This address was selected by the solver to be not used */
  1247. mlpi->n = GNUNET_NO;
  1248. if (GNUNET_NO == address->active)
  1249. {
  1250. /* Address was not used before, nothing to do */
  1251. LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : no change\n",
  1252. (1 == mlp_use) ? "[x]": "[ ]", mlp_bw_out);
  1253. return GNUNET_OK;
  1254. }
  1255. else if (GNUNET_YES == address->active)
  1256. {
  1257. /* Address was used before, disabling address */
  1258. LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : disabling address\n",
  1259. (1 == mlp_use) ? "[x]": "[ ]", mlp_bw_out);
  1260. address->active = GNUNET_NO;
  1261. /* Set bandwidth to 0 */
  1262. address->assigned_bw_in = 0;
  1263. mlpi->b_in = 0;
  1264. address->assigned_bw_out = 0;
  1265. mlpi->b_out = 0;
  1266. return GNUNET_OK;
  1267. }
  1268. else
  1269. GNUNET_break (0);
  1270. }
  1271. else
  1272. GNUNET_break (0);
  1273. return GNUNET_OK;
  1274. }
  1275. static void
  1276. notify (struct GAS_MLP_Handle *mlp,
  1277. enum GAS_Solver_Operation op,
  1278. enum GAS_Solver_Status stat,
  1279. enum GAS_Solver_Additional_Information add)
  1280. {
  1281. mlp->env->info_cb (mlp->env->cls,
  1282. op,
  1283. stat,
  1284. add);
  1285. }
  1286. static void
  1287. mlp_branch_and_cut_cb (glp_tree *tree, void *info)
  1288. {
  1289. struct GAS_MLP_Handle *mlp = info;
  1290. double mlp_obj = 0;
  1291. switch (glp_ios_reason (tree))
  1292. {
  1293. case GLP_ISELECT:
  1294. /* Do nothing here */
  1295. break;
  1296. case GLP_IPREPRO:
  1297. /* Do nothing here */
  1298. break;
  1299. case GLP_IROWGEN:
  1300. /* Do nothing here */
  1301. break;
  1302. case GLP_IHEUR:
  1303. /* Do nothing here */
  1304. break;
  1305. case GLP_ICUTGEN:
  1306. /* Do nothing here */
  1307. break;
  1308. case GLP_IBRANCH:
  1309. /* Do nothing here */
  1310. break;
  1311. case GLP_IBINGO:
  1312. /* A better solution was found */
  1313. mlp->ps.mlp_gap = glp_ios_mip_gap (tree);
  1314. mlp_obj = glp_mip_obj_val (mlp->p.prob);
  1315. mlp->ps.lp_mlp_gap = (abs(mlp_obj - mlp->ps.lp_objective_value)) / (abs(mlp_obj) + DBL_EPSILON);
  1316. LOG (GNUNET_ERROR_TYPE_INFO,
  1317. "Found better integer solution, current gaps: %.3f <= %.3f, %.3f <= %.3f\n",
  1318. mlp->ps.mlp_gap, mlp->pv.mip_gap,
  1319. mlp->ps.lp_mlp_gap, mlp->pv.lp_mip_gap);
  1320. if (mlp->ps.mlp_gap <= mlp->pv.mip_gap)
  1321. {
  1322. LOG (GNUNET_ERROR_TYPE_INFO,
  1323. "Current LP/MLP gap of %.3f smaller than tolerated gap of %.3f, terminating search\n",
  1324. mlp->ps.lp_mlp_gap, mlp->pv.lp_mip_gap);
  1325. glp_ios_terminate (tree);
  1326. }
  1327. if (mlp->ps.lp_mlp_gap <= mlp->pv.lp_mip_gap)
  1328. {
  1329. LOG (GNUNET_ERROR_TYPE_INFO,
  1330. "Current LP/MLP gap of %.3f smaller than tolerated gap of %.3f, terminating search\n",
  1331. mlp->ps.lp_mlp_gap, mlp->pv.lp_mip_gap);
  1332. glp_ios_terminate (tree);
  1333. }
  1334. break;
  1335. default:
  1336. break;
  1337. }
  1338. //GNUNET_break (0);
  1339. }
  1340. /**
  1341. * Solves the MLP problem
  1342. *
  1343. * @param solver the MLP Handle
  1344. * @return #GNUNET_OK if could be solved, #GNUNET_SYSERR on failure
  1345. */
  1346. static int
  1347. GAS_mlp_solve_problem (void *solver)
  1348. {
  1349. struct GAS_MLP_Handle *mlp = solver;
  1350. char *filename;
  1351. int res_lp = 0;
  1352. int mip_res = 0;
  1353. int mip_status = 0;
  1354. struct GNUNET_TIME_Absolute start_total;
  1355. struct GNUNET_TIME_Absolute start_cur_op;
  1356. struct GNUNET_TIME_Relative dur_total;
  1357. struct GNUNET_TIME_Relative dur_setup;
  1358. struct GNUNET_TIME_Relative dur_lp;
  1359. struct GNUNET_TIME_Relative dur_mlp;
  1360. GNUNET_assert(NULL != solver);
  1361. if (GNUNET_YES == mlp->stat_bulk_lock)
  1362. {
  1363. mlp->stat_bulk_requests++;
  1364. return GNUNET_NO;
  1365. }
  1366. notify(mlp, GAS_OP_SOLVE_START, GAS_STAT_SUCCESS,
  1367. (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL : GAS_INFO_UPDATED);
  1368. start_total = GNUNET_TIME_absolute_get();
  1369. if (0 == GNUNET_CONTAINER_multipeermap_size(mlp->requested_peers))
  1370. {
  1371. notify(mlp, GAS_OP_SOLVE_STOP, GAS_STAT_SUCCESS, GAS_INFO_NONE);
  1372. return GNUNET_OK; /* No pending requests */
  1373. }
  1374. if (0 == GNUNET_CONTAINER_multipeermap_size(mlp->env->addresses))
  1375. {
  1376. notify(mlp, GAS_OP_SOLVE_STOP, GAS_STAT_SUCCESS, GAS_INFO_NONE);
  1377. return GNUNET_OK; /* No addresses available */
  1378. }
  1379. if ((GNUNET_NO == mlp->stat_mlp_prob_changed)
  1380. && (GNUNET_NO == mlp->stat_mlp_prob_updated))
  1381. {
  1382. LOG(GNUNET_ERROR_TYPE_DEBUG, "No changes to problem\n");
  1383. notify(mlp, GAS_OP_SOLVE_STOP, GAS_STAT_SUCCESS, GAS_INFO_NONE);
  1384. return GNUNET_OK;
  1385. }
  1386. if (GNUNET_YES == mlp->stat_mlp_prob_changed)
  1387. {
  1388. LOG(GNUNET_ERROR_TYPE_DEBUG, "Problem size changed, rebuilding\n");
  1389. notify(mlp, GAS_OP_SOLVE_SETUP_START, GAS_STAT_SUCCESS, GAS_INFO_FULL);
  1390. mlp_delete_problem(mlp);
  1391. if (GNUNET_SYSERR == mlp_create_problem(mlp))
  1392. {
  1393. notify(mlp, GAS_OP_SOLVE_SETUP_STOP, GAS_STAT_FAIL, GAS_INFO_FULL);
  1394. return GNUNET_SYSERR;
  1395. }
  1396. notify(mlp, GAS_OP_SOLVE_SETUP_STOP, GAS_STAT_SUCCESS, GAS_INFO_FULL);
  1397. if (GNUNET_NO == mlp->opt_dbg_intopt_presolver)
  1398. {
  1399. mlp->control_param_lp.presolve = GLP_YES; /* LP presolver, we need lp solution */
  1400. mlp->control_param_mlp.presolve = GNUNET_NO; /* No presolver, we have LP solution */
  1401. }
  1402. else
  1403. {
  1404. mlp->control_param_lp.presolve = GNUNET_NO; /* LP presolver, we need lp solution */
  1405. mlp->control_param_mlp.presolve = GLP_YES; /* No presolver, we have LP solution */
  1406. dur_lp = GNUNET_TIME_UNIT_ZERO;
  1407. }
  1408. }
  1409. else
  1410. {
  1411. LOG(GNUNET_ERROR_TYPE_DEBUG, "Problem was updated, resolving\n");
  1412. }
  1413. /* Reset solution info */
  1414. mlp->ps.lp_objective_value = 0.0;
  1415. mlp->ps.mlp_gap = 1.0;
  1416. mlp->ps.mlp_objective_value = 0.0;
  1417. mlp->ps.lp_mlp_gap = 0.0;
  1418. dur_setup = GNUNET_TIME_absolute_get_duration (start_total);
  1419. /* Run LP solver */
  1420. if (GNUNET_NO == mlp->opt_dbg_intopt_presolver)
  1421. {
  1422. notify(mlp, GAS_OP_SOLVE_MLP_LP_START, GAS_STAT_SUCCESS,
  1423. (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL : GAS_INFO_UPDATED);
  1424. LOG(GNUNET_ERROR_TYPE_DEBUG,
  1425. "Running LP solver %s\n",
  1426. (GLP_YES == mlp->control_param_lp.presolve)? "with presolver": "without presolver");
  1427. start_cur_op = GNUNET_TIME_absolute_get();
  1428. /* Solve LP */
  1429. /* Only for debugging:
  1430. * Always use LP presolver:
  1431. * mlp->control_param_lp.presolve = GLP_YES; */
  1432. res_lp = mlp_solve_lp_problem(mlp);
  1433. if (GNUNET_OK == res_lp)
  1434. {
  1435. mlp->ps.lp_objective_value = glp_get_obj_val (mlp->p.prob);
  1436. LOG (GNUNET_ERROR_TYPE_DEBUG,
  1437. "LP solution was: %.3f\n",
  1438. mlp->ps.lp_objective_value);
  1439. }
  1440. dur_lp = GNUNET_TIME_absolute_get_duration (start_cur_op);
  1441. notify(mlp, GAS_OP_SOLVE_MLP_LP_STOP,
  1442. (GNUNET_OK == res_lp) ? GAS_STAT_SUCCESS : GAS_STAT_FAIL,
  1443. (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL : GAS_INFO_UPDATED);
  1444. }
  1445. if (GNUNET_YES == mlp->opt_dbg_intopt_presolver)
  1446. res_lp = GNUNET_OK;
  1447. /* Run MLP solver */
  1448. if ((GNUNET_OK == res_lp) || (GNUNET_YES == mlp->opt_dbg_intopt_presolver))
  1449. {
  1450. LOG(GNUNET_ERROR_TYPE_DEBUG, "Running MLP solver \n");
  1451. notify(mlp, GAS_OP_SOLVE_MLP_MLP_START, GAS_STAT_SUCCESS,
  1452. (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL : GAS_INFO_UPDATED);
  1453. start_cur_op = GNUNET_TIME_absolute_get();
  1454. /* Solve MIP */
  1455. /* Only for debugging, always use LP presolver */
  1456. if (GNUNET_YES == mlp->opt_dbg_intopt_presolver)
  1457. mlp->control_param_mlp.presolve = GNUNET_YES;
  1458. mip_res = glp_intopt (mlp->p.prob, &mlp->control_param_mlp);
  1459. switch (mip_res)
  1460. {
  1461. case 0:
  1462. /* Successful */
  1463. LOG (GNUNET_ERROR_TYPE_INFO,
  1464. "Solving MLP problem: %s\n",
  1465. mlp_solve_to_string (mip_res));
  1466. break;
  1467. case GLP_ETMLIM: /* Time limit reached */
  1468. case GLP_EMIPGAP: /* MIP gap tolerance limit reached */
  1469. case GLP_ESTOP: /* Solver was instructed to stop*/
  1470. /* Semi-successful */
  1471. LOG (GNUNET_ERROR_TYPE_INFO,
  1472. "Solving MLP problem solution was interupted: %s\n",
  1473. mlp_solve_to_string (mip_res));
  1474. break;
  1475. case GLP_EBOUND:
  1476. case GLP_EROOT:
  1477. case GLP_ENOPFS:
  1478. case GLP_ENODFS:
  1479. case GLP_EFAIL:
  1480. default:
  1481. /* Fail */
  1482. LOG (GNUNET_ERROR_TYPE_INFO,
  1483. "Solving MLP problem failed: %s\n",
  1484. mlp_solve_to_string (mip_res));
  1485. break;
  1486. }
  1487. /* Analyze problem status */
  1488. mip_status = glp_mip_status(mlp->p.prob);
  1489. switch (mip_status)
  1490. {
  1491. case GLP_OPT: /* solution is optimal */
  1492. LOG (GNUNET_ERROR_TYPE_WARNING,
  1493. "Solution of MLP problem is optimal: %s, %s\n",
  1494. mlp_solve_to_string (mip_res),
  1495. mlp_status_to_string (mip_status));
  1496. mip_res = GNUNET_OK;
  1497. break;
  1498. case GLP_FEAS: /* solution is feasible but not proven optimal */
  1499. if ( (mlp->ps.mlp_gap <= mlp->pv.mip_gap) ||
  1500. (mlp->ps.lp_mlp_gap <= mlp->pv.lp_mip_gap) )
  1501. {
  1502. LOG (GNUNET_ERROR_TYPE_INFO,
  1503. "Solution of MLP problem is feasible and solution within gap constraints: %s, %s\n",
  1504. mlp_solve_to_string (mip_res),
  1505. mlp_status_to_string (mip_status));
  1506. mip_res = GNUNET_OK;
  1507. }
  1508. else
  1509. {
  1510. LOG (GNUNET_ERROR_TYPE_WARNING,
  1511. "Solution of MLP problem is feasible but solution not within gap constraints: %s, %s\n",
  1512. mlp_solve_to_string (mip_res),
  1513. mlp_status_to_string (mip_status));
  1514. mip_res = GNUNET_SYSERR;
  1515. }
  1516. break;
  1517. case GLP_UNDEF: /* Solution undefined */
  1518. case GLP_NOFEAS: /* No feasible solution */
  1519. default:
  1520. LOG (GNUNET_ERROR_TYPE_ERROR,
  1521. "Solving MLP problem failed: %s %s\n",
  1522. mlp_solve_to_string (mip_res),
  1523. mlp_status_to_string (mip_status));
  1524. mip_res = GNUNET_SYSERR;
  1525. break;
  1526. }
  1527. dur_mlp = GNUNET_TIME_absolute_get_duration (start_cur_op);
  1528. dur_total = GNUNET_TIME_absolute_get_duration (start_total);
  1529. notify(mlp, GAS_OP_SOLVE_MLP_MLP_STOP,
  1530. (GNUNET_OK == mip_res) ? GAS_STAT_SUCCESS : GAS_STAT_FAIL,
  1531. (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL : GAS_INFO_UPDATED);
  1532. }
  1533. else
  1534. {
  1535. /* Do not execute mip solver since lp solution is invalid */
  1536. dur_mlp = GNUNET_TIME_UNIT_ZERO;
  1537. dur_total = GNUNET_TIME_absolute_get_duration (start_total);
  1538. notify(mlp, GAS_OP_SOLVE_MLP_MLP_STOP, GAS_STAT_FAIL,
  1539. (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL : GAS_INFO_UPDATED);
  1540. mip_res = GNUNET_SYSERR;
  1541. }
  1542. /* Notify about end */
  1543. notify(mlp, GAS_OP_SOLVE_STOP,
  1544. ((GNUNET_OK == mip_res) && (GNUNET_OK == mip_res)) ? GAS_STAT_SUCCESS : GAS_STAT_FAIL,
  1545. (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL : GAS_INFO_UPDATED);
  1546. LOG (GNUNET_ERROR_TYPE_DEBUG,
  1547. "Execution time for %s solve: (total/setup/lp/mlp) : %llu %llu %llu %llu\n",
  1548. (GNUNET_YES == mlp->stat_mlp_prob_changed) ? "full" : "updated",
  1549. (unsigned long long) dur_total.rel_value_us,
  1550. (unsigned long long) dur_setup.rel_value_us,
  1551. (unsigned long long) dur_lp.rel_value_us,
  1552. (unsigned long long) dur_mlp.rel_value_us);
  1553. /* Save stats */
  1554. mlp->ps.lp_res = res_lp;
  1555. mlp->ps.mip_res = mip_res;
  1556. mlp->ps.lp_presolv = mlp->control_param_lp.presolve;
  1557. mlp->ps.mip_presolv = mlp->control_param_mlp.presolve;
  1558. mlp->ps.p_cols = glp_get_num_cols(mlp->p.prob);
  1559. mlp->ps.p_rows = glp_get_num_rows(mlp->p.prob);
  1560. mlp->ps.p_elements = mlp->p.num_elements;
  1561. /* Propagate result*/
  1562. notify (mlp, GAS_OP_SOLVE_UPDATE_NOTIFICATION_START,
  1563. (GNUNET_OK == res_lp) && (GNUNET_OK == mip_res) ? GAS_STAT_SUCCESS : GAS_STAT_FAIL,
  1564. GAS_INFO_NONE);
  1565. if ((GNUNET_OK == res_lp) && (GNUNET_OK == mip_res))
  1566. {
  1567. GNUNET_CONTAINER_multipeermap_iterate(mlp->env->addresses,
  1568. &mlp_propagate_results, mlp);
  1569. }
  1570. notify (mlp, GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP,
  1571. (GNUNET_OK == res_lp) && (GNUNET_OK == mip_res) ? GAS_STAT_SUCCESS : GAS_STAT_FAIL,
  1572. GAS_INFO_NONE);
  1573. struct GNUNET_TIME_Absolute time = GNUNET_TIME_absolute_get();
  1574. if ( (GNUNET_YES == mlp->opt_dump_problem_all) ||
  1575. (mlp->opt_dump_problem_on_fail && ((GNUNET_OK != res_lp) || (GNUNET_OK != mip_res))) )
  1576. {
  1577. /* Write problem to disk */
  1578. switch (mlp->opt_log_format) {
  1579. case MLP_CPLEX:
  1580. GNUNET_asprintf(&filename, "problem_p_%u_a%u_%llu.cplex", mlp->p.num_peers,
  1581. mlp->p.num_addresses, time.abs_value_us);
  1582. glp_write_lp (mlp->p.prob, NULL, filename);
  1583. break;
  1584. case MLP_GLPK:
  1585. GNUNET_asprintf(&filename, "problem_p_%u_a%u_%llu.glpk", mlp->p.num_peers,
  1586. mlp->p.num_addresses, time.abs_value_us);
  1587. glp_write_prob (mlp->p.prob, 0, filename);
  1588. break;
  1589. case MLP_MPS:
  1590. GNUNET_asprintf(&filename, "problem_p_%u_a%u_%llu.mps", mlp->p.num_peers,
  1591. mlp->p.num_addresses, time.abs_value_us);
  1592. glp_write_mps (mlp->p.prob, GLP_MPS_FILE, NULL, filename);
  1593. break;
  1594. default:
  1595. break;
  1596. }
  1597. LOG(GNUNET_ERROR_TYPE_ERROR, "Dumped problem to file: `%s' \n", filename);
  1598. GNUNET_free(filename);
  1599. }
  1600. if ( (mlp->opt_dump_solution_all) ||
  1601. (mlp->opt_dump_solution_on_fail && ((GNUNET_OK != res_lp) || (GNUNET_OK != mip_res))) )
  1602. {
  1603. /* Write solution to disk */
  1604. GNUNET_asprintf(&filename, "problem_p_%u_a%u_%llu.sol", mlp->p.num_peers,
  1605. mlp->p.num_addresses, time.abs_value_us);
  1606. glp_print_mip(mlp->p.prob, filename);
  1607. LOG(GNUNET_ERROR_TYPE_ERROR, "Dumped solution to file: `%s' \n", filename);
  1608. GNUNET_free(filename);
  1609. }
  1610. /* Reset change and update marker */
  1611. mlp->control_param_lp.presolve = GLP_NO;
  1612. mlp->stat_mlp_prob_updated = GNUNET_NO;
  1613. mlp->stat_mlp_prob_changed = GNUNET_NO;
  1614. if ((GNUNET_OK == res_lp) && (GNUNET_OK == mip_res))
  1615. return GNUNET_OK;
  1616. else
  1617. return GNUNET_SYSERR;
  1618. }
  1619. /**
  1620. * Add a single address to the solve
  1621. *
  1622. * @param solver the solver Handle
  1623. * @param address the address to add
  1624. * @param network network type of this address
  1625. */
  1626. static void
  1627. GAS_mlp_address_add (void *solver,
  1628. struct ATS_Address *address,
  1629. uint32_t network)
  1630. {
  1631. struct GAS_MLP_Handle *mlp = solver;
  1632. if (GNUNET_ATS_NetworkTypeCount <= network)
  1633. {
  1634. GNUNET_break (0);
  1635. return;
  1636. }
  1637. if (NULL == address->solver_information)
  1638. {
  1639. address->solver_information = GNUNET_new (struct MLP_information);
  1640. }
  1641. else
  1642. LOG (GNUNET_ERROR_TYPE_ERROR,
  1643. _("Adding address for peer `%s' multiple times\n"),
  1644. GNUNET_i2s(&address->peer));
  1645. /* Is this peer included in the problem? */
  1646. if (NULL ==
  1647. GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers,
  1648. &address->peer))
  1649. {
  1650. /* FIXME: should this be an error? */
  1651. LOG (GNUNET_ERROR_TYPE_DEBUG,
  1652. "Adding address for peer `%s' without address request\n",
  1653. GNUNET_i2s(&address->peer));
  1654. return;
  1655. }
  1656. LOG (GNUNET_ERROR_TYPE_DEBUG,
  1657. "Adding address for peer `%s' with address request \n",
  1658. GNUNET_i2s(&address->peer));
  1659. /* Problem size changed: new address for peer with pending request */
  1660. mlp->stat_mlp_prob_changed = GNUNET_YES;
  1661. if (GNUNET_YES == mlp->opt_mlp_auto_solve)
  1662. GAS_mlp_solve_problem (solver);
  1663. }
  1664. /**
  1665. * Transport properties for this address have changed
  1666. *
  1667. * @param solver solver handle
  1668. * @param address the address
  1669. */
  1670. static void
  1671. GAS_mlp_address_property_changed (void *solver,
  1672. struct ATS_Address *address)
  1673. {
  1674. struct MLP_information *mlpi = address->solver_information;
  1675. struct GAS_MLP_Handle *mlp = solver;
  1676. if (NULL == mlpi)
  1677. {
  1678. LOG (GNUNET_ERROR_TYPE_INFO,
  1679. _("Updating address property for peer `%s' %p not added before\n"),
  1680. GNUNET_i2s (&address->peer),
  1681. address);
  1682. GNUNET_break (0);
  1683. return;
  1684. }
  1685. if (NULL ==
  1686. GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers,
  1687. &address->peer))
  1688. {
  1689. /* Peer is not requested, so no need to update problem */
  1690. return;
  1691. }
  1692. LOG (GNUNET_ERROR_TYPE_DEBUG,
  1693. "Updating properties for peer `%s'\n",
  1694. GNUNET_i2s(&address->peer));
  1695. if (GNUNET_YES == mlp->opt_dbg_feasibility_only)
  1696. return;
  1697. /* Update c7) [r_q[index]][c_b] = f_q * q_averaged[type_index] */
  1698. if ( (GNUNET_YES ==
  1699. mlp_create_problem_update_value (&mlp->p,
  1700. mlp->p.r_q[RQ_QUALITY_METRIC_DELAY],
  1701. mlpi->c_b,
  1702. address->norm_delay.norm,
  1703. __LINE__)) ||
  1704. (GNUNET_YES ==
  1705. mlp_create_problem_update_value (&mlp->p,
  1706. mlp->p.r_q[RQ_QUALITY_METRIC_DISTANCE],
  1707. mlpi->c_b,
  1708. address->norm_distance.norm,
  1709. __LINE__)) )
  1710. {
  1711. mlp->stat_mlp_prob_updated = GNUNET_YES;
  1712. if (GNUNET_YES == mlp->opt_mlp_auto_solve)
  1713. GAS_mlp_solve_problem (solver);
  1714. }
  1715. }
  1716. /**
  1717. * Find the active address in the set of addresses of a peer
  1718. * @param cls destination
  1719. * @param key peer id
  1720. * @param value address
  1721. * @return #GNUNET_OK
  1722. */
  1723. static int
  1724. mlp_get_preferred_address_it (void *cls,
  1725. const struct GNUNET_PeerIdentity *key,
  1726. void *value)
  1727. {
  1728. static int counter = 0;
  1729. struct ATS_Address **aa = cls;
  1730. struct ATS_Address *addr = value;
  1731. struct MLP_information *mlpi = addr->solver_information;
  1732. if (mlpi == NULL)
  1733. return GNUNET_YES;
  1734. /*
  1735. * Debug output
  1736. * GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1737. * "MLP [%u] Peer `%s' %s length %u session %u active %s mlp active %s\n",
  1738. * counter, GNUNET_i2s (&addr->peer), addr->plugin, addr->addr_len, addr->session_id,
  1739. * (GNUNET_YES == addr->active) ? "active" : "inactive",
  1740. * (GNUNET_YES == mlpi->n) ? "active" : "inactive");
  1741. */
  1742. if (GNUNET_YES == mlpi->n)
  1743. {
  1744. (*aa) = addr;
  1745. (*aa)->assigned_bw_in = mlpi->b_in;
  1746. (*aa)->assigned_bw_out = mlpi->b_out;
  1747. return GNUNET_NO;
  1748. }
  1749. counter++;
  1750. return GNUNET_YES;
  1751. }
  1752. static double
  1753. get_peer_pref_value (struct GAS_MLP_Handle *mlp,
  1754. const struct GNUNET_PeerIdentity *peer)
  1755. {
  1756. double res;
  1757. const double *preferences;
  1758. int c;
  1759. preferences = mlp->env->get_preferences (mlp->env->cls, peer);
  1760. res = 0.0;
  1761. for (c = 0; c < GNUNET_ATS_PREFERENCE_END; c++)
  1762. {
  1763. /* fprintf (stderr, "VALUE[%u] %s %.3f \n",
  1764. * c, GNUNET_i2s (&cur->addr->peer), t[c]); */
  1765. res += preferences[c];
  1766. }
  1767. res /= GNUNET_ATS_PREFERENCE_END;
  1768. res += 1.0;
  1769. LOG (GNUNET_ERROR_TYPE_DEBUG,
  1770. "Peer preference for peer `%s' == %.2f\n",
  1771. GNUNET_i2s(peer), res);
  1772. return res;
  1773. }
  1774. /**
  1775. * Get the preferred address for a specific peer
  1776. *
  1777. * @param solver the MLP Handle
  1778. * @param peer the peer
  1779. */
  1780. static void
  1781. GAS_mlp_get_preferred_address (void *solver,
  1782. const struct GNUNET_PeerIdentity *peer)
  1783. {
  1784. struct GAS_MLP_Handle *mlp = solver;
  1785. struct ATS_Peer *p;
  1786. struct ATS_Address *res;
  1787. LOG (GNUNET_ERROR_TYPE_DEBUG,
  1788. "Getting preferred address for `%s'\n",
  1789. GNUNET_i2s (peer));
  1790. /* Is this peer included in the problem? */
  1791. if (NULL ==
  1792. GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers,
  1793. peer))
  1794. {
  1795. LOG (GNUNET_ERROR_TYPE_INFO, "Adding peer `%s' to list of requested_peers with requests\n",
  1796. GNUNET_i2s (peer));
  1797. p = GNUNET_new (struct ATS_Peer);
  1798. p->id = (*peer);
  1799. p->f = get_peer_pref_value (mlp, peer);
  1800. GNUNET_CONTAINER_multipeermap_put (mlp->requested_peers,
  1801. peer, p,
  1802. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
  1803. /* Added new peer, we have to rebuild problem before solving */
  1804. mlp->stat_mlp_prob_changed = GNUNET_YES;
  1805. if ((GNUNET_YES == mlp->opt_mlp_auto_solve)&&
  1806. (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains(mlp->env->addresses,
  1807. peer)))
  1808. {
  1809. mlp->exclude_peer = peer;
  1810. GAS_mlp_solve_problem (mlp);
  1811. mlp->exclude_peer = NULL;
  1812. }
  1813. }
  1814. /* Get prefered address */
  1815. res = NULL;
  1816. GNUNET_CONTAINER_multipeermap_get_multiple (mlp->env->addresses, peer,
  1817. &mlp_get_preferred_address_it, &res);
  1818. if (NULL != res)
  1819. mlp->env->bandwidth_changed_cb (mlp->env->cls,
  1820. res);
  1821. }
  1822. /**
  1823. * Deletes a single address in the MLP problem
  1824. *
  1825. * The MLP problem has to be recreated and the problem has to be resolved
  1826. *
  1827. * @param solver the MLP Handle
  1828. * @param address the address to delete
  1829. */
  1830. static void
  1831. GAS_mlp_address_delete (void *solver,
  1832. struct ATS_Address *address)
  1833. {
  1834. struct GAS_MLP_Handle *mlp = solver;
  1835. struct MLP_information *mlpi;
  1836. struct ATS_Address *res;
  1837. int was_active;
  1838. mlpi = address->solver_information;
  1839. if (NULL != mlpi)
  1840. {
  1841. /* Remove full address */
  1842. GNUNET_free (mlpi);
  1843. address->solver_information = NULL;
  1844. }
  1845. was_active = address->active;
  1846. address->active = GNUNET_NO;
  1847. address->assigned_bw_in = 0;
  1848. address->assigned_bw_out = 0;
  1849. /* Is this peer included in the problem? */
  1850. if (NULL ==
  1851. GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers,
  1852. &address->peer))
  1853. {
  1854. LOG (GNUNET_ERROR_TYPE_INFO,
  1855. "Deleting address for peer `%s' without address request \n",
  1856. GNUNET_i2s(&address->peer));
  1857. return;
  1858. }
  1859. LOG (GNUNET_ERROR_TYPE_INFO,
  1860. "Deleting address for peer `%s' with address request \n",
  1861. GNUNET_i2s (&address->peer));
  1862. /* Problem size changed: new address for peer with pending request */
  1863. mlp->stat_mlp_prob_changed = GNUNET_YES;
  1864. if (GNUNET_YES == mlp->opt_mlp_auto_solve)
  1865. {
  1866. GAS_mlp_solve_problem (solver);
  1867. }
  1868. if (GNUNET_YES == was_active)
  1869. {
  1870. GAS_mlp_get_preferred_address (solver, &address->peer);
  1871. res = NULL;
  1872. GNUNET_CONTAINER_multipeermap_get_multiple (mlp->env->addresses,
  1873. &address->peer,
  1874. &mlp_get_preferred_address_it,
  1875. &res);
  1876. if (NULL == res)
  1877. {
  1878. /* No alternative address, disconnecting peer */
  1879. mlp->env->bandwidth_changed_cb (mlp->env->cls, address);
  1880. }
  1881. }
  1882. }
  1883. /**
  1884. * Start a bulk operation
  1885. *
  1886. * @param solver the solver
  1887. */
  1888. static void
  1889. GAS_mlp_bulk_start (void *solver)
  1890. {
  1891. struct GAS_MLP_Handle *s = solver;
  1892. LOG (GNUNET_ERROR_TYPE_DEBUG,
  1893. "Locking solver for bulk operation ...\n");
  1894. GNUNET_assert (NULL != solver);
  1895. s->stat_bulk_lock ++;
  1896. }
  1897. static void
  1898. GAS_mlp_bulk_stop (void *solver)
  1899. {
  1900. struct GAS_MLP_Handle *s = solver;
  1901. LOG (GNUNET_ERROR_TYPE_DEBUG,
  1902. "Unlocking solver from bulk operation ...\n");
  1903. GNUNET_assert (NULL != solver);
  1904. if (s->stat_bulk_lock < 1)
  1905. {
  1906. GNUNET_break (0);
  1907. return;
  1908. }
  1909. s->stat_bulk_lock --;
  1910. if (0 < s->stat_bulk_requests)
  1911. {
  1912. GAS_mlp_solve_problem (solver);
  1913. s->stat_bulk_requests= 0;
  1914. }
  1915. }
  1916. /**
  1917. * Stop notifying about address and bandwidth changes for this peer
  1918. *
  1919. * @param solver the MLP handle
  1920. * @param peer the peer
  1921. */
  1922. static void
  1923. GAS_mlp_stop_get_preferred_address (void *solver,
  1924. const struct GNUNET_PeerIdentity *peer)
  1925. {
  1926. struct GAS_MLP_Handle *mlp = solver;
  1927. struct ATS_Peer *p = NULL;
  1928. GNUNET_assert (NULL != solver);
  1929. GNUNET_assert (NULL != peer);
  1930. if (NULL != (p = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers, peer)))
  1931. {
  1932. GNUNET_assert (GNUNET_YES ==
  1933. GNUNET_CONTAINER_multipeermap_remove (mlp->requested_peers, peer, p));
  1934. GNUNET_free (p);
  1935. mlp->stat_mlp_prob_changed = GNUNET_YES;
  1936. if (GNUNET_YES == mlp->opt_mlp_auto_solve)
  1937. {
  1938. GAS_mlp_solve_problem (solver);
  1939. }
  1940. }
  1941. }
  1942. /**
  1943. * Changes the preferences for a peer in the MLP problem
  1944. *
  1945. * @param solver the MLP Handle
  1946. * @param peer the peer
  1947. * @param kind the kind to change the preference
  1948. * @param pref_rel the relative score
  1949. */
  1950. static void
  1951. GAS_mlp_address_change_preference (void *solver,
  1952. const struct GNUNET_PeerIdentity *peer,
  1953. enum GNUNET_ATS_PreferenceKind kind,
  1954. double pref_rel)
  1955. {
  1956. struct GAS_MLP_Handle *mlp = solver;
  1957. struct ATS_Peer *p;
  1958. LOG (GNUNET_ERROR_TYPE_DEBUG,
  1959. "Changing preference for address for peer `%s' to %.2f\n",
  1960. GNUNET_i2s(peer),
  1961. pref_rel);
  1962. GNUNET_STATISTICS_update (mlp->env->stats,
  1963. "# LP address preference changes", 1, GNUNET_NO);
  1964. /* Update the constraints with changed preferences */
  1965. /* Update relativity constraint c9 */
  1966. if (NULL == (p = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers, peer)))
  1967. {
  1968. LOG (GNUNET_ERROR_TYPE_INFO,
  1969. "Updating preference for unknown peer `%s'\n",
  1970. GNUNET_i2s(peer));
  1971. return;
  1972. }
  1973. if (GNUNET_NO == mlp->opt_dbg_feasibility_only)
  1974. {
  1975. p->f = get_peer_pref_value (mlp, peer);
  1976. mlp_create_problem_update_value (&mlp->p,
  1977. p->r_c9,
  1978. mlp->p.c_r,
  1979. - p->f,
  1980. __LINE__);
  1981. /* Problem size changed: new address for peer with pending request */
  1982. mlp->stat_mlp_prob_updated = GNUNET_YES;
  1983. if (GNUNET_YES == mlp->opt_mlp_auto_solve)
  1984. GAS_mlp_solve_problem (solver);
  1985. }
  1986. }
  1987. /**
  1988. * Get application feedback for a peer
  1989. *
  1990. * @param solver the solver handle
  1991. * @param application the application
  1992. * @param peer the peer to change the preference for
  1993. * @param scope the time interval for this feedback: [now - scope .. now]
  1994. * @param kind the kind to change the preference
  1995. * @param score the score
  1996. */
  1997. static void
  1998. GAS_mlp_address_preference_feedback (void *solver,
  1999. struct GNUNET_SERVER_Client *application,
  2000. const struct GNUNET_PeerIdentity *peer,
  2001. const struct GNUNET_TIME_Relative scope,
  2002. enum GNUNET_ATS_PreferenceKind kind,
  2003. double score)
  2004. {
  2005. struct GAS_PROPORTIONAL_Handle *s = solver;
  2006. GNUNET_assert (NULL != solver);
  2007. GNUNET_assert (NULL != peer);
  2008. GNUNET_assert (NULL != s);
  2009. }
  2010. static int
  2011. mlp_free_peers (void *cls,
  2012. const struct GNUNET_PeerIdentity *key, void *value)
  2013. {
  2014. struct GNUNET_CONTAINER_MultiPeerMap *map = cls;
  2015. struct ATS_Peer *p = value;
  2016. GNUNET_assert (GNUNET_YES ==
  2017. GNUNET_CONTAINER_multipeermap_remove (map, key, value));
  2018. GNUNET_free (p);
  2019. return GNUNET_OK;
  2020. }
  2021. /**
  2022. * Shutdown the MLP problem solving component
  2023. *
  2024. * @param cls the solver handle
  2025. * @return NULL
  2026. */
  2027. void *
  2028. libgnunet_plugin_ats_mlp_done (void *cls)
  2029. {
  2030. struct GNUNET_ATS_SolverFunctions *sf = cls;
  2031. struct GAS_MLP_Handle *mlp = sf->cls;
  2032. LOG (GNUNET_ERROR_TYPE_DEBUG,
  2033. "Shutting down mlp solver\n");
  2034. mlp_delete_problem (mlp);
  2035. GNUNET_CONTAINER_multipeermap_iterate (mlp->requested_peers,
  2036. &mlp_free_peers,
  2037. mlp->requested_peers);
  2038. GNUNET_CONTAINER_multipeermap_destroy (mlp->requested_peers);
  2039. mlp->requested_peers = NULL;
  2040. /* Clean up GLPK environment */
  2041. glp_free_env();
  2042. GNUNET_free (mlp);
  2043. LOG (GNUNET_ERROR_TYPE_DEBUG,
  2044. "Shutdown down of mlp solver complete\n");
  2045. return NULL;
  2046. }
  2047. void *
  2048. libgnunet_plugin_ats_mlp_init (void *cls)
  2049. {
  2050. static struct GNUNET_ATS_SolverFunctions sf;
  2051. struct GNUNET_ATS_PluginEnvironment *env = cls;
  2052. struct GAS_MLP_Handle * mlp = GNUNET_new (struct GAS_MLP_Handle);
  2053. float f_tmp;
  2054. unsigned long long tmp;
  2055. unsigned int b_min;
  2056. unsigned int n_min;
  2057. int c;
  2058. char *outputformat;
  2059. struct GNUNET_TIME_Relative max_duration;
  2060. long long unsigned int max_iterations;
  2061. /* Init GLPK environment */
  2062. int res = glp_init_env();
  2063. switch (res) {
  2064. case 0:
  2065. LOG (GNUNET_ERROR_TYPE_DEBUG, "GLPK: `%s'\n",
  2066. "initialization successful");
  2067. break;
  2068. case 1:
  2069. LOG (GNUNET_ERROR_TYPE_DEBUG, "GLPK: `%s'\n",
  2070. "environment is already initialized");
  2071. break;
  2072. case 2:
  2073. LOG (GNUNET_ERROR_TYPE_ERROR, "Could not init GLPK: `%s'\n",
  2074. "initialization failed (insufficient memory)");
  2075. GNUNET_free(mlp);
  2076. return NULL;
  2077. break;
  2078. case 3:
  2079. LOG (GNUNET_ERROR_TYPE_ERROR, "Could not init GLPK: `%s'\n",
  2080. "initialization failed (unsupported programming model)");
  2081. GNUNET_free(mlp);
  2082. return NULL;
  2083. break;
  2084. default:
  2085. break;
  2086. }
  2087. mlp->opt_dump_problem_all = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
  2088. "ats", "MLP_DUMP_PROBLEM_ALL");
  2089. if (GNUNET_SYSERR == mlp->opt_dump_problem_all)
  2090. mlp->opt_dump_problem_all = GNUNET_NO;
  2091. mlp->opt_dump_solution_all = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
  2092. "ats", "MLP_DUMP_SOLUTION_ALL");
  2093. if (GNUNET_SYSERR == mlp->opt_dump_solution_all)
  2094. mlp->opt_dump_solution_all = GNUNET_NO;
  2095. mlp->opt_dump_problem_on_fail = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
  2096. "ats", "MLP_DUMP_PROBLEM_ON_FAIL");
  2097. if (GNUNET_SYSERR == mlp->opt_dump_problem_on_fail)
  2098. mlp->opt_dump_problem_on_fail = GNUNET_NO;
  2099. mlp->opt_dump_solution_on_fail = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
  2100. "ats", "MLP_DUMP_SOLUTION_ON_FAIL");
  2101. if (GNUNET_SYSERR == mlp->opt_dump_solution_on_fail)
  2102. mlp->opt_dump_solution_on_fail = GNUNET_NO;
  2103. mlp->opt_dbg_glpk_verbose = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
  2104. "ats", "MLP_DBG_GLPK_VERBOSE");
  2105. if (GNUNET_SYSERR == mlp->opt_dbg_glpk_verbose)
  2106. mlp->opt_dbg_glpk_verbose = GNUNET_NO;
  2107. mlp->opt_dbg_feasibility_only = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
  2108. "ats", "MLP_DBG_FEASIBILITY_ONLY");
  2109. if (GNUNET_SYSERR == mlp->opt_dbg_feasibility_only)
  2110. mlp->opt_dbg_feasibility_only = GNUNET_NO;
  2111. if (GNUNET_YES == mlp->opt_dbg_feasibility_only)
  2112. LOG (GNUNET_ERROR_TYPE_WARNING,
  2113. "MLP solver is configured to check feasibility only!\n");
  2114. mlp->opt_dbg_autoscale_problem = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
  2115. "ats", "MLP_DBG_AUTOSCALE_PROBLEM");
  2116. if (GNUNET_SYSERR == mlp->opt_dbg_autoscale_problem)
  2117. mlp->opt_dbg_autoscale_problem = GNUNET_NO;
  2118. if (GNUNET_YES == mlp->opt_dbg_autoscale_problem)
  2119. LOG (GNUNET_ERROR_TYPE_WARNING,
  2120. "MLP solver is configured automatically scale the problem!\n");
  2121. mlp->opt_dbg_intopt_presolver = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
  2122. "ats", "MLP_DBG_INTOPT_PRESOLVE");
  2123. if (GNUNET_SYSERR == mlp->opt_dbg_intopt_presolver)
  2124. mlp->opt_dbg_intopt_presolver = GNUNET_NO;
  2125. if (GNUNET_YES == mlp->opt_dbg_intopt_presolver)
  2126. LOG (GNUNET_ERROR_TYPE_WARNING,
  2127. "MLP solver is configured use the mlp presolver\n");
  2128. mlp->opt_dbg_optimize_diversity = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
  2129. "ats", "MLP_DBG_OPTIMIZE_DIVERSITY");
  2130. if (GNUNET_SYSERR == mlp->opt_dbg_optimize_diversity)
  2131. mlp->opt_dbg_optimize_diversity = GNUNET_YES;
  2132. if (GNUNET_NO == mlp->opt_dbg_optimize_diversity)
  2133. LOG (GNUNET_ERROR_TYPE_WARNING,
  2134. "MLP solver is not optimizing for diversity\n");
  2135. mlp->opt_dbg_optimize_relativity= GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
  2136. "ats", "MLP_DBG_OPTIMIZE_RELATIVITY");
  2137. if (GNUNET_SYSERR == mlp->opt_dbg_optimize_relativity)
  2138. mlp->opt_dbg_optimize_relativity = GNUNET_YES;
  2139. if (GNUNET_NO == mlp->opt_dbg_optimize_relativity)
  2140. LOG (GNUNET_ERROR_TYPE_WARNING,
  2141. "MLP solver is not optimizing for relativity\n");
  2142. mlp->opt_dbg_optimize_quality = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
  2143. "ats", "MLP_DBG_OPTIMIZE_QUALITY");
  2144. if (GNUNET_SYSERR == mlp->opt_dbg_optimize_quality)
  2145. mlp->opt_dbg_optimize_quality = GNUNET_YES;
  2146. if (GNUNET_NO == mlp->opt_dbg_optimize_quality)
  2147. LOG (GNUNET_ERROR_TYPE_WARNING,
  2148. "MLP solver is not optimizing for quality\n");
  2149. mlp->opt_dbg_optimize_utility = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
  2150. "ats", "MLP_DBG_OPTIMIZE_UTILITY");
  2151. if (GNUNET_SYSERR == mlp->opt_dbg_optimize_utility)
  2152. mlp->opt_dbg_optimize_utility = GNUNET_YES;
  2153. if (GNUNET_NO == mlp->opt_dbg_optimize_utility)
  2154. LOG (GNUNET_ERROR_TYPE_WARNING,
  2155. "MLP solver is not optimizing for utility\n");
  2156. if ( (GNUNET_NO == mlp->opt_dbg_optimize_utility) &&
  2157. (GNUNET_NO == mlp->opt_dbg_optimize_quality) &&
  2158. (GNUNET_NO == mlp->opt_dbg_optimize_relativity) &&
  2159. (GNUNET_NO == mlp->opt_dbg_optimize_utility) &&
  2160. (GNUNET_NO == mlp->opt_dbg_feasibility_only))
  2161. {
  2162. LOG (GNUNET_ERROR_TYPE_ERROR,
  2163. _("MLP solver is not optimizing for anything, changing to feasibility check\n"));
  2164. mlp->opt_dbg_feasibility_only = GNUNET_YES;
  2165. }
  2166. if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (env->cfg,
  2167. "ats", "MLP_LOG_FORMAT", &outputformat))
  2168. mlp->opt_log_format = MLP_CPLEX;
  2169. else
  2170. {
  2171. GNUNET_STRINGS_utf8_toupper(outputformat, outputformat);
  2172. if (0 == strcmp (outputformat, "MPS"))
  2173. {
  2174. mlp->opt_log_format = MLP_MPS;
  2175. }
  2176. else if (0 == strcmp (outputformat, "CPLEX"))
  2177. {
  2178. mlp->opt_log_format = MLP_CPLEX;
  2179. }
  2180. else if (0 == strcmp (outputformat, "GLPK"))
  2181. {
  2182. mlp->opt_log_format = MLP_GLPK;
  2183. }
  2184. else
  2185. {
  2186. LOG (GNUNET_ERROR_TYPE_WARNING,
  2187. "Invalid log format `%s' in configuration, using CPLEX!\n",
  2188. outputformat);
  2189. mlp->opt_log_format = MLP_CPLEX;
  2190. }
  2191. GNUNET_free (outputformat);
  2192. }
  2193. mlp->pv.BIG_M = (double) BIG_M_VALUE;
  2194. mlp->pv.mip_gap = (double) 0.0;
  2195. if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats",
  2196. "MLP_MAX_MIP_GAP", &f_tmp))
  2197. {
  2198. if ((f_tmp < 0.0) || (f_tmp > 1.0))
  2199. {
  2200. LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid %s configuration %f \n"),
  2201. "MIP gap", f_tmp);
  2202. }
  2203. else
  2204. {
  2205. mlp->pv.mip_gap = f_tmp;
  2206. LOG (GNUNET_ERROR_TYPE_INFO, "Using %s of %.3f\n",
  2207. "MIP gap", f_tmp);
  2208. }
  2209. }
  2210. mlp->pv.lp_mip_gap = (double) 0.0;
  2211. if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats",
  2212. "MLP_MAX_LP_MIP_GAP", &f_tmp))
  2213. {
  2214. if ((f_tmp < 0.0) || (f_tmp > 1.0))
  2215. {
  2216. LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid %s configuration %f \n"),
  2217. "LP/MIP", f_tmp);
  2218. }
  2219. else
  2220. {
  2221. mlp->pv.lp_mip_gap = f_tmp;
  2222. LOG (GNUNET_ERROR_TYPE_INFO, "Using %s gap of %.3f\n",
  2223. "LP/MIP", f_tmp);
  2224. }
  2225. }
  2226. /* Get timeout for iterations */
  2227. if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time(env->cfg, "ats",
  2228. "MLP_MAX_DURATION", &max_duration))
  2229. {
  2230. max_duration = MLP_MAX_EXEC_DURATION;
  2231. }
  2232. /* Get maximum number of iterations */
  2233. if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_size(env->cfg, "ats",
  2234. "MLP_MAX_ITERATIONS", &max_iterations))
  2235. {
  2236. max_iterations = MLP_MAX_ITERATIONS;
  2237. }
  2238. /* Get diversity coefficient from configuration */
  2239. mlp->pv.co_D = MLP_DEFAULT_D;
  2240. if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats",
  2241. "MLP_COEFFICIENT_D", &f_tmp))
  2242. {
  2243. if ((f_tmp < 0.0))
  2244. {
  2245. LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid %s configuration %f \n"),
  2246. "MLP_COEFFICIENT_D", f_tmp);
  2247. }
  2248. else
  2249. {
  2250. mlp->pv.co_D = f_tmp;
  2251. LOG (GNUNET_ERROR_TYPE_INFO, "Using %s gap of %.3f\n",
  2252. "MLP_COEFFICIENT_D", f_tmp);
  2253. }
  2254. }
  2255. /* Get relativity coefficient from configuration */
  2256. mlp->pv.co_R = MLP_DEFAULT_R;
  2257. if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats",
  2258. "MLP_COEFFICIENT_R", &f_tmp))
  2259. {
  2260. if ((f_tmp < 0.0))
  2261. {
  2262. LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid %s configuration %f \n"),
  2263. "MLP_COEFFICIENT_R", f_tmp);
  2264. }
  2265. else
  2266. {
  2267. mlp->pv.co_R = f_tmp;
  2268. LOG (GNUNET_ERROR_TYPE_INFO, "Using %s gap of %.3f\n",
  2269. "MLP_COEFFICIENT_R", f_tmp);
  2270. }
  2271. }
  2272. /* Get utilization coefficient from configuration */
  2273. mlp->pv.co_U = MLP_DEFAULT_U;
  2274. if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats",
  2275. "MLP_COEFFICIENT_U", &f_tmp))
  2276. {
  2277. if ((f_tmp < 0.0))
  2278. {
  2279. LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid %s configuration %f \n"),
  2280. "MLP_COEFFICIENT_U", f_tmp);
  2281. }
  2282. else
  2283. {
  2284. mlp->pv.co_U = f_tmp;
  2285. LOG (GNUNET_ERROR_TYPE_INFO, "Using %s gap of %.3f\n",
  2286. "MLP_COEFFICIENT_U", f_tmp);
  2287. }
  2288. }
  2289. /* Get quality metric coefficients from configuration */
  2290. for (c = 0; c < RQ_QUALITY_METRIC_COUNT; c++)
  2291. {
  2292. /* initialize quality coefficients with default value 1.0 */
  2293. mlp->pv.co_Q[c] = MLP_DEFAULT_QUALITY;
  2294. }
  2295. if (GNUNET_OK ==
  2296. GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats",
  2297. "MLP_COEFFICIENT_QUALITY_DELAY",
  2298. &tmp))
  2299. mlp->pv.co_Q[RQ_QUALITY_METRIC_DELAY] = (double) tmp / 100;
  2300. else
  2301. mlp->pv.co_Q[RQ_QUALITY_METRIC_DELAY] = MLP_DEFAULT_QUALITY;
  2302. if (GNUNET_OK ==
  2303. GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats",
  2304. "MLP_COEFFICIENT_QUALITY_DISTANCE",
  2305. &tmp))
  2306. mlp->pv.co_Q[RQ_QUALITY_METRIC_DISTANCE] = (double) tmp / 100;
  2307. else
  2308. mlp->pv.co_Q[RQ_QUALITY_METRIC_DISTANCE] = MLP_DEFAULT_QUALITY;
  2309. /* Get minimum bandwidth per used address from configuration */
  2310. if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats",
  2311. "MLP_MIN_BANDWIDTH",
  2312. &tmp))
  2313. b_min = tmp;
  2314. else
  2315. {
  2316. b_min = ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
  2317. }
  2318. /* Get minimum number of connections from configuration */
  2319. if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats",
  2320. "MLP_MIN_CONNECTIONS",
  2321. &tmp))
  2322. n_min = tmp;
  2323. else
  2324. n_min = MLP_DEFAULT_MIN_CONNECTIONS;
  2325. /* Init network quotas */
  2326. for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
  2327. {
  2328. mlp->pv.quota_index[c] = c;
  2329. mlp->pv.quota_out[c] = env->out_quota[c];
  2330. mlp->pv.quota_in[c] = env->in_quota[c];
  2331. LOG (GNUNET_ERROR_TYPE_INFO,
  2332. "Quota for network `%s' (in/out) %llu/%llu\n",
  2333. GNUNET_ATS_print_network_type (c),
  2334. mlp->pv.quota_out[c],
  2335. mlp->pv.quota_in[c]);
  2336. /* Check if defined quota could make problem unsolvable */
  2337. if ((n_min * b_min) > mlp->pv.quota_out[c])
  2338. {
  2339. LOG (GNUNET_ERROR_TYPE_INFO,
  2340. _("Adjusting inconsistent outbound quota configuration for network `%s', is %llu must be at least %llu\n"),
  2341. GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
  2342. mlp->pv.quota_out[c],
  2343. (n_min * b_min));
  2344. mlp->pv.quota_out[c] = (n_min * b_min);
  2345. }
  2346. if ((n_min * b_min) > mlp->pv.quota_in[c])
  2347. {
  2348. LOG (GNUNET_ERROR_TYPE_INFO,
  2349. _("Adjusting inconsistent inbound quota configuration for network `%s', is %llu must be at least %llu\n"),
  2350. GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
  2351. mlp->pv.quota_in[c],
  2352. (n_min * b_min));
  2353. mlp->pv.quota_in[c] = (n_min * b_min);
  2354. }
  2355. /* Check if bandwidth is too big to make problem solvable */
  2356. if (mlp->pv.BIG_M < mlp->pv.quota_out[c])
  2357. {
  2358. LOG (GNUNET_ERROR_TYPE_INFO,
  2359. _("Adjusting outbound quota configuration for network `%s'from %llu to %.0f\n"),
  2360. GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
  2361. mlp->pv.quota_out[c],
  2362. mlp->pv.BIG_M);
  2363. mlp->pv.quota_out[c] = mlp->pv.BIG_M ;
  2364. }
  2365. if (mlp->pv.BIG_M < mlp->pv.quota_in[c])
  2366. {
  2367. LOG (GNUNET_ERROR_TYPE_INFO,
  2368. _("Adjusting inbound quota configuration for network `%s' from %llu to %.0f\n"),
  2369. GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
  2370. mlp->pv.quota_in[c],
  2371. mlp->pv.BIG_M);
  2372. mlp->pv.quota_in[c] = mlp->pv.BIG_M ;
  2373. }
  2374. }
  2375. mlp->env = env;
  2376. sf.cls = mlp;
  2377. sf.s_add = &GAS_mlp_address_add;
  2378. sf.s_address_update_property = &GAS_mlp_address_property_changed;
  2379. sf.s_get = &GAS_mlp_get_preferred_address;
  2380. sf.s_get_stop = &GAS_mlp_stop_get_preferred_address;
  2381. sf.s_pref = &GAS_mlp_address_change_preference;
  2382. sf.s_feedback = &GAS_mlp_address_preference_feedback;
  2383. sf.s_del = &GAS_mlp_address_delete;
  2384. sf.s_bulk_start = &GAS_mlp_bulk_start;
  2385. sf.s_bulk_stop = &GAS_mlp_bulk_stop;
  2386. /* Setting MLP Input variables */
  2387. mlp->pv.b_min = b_min;
  2388. mlp->pv.n_min = n_min;
  2389. mlp->pv.m_q = RQ_QUALITY_METRIC_COUNT;
  2390. mlp->stat_mlp_prob_changed = GNUNET_NO;
  2391. mlp->stat_mlp_prob_updated = GNUNET_NO;
  2392. mlp->opt_mlp_auto_solve = GNUNET_YES;
  2393. mlp->requested_peers = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
  2394. mlp->stat_bulk_requests = 0;
  2395. mlp->stat_bulk_lock = 0;
  2396. /* Setup GLPK */
  2397. /* Redirect GLPK output to GNUnet logging */
  2398. glp_term_hook (&mlp_term_hook, (void *) mlp);
  2399. /* Init LP solving parameters */
  2400. glp_init_smcp(&mlp->control_param_lp);
  2401. mlp->control_param_lp.msg_lev = GLP_MSG_OFF;
  2402. if (GNUNET_YES == mlp->opt_dbg_glpk_verbose)
  2403. mlp->control_param_lp.msg_lev = GLP_MSG_ALL;
  2404. mlp->control_param_lp.it_lim = max_iterations;
  2405. mlp->control_param_lp.tm_lim = max_duration.rel_value_us / 1000LL;
  2406. /* Init MLP solving parameters */
  2407. glp_init_iocp(&mlp->control_param_mlp);
  2408. /* Setting callback function */
  2409. mlp->control_param_mlp.cb_func = &mlp_branch_and_cut_cb;
  2410. mlp->control_param_mlp.cb_info = mlp;
  2411. mlp->control_param_mlp.msg_lev = GLP_MSG_OFF;
  2412. mlp->control_param_mlp.mip_gap = mlp->pv.mip_gap;
  2413. if (GNUNET_YES == mlp->opt_dbg_glpk_verbose)
  2414. mlp->control_param_mlp.msg_lev = GLP_MSG_ALL;
  2415. mlp->control_param_mlp.tm_lim = max_duration.rel_value_us / 1000LL;
  2416. LOG (GNUNET_ERROR_TYPE_DEBUG, "solver ready\n");
  2417. return &sf;
  2418. }
  2419. /* end of plugin_ats_mlp.c */