ConvexFlows.jl
ConvexFlows
is a solver for the convex flow problem, introduced by Diamandis et al. in Convex Network Flows[1].
Documentation Contents:
Examples:
Advanced Usage:
Overview
ConvexFlows solves convex optimization problems of the form
\[\begin{array}{ll} \text{maximize} & U(y) + \sum_{i=1}^m V_i(x_i) \\ \text{subject to} & y = \sum_{i=1}^m A_i x_i \\ & x_i \in T_i \end{array}\]
where $x_i \in \mathbb{R}^{n_i}$ and $y \in \mathbb{R}^n$ are the optimization variables. The functions $U$ and $\{V_i\}$ are concave nondecreasing utility functions, and the matrices $\{A_i\}$ map the flow over edge $i$ from the local indices to the global indices.
Compared to general conic form programs, the form we use in ConvexFlows takes advantage of underlying (hyper)graph structure in these problems and facilitates custom subroutines that often provide significant speedups. To ameliorate the extra complexity, we provide a few interfaces that allow for easy problem specification.
Objective interface
We define a few objective functions that may be used 'off the shelf', which we list below:
NonpositiveQuadratic(b, a)
is defined as
\[ U(y) = -(1/2)\sum_{i=1}^n a_i(b_i - y_i)^2\]
Markowitz(mu, Sigma)
is defined as
\[ U(y) = \mu^Ty - (1/2)y^T\Sigma y\]
Generic interface
To solve the dual problem, we work with the conjugate-like function
\[\bar U(\nu) = \sup_{y}\left(U(y) - \nu^Ty\right)\]
A user may define custom objective functions by implementing the following interface for an objective object that is a subtype of Objective
"
U(obj, y)
evaluates objectiveobj
aty
Ubar(obj, v)
evaluates the subproblem $\bar U$ atv
grad_Ubar!(g, obj, v)
(or∇Ubar!
) evaluates the gradient of $\bar U$ atv
and stores the result ing
Base.length(obj)
returns the number of nodes $n$
If using a custom linear objective, one should also define lower_limit(obj)
and upper_limit(obj)
appropriately.
Edge interfaces
Ultimately, we only need access to allowable edge flow sets via their support function (equivalently, the ability to find arbitrage). This can be done in a few ways.
Two-node edges
For two node edges, we only have to define a gain function $h(w)$ which gives the output from the edge for some positive input flow $w$. The solver then solves a single-dimensional root finding problem to compute arbitrage. Alternatively, if a closed form solution exists, it may be specified directly. These functions can be specified in native Julia code; see examples for details.
Generic interface
More generically, an edge must support the function
find_arb!(x, edge, eta).
For an edge object edge
with allowable flows $T$, this function finds a solution to the problem
\[\sup_{x \in T} \eta^T x\]
and stores it in the argument x
.
Algorithm
We use a first-order method to solve a particular dual of the convex flow problem. Check out the Algorithm page for details.
Getting Started
Please see the User Guide for a full explanation of the solver parameter options. Check out the examples in the documentation, as well as the more advanced examples in the paper
folder on GitHub.
References
- 1Diamandis, T., Angeris, G., & Edelman, A. (2024). Convex Network Flows. arXiv preprint arXiv:2404.00765.