Skip to content

API Reference

Everything below is re-exported at the top level, so from smopt import slpg_smooth and from smopt.solver import slpg_smooth are equivalent.

Manifold

smopt.Stiefel

Stiefel(n: int, p: int)

The manifold \(\{X \in \mathbb{R}^{n\times p} : X^\top X = I_p\}\). Carries the dimensions and exposes the geometric maps; each one is evaluated by the Fortran 77 core. Raises ValueError if the dimensions are not positive or if p > n.

Attribute Meaning
dim n * p, the dimension of the ambient space
Method Returns
phi(m) \((M + M^\top)/2\) for a (p, p) matrix
c(x) \(X^\top X - I_p\)
feas_eval(x) \(\|X^\top X - I_p\|_F\), as a float
ja(x, g) \(G - X\,\Phi(X^\top G)\)
jc(x, lam) \(X\,\Phi(\Lambda)\)
jc_transpose(x, d) \(\Phi(X^\top D)\)
a(x) the feasibility restoring map
post_process(x) the orthogonal polar factor \(UV^\top\)
init_point(xinit=None) a feasible starting point

init_point draws a standard normal matrix when xinit is omitted, and orthonormalizes whatever it ends up with unless it is already feasible.

Solvers

Every solver returns (X, out), where X is the solution and out is a dictionary:

Key Meaning
fvals objective value per iteration
kkts stationarity measure per iteration
feas feasibility measure per iteration
fval, kkt, fea the final values
beta the penalty used, pencf only

The objective is a single callable returning the value and the Euclidean gradient together:

def obj_fun(X):  # X has shape (n, p)
    return fval, grad  # grad has shape (n, p)

verbosity is 0 for silence, 1 for the convergence and post-processing lines, and 2 to also print periodically. maxit must be at least 1. A xinit you supply is used exactly as given; only the default one is drawn and orthonormalized.

smopt.slpg_smooth

slpg_smooth(
    obj_fun,
    manifold,
    xinit=None,
    maxit=100,
    gtol=1e-5,
    post_process=True,
    verbosity=2,
)

For a smooth objective. Prints every 20th iteration at verbosity=2.

smopt.slpg

slpg(
    obj_fun,
    manifold,
    xinit=None,
    maxit=100,
    prox=None,
    gtol=1e-5,
    post_process=True,
    verbosity=2,
)

For f(X) + r(X) with r reached through prox(X, eta), which must minimize \(\|Y - X\|_F^2/(2\eta) + r(Y)\). prox defaults to the identity, recovering the smooth case. Prints every 50th iteration at verbosity=2.

smopt.slpg_l21

slpg_l21(
    obj_fun,
    manifold,
    xinit=None,
    maxit=100,
    gamma=0,
    gtol=1e-5,
    post_process=True,
    verbosity=2,
)

For \(f(X) + \gamma\|X\|_{2,1}\), which induces row sparsity. Prints every 50th iteration at verbosity=2.

smopt.pencf

pencf(
    xinit,
    obj_fun,
    manifold,
    beta=None,
    maxit=100,
    gtol=1e-5,
    post_process=True,
    verbosity=2,
)

A constraint dissolving penalty method. Note that the starting point comes first. beta defaults to \(0.1\|\nabla f(X_0)\|_F\); the value actually used is reported as out["beta"]. Prints every 20th iteration at verbosity=2.

Proximal operators

smopt.prox_l1

prox_l1(x, eta, gamma=0)

Proximal operator of \(\gamma\|X\|_1\): entrywise soft thresholding.

smopt.prox_l21

prox_l21(x, eta, gamma=0)

Proximal operator of \(\gamma\|X\|_{2,1}\): shrinks whole rows towards the origin.

Both are shaped so they can be handed straight to slpg:

X, out = slpg(obj_fun, M, prox=lambda X, eta: prox_l1(X, eta, gamma=0.05))