Skip to content

Commit e18a569

Browse files
[itops] split convmat in allocation and a convmat_inplace builder fun… (#13)
* [itops] split convmat in allocation and a convmat_inplace builder function. * [itops] convmat_inplace add doc note on rec inplace function usage * [itops] doc typo fixes --------- Co-authored-by: Jason Kaye <[email protected]>
1 parent e57828e commit e18a569

File tree

1 file changed

+78
-9
lines changed

1 file changed

+78
-9
lines changed

c++/cppdlr/dlr_imtime.hpp

Lines changed: 78 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,76 @@ namespace cppdlr {
451451
template <nda::MemoryArray T, nda::Scalar S = nda::get_value_t<T>>
452452
nda::matrix<S> convmat(double beta, statistic_t statistic, T const &fc, bool time_order = false) const {
453453

454+
int n, m;
455+
456+
if constexpr (T::rank == 1) { // Scalar-valued Green's function
457+
n = r;
458+
m = r;
459+
} else if (T::rank == 3) { // Matrix-valued Green's function
460+
n = r * fc.shape(1);
461+
m = r * fc.shape(2);
462+
} else {
463+
throw std::runtime_error("Input arrays must be rank 1 (scalar-valued Green's function) or 3 (matrix-valued Green's function).");
464+
}
465+
466+
auto fconv = nda::matrix<S, nda::C_layout>(n, m); // Matrix of convolution by f
467+
convmat_inplace(nda::matrix_view<S, nda::C_layout>(fconv), beta, statistic, fc, time_order);
468+
469+
return fconv;
470+
}
471+
472+
/**
473+
* @brief Compute matrix of convolution by an imaginary time Green's function
474+
* in place
475+
*
476+
* The convolution of f and g is defined as h(t) = (f * g)(t) = int_0^beta
477+
* f(t-t') g(t') dt', where fermionic/bosonic antiperiodicity/periodicity are
478+
* used to define the Green's functions on (-beta, 0). This method takes the
479+
* DLR coefficients of f as input and returns the matrix of convolution by f.
480+
* This matrix can be applied to the values of g on the DLR imaginary time
481+
* grid, to produce the values of h on the DLR imaginary time grid.
482+
*
483+
* By specifying the @p time_order flag, this method can be used to compute
484+
* the time-ordered convolution of f and g, defined as h(t) = (f * g)(t) =
485+
* int_0^tau f(t-t') g(t') dt'.
486+
*
487+
* The convolution matrix is constructed using the method described in
488+
* Appendix A of
489+
*
490+
* J. Kaye, H. U. R. Strand, D. Golez, "Decomposing imaginary time Feynman
491+
* diagrams using separable basis functions: Anderson impurity model strong
492+
* coupling expansion," arXiv:2307.08566 (2023).
493+
*
494+
* @param[in/out] fconv Convolution matrix from DLR coefficients to DLR grid
495+
* @param[in] beta Inverse temperature
496+
* @param[in] statistic Fermionic ("Fermion" or 0) or bosonic ("Boson" or 1)
497+
* @param[in] fc DLR coefficients of f
498+
* @param[in] time_order Flag for ordinary (false or ORDINARY, default) or
499+
* time-ordered (true or TIME_ORDERED) convolution
500+
*
501+
* \note This function builds the matrix of convolution, in place, in the
502+
* provided matrix `fconv`. This makes it possible to control the memory
503+
* allocation externally. If this is not a concern, we advise using the
504+
* `convmat(...)` function instead of `convmat_inplace(...)`.
505+
*
506+
* \note Whereas the method imtime_ops::convolve takes the DLR coefficients
507+
* of f and g as input and computes their convolution h directly, this method
508+
* returns a matrix which should be applied to the DLR imaginary time grid values
509+
* of g, rather than its DLR coefficients, in to order to obtain the
510+
* convolution h. The purpose of this is to make the input and output
511+
* representations of the convolution matrix equal, which is often convenient
512+
* in practice.
513+
*
514+
* \note In the case of matrix-valued Green's functions, we think of the
515+
* matrix of convolution by f as an r*norb x r*norb matrix, or a block r x r
516+
* matrix of norb x norb blocks. Here r is the DLR rank and norb is the
517+
* number of orbital indices. This matrix would then be applied to a Green's
518+
* function g, represented as an r*norb x norb matrix, or a block r x 1
519+
* matrix of norb x norb blocks.
520+
* */
521+
template <nda::MemoryArray T, nda::Scalar S = nda::get_value_t<T>>
522+
void convmat_inplace(nda::matrix_view<S, nda::C_layout> fconv, double beta, statistic_t statistic, T const &fc, bool time_order = false) const {
523+
454524
if (r != fc.shape(0)) throw std::runtime_error("First dim of input array must be equal to DLR rank r.");
455525

456526
// TODO: implement bosonic case and remove
@@ -466,10 +536,9 @@ namespace cppdlr {
466536

467537
if constexpr (T::rank == 1) { // Scalar-valued Green's function
468538

469-
// First construct convolution matrix from DLR coefficients to DLR grid
470-
// values
471-
auto fconv = nda::matrix<S>(r, r); // Matrix of convolution by f
472-
539+
if (fconv.shape(0) != r || fconv.shape(1) != r)
540+
throw std::runtime_error("Matrix shape must be equal to DLR rank (r,r).");
541+
473542
// Diagonal contribution (given by diag(tau_k) * K(tau_k, om_l) * diag(fc_l))
474543
for (int k = 0; k < r; ++k) {
475544
for (int l = 0; l < r; ++l) { fconv(k, l) = tcf2it_v(k, l) * fc(l); }
@@ -495,16 +564,16 @@ namespace cppdlr {
495564
nda::lapack::getrs(transpose(it2cf.lu), fconv, it2cf.piv);
496565
}
497566

498-
return beta * fconv;
567+
fconv *= beta;
499568

500569
} else if (T::rank == 3) { // Matrix-valued Green's function
501570

502571
int norb1 = fc.shape(1);
503572
int norb2 = fc.shape(2);
504573

505-
// First construct convolution matrix from DLR coefficients to DLR grid
506-
// values
507-
auto fconv = nda::matrix<S>(r * norb1, r * norb2); // Matrix of convolution by f
574+
if (fconv.shape(0) != r*norb1 || fconv.shape(1) != r*norb2)
575+
throw std::runtime_error("Matrix shape must be equal to DLR rank times norbs (r*norb1,r*norb2).");
576+
508577
auto fconv_rs = nda::reshape(fconv, r, norb1, r, norb2); // Array view to index into fconv for conevenience
509578

510579
// Diagonal contribution (given by diag(tau_k) * K(tau_k, om_l) * diag(fc_l))
@@ -547,7 +616,7 @@ namespace cppdlr {
547616
for (int k = 0; k < r; ++k) { fconv_rs(_, _, k, i) = fconvtmp_rs(_, _, i, k); }
548617
}
549618

550-
return beta * fconv;
619+
fconv *= beta;
551620

552621
} else {
553622
throw std::runtime_error("Input arrays must be rank 1 (scalar-valued Green's function) or 3 (matrix-valued Green's function).");

0 commit comments

Comments
 (0)