def test_simple_arithmetic(): qubit = random.randint(0, 5) primitives = [paulis.X, paulis.Y, paulis.Z] assert (paulis.X(qubit).conjugate() == paulis.X(qubit)) assert (paulis.Y(qubit).conjugate() == -1 * paulis.Y(qubit)) assert (paulis.Z(qubit).conjugate() == paulis.Z(qubit)) assert (paulis.X(qubit).transpose() == paulis.X(qubit)) assert (paulis.Y(qubit).transpose() == -1 * paulis.Y(qubit)) assert (paulis.Z(qubit).transpose() == paulis.Z(qubit)) for P in primitives: assert (P(qubit) * P(qubit) == QubitHamiltonian(1.0)) n = random.randint(0, 10) nP = QubitHamiltonian.zero() for i in range(n): nP += P(qubit) assert (n * P(qubit) == nP) for i, Pi in enumerate(primitives): i1 = (i + 1) % 3 i2 = (i + 2) % 3 assert (Pi(qubit) * primitives[i1](qubit) == 1j * primitives[i2](qubit)) assert (primitives[i1](qubit) * Pi(qubit) == -1j * primitives[i2](qubit)) for qubit2 in random.randint(6, 10, 5): if qubit2 == qubit: continue P = primitives[random.randint(0, 2)] assert (Pi(qubit) * primitives[i1](qubit) * P(qubit2) == 1j * primitives[i2](qubit) * P(qubit2)) assert (P(qubit2) * primitives[i1](qubit) * Pi(qubit) == -1j * P(qubit2) * primitives[i2](qubit))
def make_excitation_generator( self, indices: typing.Iterable[typing.Tuple[int, int]]) -> QubitHamiltonian: """ Notes ---------- Creates the transformed hermitian generator of UCC type unitaries: M(a^\dagger_{a_0} a_{i_0} a^\dagger{a_1}a_{i_1} ... - h.c.) where the qubit map M depends is self.transformation Parameters ---------- indices : typing.Iterable[typing.Tuple[int, int]] : List of tuples [(a_0, i_0), (a_1, i_1), ... ] - recommended format, in spin-orbital notation (alpha odd numbers, beta even numbers) can also be given as one big list: [a_0, i_0, a_1, i_1 ...] Returns ------- type 1j*Transformed qubit excitation operator, depends on self.transformation """ # check indices and convert to list of tuples if necessary if len(indices) == 0: raise TequilaException( "make_excitation_operator: no indices given") elif not isinstance(indices[0], typing.Iterable): if len(indices) % 2 != 0: raise TequilaException( "make_excitation_generator: unexpected input format of indices\n" "use list of tuples as [(a_0, i_0),(a_1, i_1) ...]\n" "or list as [a_0, i_0, a_1, i_1, ... ]\n" "you gave: {}".format(indices)) converted = [(indices[2 * i], indices[2 * i + 1]) for i in range(len(indices) // 2)] else: converted = indices # convert to openfermion input format ofi = [] dag = [] for pair in converted: assert (len(pair) == 2) ofi += [ (int(pair[0]), 1), (int(pair[1]), 0) ] # openfermion does not take other types of integers like numpy.int64 dag += [(int(pair[0]), 0), (int(pair[1]), 1)] op = openfermion.FermionOperator(tuple(ofi), 1.j) # 1j makes it hermitian op += openfermion.FermionOperator(tuple(reversed(dag)), -1.j) qop = QubitHamiltonian(qubit_hamiltonian=self.transformation(op)) # check if the operator is hermitian and cast coefficients to floats # in order to avoid trouble with the simulation backends assert qop.is_hermitian() for k, v in qop.qubit_operator.terms.items(): qop.qubit_operator.terms[k] = to_float(v) qop = qop.simplify() return qop
def make_hamiltonian(self, occupied_indices=None, active_indices=None) -> QubitHamiltonian: """ """ if occupied_indices is None and self.active_space is not None: occupied_indices = self.active_space.frozen_reference_orbitals if active_indices is None and self.active_space is not None: active_indices = self.active_space.active_orbitals fop = openfermion.transforms.get_fermion_operator( self.molecule.get_molecular_hamiltonian(occupied_indices, active_indices)) return QubitHamiltonian(qubit_hamiltonian=self.transformation(fop))
def brute_force_transformation(H, old_basis, new_basis): def pair_unitary(a, b): ''' Accepts a BinaryPauliString. Return the paired unitary 1/sqrt(2) (a + b) in qubit hamiltonian. ''' a = QubitHamiltonian.from_paulistrings(a.to_pauli_strings()) b = QubitHamiltonian.from_paulistrings(b.to_pauli_strings()) return (1 / 2) ** (1 / 2) * (a + b) U = QubitHamiltonian(1) for i, i_basis in enumerate(old_basis): U *= pair_unitary(i_basis, new_basis[i]) return U * H * U
def reference_state(self, reference_orbitals: list = None, n_qubits: int = None) -> BitString: """Does a really lazy workaround ... but it works :return: Hartree-Fock Reference as binary-number Parameters ---------- reference_orbitals: list: give list of doubly occupied orbitals default is None which leads to automatic list of the first n_electron/2 orbitals Returns ------- """ if reference_orbitals is None: reference_orbitals = [i for i in range(self.n_electrons // 2)] spin_orbitals = sorted([2 * i for i in reference_orbitals] + [2 * i + 1 for i in reference_orbitals]) if n_qubits is None: n_qubits = 2 * self.n_orbitals string = "" for i in spin_orbitals: string += str(i) + "^ " fop = openfermion.FermionOperator(string, 1.0) op = QubitHamiltonian(qubit_hamiltonian=self.transformation(fop)) from tequila.wavefunction.qubit_wavefunction import QubitWaveFunction wfn = QubitWaveFunction.from_int(0, n_qubits=n_qubits) wfn = wfn.apply_qubitoperator(operator=op) assert (len(wfn.keys()) == 1) keys = [k for k in wfn.keys()] return keys[-1]
def to_qubit_hamiltonian(self): qub_ham = QubitHamiltonian() for p in self.binary_terms: qub_ham += QubitHamiltonian.from_paulistrings(p.to_pauli_strings()) return qub_ham