#!/usr/bin/env python # coding: utf-8 # # Perron-Frobenius matrix completion # # The DGP atom library has several functions of positive matrices, including the trace, (matrix) product, sum, Perron-Frobenius eigenvalue, and $(I - X)^{-1}$ (eye-minus-inverse). In this notebook, we use some of these atoms to formulate and solve an interesting matrix completion problem. # # In this problem, we are given some entries of an elementwise positive matrix $A$, and the goal is to choose the missing entries so as to minimize the Perron-Frobenius eigenvalue or spectral # radius. Letting $\Omega$ denote the set of indices $(i, j)$ for which $A_{ij}$ is known, the optimization problem is # # $$ # \begin{equation} # \begin{array}{ll} # \mbox{minimize} & \lambda_{\text{pf}}(X) \\ # \mbox{subject to} & \prod_{(i, j) \not\in \Omega} X_{ij} = 1 \\ # & X_{ij} = A_{ij}, \, (i, j) \in \Omega, # \end{array} # \end{equation} # $$ # # which is a log-log convex program. Below is an implementation of this problem, with specific problem data # # $$ # A = \begin{bmatrix} # 1.0 & ? & 1.9 \\ # ? & 0.8 & ? \\ # 3.2 & 5.9& ? # \end{bmatrix}, # $$ # # where the question marks denote the missing entries. # In[1]: import cvxpy as cp n = 3 known_value_indices = tuple(zip(*[[0, 0], [0, 2], [1, 1], [2, 0], [2, 1]])) known_values = [1.0, 1.9, 0.8, 3.2, 5.9] X = cp.Variable((n, n), pos=True) objective_fn = cp.pf_eigenvalue(X) constraints = [ X[known_value_indices] == known_values, X[0, 1] * X[1, 0] * X[1, 2] * X[2, 2] == 1.0, ] problem = cp.Problem(cp.Minimize(objective_fn), constraints) problem.solve(gp=True) print("Optimal value: ", problem.value) print("X:\n", X.value)