#include "config.h"
#include <assert.h>
#include <ccan/list/list.h>
#include <ccan/lqueue/lqueue.h>
#include <ccan/tal/str/str.h>
#include <ccan/tal/tal.h>
#include <common/pseudorand.h>
#include <common/utils.h>
#include <math.h>
#include <plugins/renepay/dijkstra.h>
#include <plugins/renepay/flow.h>
#include <plugins/renepay/mcf.h>
#include <stdint.h>

/* # Optimal payments
 *
 * In this module we reduce the routing optimization problem to a linear
 * cost optimization problem and find a solution using MCF algorithms.
 * The optimization of the routing itself doesn't need a precise numerical
 * solution, since we can be happy near optimal results; e.g. paying 100 msat or
 * 101 msat for fees doesn't make any difference if we wish to deliver 1M sats.
 * On the other hand, we are now also considering Pickhard's
 * [1] model to improve payment reliability,
 * hence our optimization moves to a 2D space: either we like to maximize the
 * probability of success of a payment or minimize the routing fees, or
 * alternatively we construct a function of the two that gives a good compromise.
 *
 * Therefore from now own, the definition of optimal is a matter of choice.
 * To simplify the API of this module, we think the best way to state the
 * problem is:
 *
 * 	Find a routing solution that pays the least of fees while keeping
 * 	the probability of success above a certain value `min_probability`.
 *
 *
 * # Fee Cost
 *
 * Routing fees is non-linear function of the payment flow x, that's true even
 * without the base fee:
 *
 * 	fee_msat = base_msat + floor(millionths*x_msat / 10^6)
 *
 * We approximate this fee into a linear function by computing a slope `c_fee` such
 * that:
 *
 * 	fee_microsat = c_fee * x_sat
 *
 * Function `linear_fee_cost` computes `c_fee` based on the base and
 * proportional fees of a channel.
 * The final product if microsat because if only
 * the proportional fee was considered we can have c_fee = millionths.
 * Moving to costs based in msats means we have to either truncate payments
 * below 1ksats or estimate as 0 cost for channels with less than 1000ppm.
 *
 * TODO(eduardo): shall we build a linear cost function in msats?
 *
 * # Probability cost
 *
 * The probability of success P of the payment is the product of the prob. of
 * success of forwarding parts of the payment over all routing channels. This
 * problem is separable if we log it, and since we would like to increase P,
 * then we can seek to minimize -log(P), and that's our prob. cost function [1].
 *
 * 	- log P = sum_{i} - log P_i
 *
 * The probability of success `P_i` of sending some flow `x` on a channel with
 * liquidity l in the range a<=l<b is
 *
 * 	P_{a,b}(x) = (b-x)/(b-a); for x > a
 * 		   = 1.         ; for x <= a
 *
 * Notice that unlike the similar formula in [1], the one we propose does not
 * contain the quantization shot noise for counting states. The formula remains
 * valid independently of the liquidity units (sats or msats).
 *
 * The cost associated to probability P is then -k log P, where k is some
 * constant. For k=1 we get the following table:
 *
 * 	prob | cost
 * 	-----------
 * 	0.01 | 4.6
 * 	0.02 | 3.9
 * 	0.05 | 3.0
 * 	0.10 | 2.3
 * 	0.20 | 1.6
 * 	0.50 | 0.69
 * 	0.80 | 0.22
 * 	0.90 | 0.10
 * 	0.95 | 0.05
 * 	0.98 | 0.02
 * 	0.99 | 0.01
 *
 * Clearly -log P(x) is non-linear; we try to linearize it piecewise:
 * split the channel into 4 arcs representing 4 liquidity regions:
 *
 * 	arc_0 -> [0, a)
 * 	arc_1 -> [a, a+(b-a)*f1)
 * 	arc_2 -> [a+(b-a)*f1, a+(b-a)*f2)
 * 	arc_3 -> [a+(b-a)*f2, a+(b-a)*f3)
 *
 * where f1 = 0.5, f2 = 0.8, f3 = 0.95;
 * We fill arc_0's capacity with complete certainty P=1, then if more flow is
 * needed we start filling the capacity in arc_1 until the total probability
 * of success reaches P=0.5, then arc_2 until P=1-0.8=0.2, and finally arc_3 until
 * P=1-0.95=0.05. We don't go further than 5% prob. of success per channel.

 * TODO(eduardo): this channel linearization is hard coded into
 * `CHANNEL_PIVOTS`, maybe we can parametrize this to take values from the config file.
 *
 * With this choice, the slope of the linear cost function becomes:
 *
 * 	m_0 = 0
 * 	m_1 = 1.38 k /(b-a)
 * 	m_2 = 3.05 k /(b-a)
 * 	m_3 = 9.24 k /(b-a)
 *
 * Notice that one of the assumptions in [2] for the MCF problem is that flows
 * and the slope of the costs functions are integer numbers. The only way we
 * have at hand to make it so, is to choose a universal value of `k` that scales
 * up the slopes so that floor(m_i) is not zero for every arc.
 *
 * # Combine fee and prob. costs
 *
 * We attempt to solve the original problem of finding the solution that
 * pays the least fees while keeping the prob. of success above a certain value,
 * by constructing a cost function which is a linear combination of fee and
 * prob. costs.
 * TODO(eduardo): investigate how this procedure is justified,
 * possibly with the use of Lagrange optimization theory.
 *
 * At first, prob. and fee costs live in different dimensions, they cannot be
 * summed, it's like comparing apples and oranges.
 * However we propose to scale the prob. cost by a global factor k that
 * translates into the monetization of prob. cost.
 *
 * k/1000, for instance, becomes the equivalent monetary cost
 * of increasing the probability of success by 0.1% for P~100%.
 *
 * The input parameter `prob_cost_factor` in the function `minflow` is defined
 * as the PPM from the delivery amount `T` we are *willing to pay* to increase the
 * prob. of success by 0.1%:
 *
 * 	k_microsat = floor(1000*prob_cost_factor * T_sat)
 *
 * Is this enough to make integer prob. cost per unit flow?
 * For `prob_cost_factor=10`; i.e. we pay 10ppm for increasing the prob. by
 * 0.1%, we get that
 *
 * 	-> any arc with (b-a) > 10000 T, will have zero prob. cost, which is
 * 	reasonable because even if all the flow passes through that arc, we get
 * 	a 1.3 T/(b-a) ~ 0.01% prob. of failure at most.
 *
 * 	-> if (b-a) ~ 10000 T, then the arc will have unit cost, or just that we
 * 	pay 1 microsat for every sat we send through this arc.
 *
 * 	-> it would be desirable to have a high proportional fee when (b-a)~T,
 * 	because prob. of failure start to become very high.
 * 	In this case we get to pay 10000 microsats for every sat.
 *
 * Once `k` is fixed then we can combine the linear prob. and fee costs, both
 * are in monetary units.
 *
 * Note: with costs in microsats, because slopes represent ppm and flows are in
 * sats, then our integer bounds with 64 bits are such that we can move as many
 * as 10'000 BTC without overflow:
 *
 * 	10^6 (max ppm) * 10^8 (sats per BTC) * 10^4 = 10^18
 *
 * # References
 *
 * [1] Pickhardt and Richter, https://arxiv.org/abs/2107.05322
 * [2] R.K. Ahuja, T.L. Magnanti, and J.B. Orlin. Network Flows:
 * Theory, Algorithms, and Applications. Prentice Hall, 1993.
 *
 *
 * TODO(eduardo) it would be interesting to see:
 * how much do we pay for reliability?
 * Cost_fee(most reliable solution) - Cost_fee(cheapest solution)
 *
 * TODO(eduardo): it would be interesting to see:
 * how likely is the most reliable path with respect to the cheapest?
 * Prob(reliable)/Prob(cheapest) = Exp(Cost_prob(cheapest)-Cost_prob(reliable))
 *
 * */

#define PARTS_BITS 2
#define CHANNEL_PARTS (1 << PARTS_BITS)

// These are the probability intervals we use to decompose a channel into linear
// cost function arcs.
static const double CHANNEL_PIVOTS[]={0,0.5,0.8,0.95};

static const s64 INFINITE = INT64_MAX;
static const u64 INFINITE_MSAT = UINT64_MAX;
static const u32 INVALID_INDEX = 0xffffffff;
static const s64 MU_MAX = 128;

/* Let's try this encoding of arcs:
 * Each channel `c` has two possible directions identified by a bit
 * `half` or `!half`, and each one of them has to be
 * decomposed into 4 liquidity parts in order to
 * linearize the cost function, but also to solve MCF
 * problem we need to keep track of flows in the
 * residual network hence we need for each directed arc
 * in the network there must be another arc in the
 * opposite direction refered to as it's dual. In total
 * 1+2+1 additional bits of information:
 *
 * 	(chan_idx)(half)(part)(dual)
 *
 * That means, for each channel we need to store the
 * information of 16 arcs. If we implement a convex-cost
 * solver then we can reduce that number to size(half)size(dual)=4.
 *
 * In the adjacency of a `node` we are going to store
 * the outgoing arcs. If we ever need to loop over the
 * incoming arcs then we will define a reverse adjacency
 * API.
 * Then for each outgoing channel `(c,half)` there will
 * be 4 parts for the actual residual capacity, hence
 * with the dual bit set to 0:
 *
 * 	(c,half,0,0)
 * 	(c,half,1,0)
 * 	(c,half,2,0)
 * 	(c,half,3,0)
 *
 * and also we need to consider the dual arcs
 * corresponding to the channel direction `(c,!half)`
 * (the dual has reverse direction):
 *
 * 	(c,!half,0,1)
 * 	(c,!half,1,1)
 * 	(c,!half,2,1)
 * 	(c,!half,3,1)
 *
 * These are the 8 outgoing arcs relative to `node` and
 * associated with channel `c`. The incoming arcs will
 * be:
 *
 * 	(c,!half,0,0)
 * 	(c,!half,1,0)
 * 	(c,!half,2,0)
 * 	(c,!half,3,0)
 *
 * 	(c,half,0,1)
 * 	(c,half,1,1)
 * 	(c,half,2,1)
 * 	(c,half,3,1)
 *
 * but they will be stored as outgoing arcs on the peer
 * node `next`.
 *
 * I hope this will clarify my future self when I forget.
 *
 * */

/*
 * We want to use the whole number here for convenience, but
 * we can't us a union, since bit order is implementation-defined and
 * we want chanidx on the highest bits:
 *
 * [ 0       1 2     3            4 5 6 ... 31 ]
 *   dual    part    chandir      chanidx
 */
struct arc {
	u32 idx;
};

#define ARC_DUAL_BITOFF (0)
#define ARC_PART_BITOFF (1)
#define ARC_CHANDIR_BITOFF (1 + PARTS_BITS)
#define ARC_CHANIDX_BITOFF (1 + PARTS_BITS + 1)
#define ARC_CHANIDX_BITS  (32 - ARC_CHANIDX_BITOFF)

/* How many arcs can we have for a single channel?
 * linearization parts, both directions, and dual */
#define ARCS_PER_CHANNEL ((size_t)1 << (PARTS_BITS + 1 + 1))

static inline void arc_to_parts(struct arc arc,
				u32 *chanidx,
				int *chandir,
				u32 *part,
				bool *dual)
{
	if (chanidx)
		*chanidx = (arc.idx >> ARC_CHANIDX_BITOFF);
	if (chandir)
		*chandir = (arc.idx >> ARC_CHANDIR_BITOFF) & 1;
	if (part)
		*part = (arc.idx >> ARC_PART_BITOFF) & ((1 << PARTS_BITS)-1);
	if (dual)
		*dual = (arc.idx >> ARC_DUAL_BITOFF) & 1;
}

static inline struct arc arc_from_parts(u32 chanidx, int chandir, u32 part, bool dual)
{
	struct arc arc;

	assert(part < CHANNEL_PARTS);
	assert(chandir == 0 || chandir == 1);
	assert(chanidx < (1U << ARC_CHANIDX_BITS));
	arc.idx = ((u32)dual << ARC_DUAL_BITOFF)
		| (part << ARC_PART_BITOFF)
		| ((u32)chandir << ARC_CHANDIR_BITOFF)
		| (chanidx << ARC_CHANIDX_BITOFF);
	return arc;
}

#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))

struct pay_parameters {
	/* The gossmap we are using */
	struct gossmap *gossmap;
	const struct gossmap_node *source;
	const struct gossmap_node *target;

	/* Extra information we intuited about the channels */
	struct chan_extra_map *chan_extra_map;

	/* Optional bitarray of disabled channels. */
	const bitmap *disabled;

	// how much we pay
	struct amount_msat amount;

	// channel linearization parameters
	double cap_fraction[CHANNEL_PARTS],
	       cost_fraction[CHANNEL_PARTS];

	struct amount_msat max_fee;
	double min_probability;
	double base_probability;
	double delay_feefactor;
	double base_fee_penalty;
	u32 prob_cost_factor;
};

/* Representation of the linear MCF network.
 * This contains the topology of the extended network (after linearization and
 * addition of arc duality).
 * This contains also the arc probability and linear fee cost, as well as
 * capacity; these quantities remain constant during MCF execution. */
struct linear_network
{
	u32 *arc_tail_node;
	// notice that a tail node is not needed,
	// because the tail of arc is the head of dual(arc)

	struct arc *node_adjacency_next_arc;
	struct arc *node_adjacency_first_arc;

	// probability and fee cost associated to an arc
	s64 *arc_prob_cost, *arc_fee_cost;
	s64 *capacity;

	size_t max_num_arcs,max_num_nodes;
};

/* This is the structure that keeps track of the network properties while we
 * seek for a solution. */
struct residual_network {
	/* residual capacity on arcs */
	s64 *cap;

	/* some combination of prob. cost and fee cost on arcs */
	s64 *cost;

	/* potential function on nodes */
	s64 *potential;
};

/* Helper function.
 * Given an arc idx, return the dual's idx in the residual network. */
static struct arc arc_dual(struct arc arc)
{
	arc.idx ^= (1U << ARC_DUAL_BITOFF);
	return arc;
}
/* Helper function. */
static bool arc_is_dual(struct arc arc)
{
	bool dual;
	arc_to_parts(arc, NULL, NULL, NULL, &dual);
	return dual;
}

/* Helper function.
 * Given an arc of the network (not residual) give me the flow. */
static s64 get_arc_flow(
		const struct residual_network *network,
		const struct arc arc)
{
	assert(!arc_is_dual(arc));
	assert(arc_dual(arc).idx < tal_count(network->cap));
	return network->cap[ arc_dual(arc).idx ];
}

/* Helper function.
 * Given an arc idx, return the node from which this arc emanates in the residual network. */
static u32 arc_tail(const struct linear_network *linear_network,
                    const struct arc arc)
{
	assert(arc.idx < tal_count(linear_network->arc_tail_node));
	return linear_network->arc_tail_node[ arc.idx ];
}
/* Helper function.
 * Given an arc idx, return the node that this arc is pointing to in the residual network. */
static u32 arc_head(const struct linear_network *linear_network,
                    const struct arc arc)
{
	const struct arc dual = arc_dual(arc);
	assert(dual.idx < tal_count(linear_network->arc_tail_node));
	return linear_network->arc_tail_node[dual.idx];
}

/* Helper function.
 * Given node idx `node`, return the idx of the first arc whose tail is `node`.
 * */
static struct arc node_adjacency_begin(
		const struct linear_network * linear_network,
		const u32 node)
{
	assert(node < tal_count(linear_network->node_adjacency_first_arc));
	return linear_network->node_adjacency_first_arc[node];
}

/* Helper function.
 * Is this the end of the adjacency list. */
static bool node_adjacency_end(const struct arc arc)
{
	return arc.idx == INVALID_INDEX;
}

/* Helper function.
 * Given node idx `node` and `arc`, returns the idx of the next arc whose tail is `node`. */
static struct arc node_adjacency_next(
		const struct linear_network *linear_network,
		const struct arc arc)
{
	assert(arc.idx < tal_count(linear_network->node_adjacency_next_arc));
	return linear_network->node_adjacency_next_arc[arc.idx];
}

static bool channel_is_available(const struct gossmap_chan *c, int dir,
				 const struct gossmap *gossmap,
				 const bitmap *disabled)
{
	if (!gossmap_chan_set(c, dir))
		return false;

	const u32 chan_idx = gossmap_chan_idx(gossmap, c);
	return !bitmap_test_bit(disabled, chan_idx * 2 + dir);
}

// TODO(eduardo): unit test this
/* Split a directed channel into parts with linear cost function. */
static bool linearize_channel(const struct pay_parameters *params,
			      const struct gossmap_chan *c, const int dir,
			      s64 *capacity, s64 *cost)
{
	struct chan_extra_half *extra_half = get_chan_extra_half_by_chan(
							params->gossmap,
							params->chan_extra_map,
							c,
							dir);

	if (!extra_half) {
		return false;
	}

	/* FIXME: this assertion has been reported to be triggered in issue
	 * #7535. A quick and dirty solution is to comment it and work-around
	 * this case. But in principle if we do things the right way we should
	 * not have htlc_total>known_max. The problem is likely to be
	 * asynchronous way in which reserved htlcs are removed and known_max is
	 * updated. */
	// assert(
	//    amount_msat_less_eq(extra_half->htlc_total, extra_half->known_max));
	assert(
	    amount_msat_less_eq(extra_half->known_min, extra_half->known_max));

	s64 h = (extra_half->htlc_total.millisatoshis+999)/1000; /* Raw: linearize_channel */
	s64 a = extra_half->known_min.millisatoshis/1000, /* Raw: linearize_channel */
	    b = 1 + extra_half->known_max.millisatoshis/1000; /* Raw: linearize_channel */

	/* If HTLCs add up to more than the known_max it means we have a
	 * completely wrong knowledge. */
	// assert(h<b);
	/* HTLCs allocated could instead be greater than known_min, we enter in
	 * the uncertainty region. If h>a it doesn't mean automatically that our
	 * known_min should have been updated, because we reserve this HTLC
	 * after sendpay behind the scenes it might happen that sendpay failed
	 * because of insufficient funds we haven't noticed yet. */
	// assert(h<=a);

	/* We reduce this channel capacity because HTLC are reserving liquidity. */
	a -= h;
	b -= h;
	a = MAX(a,0);
	b = MAX(a+1,b);

	/* An extra bound on capacity, here we use it to reduce the flow such
	 * that it does not exceed htlcmax. */
	s64 cap_on_capacity =
	 gossmap_chan_htlc_max(c, dir).millisatoshis/1000; /* Raw: linearize_channel */

	capacity[0]=a;
	cost[0]=0;
	assert(params->base_probability > 5e-7);
	assert(params->base_probability <= 1.0);
	const double base_prob_factor = -log(params->base_probability);

	for(size_t i=1;i<CHANNEL_PARTS;++i)
	{
		capacity[i] = MIN(params->cap_fraction[i]*(b-a), cap_on_capacity);
		cap_on_capacity -= capacity[i];
		assert(cap_on_capacity>=0);

		cost[i] = (params->cost_fraction[i]*1.0/(b-a) + base_prob_factor)
		          *params->amount.millisatoshis /* Raw: linearize_channel */
		          *params->prob_cost_factor;
	}
	return true;
}

static struct residual_network *
alloc_residual_network(const tal_t *ctx, const size_t max_num_nodes,
		      const size_t max_num_arcs)
{
	struct residual_network *residual_network =
	    tal(ctx, struct residual_network);
	if (!residual_network)
		goto function_fail;

	residual_network->cap = tal_arrz(residual_network, s64, max_num_arcs);
	residual_network->cost = tal_arrz(residual_network, s64, max_num_arcs);
	residual_network->potential =
	    tal_arrz(residual_network, s64, max_num_nodes);

	if (!residual_network->cap || !residual_network->cost ||
	    !residual_network->potential) {
		goto function_fail;
	}
	return residual_network;

	function_fail:
	return tal_free(residual_network);
}

static void init_residual_network(
		const struct linear_network * linear_network,
		struct residual_network* residual_network)
{
	const size_t max_num_arcs = linear_network->max_num_arcs;
	const size_t max_num_nodes = linear_network->max_num_nodes;

	for(struct arc arc = {0};arc.idx < max_num_arcs; ++arc.idx)
	{
		if(arc_is_dual(arc))
			continue;

		struct arc dual = arc_dual(arc);
		residual_network->cap[arc.idx]=linear_network->capacity[arc.idx];
		residual_network->cap[dual.idx]=0;

		residual_network->cost[arc.idx]=residual_network->cost[dual.idx]=0;
	}
	for(u32 i=0;i<max_num_nodes;++i)
	{
		residual_network->potential[i]=0;
	}
}

static void combine_cost_function(
		const struct linear_network* linear_network,
		struct residual_network *residual_network,
		s64 mu)
{
	for(struct arc arc = {0};arc.idx < linear_network->max_num_arcs; ++arc.idx)
	{
		if(arc_tail(linear_network,arc)==INVALID_INDEX)
			continue;

		const s64 pcost = linear_network->arc_prob_cost[arc.idx],
		          fcost = linear_network->arc_fee_cost[arc.idx];

		const s64 combined = pcost==INFINITE || fcost==INFINITE ? INFINITE :
		                     mu*fcost + (MU_MAX-1-mu)*pcost;

		residual_network->cost[arc.idx]
			= mu==0 ? pcost :
			          (mu==(MU_MAX-1) ? fcost : combined);
	}
}

static void linear_network_add_adjacenct_arc(
		struct linear_network *linear_network,
		const u32 node_idx,
		const struct arc arc)
{
	assert(arc.idx < tal_count(linear_network->arc_tail_node));
	linear_network->arc_tail_node[arc.idx] = node_idx;

	assert(node_idx < tal_count(linear_network->node_adjacency_first_arc));
	const struct arc first_arc = linear_network->node_adjacency_first_arc[node_idx];

	assert(arc.idx < tal_count(linear_network->node_adjacency_next_arc));
	linear_network->node_adjacency_next_arc[arc.idx]=first_arc;

	assert(node_idx < tal_count(linear_network->node_adjacency_first_arc));
	linear_network->node_adjacency_first_arc[node_idx]=arc;
}

/* Get the fee cost associated to this directed channel.
 * Cost is expressed as PPM of the payment.
 *
 * Choose and integer `c_fee` to linearize the following fee function
 *
 *  	fee_msat = base_msat + floor(millionths*x_msat / 10^6)
 *
 * into
 *
 *  	fee_microsat = c_fee * x_sat
 *
 *  use `base_fee_penalty` to weight the base fee and `delay_feefactor` to
 *  weight the CLTV delay.
 *  */
static s64 linear_fee_cost(
		const struct gossmap_chan *c,
		const int dir,
		double base_fee_penalty,
		double delay_feefactor)
{
	assert(c);
	assert(dir==0 || dir==1);
	s64 pfee = c->half[dir].proportional_fee,
	    bfee = c->half[dir].base_fee,
	    delay = c->half[dir].delay;

	return pfee + bfee* base_fee_penalty+ delay*delay_feefactor;
}

static struct linear_network *
init_linear_network(const tal_t *ctx, const struct pay_parameters *params,
		    char **fail)
{
	tal_t *this_ctx = tal(ctx,tal_t);

	struct linear_network * linear_network = tal(ctx, struct linear_network);
	if (!linear_network) {
		if (fail)
		*fail = tal_fmt(ctx, "bad allocation of linear_network");
		goto function_fail;
	}

	const size_t max_num_chans = gossmap_max_chan_idx(params->gossmap);
	const size_t max_num_arcs = max_num_chans * ARCS_PER_CHANNEL;
	const size_t max_num_nodes = gossmap_max_node_idx(params->gossmap);

	linear_network->max_num_arcs = max_num_arcs;
	linear_network->max_num_nodes = max_num_nodes;

	linear_network->arc_tail_node = tal_arr(linear_network,u32,max_num_arcs);
	if(!linear_network->arc_tail_node)
	{
		if (fail)
		*fail = tal_fmt(ctx, "bad allocation of arc_tail_node");
		goto function_fail;
	}
	for(size_t i=0;i<tal_count(linear_network->arc_tail_node);++i)
		linear_network->arc_tail_node[i]=INVALID_INDEX;

	linear_network->node_adjacency_next_arc = tal_arr(linear_network,struct arc,max_num_arcs);
	if(!linear_network->node_adjacency_next_arc)
	{
		if (fail)
		*fail = tal_fmt(ctx, "bad allocation of node_adjacency_next_arc");
		goto function_fail;
	}
	for(size_t i=0;i<tal_count(linear_network->node_adjacency_next_arc);++i)
		linear_network->node_adjacency_next_arc[i].idx=INVALID_INDEX;

	linear_network->node_adjacency_first_arc = tal_arr(linear_network,struct arc,max_num_nodes);
	if(!linear_network->node_adjacency_first_arc)
	{
		if (fail)
		*fail = tal_fmt(ctx, "bad allocation of node_adjacency_first_arc");
		goto function_fail;
	}
	for(size_t i=0;i<tal_count(linear_network->node_adjacency_first_arc);++i)
		linear_network->node_adjacency_first_arc[i].idx=INVALID_INDEX;

	linear_network->arc_prob_cost = tal_arr(linear_network,s64,max_num_arcs);
	if(!linear_network->arc_prob_cost)
	{
		if (fail)
		*fail = tal_fmt(ctx, "bad allocation of arc_prob_cost");
		goto function_fail;
	}
	for(size_t i=0;i<tal_count(linear_network->arc_prob_cost);++i)
		linear_network->arc_prob_cost[i]=INFINITE;

	linear_network->arc_fee_cost = tal_arr(linear_network,s64,max_num_arcs);
	if(!linear_network->arc_fee_cost)
	{
		if (fail)
		*fail = tal_fmt(ctx, "bad allocation of arc_fee_cost");
		goto function_fail;
	}
	for(size_t i=0;i<tal_count(linear_network->arc_fee_cost);++i)
		linear_network->arc_fee_cost[i]=INFINITE;

	linear_network->capacity = tal_arrz(linear_network,s64,max_num_arcs);
	if(!linear_network->capacity)
	{
		if (fail)
		*fail = tal_fmt(ctx, "bad allocation of capacity");
		goto function_fail;
	}

	for(struct gossmap_node *node = gossmap_first_node(params->gossmap);
	    node;
	    node=gossmap_next_node(params->gossmap,node))
	{
		const u32 node_id = gossmap_node_idx(params->gossmap,node);

		for(size_t j=0;j<node->num_chans;++j)
		{
			int half;
			const struct gossmap_chan *c = gossmap_nth_chan(params->gossmap,
			                                                node, j, &half);

			if (!channel_is_available(c, half, params->gossmap,
						  params->disabled))
				continue;

			const u32 chan_id = gossmap_chan_idx(params->gossmap, c);

			const struct gossmap_node *next = gossmap_nth_node(params->gossmap,
									   c,!half);

			const u32 next_id = gossmap_node_idx(params->gossmap,next);

			if(node_id==next_id)
				continue;

			// `cost` is the word normally used to denote cost per
			// unit of flow in the context of MCF.
			s64 prob_cost[CHANNEL_PARTS], capacity[CHANNEL_PARTS];

			// split this channel direction to obtain the arcs
			// that are outgoing to `node`
			if (!linearize_channel(params, c, half,
					       capacity, prob_cost)) {
				if(fail)
				*fail =
				    tal_fmt(ctx, "linearize_channel failed");
				goto function_fail;
			}

			const s64 fee_cost = linear_fee_cost(c,half,
						params->base_fee_penalty,
						params->delay_feefactor);

			// let's subscribe the 4 parts of the channel direction
			// (c,half), the dual of these guys will be subscribed
			// when the `i` hits the `next` node.
			for(size_t k=0;k<CHANNEL_PARTS;++k)
			{
				// if(capacity[k]==0)continue;

				struct arc arc = arc_from_parts(chan_id, half, k, false);

				linear_network_add_adjacenct_arc(linear_network,node_id,arc);

				linear_network->capacity[arc.idx] = capacity[k];
				linear_network->arc_prob_cost[arc.idx] = prob_cost[k];

				linear_network->arc_fee_cost[arc.idx] = fee_cost;

				// + the respective dual
				struct arc dual = arc_dual(arc);

				linear_network_add_adjacenct_arc(linear_network,next_id,dual);

				linear_network->capacity[dual.idx] = 0;
				linear_network->arc_prob_cost[dual.idx] = -prob_cost[k];

				linear_network->arc_fee_cost[dual.idx] = -fee_cost;
			}
		}
	}

	tal_free(this_ctx);
	return linear_network;

	function_fail:
	tal_free(this_ctx);
	return tal_free(linear_network);
}

/* Simple queue to traverse the network. */
struct queue_data
{
	u32 idx;
	struct lqueue_link ql;
};

// TODO(eduardo): unit test this
/* Finds an admissible path from source to target, traversing arcs in the
 * residual network with capacity greater than 0.
 * The path is encoded into prev, which contains the idx of the arcs that are
 * traversed. */
static bool
find_admissible_path(const tal_t *ctx,
		     const struct linear_network *linear_network,
		     const struct residual_network *residual_network,
		     const u32 source, const u32 target, struct arc *prev)
{
	tal_t *this_ctx = tal(ctx,tal_t);

	bool target_found = false;

	for(size_t i=0;i<tal_count(prev);++i)
		prev[i].idx=INVALID_INDEX;

	// The graph is dense, and the farthest node is just a few hops away,
	// hence let's BFS search.
	LQUEUE(struct queue_data,ql) myqueue = LQUEUE_INIT;
	struct queue_data *qdata;

	qdata = tal(this_ctx,struct queue_data);
	qdata->idx = source;
	lqueue_enqueue(&myqueue,qdata);

	while(!lqueue_empty(&myqueue))
	{
		qdata = lqueue_dequeue(&myqueue);
		u32 cur = qdata->idx;

		tal_free(qdata);

		if(cur==target)
		{
			target_found = true;
			break;
		}

		for(struct arc arc = node_adjacency_begin(linear_network,cur);
		        !node_adjacency_end(arc);
			arc = node_adjacency_next(linear_network,arc))
		{
			// check if this arc is traversable
			if(residual_network->cap[arc.idx] <= 0)
				continue;

			u32 next = arc_head(linear_network,arc);

			assert(next < tal_count(prev));

			// if that node has been seen previously
			if(prev[next].idx!=INVALID_INDEX)
				continue;

			prev[next] = arc;

			qdata = tal(this_ctx,struct queue_data);
			qdata->idx = next;
			lqueue_enqueue(&myqueue,qdata);
		}
	}
	tal_free(this_ctx);
	return target_found;
}

/* Get the max amount of flow one can send from source to target along the path
 * encoded in `prev`. */
static s64 get_augmenting_flow(
		const struct linear_network* linear_network,
		const struct residual_network *residual_network,
	        const u32 source,
		const u32 target,
		const struct arc *prev)
{
	s64 flow = INFINITE;

	u32 cur = target;
	while(cur!=source)
	{
		assert(cur<tal_count(prev));
		const struct arc arc = prev[cur];
		flow = MIN(flow , residual_network->cap[arc.idx]);

		// we are traversing in the opposite direction to the flow,
		// hence the next node is at the tail of the arc.
		cur = arc_tail(linear_network,arc);
	}

	assert(flow<INFINITE && flow>0);
	return flow;
}

/* Augment a `flow` amount along the path defined by `prev`.*/
static void augment_flow(
		const struct linear_network *linear_network,
		struct residual_network *residual_network,
	        const u32 source,
		const u32 target,
		const struct arc *prev,
		s64 flow)
{
	u32 cur = target;

	while(cur!=source)
	{
		assert(cur < tal_count(prev));
		const struct arc arc = prev[cur];
		const struct arc dual = arc_dual(arc);

		assert(arc.idx < tal_count(residual_network->cap));
		assert(dual.idx < tal_count(residual_network->cap));

		residual_network->cap[arc.idx] -= flow;
		residual_network->cap[dual.idx] += flow;

		assert(residual_network->cap[arc.idx] >=0 );

		// we are traversing in the opposite direction to the flow,
		// hence the next node is at the tail of the arc.
		cur = arc_tail(linear_network,arc);
	}
}


// TODO(eduardo): unit test this
/* Finds any flow that satisfy the capacity and balance constraints of the
 * uncertainty network. For the balance function condition we have:
 * 	balance(source) = - balance(target) = amount
 * 	balance(node) = 0 , for every other node
 * Returns an error code if no feasible flow is found.
 *
 * 13/04/2023 This implementation uses a simple augmenting path approach.
 * */
static bool find_feasible_flow(const tal_t *ctx,
			       const struct linear_network *linear_network,
			       struct residual_network *residual_network,
			       const u32 source, const u32 target, s64 amount,
			       char **fail)
{
	assert(amount>=0);
	tal_t *this_ctx = tal(ctx,tal_t);

	/* path information
	 * prev: is the id of the arc that lead to the node. */
	struct arc *prev = tal_arr(this_ctx,struct arc,linear_network->max_num_nodes);
	if(!prev)
	{
		if(fail)
		*fail = tal_fmt(ctx, "bad allocation of prev");
		goto function_fail;
	}

	while(amount>0)
	{
		// find a path from source to target
		if (!find_admissible_path(this_ctx, linear_network,
					  residual_network, source, target,
					  prev))

		{
			if(fail)
			*fail = tal_fmt(ctx, "find_admissible_path failed");
			goto function_fail;
		}

		// traverse the path and see how much flow we can send
		s64 delta = get_augmenting_flow(linear_network,
						residual_network,
						source,target,prev);

		// commit that flow to the path
		delta = MIN(amount,delta);
		assert(delta>0 && delta<=amount);

		augment_flow(linear_network,residual_network,source,target,prev,delta);
		amount -= delta;
	}

	tal_free(this_ctx);
	return true;

	function_fail:
	tal_free(this_ctx);
	return false;
}

// TODO(eduardo): unit test this
/* Similar to `find_admissible_path` but use Dijkstra to optimize the distance
 * label. Stops when the target is hit. */
static bool find_optimal_path(const tal_t *ctx, struct dijkstra *dijkstra,
			      const struct linear_network *linear_network,
			      const struct residual_network *residual_network,
			      const u32 source, const u32 target,
			      struct arc *prev, char **fail)
{
	tal_t *this_ctx = tal(ctx,tal_t);
	bool target_found = false;

	bitmap *visited = tal_arrz(this_ctx, bitmap,
					BITMAP_NWORDS(linear_network->max_num_nodes));

	if(!visited)
	{
		if(fail)
		*fail = tal_fmt(ctx, "bad allocation of visited");
		goto finish;
	}


	for(size_t i=0;i<tal_count(prev);++i)
		prev[i].idx=INVALID_INDEX;

	const s64 *const distance=dijkstra_distance_data(dijkstra);

	dijkstra_init(dijkstra);
	dijkstra_update(dijkstra,source,0);

	while(!dijkstra_empty(dijkstra))
	{
		u32 cur = dijkstra_top(dijkstra);
		dijkstra_pop(dijkstra);

		if(bitmap_test_bit(visited,cur))
			continue;

		bitmap_set_bit(visited,cur);

		if(cur==target)
		{
			target_found = true;
			break;
		}

		for(struct arc arc = node_adjacency_begin(linear_network,cur);
		        !node_adjacency_end(arc);
			arc = node_adjacency_next(linear_network,arc))
		{
			// check if this arc is traversable
			if(residual_network->cap[arc.idx] <= 0)
				continue;

			u32 next = arc_head(linear_network,arc);

			s64 cij = residual_network->cost[arc.idx]
					- residual_network->potential[cur]
					+ residual_network->potential[next];

			// Dijkstra only works with non-negative weights
			assert(cij>=0);

			if(distance[next]<=distance[cur]+cij)
				continue;

			dijkstra_update(dijkstra,next,distance[cur]+cij);
			prev[next]=arc;
		}
	}

	if (!target_found && fail)
		*fail = tal_fmt(ctx, "no route to destination");

	finish:
	tal_free(this_ctx);
	return target_found;
}

/* Set zero flow in the residual network. */
static void zero_flow(
		const struct linear_network *linear_network,
		struct residual_network *residual_network)
{
	for(u32 node=0;node<linear_network->max_num_nodes;++node)
	{
		residual_network->potential[node]=0;
		for(struct arc arc=node_adjacency_begin(linear_network,node);
			  !node_adjacency_end(arc);
			  arc = node_adjacency_next(linear_network,arc))
		{
			if(arc_is_dual(arc))continue;

			struct arc dual = arc_dual(arc);

			residual_network->cap[arc.idx] = linear_network->capacity[arc.idx];
			residual_network->cap[dual.idx] = 0;
		}
	}
}

// TODO(eduardo): unit test this
/* Starting from a feasible flow (satisfies the balance and capacity
 * constraints), find a solution that minimizes the network->cost function.
 *
 * TODO(eduardo) The MCF must be called several times until we get a good
 * compromise between fees and probabilities. Instead of re-computing the MCF at
 * each step, we might use the previous flow result, which is not optimal in the
 * current iteration but I might be not too far from the truth.
 * It comes to mind to use cycle cancelling. */
static bool optimize_mcf(const tal_t *ctx, struct dijkstra *dijkstra,
			 const struct linear_network *linear_network,
			 struct residual_network *residual_network,
			 const u32 source, const u32 target, const s64 amount,
			 char **fail)
{
	assert(amount>=0);
	tal_t *this_ctx = tal(ctx,tal_t);
	char *errmsg;

	zero_flow(linear_network,residual_network);
	struct arc *prev = tal_arr(this_ctx,struct arc,linear_network->max_num_nodes);

	const s64 *const distance = dijkstra_distance_data(dijkstra);

	s64 remaining_amount = amount;

	while(remaining_amount>0)
	{
		if (!find_optimal_path(this_ctx, dijkstra, linear_network,
				       residual_network, source, target, prev,
				       &errmsg)) {
			if (fail)
			*fail =
			    tal_fmt(ctx, "find_optimal_path failed: %s",
				    errmsg);
			goto function_fail;
		}

		// traverse the path and see how much flow we can send
		s64 delta = get_augmenting_flow(linear_network,residual_network,source,target,prev);

		// commit that flow to the path
		delta = MIN(remaining_amount,delta);
		assert(delta>0 && delta<=remaining_amount);

		augment_flow(linear_network,residual_network,source,target,prev,delta);
		remaining_amount -= delta;

		// update potentials
		for(u32 n=0;n<linear_network->max_num_nodes;++n)
		{
			// see page 323 of Ahuja-Magnanti-Orlin
			residual_network->potential[n] -= MIN(distance[target],distance[n]);

			/* Notice:
			 * if node i is permanently labeled we have
			 * 	d_i<=d_t
			 * which implies
			 * 	MIN(d_i,d_t) = d_i
			 * if node i is temporarily labeled we have
			 * 	d_i>=d_t
			 * which implies
			 * 	MIN(d_i,d_t) = d_t
			 * */
		}
	}
	tal_free(this_ctx);
	return true;

	function_fail:

	tal_free(this_ctx);
	return false;
}

// flow on directed channels
struct chan_flow
{
	s64 half[2];
};

/* Search in the network a path of positive flow until we reach a node with
 * positive balance. */
static u32 find_positive_balance(
		const struct gossmap *gossmap,
		const bitmap *disabled,
		const struct chan_flow *chan_flow,
		const u32 start_idx,
		const s64 *balance,

		const struct gossmap_chan **prev_chan,
		int *prev_dir,
		u32 *prev_idx)
{
	u32 final_idx = start_idx;

	/* TODO(eduardo)
	 * This is guaranteed to halt if there are no directed flow cycles.
	 * There souldn't be any. In fact if cost is strickly
	 * positive, then flow cycles do not exist at all in the
	 * MCF solution. But if cost is allowed to be zero for
	 * some arcs, then we might have flow cyles in the final
	 * solution. We must somehow ensure that the MCF
	 * algorithm does not come up with spurious flow cycles. */
	while(balance[final_idx]<=0)
	{
		// printf("%s: node = %d\n",__func__,final_idx);
		u32 updated_idx=INVALID_INDEX;
		struct gossmap_node *cur
			= gossmap_node_byidx(gossmap,final_idx);

		for(size_t i=0;i<cur->num_chans;++i)
		{
			int dir;
			const struct gossmap_chan *c
				= gossmap_nth_chan(gossmap,
				                   cur,i,&dir);

			if (!channel_is_available(c, dir, gossmap, disabled))
				continue;

			const u32 c_idx = gossmap_chan_idx(gossmap,c);

			// follow the flow
			if(chan_flow[c_idx].half[dir]>0)
			{
				const struct gossmap_node *next
					= gossmap_nth_node(gossmap,c,!dir);
				u32 next_idx = gossmap_node_idx(gossmap,next);


				prev_dir[next_idx] = dir;
				prev_chan[next_idx] = c;
				prev_idx[next_idx] = final_idx;

				updated_idx = next_idx;
				break;
			}
		}

		assert(updated_idx!=INVALID_INDEX);
		assert(updated_idx!=final_idx);

		final_idx = updated_idx;
	}
	return final_idx;
}

struct list_data
{
	struct list_node list;
	struct flow *flow_path;
};

static inline uint64_t pseudorand_interval(uint64_t a, uint64_t b)
{
	if (a == b)
		return b;
	assert(b > a);
	return a + pseudorand(b - a);
}

/* Given a flow in the residual network, build a set of payment flows in the
 * gossmap that corresponds to this flow. */
static struct flow **
get_flow_paths(const tal_t *ctx, const struct gossmap *gossmap,
	       const bitmap *disabled,

	       // chan_extra_map cannot be const because we use it to keep
	       // track of htlcs and in_flight sats.
	       struct chan_extra_map *chan_extra_map,
	       const struct linear_network *linear_network,
	       const struct residual_network *residual_network,

	       // how many msats in excess we paid for not having msat accuracy
	       // in the MCF solver
	       struct amount_msat excess,
	       const double base_probability,

	       // error message
	       char **fail)
{
	tal_t *this_ctx = tal(ctx,tal_t);
	struct flow **flows = tal_arr(ctx,struct flow*,0);

	assert(amount_msat_less(excess, AMOUNT_MSAT(1000)));

	const size_t max_num_chans = gossmap_max_chan_idx(gossmap);
	struct chan_flow *chan_flow = tal_arrz(this_ctx,struct chan_flow,max_num_chans);

	const size_t max_num_nodes = gossmap_max_node_idx(gossmap);
	s64 *balance = tal_arrz(this_ctx,s64,max_num_nodes);

	const struct gossmap_chan **prev_chan
		= tal_arr(this_ctx,const struct gossmap_chan *,max_num_nodes);


	int *prev_dir = tal_arr(this_ctx,int,max_num_nodes);
	u32 *prev_idx = tal_arr(this_ctx,u32,max_num_nodes);

	if (!chan_flow || !balance || !prev_chan || !prev_idx || !prev_dir) {
		if (fail)
		*fail = tal_fmt(ctx, "bad allocation");
		goto function_fail;
	}

	// Convert the arc based residual network flow into a flow in the
	// directed channel network.
	// Compute balance on the nodes.
	for(u32 n = 0;n<max_num_nodes;++n)
	{
		for(struct arc arc = node_adjacency_begin(linear_network,n);
		        !node_adjacency_end(arc);
			arc = node_adjacency_next(linear_network,arc))
		{
			if(arc_is_dual(arc))
				continue;
			u32 m = arc_head(linear_network,arc);
			s64 flow = get_arc_flow(residual_network,arc);
			u32 chanidx;
			int chandir;

			balance[n] -= flow;
			balance[m] += flow;

			arc_to_parts(arc, &chanidx, &chandir, NULL, NULL);
			chan_flow[chanidx].half[chandir] +=flow;
		}

	}


	// Select all nodes with negative balance and find a flow that reaches a
	// positive balance node.
	for(u32 node_idx=0;node_idx<max_num_nodes;++node_idx)
	{
		// for(size_t i=0;i<tal_count(prev_idx);++i)
		// {
		// 	prev_idx[i]=INVALID_INDEX;
		// }
		// this node has negative balance, flows leaves from here
		while(balance[node_idx]<0)
		{
			prev_chan[node_idx]=NULL;
			u32 final_idx = find_positive_balance(
			    gossmap, disabled, chan_flow, node_idx, balance,
			    prev_chan, prev_dir, prev_idx);

			/* For each route we will compute the highest htlc_min
			 * and the smallest htlc_max and use those to constraint
			 * the flow we will allocate. */
			struct amount_msat sup_htlc_min = AMOUNT_MSAT_INIT(0),
					   inf_htlc_max =
					       AMOUNT_MSAT_INIT(INFINITE_MSAT);

			s64 delta=-balance[node_idx];
			int length = 0;
			delta = MIN(delta,balance[final_idx]);

			// walk backwards, get me the length and the max flow we
			// can send.
			for(u32 cur_idx = final_idx;
			    cur_idx!=node_idx;
			    cur_idx=prev_idx[cur_idx])
			{
				assert(cur_idx!=INVALID_INDEX);

				const int dir = prev_dir[cur_idx];
				const struct gossmap_chan *const c = prev_chan[cur_idx];
				const u32 c_idx = gossmap_chan_idx(gossmap,c);

				delta=MIN(delta,chan_flow[c_idx].half[dir]);
				length++;

				/* obtain the supremum htlc_min along the route
				 */
				sup_htlc_min = amount_msat_max(
				    sup_htlc_min, gossmap_chan_htlc_min(c, dir));

				/* obtain the infimum htlc_max along the route
				 */
				inf_htlc_max = amount_msat_min(
				    inf_htlc_max, gossmap_chan_htlc_max(c, dir));
			}

			s64 htlc_max=inf_htlc_max.millisatoshis/1000;/* Raw: need htlc_max in sats to do arithmetic operations.*/
			s64 htlc_min=(sup_htlc_min.millisatoshis+999)/1000;/* Raw: need htlc_min in sats to do arithmetic operations.*/

			if (htlc_min > htlc_max) {
				/* htlc_min is too big or htlc_max is too small,
				 * we cannot send `delta` along this route.
				 *
				 * FIXME: We try anyways because failing
				 * channels will be blacklisted downstream. */
				htlc_min = 0;
			}

			/* If we divide this route into different flows make it
			 * random to avoid routing nodes making correlations. */
			if (delta > htlc_max) {
				// FIXME: choosing a number in the range
				// [htlc_min, htlc_max] or
				// [0.5 htlc_max, htlc_max]
				// The choice of the fraction was completely
				// arbitrary.
				delta = pseudorand_interval(
				    MAX(htlc_min, (htlc_max * 50) / 100),
				    htlc_max);
			}

			struct flow *fp = tal(this_ctx,struct flow);
			fp->path = tal_arr(fp,const struct gossmap_chan *,length);
			fp->dirs = tal_arr(fp,int,length);

			balance[node_idx] += delta;
			balance[final_idx]-= delta;

			// walk backwards, substract flow
			for(u32 cur_idx = final_idx;
			    cur_idx!=node_idx;
			    cur_idx=prev_idx[cur_idx])
			{
				assert(cur_idx!=INVALID_INDEX);

				const int dir = prev_dir[cur_idx];
				const struct gossmap_chan *const c = prev_chan[cur_idx];
				const u32 c_idx = gossmap_chan_idx(gossmap,c);

				length--;
				fp->path[length]=c;
				fp->dirs[length]=dir;
				// notice: fp->path and fp->dirs have the path
				// in the correct order.

				chan_flow[c_idx].half[prev_dir[cur_idx]]-=delta;
			}

			assert(delta>0);

			// substract the excess of msats for not having msat
			// accuracy
			struct amount_msat delivered = amount_msat(delta*1000);
			if (!amount_msat_deduct(&delivered, excess)) {
				if (fail)
				*fail = tal_fmt(
				    ctx, "unable to substract excess");
				goto function_fail;
			}
			excess = amount_msat(0);
			fp->amount = delivered;

			fp->success_prob =
			    flow_probability(fp, gossmap, chan_extra_map, false)
			    * pow(base_probability, tal_count(fp->path));
			if (fp->success_prob < 0) {
				if (fail)
					*fail =
					    tal_fmt(ctx, "failed to compute "
							 "flow probability");
				goto function_fail;
			}

			// add fp to flows
			tal_arr_expand(&flows, fp);
		}
	}

	/* Establish ownership. */
	for(size_t i=0;i<tal_count(flows);++i)
	{
		flows[i] = tal_steal(flows,flows[i]);
		assert(flows[i]);
	}
	if (fail)
		*fail = NULL;
	tal_free(this_ctx);
	return flows;

	function_fail:
	tal_free(this_ctx);
	return tal_free(flows);
}

/* Given the constraints on max fee and min prob.,
 * is the flow A better than B? */
static bool is_better(
		struct amount_msat max_fee,
		double min_probability,

		struct amount_msat A_fee,
		double A_prob,

		struct amount_msat B_fee,
		double B_prob)
{
	bool A_fee_pass = amount_msat_less_eq(A_fee,max_fee);
	bool B_fee_pass = amount_msat_less_eq(B_fee,max_fee);
	bool A_prob_pass = A_prob >= min_probability;
	bool B_prob_pass = B_prob >= min_probability;

	// all bounds are met
	if(A_fee_pass && B_fee_pass && A_prob_pass && B_prob_pass)
	{
		// prefer lower fees
		goto fees_or_prob;
	}

	// prefer the solution that satisfies both bounds
	if(!(A_fee_pass && A_prob_pass) && (B_fee_pass && B_prob_pass))
	{
		return false;
	}
	// prefer the solution that satisfies both bounds
	if((A_fee_pass && A_prob_pass) && !(B_fee_pass && B_prob_pass))
	{
		return true;
	}

	// no solution satisfies both bounds

	// bound on fee is met
	if(A_fee_pass && B_fee_pass)
	{
		// pick the highest prob.
		return A_prob > B_prob;
	}

	// bound on prob. is met
	if(A_prob_pass && B_prob_pass)
	{
		goto fees_or_prob;
	}

	// prefer the solution that satisfies the bound on fees
	if(A_fee_pass && !B_fee_pass)
	{
		return true;
	}
	if(B_fee_pass && !A_fee_pass)
	{
		return false;
	}

	// none of them satisfy the fee bound

	// prefer the solution that satisfies the bound on prob.
	if(A_prob_pass && !B_prob_pass)
	{
		return true;
	}
	if(B_prob_pass && !A_prob_pass)
	{
		return true;
	}

	// no bound whatsoever is satisfied

	fees_or_prob:

	// fees are the same, wins the highest prob.
	if(amount_msat_eq(A_fee,B_fee))
	{
		return A_prob > B_prob;
	}

	// go for fees
	return amount_msat_less_eq(A_fee,B_fee);
}

/* Channels that are not in the chan_extra_map should be disabled. */
static bool check_disabled(const bitmap *disabled,
			   const struct gossmap *gossmap,
			   const struct chan_extra_map *chan_extra_map)
{
	assert(disabled);
	assert(gossmap);
	assert(chan_extra_map);

	if (tal_bytelen(disabled) !=
	    2 * bitmap_sizeof(gossmap_max_chan_idx(gossmap)))
		return false;

	for (struct gossmap_chan *chan = gossmap_first_chan(gossmap); chan;
	     chan = gossmap_next_chan(gossmap, chan)) {
		const u32 chan_idx = gossmap_chan_idx(gossmap, chan);
		/* If both directions are disabled anyways, there is no need to
		 * fetch their information in chan_extra. */
		if (bitmap_test_bit(disabled, chan_idx * 2 + 0) &&
		    bitmap_test_bit(disabled, chan_idx * 2 + 1))
			continue;

		struct short_channel_id scid = gossmap_chan_scid(gossmap, chan);
		struct chan_extra *ce =
		    chan_extra_map_get(chan_extra_map, scid);
		if (!ce)
			return false;
	}
	return true;
}

// TODO(eduardo): choose some default values for the minflow parameters
/* eduardo: I think it should be clear that this module deals with linear
 * flows, ie. base fees are not considered. Hence a flow along a path is
 * described with a sequence of directed channels and one amount.
 * In the `pay_flow` module there are dedicated routes to compute the actual
 * amount to be forward on each hop.
 *
 * TODO(eduardo): notice that we don't pay fees to forward payments with local
 * channels and we can tell with absolute certainty the liquidity on them.
 * Check that local channels have fee costs = 0 and bounds with certainty (min=max). */
// TODO(eduardo): we should LOG_DBG the process of finding the MCF while
// adjusting the frugality factor.
struct flow **minflow(const tal_t *ctx, struct gossmap *gossmap,
		      const struct gossmap_node *source,
		      const struct gossmap_node *target,
		      struct chan_extra_map *chan_extra_map,
		      const bitmap *disabled, struct amount_msat amount,
		      struct amount_msat max_fee, double min_probability,
		      double base_probability,
		      double delay_feefactor, double base_fee_penalty,
		      u32 prob_cost_factor, char **fail)
{
	tal_t *this_ctx = tal(ctx,tal_t);
	char *errmsg;
	struct flow **best_flow_paths = NULL;

	struct pay_parameters *params = tal(this_ctx,struct pay_parameters);
	struct dijkstra *dijkstra;

	params->gossmap = gossmap;
	params->source = source;
	params->target = target;
	params->chan_extra_map = chan_extra_map;

	params->disabled = disabled;

	if (!check_disabled(disabled, gossmap, chan_extra_map)) {
		if (fail)
			*fail = tal_fmt(ctx, "Invalid disabled bitmap.");
		goto function_fail;
	}

	params->amount = amount;

	// template the channel partition into linear arcs
	params->cap_fraction[0]=0;
	params->cost_fraction[0]=0;
	for(size_t i =1;i<CHANNEL_PARTS;++i)
	{
		params->cap_fraction[i]=CHANNEL_PIVOTS[i]-CHANNEL_PIVOTS[i-1];
		params->cost_fraction[i]=
			log((1-CHANNEL_PIVOTS[i-1])/(1-CHANNEL_PIVOTS[i]))
			/params->cap_fraction[i];

		// printf("channel part: %ld, fraction: %lf, cost_fraction: %lf\n",
		//	i,params->cap_fraction[i],params->cost_fraction[i]);
	}

	params->max_fee = max_fee;
	params->min_probability = min_probability;
	params->delay_feefactor = delay_feefactor;
	params->base_fee_penalty = base_fee_penalty;
	params->prob_cost_factor = prob_cost_factor;
	params->base_probability = base_probability;

	// build the uncertainty network with linearization and residual arcs
	struct linear_network *linear_network= init_linear_network(this_ctx, params, &errmsg);
	if (!linear_network) {
		if(fail)
		*fail = tal_fmt(ctx, "init_linear_network failed: %s",
				errmsg);
		goto function_fail;
	}

	struct residual_network *residual_network =
	    alloc_residual_network(this_ctx, linear_network->max_num_nodes,
				  linear_network->max_num_arcs);
	if (!residual_network) {
		if (fail)
		*fail = tal_fmt(
		    ctx, "failed to allocate the residual network");
		goto function_fail;
	}

	dijkstra = dijkstra_new(this_ctx, gossmap_max_node_idx(params->gossmap));

	const u32 target_idx = gossmap_node_idx(params->gossmap,target);
	const u32 source_idx = gossmap_node_idx(params->gossmap,source);

	init_residual_network(linear_network,residual_network);

	struct amount_msat best_fee;
	double best_prob_success;

	/* TODO(eduardo):
	 * Some MCF algorithms' performance depend on the size of maxflow. If we
	 * were to work in units of msats we 1. risking overflow when computing
	 * costs and 2. we risk a performance overhead for no good reason.
	 *
	 * Working in units of sats was my first choice, but maybe working in
	 * units of 10, or 100 sats could be even better.
	 *
	 * IDEA: define the size of our precision as some parameter got at
	 * runtime that depends on the size of the payment and adjust the MCF
	 * accordingly.
	 * For example if we are trying to pay 1M sats our precision could be
	 * set to 1000sat, then channels that had capacity for 3M sats become 3k
	 * flow units. */
	const u64 pay_amount_msats = params->amount.millisatoshis % 1000; /* Raw: minflow */
	const u64 pay_amount_sats = params->amount.millisatoshis/1000 /* Raw: minflow */
			+ (pay_amount_msats ? 1 : 0);
	const struct amount_msat excess
		= amount_msat(pay_amount_msats ? 1000 - pay_amount_msats : 0);

	if (!find_feasible_flow(this_ctx, linear_network, residual_network,
				source_idx, target_idx, pay_amount_sats,
				&errmsg)) {
		// there is no flow that satisfy the constraints, we stop here
		if(fail)
		*fail = tal_fmt(ctx, "failed to find a feasible flow: %s", errmsg);
		goto function_fail;
	}

	// first flow found
	best_flow_paths = get_flow_paths(
	    this_ctx, params->gossmap, params->disabled, params->chan_extra_map,
	    linear_network, residual_network, excess, params->base_probability,
	    &errmsg);
	if (!best_flow_paths) {
		if (fail)
		*fail =
		    tal_fmt(ctx, "get_flow_paths failed: %s", errmsg);
		goto function_fail;
	}
	best_flow_paths = tal_steal(ctx, best_flow_paths);

	best_prob_success =
	    flowset_probability(this_ctx, best_flow_paths, params->gossmap,
				params->chan_extra_map, false, &errmsg)
	    * pow(params->base_probability, flowset_size(best_flow_paths));
	if (best_prob_success < 0) {
		if (fail)
			*fail = tal_fmt(
			    ctx,
			    "flowset_probability failed on MaxFlow phase: %s",
			    errmsg);
		goto function_fail;
	}
	if (!flowset_fee(&best_fee, best_flow_paths)) {
		if (fail)
		*fail =
		    tal_fmt(ctx, "flowset_fee failed on MaxFlow phase");
		goto function_fail;
	}

	// binary search for a value of `mu` that fits our fee and prob.
	// constraints.
	// mu=0 corresponds to only probabilities
	// mu=MU_MAX-1 corresponds to only fee
	s64 mu_left = 0, mu_right = MU_MAX;
	while(mu_left<mu_right)
	{

		s64 mu = (mu_left + mu_right)/2;

		combine_cost_function(linear_network,residual_network,mu);

		/* We solve a linear MCF problem. */
		if(!optimize_mcf(this_ctx, dijkstra,linear_network,residual_network,
				source_idx,target_idx,pay_amount_sats, &errmsg))
		{
			// optimize_mcf doesn't fail unless there is a bug.
			if (fail)
			*fail =
			    tal_fmt(ctx, "optimize_mcf failed: %s", errmsg);
			goto function_fail;
		}

		struct flow **flow_paths;
		/* We dissect the solution of the MCF into payment routes.
		 * Actual amounts considering fees are computed for every
		 * channel in the routes. */
		flow_paths =
		    get_flow_paths(this_ctx, params->gossmap, params->disabled,
				   params->chan_extra_map, linear_network,
				   residual_network, excess, params->base_probability,
				   &errmsg);
		if(!flow_paths)
		{
			// get_flow_paths doesn't fail unless there is a bug.
			if (fail)
			*fail =
			    tal_fmt(ctx, "get_flow_paths failed: %s", errmsg);
			goto function_fail;
		}

		double prob_success =
		    flowset_probability(this_ctx, flow_paths, params->gossmap,
					params->chan_extra_map, false, &errmsg)
		    * pow(params->base_probability, flowset_size(flow_paths));
		if (prob_success < 0) {
			// flowset_probability doesn't fail unless there is a bug.
			if (fail)
			*fail =
			    tal_fmt(ctx, "flowset_probability: %s", errmsg);
			goto function_fail;
		}

		struct amount_msat fee;
		if (!flowset_fee(&fee, flow_paths)) {
			// flowset_fee doesn't fail unless there is a bug.
			if (fail)
			*fail =
			    tal_fmt(ctx, "flowset_fee failed evaluating MinCostFlow candidate");
			goto function_fail;
		}

		/* Is this better than the previous one? */
		if(!best_flow_paths ||
			is_better(params->max_fee,params->min_probability,
				  fee,prob_success,
			          best_fee, best_prob_success))
		{

			best_flow_paths = tal_free(best_flow_paths);
			best_flow_paths = tal_steal(ctx,flow_paths);

			best_fee = fee;
			best_prob_success=prob_success;
			flow_paths = NULL;
		}
		/* I don't like this candidate. */
		else
			tal_free(flow_paths);

		if(amount_msat_greater(fee,params->max_fee))
		{
			// too expensive
			mu_left = mu+1;

		}else if(prob_success < params->min_probability)
		{
			// too unlikely
			mu_right = mu;
		}else
		{
			// with mu constraints are satisfied, now let's optimize
			// the fees
			mu_left = mu+1;
		}
	}

	tal_free(this_ctx);
	return best_flow_paths;

	function_fail:
	tal_free(this_ctx);
	return tal_free(best_flow_paths);
}

