Disciplined Biconvex Programming (DBCP)
- Disciplined Biconvex Programming (DBCP) is a framework that defines biconvex optimization problems with a clear block structure, ensuring biconvexity by design.
- It extends Disciplined Convex Programming by enforcing strict syntax and variable-interaction rules through a restricted product rule.
- The framework automatically splits problems into DCP-compliant subproblems solved via alternate convex search, facilitating rapid prototyping in CVXPY.
Disciplined Biconvex Programming (DBCP) is a modeling and solution framework for specifying and solving biconvex optimization problems. Biconvex problems are nonconvex optimization problems in which variables can be partitioned into two blocks so that, when one block is fixed, the objective and constraints are convex in the other block. The DBCP framework extends the principles of Disciplined Convex Programming (DCP) to the biconvex setting, providing a syntax and verification mechanism that guarantees biconvexity by construction, and enabling automatic generation and solution of the resulting subproblems via alternate convex search (ACS). DBCP is implemented as an open-source extension to the Python package CVXPY.
1. Formal Structure of Biconvex Problems
Let and be nonempty closed convex sets. A set is biconvex if all slices are convex for each fixed , and all are convex for each fixed . An extended-real-valued function is biconvex if its effective domain is biconvex and both and are convex in and for fixed and , respectively.
A canonical biconvex optimization problem is:
where each is biconvex and each is biaffine (affine in ). The feasible set is thus biconvex, but globally solving such problems is generally NP-hard. Practical algorithms target stationary or partially optimal points.
Arithmetic and composition rules extend from convex analysis: non-negative weighted sums and pointwise maxima of biconvex functions are biconvex; if is convex and nondecreasing in each argument and is biaffine, then is biconvex.
2. Syntax and Verification Rules in DBCP
DBCP extends DCP with a carefully restricted product rule to express admissible biconvex terms. In DCP, objective and constraint expressions are recursively constructed from atomic operations with known curvature and monotonicity, strictly forbidding arbitrary products unless one operand is a constant or of known sign. DBCP introduces the following product rule:
A product is permitted if and are DCP-compliant and one of the following ensures biconvexity:
- and are both affine in .
- is affine, nonnegative, and is convex.
- is affine, nonpositive, and is concave.
- is convex, nonnegative, and is convex, nonnegative.
- is concave, nonpositive, and is concave, nonpositive.
Additionally, the variable-interaction graph (nodes are variables, edges indicate variables on opposite sides of a product) must be acyclic and bipartite, preventing cyclic "multi-block" dependencies that would destroy biconvexity.
Variables are partitioned into two blocks, and . Any remaining variables that only appear in convex expressions may be left outside the partition as these do not participate in alternation.
3. Automatic Problem Transformation and Solver Generation
Once a compliant DBCP problem is specified, the problem is automatically split into two DCP subproblems according to the supplied partition. The solution loop is an instance of alternate convex search (ACS), also known as block coordinate descent in this setting.
Given an initial feasible , the iterates are:
Each subproblem is DCP-compliant and can be solved with any conic, QP, or SOCP solver supported by CVXPY (e.g., ECOS, OSQP).
A generic ACS implementation in pseudocode:
1 2 3 4 5 6 7 8 9 |
initialize x = x⁽⁰⁾, y = y⁽⁰⁾ feasibly k ← 0 repeat solve (P_x): minimize f₀(x, yᵏ) subject to f_i(x, yᵏ) ≤ 0, h_j(x, yᵏ) = 0 let xᵏ⁺¹ ← solution of (P_x) solve (P_y): minimize f₀(xᵏ⁺¹, y) subject to f_i(xᵏ⁺¹, y) ≤ 0, h_j(xᵏ⁺¹, y) = 0 let yᵏ⁺¹ ← solution of (P_y) k ← k+1 until stopping criterion |
DBCP supports proximal-regularized subproblems by augmenting the objective with or to promote stability and strong convexity; the proximal weight is user-configurable via the lbd keyword.
For initialization, if no feasible is supplied, DBCP solves a relaxed feasibility problem
via ACS until the total slack is zero, producing a feasible point. Alternatively, an infeasible-start penalized ACS variant minimizes over the same relaxed constraints, controlled by the penalty parameter .
4. Convergence and Theoretical Properties
Under the assumption that each convex subproblem possesses a unique minimizer or attains its infimum, and that all relevant level sets are compact, the ACS sequence of objective values is monotone nonincreasing and bounded below:
with for some . If , the limit is a stationary or partially optimal point of the original biconvex problem. There is no guarantee of finding a global minimum; in general, different initializations may yield convergence to different local optima.
5. Practical Implementation in CVXPY/dbcp: Examples
DBCP is implemented as a lightweight extension of CVXPY, under the Python package dbcp. Users express biconvex problems at a high level as in DCP, then specify the block partition of variables.
Example 1: Low-Rank Approximation
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import cvxpy as cp from dbcp import BiconvexProblem X = cp.Variable((m, k)) Y = cp.Variable((k, n)) Z = cp.Variable((m, n)) obj = cp.Minimize(cp.norm(X @ Y + Z - A, "fro")) constr = [cp.norm(Z, "fro") <= 1] prob = BiconvexProblem(obj, [[X], [Y]], constr) prob.solve(lbd=1e-2, gap_tolerance=1e-6, solver="ECOS") print("objective value:", prob.value) print("iterations:", prob.num_iters) |
Example 2: Nonnegative Matrix Factorization
1 2 3 4 5 6 7 |
X = cp.Variable((m, k), nonneg=True) Y = cp.Variable((k, n), nonneg=True) A = ... # data matrix obj = cp.Minimize(cp.sum_squares(X @ Y - A)) prob = BiconvexProblem(obj, [[X], [Y]]) prob.solve(lbd=0.1, gap_tolerance=1e-5) print("NMF objective:", prob.value) |
Example 3: -Means Clustering via Soft Assignments
1 2 3 4 5 6 7 8 9 |
xs = ... # data points R^{m×n} k = ... xbars = cp.Variable((k, n)) zs = cp.Variable((m, k), nonneg=True) dist2 = lambda c: cp.sum(cp.square(xs - c), axis=1) obj = cp.Minimize(cp.sum(cp.multiply(zs, cp.vstack([dist2(c) for c in xbars]).T))) constr = [zs <= 1, cp.sum(zs, axis=1) == 1] prob = BiconvexProblem(obj, [[xbars], [zs]], constr) prob.solve(lbd=0.5) |
Infeasible start and relaxation variants can be accessed via BiconvexRelaxProblem, allowing penalty-based constraint handling.
6. Benefits, Limitations, and Extensions
The DBCP framework centralizes the modeling and solution of biconvex problems:
| Aspect | DBCP Mechanism | Comment |
|---|---|---|
| Modeling Simplicity | High-level syntax, automated splitting | No manual ACS coding |
| Correctness | Syntax/graph checks for biconvexity | Ensures each subproblem is DCP-compliant |
| Modularity | User options for proximal weights, penalties | Easily adapted to problem structure |
| Expressiveness | Rapid prototyping of new problem forms | Swap objectives/constraints in seconds |
However, DBCP only guarantees locally optimal or stationary points and is sensitive to initialization. Overhead can be high since each ACS iteration invokes an external convex solver. Not all biconvex problems are representable if the DBCP product rule or variable-interaction graph constraints are violated.
Open directions include:
- Extension to multi-convex programming for more than two blocks (Shen et al., 2016).
- Heuristic combination with global optimization methods for valid lower and upper bounds.
- Embedded biconvex subproblems within stochastic or dynamic models (e.g., inside EM loops).
Disciplined biconvex programming thus provides a rigorous, modular way to formulate and solve a broad class of biconvex optimization problems in a manner that is robust to user modeling errors and allows rapid experimentation, provided the inherent local nature of the solution landscape is accepted as a fundamental limitation.