def analyze_operator_blockbreaking(the_operator, the_blocks, block_labels=None): if block_labels is None: block_labels = np.arange(len(the_blocks), dtype=int) if isinstance(the_blocks[0], np.ndarray): c2s = np.concatenate(the_blocks, axis=1) assert (is_basis_orthonormal_and_complete(c2s) ), "Symmetry block problem? Not a complete, orthonormal basis." blocked_operator = represent_operator_in_basis(the_operator, c2s) blocked_idx = np.concatenate([[ idx, ] * blk.shape[1] for idx, blk in enumerate(the_blocks)]) c2l, op_svals, c2r = analyze_operator_blockbreaking( blocked_operator, blocked_idx, block_labels=block_labels) c2l = [c2s @ s2l for s2l in c2l] c2r = [c2s @ s2r for s2r in c2r] return c2l, op_svals, c2r elif np.asarray(the_blocks).dtype == np.asarray(block_labels).dtype: the_indices = np.empty(len(the_blocks), dtype=int) for idx, lbl in enumerate(block_labels): idx_indices = (the_blocks == lbl) the_indices[idx_indices] = idx the_blocks = the_indices c2l = [] c2r = [] op_svals = [] norbs = the_operator.shape[0] my_range = [ idx for idx, bl in enumerate(block_labels) if idx in the_blocks ] for idx1, idx2 in combinations(my_range, 2): blk1 = block_labels[idx1] blk2 = block_labels[idx2] idx12 = np.ix_(the_blocks == idx1, the_blocks == idx2) lvecs = np.eye(norbs, dtype=the_operator.dtype)[:, the_blocks == idx1] rvecs = np.eye(norbs, dtype=the_operator.dtype)[:, the_blocks == idx2] mat12 = the_operator[idx12] if is_matrix_zero(mat12): c2l.append(np.zeros((norbs, 0), dtype=the_operator.dtype)) c2r.append(np.zeros((norbs, 0), dtype=the_operator.dtype)) op_svals.append(np.zeros((0), dtype=the_operator.dtype)) continue try: vecs1, svals, vecs2 = matrix_svd_control_options( mat12, sort_vecs=-1, only_nonzero_vals=False) lvecs = lvecs @ vecs1 rvecs = rvecs @ vecs2 except ValueError as e: if the_operator[idx12].size > 0: raise (e) c2l.append(np.zeros((norbs, 0), dtype=the_operator.dtype)) c2r.append(np.zeros((norbs, 0), dtype=the_operator.dtype)) op_svals.append(np.zeros((0), dtype=the_operator.dtype)) continue #print ("Coupling between {} and {}: {} svals, norm = {}".format (idx1, idx2, len (svals), linalg.norm (svals))) c2l.append(lvecs) c2r.append(rvecs) op_svals.append(svals) return c2l, op_svals, c2r
def are_bases_orthogonal(bra_basis, ket_basis, ovlp=1, rtol=params.num_zero_rtol, atol=params.num_zero_atol): test_matrix = basis_olap(bra_basis, ket_basis, ovlp) rtol *= sqrt(bra_basis.shape[1] * ket_basis.shape[1]) atol *= sqrt(bra_basis.shape[1] * ket_basis.shape[1]) return is_matrix_zero(test_matrix, rtol=rtol, atol=atol), test_matrix
def count_linind_states (the_states, ovlp=1, num_zero_atol=params.num_zero_atol): c2b = np.asarray (the_states) b2c = c2b.conjugate ().T cOc = np.asarray (ovlp) nbas = c2b.shape[0] nstates = c2b.shape[1] bOb = b2c @ cOc @ c2b if cOc.shape == ((nbas, nbas)) else b2c @ c2b if is_matrix_zero (bOb) or np.abs (np.trace (bOb)) <= num_zero_atol: return 0 evals = matrix_eigen_control_options (bOb, only_nonzero_vals=True)[0] return len (evals)
def orthonormalize_a_basis (overlapping_basis, ovlp=1, num_zero_atol=params.num_zero_ltol, symmetry=None, enforce_symmetry=False): if (is_basis_orthonormal (overlapping_basis)): return overlapping_basis c2b = np.asarray (overlapping_basis) cOc = np.asarray (ovlp) if enforce_symmetry: c2n = np.zeros ((overlapping_basis.shape[0], 0), dtype=overlapping_basis.dtype) for c2s in symmetry: s2c = c2s.conjugate ().T s2b = s2c @ c2b sOs = s2c @ cOc @ c2s if cOc.shape == ((c2b.shape[0], c2b.shape[0])) else (s2c * cOc) @ c2s s2n = orthonormalize_a_basis (s2b, ovlp=sOs, num_zero_atol=num_zero_atol, symmetry=None, enforce_symmetry=False) c2n = np.append (c2n, c2s @ s2n, axis=1) return (c2n) b2c = c2b.conjugate ().T bOb = b2c @ cOc @ c2b if cOc.shape == ((c2b.shape[0], c2b.shape[0])) else (b2c * cOc) @ c2b assert (not is_matrix_zero (bOb)), "overlap matrix is zero! problem with basis?" assert (np.allclose (bOb, bOb.conjugate ().T)), "overlap matrix not hermitian! problem with basis?" assert (np.abs (np.trace (bOb)) > num_zero_atol), "overlap matrix zero or negative trace! problem with basis?" evals, evecs = matrix_eigen_control_options (bOb, sort_vecs=-1, only_nonzero_vals=True, num_zero_atol=num_zero_atol) if len (evals) == 0: return np.zeros ((c2b.shape[0], 0), dtype=c2b.dtype) p2x = np.asarray (evecs) c2x = c2b @ p2x assert (not np.any (evals < 0)), "overlap matrix has negative eigenvalues! problem with basis?" # I want c2n = c2x * x2n # x2n defined such that n2c * c2n = I # n2x * x2c * c2x * x2n = n2x * evals_xx * x2n = I # therefore # x2n = evals_xx^{-1/2} x2n = np.asarray (np.diag (np.reciprocal (np.sqrt (evals)))) c2n = c2x @ x2n n2c = c2n.conjugate ().T nOn = n2c @ cOc @ c2n if cOc.shape == ((c2b.shape[0], c2b.shape[0])) else (n2c * cOc) @ c2n if not is_basis_orthonormal (c2n): # Assuming numerical problem due to massive degeneracy; remove constant from diagonal to improve solver? assert (np.all (np.isclose (np.diag (nOn), 1))), np.diag (nOn) - 1 nOn[np.diag_indices_from (nOn)] -= 1 evals, evecs = matrix_eigen_control_options (nOn, sort_vecs=-1, only_nonzero_vals=False) n2x = np.asarray (evecs) c2x = c2n @ n2x x2n = np.asarray (np.diag (np.reciprocal (np.sqrt (evals + 1)))) c2n = c2x @ x2n n2c = c2n.conjugate ().T nOn = n2c @ cOc @ c2n if cOc.shape == ((c2b.shape[0], c2b.shape[0])) else (n2c * cOc) @ c2n assert (is_basis_orthonormal (c2n)), "failed to orthonormalize basis even after two tries somehow\n" + str ( prettyprint_ndarray (nOn)) + "\n" + str (np.linalg.norm (nOn - np.eye (c2n.shape[1]))) + "\n" + str (evals) return np.asarray (c2n)
def is_operator_block_adapted (the_operator, the_blocks, tol=params.num_zero_atol): tol *= the_operator.shape[0] if isinstance (the_blocks[0], np.ndarray): umat = np.concatenate (the_blocks, axis=1) assert (is_basis_orthonormal_and_complete (umat)), 'Symmetry blocks must be orthonormal and complete, {}'.format (len (the_blocks)) operator_block = represent_operator_in_basis (the_operator, umat) labels = np.concatenate ([[idx,] * blk.shape[1] for idx, blk in enumerate (the_blocks)]) return is_operator_block_adapted (operator_block, labels) iterable = the_blocks if isinstance (the_blocks[0], np.ndarray) else np.unique (the_blocks) offblk_operator = the_operator.copy () for blk in np.unique (the_blocks): offblk_operator[np.ix_(the_blocks==blk,the_blocks==blk)] = 0 return is_matrix_zero (offblk_operator, atol=tol)