24 #include "TensorOperator.h" 32 this->
index = boundary_index;
43 assert( n_irrep >= 0 );
44 assert( n_irrep < bk_up->getNumberOfIrreps() );
53 const int n_down = n_up +
n_elec;
54 for (
int two_s_down = two_s_up - two_j; two_s_down <= two_s_up +
two_j; two_s_down += 2 ){
55 if ( two_s_down >= 0 ){
56 const int dim_down = bk_down->
gCurrentDim(
index, n_down, two_s_down, irrep_down );
81 const int n_down = n_up +
n_elec;
82 for (
int two_s_down = two_s_up - two_j; two_s_down <= two_s_up +
two_j; two_s_down += 2 ){
83 if ( two_s_down >= 0 ){
84 const int dim_down = bk_down->
gCurrentDim(
index, n_down, two_s_down, irrep_down );
122 if ( N2 != N1 +
n_elec ){
return -1; }
123 if ( abs( TwoS1 - TwoS2 ) >
two_j ){
return -1; }
126 for (
int cnt = 0; cnt <
nKappa; cnt++ ){
130 for (
int cnt = 0; cnt <
nKappa; cnt++ ){
143 int kappa =
gKappa( N1, TwoS1, I1, N2, TwoS2, I2 );
144 if ( kappa == -1 ){
return NULL; }
168 for (
int ikappa = 0; ikappa <
nKappa; ikappa++ ){
172 for (
int ikappa = 0; ikappa <
nKappa; ikappa++ ){
182 const int n_right_down = n_right_up +
n_elec;
191 for (
int geval = 0; geval < 6; geval++ ){
192 int n_left_up, n_left_down, two_s_left_up, two_s_left_down, irrep_left_up, irrep_left_down;
195 two_s_left_up = two_s_right_up;
196 two_s_left_down = two_s_right_down;
197 n_left_up = n_right_up;
198 n_left_down = n_right_down;
199 irrep_left_up = irrep_right_up;
200 irrep_left_down = irrep_right_down;
203 two_s_left_up = two_s_right_up;
204 two_s_left_down = two_s_right_down;
205 n_left_up = n_right_up - 2;
206 n_left_down = n_right_down - 2;
207 irrep_left_up = irrep_right_up;
208 irrep_left_down = irrep_right_down;
211 two_s_left_up = two_s_right_up - 1;
212 two_s_left_down = two_s_right_down - 1;
213 n_left_up = n_right_up - 1;
214 n_left_down = n_right_down - 1;
219 two_s_left_up = two_s_right_up - 1;
220 two_s_left_down = two_s_right_down + 1;
221 n_left_up = n_right_up - 1;
222 n_left_down = n_right_down - 1;
227 two_s_left_up = two_s_right_up + 1;
228 two_s_left_down = two_s_right_down - 1;
229 n_left_up = n_right_up - 1;
230 n_left_down = n_right_down - 1;
235 two_s_left_up = two_s_right_up + 1;
236 two_s_left_down = two_s_right_down + 1;
237 n_left_up = n_right_up - 1;
238 n_left_down = n_right_down - 1;
244 if ( abs( two_s_left_up - two_s_left_down ) <=
two_j ){
249 if (( dim_left_up > 0 ) && ( dim_left_down > 0 )){
251 double * mps_block_up = mps_tensor_up->
gStorage( n_left_up, two_s_left_up, irrep_left_up, n_right_up, two_s_right_up, irrep_right_up );
252 double * mps_block_down = mps_tensor_down->
gStorage( n_left_down, two_s_left_down, irrep_left_down, n_right_down, two_s_right_down, irrep_right_down );
253 double * left_block = previous->
gStorage( n_left_up, two_s_left_up, irrep_left_up, n_left_down, two_s_left_down, irrep_left_down );
259 alpha = ( (
jw_phase ) ? -1.0 : 1.0 );
263 * sqrt( ( two_s_left_down + 1.0 ) * ( two_s_right_up + 1.0 ) )
267 * sqrt( ( two_s_left_up + 1.0 ) * ( two_s_right_down + 1.0 ) )
277 dgemm_(&trans, ¬r, &dim_right_up, &dim_left_down, &dim_left_up,
278 &alpha, mps_block_up, &dim_left_up, left_block, &dim_left_up,
279 &beta, workmem, &dim_right_up);
284 dgemm_(¬r, ¬r, &dim_right_up, &dim_right_down, &dim_left_down,
285 &alpha, workmem, &dim_right_up, mps_block_down, &dim_left_down,
296 const int n_left_down = n_left_up +
n_elec;
305 for (
int geval = 0; geval < 6; geval++ ){
306 int n_right_up, n_right_down, two_s_right_up, two_s_right_down, irrep_right_up, irrep_right_down;
309 two_s_right_up = two_s_left_up;
310 two_s_right_down = two_s_left_down;
311 n_right_up = n_left_up;
312 n_right_down = n_left_down;
313 irrep_right_up = irrep_left_up;
314 irrep_right_down = irrep_left_down;
317 two_s_right_up = two_s_left_up;
318 two_s_right_down = two_s_left_down;
319 n_right_up = n_left_up + 2;
320 n_right_down = n_left_down + 2;
321 irrep_right_up = irrep_left_up;
322 irrep_right_down = irrep_left_down;
325 two_s_right_up = two_s_left_up - 1;
326 two_s_right_down = two_s_left_down - 1;
327 n_right_up = n_left_up + 1;
328 n_right_down = n_left_down + 1;
333 two_s_right_up = two_s_left_up - 1;
334 two_s_right_down = two_s_left_down + 1;
335 n_right_up = n_left_up + 1;
336 n_right_down = n_left_down + 1;
341 two_s_right_up = two_s_left_up + 1;
342 two_s_right_down = two_s_left_down - 1;
343 n_right_up = n_left_up + 1;
344 n_right_down = n_left_down + 1;
349 two_s_right_up = two_s_left_up + 1;
350 two_s_right_down = two_s_left_down + 1;
351 n_right_up = n_left_up + 1;
352 n_right_down = n_left_down + 1;
358 if ( abs( two_s_right_up - two_s_right_down ) <=
two_j ){
363 if (( dim_right_up > 0 ) && ( dim_right_down > 0 )){
365 double * mps_block_up = mps_tensor_up->
gStorage( n_left_up, two_s_left_up, irrep_left_up, n_right_up, two_s_right_up, irrep_right_up );
366 double * mps_block_down = mps_tensor_down->
gStorage( n_left_down, two_s_left_down, irrep_left_down, n_right_down, two_s_right_down, irrep_right_down );
367 double * right_block = previous->
gStorage( n_right_up, two_s_right_up, irrep_right_up, n_right_down, two_s_right_down, irrep_right_down );
373 alpha = ( (
jw_phase ) ? -1.0 : 1.0 ) * (( two_s_right_up + 1.0 ) / ( two_s_left_up + 1 ));
377 * ( two_s_right_down + 1 ) * sqrt( ( two_s_right_up + 1.0 ) / ( two_s_left_down + 1 ) )
381 * ( two_s_right_up + 1 ) * sqrt( ( two_s_right_down + 1.0 ) / ( two_s_left_up + 1 ) )
390 dgemm_(¬r, ¬r, &dim_left_up, &dim_right_down, &dim_right_up,
391 &alpha, mps_block_up, &dim_left_up, right_block, &dim_right_up,
392 &beta, workmem, &dim_left_up);
398 dgemm_(¬r, &trans, &dim_left_up, &dim_left_down, &dim_right_down,
399 &alpha, workmem, &dim_left_up, mps_block_down, &dim_left_down,
423 for (
int ikappa = 0; ikappa <
nKappa; ikappa++ ){
434 double prefactor = alpha;
441 if ( two_s_up != two_s_down ){
443 * sqrt((
moving_right ) ? (( two_s_up + 1.0 ) / ( two_s_down + 1 )) : (( two_s_down + 1.0 ) / ( two_s_up + 1 )));
446 double * block = to_add->
gStorage( n_updown, two_s_down, irrep_down, n_updown, two_s_up, irrep_up );
447 for (
int irow = 0; irow < dim_up; irow++ ){
448 for (
int icol = 0; icol < dim_down; icol++ ){
449 storage[
kappa2index[ikappa] + irow + dim_up * icol ] += prefactor * block[ icol + dim_down * irow ];
459 if ( buddy == NULL ){
return 0.0; }
476 for (
int ikappa = 0; ikappa <
nKappa; ikappa++ ){
485 double * buddy_block = buddy->
gStorage( n_updown, two_j_down, irrep_down, n_updown, two_j_up, irrep_up );
490 for (
int row = 0; row < dim_up; row++ ){
491 for (
int col = 0; col < dim_down; col++ ){
492 temp += my_block[ row + dim_up * col ] * buddy_block[ col + dim_down * row ];
496 const double prefactor = ((
get_2j() == 0 ) ? 1.0 : ( sqrt( ( two_j_up + 1.0 ) / ( two_j_down + 1 ) ) *
Special::phase( two_j_up - two_j_down ) ));
497 value += prefactor * temp;
static double wigner6j(const int two_ja, const int two_jb, const int two_jc, const int two_jd, const int two_je, const int two_jf)
Wigner-6j symbol (gsl api)
int gNmin(const int boundary) const
Get the min. possible particle number for a certain boundary.
void update(TensorOperator *previous, TensorT *mps_tensor_up, TensorT *mps_tensor_down, double *workmem)
Clear and update.
int index
Index of the Tensor object. For TensorT: a site index; for other tensors: a boundary index...
virtual ~TensorOperator()
Destructor.
int * sector_nelec_up
The up particle number sector.
int get_2j() const
Get twice the spin of the tensor operator.
int * sector_spin_down
The down spin symmetry sector (pointer points to sectorTwoS1 if two_j == 0)
int gCurrentDim(const int boundary, const int N, const int TwoS, const int irrep) const
Get the current virtual dimensions.
int get_nelec() const
Get how many electrons there are more in the symmetry sector of the lower leg compared to the upper l...
int gKappa(const int N1, const int TwoS1, const int I1, const int N2, const int TwoS2, const int I2) const
Get the index corresponding to a certain tensor block.
bool prime_last
Convention in which the tensor operator is stored (see class information)
static int phase(const int power_times_two)
Phase function.
int gTwoSmin(const int boundary, const int N) const
Get the minimum possible spin value for a certain boundary and particle number.
const SyBookkeeper * bk_down
The bookkeeper of the lower MPS.
int gKappa2index(const int kappa) const
Get the storage jump corresponding to a certain tensor block.
int gTwoSmax(const int boundary, const int N) const
Get the maximum possible spin value for a certain boundary and particle number.
double * gStorage()
Get the pointer to the storage.
double inproduct(TensorOperator *buddy, const char trans) const
Make the in-product of two TensorOperator.
void daxpy(double alpha, TensorOperator *to_add)
daxpy for TensorOperator
bool moving_right
Whether or not moving right.
int * sector_spin_up
The up spin symmetry sector.
double * gStorage()
Get the pointer to the storage.
int n_irrep
The (real-valued abelian) point group irrep difference between the symmetry sectors of the lower and ...
void update_moving_left(const int ikappa, TensorOperator *previous, TensorT *mps_tensor_up, TensorT *mps_tensor_down, double *workmem)
Update moving left.
static int directProd(const int Irrep1, const int Irrep2)
Get the direct product of the irreps with numbers Irrep1 and Irrep2: a bitwise XOR for psi4's convent...
int * sector_irrep_up
The up spin symmetry sector.
int getNumberOfIrreps() const
Get the total number of irreps.
TensorOperator(const int boundary_index, const int two_j, const int n_elec, const int n_irrep, const bool moving_right, const bool prime_last, const bool jw_phase, const SyBookkeeper *bk_up, const SyBookkeeper *bk_down)
Constructor.
void daxpy_transpose_tensorCD(const double alpha, TensorOperator *to_add)
daxpy_transpose for C- and D-tensors (with special spin-dependent factors)
int gNKappa() const
Get the number of symmetry blocks.
const SyBookkeeper * bk_up
The bookkeeper of the upper MPS.
int * kappa2index
kappa2index[kappa] indicates the start of tensor block kappa in storage. kappa2index[nKappa] gives th...
bool jw_phase
Whether or not to include a Jordan-Wigner phase due to the fermion anti-commutation relations...
int gNmax(const int boundary) const
Get the max. possible particle number for a certain boundary.
int get_irrep() const
Get the (real-valued abelian) point group irrep difference between the symmetry sectors of the lower ...
void clear()
Set all storage variables to 0.0.
int nKappa
Number of Tensor blocks.
int gIrrep(const int orbital) const
Get an orbital irrep.
int gIndex() const
Get the boundary index.
int n_elec
How many electrons there are more in the symmetry sector of the lower leg compared to the upper leg...
int two_j
Twice the spin of the tensor operator.
double * storage
The actual variables. Tensor block kappa begins at storage+kappa2index[kappa] and ends at storage+kap...
void update_moving_right(const int ikappa, TensorOperator *previous, TensorT *mps_tensor_up, TensorT *mps_tensor_down, double *workmem)
Update moving right.