/* * the intermediate determinants ~ (norb,neleca+1;norb,nelecb-1) * Annihilating one alpha electron and creating one beta electron lead * to the input ground state CI |0> * stra_id is the ID of the intermediate determinants. t1 is a buffer * of size [nstrb_or_fillcnt,norb*norb]. fillcnt is the dim of beta * strings for intermediate determinants */ static double ades_bcre_t1(double *ci0, double *t1, int fillcnt, int stra_id, int norb, int nstrb, int neleca, int nelecb, int *ades_index, int *bcre_index) { const int nnorb = norb * norb; const int inelec = neleca + 1; const int invir = norb - nelecb + 1; int ic, id, i, j, k, str1, sign, signa; const int *tab; double *pt1, *pci; double csum = 0; ades_index = ades_index + stra_id * inelec * 4; for (id = 0; id < inelec; id++) { j = EXTRACT_DES (ades_index, id); str1 = EXTRACT_ADDR(ades_index, id); signa = EXTRACT_SIGN(ades_index, id); pci = ci0 + str1 * (size_t)nstrb; pt1 = t1 + j*norb; for (k = 0; k < fillcnt; k++) { tab = bcre_index + k * invir * 4; for (ic = 0; ic < invir; ic++) { i = EXTRACT_CRE (tab, ic); str1 = EXTRACT_ADDR(tab, ic); sign = EXTRACT_SIGN(tab, ic) * signa; pt1[i] += pci[str1] * sign; csum += pci[str1] * pci[str1]; } pt1 += nnorb; } } return csum; }
/* * the intermediate determinants ~ (norb,neleca-1;norb,nelecb+1) * Annihilating one beta electron and creating one alpha electron lead * to the input ground state CI |0> * stra_id is the ID of the intermediate determinants. t1 is a buffer * of size [nstrb_or_fillcnt,norb*norb]. fillcnt is the dim of beta * strings for intermediate determinants */ static double acre_bdes_t1(double *ci0, double *t1, int fillcnt, int stra_id, int norb, int nstrb, int neleca, int nelecb, int *acre_index, int *bdes_index) { const int nnorb = norb * norb; const int inelec = nelecb + 1; const int invir = norb - neleca + 1; int ic, id, i, j, str0, str1, sign, signa; const int *tab; double *pci, *pt1; double csum = 0; acre_index = acre_index + stra_id * invir * 4; for (ic = 0; ic < invir; ic++) { i = EXTRACT_CRE (acre_index, ic); str1 = EXTRACT_ADDR(acre_index, ic); signa = EXTRACT_SIGN(acre_index, ic); pci = ci0 + str1 * (size_t)nstrb; pt1 = t1 + i; tab = bdes_index; for (str0 = 0; str0 < fillcnt; str0++) { for (id = 0; id < inelec; id++) { j = EXTRACT_DES (tab, id); str1 = EXTRACT_ADDR(tab, id); sign = EXTRACT_SIGN(tab, id) * signa; pt1[j*norb] += sign * pci[str1]; csum += pci[str1] * pci[str1]; } tab += inelec * 4; pt1 += nnorb; } } return csum; }
static void spread_a_t1(double *ci1, double *t1, int bcount, int stra_id, int strb_id, int norb, int nstrb, int nlinka, _LinkT *clink_indexa) { ci1 += strb_id; const int nnorb = norb * norb; int j, k, i, a, str1, sign; const _LinkT *tab = clink_indexa + stra_id * nlinka; double *cp0, *cp1; for (j = 0; j < nlinka; j++) { a = EXTRACT_CRE (tab[j]); i = EXTRACT_DES (tab[j]); str1 = EXTRACT_ADDR(tab[j]); sign = EXTRACT_SIGN(tab[j]); cp0 = t1 + a*norb+i; // propagate from t1 to bra, through a^+ i cp1 = ci1 + str1*(size_t)nstrb; if (sign > 0) { for (k = 0; k < bcount; k++) { cp1[k] += cp0[k*nnorb]; } } else { for (k = 0; k < bcount; k++) { cp1[k] -= cp0[k*nnorb]; } } } }
void FCIcontract_b_1e_nosym(double *h1e, double *ci0, double *ci1, int norb, int nstra, int nstrb, int nlinka, int nlinkb, int *link_indexa, int *link_indexb) { int j, k, i, a, sign; size_t str0, str1; double *pci1; double tmp; _LinkT *tab; _LinkT *clink = malloc(sizeof(_LinkT) * nlinkb * nstrb); FCIcompress_link(clink, link_indexb, norb, nstrb, nlinkb); for (str0 = 0; str0 < nstra; str0++) { pci1 = ci1 + str0 * nstrb; for (k = 0; k < nstrb; k++) { tab = clink + k * nlinkb; tmp = ci0[str0*nstrb+k]; for (j = 0; j < nlinkb; j++) { a = EXTRACT_CRE (tab[j]); i = EXTRACT_DES (tab[j]); str1 = EXTRACT_ADDR(tab[j]); sign = EXTRACT_SIGN(tab[j]); pci1[str1] += sign * tmp * h1e[a*norb+i]; } } } free(clink); }
double FCIrdm2_0b_t1ci(double *ci0, double *t1, int bcount, int stra_id, int strb_id, int norb, int nstrb, int nlinkb, _LinkT *clink_indexb) { const int nnorb = norb * norb; int i, j, a, str0, str1, sign; const _LinkT *tab = clink_indexb + strb_id * nlinkb; double *pci = ci0 + stra_id*(size_t)nstrb; double csum = 0; for (str0 = 0; str0 < bcount; str0++) { memset(t1, 0, sizeof(double) * nnorb); for (j = 0; j < nlinkb; j++) { a = EXTRACT_CRE (tab[j]); i = EXTRACT_DES (tab[j]); str1 = EXTRACT_ADDR(tab[j]); sign = EXTRACT_SIGN(tab[j]); t1[i*norb+a] += sign * pci[str1]; csum += pci[str1] * pci[str1]; } t1 += nnorb; tab += nlinkb; } return csum; }
/* * f1e_tril is the 1e hamiltonian for spin beta */ void FCIcontract_b_1e(double *f1e_tril, double *ci0, double *ci1, int norb, int nstra, int nstrb, int nlinka, int nlinkb, int *link_indexa, int *link_indexb) { int j, k, ia, str0, str1, sign; double *pci1; double tmp; _LinkT *tab; _LinkT *clink = malloc(sizeof(_LinkT) * nlinkb * nstrb); compress_link(clink, link_indexb, nstrb, nlinkb); for (str0 = 0; str0 < nstra; str0++) { pci1 = ci1 + str0 * (uint64_t)nstrb; for (k = 0; k < nstrb; k++) { tab = clink + k * nlinkb; tmp = ci0[str0*(uint64_t)nstrb+k]; for (j = 0; j < nlinkb; j++) { ia = EXTRACT_IA (tab[j]); str1 = EXTRACT_ADDR(tab[j]); sign = EXTRACT_SIGN(tab[j]); if (sign > 0) { pci1[str1] += tmp * f1e_tril[ia]; } else { pci1[str1] -= tmp * f1e_tril[ia]; } } } } free(clink); }
/* * For given stra_id, spread alpah-strings (which can propagate to stra_id) * into t1[:nstrb,nnorb] * str1-of-alpha -> create/annihilate -> str0-of-alpha * ci0[:nstra,:nstrb] is contiguous in beta-strings * bcount control the number of beta strings to be calculated. * for spin=0 system, only lower triangle of the intermediate ci vector * needs to be calculated */ static double prog_a_t1(double *ci0, double *t1, int bcount, int stra_id, int strb_id, int norb, int nstrb, int nlinka, _LinkT *clink_indexa) { ci0 += strb_id; const int nnorb = norb * (norb+1)/2; int j, k, ia, str1, sign; const _LinkT *tab = clink_indexa + stra_id * nlinka; double *pt1, *pci; double csum = 0; for (j = 0; j < nlinka; j++) { ia = EXTRACT_IA (tab[j]); str1 = EXTRACT_ADDR(tab[j]); sign = EXTRACT_SIGN(tab[j]); pt1 = t1 + ia; pci = ci0 + str1*(uint64_t)nstrb; if (sign > 0) { for (k = 0; k < bcount; k++) { pt1[k*nnorb] += pci[k]; csum += pci[k] * pci[k]; } } else { for (k = 0; k < bcount; k++) { pt1[k*nnorb] -= pci[k]; csum += pci[k] * pci[k]; } } } return csum; }
void FCIcontract_a_1e_nosym(double *h1e, double *ci0, double *ci1, int norb, int nstra, int nstrb, int nlinka, int nlinkb, int *link_indexa, int *link_indexb) { int j, k, i, a, sign; size_t str0, str1; double *pci0, *pci1; double tmp; _LinkT *tab; _LinkT *clink = malloc(sizeof(_LinkT) * nlinka * nstra); FCIcompress_link(clink, link_indexa, norb, nstra, nlinka); for (str0 = 0; str0 < nstra; str0++) { tab = clink + str0 * nlinka; for (j = 0; j < nlinka; j++) { a = EXTRACT_CRE (tab[j]); // propagate from t1 to bra, through a^+ i i = EXTRACT_DES (tab[j]); str1 = EXTRACT_ADDR(tab[j]); sign = EXTRACT_SIGN(tab[j]); pci0 = ci0 + str0 * nstrb; pci1 = ci1 + str1 * nstrb; tmp = sign * h1e[a*norb+i]; for (k = 0; k < nstrb; k++) { pci1[k] += tmp * pci0[k]; } } } free(clink); }
/* * f1e_tril is the 1e hamiltonian for spin alpha */ void FCIcontract_a_1e(double *f1e_tril, double *ci0, double *ci1, int norb, int nstra, int nstrb, int nlinka, int nlinkb, int *link_indexa, int *link_indexb) { int j, k, ia, str0, str1, sign; double *pci0, *pci1; double tmp; _LinkT *tab; _LinkT *clink = malloc(sizeof(_LinkT) * nlinka * nstra); compress_link(clink, link_indexa, nstra, nlinka); for (str0 = 0; str0 < nstra; str0++) { tab = clink + str0 * nlinka; for (j = 0; j < nlinka; j++) { ia = EXTRACT_IA (tab[j]); str1 = EXTRACT_ADDR(tab[j]); sign = EXTRACT_SIGN(tab[j]); pci0 = ci0 + str0 * (uint64_t)nstrb; pci1 = ci1 + str1 * (uint64_t)nstrb; tmp = sign * f1e_tril[ia]; for (k = 0; k < nstrb; k++) { pci1[k] += tmp * pci0[k]; } } } free(clink); }
/* * spread t1 into ci1 */ static void spread_a_t1(double *ci1, double *t1, int bcount, int stra_id, int strb_id, int norb, int nstrb, int nlinka, _LinkT *clink_indexa) { ci1 += strb_id; const int nnorb = norb * (norb+1)/2; int j, k, ia, str1, sign; const _LinkT *tab = clink_indexa + stra_id * nlinka; double *cp0, *cp1; for (j = 0; j < nlinka; j++) { ia = EXTRACT_IA (tab[j]); str1 = EXTRACT_ADDR(tab[j]); sign = EXTRACT_SIGN(tab[j]); cp0 = t1 + ia; cp1 = ci1 + str1*(uint64_t)nstrb; if (sign > 0) { for (k = 0; k < bcount; k++) { cp1[k] += cp0[k*nnorb]; } } else { for (k = 0; k < bcount; k++) { cp1[k] -= cp0[k*nnorb]; } } } }
void FCItrans_rdm1b(double *rdm1, double *bra, double *ket, int norb, int na, int nb, int nlinka, int nlinkb, int *link_indexa, int *link_indexb) { int i, a, j, k, str0, str1, sign; double *pket, *pbra; double tmp; _LinkT *tab; _LinkT *clink = malloc(sizeof(_LinkT) * nlinkb * nb); FCIcompress_link(clink, link_indexb, norb, nb, nlinkb); memset(rdm1, 0, sizeof(double) * norb*norb); for (str0 = 0; str0 < na; str0++) { pbra = bra + str0 * nb; pket = ket + str0 * nb; for (k = 0; k < nb; k++) { tab = clink + k * nlinkb; tmp = pket[k]; for (j = 0; j < nlinkb; j++) { a = EXTRACT_CRE (tab[j]); i = EXTRACT_DES (tab[j]); str1 = EXTRACT_ADDR(tab[j]); sign = EXTRACT_SIGN(tab[j]); if (sign == 0) { break; } else { rdm1[a*norb+i] += sign*pbra[str1]*tmp; } } } } free(clink); }
double FCIrdm2_a_t1ci(double *ci0, double *t1, int bcount, int stra_id, int strb_id, int norb, int nstrb, int nlinka, _LinkT *clink_indexa) { ci0 += strb_id; const int nnorb = norb * norb; int i, j, k, a, sign; size_t str1; const _LinkT *tab = clink_indexa + stra_id * nlinka; double *pt1, *pci; double csum = 0; for (j = 0; j < nlinka; j++) { a = EXTRACT_CRE (tab[j]); i = EXTRACT_DES (tab[j]); str1 = EXTRACT_ADDR(tab[j]); sign = EXTRACT_SIGN(tab[j]); pci = ci0 + str1*nstrb; pt1 = t1 + i*norb+a; if (sign == 0) { break; } else if (sign > 0) { for (k = 0; k < bcount; k++) { pt1[k*nnorb] += pci[k]; csum += pci[k] * pci[k]; } } else { for (k = 0; k < bcount; k++) { pt1[k*nnorb] -= pci[k]; csum += pci[k] * pci[k]; } } } return csum; }
/* * t2[:,i,j,k,l] = E^i_j E^k_l|ci0> */ static void rdm4_0b_t2(double *ci0, double *t2, int bcount, int stra_id, int strb_id, int norb, int na, int nb, int nlinka, int nlinkb, _LinkT *clink_indexa, _LinkT *clink_indexb) { const int nnorb = norb * norb; const int n4 = nnorb * nnorb; int i, j, k, l, a, sign, str1; double *t1 = malloc(sizeof(double) * nb * nnorb); double *pt1, *pt2; _LinkT *tab; // form t1 which has beta^+ beta |t1> => target stra_id FCI_t1ci_sf(ci0, t1, nb, stra_id, 0, norb, na, nb, nlinka, nlinkb, clink_indexa, clink_indexb); #pragma omp parallel default(none) \ shared(t1, t2, bcount, strb_id, norb, nlinkb, clink_indexb), \ private(i, j, k, l, a, str1, sign, pt1, pt2, tab) { #pragma omp for schedule(static, 1) nowait for (k = 0; k < bcount; k++) { memset(t2+k*n4, 0, sizeof(double)*n4); tab = clink_indexb + (strb_id+k) * nlinkb; for (j = 0; j < nlinkb; j++) { a = EXTRACT_CRE (tab[j]); i = EXTRACT_DES (tab[j]); str1 = EXTRACT_ADDR(tab[j]); sign = EXTRACT_SIGN(tab[j]); pt1 = t1 + str1 * nnorb; pt2 = t2 + k * n4 + (i*norb+a)*nnorb; if (sign > 0) { for (l = 0; l < nnorb; l++) { pt2[l] += pt1[l]; } } else { for (l = 0; l < nnorb; l++) { pt2[l] -= pt1[l]; } } } } } free(t1); }
/* * t2[:,i,j,k,l] = E^i_j E^k_l|ci0> */ static void rdm4_a_t2(double *ci0, double *t2, int bcount, int stra_id, int strb_id, int norb, int na, int nb, int nlinka, int nlinkb, _LinkT *clink_indexa, _LinkT *clink_indexb) { const int nnorb = norb * norb; const int n4 = nnorb * nnorb; int i, j, k, l, a, sign, str1; double *pt1, *pt2; _LinkT *tab = clink_indexa + stra_id * nlinka; #pragma omp parallel default(none) \ shared(ci0, t2, bcount, strb_id, norb, na, nb, nlinka, nlinkb, \ clink_indexa, clink_indexb, tab), \ private(i, j, k, l, a, str1, sign, pt1, pt2) { double *t1 = malloc(sizeof(double) * bcount * nnorb); #pragma omp for schedule(static, 40) for (j = 0; j < nlinka; j++) { a = EXTRACT_CRE (tab[j]); i = EXTRACT_DES (tab[j]); str1 = EXTRACT_ADDR(tab[j]); sign = EXTRACT_SIGN(tab[j]); // form t1 which has alpha^+ alpha |t1> => target stra_id (through str1) FCI_t1ci_sf(ci0, t1, bcount, str1, strb_id, norb, na, nb, nlinka, nlinkb, clink_indexa, clink_indexb); for (k = 0; k < bcount; k++) { pt1 = t1 + k * nnorb; pt2 = t2 + k * n4 + (i*norb+a)*nnorb; if (sign > 0) { for (l = 0; l < nnorb; l++) { pt2[l] += pt1[l]; } } else { for (l = 0; l < nnorb; l++) { pt2[l] -= pt1[l]; } } } } free(t1); } }
/* * make_rdm1 assumed the hermitian of density matrix */ void FCImake_rdm1a(double *rdm1, double *cibra, double *ciket, int norb, int na, int nb, int nlinka, int nlinkb, int *link_indexa, int *link_indexb) { int i, a, j, k, str0, str1, sign; double *pci0, *pci1; double *ci0 = ciket; _LinkT *tab; _LinkT *clink = malloc(sizeof(_LinkT) * nlinka * na); FCIcompress_link(clink, link_indexa, norb, na, nlinka); memset(rdm1, 0, sizeof(double) * norb*norb); for (str0 = 0; str0 < na; str0++) { tab = clink + str0 * nlinka; pci0 = ci0 + str0 * nb; for (j = 0; j < nlinka; j++) { a = EXTRACT_CRE (tab[j]); i = EXTRACT_DES (tab[j]); str1 = EXTRACT_ADDR(tab[j]); sign = EXTRACT_SIGN(tab[j]); pci1 = ci0 + str1 * nb; if (a >= i) { if (sign == 0) { break; } else if (sign > 0) { for (k = 0; k < nb; k++) { rdm1[a*norb+i] += pci0[k]*pci1[k]; } } else { for (k = 0; k < nb; k++) { rdm1[a*norb+i] -= pci0[k]*pci1[k]; } } } } } for (j = 0; j < norb; j++) { for (k = 0; k < j; k++) { rdm1[k*norb+j] = rdm1[j*norb+k]; } } free(clink); }
static void spread_b_t1(double *ci1, double *t1, int bcount, int stra_id, int strb_id, int norb, int nstrb, int nlinkb, _LinkT *clink_indexb) { const int nnorb = norb * (norb+1)/2; int j, ia, str0, str1, sign; const _LinkT *tab = clink_indexb + strb_id * nlinkb; double *pci = ci1 + stra_id * (uint64_t)nstrb; for (str0 = 0; str0 < bcount; str0++) { for (j = 0; j < nlinkb; j++) { ia = EXTRACT_IA (tab[j]); str1 = EXTRACT_ADDR(tab[j]); sign = EXTRACT_SIGN(tab[j]); pci[str1] += sign * t1[ia]; } t1 += nnorb; tab += nlinkb; } }
static void spread_b_t1(double *ci1, double *t1, int bcount, int stra_id, int strb_id, int norb, int nstrb, int nlinkb, _LinkT *clink_indexb) { const int nnorb = norb * norb; int j, i, a, str0, str1, sign; const _LinkT *tab = clink_indexb + strb_id * nlinkb; double *pci = ci1 + stra_id * (size_t)nstrb; for (str0 = 0; str0 < bcount; str0++) { for (j = 0; j < nlinkb; j++) { a = EXTRACT_CRE (tab[j]); i = EXTRACT_DES (tab[j]); str1 = EXTRACT_ADDR(tab[j]); sign = EXTRACT_SIGN(tab[j]); // propagate from t1 to bra, through a^+ i pci[str1] += sign * t1[a*norb+i]; } t1 += nnorb; tab += nlinkb; } }
/* * prog0_b_t1 is the same to prog_b_t1, except that prog0_b_t1 * initializes t1 with 0, to reduce data transfer between CPU * cache and memory */ static double prog0_b_t1(double *ci0, double *t1, int bcount, int stra_id, int strb_id, int norb, int nstrb, int nlinkb, _LinkT *clink_indexb) { const int nnorb = norb * (norb+1)/2; int j, ia, str0, str1, sign; const _LinkT *tab = clink_indexb + strb_id * nlinkb; double *pci = ci0 + stra_id*(uint64_t)nstrb; double csum = 0; for (str0 = 0; str0 < bcount; str0++) { memset(t1, 0, sizeof(double)*nnorb); for (j = 0; j < nlinkb; j++) { ia = EXTRACT_IA (tab[j]); str1 = EXTRACT_ADDR(tab[j]); sign = EXTRACT_SIGN(tab[j]); t1[ia] += sign * pci[str1]; csum += pci[str1] * pci[str1]; } t1 += nnorb; tab += nlinkb; } return csum; }