Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nick/tenmat docs #294

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
TENMAT: Add copy argument to give option to try and optimize views.
  • Loading branch information
ntjohnson1 committed Dec 16, 2023
commit 5bf98952cb4c559ffda09dfed8123a95d09cc32e
52 changes: 32 additions & 20 deletions pyttb/tenmat.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ class tenmat:

__slots__ = ("tshape", "rindices", "cindices", "data")

def __init__( # noqa: PLR0912
def __init__( # noqa: PLR0912, PLR0913
self,
data: Optional[np.ndarray] = None,
rdims: Optional[np.ndarray] = None,
cdims: Optional[np.ndarray] = None,
tshape: Optional[Tuple[int, ...]] = None,
copy: bool = True,
):
"""
Construct a :class:`pyttb.tenmat` from explicit components.
Expand All @@ -41,6 +42,8 @@ def __init__( # noqa: PLR0912
Which dimensions of original tensor map to columns.
tshape:
Original tensor shape.
copy:
Whether to make a copy of provided data or just reference it.

Examples
--------
Expand Down Expand Up @@ -158,7 +161,10 @@ def __init__( # noqa: PLR0912
self.tshape = tshape
self.rindices = rdims.copy()
self.cindices = cdims.copy()
self.data = np.asfortranarray(data.copy())
if copy:
self.data = data.copy()
else:
self.data = data
return

def copy(self) -> tenmat:
Expand All @@ -181,19 +187,21 @@ def copy(self) -> tenmat:
False
"""
# Create tenmat
tenmatInstance = tenmat()
tenmatInstance.tshape = self.tshape
tenmatInstance.rindices = self.rindices.copy()
tenmatInstance.cindices = self.cindices.copy()
tenmatInstance.data = self.data.copy()
return tenmatInstance
return ttb.tenmat(
self.data, self.rindices, self.cindices, self.tshape, copy=True
)

def __deepcopy__(self, memo):
return self.copy()

def to_tensor(self) -> ttb.tensor:
def to_tensor(self, copy: bool = True) -> ttb.tensor:
"""
Return copy of :class:`pyttb.tenmat` data as a :class:`pyttb.tensor`.
Return :class:`pyttb.tenmat` data as a :class:`pyttb.tensor`.

Parameters
----------
copy:
Whether to make a copy of provided data or just reference it.

Examples
--------
Expand Down Expand Up @@ -235,7 +243,10 @@ def to_tensor(self) -> ttb.tensor:
# it using ipermute.
shape = self.tshape
order = np.hstack([self.rindices, self.cindices])
data = np.reshape(self.data.copy(), np.array(shape)[order], order="F")
data = self.data
if copy:
data = self.data.copy()
data = np.reshape(data, np.array(shape)[order], order="F")
if order.size > 1:
data = np.transpose(data, np.argsort(order))
return ttb.tensor(data, shape, copy=False)
Expand Down Expand Up @@ -268,10 +279,11 @@ def ctranspose(self) -> tenmat:
[1. 1.]]
"""
return tenmat(
self.data.conj().T.copy(),
self.cindices.copy(),
self.rindices.copy(),
self.data.conj().T,
self.cindices,
self.rindices,
self.tshape,
copy=True,
)

def double(self) -> np.ndarray:
Expand Down Expand Up @@ -469,13 +481,13 @@ def __mul__(self, other):

if not tshape:
return (self.data @ other.data)[0, 0]
tenmatInstance = tenmat()
tenmatInstance.tshape = tshape
tenmatInstance.rindices = np.arange(len(self.rindices))
tenmatInstance.cindices = np.arange(len(other.cindices)) + len(
self.rindices
tenmatInstance = tenmat(
self.data @ other.data,
np.arange(len(self.rindices)),
np.arange(len(other.cindices)) + len(self.rindices),
tshape,
copy=False,
)
tenmatInstance.data = self.data @ other.data
return tenmatInstance
assert False, "tenmat multiplication only valid with scalar or tenmat objects."

Expand Down
7 changes: 5 additions & 2 deletions pyttb/tensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,7 @@ def to_tenmat(
cdims_cyclic: Optional[
Union[Literal["fc"], Literal["bc"], Literal["t"]]
] = None,
copy: bool = True,
) -> ttb.tenmat:
"""
Construct a :class:`pyttb.tenmat` from a :class:`pyttb.tensor` and
Expand All @@ -476,6 +477,8 @@ def to_tenmat(
in the order range(rdims,self.ndims()) followed by range(0, rdims).
_bc_ (backward cyclic) range(rdims-1, -1, -1) then
range(self.ndims(), rdims, -1).
copy:
Whether to make a copy of provided data or just reference it.

Notes
-----
Expand Down Expand Up @@ -570,7 +573,7 @@ def to_tenmat(
(rprod, cprod),
order="F",
)
return ttb.tenmat(data, rdims, cdims, tshape=tshape)
return ttb.tenmat(data, rdims, cdims, tshape=tshape, copy=copy)

def innerprod(
self, other: Union[tensor, ttb.sptensor, ttb.ktensor, ttb.ttensor]
Expand Down Expand Up @@ -1203,7 +1206,7 @@ def scale(
vector_self = self.to_tenmat(dims, remdims).double()
# Numpy broadcasting should be equivalent to bsxfun
result = vector_self * vector_factor
return ttb.tenmat(result, dims, remdims, self.shape).to_tensor()
return ttb.tenmat(result, dims, remdims, self.shape, copy=False).to_tensor()

def squeeze(self) -> Union[tensor, float]:
"""
Expand Down
16 changes: 16 additions & 0 deletions tests/test_tenmat.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ def test_tenmat_initialization_from_data(
tenmatNdarray2 = ttb.tenmat(ndarrayInstance2, rdims, cdims, tshape)
assert tenmatNdarray2.isequal(tenmatInstance)

# Reference instead of copy
tenmatNdarray2 = ttb.tenmat(ndarrayInstance2, rdims, cdims, tshape, copy=False)
assert tenmatNdarray2.isequal(tenmatInstance)
assert np.may_share_memory(ndarrayInstance2, tenmatNdarray2.data)

# Exceptions

## data is not numpy.ndarray
Expand Down Expand Up @@ -279,6 +284,12 @@ def test_tenmat_initialization_from_tensor_type(
assert tenmatTensorBC.shape == shapeBC
assert tenmatTensorBC.tshape == tshapeBC

# Reference only
simple_tensor = ttb.tenones((2, 2))
rdims = np.array([0])
tenmat_reference = simple_tensor.to_tenmat(rdims=rdims, copy=False)
assert np.may_share_memory(tenmat_reference.data, simple_tensor.data)

# Exceptions

# cdims_cyclic has incorrect value
Expand Down Expand Up @@ -337,6 +348,11 @@ def test_tenmat_to_tensor():
tenmatInstance4 = tensorInstance4.to_tenmat(np.array([3, 0]))
tensorTenmatInstance4 = tenmatInstance4.to_tensor()
assert tensorInstance4.isequal(tensorTenmatInstance4)
assert not np.may_share_memory(tensorTenmatInstance4.data, tenmatInstance4.data)

# Reference instead of copy
tensorTenmatInstance4_ref = tenmatInstance4.to_tensor(copy=False)
assert np.may_share_memory(tensorTenmatInstance4_ref.data, tenmatInstance4.data)


def test_tenmat_ctranspose(sample_tenmat_4way):
Expand Down