def d1_q1_mapping(dim): """ Map the ck to kc D1 + Q1 = I :param dim: linear dimension of the 1-RDM :return: the dual basis of the mapping :rtype: DualBasis """ db = DualBasis() dbe_list = [] for i in range(dim): for j in range(i, dim): dbe = DualBasisElement() if i != j: dbe.add_element('ck', (i, j), 0.5) dbe.add_element('ck', (j, i), 0.5) dbe.add_element('kc', (j, i), 0.5) dbe.add_element('kc', (i, j), 0.5) dbe.dual_scalar = 0.0 else: dbe.add_element('ck', (i, j), 1.0) dbe.add_element('kc', (i, j), 1.0) dbe.dual_scalar = 1.0 # db += dbe dbe_list.append(dbe) return DualBasis(elements=dbe_list) # db
def trace_d2_bb(dim, Nb): dbe = DualBasisElement() for i, j in product(range(dim), repeat=2): if i < j: dbe.add_element('cckk_bb', (i, j, i, j), 2.0) dbe.dual_scalar = Nb * (Nb - 1) return dbe
def _trace_map(tname, dim, normalization): dbe = DualBasisElement() for i, j in product(range(dim), repeat=2): if i < j: dbe.add_element(tname, (i, j, i, j), 1.0) dbe.dual_scalar = normalization return dbe
def d2_e2_mapping(dim, measured_tpdm): """ Generate the constraints between the error matrix, d2, and a measured d2. :param dim: dimension of the spin-orbital basis :param measured_tpdm: a 4-tensor of the measured 2-p :return: """ db_elements = [] for p, q, r, s in product(range(dim), repeat=4): if p * dim + q >= r * dim + s: dbe = DualBasisElement() # two elements of d2 dbe.add_element('cckk', (p, q, r, s), 0.5) dbe.add_element('cckk', (r, s, p, q), 0.5) # add four elements of the error matrix dbe.add_element('cckk_me', (p * dim + q + dim**2, r * dim + s), -0.25) dbe.add_element('cckk_me', (r * dim + s + dim**2, p * dim + q), -0.25) dbe.add_element('cckk_me', (p * dim + q, r * dim + s + dim**2), -0.25) dbe.add_element('cckk_me', (r * dim + s, p * dim + q + dim**2), -0.25) dbe.dual_scalar = measured_tpdm[p, q, r, s].real dbe.simplify() # construct the dual basis element for constraining the [0, 0] orthant to be identity matrix dbe_idenity = DualBasisElement() if p * dim + q == r * dim + s: dbe_idenity.add_element('cckk_me', (p * dim + q, r * dim + s), 1.0) dbe_idenity.dual_scalar = 1.0 else: # will a symmetric constraint provide variational freedom? dbe_idenity.add_element('cckk_me', (p * dim + q, r * dim + s), 0.5) dbe_idenity.add_element('cckk_me', (r * dim + s, p * dim + q), 0.5) dbe_idenity.dual_scalar = 0.0 db_elements.append(dbe) db_elements.append(dbe_idenity) return DualBasis(elements=db_elements)
def d1a_d1b_mapping(tname_d1a, tname_d1b, dim): db = DualBasis() for i in range(dim): for j in range(i, dim): dbe = DualBasisElement() if i != j: dbe.add_element(tname_d1a, (i, j), 0.5) dbe.add_element(tname_d1a, (j, i), 0.5) dbe.add_element(tname_d1b, (i, j), -0.5) dbe.add_element(tname_d1b, (j, i), -0.5) dbe.dual_scalar = 0.0 else: dbe.add_element(tname_d1a, (i, j), 1.0) dbe.add_element(tname_d1b, (i, j), -1.0) dbe.dual_scalar = 0.0 db += dbe # .simplify() return db
def _d1_q1_mapping(tname_d1, tname_q1, dim): db = DualBasis() for i in range(dim): for j in range(i, dim): dbe = DualBasisElement() if i != j: dbe.add_element(tname_d1, (i, j), 0.5) dbe.add_element(tname_d1, (j, i), 0.5) dbe.add_element(tname_q1, (i, j), 0.5) dbe.add_element(tname_q1, (j, i), 0.5) dbe.dual_scalar = 0.0 else: dbe.add_element(tname_d1, (i, j), 1.0) dbe.add_element(tname_q1, (i, j), 1.0) dbe.dual_scalar = 1.0 db += dbe.simplify() return db
def nb_constraint(dim, nb): """ :param dim: :param sz: :return: """ dbe = DualBasisElement() for i in range(dim // 2): dbe.add_element('ck', (2 * i + 1, 2 * i + 1), 1.0) dbe.dual_scalar = nb return DualBasis(elements=[dbe])
def d2q2element_ab(p, q, r, s, factor): dbe = DualBasisElement() if q == s: dbe.add_element('ck_a', (p, r), factor) if p == r: dbe.add_element('kc_b', (s, q), -factor) dbe.add_element('kkcc_ab', (r, s, p, q), factor) dbe.add_element('cckk_ab', (p, q, r, s), -factor) # dbe.dual_scalar = -krond[q, s]*krond[p, r] * factor dbe.dual_scalar = 0 return dbe
def d2q2element_ab(p, q, r, s, factor, tname_d1_1, tname_d1_2, tname_d2, tname_q2): if tname_d1_1 != 'ck_a': raise TypeError("For some reason I am expecting a ck_a. Ask Nick") dbe = DualBasisElement() dbe.add_element(tname_d1_1, (p, r), krond[q, s] * factor) dbe.add_element(tname_d1_2, (q, s), krond[p, r] * factor) dbe.add_element(tname_q2, (r, s, p, q), 1.0 * factor) dbe.add_element(tname_d2, (p, q, r, s), -1.0 * factor) dbe.dual_scalar = krond[q, s] * krond[p, r] * factor return dbe
def sz_constraint(dim, sz): """ Sz constraint is on the 1-RDM :param dim: :param sz: :return: """ dbe = DualBasisElement() for i in range(dim // 2): dbe.add_element('ck', (2 * i, 2 * i), 0.5) dbe.add_element('ck', (2 * i + 1, 2 * i + 1), -0.5) dbe.dual_scalar = sz return DualBasis(elements=[dbe])
def g2d2map_ab(p, q, r, s, key, factor=1.0): dbe = DualBasisElement() if key == 'ab': dbe.add_element('ck_' + key[0], (p, r), krond[q, s] * factor) dbe.add_element('cckk_' + key, (p, s, r, q), -1.0 * factor) elif key == 'ba': dbe.add_element('ck_' + key[0], (p, r), krond[q, s] * factor) dbe.add_element('cckk_ab', (s, p, q, r), -1.0 * factor) else: raise TypeError("I only accept ab or ba blocks") dbe.add_element('ckck_' + key, (p, q, r, s), -1.0 * factor) dbe.dual_scalar = 0.0 return dbe
def d2q2element(p, q, r, s, factor, tname_d1_1, tname_d1_2, tname_d2, tname_q2): dbe = DualBasisElement() dbe.add_element(tname_d1_1, (p, r), 2.0 * krond[q, s] * factor) dbe.add_element(tname_d1_2, (q, s), 2.0 * krond[p, r] * factor) dbe.add_element(tname_d1_1, (p, s), -2.0 * krond[r, q] * factor) dbe.add_element(tname_d1_2, (q, r), -2.0 * krond[p, s] * factor) dbe.add_element(tname_q2, (r, s, p, q), 1.0 * factor) dbe.add_element(tname_d2, (p, q, r, s), -1.0 * factor) # remember the negative sign because AX = b dbe.dual_scalar = -2.0 * krond[s, p] * krond[ r, q] * factor + 2.0 * krond[q, s] * krond[r, p] * factor return dbe
def sz_representability(dim, M): """ Constraint for S_z-representability Helgaker, Jorgensen, Olsen. Sz is one-body RDM constraint :param dim: number of spatial basis functions :param M: Sz expected value :return: """ dbe = DualBasisElement() for i in range(dim): dbe.add_element('ck_a', (i, i), 0.5) dbe.add_element('ck_b', (i, i), -0.5) dbe.dual_scalar = M return dbe
def d2q2element(p, q, r, s, factor, tname_d1_1, tname_d2, tname_q2): # , spin_string): """ # ( 1.00000) cre(r) cre(s) des(q) des(p) # ( 1.00000) kdelta(p,s) cre(r) des(q) # ( -1.00000) kdelta(p,r) cre(s) des(q) # ( -1.00000) kdelta(q,s) cre(r) des(p) # ( 1.00000) kdelta(q,r) cre(s) des(p) # ( -1.00000) kdelta(p,s) kdelta(q,r) # ( 1.00000) kdelta(p,r) kdelta(q,s) """ dbe = DualBasisElement() dbe.add_element(tname_q2, (p, q, r, s), -factor) dbe.add_element(tname_d2, (r, s, p, q), factor) if p == s: dbe.add_element(tname_d1_1, (r, q), factor) if p == r: dbe.add_element(tname_d1_1, (s, q), -factor) if q == s: dbe.add_element(tname_d1_1, (r, p), -factor) if q == r: dbe.add_element(tname_d1_1, (s, p), factor) # remember the negative sign because AX = b dbe.dual_scalar = -factor * (krond[p, r] * krond[q, s] - krond[p, s] * krond[q, r]) # dbe.add_element('kkcc_' + spin_string + spin_string, (r, s, p, q), factor) # if q == s: # dbe.add_element('ck_' + spin_string, (p, r), factor) # if p == s: # dbe.add_element('ck_' + spin_string, (q, r), -factor) # if q == r: # dbe.add_element('kc_' + spin_string, (s, p), factor) # if p == r: # dbe.add_element('kc_' + spin_string, (s, q), -factor) # dbe.add_element('cckk_' + spin_string + spin_string, (p, q, r, s), -factor) # dbe.dual_scalar = 0 return dbe
def _contraction_base(tname_d2, tname_d1, dim, normalization, offset): db = DualBasis() for i in range(dim): for j in range(i + offset, dim): dbe = DualBasisElement() for r in range(dim): dbe.add_element(tname_d2, (i, r, j, r), 0.5) dbe.add_element(tname_d2, (j, r, i, r), 0.5) dbe.add_element(tname_d1, (i, j), -0.5 * normalization) dbe.add_element(tname_d1, (j, i), -0.5 * normalization) dbe.dual_scalar = 0 # dbe.simplify() db += dbe return db
def d2bb_d1b_mapping(dim, Nb): """ Map the d2_spin-adapted 2-RDM to the D1 rdm :param Nb: number of beta electrons :param dim: :return: """ db = DualBasis() for i in range(dim): for j in range(i, dim): dbe = DualBasisElement() for r in range(dim): # Not in the basis because always zero if i == r or j == r: continue else: sir = 1 if i < r else -1 sjr = 1 if j < r else -1 ir_pair = (i, r) if i < r else (r, i) jr_pair = (j, r) if j < r else (r, j) if i == j: dbe.add_element( 'cckk_bb', (ir_pair[0], ir_pair[1], jr_pair[0], jr_pair[1]), sir * sjr * 0.5) else: # TODO: Remember why I derived a factor of 0.25 (0.5 above) for this equation. dbe.add_element( 'cckk_bb', (ir_pair[0], ir_pair[1], jr_pair[0], jr_pair[1]), sir * sjr * 0.25) dbe.add_element( 'cckk_bb', (jr_pair[0], jr_pair[1], ir_pair[0], ir_pair[1]), sir * sjr * 0.25) dbe.add_element('ck_b', (i, j), -0.5 * (Nb - 1)) dbe.add_element('ck_b', (j, i), -0.5 * (Nb - 1)) dbe.dual_scalar = 0 dbe.simplify() db += dbe return db
def s_representability_d2ab(dim, N, M, S): """ Constraint for S-representability PHYSICAL REVIEW A 72, 052505 2005 :param dim: number of spatial basis functions :param N: Total number of electrons :param M: Sz expected value :param S: S(S + 1) is eigenvalue of S^{2} :return: """ dbe = DualBasisElement() for i, j in product(range(dim), repeat=2): dbe.add_element('cckk_ab', (i, j, j, i), 1.0) dbe.dual_scalar = N / 2.0 + M**2 - S * (S + 1) return dbe
def g2d2map(p, q, r, s, factor=1): """ Build the dual basis element for a symmetric 2-marginal :param p: tensor index :param q: tensor index :param r: tensor index :param s: tensor index :param factor: weighting of the element :return: the dual basis element """ dbe = DualBasisElement() dbe.add_element('ck', (p, r), -1. * krond[q, s] * factor) dbe.add_element('ckck', (p, s, r, q), 1.0 * factor) dbe.add_element('cckk', (p, q, r, s), 1.0 * factor) dbe.dual_scalar = 0 return dbe
def d2aa_d1a_mapping(dim, Na): """ Map the d2_spin-adapted 2-RDM to the D1 rdm :param Nb: number of beta electrons :param dim: :return: """ db = DualBasis() for i in range(dim): for j in range(i, dim): dbe = DualBasisElement() for r in range(dim): # Not in the basis because always zero if i == r or j == r: continue else: sir = 1 if i < r else -1 sjr = 1 if j < r else -1 ir_pair = (i, r) if i < r else (r, i) jr_pair = (j, r) if j < r else (r, j) if i == j: dbe.add_element( 'cckk_aa', (ir_pair[0], ir_pair[1], jr_pair[0], jr_pair[1]), sir * sjr) else: dbe.add_element( 'cckk_aa', (ir_pair[0], ir_pair[1], jr_pair[0], jr_pair[1]), sir * sjr * 0.5) dbe.add_element( 'cckk_aa', (jr_pair[0], jr_pair[1], ir_pair[0], ir_pair[1]), sir * sjr * 0.5) dbe.add_element('ck_a', (i, j), -0.5 * (Na - 1)) dbe.add_element('ck_a', (j, i), -0.5 * (Na - 1)) dbe.dual_scalar = 0 # dbe.simplify() db += dbe return db
def g2d2map_aabb(p, q, r, s, dim, key, factor=1.0): """ Accept pqrs of G2 and map to D2 """ dbe = DualBasisElement() # this is ugly. :( quad = {'aabb': [0, 1], 'bbaa': [1, 0]} dbe.add_element('ckck_aabb', (p * dim + q + quad[key][0] * dim**2, r * dim + s + quad[key][1] * dim**2), 1.0 * factor) dbe.add_element('ckck_aabb', (r * dim + s + quad[key[::-1]][0] * dim**2, p * dim + q + quad[key[::-1]][1] * dim**2), 1.0 * factor) dbe.add_element('cckk_ab', (p, s, q, r), -1.0 * factor) dbe.add_element('cckk_ab', (q, r, p, s), -1.0 * factor) dbe.dual_scalar = 0.0 return dbe
def g2d2map_aa_or_bb(p, q, r, s, dim, key, factor=1.0): """ Accept pqrs of G2 and map to D2 """ dbe = DualBasisElement() quad = {'aa': [0, 0], 'bb': [1, 1]} dbe.add_element('ckck_aabb', (p * dim + q + quad[key][0] * dim**2, r * dim + s + quad[key][1] * dim**2), -1.0 * factor) dbe.add_element('ck_' + key[0], (p, r), krond[q, s] * factor) if p != s and r != q: gem1 = tuple(sorted([p, s])) gem2 = tuple(sorted([r, q])) parity = (-1)**(p < s) * (-1)**(r < q) dbe.add_element('cckk_' + key, (gem1[0], gem1[1], gem2[0], gem2[1]), parity * -0.5 * factor) dbe.dual_scalar = 0 return dbe
def d2q2element(p, q, r, s, factor): """ Build the dual basis element for symmetric form of 2-marginal :param p: tensor index :param q: tensor index :param r: tensor index :param s: tensor index :param factor: scaling coeff for a symmetric constraint :return: the dual basis of the mapping """ dbe = DualBasisElement() dbe.add_element('cckk', (p, q, r, s), -1.0 * factor) dbe.add_element('kkcc', (r, s, p, q), +1.0 * factor) dbe.add_element('ck', (p, r), krond[q, s] * factor) dbe.add_element('ck', (q, s), krond[p, r] * factor) dbe.add_element('ck', (p, s), -1. * krond[q, r] * factor) dbe.add_element('ck', (q, r), -1. * krond[p, s] * factor) dbe.dual_scalar = (krond[q, s] * krond[p, r] - krond[q, r] * krond[p, s]) * factor return dbe
def d2ab_d1b_mapping(dim, Na): """ Map the d2_spin-adapted 2-RDM to the D1 rdm :param Nb: number of beta electrons :param dim: :return: """ db = DualBasis() for i in range(dim): for j in range(i, dim): dbe = DualBasisElement() for r in range(dim): dbe.add_element('cckk_ab', (r, i, r, j), 0.5) dbe.add_element('cckk_ab', (r, j, r, i), 0.5) dbe.add_element('ck_b', (i, j), -0.5 * Na) dbe.add_element('ck_b', (j, i), -0.5 * Na) dbe.dual_scalar = 0 # dbe.simplify() db += dbe return db
def trace_d2_ab(dim, Na, Nb): dbe = DualBasisElement() for i, j in product(range(dim), repeat=2): dbe.add_element('cckk_ab', (i, j, i, j), 1.0) dbe.dual_scalar = Na * Nb return dbe
def d2_e2_mapping(dim, bas_aa, bas_ab, measured_tpdm_aa, measured_tpdm_bb, measured_tpdm_ab): """ Generate constraints such that the error matrix and the d2 matrices look like the measured matrices :param dim: spatial basis dimension :param measured_tpdm_aa: two-marginal of alpha-alpha spins :param measured_tpdm_bb: two-marginal of beta-beta spins :param measured_tpdm_ab: two-marginal of alpha-beta spins :return: """ db = DualBasis() # first constrain the aa-matrix aa_dim = dim * (dim - 1) / 2 ab_dim = dim**2 # map the aa matrix to the measured_tpdm_aa for p, q, r, s in product(range(dim), repeat=4): if p < q and r < s and bas_aa[(p, q)] <= bas_aa[(r, s)]: dbe = DualBasisElement() # two elements of D2aa dbe.add_element('cckk_aa', (p, q, r, s), 0.5) dbe.add_element('cckk_aa', (r, s, p, q), 0.5) # four elements of the E2aa dbe.add_element('cckk_me_aa', (bas_aa[(p, q)] + aa_dim, bas_aa[(r, s)]), 0.25) dbe.add_element('cckk_me_aa', (bas_aa[(r, s)] + aa_dim, bas_aa[(p, q)]), 0.25) dbe.add_element('cckk_me_aa', (bas_aa[(p, q)], bas_aa[(r, s)] + aa_dim), 0.25) dbe.add_element('cckk_me_aa', (bas_aa[(r, s)], bas_aa[(p, q)] + aa_dim), 0.25) dbe.dual_scalar = measured_tpdm_aa[bas_aa[(p, q)], bas_aa[(r, s)]].real dbe.simplify() # construct the dbe for constraining the [0, 0] orthant to the idenity matrix dbe_identity_aa = DualBasisElement() if bas_aa[(p, q)] == bas_aa[(r, s)]: dbe_identity_aa.add_element('cckk_me_aa', (bas_aa[(p, q)], bas_aa[(r, s)]), 1.0) dbe_identity_aa.dual_scalar = 1.0 else: dbe_identity_aa.add_element('cckk_me_aa', (bas_aa[(p, q)], bas_aa[(r, s)]), 0.5) dbe_identity_aa.add_element('cckk_me_aa', (bas_aa[(r, s)], bas_aa[(p, q)]), 0.5) dbe_identity_aa.dual_scalar = 0.0 db += dbe db += dbe_identity_aa # map the bb matrix to the measured_tpdm_bb for p, q, r, s in product(range(dim), repeat=4): if p < q and r < s and bas_aa[(p, q)] <= bas_aa[(r, s)]: dbe = DualBasisElement() # two elements of D2bb dbe.add_element('cckk_bb', (p, q, r, s), 0.5) dbe.add_element('cckk_bb', (r, s, p, q), 0.5) # four elements of the E2bb dbe.add_element('cckk_me_bb', (bas_aa[(p, q)] + aa_dim, bas_aa[(r, s)]), 0.25) dbe.add_element('cckk_me_bb', (bas_aa[(r, s)] + aa_dim, bas_aa[(p, q)]), 0.25) dbe.add_element('cckk_me_bb', (bas_aa[(p, q)], bas_aa[(r, s)] + aa_dim), 0.25) dbe.add_element('cckk_me_bb', (bas_aa[(r, s)], bas_aa[(p, q)] + aa_dim), 0.25) dbe.dual_scalar = measured_tpdm_bb[bas_aa[(p, q)], bas_aa[(r, s)]].real dbe.simplify() # construct the dbe for constraining the [0, 0] orthant to the idenity matrix dbe_identity_bb = DualBasisElement() if bas_aa[(p, q)] == bas_aa[(r, s)]: dbe_identity_bb.add_element('cckk_me_bb', (bas_aa[(p, q)], bas_aa[(r, s)]), 1.0) dbe_identity_bb.dual_scalar = 1.0 else: dbe_identity_bb.add_element('cckk_me_bb', (bas_aa[(p, q)], bas_aa[(r, s)]), 0.5) dbe_identity_bb.add_element('cckk_me_bb', (bas_aa[(r, s)], bas_aa[(p, q)]), 0.5) dbe_identity_bb.dual_scalar = 0.0 db += dbe db += dbe_identity_bb # map the ab matrix to the measured_tpdm_ab for p, q, r, s in product(range(dim), repeat=4): if bas_ab[(p, q)] <= bas_ab[(r, s)]: dbe = DualBasisElement() # two elements of D2ab dbe.add_element('cckk_ab', (p, q, r, s), 0.5) dbe.add_element('cckk_ab', (r, s, p, q), 0.5) # four elements of the E2ab dbe.add_element('cckk_me_ab', (bas_ab[(p, q)] + ab_dim, bas_ab[(r, s)]), 0.25) dbe.add_element('cckk_me_ab', (bas_ab[(r, s)] + ab_dim, bas_ab[(p, q)]), 0.25) dbe.add_element('cckk_me_ab', (bas_ab[(p, q)], bas_ab[(r, s)] + ab_dim), 0.25) dbe.add_element('cckk_me_ab', (bas_ab[(r, s)], bas_ab[(p, q)] + ab_dim), 0.25) dbe.dual_scalar = measured_tpdm_ab[bas_ab[(p, q)], bas_ab[(r, s)]].real dbe.simplify() # construct the dbe for constraining the [0, 0] orthant to the idenity matrix dbe_identity_ab = DualBasisElement() if bas_ab[(p, q)] == bas_ab[(r, s)]: dbe_identity_ab.add_element('cckk_me_ab', (bas_ab[(p, q)], bas_ab[(r, s)]), 1.0) dbe_identity_ab.dual_scalar = 1.0 else: dbe_identity_ab.add_element('cckk_me_ab', (bas_ab[(p, q)], bas_ab[(r, s)]), 0.5) dbe_identity_ab.add_element('cckk_me_ab', (bas_ab[(r, s)], bas_ab[(p, q)]), 0.5) dbe_identity_ab.dual_scalar = 0.0 db += dbe db += dbe_identity_ab return db
def s_rep(dim, Na, Nb, S, sz): dbe = DualBasisElement() for i, j in product(range(dim // 2), repeat=2): dbe.add_element('cckk', (2 * i, 2 * j + 1, 2 * i + 1, 2 * j), 1.0) dbe.dual_scalar = 0.5 * (Na + Nb) + sz**2 - S * (S + 1) return DualBasis(elements=[dbe])