CP-APR: Alternating Poisson Regression for fitting CP to sparse count data

Copyright 2025 National Technology & Engineering Solutions of Sandia,
LLC (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the
U.S. Government retains certain rights in this software.

Set up a sample problem

We follow the general procedure outlined by E. C. Chi and T. G. Kolda, On Tensors, Sparsity, and Nonnegative Factorizations, arXiv:1112.2414 [math.NA], December 2011 (http://arxiv.org/abs/1112.2414).

import os
import sys
import pyttb as ttb
import numpy as np
# Pick the shape and rank
sz = (10, 8, 6)
R = 5

# Generate factor matrices with a few large entries in each column
# this will be the basis of our solution.
np.random.seed(0)  # Set seed for reproducibility
A = []
for n in range(len(sz)):
    A.append(np.random.uniform(size=(sz[n], R)))
    for r in range(R):
        p = np.random.permutation(sz[n])
        nbig = round((1 / R) * sz[n])
        A[-1][p[0:nbig], r] *= 100
weights = np.random.uniform(size=(R,))
S = ttb.ktensor(A, weights)
S.normalize(sort=True, normtype=1)

X = S.to_tensor()
X.data = np.floor(np.abs(X.data))

Call CP-APR

# Compute a solution
short_tutorial = 2  # Cut off solve early for demo
M = ttb.cp_apr(X, R, printitn=10, stoptime=short_tutorial);
CP_APR:
	Iter 0: Inner Its = 30.0 KKT violation = 0.70173684251678, nViolations = 0.0
	Iter 10: Inner Its = 30.0 KKT violation = 0.05721561635359751, nViolations = 0.0
	Iter 20: Inner Its = 26.0 KKT violation = 0.012967978458406026, nViolations = 0.0
	Iter 30: Inner Its = 22.0 KKT violation = 0.008994287986022087, nViolations = 0.0
	Iter 40: Inner Its = 20.0 KKT violation = 0.004412950418894557, nViolations = 0.0
	Iter 50: Inner Its = 19.0 KKT violation = 0.0018915758389352888, nViolations = 0.0
	Iter 60: Inner Its = 20.0 KKT violation = 0.001286969943133598, nViolations = 0.0
	Iter 70: Inner Its = 21.0 KKT violation = 0.0011562208758997272, nViolations = 0.0
	Iter 80: Inner Its = 22.0 KKT violation = 0.0010417291154152242, nViolations = 0.0
	Iter 90: Inner Its = 22.0 KKT violation = 0.0009427649122030202, nViolations = 0.0
	Iter 100: Inner Its = 22.0 KKT violation = 0.0008566762816728524, nViolations = 0.0
	Iter 110: Inner Its = 21.0 KKT violation = 0.0007815573110677709, nViolations = 0.0
	Iter 120: Inner Its = 20.0 KKT violation = 0.0007157176199857895, nViolations = 0.0
	Iter 130: Inner Its = 19.0 KKT violation = 0.0006577683101630649, nViolations = 0.0
	Iter 140: Inner Its = 19.0 KKT violation = 0.0006062499144334765, nViolations = 0.0
	Iter 150: Inner Its = 18.0 KKT violation = 0.0005605759635001206, nViolations = 0.0
	Iter 160: Inner Its = 17.0 KKT violation = 0.0005198182925200134, nViolations = 0.0
	Iter 170: Inner Its = 16.0 KKT violation = 0.0004833097888181648, nViolations = 0.0
	Iter 180: Inner Its = 16.0 KKT violation = 0.00045028657371282144, nViolations = 0.0
	Iter 190: Inner Its = 15.0 KKT violation = 0.0004203811655830725, nViolations = 0.0
	Iter 200: Inner Its = 14.0 KKT violation = 0.00039367079629715196, nViolations = 0.0
	Iter 210: Inner Its = 14.0 KKT violation = 0.00036694425054495383, nViolations = 0.0
	Iter 220: Inner Its = 14.0 KKT violation = 0.00034502387049384353, nViolations = 0.0
	Iter 230: Inner Its = 14.0 KKT violation = 0.00032504487639428703, nViolations = 0.0
	Iter 240: Inner Its = 14.0 KKT violation = 0.00030673119777768765, nViolations = 0.0
	Iter 250: Inner Its = 13.0 KKT violation = 0.00029040278118230844, nViolations = 0.0
	Iter 260: Inner Its = 13.0 KKT violation = 0.0002747802137601507, nViolations = 0.0
	Iter 270: Inner Its = 13.0 KKT violation = 0.0002598287806978572, nViolations = 0.0
	Iter 280: Inner Its = 14.0 KKT violation = 0.0002459165246927464, nViolations = 0.0
	Iter 290: Inner Its = 13.0 KKT violation = 0.00023448594524999589, nViolations = 0.0
	Iter 300: Inner Its = 13.0 KKT violation = 0.00022219249722044143, nViolations = 0.0
	Iter 310: Inner Its = 12.0 KKT violation = 0.00021169583034075234, nViolations = 0.0
	Iter 320: Inner Its = 12.0 KKT violation = 0.00020196296321350893, nViolations = 0.0
	Iter 330: Inner Its = 12.0 KKT violation = 0.00019236099107544646, nViolations = 0.0
	Iter 340: Inner Its = 12.0 KKT violation = 0.00018359967830849921, nViolations = 0.0
	Iter 350: Inner Its = 12.0 KKT violation = 0.0001756587093748596, nViolations = 0.0
	Iter 360: Inner Its = 12.0 KKT violation = 0.0001681962362595213, nViolations = 0.0
	Iter 370: Inner Its = 12.0 KKT violation = 0.0001614054851718505, nViolations = 0.0
	Iter 380: Inner Its = 12.0 KKT violation = 0.00015504296621560165, nViolations = 0.0
	Iter 390: Inner Its = 13.0 KKT violation = 0.00014757230955031453, nViolations = 0.0
	Iter 400: Inner Its = 12.0 KKT violation = 0.00013059995354025578, nViolations = 0.0
	Iter 410: Inner Its = 14.0 KKT violation = 0.00011465399883736627, nViolations = 0.0
	Iter 420: Inner Its = 12.0 KKT violation = 0.00013134051357654997, nViolations = 0.0
	Iter 430: Inner Its = 12.0 KKT violation = 0.00011604661571451569, nViolations = 0.0
	Iter 440: Inner Its = 13.0 KKT violation = 0.00010283670571187287, nViolations = 0.0
	Iter 450: Inner Its = 12.0 KKT violation = 0.00011746833500481113, nViolations = 0.0
Exiting because all subproblems reached KKT tol.
===========================================
 Final log-likelihood = 21158574.867987577
 Final least squares fit = 0.9998884608160244
 Final KKT violation = 9.949517806429053e-05
 Total inner iterations = 7382.0
 Total execution time = 1.8301475048065186 secs