def test_daulbasis_init(): db = DualBasis() assert isinstance(db, DualBasis) dbe = DualBasisElement(tensor_names=['A'] * 5, tensor_coeffs=[1] * 5, tensor_elements=[(i, i) for i in range(5)]) db = DualBasis(elements=[dbe]) assert db[0] == dbe assert len(db) == 1 for tdbe in db: assert tdbe == dbe db2 = db + dbe assert isinstance(db2, DualBasis) assert len(db2) == 2 tdbe = DualBasisElement(tensor_names=['B'] * 5, tensor_coeffs=[1] * 5, tensor_elements=[(i, i) for i in range(5)]) tdb = DualBasis(elements=[tdbe]) db3 = db + tdb assert isinstance(db3, DualBasis) assert len(db3) == 2 db4 = tdbe + db assert len(db4) == 2 with pytest.raises(TypeError): _ = DualBasis(elements=[tdbe, 4]) with pytest.raises(TypeError): db = DualBasis(elements=[tdbe]) _ = db + 4
def tpdm_antisymmetry_constraint(dim: int) -> DualBasis: """ The dual basis elements representing the antisymmetry constraints :param dim: spinless Fermion basis rank :return: the dual basis of antisymmetry_constraints :rtype: DualBasis """ # dual_basis = DualBasis() dbe_list = [] for p, q, r, s in product(range(dim), repeat=4): if p * dim + q <= r * dim + s: if p < q and r < s: tensor_elements = [ tuple(indices) for indices in _coord_generator(p, q, r, s) ] tensor_names = ['cckk'] * len(tensor_elements) tensor_coeffs = [0.5] * len(tensor_elements) dbe = DualBasisElement() for n, e, c in zip(tensor_names, tensor_elements, tensor_coeffs): dbe.add_element(n, e, c) # dual_basis += dbe dbe_list.append(dbe) return DualBasis(elements=dbe_list)
def test_dual_basis_element(): de = DualBasisElement() de_2 = DualBasisElement() db_0 = de + de_2 assert isinstance(db_0, DualBasis) db_1 = db_0 + db_0 assert isinstance(db_1, DualBasis) dim = 2 opdm = np.random.random((dim, dim)) opdm = (opdm.T + opdm) / 2 opdm = Tensor(tensor=opdm, name='opdm') rdm = MultiTensor([opdm]) def generate_dual_basis_element(i, j): element = DualBasisElement(tensor_names=["opdm"], tensor_elements=[(i, j)], tensor_coeffs=[-1.0], bias=1 if i == j else 0, scalar=0) return element opdm_to_oqdm_map = DualBasis() for _, idx in opdm.all_iterator(): i, j = idx opdm_to_oqdm_map += generate_dual_basis_element(i, j) rdm.dual_basis = opdm_to_oqdm_map A, b, _ = rdm.synthesize_dual_basis() Adense = A.todense() opdm_flat = opdm.data.reshape((-1, 1)) oqdm = Adense.dot(opdm_flat) test_oqdm = oqdm + b.todense() assert np.allclose(test_oqdm.reshape((dim, dim)), np.eye(dim) - opdm.data)
def opdm_to_ohdm_mapping(dim: int) -> DualBasis: """ Map the ck to kc D1 + Q1 = I Args: dim: dimension of the spin-orbital basis Returns: DualBasis for the 1-RDM representability constraint """ 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 test_dbe_element_add(): de = DualBasisElement() de_2 = DualBasisElement() db_0 = de + de_2 assert isinstance(db_0, DualBasis) db_0 = de_2 + de assert isinstance(db_0, DualBasis) db_1 = db_0 + db_0 assert isinstance(db_1, DualBasis) with pytest.raises(TypeError): _ = de + 2
def test_dualbasis_element_init(): dbe = DualBasisElement() assert isinstance(dbe, DualBasisElement) dbe = DualBasisElement(tensor_names=['A'] * 5, tensor_coeffs=[1] * 5, tensor_elements=[(i, i) for i in range(5)]) assert dbe.primal_tensors_names == ['A'] * 5 assert dbe.primal_coeffs == [1] * 5 assert dbe.primal_elements == [(i, i) for i in range(5)] assert dbe.constant_bias == 0 assert dbe.dual_scalar == 0
def test_simplify(): i, j, k, l = 0, 1, 2, 3 names = ['opdm'] * 3 + ['oqdm'] elements = [(i, j), (i, j), (i, l), (l, k)] coeffs = [1, 1, 0.25, 0.3] dbe = DualBasisElement(tensor_names=names, tensor_elements=elements, tensor_coeffs=coeffs) dbe.simplify() assert len(dbe.primal_tensors_names) == 3 assert set(dbe.primal_coeffs) == {2, 0.25, 0.3} assert set(dbe.primal_tensors_names) == {'opdm', 'oqdm'} assert set(dbe.primal_elements) == {(0, 1), (0, 3), (3, 2)}
def test_add_dualelement(): a = np.random.random((5, 5, 5, 5)) b = np.random.random((4, 4, 4)) c = np.random.random((3, 3)) at = Tensor(tensor=a, name='a') bt = Tensor(tensor=b, name='b') ct = Tensor(tensor=c, name='c') mt = MultiTensor([at, bt, ct]) assert isinstance(mt.dual_basis, DualBasis) dbe = DualBasisElement() dbe.add_element('a', (0, 1, 2, 3), 4) mt.add_dual_elements(dbe) assert len(mt.dual_basis) == 1
def tpdm_to_opdm_mapping(dim: int, normalization: Union[float, int]) -> DualBasis: """ Construct the DualBasis for mapping of the tpdm to the opdm Args: dim: dimension of the spin-orbital basis. normalization: Scalar for mapping tpdm to opdm. Generally, this is 1 / (N - 1) where N is the number of electrons. Returns: DualBasis for all dim^2 """ db_basis = DualBasis() for i in range(dim): for j in range(i, dim): dbe = DualBasisElement() # contract over tpdm terms for r in range(dim): # duplicate entries get summed in DualBasisElement dbe.add_element('cckk', (i, r, j, r), 0.5) dbe.add_element('cckk', (j, r, i, r), 0.5) # opdm terms dbe.add_element('ck', (i, j), -0.5 * normalization) dbe.add_element('ck', (j, i), -0.5 * normalization) dbe.simplify() db_basis += dbe return db_basis
def generate_dual_basis_element(i, j): element = DualBasisElement(tensor_names=["opdm"], tensor_elements=[(i, j)], tensor_coeffs=[-1.0], bias=1 if i == j else 0, scalar=0) return element
def nb_constraint(dim, nb): """ Constraint the trace of the alpha block of the opdm to equal the number of spin-down electrons Args: dim: Dimension of the spin-orbital basis. na: Number of spin down electrons Returns: DualBasis representing the cosntraint that is length 1 """ 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 test_dbe_iterator(): dbe = DualBasisElement(tensor_names=['A'] * 5, tensor_coeffs=[1] * 5, tensor_elements=[(i, i) for i in range(5)]) for idx, (t, v, c) in enumerate(dbe): assert t == 'A' assert v == (idx, idx) assert c == 1
def na_constraint(dim: int, na: Union[float, int]) -> DualBasis: """ Constraint the trace of the alpha block of the opdm to equal the number of spin-up electrons Args: dim: Dimension of the spin-orbital basis. na: Number of spin up electrons Returns: DualBasis representing the cosntraint that is length 1 """ dbe = DualBasisElement() for i in range(dim // 2): dbe.add_element('ck', (2 * i, 2 * i), 1.0) dbe.dual_scalar = na return DualBasis(elements=[dbe])
def test_synthesis_dualbasis(): a = np.random.random((5, 5)) b = np.random.random((4, 4)) c = np.random.random((3, 3)) at = Tensor(tensor=a, name='a') bt = Tensor(tensor=b, name='b') ct = Tensor(tensor=c, name='c') dbe = DualBasisElement() dbe.add_element('a', (0, 1), 4) dbe.add_element('a', (1, 0), 4) mt = MultiTensor([at, bt, ct], DualBasis(elements=[dbe])) A, c, b = mt.synthesize_dual_basis() assert isinstance(A, sp.sparse.csr_matrix) assert isinstance(c, sp.sparse.csr_matrix) assert isinstance(b, sp.sparse.csr_matrix) assert A.shape == (1, 50) assert b.shape == (1, 1) assert c.shape == (1, 1)
def sz_constraint(dim: int, sz: Union[float, int]) -> DualBasis: """ Constraint on the 1-RDM Args: dim: dimension of the spin-orbital basis. sz: expectation value of the magnetic quantum number. Returns: DualBasis """ 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 tpdm_trace_constraint(dim: int, normalization: float) -> DualBasisElement: """ Generate the trace constraint on the 2-PDM Args: dim: Dimension of the spin-orbital single-particle Hilbert space normalization: Desired trace value. Returns: A DualBasisElement (Row of the constraint matrix) encoding the trace constraint on the 2-RDM. """ tensor_elements = [(i, j, i, j) for i, j in product(range(dim), repeat=2)] tensor_names = ['cckk'] * (dim**2) tensor_coeffs = [1.0] * (dim**2) bias = 0 return DualBasisElement(tensor_names=tensor_names, tensor_elements=tensor_elements, tensor_coeffs=tensor_coeffs, bias=bias, scalar=normalization)
def g2d2map(p: int, q: int, r: int, s: int, factor: Optional[Union[float, int]] = 1) -> DualBasisElement: """ 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() if q == s: dbe.add_element('ck', (p, r), -1. * 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 test_synthesis_element(): a = np.random.random((5, 5)) b = np.random.random((4, 4)) c = np.random.random((3, 3)) at = Tensor(tensor=a, name='a') bt = Tensor(tensor=b, name='b') ct = Tensor(tensor=c, name='c') mt = MultiTensor([at, bt, ct]) dbe = DualBasisElement() dbe.add_element('a', (0, 1), 4) dbe.add_element('a', (1, 0), 4) with pytest.raises(TypeError): dbe.add_element(5) with pytest.raises(TypeError): mt.add_dual_elements(5) mt.add_dual_elements(dbe) colidx, data_vals = mt.synthesize_element(dbe) assert data_vals == [4, 4] assert colidx == [1, 5] assert [at.data[0, 1], at.data[1, 0]] == [at(0, 1), at(1, 0)]
def test_dbe_string(): dbe = DualBasisElement(tensor_names=['A'] * 5, tensor_coeffs=[1] * 5, tensor_elements=[(i, i) for i in range(5)]) assert dbe.id() == "A(0,0) A(1,1) A(2,2) A(3,3) A(4,4)\t"
def d2q2element(p: int, q: int, r: int, s: int, factor: Union[float, int])\ -> DualBasisElement: """ 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) if q == s: dbe.add_element('ck', (p, r), factor) if p == r: dbe.add_element('ck', (q, s), factor) if q == r: dbe.add_element('ck', (p, s), -1. * factor) if p == s: dbe.add_element('ck', (q, r), -1. * factor) dbe.dual_scalar = ( kronecker_delta(q, s) * kronecker_delta(p, r) - kronecker_delta(q, r) * kronecker_delta(p, s)) * factor return dbe
def test_add_element(): with pytest.raises(TypeError): dbe = DualBasisElement() dbe.add_element('cckk', [1, 2, 3, 4], 0.5) with pytest.raises(TypeError): dbe = DualBasisElement() dbe.add_element(5, (1, 2, 3, 4), 0.5) with pytest.raises(TypeError): dbe = DualBasisElement() dbe.add_element('a', (1, 2, 3, 4), 'a') dbe = DualBasisElement() dbe.add_element('cckk', (1, 2, 3, 4), 0.5) dbe.constant_bias = 0.33 assert dbe.primal_coeffs == [0.5] assert dbe.primal_tensors_names == ['cckk'] assert dbe.primal_elements == [(1, 2, 3, 4)] dbe.add_element('ck', (0, 1), 1) assert dbe.primal_coeffs == [0.5, 1] assert dbe.primal_tensors_names == ['cckk', 'ck'] assert dbe.primal_elements == [(1, 2, 3, 4), (0, 1)] dbe2 = DualBasisElement() with pytest.raises(TypeError): dbe2.join_elements((1, 1)) dbe2.constant_bias = 0.25 dbe2.add_element('cckk', (1, 2, 3, 4), 0.5) dbe3 = dbe2.join_elements(dbe) assert np.isclose(dbe3.constant_bias, 0.58) assert set(dbe3.primal_elements) == {(0, 1), (1, 2, 3, 4)} assert np.allclose(dbe3.primal_coeffs, [1, 1]) assert set(dbe3.primal_tensors_names) == {'ck', 'cckk'}