tensor: recurse conj() into nested tiles (tensor-of-tensors)#560
Merged
evaleev merged 2 commits intoJun 6, 2026
Merged
Conversation
Tensor::conj() is scale(conj_op()), which multiplies each element by a ComplexConjugate operator and thus calls detail::conj() on each element. For a tensor-of-tensors the element is itself a TA::Tensor, and detail::conj() only had scalar (real/std::complex) overloads, so conj() of a Tensor<Tensor<...>> (and DistArray<Tensor<Tensor<...>>>::operator()(...).conj()) failed to compile. Add a detail::conj() overload for non-numeric types that forwards to the element's own conj(), recursing until the scalar overloads terminate it. SFINAE'd on a non-numeric type with a conj() member so it never competes with the scalar overloads. Add a Tensor<Tensor<complex>> conj test.
…renaTensor::conj_to)
The complex-ToT conj recursion (prior commit) handled the value-returning path,
but the out-of-place permuted path threw for arena/view inner: Tensor::scale(
factor, perm) had only a view-TA_EXCEPTION branch and a value-based unary branch.
The DistArray .conj() expression lowers to scale(factor, perm) (and scale_to),
so adjoint of a complex ArenaTensor-backed tensor-of-tensors hit that throw.
- scale(factor, perm): add an arena branch mirroring add(right, perm) — scale via
the arena kernel (manages the slab), then permute the result if non-trivial
(arena_perm_is_trivial). Precedes the view branch since ArenaTensor is a view.
- ArenaTensor::conj_to(): in-place conjugation via the free scale_to kernel with a
ComplexConjugate factor (no-op for real T); mirrors neg_to(). Include complex.h.
- tests/tot_construction: conj_tot_{tensor,arena}_inner exercise conj(),
conj(perm), and conj_to() on complex tensor-of-tensors for both inner kinds.
scale_to needed no arena branch: res *= conj_op routes through the free
operator*= -> scale_to kernel, conjugating arena scalars in place.
e8ed544 to
196f29a
Compare
There was a problem hiding this comment.
Pull request overview
This PR fixes Tensor::conj() for tensor-of-tensors (e.g., Tensor<Tensor<std::complex<...>>>) by making the internal conjugation helper recurse into nested tensor elements, and extends test coverage to prevent regressions (including arena-backed inner tiles).
Changes:
- Added a
TiledArray::detail::conj(const T&)overload for non-numeric types that forwards tot.conj(), enabling recursive conjugation for nested tensor element types. - Updated
Tensor::scale(..., perm)/Tensor::scale_to(...)handling forTensor<ArenaTensor<...>>so conjugation/scaling paths work with arena-backed inner cells and permutations. - Added regression tests covering
Tensor<Tensor<complex>>.conj()and ToT conjugation (including permuted and in-place variants, and arena inner tiles).
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
src/TiledArray/tensor/complex.h |
Adds recursive detail::conj() overload to support conjugating nested tensor element types. |
src/TiledArray/tensor/tensor.h |
Routes arena inner-cell scaling/conjugation through arena-aware paths and supports permuted scale for arena inners. |
src/TiledArray/tensor/arena_tensor.h |
Adds ArenaTensor::conj_to() implemented via the arena scale_to kernel with conj_op(). |
tests/tensor.cpp |
Adds a regression test ensuring Tensor<Tensor<complex>>::conj() compiles and conjugates inner scalars. |
tests/tot_construction.cpp |
Adds ToT conjugation tests covering out-of-place, permuted, and in-place conjugation for tensor and arena inner tiles. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
evaleev
added a commit
to ValeevGroup/SeQuant
that referenced
this pull request
Jun 6, 2026
…iledArray pin TiledArray now recurses conj() into nested tiles and handles it for arena/view inner cells (ValeevGroup/tiledarray#560), so the tensor-of-tensors adjoint() no longer needs the complex-only local-tile-walk workaround — it uses the uniform result(post_annot) = arr(pre_annot).conj(), identical to the regular-tensor branch. - external/versions.cmake: bump SEQUANT_TRACKED_TILEDARRAY_TAG to the merged TA commit (b8c1d7553) carrying the recursive + arena-aware conj. - eval/backends/tiledarray: collapse ResultTensorOfTensorTA::adjoint() to the uniform .conj() (drops the local-tile walk and the now-unused <complex>). - tests/test_eval_ta: ta_tot_conj_complex runtime-checks TA's ToT .conj() over a complex tensor-of-tensors; force-instantiate ResultTensorOfTensorTA<complex> to compile-check the collapsed adjoint().
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Tensor::conj()isscale(conj_op()), which multiplies each element by aComplexConjugateoperator and thus callsdetail::conj()on each element. For a tensor-of-tensors the element is itself aTA::Tensor, anddetail::conj()only had scalar (real /std::complex) overloads — soconj()of aTensor<Tensor<...>>(andDistArray<Tensor<Tensor<...>>>::operator()(...).conj()) failed to compile.Change
detail::conj()overload for non-numeric types that forwards to the element's ownconj(), recursing until the scalar overloads terminate it. SFINAE'd on a non-numeric type that provides aconj()member, so it never competes with the scalar overloads.Tensor<Tensor<complex>>conj unit test (tests/tensor.cpp).Motivation
Downstream (SeQuant), evaluating the adjoint of a Nonsymm tensor backed by a complex tensor-of-tensors array needs
arr(annot).conj()to work uniformly for regular and nested arrays. This removes a SeQuant-side local-tile-walk workaround in favor of the proper TA capability.Notes
Based on
zhihao/feature/strided-dgemm(the branch the consuming build currently tracks), notmaster. Can rebase ontomasterif preferred.