PySTOP
Introduction
The STOP toolbox is designed for optimization problems on the Stiefel manifold, which could be expressed as $$ \begin{aligned} \min_{X \in \mathbb{R}^{n\times p}} ~ &f(X)\ \text{s. t.}~& X^\top X = I_p, \end{aligned} $$ where $I_p$ refers to the $p$-th order identity matrix, $X$ is a matrix with $n$ rows and $p$ columns. The feasible set of this optimization problem $$ \mathcal{S}_{n,p} := \left{X \in \mathbb{R}^{n\times p}: X^\top X = I_p \right}, $$ can be regarded as a Riemannian manifold in $\mathbb{R}^{n\times p}$, and we also call it as Stiefel manifold.
This document describes the python version of SLPG solver.
Installation
The source code of those solvers can be found from the website or directly from this link. Besides, it supports direct installation from pip:
pip install --user pystop
Example
Problem formulation
In this section, we consider the following nonlinear eigenvalue problem $$ \min_{X \in \mathcal{S}_{n, p}} ~ \frac{1}{2}\mathrm{tr}(X^\top L X) + \frac{\alpha}{4} \rho^\top L^{\dagger} \rho, $$ where $\rho = \mathrm{Diag}(XX^\top)$, and $L^{\dagger}$ denotes the pseudo-inverse of the positive definite matrix $L$, i.e. $L^{\dagger}LL^{\dagger} = L^{\dagger}$, $LL^{\dagger}L = L$. Here we uses $\mathrm{Diag}(M)$ to denote the vector that is composed of diagonal entries of the square matrix $M$, while $\mathrm{diag}(v)$ refers to a diagonal matrix with $v$ to be its diagonal entries. Then the cost function and its Euclidean gradient can be expressed as $$ \begin{aligned} f(X) ={}& \frac{1}{2}\mathrm{tr}(X^\top L X) + \frac{\alpha}{4} \rho^\top L^{\dagger} \rho,\ \nabla f(X) ={}& LX + \alpha \mathrm{diag}(L^{\dagger}\rho)X. \end{aligned} $$
In this example, we choose $L$ as a tri-diagonal matrix generated by L = gallery('tridiag',n,-1,2,-1). Noting that $L$ is full-rank, then we can conclude that $L^{\dagger} = L^{-1}$ in this case. We solve this simple optimization problem using solvers in STOP to illustrate the most basic usage of the STOP toolbox. For additional theory, readers are recommended to refer the papers in the about page.
# Import packages
import numpy as np
import scipy as sp
from scipy.sparse import diags
from scipy.sparse.linalg import spsolve
# Import manifolds and solvers
from manifold import Stiefel
from Solver.SLPG import SLPG_smooth
# Set parameters
n = 1000
p = 10
alpha = 1
M = Stiefel(n,p)
# Defining objective function
L = diags(np.array([-1, 2, -1]), np.array([1, 0, -1]), shape = (n,n)).tocsc()
def obj_fun(X):
LX = L@X
rho = np.sum(X * X, 1)
Lrho = spsolve(L, rho)
fval = 0.5*np.sum(X* LX) + (alpha /4) * np.sum(rho * Lrho)
grad = LX + alpha * Lrho[: ,np.newaxis] * X
return fval, grad
# Execute the solver
X, out_dict = SLPG_smooth(obj_fun, M)
Let us review the code step by step. First, we specify the dimension of the problem and specify the Stiefel manifold. In pySTOP package, we need to specify the dimension of the Stiefel manifold before executing the solver. The Stiefel manifold should be specified as the STOP manifold class, for example,
# Set parameters
n = 1000
p = 10
alpha = 1
# Specify the Stiefel manifold
M = Stiefel(n,p)
Here pystop.manifold.stiefel is a build-in function to specify the Stiefel manifold and hence provides essential tools for the algorithm.
Then we generate the data (matrix $L$) for the optimization problem by the following code,
L = diags(np.array([-1, 2, -1]), np.array([1, 0, -1]), shape = (n,n)).tocsc()
Here we utilize SciPy.sparse to create a sparse representation of $L$ . Therefore, in each step we could use the scipy.sparse.linalg.spsolve function to compute .
Then we specify the cost function and its gradient in the following function
# Defin objective function
def obj_fun(X):
LX = L@X
rho = np.sum(X * X, 1)
Lrho = spsolve(L, rho)
fval = 0.5*np.sum(X* LX) + (alpha /4) * np.sum(rho * Lrho)
grad = LX + alpha * Lrho[: ,np.newaxis] * X
return fval, grad
Currently, in STOP toolbox, we require the function return the function value and its gradient simultaneously. Usually, computing the function value and gradient simultaneously is much faster than compute them separately, even when cache techniques are involved. To achieve a better performance, we strongly suggest to compute the function value and gradient in a single function.
Then we call a solver to solve the nonlinear eigenvalue problem,
# Execute the solver
X, out_dict = SLPG_smooth(obj_fun, M)
Solvers
The PySTOP solver classes provide the solvers for optimization. Once we specify the Stiefel manifold and define the objective function, the PySTOP solver can be executed by
X, out_dict = SLPG_smooth(obj_fun, M)
Here X is the final output of the problem, and out_dict is a dictionary that contains the log information.
| Name | Comment | Call |
|---|---|---|
| SLPG_smooth | Penalty-free first-order method for smooth problems | SLPG_smooth(...) |
| SLPG | Penalty-free first-order method for nonsmooth problems | SLPG(...) |
| SLPG_l21 | Penalty-free first-order method for $\ell_{2,1}$-norm regularized problems | SLPG_l21(...) |
Metadata
Release files for pystmopt 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pystmopt-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Release files / pystmopt-0.1.0-py3-none-any.whl
| Download URL | pystmopt-0.1.0-py3-none-any.whl |
|---|---|
| Size | 22.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e1f046f98a039f79fbd92bdc8898fae4ee358a0e080b34e9ea5d01c672cbface
|
|
BLAKE2b-256 checksum How to use checksums |
37562ddf0101aeadb27373ac367261c6d14d9d5cf14c03e8dff2f5da65ec9366
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/3.6.0 importlib_metadata/4.8.1 pkginfo/1.4.2 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.26.0 CPython/3.7.0
|
Security for pystmopt 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.