+DEBUG_DEFINE_DEBUGF(value);
+
+typedef struct { int mass, volu; } CommodInfo;
+static int commodstablesz;
+static CommodInfo *commodstable;
+
+static sqlite3_stmt *ss_ipair_dist, *ss_ipair_trades;
+static sqlite3_stmt *ss_ite_buy, *ss_ite_sell;
+
+#define MAX_LEGS (MAX_ROUTELEN-1)
+
+typedef struct {
+ int commodid, src_price, src_qty, dst_price, dst_qty;
+} Trade;
+
+#define TRADES_PER_BLOCK 10
+
+typedef struct TradesBlock{
+ struct TradesBlock *next;
+ Trade t[TRADES_PER_BLOCK];
+} TradesBlock;
+
+typedef struct {
+ double distance_loss_factor;
+ int ntrades;
+ TradesBlock *trades;
+} IslandPair;
+
+int nislands;
+IslandPair ***ipairs; /* ipairs[sislandid][dislandid] */
+
+typedef struct IslandTradeEnd {
+ struct IslandTradeEnd *next;
+ int commodid, price;
+ int qty;
+ unsigned long generation;
+ int rownum;
+} IslandTradeEnd, *IslandDirnTradeEnds;
+
+typedef struct {
+ int islandid;
+ IslandDirnTradeEnds collect, deliver;
+} IslandTradeEnds;
+
+static LPX *lp;
+static unsigned long generation;
+
+static int nconstraint_rows;
+static int constraint_rows[1+2+3*MAX_LEGS];
+static double constraint_coeffs[1+2+3*MAX_LEGS];
+ /* dummy0, src, dst, for_each_leg( [mass], [volume], [capital] ) */
+
+static void add_constraint(int row, double coefficient) {
+ nconstraint_rows++; /* glpk indices start from 1 !!! */
+ constraint_rows [nconstraint_rows]= row;
+ constraint_coeffs[nconstraint_rows]= coefficient;
+}
+
+static void avail_c(const Trade *t, IslandDirnTradeEnds *trades,
+ int price, const char *srcdst,
+ int islandid, sqlite3_stmt *ss_ite) {
+ /* find row number of trade availability constraint */
+ IslandTradeEnd *search;
+
+ for (search= *trades; search; search=search->next)
+ if (search->commodid==t->commodid && search->price==price)
+ goto found;
+ /* not found, add new row */
+
+ search= mmalloc(sizeof(*search));
+ search->commodid= t->commodid;
+ search->price= price;
+ search->next= *trades;
+ search->generation= 0;
+
+ SQL_MUST( sqlite3_bind_int(ss_ite, 1, islandid) );
+ SQL_MUST( sqlite3_bind_int(ss_ite, 2, t->commodid) );
+ SQL_MUST( sqlite3_bind_int(ss_ite, 3, price) );
+ assert(SQL_STEP(ss_ite));
+ search->qty= sqlite3_column_int(ss_ite, 0);
+ SQL_MUST( sqlite3_reset(ss_ite) );
+
+ *trades= search;
+
+ found:;
+ if (search->generation != generation) {
+ search->rownum= lpx_add_rows(lp, 1);
+ lpx_set_row_bnds(lp, search->rownum, LPX_UP, 0, search->qty);
+
+ if (DEBUGP(value)) {
+ char *name= masprintf("%s_commod%d_price%d",srcdst,t->commodid,price);
+ lpx_set_row_name(lp,search->rownum,name);
+ free(name);
+ }
+ search->generation= generation;
+ }
+
+ add_constraint(search->rownum, 1.0);
+}
+
+static int setup_leg_constraints(double max_thing, int legs, const char *wh) {
+ int leg, startrow;
+ if (max_thing < 0 || !legs) return -1;
+ startrow= lpx_add_rows(lp, legs);
+ for (leg=0; leg<nislands-1; leg++) {
+ int row= leg+startrow;
+ lpx_set_row_bnds(lp, row, LPX_UP, 0, max_thing);
+ if (DEBUGP(value)) {
+ char *name= masprintf("max_leg%d_%s",leg,wh);
+ lpx_set_row_name(lp,row,name);
+ free(name);
+ }
+ }
+ return startrow;
+}
+
+static void add_leg_c(int startrow, int leg, double value) {
+ if (startrow<=0) return;
+ assert(value > 0);
+ add_constraint(startrow+leg, value);
+}
+
+static IslandPair *ipair_get(int si, int di) {
+ IslandPair *ip, **ipa;
+
+ assert(si < nislands);
+ assert(di < nislands);
+
+ if (!(ipa= ipairs[si])) {
+ ipa= ipairs[si]= mcalloc(sizeof(*ipa) * nislands);
+ }
+ if ((ip= ipa[di]))
+ return ip;
+
+ ipa[di]= ip= mmalloc(sizeof(*ip));
+ ip->ntrades= 0;
+ ip->trades= 0;
+ int inblock= TRADES_PER_BLOCK;
+ TradesBlock *block= 0;
+
+ debugf("VALUE ipair_get(%d,%d) running...\n", si,di);
+ SQL_MUST( sqlite3_bind_int(ss_ipair_dist, 1, si) );
+ SQL_MUST( sqlite3_bind_int(ss_ipair_dist, 2, di) );
+ assert(SQL_STEP(ss_ipair_dist));
+ int dist= sqlite3_column_int(ss_ipair_dist, 0);
+ ip->distance_loss_factor= pow(distance_loss_factor_per_league, dist);
+ sqlite3_reset(ss_ipair_dist);
+
+ SQL_MUST( sqlite3_bind_int(ss_ipair_trades, 1, si) );
+ SQL_MUST( sqlite3_bind_int(ss_ipair_trades, 2, di) );
+
+ while (SQL_STEP(ss_ipair_trades)) {
+ if (inblock == TRADES_PER_BLOCK) {
+ block= mmalloc(sizeof(*block));
+ block->next= ip->trades;
+ ip->trades= block;
+ inblock= 0;
+ }
+ int *irp, i;
+ for (i=0, irp=&block->t[inblock].commodid; i<5; i++, irp++)
+ *irp= sqlite3_column_int(ss_ipair_trades, i);
+ ip->ntrades++;
+ inblock++;
+ }
+ if (inblock < TRADES_PER_BLOCK)
+ block->t[inblock].commodid= -1;
+
+ sqlite3_reset(ss_ipair_trades);
+
+ return ip;
+}
+