+ /**
+ * @brief Set of debug functions to print the different objects
+ */
+ template <typename T> std::string debug_eigen(const T& obj) const;
+ template <typename C> std::string debug_vector(const C& container) const;
+ std::string debug_alloc(const allocation_map_t& alloc) const;
+
+ Eigen::MatrixXd A_; //!< A_ji: resource usage matrix, each row j represents a resource and col i a flow/player
+ Eigen::MatrixXd maxA_; //!< maxA_ji, similar as A_, but containing the maximum consumption of player i (if player a
+ //!< single flow it's equal to A_)
+ Eigen::VectorXd C_; //!< C_j Capacity of each resource
+ std::vector<bool> C_shared_; //!< shared_j Resource j is shared or not
+ Eigen::VectorXd phi_; //!< phi_i bound for each player
+
+ std::set<std::vector<int>> allocations_; //!< set of already tested allocations, since last identified loop
+ AllocationGenerator gen_;
+ static constexpr int NO_RESOURCE = -1; //!< flag to indicate player has selected no resource
+ int max_iteration_; //!< number maximum of iterations of BMF algorithm
+};
+
+/**
+ * @beginrst
+ *
+ * A BMF (bottleneck max fairness) solver to resolve inequation systems.
+ *
+ * Usually, SimGrid relies on a *max-min fairness* solver to share the resources.
+ * Max-min is great when sharing homogenous resources, however it cannot be used with heterogeneous resources.
+ *
+ * BMF is a natural alternative to max-min, providing a fair-sharing of heterogeneous resources (CPU, network, disk).
+ * It is specially relevant for the implementation of parallel tasks whose sharing involves different
+ * kinds of resources.
+ *
+ * BMF assures that every flow receives the maximum share possible in at least 1 bottleneck (fully used) resource.
+ *
+ * The BMF is characterized by:
+ * - A_ji: a matrix of requirement for flows/player. For each resource j, and flow i, A_ji represents the utilization
+ * of resource j for 1 unit of the flow i.
+ * - rho_i: the rate allocated for flow i (same among all resources)
+ * - C_j: the capacity of each resource (can be bytes/s, flops/s, etc)
+ *
+ * Therefore, these conditions need to satisfied to an allocation be considered a BMF:
+ * 1) All constraints are respected (flows cannot use more than the resource has available)
+ * - for all resource j and player i: A_ji * rho_i <= C_j
+ * 2) At least 1 resource is fully used (bottleneck).
+ * - for some resource j: A_ji * rho_i = C_j
+ * 3) Each flow (player) receives the maximum share in at least 1 bottleneck.
+ * - for all player i: exist a resource j: A_ji * rho_i >= A_jk * rho_k for all other player k
+ *
+ * Despite the prove of existence of a BMF allocation in the general case, it may not
+ * be unique, which leads to possible different rate for the applications.
+ *
+ * More details about BMF can be found at: https://hal.inria.fr/hal-01243985/document
+ *
+ * @endrst
+ */
+/**
+ * @brief Bottleneck max-fair system
+ */
+class XBT_PUBLIC BmfSystem : public System {
+public:
+ using System::System;
+
+private:
+ /** @brief Implements the solve method to calculate a BMF allocation */
+ void do_solve() final;
+ using allocation_map_t = std::unordered_map<int, std::unordered_set<int>>;
+ /**
+ * @brief Solve equation system to find a fair-sharing of resources
+ *
+ * @param cnst_list Constraint list (modified for selective update or active)
+ */
+ template <class CnstList> void bmf_solve(const CnstList& cnst_list);
+ /**
+ * @brief Iterates over system and build the consumption matrix A_ji and maxA_ji
+ *
+ * Each row j represents a resource and each col i a player/flow
+ *
+ * Considers only active variables to build the matrix.
+ *
+ * @param number_cnsts Number of constraints in the system
+ * @param A Consumption matrix (OUTPUT)
+ * @param maxA Max subflow consumption matrix (OUTPUT)
+ * @param phi Bounds for variables
+ */
+ void get_flows_data(Eigen::Index number_cnsts, Eigen::MatrixXd& A, Eigen::MatrixXd& maxA, Eigen::VectorXd& phi);
+ /**
+ * @brief Builds the vector C_ with resource's capacity
+ *
+ * @param cnst_list Constraint list (modified for selective update or active)
+ * @param C Resource capacity vector
+ * @param shared Resource is shared or not (fatpipe links)
+ */
+ template <class CnstList>
+ void get_constraint_data(const CnstList& cnst_list, Eigen::VectorXd& C, std::vector<bool>& shared);
+
+ std::unordered_map<int, Variable*> idx2Var_; //!< Map player index (and position in matrices) to system's variable
+ std::unordered_map<const Constraint*, int> cnst2idx_; //!< Conversely map constraint to index