plugin_ats_mlp.c 82 KB

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