Skip to content

Commit

Permalink
Merge branch 'main' into vis
Browse files Browse the repository at this point in the history
  • Loading branch information
dmdunla authored Oct 23, 2024
2 parents ab63cf2 + 24c8480 commit 61c8be4
Show file tree
Hide file tree
Showing 18 changed files with 165 additions and 89 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/markdown-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ jobs:
markdown-link-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: gaurav-nelson/github-action-markdown-link-check@v1
6 changes: 3 additions & 3 deletions .github/workflows/pre-commit-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v3
- uses: pre-commit/[email protected].0
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: pre-commit/[email protected].1
65 changes: 41 additions & 24 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
@@ -1,39 +1,56 @@
# This workflow will upload a Python Package using Twine when a release is created
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# For more information see:
# https://packaging.python.org/en/latest/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/

name: Upload Python Package

on:
release:
types: [published]

permissions:
contents: read

jobs:
deploy:

build:
name: Build distribution
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v3
uses: actions/setup-python@v5
with:
python-version: "3.x"
- name: Install pypa/build
run: >-
python3 -m
pip install
build
--user
- name: Build a binary wheel and a source tarball
run: python3 -m build
- name: Store the distribution packages
uses: actions/upload-artifact@v4
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install build
- name: Build package
run: python -m build
- name: Publish package
uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
name: python-package-distributions
path: dist/

publish-to-pypi:
name: >-
Publish Python distribution to PyPI
needs:
- build
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/pyttb
permissions:
id-token: write

steps:
- name: Download all the dists
uses: actions/download-artifact@v4
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
name: python-package-distributions
path: dist/
- name: Publish distribution 📦 to PyPI
uses: pypa/gh-action-pypi-publish@release/v1

19 changes: 9 additions & 10 deletions .github/workflows/regression-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,27 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
- name: Install base dependencies
run: |
python -m pip install --upgrade pip
pip install .
# Basic check for minimal deployed env requirements
python -c "import pyttb"
- name: Install dev dependencies
run: |
python -m pip install --upgrade coverage coveralls sphinx_rtd_theme
pip install ".[dev]"
- name: Check auto-formatters
run: |
black --check .
# - name: Lint with flake8
# run: |
# # stop the build if there are Python syntax errors or undefined names
# flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
# flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Run tests
run: |
coverage run --source pyttb -m pytest tests/
Expand Down
16 changes: 10 additions & 6 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,19 @@ U.S. Government retains certain rights in this software.

**Main Developers:**

- [Danny Dunlavy](https://github.com/dmdunla) - original author, `sptensor`, `ktensor`, `tensor`, `tenmat`, `cp_als`, `cp_apr`,
- [Danny Dunlavy](https://github.com/dmdunla) - original author
[PRs](https://github.com/sandialabs/pyttb/commits?author=dmdunla)
- [Nick Johnson](https://github.com/ntjohnson1) - original author, `sptensor`, `ktensor`, `tensor`, `ttensor`, `cp_als`, `cp_apr`,
- [Nick Johnson](https://github.com/ntjohnson1) - original author
[PRs](https://github.com/sandialabs/pyttb/commits?author=ntjohnson1)
- [Jordan Medina](https://github.com/DeepBlockDeepak) - documentation, tutorials,
[PRs](https://github.com/sandialabs/pyttb/commits?author=DeepBlockDeepak)
- [Jeremy Myers](https://github.com/jeremy-myers) - bug fixes, documentation
[PRs](https://github.com/sandialabs/pyttb/commits?author=jeremy-myers)

**Other Contributors:**
- [Brian Kelley](https://github.com/brian-kelley) - `numpy` compatability,
- [Brian Kelley](https://github.com/brian-kelley) - dependencies
[PRs](https://github.com/sandialabs/pyttb/commits?author=brian-kelley)
- [Derek Tucker](https://github.com/jdtuck)[#1] - `tensor`,
- [Jordan Medina](https://github.com/DeepBlockDeepak) - bug fixes, documentation
[PRs](https://github.com/sandialabs/pyttb/commits?author=DeepBlockDeepak)
- [Eric Phipps](https://github.com/etphipp) - bug fixes
[PRs](https://github.com/sandialabs/pyttb/commits?author=etphipp)
- [Derek Tucker](https://github.com/jdtuck) - bug fixes
[PRs](https://github.com/sandialabs/pyttb/commits?author=jdtuck)
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ readme = "README.md"
requires-python = ">=3.8"

dependencies = [
"numpy",
"numpy < 2",
"numpy_groupies",
"scipy",
"matplotlib",
Expand All @@ -23,6 +23,7 @@ classifiers = [
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
]

[project.urls]
Expand Down
2 changes: 1 addition & 1 deletion pyttb/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# U.S. Government retains certain rights in this software.
from __future__ import annotations

__version__ = "1.6.2"
__version__ = "1.7.0"


import warnings
Expand Down
6 changes: 4 additions & 2 deletions pyttb/gcp/handles.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,15 +115,17 @@ def huber_grad(data: ttb.tensor, model: ttb.tensor, threshold: float) -> np.ndar
) * np.logical_not(below_threshold)


# FIXME: Num trials should be enforced as integer here and in MATLAB
# requires updating our regression test values to calculate MATLAB integer version
def negative_binomial(
data: np.ndarray, model: np.ndarray, num_trials: int
data: np.ndarray, model: np.ndarray, num_trials: float
) -> np.ndarray:
"""Return objective function for negative binomial distributions"""
return (num_trials + data) * np.log(model + 1) - data * np.log(model + EPS)


def negative_binomial_grad(
data: np.ndarray, model: np.ndarray, num_trials: int
data: np.ndarray, model: np.ndarray, num_trials: float
) -> np.ndarray:
"""Return gradient function for negative binomial distributions"""
return (num_trials + 1) / (1 + model) - data / (model + EPS)
Expand Down
7 changes: 5 additions & 2 deletions pyttb/gcp/samplers.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ def zeros(

# Select out just the zeros
tmpidx = tt_sub2ind(data.shape, tmpsubs)
iszero = np.logical_not(np.in1d(tmpidx, nz_idx))
iszero = np.logical_not(np.isin(tmpidx, nz_idx))
tmpsubs = tmpsubs[iszero, :]

# Trim back to desired numb of samples
Expand Down Expand Up @@ -425,7 +425,7 @@ def semistrat(data: ttb.sptensor, num_nonzeros: int, num_zeros: int) -> sample_t


def stratified(
data: ttb.sptensor,
data: Union[ttb.sptensor, ttb.tensor],
nz_idx: np.ndarray,
num_nonzeros: int,
num_zeros: int,
Expand All @@ -450,6 +450,9 @@ def stratified(
-------
Subscripts, values, and weights of samples (Nonzeros then zeros).
"""
assert isinstance(
data, ttb.sptensor
), "For stratified sampling Sparse Tensor must be provided"
[nonzero_subs, nonzero_vals] = nonzeros(data, num_nonzeros, with_replacement=True)
nonzero_weights = np.ones((num_nonzeros,))
if num_nonzeros > 0:
Expand Down
15 changes: 8 additions & 7 deletions pyttb/ktensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@
import matplotlib.pyplot as plt
import numpy as np
import scipy.sparse.linalg
from typing_extensions import Self

import pyttb as ttb
from pyttb.pyttb_utils import (
get_mttkrp_factors,
isrow,
isvector,
np_to_python,
tt_dimscheck,
tt_ind2sub,
)
Expand Down Expand Up @@ -696,7 +696,8 @@ def extract(
invalid_entries.append(component)
if len(invalid_entries) > 0:
assert False, (
f"Invalid component indices to be extracted: {invalid_entries} "
f"Invalid component indices to be extracted: "
f"{np_to_python(invalid_entries)} "
f"not in range({self.ncomponents})"
)
new_weights = self.weights[components]
Expand All @@ -707,7 +708,7 @@ def extract(
else:
assert False, "Input parameter must be an int, tuple, list or numpy.ndarray"

def fixsigns(self, other: Optional[ktensor] = None) -> Self: # noqa: PLR0912
def fixsigns(self, other: Optional[ktensor] = None) -> ktensor: # noqa: PLR0912
"""
Change the elements of a :class:`pyttb.ktensor` in place so that the
largest magnitude entries for each column vector in each factor
Expand Down Expand Up @@ -1185,7 +1186,7 @@ def normalize(
sort: Optional[bool] = False,
normtype: float = 2,
mode: Optional[int] = None,
) -> Self:
) -> ktensor:
"""
Normalize the columns of the factor matrices of a
:class:`pyttb.ktensor` in place, then optionally
Expand Down Expand Up @@ -1406,7 +1407,7 @@ def permute(self, order: np.ndarray) -> ktensor:

return ttb.ktensor([self.factor_matrices[i] for i in order], self.weights)

def redistribute(self, mode: int) -> Self:
def redistribute(self, mode: int) -> ktensor:
"""
Distribute weights of a :class:`pyttb.ktensor` to the specified mode.
The redistribution is performed in place.
Expand Down Expand Up @@ -1622,7 +1623,7 @@ def score(

# Rearrange the components of A according to the best matching
foo = np.arange(RA)
tf = np.in1d(foo, best_perm)
tf = np.isin(foo, best_perm)
best_perm[RB : RA + 1] = foo[~tf]
A.arrange(permutation=best_perm)
return best_score, A, flag, best_perm
Expand Down Expand Up @@ -2000,7 +2001,7 @@ def ttv(
factor_matrices.append(self.factor_matrices[i])
return ttb.ktensor(factor_matrices, new_weights, copy=False)

def update(self, modes: Union[int, Iterable[int]], data: np.ndarray) -> Self:
def update(self, modes: Union[int, Iterable[int]], data: np.ndarray) -> ktensor:
"""
Updates a :class:`pyttb.ktensor` in the specific dimensions with the
values in `data` (in vector or matrix form). The value of `modes` must
Expand Down
30 changes: 29 additions & 1 deletion pyttb/pyttb_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,16 @@

from enum import Enum
from inspect import signature
from typing import List, Literal, Optional, Tuple, Union, get_args, overload
from typing import (
Iterable,
List,
Literal,
Optional,
Tuple,
Union,
get_args,
overload,
)

import numpy as np

Expand Down Expand Up @@ -921,3 +930,22 @@ def gather_wrap_dims(

assert rdims is not None and cdims is not None
return rdims.astype(int), cdims.astype(int)


def np_to_python(
iterable: Iterable,
) -> Iterable:
"""Convert a structure containing numpy scalars to pure python types.
Mostly useful for prettier printing post numpy 2.0.
Parameters
----------
iterable:
Structure potentially containing numpy scalars.
"""
output_type = type(iterable)
return output_type( # type: ignore [call-arg]
element.item() if isinstance(element, np.generic) else element
for element in iterable
)
2 changes: 1 addition & 1 deletion pyttb/sptenmat.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ def __init__( # noqa: PLR0913
# Sum the corresponding values
# Squeeze to convert from column vector to row vector
newvals = accumarray(
loc, np.squeeze(vals, axis=1), size=newsubs.shape[0], func=sum
loc.flatten(), np.squeeze(vals, axis=1), size=newsubs.shape[0], func=sum
)

# Find the nonzero indices of the new values
Expand Down
Loading

0 comments on commit 61c8be4

Please sign in to comment.