diff --git a/CLAUDE.md b/CLAUDE.md index 761aa38..b051483 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -97,7 +97,7 @@ decisions and plans agreed with the author, so that they survive a fresh clone. dependent defaults live in LA_precision (la_traits.h, only double and float; double values unchanged). optimize done 2026-11-05: own trait opt_precision in optimize.h, INSTANTIZE(float), float tests in testoptimize.cc (test_float); float LM on badly scaled problems needs my_scaling=true. reg/regsurf, csrmat, strassen, CUDA stay double-only. - Open: Tensor Tucker bugs (complex roundtrip, inverseorder=true abort, also double; bugtests/tensor_tucker_bug.cc). + Tensor Tucker bugs fixed 2026-11-06 (complex: factor = vt.transpose(false); unnamed tensors with inverseorder; bugtests/tensor/tucker.cc). BLAS-based NRVec members are meant for floating types only, not integers. - NRSMat: possible bool member `hermitian` toggling hermitian vs complex symmetric behaviour (Tensor(const NRSMat&) must then respect it). diff --git a/doc/tensor.tex b/doc/tensor.tex index a9c41fa..84a1f7b 100644 --- a/doc/tensor.tex +++ b/doc/tensor.tex @@ -291,7 +291,7 @@ Names are permuted together with the indices unless stated otherwise. \begin{lareference} \lafunc{void apply_permutation_algebra(const Tensor &rhs, const PermutationAlgebra &pa, bool inverse=false, T alpha=1, T beta=0, bool conjugate_by_parity=false)}{$\mathtt{*this} \leftarrow \beta\,\mathtt{*this}$, then for all stored elements $I$ of \code{*this}: $\mathtt{this}(I) \mathrel{+}= \alpha \sum_P c_P\, \mathtt{rhs}(P(I))$, with $P$ acting on the flat index list (inverse permutations if \code{inverse}); with \code{conjugate_by_parity} odd permutations take the complex conjugate. Can represent general (anti)symmetrizers, e.g.\ \code{general_antisymmetrizer} (chapter~\ref{ch:permutation}). \code{*this} may have a symmetry which \code{rhs} lacks. The names of \code{*this} are taken from (or checked against) the names of \code{rhs} permuted by the first permutation. Element-by-element, not optimally efficient.} \lafunc{void apply_permutation_algebra(const NRVec &rhsvec, const PermutationAlgebra &pa, bool inverse=false, T alpha=1, T beta=0)}{the same with \code{rhs} being the outer product of the tensors in \code{rhsvec}, which is not formed explicitly (e.g.\ Grassmann products building a density matrix from cumulants); rather inefficient.} -\lafunc{NRVec > Tucker(typename LA_traits::normtype thr=LA_precision::svd_threshold(), bool inverseorder=false)}{HOSVD/Tucker decomposition: \code{*this} is replaced by the flat core tensor and the factor matrices (one per index, columns orthonormal) are returned; singular values below \code{thr} are dropped, which reduces the corresponding range of the core.} +\lafunc{NRVec > Tucker(typename LA_traits::normtype thr=LA_precision::svd_threshold(), bool inverseorder=false)}{HOSVD/Tucker decomposition: \code{*this} is replaced by the flat core tensor and the factor matrices (one per index, columns orthonormal) are returned; singular values below \code{thr} are dropped, which reduces the corresponding range of the core. The tensor is $X=G\times_1U_1\cdots\times_rU_r$ with the core $G$ and the factor matrices $U_k$, contracted without complex conjugation ($G=X\times_1U_1^\dagger\cdots\times_rU_r^\dagger$).} \lafunc{Tensor inverseTucker(const NRVec > &x, bool inverseorder=false) const}{rebuild the tensor from the core (\code{*this}) and the matrices returned by \code{Tucker} with the same \code{inverseorder}.} \lafunc{Tensor linear_transform(const NRVec > &x) const}{transform every index of group $g$ by the matrix \code{x[g]} (\code{x[g].ncols()} must equal the range; the new range is \code{x[g].nrows()}), preserving the group symmetries: $t'_{\dots a \dots} = \sum_i x_{ai}\, t_{\dots i\dots}$.} \lafunc{Tensor linear_transform(const int g, const Tensor &x) const; Tensor linear_transform(const int g, const NRMat &x) const}{transform only group \code{g}, keeping its position and symmetry; \code{x} must be a flat rank-2 tensor (useful for raising/lowering indices) or a matrix.} diff --git a/tensor.cc b/tensor.cc index 6b7428a..51d10e7 100644 --- a/tensor.cc +++ b/tensor.cc @@ -1829,7 +1829,7 @@ for(int i=0; i p(rank()); p.identity(); - names=names_saved.permuted(p.reverse()); + if(names_saved.size()) names=names_saved.permuted(p.reverse()); } else names=names_saved; @@ -1889,7 +1889,7 @@ for(int i=rank()-1; i>=0; --i) if(inverseorder) { NRPerm p(rank()); p.identity(); - r.names=names.permuted(p.reverse()); + if(is_named()) r.names=names.permuted(p.reverse()); } else r.names=names;