Skip to content

Commit f06e9fc

Browse files
committed
btas inner-tile path: empty-arg handling + rank-1 TI ordinal lookup
Two fixes needed by MPQC's CSV CCk validation tests (which exercise TA::Tensor<btas::Tensor<T>> inner tiles end-to-end): 1. external/btas.h: mirror TA::Tensor's empty-/null-argument early-exits in the btas free-function suite (add/add_to/subt/subt_to/mult/mult_to, their factored and permuted variants, scale/scale_to/neg/neg_to). TA's ToT lambdas default-construct result inner tiles and accumulate into them, so consumers regularly hit the empty-result-then-add_to(arg) pattern; without these guards, TA's congruent-range assertion fires inside the underlying TensorInterface machinery. 2. tensor/tensor_interface.h: replace range_.includes(index_ordinal) with range_.includes_ordinal(index_ordinal) in TensorInterface's operator[] / at_ordinal. The integral includes(Ordinal) overload on TA::Range asserts rank!=1 to disambiguate from the includes(Index) coordinate-tuple form; TI's ordinal-lookup path was inadvertently tripping that for rank-1 inner tiles (e.g. PNO-basis 1-D energies).
1 parent 53dee00 commit f06e9fc

2 files changed

Lines changed: 113 additions & 8 deletions

File tree

src/TiledArray/external/btas.h

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,11 +308,21 @@ inline btas::Tensor<T, Range, Storage>&& shift_to(
308308
return std::move(arg);
309309
}
310310

311+
// NOTE on empty-handling: these btas free functions mirror the empty-/null-
312+
// argument behavior of TA::Tensor's same-named member ops, so generic ToT
313+
// code (e.g. TA::Tensor<btas::Tensor<T>>'s lambdas in
314+
// TA::Tensor::{add,subt,mult,add_to,subt_to,mult_to,neg,scale}) can produce
315+
// or accumulate into default-constructed (empty) btas inner tiles without
316+
// hitting TA's congruent-range assertion in the underlying TensorInterface
317+
// machinery.
318+
311319
/// result[i] = arg1[i] + arg2[i]
312320
template <typename T, typename Range, typename Storage>
313321
inline btas::Tensor<T, Range, Storage> add(
314322
const btas::Tensor<T, Range, Storage>& arg1,
315323
const btas::Tensor<T, Range, Storage>& arg2) {
324+
if (arg1.empty()) return arg2;
325+
if (arg2.empty()) return arg1;
316326
auto arg1_view = make_ti(arg1);
317327
auto arg2_view = make_ti(arg2);
318328
return arg1_view.add(arg2_view);
@@ -325,6 +335,9 @@ template <typename T, typename Range, typename Storage, typename Scalar,
325335
inline btas::Tensor<T, Range, Storage> add(
326336
const btas::Tensor<T, Range, Storage>& arg1,
327337
const btas::Tensor<T, Range, Storage>& arg2, const Scalar factor) {
338+
if (arg1.empty() && arg2.empty()) return {};
339+
if (arg1.empty()) return scale(arg2, factor);
340+
if (arg2.empty()) return scale(arg1, factor);
328341
auto arg1_view = make_ti(arg1);
329342
auto arg2_view = make_ti(arg2);
330343
return arg1_view.add(arg2_view, factor);
@@ -337,6 +350,9 @@ template <
337350
inline btas::Tensor<T, Range, Storage> add(
338351
const btas::Tensor<T, Range, Storage>& arg1,
339352
const btas::Tensor<T, Range, Storage>& arg2, const Perm& perm) {
353+
if (arg1.empty() && arg2.empty()) return {};
354+
if (arg1.empty()) return permute(arg2, perm);
355+
if (arg2.empty()) return permute(arg1, perm);
340356
auto arg1_view = make_ti(arg1);
341357
auto arg2_view = make_ti(arg2);
342358
return arg1_view.add(arg2_view, perm);
@@ -352,6 +368,9 @@ inline btas::Tensor<T, Range, Storage> add(
352368
const btas::Tensor<T, Range, Storage>& arg1,
353369
const btas::Tensor<T, Range, Storage>& arg2, const Scalar factor,
354370
const Perm& perm) {
371+
if (arg1.empty() && arg2.empty()) return {};
372+
if (arg1.empty()) return scale(permute(arg2, perm), factor);
373+
if (arg2.empty()) return scale(permute(arg1, perm), factor);
355374
auto arg1_view = make_ti(arg1);
356375
auto arg2_view = make_ti(arg2);
357376
return arg1_view.add(arg2_view, factor, perm);
@@ -362,6 +381,15 @@ template <typename T, typename Range, typename Storage>
362381
inline btas::Tensor<T, Range, Storage>& add_to(
363382
btas::Tensor<T, Range, Storage>& result,
364383
const btas::Tensor<T, Range, Storage>& arg) {
384+
// Mirror TA::Tensor::add_to's empty-handling so consumers (e.g. einsum's
385+
// inner-contraction loop, which default-constructs result inner tiles)
386+
// can accumulate into an empty result. Without these the make_ti's view
387+
// ranges differ and TA's congruent-range assertion fires.
388+
if (arg.empty()) return result;
389+
if (result.empty()) {
390+
result = arg;
391+
return result;
392+
}
365393
auto result_view = make_ti(result);
366394
auto arg_view = make_ti(arg);
367395
result_view.add_to(arg_view);
@@ -375,6 +403,15 @@ template <typename T, typename Range, typename Storage, typename Scalar,
375403
inline btas::Tensor<T, Range, Storage>& add_to(
376404
btas::Tensor<T, Range, Storage>& result,
377405
const btas::Tensor<T, Range, Storage>& arg, const Scalar factor) {
406+
if (arg.empty()) return result;
407+
if (result.empty()) {
408+
result = arg;
409+
{
410+
auto result_view = make_ti(result);
411+
result_view.scale_to(factor);
412+
}
413+
return result;
414+
}
378415
auto result_view = make_ti(result);
379416
auto arg_view = make_ti(arg);
380417
result_view.add_to(arg_view, factor);
@@ -386,6 +423,8 @@ template <typename T, typename Range, typename Storage>
386423
inline btas::Tensor<T, Range, Storage> subt(
387424
const btas::Tensor<T, Range, Storage>& arg1,
388425
const btas::Tensor<T, Range, Storage>& arg2) {
426+
if (arg2.empty()) return arg1;
427+
if (arg1.empty()) return neg(arg2);
389428
auto arg1_view = make_ti(arg1);
390429
auto arg2_view = make_ti(arg2);
391430
return arg1_view.subt(arg2_view);
@@ -398,6 +437,9 @@ template <typename T, typename Range, typename Storage, typename Scalar,
398437
inline btas::Tensor<T, Range, Storage> subt(
399438
const btas::Tensor<T, Range, Storage>& arg1,
400439
const btas::Tensor<T, Range, Storage>& arg2, const Scalar factor) {
440+
if (arg1.empty() && arg2.empty()) return {};
441+
if (arg2.empty()) return scale(arg1, factor);
442+
if (arg1.empty()) return scale(arg2, -factor);
401443
auto arg1_view = make_ti(arg1);
402444
auto arg2_view = make_ti(arg2);
403445
return arg1_view.subt(arg2_view, factor);
@@ -410,6 +452,9 @@ template <
410452
inline btas::Tensor<T, Range, Storage> subt(
411453
const btas::Tensor<T, Range, Storage>& arg1,
412454
const btas::Tensor<T, Range, Storage>& arg2, const Perm& perm) {
455+
if (arg1.empty() && arg2.empty()) return {};
456+
if (arg2.empty()) return permute(arg1, perm);
457+
if (arg1.empty()) return neg(permute(arg2, perm));
413458
auto arg1_view = make_ti(arg1);
414459
auto arg2_view = make_ti(arg2);
415460
return arg1_view.subt(arg2_view, perm);
@@ -425,6 +470,9 @@ inline btas::Tensor<T, Range, Storage> subt(
425470
const btas::Tensor<T, Range, Storage>& arg1,
426471
const btas::Tensor<T, Range, Storage>& arg2, const Scalar factor,
427472
const Perm& perm) {
473+
if (arg1.empty() && arg2.empty()) return {};
474+
if (arg2.empty()) return scale(permute(arg1, perm), factor);
475+
if (arg1.empty()) return scale(permute(arg2, perm), -factor);
428476
auto arg1_view = make_ti(arg1);
429477
auto arg2_view = make_ti(arg2);
430478
return arg1_view.subt(arg2_view, factor, perm);
@@ -435,6 +483,11 @@ template <typename T, typename Range, typename Storage>
435483
inline btas::Tensor<T, Range, Storage>& subt_to(
436484
btas::Tensor<T, Range, Storage>& result,
437485
const btas::Tensor<T, Range, Storage>& arg) {
486+
if (arg.empty()) return result;
487+
if (result.empty()) {
488+
result = neg(arg);
489+
return result;
490+
}
438491
auto result_view = make_ti(result);
439492
auto arg_view = make_ti(arg);
440493
result_view.subt_to(arg_view);
@@ -445,6 +498,11 @@ template <typename T, typename Range, typename Storage>
445498
inline btas::Tensor<T, Range, Storage>&& subt_to(
446499
btas::Tensor<T, Range, Storage>&& result,
447500
const btas::Tensor<T, Range, Storage>& arg) {
501+
if (arg.empty()) return std::move(result);
502+
if (result.empty()) {
503+
result = neg(arg);
504+
return std::move(result);
505+
}
448506
auto result_view = make_ti(result);
449507
auto arg_view = make_ti(arg);
450508
result_view.subt_to(arg_view);
@@ -457,6 +515,15 @@ template <typename T, typename Range, typename Storage, typename Scalar,
457515
inline btas::Tensor<T, Range, Storage>& subt_to(
458516
btas::Tensor<T, Range, Storage>& result,
459517
const btas::Tensor<T, Range, Storage>& arg, const Scalar factor) {
518+
// TA::Tensor::subt_to(right, factor): right empty -> scale_to(factor).
519+
if (arg.empty()) {
520+
if (!result.empty()) scale_to(result, factor);
521+
return result;
522+
}
523+
if (result.empty()) {
524+
result = scale(arg, -factor);
525+
return result;
526+
}
460527
auto result_view = make_ti(result);
461528
auto arg_view = make_ti(arg);
462529
result_view.subt_to(arg_view, factor);
@@ -469,6 +536,14 @@ template <typename T, typename Range, typename Storage, typename Scalar,
469536
inline btas::Tensor<T, Range, Storage>&& subt_to(
470537
btas::Tensor<T, Range, Storage>&& result,
471538
const btas::Tensor<T, Range, Storage>& arg, const Scalar factor) {
539+
if (arg.empty()) {
540+
if (!result.empty()) scale_to(result, factor);
541+
return std::move(result);
542+
}
543+
if (result.empty()) {
544+
result = scale(arg, -factor);
545+
return std::move(result);
546+
}
472547
auto result_view = make_ti(result);
473548
auto arg_view = make_ti(arg);
474549
result_view.subt_to(arg_view, factor);
@@ -480,6 +555,7 @@ template <typename T, typename Range, typename Storage>
480555
inline btas::Tensor<T, Range, Storage> mult(
481556
const btas::Tensor<T, Range, Storage>& arg1,
482557
const btas::Tensor<T, Range, Storage>& arg2) {
558+
if (arg1.empty() || arg2.empty()) return {};
483559
auto arg1_view = make_ti(arg1);
484560
auto arg2_view = make_ti(arg2);
485561
return arg1_view.mult(arg2_view);
@@ -492,6 +568,7 @@ template <typename T, typename Range, typename Storage, typename Scalar,
492568
inline btas::Tensor<T, Range, Storage> mult(
493569
const btas::Tensor<T, Range, Storage>& arg1,
494570
const btas::Tensor<T, Range, Storage>& arg2, const Scalar factor) {
571+
if (arg1.empty() || arg2.empty()) return {};
495572
auto arg1_view = make_ti(arg1);
496573
auto arg2_view = make_ti(arg2);
497574
return arg1_view.mult(arg2_view, factor);
@@ -504,6 +581,7 @@ template <
504581
inline btas::Tensor<T, Range, Storage> mult(
505582
const btas::Tensor<T, Range, Storage>& arg1,
506583
const btas::Tensor<T, Range, Storage>& arg2, const Perm& perm) {
584+
if (arg1.empty() || arg2.empty()) return {};
507585
auto arg1_view = make_ti(arg1);
508586
auto arg2_view = make_ti(arg2);
509587
return arg1_view.mult(arg2_view, perm);
@@ -519,16 +597,23 @@ inline btas::Tensor<T, Range, Storage> mult(
519597
const btas::Tensor<T, Range, Storage>& arg1,
520598
const btas::Tensor<T, Range, Storage>& arg2, const Scalar factor,
521599
const Perm& perm) {
600+
if (arg1.empty() || arg2.empty()) return {};
522601
auto arg1_view = make_ti(arg1);
523602
auto arg2_view = make_ti(arg2);
524603
return arg1_view.mult(arg2_view, factor, perm);
525604
}
526605

527606
/// result[i] *= arg[i]
607+
/// (TA::Tensor::mult_to: right empty -> result = {}; left empty -> result.)
528608
template <typename T, typename Range, typename Storage>
529609
inline btas::Tensor<T, Range, Storage>& mult_to(
530610
btas::Tensor<T, Range, Storage>& result,
531611
const btas::Tensor<T, Range, Storage>& arg) {
612+
if (arg.empty()) {
613+
result = btas::Tensor<T, Range, Storage>{};
614+
return result;
615+
}
616+
if (result.empty()) return result;
532617
auto result_view = make_ti(result);
533618
auto arg_view = make_ti(arg);
534619
result_view.mult_to(arg_view);
@@ -539,6 +624,11 @@ template <typename T, typename Range, typename Storage>
539624
inline btas::Tensor<T, Range, Storage>&& mult_to(
540625
btas::Tensor<T, Range, Storage>&& result,
541626
const btas::Tensor<T, Range, Storage>& arg) {
627+
if (arg.empty()) {
628+
result = btas::Tensor<T, Range, Storage>{};
629+
return std::move(result);
630+
}
631+
if (result.empty()) return std::move(result);
542632
auto result_view = make_ti(result);
543633
auto arg_view = make_ti(arg);
544634
result_view.mult_to(arg_view);
@@ -552,6 +642,11 @@ template <typename T, typename Range, typename Storage, typename Scalar,
552642
inline btas::Tensor<T, Range, Storage>& mult_to(
553643
btas::Tensor<T, Range, Storage>& result,
554644
const btas::Tensor<T, Range, Storage>& arg, const Scalar factor) {
645+
if (result.empty()) return result;
646+
if (arg.empty()) {
647+
result = btas::Tensor<T, Range, Storage>{};
648+
return result;
649+
}
555650
auto result_view = make_ti(result);
556651
auto arg_view = make_ti(arg);
557652
result_view.mult_to(arg_view, factor);
@@ -564,6 +659,11 @@ template <typename T, typename Range, typename Storage, typename Scalar,
564659
inline btas::Tensor<T, Range, Storage>&& mult_to(
565660
btas::Tensor<T, Range, Storage>&& result,
566661
const btas::Tensor<T, Range, Storage>& arg, const Scalar factor) {
662+
if (result.empty()) return std::move(result);
663+
if (arg.empty()) {
664+
result = btas::Tensor<T, Range, Storage>{};
665+
return std::move(result);
666+
}
567667
auto result_view = make_ti(result);
568668
auto arg_view = make_ti(arg);
569669
result_view.mult_to(arg_view, factor);
@@ -605,6 +705,7 @@ template <typename T, typename Range, typename Storage, typename Scalar,
605705
std::enable_if_t<TiledArray::detail::is_numeric_v<Scalar>>* = nullptr>
606706
inline btas::Tensor<T, Range, Storage>& scale_to(
607707
btas::Tensor<T, Range, Storage>& result, const Scalar factor) {
708+
if (result.empty()) return result;
608709
auto result_view = make_ti(result);
609710
result_view.scale_to(factor);
610711
return result;
@@ -614,6 +715,7 @@ template <typename T, typename Range, typename Storage, typename Scalar,
614715
std::enable_if_t<TiledArray::detail::is_numeric_v<Scalar>>* = nullptr>
615716
inline decltype(auto) scale(const btas::Tensor<T, Range, Storage>& result,
616717
const Scalar factor) {
718+
if (result.empty()) return btas::Tensor<T, Range, Storage>{};
617719
auto result_view = make_ti(result);
618720
return result_view.scale(factor);
619721
}
@@ -625,13 +727,15 @@ template <
625727
TiledArray::detail::is_permutation_v<Perm>>* = nullptr>
626728
inline decltype(auto) scale(const btas::Tensor<T, Range, Storage>& result,
627729
const Scalar factor, const Perm& perm) {
730+
if (result.empty()) return btas::Tensor<T, Range, Storage>{};
628731
auto result_view = make_ti(result);
629732
return result_view.scale(factor, perm);
630733
}
631734

632735
template <typename T, typename Range, typename Storage>
633736
inline btas::Tensor<T, Range, Storage>& neg_to(
634737
btas::Tensor<T, Range, Storage>& result) {
738+
if (result.empty()) return result;
635739
auto result_view = make_ti(result);
636740
result_view.neg_to();
637741
return result;
@@ -640,6 +744,7 @@ inline btas::Tensor<T, Range, Storage>& neg_to(
640744
template <typename T, typename Range, typename Storage>
641745
inline btas::Tensor<T, Range, Storage>&& neg_to(
642746
btas::Tensor<T, Range, Storage>&& result) {
747+
if (result.empty()) return std::move(result);
643748
auto result_view = make_ti(result);
644749
result_view.neg_to();
645750
return std::move(result);
@@ -648,6 +753,7 @@ inline btas::Tensor<T, Range, Storage>&& neg_to(
648753
template <typename T, typename Range, typename Storage>
649754
inline btas::Tensor<T, Range, Storage> neg(
650755
const btas::Tensor<T, Range, Storage>& arg) {
756+
if (arg.empty()) return {};
651757
auto arg_view = make_ti(arg);
652758
return arg_view.neg();
653759
}
@@ -657,6 +763,7 @@ template <
657763
typename = std::enable_if_t<TiledArray::detail::is_permutation_v<Perm>>>
658764
inline btas::Tensor<T, Range, Storage> neg(
659765
const btas::Tensor<T, Range, Storage>& arg, const Perm& perm) {
766+
if (arg.empty()) return {};
660767
auto arg_view = make_ti(arg);
661768
return arg_view.neg(perm);
662769
}

src/TiledArray/tensor/tensor_interface.h

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -178,16 +178,14 @@ class TensorInterface {
178178
/// \param range The range of this tensor
179179
/// \param data The data pointer for this tensor
180180
TensorInterface(const range_type& range, pointer data)
181-
: range_(range), data_(data) {
182-
}
181+
: range_(range), data_(data) {}
183182

184183
/// Construct a new view of \c tensor
185184

186185
/// \param range The range of this tensor
187186
/// \param data The data pointer for this tensor
188187
TensorInterface(range_type&& range, pointer data)
189-
: range_(std::move(range)), data_(data) {
190-
}
188+
: range_(std::move(range)), data_(data) {}
191189

192190
template <typename T1, typename std::enable_if<detail::is_nested_tensor<
193191
T1>::value>::type* = nullptr>
@@ -223,7 +221,7 @@ class TensorInterface {
223221
/// \param index_ordinal The ordinal element index
224222
/// \return A const reference to the element at \c index_ordinal.
225223
const_reference operator[](const ordinal_type index_ordinal) const {
226-
TA_ASSERT(range_.includes(index_ordinal));
224+
TA_ASSERT(range_.includes_ordinal(index_ordinal));
227225
return data_[range_.ordinal(index_ordinal)];
228226
}
229227

@@ -232,7 +230,7 @@ class TensorInterface {
232230
/// \param index The ordinal element index
233231
/// \return A const reference to the element at \c index_ordinal.
234232
reference operator[](const ordinal_type index_ordinal) {
235-
TA_ASSERT(range_.includes(index_ordinal));
233+
TA_ASSERT(range_.includes_ordinal(index_ordinal));
236234
return data_[range_.ordinal(index_ordinal)];
237235
}
238236

@@ -241,7 +239,7 @@ class TensorInterface {
241239
/// \param index_ordinal The ordinal element index
242240
/// \return A const reference to the element at \c index_ordinal.
243241
const_reference at_ordinal(const ordinal_type index_ordinal) const {
244-
TA_ASSERT(range_.includes(index_ordinal));
242+
TA_ASSERT(range_.includes_ordinal(index_ordinal));
245243
return data_[range_.ordinal(index_ordinal)];
246244
}
247245

@@ -250,7 +248,7 @@ class TensorInterface {
250248
/// \param index_ordinal The ordinal element index
251249
/// \return A const reference to the element at \c index_ordinal.
252250
reference at_ordinal(const ordinal_type index_ordinal) {
253-
TA_ASSERT(range_.includes(index_ordinal));
251+
TA_ASSERT(range_.includes_ordinal(index_ordinal));
254252
return data_[range_.ordinal(index_ordinal)];
255253
}
256254

0 commit comments

Comments
 (0)