diff --git a/docs/source/gcp/fg.rst b/docs/source/gcp/fg.rst index 055d8d31..edd70901 100644 --- a/docs/source/gcp/fg.rst +++ b/docs/source/gcp/fg.rst @@ -1,7 +1,7 @@ -pyttb.gcp.fg -==================== +pyttb.decompositions.cp.gcp.fg +============================== -.. automodule:: pyttb.gcp.fg +.. automodule:: pyttb.decompositions.cp.gcp.fg :members: :undoc-members: :show-inheritance: \ No newline at end of file diff --git a/docs/source/gcp/fg_est.rst b/docs/source/gcp/fg_est.rst index 3c804f81..7874f96b 100644 --- a/docs/source/gcp/fg_est.rst +++ b/docs/source/gcp/fg_est.rst @@ -1,7 +1,7 @@ -pyttb.gcp.fg_est -==================== +pyttb.decompositions.cp.gcp.fg_est +================================== -.. automodule:: pyttb.gcp.fg_est +.. automodule:: pyttb.decompositions.cp.gcp.fg_est :members: :undoc-members: :show-inheritance: \ No newline at end of file diff --git a/docs/source/gcp/fg_setup.rst b/docs/source/gcp/fg_setup.rst index 27feaa7d..4f05ccc1 100644 --- a/docs/source/gcp/fg_setup.rst +++ b/docs/source/gcp/fg_setup.rst @@ -1,7 +1,7 @@ -pyttb.gcp.fg_setup -==================== +pyttb.decompositions.cp.gcp.fg_setup +==================================== -.. automodule:: pyttb.gcp.fg_setup +.. automodule:: pyttb.decompositions.cp.gcp.fg_setup :members: :undoc-members: :show-inheritance: \ No newline at end of file diff --git a/docs/source/gcp/handles.rst b/docs/source/gcp/handles.rst index e0f2066f..18b9e00f 100644 --- a/docs/source/gcp/handles.rst +++ b/docs/source/gcp/handles.rst @@ -1,7 +1,7 @@ -pyttb.gcp.handles -==================== +pyttb.decompositions.cp.gcp.handles +=================================== -.. automodule:: pyttb.gcp.handles +.. automodule:: pyttb.decompositions.cp.gcp.handles :members: :undoc-members: :show-inheritance: \ No newline at end of file diff --git a/docs/source/gcp/optimizers.rst b/docs/source/gcp/optimizers.rst index 6d892ba8..f302c453 100644 --- a/docs/source/gcp/optimizers.rst +++ b/docs/source/gcp/optimizers.rst @@ -1,7 +1,7 @@ -pyttb.gcp.optimizers -==================== +pyttb.decompositions.cp.gcp.optimizers +====================================== -.. automodule:: pyttb.gcp.optimizers +.. automodule:: pyttb.decompositions.cp.gcp.optimizers :members: :undoc-members: :special-members: __init__ diff --git a/docs/source/gcp/samplers.rst b/docs/source/gcp/samplers.rst index 8b9107c7..90ca9bc5 100644 --- a/docs/source/gcp/samplers.rst +++ b/docs/source/gcp/samplers.rst @@ -1,7 +1,7 @@ -pyttb.gcp.samplers -==================== +pyttb.decompositions.cp.gcp.samplers +==================================== -.. automodule:: pyttb.gcp.samplers +.. automodule:: pyttb.decompositions.cp.gcp.samplers :members: :undoc-members: :special-members: __init__ diff --git a/docs/source/tutorial/algorithm_gcp_opt.ipynb b/docs/source/tutorial/algorithm_gcp_opt.ipynb index f56fac50..99ebe628 100644 --- a/docs/source/tutorial/algorithm_gcp_opt.ipynb +++ b/docs/source/tutorial/algorithm_gcp_opt.ipynb @@ -163,10 +163,10 @@ "import numpy as np\n", "\n", "import pyttb as ttb\n", - "from pyttb.gcp.fg_setup import function_type, setup\n", - "from pyttb.gcp.handles import Objectives\n", - "from pyttb.gcp.optimizers import LBFGSB, SGD, Adagrad, Adam\n", - "from pyttb.gcp.samplers import GCPSampler" + "from pyttb.decompositions.cp.gcp.fg_setup import function_type, setup\n", + "from pyttb.decompositions.cp.gcp.handles import Objectives\n", + "from pyttb.decompositions.cp.gcp.optimizers import LBFGSB, SGD, Adagrad, Adam\n", + "from pyttb.decompositions.cp.gcp.samplers import GCPSampler" ] }, { diff --git a/pyttb/__init__.py b/pyttb/__init__.py index 4492505b..ce8dc49b 100644 --- a/pyttb/__init__.py +++ b/pyttb/__init__.py @@ -11,22 +11,23 @@ import warnings -from pyttb.cp_als import cp_als -from pyttb.cp_apr import cp_apr +from pyttb.decompositions.cp import cp_als, cp_apr, gcp_opt +from pyttb.decompositions.tucker import hosvd, tucker_als from pyttb.export_data import export_data -from pyttb.gcp_opt import gcp_opt -from pyttb.hosvd import hosvd from pyttb.import_data import import_data from pyttb.khatrirao import khatrirao -from pyttb.ktensor import ktensor from pyttb.matlab import matlab_support -from pyttb.sptenmat import sptenmat -from pyttb.sptensor import sptendiag, sptenrand, sptensor -from pyttb.sumtensor import sumtensor -from pyttb.tenmat import tenmat -from pyttb.tensor import tendiag, teneye, tenones, tenrand, tensor, tenzeros -from pyttb.ttensor import ttensor -from pyttb.tucker_als import tucker_als +from pyttb.tensors import ( + ktensor, + sptenmat, + sptensor, + sumtensor, + tenmat, + tensor, + ttensor, +) +from pyttb.tensors.dense import tendiag, teneye, tenones, tenrand, tenzeros +from pyttb.tensors.sparse import sptendiag, sptenrand def ignore_warnings(ignore=True): diff --git a/pyttb/decompositions/__init__.py b/pyttb/decompositions/__init__.py new file mode 100644 index 00000000..c3826199 --- /dev/null +++ b/pyttb/decompositions/__init__.py @@ -0,0 +1 @@ +"""Tensor Decompositions.""" diff --git a/pyttb/decompositions/cp/__init__.py b/pyttb/decompositions/cp/__init__.py new file mode 100644 index 00000000..bb1cc923 --- /dev/null +++ b/pyttb/decompositions/cp/__init__.py @@ -0,0 +1,13 @@ +"""CP Decompositions.""" + +from __future__ import annotations + +from .als import cp_als +from .apr import cp_apr +from .general import gcp_opt + +__all__ = [ + "cp_als", + "cp_apr", + "gcp_opt", +] diff --git a/pyttb/cp_als.py b/pyttb/decompositions/cp/als.py similarity index 96% rename from pyttb/cp_als.py rename to pyttb/decompositions/cp/als.py index b25fd3da..f03bc9b9 100644 --- a/pyttb/cp_als.py +++ b/pyttb/decompositions/cp/als.py @@ -12,19 +12,20 @@ import pyttb as ttb from pyttb.pyttb_utils import OneDArray, parse_one_d +from pyttb.tensors import ktensor, sptensor, tensor, ttensor def cp_als( # noqa: PLR0912,PLR0913,PLR0915 - input_tensor: ttb.tensor | ttb.sptensor | ttb.ttensor | ttb.sumtensor, + input_tensor: tensor | sptensor | ttensor | ttb.sumtensor, rank: int, stoptol: float = 1e-4, maxiters: int = 1000, dimorder: OneDArray | None = None, optdims: OneDArray | None = None, - init: Literal["random"] | Literal["nvecs"] | ttb.ktensor = "random", + init: Literal["random"] | Literal["nvecs"] | ktensor = "random", printitn: int = 1, fixsigns: bool = True, -) -> tuple[ttb.ktensor, ttb.ktensor, dict]: +) -> tuple[ktensor, ktensor, dict]: """Compute CP decomposition with alternating least squares. Parameters @@ -150,7 +151,7 @@ def cp_als( # noqa: PLR0912,PLR0913,PLR0915 assert rank > 0, "Number of components requested must be positive" # Set up and error checking on initial guess - if isinstance(init, ttb.ktensor): + if isinstance(init, ktensor): # User provided an initial ktensor; validate it assert init.ndims == N, f"Initial guess does not have {N} modes" assert init.ncomponents == rank, ( @@ -165,7 +166,7 @@ def cp_als( # noqa: PLR0912,PLR0913,PLR0915 factor_matrices.append( np.random.uniform(0, 1, (input_tensor.shape[n], rank)) ) - init = ttb.ktensor(factor_matrices) + init = ktensor(factor_matrices) elif isinstance(init, str) and init.lower() == "nvecs": assert not isinstance(input_tensor, ttb.sumtensor), ( "Sumtensor doesn't support nvecs" @@ -173,7 +174,7 @@ def cp_als( # noqa: PLR0912,PLR0913,PLR0915 factor_matrices = [] for n in range(N): factor_matrices.append(input_tensor.nvecs(n, rank)) - init = ttb.ktensor(factor_matrices) + init = ktensor(factor_matrices) else: assert False, "The selected initialization method is not supported" @@ -234,7 +235,7 @@ def cp_als( # noqa: PLR0912,PLR0913,PLR0915 U[n] = Unew UtU[:, :, n] = U[n].T @ U[n] - M = ttb.ktensor(U, weights) + M = ktensor(U, weights) # This is equivalent to innerprod(X,P). iprod = np.sum( diff --git a/pyttb/cp_apr.py b/pyttb/decompositions/cp/apr.py similarity index 100% rename from pyttb/cp_apr.py rename to pyttb/decompositions/cp/apr.py diff --git a/pyttb/gcp/__init__.py b/pyttb/decompositions/cp/gcp/__init__.py similarity index 100% rename from pyttb/gcp/__init__.py rename to pyttb/decompositions/cp/gcp/__init__.py diff --git a/pyttb/gcp/fg.py b/pyttb/decompositions/cp/gcp/fg.py similarity index 97% rename from pyttb/gcp/fg.py rename to pyttb/decompositions/cp/gcp/fg.py index 8a2f84fa..dbc34372 100644 --- a/pyttb/gcp/fg.py +++ b/pyttb/decompositions/cp/gcp/fg.py @@ -13,7 +13,7 @@ import pyttb as ttb if TYPE_CHECKING: - from pyttb.gcp.fg_setup import function_type + from pyttb.decompositions.cp.gcp.fg_setup import function_type @overload diff --git a/pyttb/gcp/fg_est.py b/pyttb/decompositions/cp/gcp/fg_est.py similarity index 98% rename from pyttb/gcp/fg_est.py rename to pyttb/decompositions/cp/gcp/fg_est.py index 4a3bb48c..3dafe58d 100644 --- a/pyttb/gcp/fg_est.py +++ b/pyttb/decompositions/cp/gcp/fg_est.py @@ -14,7 +14,7 @@ if TYPE_CHECKING: import pyttb as ttb - from pyttb.gcp.fg_setup import function_type + from pyttb.decompositions.cp.gcp.fg_setup import function_type @overload diff --git a/pyttb/gcp/fg_setup.py b/pyttb/decompositions/cp/gcp/fg_setup.py similarity index 90% rename from pyttb/gcp/fg_setup.py rename to pyttb/decompositions/cp/gcp/fg_setup.py index 87eccc5c..d13c71ab 100644 --- a/pyttb/gcp/fg_setup.py +++ b/pyttb/decompositions/cp/gcp/fg_setup.py @@ -7,13 +7,16 @@ from __future__ import annotations from functools import partial -from typing import Callable +from typing import TYPE_CHECKING, Callable import numpy as np -import pyttb as ttb -from pyttb.gcp import handles -from pyttb.gcp.handles import Objectives +from pyttb.decompositions.cp.gcp import handles +from pyttb.decompositions.cp.gcp.handles import Objectives +from pyttb.tensors.sparse import sptensor + +if TYPE_CHECKING: + from pyttb.tensors.dense import tensor function_type = Callable[[np.ndarray, np.ndarray], np.ndarray] fg_return = tuple[function_type, function_type, float] @@ -21,7 +24,7 @@ def setup( # noqa: PLR0912,PLR0915 objective: Objectives, - data: ttb.tensor | ttb.sptensor | None = None, + data: tensor | sptensor | None = None, additional_parameter: float | None = None, ) -> fg_return: """Collect the function and gradient handles for GCP. @@ -121,23 +124,23 @@ def setup( # noqa: PLR0912,PLR0915 return function_handle, gradient_handle, lower_bound -def valid_nonneg(data: ttb.tensor | ttb.sptensor) -> bool: +def valid_nonneg(data: tensor | sptensor) -> bool: """Check if provided data is valid non-negative tensor.""" - if isinstance(data, ttb.sptensor): + if isinstance(data, sptensor): return bool(np.all(data.vals > 0)) return bool(np.all(data.data > 0)) -def valid_binary(data: ttb.tensor | ttb.sptensor) -> bool: +def valid_binary(data: tensor | sptensor) -> bool: """Check if provided data is valid binary tensor.""" - if isinstance(data, ttb.sptensor): + if isinstance(data, sptensor): return bool(np.all(data.vals == 1)) return bool(np.all(np.isin(np.unique(data.data), [0, 1]))) -def valid_natural(data: ttb.tensor | ttb.sptensor) -> bool: +def valid_natural(data: tensor | sptensor) -> bool: """Check if provided data is valid natural number tensor.""" - if isinstance(data, ttb.sptensor): + if isinstance(data, sptensor): vals = data.vals else: vals = data.data diff --git a/pyttb/gcp/handles.py b/pyttb/decompositions/cp/gcp/handles.py similarity index 100% rename from pyttb/gcp/handles.py rename to pyttb/decompositions/cp/gcp/handles.py diff --git a/pyttb/gcp/optimizers.py b/pyttb/decompositions/cp/gcp/optimizers.py similarity index 98% rename from pyttb/gcp/optimizers.py rename to pyttb/decompositions/cp/gcp/optimizers.py index 5e4c7462..ab5327c6 100644 --- a/pyttb/gcp/optimizers.py +++ b/pyttb/decompositions/cp/gcp/optimizers.py @@ -16,12 +16,12 @@ from scipy.optimize import fmin_l_bfgs_b import pyttb as ttb -from pyttb.gcp.fg import evaluate -from pyttb.gcp.fg_est import estimate -from pyttb.gcp.samplers import GCPSampler +from pyttb.decompositions.cp.gcp.fg import evaluate +from pyttb.decompositions.cp.gcp.fg_est import estimate +from pyttb.decompositions.cp.gcp.samplers import GCPSampler if TYPE_CHECKING: - from pyttb.gcp.fg_setup import function_type + from pyttb.decompositions.cp.gcp.fg_setup import function_type class StochasticSolver(ABC): diff --git a/pyttb/gcp/samplers.py b/pyttb/decompositions/cp/gcp/samplers.py similarity index 99% rename from pyttb/gcp/samplers.py rename to pyttb/decompositions/cp/gcp/samplers.py index 8a75a3fc..69fdc407 100644 --- a/pyttb/gcp/samplers.py +++ b/pyttb/decompositions/cp/gcp/samplers.py @@ -17,8 +17,8 @@ import pyttb as ttb from pyttb.pyttb_utils import tt_sub2ind -from pyttb.sptensor import sptensor -from pyttb.tensor import tensor +from pyttb.tensors.dense import tensor +from pyttb.tensors.sparse import sptensor sample_type = tuple[np.ndarray, np.ndarray, np.ndarray] sampler_type = Callable[[Union[tensor, sptensor]], sample_type] diff --git a/pyttb/gcp_opt.py b/pyttb/decompositions/cp/general.py similarity index 95% rename from pyttb/gcp_opt.py rename to pyttb/decompositions/cp/general.py index 025cc68c..a7e830b7 100644 --- a/pyttb/gcp_opt.py +++ b/pyttb/decompositions/cp/general.py @@ -15,12 +15,12 @@ import numpy as np import pyttb as ttb -from pyttb.gcp.fg_setup import function_type, setup -from pyttb.gcp.handles import Objectives -from pyttb.gcp.optimizers import LBFGSB, StochasticSolver +from pyttb.decompositions.cp.gcp.fg_setup import function_type, setup +from pyttb.decompositions.cp.gcp.handles import Objectives +from pyttb.decompositions.cp.gcp.optimizers import LBFGSB, StochasticSolver if TYPE_CHECKING: - from pyttb.gcp.samplers import GCPSampler + from pyttb.decompositions.cp.gcp.samplers import GCPSampler def gcp_opt( # noqa: PLR0912,PLR0913 diff --git a/pyttb/decompositions/tucker/__init__.py b/pyttb/decompositions/tucker/__init__.py new file mode 100644 index 00000000..e9b9ae70 --- /dev/null +++ b/pyttb/decompositions/tucker/__init__.py @@ -0,0 +1,11 @@ +"""Tucker Decompositions.""" + +from __future__ import annotations + +from .als import tucker_als +from .svd import hosvd + +__all__ = [ + "hosvd", + "tucker_als", +] diff --git a/pyttb/tucker_als.py b/pyttb/decompositions/tucker/als.py similarity index 99% rename from pyttb/tucker_als.py rename to pyttb/decompositions/tucker/als.py index 7d5490d1..5b4d2cc1 100644 --- a/pyttb/tucker_als.py +++ b/pyttb/decompositions/tucker/als.py @@ -12,7 +12,7 @@ import numpy as np from pyttb.pyttb_utils import OneDArray, parse_one_d -from pyttb.ttensor import ttensor +from pyttb.tensors.tucker import ttensor if TYPE_CHECKING: import pyttb as ttb diff --git a/pyttb/hosvd.py b/pyttb/decompositions/tucker/svd.py similarity index 100% rename from pyttb/hosvd.py rename to pyttb/decompositions/tucker/svd.py diff --git a/pyttb/matlab/matlab_support.py b/pyttb/matlab/matlab_support.py index 859a1192..2cb55f9d 100644 --- a/pyttb/matlab/matlab_support.py +++ b/pyttb/matlab/matlab_support.py @@ -9,7 +9,7 @@ import numpy as np -from pyttb.tensor import tensor +from pyttb.tensors.dense import tensor from .matlab_utilities import _matlab_array_str diff --git a/pyttb/tensors/__init__.py b/pyttb/tensors/__init__.py new file mode 100644 index 00000000..ee798716 --- /dev/null +++ b/pyttb/tensors/__init__.py @@ -0,0 +1,21 @@ +"""Tensor Classes.""" + +from __future__ import annotations + +from .dense import tensor +from .kruskal import ktensor +from .matricized import tenmat +from .sparse import sptensor +from .sparse_matricized import sptenmat +from .sum import sumtensor +from .tucker import ttensor + +__all__ = [ + "ktensor", + "sptenmat", + "sptensor", + "sumtensor", + "tenmat", + "tensor", + "ttensor", +] diff --git a/pyttb/tensor.py b/pyttb/tensors/dense.py similarity index 100% rename from pyttb/tensor.py rename to pyttb/tensors/dense.py diff --git a/pyttb/ktensor.py b/pyttb/tensors/kruskal.py similarity index 100% rename from pyttb/ktensor.py rename to pyttb/tensors/kruskal.py diff --git a/pyttb/tenmat.py b/pyttb/tensors/matricized.py similarity index 100% rename from pyttb/tenmat.py rename to pyttb/tensors/matricized.py diff --git a/pyttb/sptensor.py b/pyttb/tensors/sparse.py similarity index 100% rename from pyttb/sptensor.py rename to pyttb/tensors/sparse.py diff --git a/pyttb/sptenmat.py b/pyttb/tensors/sparse_matricized.py similarity index 100% rename from pyttb/sptenmat.py rename to pyttb/tensors/sparse_matricized.py diff --git a/pyttb/sumtensor.py b/pyttb/tensors/sum.py similarity index 100% rename from pyttb/sumtensor.py rename to pyttb/tensors/sum.py diff --git a/pyttb/ttensor.py b/pyttb/tensors/tucker.py similarity index 100% rename from pyttb/ttensor.py rename to pyttb/tensors/tucker.py diff --git a/tests/gcp/test_fg.py b/tests/gcp/test_fg.py index f8389d30..7f141239 100644 --- a/tests/gcp/test_fg.py +++ b/tests/gcp/test_fg.py @@ -8,9 +8,9 @@ import pytest import pyttb as ttb -from pyttb.gcp import fg_setup -from pyttb.gcp.fg import evaluate -from pyttb.gcp.handles import Objectives +from pyttb.decompositions.cp.gcp import fg_setup +from pyttb.decompositions.cp.gcp.fg import evaluate +from pyttb.decompositions.cp.gcp.handles import Objectives def test_evaluate(): diff --git a/tests/gcp/test_fg_est.py b/tests/gcp/test_fg_est.py index 9699adc1..64f535a7 100644 --- a/tests/gcp/test_fg_est.py +++ b/tests/gcp/test_fg_est.py @@ -8,7 +8,7 @@ import pytest import pyttb as ttb -from pyttb.gcp.fg_est import estimate, estimate_helper +from pyttb.decompositions.cp.gcp.fg_est import estimate, estimate_helper def test_estimate_helper(): diff --git a/tests/gcp/test_fg_setup.py b/tests/gcp/test_fg_setup.py index 2e311352..073df065 100644 --- a/tests/gcp/test_fg_setup.py +++ b/tests/gcp/test_fg_setup.py @@ -10,8 +10,8 @@ import pytest import pyttb as ttb -from pyttb.gcp import fg_setup -from pyttb.gcp.handles import Objectives +from pyttb.decompositions.cp.gcp import fg_setup +from pyttb.decompositions.cp.gcp.handles import Objectives def test_setup_success(): diff --git a/tests/gcp/test_gcp_opt.py b/tests/gcp/test_gcp_opt.py index d266bb23..4942e8b1 100644 --- a/tests/gcp/test_gcp_opt.py +++ b/tests/gcp/test_gcp_opt.py @@ -8,8 +8,8 @@ import pytest import pyttb as ttb -from pyttb.gcp.handles import Objectives, gaussian, gaussian_grad -from pyttb.gcp.optimizers import LBFGSB, SGD +from pyttb.decompositions.cp.gcp.handles import Objectives, gaussian, gaussian_grad +from pyttb.decompositions.cp.gcp.optimizers import LBFGSB, SGD class TestGcpOpt: diff --git a/tests/gcp/test_handles.py b/tests/gcp/test_handles.py index 06270539..cc0702be 100644 --- a/tests/gcp/test_handles.py +++ b/tests/gcp/test_handles.py @@ -11,8 +11,8 @@ import scipy import pyttb as ttb -from pyttb.gcp import handles -from pyttb.gcp.handles import EPS +from pyttb.decompositions.cp.gcp import handles +from pyttb.decompositions.cp.gcp.handles import EPS @pytest.fixture() diff --git a/tests/gcp/test_optimizers.py b/tests/gcp/test_optimizers.py index dd75c1a9..46292428 100644 --- a/tests/gcp/test_optimizers.py +++ b/tests/gcp/test_optimizers.py @@ -10,9 +10,9 @@ import pytest import pyttb as ttb -from pyttb.gcp import samplers -from pyttb.gcp.handles import gaussian, gaussian_grad -from pyttb.gcp.optimizers import LBFGSB, SGD, Adagrad, Adam +from pyttb.decompositions.cp.gcp import samplers +from pyttb.decompositions.cp.gcp.handles import gaussian, gaussian_grad +from pyttb.decompositions.cp.gcp.optimizers import LBFGSB, SGD, Adagrad, Adam if TYPE_CHECKING: from pyttb.gcp.fg_setup import function_type diff --git a/tests/gcp/test_samplers.py b/tests/gcp/test_samplers.py index 0836bdc4..6f6120dc 100644 --- a/tests/gcp/test_samplers.py +++ b/tests/gcp/test_samplers.py @@ -8,7 +8,7 @@ import pytest import pyttb as ttb -from pyttb.gcp import samplers +from pyttb.decompositions.cp.gcp import samplers from pyttb.pyttb_utils import tt_sub2ind diff --git a/tests/test_cp_als.py b/tests/test_cp_als.py index b1a180b3..d663feaa 100644 --- a/tests/test_cp_als.py +++ b/tests/test_cp_als.py @@ -6,7 +6,8 @@ import numpy as np import pytest -import pyttb as ttb +from pyttb.decompositions.cp import cp_als +from pyttb.tensors import ktensor, sptensor, tensor, ttensor @pytest.fixture() @@ -14,7 +15,7 @@ def sample_tensor(): data = np.array([[29, 39.0], [63.0, 85.0]]) shape = (2, 2) params = {"data": data, "shape": shape} - tensorInstance = ttb.tensor(data, shape) + tensorInstance = tensor(data, shape) return params, tensorInstance @@ -24,53 +25,53 @@ def sample_sptensor(): vals = np.array([[0.5], [0.5], [0.5]]) shape = (2, 2) data = {"subs": subs, "vals": vals, "shape": shape} - sptensorInstance = ttb.sptensor(subs, vals, shape) + sptensorInstance = sptensor(subs, vals, shape) return data, sptensorInstance @pytest.fixture() def sample_ttensor(): """Simple TTENSOR to verify by hand""" - core = ttb.tensor(np.ones((2, 3))) + core = tensor(np.ones((2, 3))) factors = [ np.ones((5, 2)), np.ones((2, 3)), ] - ttensorInstance = ttb.ttensor(core, factors) + ttensorInstance = ttensor(core, factors) return ttensorInstance @pytest.fixture() def random_ttensor(): """Arbitrary TTENSOR to verify consistency between alternative operations""" - core = ttb.tensor(np.random.random((2, 3, 4))) + core = tensor(np.random.random((2, 3, 4))) factors = [ np.random.random((5, 2)), np.random.random((2, 3)), np.random.random((4, 4)), ] - ttensorInstance = ttb.ttensor(core, factors) + ttensorInstance = ttensor(core, factors) return ttensorInstance def test_cp_als_tensor_default_init(capsys, sample_tensor): (data, T) = sample_tensor - (M, Minit, output) = ttb.cp_als(T, 2) + (M, Minit, output) = cp_als(T, 2) capsys.readouterr() assert pytest.approx(output["fit"]) == 1 def test_cp_als_tensor_nvecs_init(capsys, sample_tensor): (data, T) = sample_tensor - (M, Minit, output) = ttb.cp_als(T, 1, init="nvecs") + (M, Minit, output) = cp_als(T, 1, init="nvecs") capsys.readouterr() assert pytest.approx(output["fit"], 1) == 0 def test_cp_als_tensor_ktensor_init(capsys, sample_tensor): (data, T) = sample_tensor - KInit = ttb.ktensor.from_function(np.random.random_sample, T.shape, 2) - (M, Minit, output) = ttb.cp_als(T, 2, init=KInit) + KInit = ktensor.from_function(np.random.random_sample, T.shape, 2) + (M, Minit, output) = cp_als(T, 2, init=KInit) capsys.readouterr() assert pytest.approx(output["fit"]) == 1 @@ -80,54 +81,54 @@ def test_cp_als_incorrect_init(capsys, sample_tensor): # unsupported init type with pytest.raises(AssertionError) as excinfo: - (M, Minit, output) = ttb.cp_als(T, 2, init="init") + (M, Minit, output) = cp_als(T, 2, init="init") assert "The selected initialization method is not supported" in str(excinfo) # incorrect size of initial ktensor Tshape_incorrect = list(T.shape) Tshape_incorrect[0] = Tshape_incorrect[0] + 1 Tshape_incorrect = tuple(Tshape_incorrect) - KInit = ttb.ktensor.from_function(np.random.random_sample, Tshape_incorrect, 2) + KInit = ktensor.from_function(np.random.random_sample, Tshape_incorrect, 2) with pytest.raises(AssertionError) as excinfo: - (M, Minit, output) = ttb.cp_als(T, 2, init=KInit) + (M, Minit, output) = cp_als(T, 2, init=KInit) assert "Mode 0 of the initial guess is the wrong size" in str(excinfo) def test_cp_als_sptensor_default_init(capsys, sample_sptensor): (data, T) = sample_sptensor - (M, Minit, output) = ttb.cp_als(T, 2) + (M, Minit, output) = cp_als(T, 2) capsys.readouterr() assert pytest.approx(output["fit"]) == 1 def test_cp_als_sptensor_nvecs_init(capsys, sample_sptensor): (data, T) = sample_sptensor - (M, Minit, output) = ttb.cp_als(T, 1, init="nvecs") + (M, Minit, output) = cp_als(T, 1, init="nvecs") capsys.readouterr() assert pytest.approx(output["fit"], 1) == 0 def test_cp_als_sptensor_ktensor_init(capsys, sample_sptensor): (data, T) = sample_sptensor - KInit = ttb.ktensor.from_function(np.random.random_sample, T.shape, 2) - (M, Minit, output) = ttb.cp_als(T, 2, init=KInit) + KInit = ktensor.from_function(np.random.random_sample, T.shape, 2) + (M, Minit, output) = cp_als(T, 2, init=KInit) capsys.readouterr() assert pytest.approx(output["fit"]) == 1 def test_cp_als_ttensor_default_init(capsys, sample_ttensor): T = sample_ttensor - (M, Minit, output) = ttb.cp_als(T, 1) + (M, Minit, output) = cp_als(T, 1) capsys.readouterr() assert pytest.approx(output["fit"]) == 1 def test_cp_als_ttensor_default_init_consistency(capsys, random_ttensor): T = random_ttensor - KInit = ttb.ktensor.from_function(np.random.random_sample, T.shape, 2) - _, _, output = ttb.cp_als(T, 2, init=KInit) + KInit = ktensor.from_function(np.random.random_sample, T.shape, 2) + _, _, output = cp_als(T, 2, init=KInit) capsys.readouterr() - _, _, dense_output = ttb.cp_als(T.full(), 2, init=KInit) + _, _, dense_output = cp_als(T.full(), 2, init=KInit) capsys.readouterr() assert pytest.approx(output["fit"]) == dense_output["fit"] @@ -137,26 +138,26 @@ def test_cp_als_tensor_dimorder(capsys, sample_tensor): # default dimorder dimorder = [i for i in range(T.ndims)] - (M, Minit, output) = ttb.cp_als(T, 2, dimorder=dimorder) + (M, Minit, output) = cp_als(T, 2, dimorder=dimorder) capsys.readouterr() assert pytest.approx(output["fit"]) == 1 # reverse should work dimorder = [T.ndims - i - 1 for i in range(T.ndims)] - (M, Minit, output) = ttb.cp_als(T, 2, dimorder=dimorder) + (M, Minit, output) = cp_als(T, 2, dimorder=dimorder) capsys.readouterr() assert pytest.approx(output["fit"]) == 1 # dimorder not a list with pytest.raises(AssertionError) as excinfo: - (M, Minit, output) = ttb.cp_als(T, 2, dimorder=2) + (M, Minit, output) = cp_als(T, 2, dimorder=2) assert "Dimorder must be a list" in str(excinfo) # dimorder not a permutation of [range(tensor.ndims)] dimorder = [i for i in range(T.ndims)] dimorder[-1] = dimorder[-1] + 1 with pytest.raises(AssertionError) as excinfo: - (M, Minit, output) = ttb.cp_als(T, 2, dimorder=dimorder) + (M, Minit, output) = cp_als(T, 2, dimorder=dimorder) assert "Dimorder must be a list or permutation of range(tensor.ndims)" in str( excinfo ) @@ -164,15 +165,15 @@ def test_cp_als_tensor_dimorder(capsys, sample_tensor): def test_cp_als_tensor_zeros(capsys, sample_tensor): # 2-way tensor - T2 = ttb.tensor.from_function(np.zeros, (2, 2)) - (M2, Minit2, output2) = ttb.cp_als(T2, 2) + T2 = tensor.from_function(np.zeros, (2, 2)) + (M2, Minit2, output2) = cp_als(T2, 2) capsys.readouterr() assert pytest.approx(output2["fit"], 1) == 0 assert output2["normresidual"] == 0 # 3-way tensor - T3 = ttb.tensor.from_function(np.zeros, (3, 4, 5)) - (M3, Minit3, output3) = ttb.cp_als(T3, 2) + T3 = tensor.from_function(np.zeros, (3, 4, 5)) + (M3, Minit3, output3) = cp_als(T3, 2) capsys.readouterr() assert pytest.approx(output3["fit"], 1) == 0 assert output3["normresidual"] == 0 @@ -181,17 +182,17 @@ def test_cp_als_tensor_zeros(capsys, sample_tensor): def test_cp_als_sptensor_zeros(capsys): # 2-way tensor shape2 = (2, 2) - T2 = ttb.sptensor.from_function(np.zeros, shape2, np.ceil(np.prod(shape2) / 2.0)) + T2 = sptensor.from_function(np.zeros, shape2, np.ceil(np.prod(shape2) / 2.0)) print(T2) - (M2, Minit2, output2) = ttb.cp_als(T2, 2) + (M2, Minit2, output2) = cp_als(T2, 2) capsys.readouterr() assert pytest.approx(output2["fit"], 1) == 0 assert output2["normresidual"] == 0 # 3-way tensor shape3 = (2, 2) - T3 = ttb.sptensor.from_function(np.zeros, shape3, np.ceil(np.prod(shape3) / 2.0)) - (M3, Minit3, output3) = ttb.cp_als(T3, 2) + T3 = sptensor.from_function(np.zeros, shape3, np.ceil(np.prod(shape3) / 2.0)) + (M3, Minit3, output3) = cp_als(T3, 2) capsys.readouterr() assert pytest.approx(output3["fit"], 1) == 0 assert output3["normresidual"] == 0 @@ -199,17 +200,17 @@ def test_cp_als_sptensor_zeros(capsys): def test_cp_als_tensor_pass_params(capsys, sample_tensor): _, T = sample_tensor - KInit = ttb.ktensor.from_function(np.random.random_sample, T.shape, 2) + KInit = ktensor.from_function(np.random.random_sample, T.shape, 2) - _, _, output = ttb.cp_als(T, 2, init=KInit, maxiters=2) + _, _, output = cp_als(T, 2, init=KInit, maxiters=2) capsys.readouterr() # passing the same parameters back to the method will yield the exact same results - _, _, output1 = ttb.cp_als(T, 2, init=KInit, **output["params"]) + _, _, output1 = cp_als(T, 2, init=KInit, **output["params"]) capsys.readouterr() # changing the order should also work - _, _, output2 = ttb.cp_als(T, 2, **output["params"], init=KInit) + _, _, output2 = cp_als(T, 2, **output["params"], init=KInit) capsys.readouterr() assert output["params"] == output1["params"] @@ -220,17 +221,17 @@ def test_cp_als_tensor_printitn(capsys, sample_tensor): _, T = sample_tensor # default printitn - ttb.cp_als(T, 2, printitn=1, maxiters=2) + cp_als(T, 2, printitn=1, maxiters=2) capsys.readouterr() # zero printitn - ttb.cp_als(T, 2, printitn=0, maxiters=2) + cp_als(T, 2, printitn=0, maxiters=2) capsys.readouterr() # negative printitn - ttb.cp_als(T, 2, printitn=-1, maxiters=2) + cp_als(T, 2, printitn=-1, maxiters=2) capsys.readouterr() # float printitn - ttb.cp_als(T, 2, printitn=1.5, maxiters=2) + cp_als(T, 2, printitn=1.5, maxiters=2) capsys.readouterr() diff --git a/tests/test_cp_apr.py b/tests/test_cp_apr.py index 10c4d7e4..433b03ca 100644 --- a/tests/test_cp_apr.py +++ b/tests/test_cp_apr.py @@ -6,8 +6,8 @@ import numpy as np import pytest -import pyttb as ttb -from pyttb.cp_apr import ( +from pyttb.decompositions.cp import cp_apr +from pyttb.decompositions.cp.apr import ( calc_partials, calculate_phi, calculate_pi, @@ -20,6 +20,7 @@ tt_loglikelihood_row, vectorize_for_mu, ) +from pyttb.tensors import ktensor, tensor @pytest.fixture() @@ -28,7 +29,7 @@ def sample_tensor1(): fm0 = np.array([[0.0, 0.0], [3.0, 4.0]]) fm1 = np.array([[0.0, 6.0], [7.0, 8.0]]) factor_matrices = [fm0, fm1] - ktensorInstance = ttb.ktensor(factor_matrices, weights) + ktensorInstance = ktensor(factor_matrices, weights) tensorInstance = ktensorInstance.full() return tensorInstance, ktensorInstance @@ -39,7 +40,7 @@ def sample_tensor2(): fm0 = np.array([[1.0, 1.0], [3.0, 4.0]]) fm1 = np.array([[1.0, 6.0], [7.0, 8.0]]) factor_matrices = [fm0, fm1] - ktensorInstance = ttb.ktensor(factor_matrices, weights) + ktensorInstance = ktensor(factor_matrices, weights) tensorInstance = ktensorInstance.full() return tensorInstance, ktensorInstance @@ -50,7 +51,7 @@ def default_init_ktensor(): fm0 = np.array([[1.0, 1.0], [1.0, 1.0]]) fm1 = np.array([[1.0, 1.0], [1.0, 1.0]]) factor_matrices = [fm0, fm1] - ktensorInstance = ttb.ktensor(factor_matrices=factor_matrices, weights=weights) + ktensorInstance = ktensor(factor_matrices=factor_matrices, weights=weights) return ktensorInstance @@ -59,7 +60,7 @@ def rand_ktensor(): fm0 = np.array([[0.69646919, 0.28613933], [0.22685145, 0.55131477]]) fm1 = np.array([[0.71946897, 0.42310646], [0.9807642, 0.68482974]]) factor_matrices = [fm0, fm1] - ktensorInstance = ttb.ktensor(factor_matrices=factor_matrices) + ktensorInstance = ktensor(factor_matrices=factor_matrices) return ktensorInstance @@ -75,7 +76,7 @@ def test_loglikelihood(): fm0 = np.array([[0.0, 0.0], [3.0, 4.0]]) fm1 = np.array([[0.0, 6.0], [7.0, 8.0]]) factor_matrices = [fm0, fm1] - ktensorInstance = ttb.ktensor(factor_matrices, weights) + ktensorInstance = ktensor(factor_matrices, weights) tensorInstance = ktensorInstance.full() sptensorInstance = tensorInstance.to_sptensor() @@ -96,8 +97,8 @@ def test_loglikelihood(): factor_matrices = [] for i in range(n): factor_matrices.append(np.abs(np.random.normal(size=(5, n)))) - ktensorInstance = ttb.ktensor(factor_matrices, weights) - tensorInstance = ttb.tensor(np.abs(np.random.normal(size=ktensorInstance.shape))) + ktensorInstance = ktensor(factor_matrices, weights) + tensorInstance = tensor(np.abs(np.random.normal(size=ktensorInstance.shape))) sptensorInstance = tensorInstance.to_sptensor() vector = ktensorInstance.full().data.ravel() @@ -121,7 +122,7 @@ def test_calculatePi(): fm0 = np.array([[0.0, 0.0], [3.0, 4.0]]) fm1 = np.array([[0.0, 6.0], [7.0, 8.0]]) factor_matrices = [fm0, fm1] - ktensorInstance = ttb.ktensor(factor_matrices, weights) + ktensorInstance = ktensor(factor_matrices, weights) tensorInstance = ktensorInstance.full() sptensorInstance = tensorInstance.to_sptensor() answer = np.array([[0, 6], [7, 8]]) @@ -148,8 +149,8 @@ def test_calculatePi(): factor_matrices = [] for i in range(n): factor_matrices.append(np.abs(np.random.normal(size=(5, n)))) - ktensorInstance = ttb.ktensor(factor_matrices, weights) - tensorInstance = ttb.tensor(np.abs(np.random.normal(size=ktensorInstance.shape))) + ktensorInstance = ktensor(factor_matrices, weights) + tensorInstance = tensor(np.abs(np.random.normal(size=ktensorInstance.shape))) sptensorInstance = tensorInstance.to_sptensor() print(tensorInstance.shape) @@ -168,7 +169,7 @@ def test_calculatePhi(): fm0 = np.array([[0.0, 0.0], [3.0, 4.0]]) fm1 = np.array([[0.0, 6.0], [7.0, 8.0]]) factor_matrices = [fm0, fm1] - ktensorInstance = ttb.ktensor(factor_matrices, weights) + ktensorInstance = ktensor(factor_matrices, weights) tensorInstance = ktensorInstance.full() sptensorInstance = tensorInstance.to_sptensor() answer = np.array([[0, 0], [11.226415094339623, 24.830188679245282]]) @@ -185,7 +186,7 @@ def test_cpapr_mu(capsys, sample_tensor1, default_init_ktensor): # Test simple case tensorInstance, ktensorSolnInstance = sample_tensor1 ktensorInitInstance = default_init_ktensor - M, _, _ = ttb.cp_apr( + M, _, _ = cp_apr( input_tensor=tensorInstance, rank=2, init=ktensorInitInstance, printinneritn=1 ) @@ -194,14 +195,12 @@ def test_cpapr_mu(capsys, sample_tensor1, default_init_ktensor): assert np.isclose(M.full().data, ktensorSolnInstance.full().data).all() # Assert given an initial guess of the final answer yields immediate convergence - M, _, output = ttb.cp_apr( - input_tensor=tensorInstance, rank=2, init=ktensorSolnInstance - ) + M, _, output = cp_apr(input_tensor=tensorInstance, rank=2, init=ktensorSolnInstance) capsys.readouterr() assert output["nTotalIters"] == 2 # Assert that params from previous run can be provided as input - M, _, output2 = ttb.cp_apr( + M, _, output2 = cp_apr( input_tensor=tensorInstance, rank=2, init=ktensorSolnInstance, @@ -212,7 +211,7 @@ def test_cpapr_mu(capsys, sample_tensor1, default_init_ktensor): # Edge cases # Confirm timeout works - _ = ttb.cp_apr( + _ = cp_apr( input_tensor=tensorInstance, rank=2, init=ktensorInitInstance, stoptime=-1 ) out, _ = capsys.readouterr() @@ -226,7 +225,7 @@ def test_cpapr_pdnr(capsys, sample_tensor1, default_init_ktensor): # Test simple case tensorInstance, ktensorSolnInstance = sample_tensor1 ktensorInitInstance = default_init_ktensor - M, _, _ = ttb.cp_apr( + M, _, _ = cp_apr( input_tensor=tensorInstance, rank=2, init=ktensorInitInstance, @@ -241,14 +240,14 @@ def test_cpapr_pdnr(capsys, sample_tensor1, default_init_ktensor): # Try solve with sptensor sptensorInstance = tensorInstance.to_sptensor() - M, _, _ = ttb.cp_apr( + M, _, _ = cp_apr( input_tensor=tensorInstance, rank=2, init=ktensorInitInstance, algorithm="pdnr" ) capsys.readouterr() assert np.isclose(M.full().data, ktensorSolnInstance.full().data, rtol=1e-04).all() # Do not precompute indices - M, _, output = ttb.cp_apr( + M, _, output = cp_apr( input_tensor=sptensorInstance, rank=2, init=ktensorInitInstance, @@ -259,13 +258,13 @@ def test_cpapr_pdnr(capsys, sample_tensor1, default_init_ktensor): assert np.isclose(M.full().data, ktensorSolnInstance.full().data, rtol=1e-04).all() # Assert that params from previous run can be provided as input - M, _, output2 = ttb.cp_apr(input_tensor=tensorInstance, rank=2, **output["params"]) + M, _, output2 = cp_apr(input_tensor=tensorInstance, rank=2, **output["params"]) capsys.readouterr() assert output["params"] == output2["params"] # Edge cases # Confirm timeout works - _ = ttb.cp_apr( + _ = cp_apr( input_tensor=tensorInstance, rank=2, init=ktensorInitInstance, @@ -291,7 +290,7 @@ def test_cpapr_pqnr( ktensorInitInstance = default_init_ktensor with pytest.raises(AssertionError) as excinfo: - M, _, _ = ttb.cp_apr( + M, _, _ = cp_apr( input_tensor=tensorInstance, rank=2, init=ktensorInitInstance, @@ -303,7 +302,7 @@ def test_cpapr_pqnr( # Test simple case tensorInstance, ktensorSolnInstance = sample_tensor2 ktensorInitInstance = rand_ktensor - M, _, _ = ttb.cp_apr( + M, _, _ = cp_apr( input_tensor=tensorInstance, rank=2, init=ktensorInitInstance, @@ -315,7 +314,7 @@ def test_cpapr_pqnr( # Try solve with sptensor sptensorInstance = tensorInstance.to_sptensor() - M, _, _ = ttb.cp_apr( + M, _, _ = cp_apr( input_tensor=sptensorInstance, rank=2, init=ktensorInitInstance, @@ -325,7 +324,7 @@ def test_cpapr_pqnr( assert np.isclose(M.full().data, ktensorSolnInstance.full().data, rtol=1e-01).all() # Do not precompute indices - M, _, output = ttb.cp_apr( + M, _, output = cp_apr( input_tensor=sptensorInstance, rank=2, init=ktensorInitInstance, @@ -336,7 +335,7 @@ def test_cpapr_pqnr( assert np.isclose(M.full().data, ktensorSolnInstance.full().data, rtol=1e-01).all() # Assert that params from previous run can be provided as input - M, _, output2 = ttb.cp_apr( + M, _, output2 = cp_apr( input_tensor=sptensorInstance, rank=2, init=ktensorInitInstance, @@ -347,7 +346,7 @@ def test_cpapr_pqnr( # Edge cases # Confirm timeout works - _ = ttb.cp_apr( + _ = cp_apr( input_tensor=tensorInstance, rank=2, init=ktensorInitInstance, @@ -367,7 +366,7 @@ def test_calculatepi_prowsubprob(): fm0 = np.array([[0.0, 0.0], [3.0, 4.0]]) fm1 = np.array([[0.0, 6.0], [7.0, 8.0]]) factor_matrices = [fm0, fm1] - ktensorInstance = ttb.ktensor(factor_matrices, weights) + ktensorInstance = ktensor(factor_matrices, weights) tensorInstance = ktensorInstance.full() sptensorInstance = tensorInstance.to_sptensor() answer = np.array([[0, 6], [7, 8]]) @@ -402,7 +401,7 @@ def test_calc_partials(): fm0 = np.array([[0.0, 0.0], [3.0, 4.0]]) fm1 = np.array([[0.0, 6.0], [7.0, 8.0]]) factor_matrices = [fm0, fm1] - ktensorInstance = ttb.ktensor(factor_matrices, weights) + ktensorInstance = ktensor(factor_matrices, weights) tensorInstance = ktensorInstance.full() # print(tensorInstance[:, 0]) sptensorInstance = tensorInstance.to_sptensor() @@ -473,7 +472,7 @@ def test_getHessian(): fm0 = np.array([[0.0, 0.0], [3.0, 4.0]]) fm1 = np.array([[0.0, 6.0], [7.0, 8.0]]) factor_matrices = [fm0, fm1] - ktensorInstance = ttb.ktensor(factor_matrices, weights) + ktensorInstance = ktensor(factor_matrices, weights) tensorInstance = ktensorInstance.full() # print(tensorInstance[:, 0]) free_indices = [0, 1] @@ -521,7 +520,7 @@ def test_getSearchDirPdnr(): fm0 = np.array([[0.0, 0.0], [3.0, 4.0]]) fm1 = np.array([[0.0, 6.0], [7.0, 8.0]]) factor_matrices = [fm0, fm1] - ktensorInstance = ttb.ktensor(factor_matrices, weights) + ktensorInstance = ktensor(factor_matrices, weights) tensorInstance = ktensorInstance.full() # print(tensorInstance[:, 0]) sptensorInstance = tensorInstance.to_sptensor() @@ -559,7 +558,7 @@ def test_tt_loglikelihood_row(): fm0 = np.array([[0.0, 0.0], [3.0, 4.0]]) fm1 = np.array([[0.0, 6.0], [7.0, 8.0]]) factor_matrices = [fm0, fm1] - ktensorInstance = ttb.ktensor(factor_matrices, weights) + ktensorInstance = ktensor(factor_matrices, weights) tensorInstance = ktensorInstance.full() # print(tensorInstance[:, 0]) sptensorInstance = tensorInstance.to_sptensor() @@ -576,7 +575,7 @@ def test_tt_linesearch_prowsubprob(): fm0 = np.array([[0.0, 0.0], [3.0, 4.0]]) fm1 = np.array([[0.0, 6.0], [7.0, 8.0]]) factor_matrices = [fm0, fm1] - ktensorInstance = ttb.ktensor(factor_matrices, weights) + ktensorInstance = ktensor(factor_matrices, weights) tensorInstance = ktensorInstance.full() # print(tensorInstance[:, 0]) sptensorInstance = tensorInstance.to_sptensor() @@ -617,7 +616,7 @@ def test_getSearchDirPqnr(): fm0 = np.array([[0.0, 0.0], [3.0, 4.0]]) fm1 = np.array([[0.0, 6.0], [7.0, 8.0]]) factor_matrices = [fm0, fm1] - ktensorInstance = ttb.ktensor(factor_matrices, weights) + ktensorInstance = ktensor(factor_matrices, weights) tensorInstance = ktensorInstance.full() # print(tensorInstance[:, 0]) sptensorInstance = tensorInstance.to_sptensor() @@ -635,23 +634,23 @@ def test_getSearchDirPqnr(): def test_cp_apr_negative_tests(): - dense_tensor = ttb.tensor(np.ones((2, 2, 2))) + dense_tensor = tensor(np.ones((2, 2, 2))) bad_weights = np.array([8.0]) bad_factors = [np.array([[1.0]])] * 3 - bad_initial_guess_shape = ttb.ktensor(bad_factors, bad_weights) + bad_initial_guess_shape = ktensor(bad_factors, bad_weights) with pytest.raises(AssertionError): - ttb.cp_apr(dense_tensor, init=bad_initial_guess_shape, rank=1) + cp_apr(dense_tensor, init=bad_initial_guess_shape, rank=1) good_weights = np.array([8.0] * 3) good_factor = np.array([[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]]) - bad_initial_guess_factors = ttb.ktensor([-1.0 * good_factor] * 3, good_weights) + bad_initial_guess_factors = ktensor([-1.0 * good_factor] * 3, good_weights) with pytest.raises(AssertionError): - ttb.cp_apr(dense_tensor, init=bad_initial_guess_factors, rank=3) - bad_initial_guess_weight = ttb.ktensor([good_factor] * 3, -1.0 * good_weights) + cp_apr(dense_tensor, init=bad_initial_guess_factors, rank=3) + bad_initial_guess_weight = ktensor([good_factor] * 3, -1.0 * good_weights) with pytest.raises(AssertionError): - ttb.cp_apr(dense_tensor, init=bad_initial_guess_weight, rank=3) + cp_apr(dense_tensor, init=bad_initial_guess_weight, rank=3) with pytest.raises(AssertionError): - ttb.cp_apr(dense_tensor, rank=1, algorithm="UNSUPPORTED_ALG") + cp_apr(dense_tensor, rank=1, algorithm="UNSUPPORTED_ALG") with pytest.raises(ValueError): - ttb.cp_apr(dense_tensor, rank=1, init="Bad initial guess") + cp_apr(dense_tensor, rank=1, init="Bad initial guess") diff --git a/tests/test_create_problem.py b/tests/test_create_problem.py index 9d16c2b1..3cf82dfb 100644 --- a/tests/test_create_problem.py +++ b/tests/test_create_problem.py @@ -15,6 +15,7 @@ generate_data_sparse, generate_solution, ) +from pyttb.tensors import ktensor, tensor, ttensor class TestDataclasses: @@ -86,7 +87,7 @@ def test_generate_solution_cp(): shape = (2, 2, 2) cp_params = CPProblem(shape) model = generate_solution(cp_params) - assert isinstance(model, ttb.ktensor) + assert isinstance(model, ktensor) assert model.shape == shape # TODO could test with different generators and enforce that they actually get used @@ -98,7 +99,7 @@ def test_generate_data_cp(): cp_params = CPProblem(shape) model = generate_solution(cp_params) data = generate_data(model, cp_params) - assert isinstance(data, ttb.tensor) + assert isinstance(data, tensor) assert data.shape == model.shape @@ -107,14 +108,14 @@ def test_generate_solution_tucker(): shape = (2, 2, 2) tucker_params = TuckerProblem(shape) model = generate_solution(tucker_params) - assert isinstance(model, ttb.ttensor) + assert isinstance(model, ttensor) assert model.shape == shape # Smoke test with a tensor core generator shape = (2, 2, 2) tucker_params = TuckerProblem(shape, core_generator=ttb.tenrand) model = generate_solution(tucker_params) - assert isinstance(model, ttb.ttensor) + assert isinstance(model, ttensor) assert model.shape == shape # TODO could test with different generators and enforce that they actually get used @@ -125,7 +126,7 @@ def test_generate_data_tucker(): tucker_params = TuckerProblem(shape) model = generate_solution(tucker_params) data = generate_data(model, tucker_params) - assert isinstance(data, ttb.tensor) + assert isinstance(data, tensor) assert data.shape == model.shape @@ -203,7 +204,7 @@ def test_generate_data_sparse_value_errors(): # Test negative weights factor_matrices = [np.random.random((3, 2)) for _ in range(3)] negative_weights = np.array([-1.0, 1.0]) # One negative weight - solution = ttb.ktensor(factor_matrices, negative_weights) + solution = ktensor(factor_matrices, negative_weights) problem_params = CPProblem(shape, sparse_generation=0.5) with pytest.raises(ValueError): @@ -213,7 +214,7 @@ def test_generate_data_sparse_value_errors(): factor_matrices = [np.random.random((3, 2)) for _ in range(3)] factor_matrices[0][0, 0] = -1.0 # Make one element negative positive_weights = np.array([1.0, 1.0]) - solution = ttb.ktensor(factor_matrices, positive_weights) + solution = ktensor(factor_matrices, positive_weights) problem_params = CPProblem(shape, sparse_generation=0.5) with pytest.raises(ValueError): @@ -222,7 +223,7 @@ def test_generate_data_sparse_value_errors(): # Test missing sparse_generation factor_matrices = [np.random.random((3, 2)) for _ in range(3)] positive_weights = np.array([1.0, 1.0]) - solution = ttb.ktensor(factor_matrices, positive_weights) + solution = ktensor(factor_matrices, positive_weights) problem_params = CPProblem(shape, sparse_generation=None) with pytest.raises(ValueError): diff --git a/tests/test_hosvd.py b/tests/test_hosvd.py index cfe0c62b..4967b7fa 100644 --- a/tests/test_hosvd.py +++ b/tests/test_hosvd.py @@ -6,7 +6,8 @@ import numpy as np import pytest -import pyttb as ttb +from pyttb.decompositions.tucker import hosvd +from pyttb.tensors import tensor, ttensor @pytest.fixture() @@ -14,7 +15,7 @@ def sample_tensor(): data = np.array([[29, 39.0], [63.0, 85.0]]) shape = (2, 2) params = {"data": data, "shape": shape} - tensorInstance = ttb.tensor(data, shape) + tensorInstance = tensor(data, shape) return params, tensorInstance @@ -23,25 +24,25 @@ def sample_tensor_3way(): shape = (3, 3, 3) data = np.array(range(1, 28)).reshape(shape, order="F") params = {"data": data, "shape": shape} - tensorInstance = ttb.tensor(data, shape) + tensorInstance = tensor(data, shape) return params, tensorInstance def test_hosvd_simple_convergence(capsys, sample_tensor): (data, T) = sample_tensor tol = 1e-4 - result = ttb.hosvd(T, tol) + result = hosvd(T, tol) assert (result.full() - T).norm() / T.norm() < tol, "Failed to converge" tol = 1e-4 - result = ttb.hosvd(T, tol, sequential=False) + result = hosvd(T, tol, sequential=False) assert (result.full() - T).norm() / T.norm() < tol, ( "Failed to converge for non-sequential option" ) impossible_tol = 1e-20 with pytest.warns(UserWarning): - result = ttb.hosvd(T, impossible_tol) + result = hosvd(T, impossible_tol) assert (result.full() - T).norm() / T.norm() > impossible_tol, ( "Converged beyond provided precision" ) @@ -49,36 +50,36 @@ def test_hosvd_simple_convergence(capsys, sample_tensor): def test_hosvd_default_init(capsys, sample_tensor): (data, T) = sample_tensor - _ = ttb.hosvd(T, 1) + _ = hosvd(T, 1) def test_hosvd_smoke_test_verbosity(capsys, sample_tensor): """For now just make sure verbosity calcs don't crash""" (data, T) = sample_tensor - ttb.hosvd(T, 1, verbosity=10) + hosvd(T, 1, verbosity=10) def test_hosvd_incorrect_ranks(capsys, sample_tensor): (data, T) = sample_tensor ranks = list(range(T.ndims - 1)) with pytest.raises(ValueError): - _ = ttb.hosvd(T, 1, ranks=ranks) + _ = hosvd(T, 1, ranks=ranks) def test_hosvd_incorrect_dimorder(capsys, sample_tensor): (data, T) = sample_tensor dimorder = list(range(T.ndims - 1)) with pytest.raises(ValueError): - _ = ttb.hosvd(T, 1, dimorder=dimorder) + _ = hosvd(T, 1, dimorder=dimorder) dimorder = 1 with pytest.raises(ValueError): - _ = ttb.hosvd(T, 1, dimorder=dimorder) + _ = hosvd(T, 1, dimorder=dimorder) def test_hosvd_3way(capsys, sample_tensor_3way): (data, T) = sample_tensor_3way - M = ttb.hosvd(T, 1e-4, verbosity=0) + M = hosvd(T, 1e-4, verbosity=0) capsys.readouterr() print(f"M=\n{M}") core = np.array( @@ -114,7 +115,7 @@ def test_hosvd_3way(capsys, sample_tensor_3way): [-8.359253825873615e-01, -3.668270547267537e-01], ] ) - expected = ttb.ttensor(ttb.tensor(core), [fm0, fm1, fm2]) + expected = ttensor(tensor(core), [fm0, fm1, fm2]) assert np.allclose(M.double(), expected.double()) assert np.allclose(np.abs(M.core.data), np.abs(core)) assert np.allclose(np.abs(M.factor_matrices[0]), np.abs(fm0)) diff --git a/tests/test_tensor.py b/tests/test_tensor.py index 5bfe6afd..7a1d97d6 100644 --- a/tests/test_tensor.py +++ b/tests/test_tensor.py @@ -9,7 +9,7 @@ import pytest import pyttb as ttb -from pyttb.tensor import min_split, mttv_left, mttv_mid +from pyttb.tensors.dense import min_split, mttv_left, mttv_mid from tests.test_utils import assert_consistent_order