Skip to content

Commit 6079a1f

Browse files
authored
Fixing arrange and normalize. (#103)
* Fixing arrange and normalize. * Merge main (#104) * Trying to fix coveralls * Trying coveralls github action
1 parent 71672d6 commit 6079a1f

File tree

1 file changed

+56
-30
lines changed

1 file changed

+56
-30
lines changed

pyttb/ktensor.py

Lines changed: 56 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -495,25 +495,27 @@ def from_vector(cls, data, shape, contains_weights):
495495

496496
def arrange(self, weight_factor=None, permutation=None):
497497
"""
498-
Arrange the rank-1 components of a :class:`pyttb.ktensor`. The
499-
columns are permuted in place, so you must make a copy before calling
500-
this method if you want to store the original :class:`pyttb.ktensor`.
501-
One of the parameters, either `weight_factor` or `permutation`
502-
must be passed, and passing both parameters leads to an error.
498+
Arrange the rank-1 components of a :class:`pyttb.ktensor` in place.
499+
If `permutation` is passed, the columns of `self.factor_matrices` are
500+
arranged using the provided permutation, so you must make a copy
501+
before calling this method if you want to store the original
502+
:class:`pyttb.ktensor`. If `weight_factor` is passed, then the values
503+
in `self.weights` are absorbed into
504+
`self.factor_matrices[weight_factor]`. If no parameters are passed,
505+
then the columns of `self.factor_matrices` are normalized and then
506+
permuted such that the resulting `self.weights` are sorted by
507+
magnitude, greatest to least. Passing both parameters leads to an
508+
error.
503509
504510
Parameters
505511
----------
506512
weight_factor: int, optional
507-
The index of the factor that the weights will be absorbed into
508-
permutation: :class:`tuple`, :class:`list`, :class:`numpy.ndarray`, optional
513+
The index of the factor matrix that the weights will be absorbed into.
514+
permutation: :class:`tuple`, :class:`list`, or :class:`numpy.ndarray`, optional
509515
The new order of the components of the :class:`pyttb.ktensor`
510516
into which to permute. The permutation must be of length equal to
511-
the number of components of the :class:`pyttb.ktensor`, N, and
512-
must be a permutation of 1 to N.
513-
514-
Returns
515-
-------
516-
:class:`pyttb.ktensor`
517+
the number of components of the :class:`pyttb.ktensor`, `self.ncomponents`
518+
and must be a permutation of [0,...,`self.ncomponents`-1].
517519
518520
Examples
519521
--------
@@ -546,13 +548,40 @@ def arrange(self, weight_factor=None, permutation=None):
546548
factor_matrices[1] =
547549
[[6. 5.]
548550
[8. 7.]]
549-
"""
550551
552+
Normalize and permute columns such that `weights` are sorted in
553+
decreasing order:
554+
555+
>>> K.arrange()
556+
>>> print(K) # doctest: +ELLIPSIS
557+
ktensor of shape 2 x 2
558+
weights=[89.4427... 27.2029...]
559+
factor_matrices[0] =
560+
[[0.4472... 0.3162...]
561+
[0.8944... 0.9486...]]
562+
factor_matrices[1] =
563+
[[0.6... 0.5812...]
564+
[0.8... 0.8137...]]
565+
566+
Absorb the weights into the second factor:
567+
568+
>>> K.arrange(weight_factor=1)
569+
>>> print(K) # doctest: +ELLIPSIS
570+
ktensor of shape 2 x 2
571+
weights=[1. 1.]
572+
factor_matrices[0] =
573+
[[0.4472... 0.3162...]
574+
[0.8944... 0.9486...]]
575+
factor_matrices[1] =
576+
[[53.6656... 15.8113...]
577+
[71.5541... 22.1359...]]
578+
"""
551579
if permutation is not None and weight_factor is not None:
552580
assert (
553581
False
554582
), "Weighting and permuting the ktensor at the same time is not allowed."
555583

584+
# arrange columns of factor matrices using the permutation provided
556585
if permutation is not None and isinstance(
557586
permutation, (tuple, list, np.ndarray)
558587
):
@@ -566,8 +595,8 @@ def arrange(self, weight_factor=None, permutation=None):
566595
False
567596
), "Number of elements in permutation does not match number of components in ktensor."
568597

569-
# TODO there is a relationship here between normalize and arrange that repeats tasks. Can this be made to be more efficient?
570-
# ensure that factor matrices are normalized
598+
# TODO there is a relationship here between normalize and arrange that repeats tasks.
599+
# Can this be made to be more efficient? ensure that factor matrices are normalized
571600
self.normalize()
572601

573602
# sort
@@ -576,16 +605,13 @@ def arrange(self, weight_factor=None, permutation=None):
576605
for i in range(self.ndims):
577606
self.factor_matrices[i] = self.factor_matrices[i][:, p]
578607

579-
# TODO is this necessary? Matlab only absorbs into the last factor, not factor N as is documented
580-
# absorb weight into one factor if requested
608+
# absorb the weights into one factor, optional
581609
if weight_factor is not None:
582-
pass
583-
# if exist('foo','var')
584-
# r = length(X.lambda);
585-
# X.u{end} = full(X.u{end} * spdiags(X.lambda,0,r,r));
586-
# X.lambda = ones(size(X.lambda));
587-
# end
588-
return self
610+
r = len(self.weights)
611+
self.factor_matrices[weight_factor] *= self.weights
612+
self.weights = np.ones_like(self.weights)
613+
614+
return
589615

590616
def copy(self):
591617
"""
@@ -1260,7 +1286,7 @@ def norm(self):
12601286
def normalize(self, weight_factor=None, sort=False, normtype=2, mode=None):
12611287
"""
12621288
Normalize the columns of the factor matrices of a
1263-
:class:`pyttb.ktensor`.
1289+
:class:`pyttb.ktensor` in place.
12641290
12651291
Parameters
12661292
----------
@@ -1273,7 +1299,7 @@ def normalize(self, weight_factor=None, sort=False, normtype=2, mode=None):
12731299
normtype: {non-negative int, -1, -2, np.inf, -np.inf}, optional
12741300
Order of the norm (see :func:`numpy.linalg.norm` for possible
12751301
values).
1276-
mode: {int, None}, optional
1302+
mode: int, optional
12771303
Index of factor matrix to normalize. A value of `None` means
12781304
normalize all factor matrices.
12791305
@@ -1284,7 +1310,7 @@ def normalize(self, weight_factor=None, sort=False, normtype=2, mode=None):
12841310
Examples
12851311
--------
12861312
>>> K = ttb.ktensor.from_function(np.ones, (2, 3, 4), 2)
1287-
>>> print(K.normalize()) # doctest: +ELLIPSIS
1313+
>>> print(K.normalize()) # doctest: +ELLIPSIS
12881314
ktensor of shape 2 x 3 x 4
12891315
weights=[4.898... 4.898...]
12901316
factor_matrices[0] =
@@ -1310,7 +1336,7 @@ def normalize(self, weight_factor=None, sort=False, normtype=2, mode=None):
13101336
1.0 / tmp * self.factor_matrices[mode][:, r]
13111337
)
13121338
self.weights[r] = self.weights[r] * tmp
1313-
return
1339+
return self
13141340
else:
13151341
assert (
13161342
False
@@ -1349,7 +1375,7 @@ def normalize(self, weight_factor=None, sort=False, normtype=2, mode=None):
13491375
if self.ncomponents > 1:
13501376
# indices of srting in descending order
13511377
p = np.argsort(self.weights)[::-1]
1352-
self = self.arrange(permutation=p)
1378+
self.arrange(permutation=p)
13531379

13541380
return self
13551381

0 commit comments

Comments
 (0)