Exemplo n.º 1
0
    def test_model_integration_with_constant(self):
        # Compute Hamiltonian in both momentum and position space.
        length_scale = 0.7
        for length in [2, 3]:
            grid = Grid(dimensions=2, length=length, scale=length_scale)
            spinless = True

            # Include Madelung constant in the momentum but not the position
            # Hamiltonian.
            momentum_hamiltonian = jellium_model(grid,
                                                 spinless,
                                                 True,
                                                 include_constant=True)
            position_hamiltonian = jellium_model(grid, spinless, False)

            # Confirm they are Hermitian
            momentum_hamiltonian_operator = (
                get_sparse_operator(momentum_hamiltonian))
            self.assertTrue(is_hermitian(momentum_hamiltonian_operator))

            position_hamiltonian_operator = (
                get_sparse_operator(position_hamiltonian))
            self.assertTrue(is_hermitian(position_hamiltonian_operator))

            # Diagonalize and confirm the same energy.
            jw_momentum = jordan_wigner(momentum_hamiltonian)
            jw_position = jordan_wigner(position_hamiltonian)
            momentum_spectrum = eigenspectrum(jw_momentum)
            position_spectrum = eigenspectrum(jw_position)

            # Confirm momentum spectrum is shifted 2.8372/length_scale higher.
            max_difference = numpy.amax(momentum_spectrum - position_spectrum)
            min_difference = numpy.amax(momentum_spectrum - position_spectrum)
            self.assertAlmostEqual(max_difference, 2.8372 / length_scale)
            self.assertAlmostEqual(min_difference, 2.8372 / length_scale)
Exemplo n.º 2
0
    def setUp(self):
        self.x_dimension = 2
        self.y_dimension = 3

        # Create a Hamiltonian with nearest-neighbor hopping terms
        self.ferm_op = fermi_hubbard(self.x_dimension, self.y_dimension, 1.,
                                     0., 0., 0., False, True)

        # Get the ground energy and ground state
        self.ferm_op_sparse = get_sparse_operator(self.ferm_op)
        self.ferm_op_ground_energy, self.ferm_op_ground_state = (
            get_ground_state(self.ferm_op_sparse))

        # Transform the FermionOperator to a QubitOperator
        self.transformed_op = verstraete_cirac_2d_square(
            self.ferm_op,
            self.x_dimension,
            self.y_dimension,
            add_auxiliary_hamiltonian=True,
            snake=False)

        # Get the ground energy and state of the transformed operator
        self.transformed_sparse = get_sparse_operator(self.transformed_op)
        self.transformed_ground_energy, self.transformed_ground_state = (
            get_ground_state(self.transformed_sparse))
Exemplo n.º 3
0
    def test_bk_jw_majoranas(self):
        # Check if the Majorana operators have the same spectrum
        # irrespectively of the transform.
        n_qubits = 7

        a = FermionOperator(((1, 0),))
        a_dag = FermionOperator(((1, 1),))

        c = a + a_dag
        d = 1j * (a_dag - a)

        c_spins = [jordan_wigner(c), bravyi_kitaev_tree(c)]
        d_spins = [jordan_wigner(d), bravyi_kitaev_tree(d)]

        c_sparse = [get_sparse_operator(c_spins[0]),
                    get_sparse_operator(c_spins[1])]
        d_sparse = [get_sparse_operator(d_spins[0]),
                    get_sparse_operator(d_spins[1])]

        c_spectrum = [eigenspectrum(c_spins[0]),
                      eigenspectrum(c_spins[1])]
        d_spectrum = [eigenspectrum(d_spins[0]),
                      eigenspectrum(d_spins[1])]

        self.assertAlmostEqual(0., numpy.amax(numpy.absolute(d_spectrum[0] -
                                                             d_spectrum[1])))
    def test_jw_get_ground_states_by_particle_number_herm_conserving(self):
        # Initialize a particle-number-conserving Hermitian operator
        ferm_op = FermionOperator('0^ 1') + FermionOperator('1^ 0') + \
            FermionOperator('1^ 2') + FermionOperator('2^ 1') + \
            FermionOperator('1^ 3', -.4) + FermionOperator('3^ 1', -.4)
        jw_hamiltonian = jordan_wigner(ferm_op)
        sparse_operator = get_sparse_operator(jw_hamiltonian)
        n_qubits = 4

        # Test each possible particle number
        for particle_number in range(n_qubits):
            # Get the ground energy and ground states at this particle number
            energy, states = jw_get_ground_states_by_particle_number(
                sparse_operator, particle_number)
            # Construct particle number operator
            num_op = get_sparse_operator(number_operator(n_qubits))
            # For each vector returned, make sure that it is indeed an
            # eigenvector of the original operator with the returned eigenvalue
            # and that it has the correct particle number
            for vec in states:
                # Check that it's an eigenvector with the correct eigenvalue
                op_vec_product = sparse_operator.dot(vec)
                difference = op_vec_product - energy * vec
                discrepancy = 0.
                if difference.nnz:
                    discrepancy = max(map(abs, difference.data))
                self.assertAlmostEqual(0., discrepancy)
                # Check that it has the correct particle number
                num = expectation(num_op, vec)
                self.assertAlmostEqual(num, particle_number)
Exemplo n.º 5
0
    def test_plane_wave_hamiltonian_integration(self):
        length_set = [2, 3, 4]
        spinless_set = [True, False]
        length_scale = 1.1
        for geometry in [[('H', (0, )), ('H', (0.8, ))], [('H', (0.1, ))],
                         [('H', (0.1, ))]]:
            for l in length_set:
                for spinless in spinless_set:
                    grid = Grid(dimensions=1, scale=length_scale, length=l)
                    h_plane_wave = plane_wave_hamiltonian(
                        grid, geometry, spinless, True, include_constant=False)
                    h_dual_basis = plane_wave_hamiltonian(
                        grid,
                        geometry,
                        spinless,
                        False,
                        include_constant=False)

                    # Test for Hermiticity
                    plane_wave_operator = get_sparse_operator(h_plane_wave)
                    dual_operator = get_sparse_operator(h_dual_basis)
                    self.assertTrue(is_hermitian((plane_wave_operator)))
                    self.assertTrue(is_hermitian(dual_operator))

                    jw_h_plane_wave = jordan_wigner(h_plane_wave)
                    jw_h_dual_basis = jordan_wigner(h_dual_basis)
                    h_plane_wave_spectrum = eigenspectrum(jw_h_plane_wave)
                    h_dual_basis_spectrum = eigenspectrum(jw_h_dual_basis)

                    max_diff = numpy.amax(h_plane_wave_spectrum -
                                          h_dual_basis_spectrum)
                    min_diff = numpy.amin(h_plane_wave_spectrum -
                                          h_dual_basis_spectrum)
                    self.assertAlmostEqual(max_diff, 0)
                    self.assertAlmostEqual(min_diff, 0)
Exemplo n.º 6
0
    def setUp(self):
        self.n_qubits = 5
        self.constant = 1.7
        self.chemical_potential = 2.

        # Obtain random Hermitian and antisymmetric matrices
        self.hermitian_mat = random_hermitian_matrix(self.n_qubits)
        self.antisymmetric_mat = random_antisymmetric_matrix(self.n_qubits)

        self.combined_hermitian = (
            self.hermitian_mat -
            self.chemical_potential * numpy.eye(self.n_qubits))

        # Initialize a particle-number-conserving Hamiltonian
        self.quad_ham_pc = QuadraticHamiltonian(self.hermitian_mat,
                                                constant=self.constant)

        # Initialize a non-particle-number-conserving Hamiltonian
        self.quad_ham_npc = QuadraticHamiltonian(self.hermitian_mat,
                                                 self.antisymmetric_mat,
                                                 self.constant,
                                                 self.chemical_potential)

        # Initialize the sparse operators and get their ground energies
        self.quad_ham_pc_sparse = get_sparse_operator(self.quad_ham_pc)
        self.quad_ham_npc_sparse = get_sparse_operator(self.quad_ham_npc)

        self.pc_ground_energy, self.pc_ground_state = get_ground_state(
            self.quad_ham_pc_sparse)
        self.npc_ground_energy, self.npc_ground_state = get_ground_state(
            self.quad_ham_npc_sparse)
Exemplo n.º 7
0
    def get_exact_gs(self, hamiltonian=None):
        """
        Calculate the exact groundstate energy of the loaded Hamiltonian

        :param PauliSum hamiltonian: (optional) Hamiltonian of which
                one would like to calculate the GS energy

        :return: groundstate energy
        :rtype: float
        """
        if hamiltonian is None:
            h = get_sparse_operator(
                    pyquilpauli_to_qubitop(PauliSum(self.pauli_list)))
        else:
            if isinstance(hamiltonian, PauliSum):
                h = get_sparse_operator(pyquilpauli_to_qubitop(hamiltonian))
            else:
                raise TypeError('please give a PauliSum()'
                        ' object as the Hamiltonian.')

        if h.shape[0] > 1024:
            # sparse matrix eigenvalue decomposition is less accurate,
            # but is necessary for larger matrices
            [w, _] = sp.sparse.linalg.eigsh(h, k=1)
        else:
            [w, _] = np.linalg.eigh(h.todense())

        Egs = min(w).real

        return Egs
Exemplo n.º 8
0
    def test_potential_integration(self):
        # Compute potential energy operator in momentum and position space.
        for length in [2, 3]:
            grid = Grid(dimensions=2, length=length, scale=2.)
            spinless = True
            momentum_potential = plane_wave_potential(grid, spinless)
            position_potential = dual_basis_potential(grid, spinless)

            # Confirm they are Hermitian
            momentum_potential_operator = (
                get_sparse_operator(momentum_potential))
            self.assertTrue(is_hermitian(momentum_potential_operator))

            position_potential_operator = (
                get_sparse_operator(position_potential))
            self.assertTrue(is_hermitian(position_potential_operator))

            # Diagonalize and confirm the same energy.
            jw_momentum = jordan_wigner(momentum_potential)
            jw_position = jordan_wigner(position_potential)
            momentum_spectrum = eigenspectrum(jw_momentum)
            position_spectrum = eigenspectrum(jw_position)

            # Confirm spectra are the same.
            difference = numpy.amax(
                numpy.absolute(momentum_spectrum - position_spectrum))
            self.assertAlmostEqual(difference, 0.)
Exemplo n.º 9
0
    def test_model_integration(self):
        # Compute Hamiltonian in both momentum and position space.
        for length in [2, 3]:
            grid = Grid(dimensions=2, length=length, scale=1.0)
            spinless = True
            momentum_hamiltonian = jellium_model(grid, spinless, True)
            position_hamiltonian = jellium_model(grid, spinless, False)

            # Confirm they are Hermitian
            momentum_hamiltonian_operator = (
                get_sparse_operator(momentum_hamiltonian))
            self.assertTrue(is_hermitian(momentum_hamiltonian_operator))

            position_hamiltonian_operator = (
                get_sparse_operator(position_hamiltonian))
            self.assertTrue(is_hermitian(position_hamiltonian_operator))

            # Diagonalize and confirm the same energy.
            jw_momentum = jordan_wigner(momentum_hamiltonian)
            jw_position = jordan_wigner(position_hamiltonian)
            momentum_spectrum = eigenspectrum(jw_momentum)
            position_spectrum = eigenspectrum(jw_position)

            # Confirm spectra are the same.
            difference = numpy.amax(
                numpy.absolute(momentum_spectrum - position_spectrum))
            self.assertAlmostEqual(difference, 0.)
Exemplo n.º 10
0
    def test_nonperiodic_external_potential_integration(self):
        # Compute potential energy operator in momentum and position space.
        # Non-periodic test.
        
        '''
        Key: Spatial dimension.
        Value: List of geometries.
        '''
        geometry_sets = {
                    2: [[('H', (0., 0.)), ('H', (0.8, 0.))], 
                        [('H', (0.1, 0.))]], 
                    3: [[('H', (0., 0., 0.)), ('H', (0.8, 0., 0.))], 
                        [('H', (0.1, 0., 0.))]]
                  }
        
        # [[spatial dimension, fieldline dimension]]
        dims = [[2, 2], [2, 3], [3, 3]]
        scale = 8 * 1.
        spinless = True
        
        for dim in dims:
            
            # If dim[0] == 2, get range(2, 4).
            # If dim[0] == 3, get range(2, 3).
            for length in range(2, 6 - dim[0]):
                for geometry in geometry_sets[dim[0]]:
                    grid = Grid(dimensions=dim[0], scale=scale, length=length)
                    period_cutoff = grid.volume_scale() ** (1. / grid.dimensions)

                    momentum_external_potential = plane_wave_external_potential(grid, geometry, spinless, e_cutoff=None, 
                                                                                non_periodic=True, period_cutoff=period_cutoff,
                                                                                fieldlines=dim[1])
                    position_external_potential = dual_basis_external_potential(grid, geometry, spinless, 
                                                                                non_periodic=True, period_cutoff=period_cutoff,
                                                                                fieldlines=dim[1])

                    # Confirm they are Hermitian
                    momentum_external_potential_operator = (
                        get_sparse_operator(momentum_external_potential))
                    self.assertTrue(is_hermitian(momentum_external_potential_operator))

                    position_external_potential_operator = (
                        get_sparse_operator(position_external_potential))
                    self.assertTrue(is_hermitian(position_external_potential_operator))

                    # Diagonalize.
                    jw_momentum = jordan_wigner(momentum_external_potential)
                    jw_position = jordan_wigner(position_external_potential)
                    momentum_spectrum = eigenspectrum(jw_momentum)
                    position_spectrum = eigenspectrum(jw_position)

                    # Confirm spectra are the same.
                    difference = numpy.amax(
                        numpy.absolute(momentum_spectrum - position_spectrum))
                    self.assertAlmostEqual(difference, 0.)
    def test_apply_constraints(self):

        # Get norm of original operator.
        original_norm = 0.
        for term, coefficient in self.fermion_hamiltonian.terms.items():
            if term != ():
                original_norm += abs(coefficient)

        # Get modified operator.
        modified_operator = apply_constraints(self.fermion_hamiltonian,
                                              self.n_fermions)
        modified_operator.compress()

        # Get norm of modified operator.
        modified_norm = 0.
        for term, coefficient in modified_operator.terms.items():
            if term != ():
                modified_norm += abs(coefficient)
        self.assertTrue(modified_norm < original_norm)

        # Map both to sparse matrix under Jordan-Wigner.
        sparse_original = get_sparse_operator(self.fermion_hamiltonian)
        sparse_modified = get_sparse_operator(modified_operator)

        # Check spectra.
        sparse_original = jw_number_restrict_operator(sparse_original,
                                                      self.n_fermions)
        sparse_modified = jw_number_restrict_operator(sparse_modified,
                                                      self.n_fermions)
        original_spectrum = sparse_eigenspectrum(sparse_original)
        modified_spectrum = sparse_eigenspectrum(sparse_modified)
        spectral_deviation = numpy.amax(
            numpy.absolute(original_spectrum - modified_spectrum))
        self.assertAlmostEqual(spectral_deviation, 0.)

        # Check expectation value.
        energy, wavefunction = get_ground_state(sparse_original)
        modified_energy = expectation(sparse_modified, wavefunction)
        self.assertAlmostEqual(modified_energy, energy)

        # Test consistency with cvxopt.
        scipy_operator = apply_constraints(self.fermion_hamiltonian,
                                           self.n_fermions,
                                           use_scipy=False)

        # Get norm.
        scipy_norm = 0.
        for term, coefficient in scipy_operator.terms.items():
            if term != ():
                scipy_norm += abs(coefficient)
        self.assertAlmostEqual(scipy_norm, modified_norm)
Exemplo n.º 12
0
    def test_model_integration_with_constant(self):
        # Compute Hamiltonian in both momentum and position space.
        length_scale = 0.7
        spinless = True

        # [[spatial dimension, fieldline dimension]]
        dims = [[2, 2], [2, 3], [3, 3]]

        for dim in dims:

            # If dim[0] == 2, get range(2, 4).
            # If dim[0] == 3, get range(2, 3).
            for length in range(2, 6 - dim[0]):
                grid = Grid(dimensions=dim[0],
                            length=length,
                            scale=length_scale)

                # Include Madelung constant in the momentum but not the position
                # Hamiltonian.
                momentum_hamiltonian = jellium_model(grid,
                                                     spinless,
                                                     True,
                                                     include_constant=True,
                                                     fieldlines=dim[1])
                position_hamiltonian = jellium_model(grid,
                                                     spinless,
                                                     False,
                                                     fieldlines=dim[1])

                # Confirm they are Hermitian.
                momentum_hamiltonian_operator = (
                    get_sparse_operator(momentum_hamiltonian))
                self.assertTrue(is_hermitian(momentum_hamiltonian_operator))

                position_hamiltonian_operator = (
                    get_sparse_operator(position_hamiltonian))
                self.assertTrue(is_hermitian(position_hamiltonian_operator))

                # Diagonalize and confirm the same energy.
                jw_momentum = jordan_wigner(momentum_hamiltonian)
                jw_position = jordan_wigner(position_hamiltonian)
                momentum_spectrum = eigenspectrum(jw_momentum)
                position_spectrum = eigenspectrum(jw_position)

                # Confirm momentum spectrum is shifted 2.8372/length_scale higher.
                max_difference = numpy.amax(momentum_spectrum -
                                            position_spectrum)
                min_difference = numpy.amax(momentum_spectrum -
                                            position_spectrum)
                self.assertAlmostEqual(max_difference, 2.8372 / length_scale)
                self.assertAlmostEqual(min_difference, 2.8372 / length_scale)
Exemplo n.º 13
0
    def test_nonperiodic_potential_integration(self):
        # Compute potential energy operator in momentum and position space.
        # Non-periodic test.
        spinless = True

        # [[spatial dimension, fieldline dimension]]
        dims = [[2, 2], [2, 3], [3, 3]]

        for dim in dims:

            # If dim[0] == 2, get range(2, 4).
            # If dim[0] == 3, get range(2, 3).
            for length in range(2, 6 - dim[0]):
                grid = Grid(dimensions=dim[0], length=length, scale=1.)
                period_cutoff = grid.volume_scale()**(1. /
                                                      grid.dimensions) / 2.

                momentum_potential = plane_wave_potential(
                    grid,
                    spinless=spinless,
                    e_cutoff=None,
                    non_periodic=True,
                    period_cutoff=period_cutoff,
                    fieldlines=dim[1])
                position_potential = dual_basis_potential(
                    grid,
                    spinless=spinless,
                    non_periodic=True,
                    period_cutoff=period_cutoff,
                    fieldlines=dim[1])

                # Confirm they are Hermitian
                momentum_potential_operator = (
                    get_sparse_operator(momentum_potential))
                self.assertTrue(is_hermitian(momentum_potential_operator))

                position_potential_operator = (
                    get_sparse_operator(position_potential))
                self.assertTrue(is_hermitian(position_potential_operator))

                # Diagonalize and confirm the same energy.
                jw_momentum = jordan_wigner(momentum_potential)
                jw_position = jordan_wigner(position_potential)
                momentum_spectrum = eigenspectrum(jw_momentum)
                position_spectrum = eigenspectrum(jw_position)

                # Confirm spectra are the same.
                difference = numpy.amax(
                    numpy.absolute(momentum_spectrum - position_spectrum))
                self.assertAlmostEqual(difference, 0.)
Exemplo n.º 14
0
def test_circuit_generation_and_accuracy():
    for dim in range(2, 10):
        qubits = cirq.LineQubit.range(dim)
        u_generator = numpy.random.random(
            (dim, dim)) + 1j * numpy.random.random((dim, dim))
        u_generator = u_generator - numpy.conj(u_generator).T
        assert numpy.allclose(-1 * u_generator, numpy.conj(u_generator).T)

        unitary = scipy.linalg.expm(u_generator)
        circuit = cirq.Circuit()
        circuit.append(optimal_givens_decomposition(qubits, unitary))

        fermion_generator = QubitOperator(()) * 0.0
        for i, j in product(range(dim), repeat=2):
            fermion_generator += jordan_wigner(
                FermionOperator(((i, 1), (j, 0)), u_generator[i, j]))

        true_unitary = scipy.linalg.expm(
            get_sparse_operator(fermion_generator).toarray())
        assert numpy.allclose(true_unitary.conj().T.dot(true_unitary),
                              numpy.eye(2 ** dim, dtype=complex))

        test_unitary = cirq.unitary(circuit)
        assert numpy.isclose(
            abs(numpy.trace(true_unitary.conj().T.dot(test_unitary))), 2 ** dim)
    def test_ground_state_particle_nonconserving(self):
        """Test getting the ground state preparation circuit for a Hamiltonian
        that does not conserve particle number."""
        for n_qubits in self.n_qubits_range:
            # Initialize a particle-number-conserving Hamiltonian
            quadratic_hamiltonian = random_quadratic_hamiltonian(
                n_qubits, False, True)

            # Compute the true ground state
            sparse_operator = get_sparse_operator(quadratic_hamiltonian)
            ground_energy, _ = get_ground_state(sparse_operator)

            # Obtain the circuit
            circuit_description, start_orbitals = (
                gaussian_state_preparation_circuit(quadratic_hamiltonian))

            # Initialize the starting state
            state = jw_configuration_state(start_orbitals, n_qubits)

            # Apply the circuit
            particle_hole_transformation = (
                jw_sparse_particle_hole_transformation_last_mode(n_qubits))
            for parallel_ops in circuit_description:
                for op in parallel_ops:
                    if op == 'pht':
                        state = particle_hole_transformation.dot(state)
                    else:
                        i, j, theta, phi = op
                        state = jw_sparse_givens_rotation(
                            i, j, theta, phi, n_qubits).dot(state)

            # Check that the state obtained using the circuit is a ground state
            difference = sparse_operator * state - ground_energy * state
            discrepancy = numpy.amax(numpy.abs(difference))
            self.assertAlmostEqual(discrepancy, 0)
Exemplo n.º 16
0
    def test_excited_state_particle_nonconserving(self):
        """Test getting an excited state of a Hamiltonian that conserves
        particle number."""
        for n_qubits in self.n_qubits_range:
            # Initialize a non-particle-number-conserving Hamiltonian
            quadratic_hamiltonian = random_quadratic_hamiltonian(
                n_qubits, False)

            # Pick some orbitals to occupy
            num_occupied_orbitals = numpy.random.randint(1, n_qubits + 1)
            occupied_orbitals = numpy.random.choice(
                range(n_qubits), num_occupied_orbitals, False)

            # Compute the Gaussian state
            circuit_energy, gaussian_state = jw_get_gaussian_state(
                quadratic_hamiltonian, occupied_orbitals)

            # Compute the true energy
            orbital_energies, constant = (
                quadratic_hamiltonian.orbital_energies())
            energy = numpy.sum(orbital_energies[occupied_orbitals]) + constant

            # Check that the energies match
            self.assertAlmostEqual(energy, circuit_energy)

            # Check that the state obtained using the circuit is an eigenstate
            # with the correct eigenvalue
            sparse_operator = get_sparse_operator(quadratic_hamiltonian)
            difference = (sparse_operator * gaussian_state -
                          energy * gaussian_state)
            discrepancy = 0.
            if difference.nnz:
                discrepancy = max(abs(difference.data))

            self.assertTrue(discrepancy < EQ_TOLERANCE)
Exemplo n.º 17
0
 def __init__(self,
              L: int,
              J: float,
              B: float,
              sparse=False,
              qubits: Sequence[cirq.Qid] = None):
     ''' TODO: TFIMChain.__init__ documentation '''
     self.L = L
     self.J = J
     self.B = B
     if L <= 2 and sparse:
         print(f'! sparse encoding unavailable for {L} qubit system.\n'
               '! setting self.sparse = False.')
         sparse = False
     ground_state_degeneracy = 2 if J > B else 1
     if qubits is None:
         qubits = [cirq.LineQubit(i) for i in range(L)]
     else:
         qubits = qubits
     self.qubit_ham = ops.QubitOperator('X0', -B)
     for i in range(L - 1):
         self.qubit_ham += ops.QubitOperator(f'X{i+1}', -B)
         self.qubit_ham += ops.QubitOperator(f'Z{i} Z{i+1}', -J)
     sparse_ham = transforms.get_sparse_operator(self.qubit_ham)
     super().__init__(sparse_ham, qubits, ground_state_degeneracy, sparse)
Exemplo n.º 18
0
def expectation(qubit_op, wavefunction, reverse_operator=True):
    """Get the expectation value of a qubit operator with respect to a wavefunction.
	Args:
		qubit_op (openfermion.ops.QubitOperator): the operator
		wavefunction (pyquil.wavefunction.Wavefunction): the wavefunction
		reverse_operator (boolean): whether to reverse order of qubit operator
			before computing expectation value. This should be True if the convention
			of the basis states used for the wavefunction is the opposite of the one in
			the qubit operator. This is the case, e.g. when the wavefunction comes from
			Pyquil.
	Returns:
		complex: the expectation value
	"""
    n_qubits = wavefunction.amplitudes.shape[0].bit_length() - 1

    # Convert the qubit operator to a sparse matrix. Note that the qubit indices
    # must be reversed because OpenFermion and pyquil use different conventions
    # for how to order the computational basis states!
    if reverse_operator:
        qubit_op = reverse_qubit_order(qubit_op, n_qubits=n_qubits)
    sparse_op = get_sparse_operator(qubit_op, n_qubits=n_qubits)

    # Computer the expectation value
    exp_val = openfermion_expectation(sparse_op, wavefunction.amplitudes)
    return exp_val
Exemplo n.º 19
0
def eigenspectrum(operator, n_qubits=None):
    """Compute the eigenspectrum of an operator.

    WARNING: This function has cubic runtime in dimension of
        Hilbert space operator, which might be exponential.

    NOTE: This function does not currently support
        QuadOperator and BosonOperator.

    Args:
        operator: QubitOperator, InteractionOperator, FermionOperator,
            PolynomialTensor, or InteractionRDM.
        n_qubits (int): number of qubits/modes in operator. if None, will
            be counted.

    Returns:
        spectrum: dense numpy array of floats giving eigenspectrum.
    """
    if isinstance(operator, (QuadOperator, BosonOperator)):
        raise TypeError('Operator of invalid type.')
    from openfermion.transforms import get_sparse_operator
    from openfermion.utils import sparse_eigenspectrum
    sparse_operator = get_sparse_operator(operator, n_qubits)
    spectrum = sparse_eigenspectrum(sparse_operator)
    return spectrum
Exemplo n.º 20
0
    def test_simulate_overlapping_number_and_hopping_terms(self):
        hamiltonian = (0.37 * FermionOperator('1^ 0^ 1 0') +
                       FermionOperator('2^ 0') + FermionOperator('0^ 2'))

        projectq.ops.All(projectq.ops.H) | self.register

        _low_depth_trotter_simulation.simulate_dual_basis_evolution(
            self.register, hamiltonian, trotter_steps=2, first_order=False)

        self.engine.flush()

        # get_sparse_operator reverses the indices, so reverse the sites
        # the Hamiltonian acts on so as to compare them.
        reversed_operator = (0.37 * FermionOperator('3^ 2^ 3 2') +
                             FermionOperator('3^ 1') + FermionOperator('1^ 3'))
        evol_matrix = expm(-1j * get_sparse_operator(
            reversed_operator, n_qubits=self.size)).todense()
        expected = evol_matrix * numpy.matrix(
            [2**(-self.size / 2.)] * 2**self.size).T

        self.assertTrue(
            numpy.allclose(ordered_wavefunction(self.engine),
                           expected.T,
                           atol=1e-2),
            msg=str(
                numpy.array(ordered_wavefunction(self.engine) - expected.T)))
Exemplo n.º 21
0
    def test_hf_state_plane_wave_basis_lowest_single_determinant_state(self):
        grid_length = 7
        dimension = 1
        spinless = True
        n_particles = 4
        length_scale = 2.0

        grid = Grid(dimension, grid_length, length_scale)
        hamiltonian = jellium_model(grid, spinless)
        hamiltonian_sparse = get_sparse_operator(hamiltonian)

        hf_state = hartree_fock_state_jellium(grid,
                                              n_particles,
                                              spinless,
                                              plane_wave=True)

        HF_energy = expectation(hamiltonian_sparse, hf_state)

        for occupied_orbitals in permutations([1] * n_particles + [0] *
                                              (grid_length - n_particles)):
            state_index = numpy.sum(2**numpy.array(occupied_orbitals))
            HF_competitor = numpy.zeros(2**grid_length)
            HF_competitor[state_index] = 1.0

            self.assertLessEqual(
                HF_energy, expectation(hamiltonian_sparse, HF_competitor))
Exemplo n.º 22
0
    def test_simulate_dual_basis_hamiltonian(self):
        hamiltonian = dual_basis_hamiltonian(1, self.size)
        self.engine.flush()

        # Choose random state.
        initial_state = numpy.zeros(2**self.size, dtype=complex)
        for i in range(len(initial_state)):
            initial_state[i] = (random.random() *
                                numpy.exp(1j * 2 * numpy.pi * random.random()))
        initial_state /= numpy.linalg.norm(initial_state)

        # Put randomly chosen state in the registers.
        self.engine.backend.set_wavefunction(initial_state, self.register)

        _low_depth_trotter_simulation.simulate_dual_basis_evolution(
            self.register, hamiltonian, trotter_steps=7, first_order=False)

        self.engine.flush()

        # get_sparse_operator reverses the indices, but the jellium
        # Hamiltonian is symmetric.
        evol_matrix = expm(
            -1j *
            get_sparse_operator(hamiltonian, n_qubits=self.size)).todense()
        initial_state = numpy.matrix(initial_state).T
        expected = evol_matrix * initial_state

        self.assertTrue(
            numpy.allclose(ordered_wavefunction(self.engine),
                           expected.T,
                           atol=1e-2),
            msg=str(
                numpy.array(ordered_wavefunction(self.engine) - expected.T)))
Exemplo n.º 23
0
def test_circuit_generation_state():
    """
    Determine if we rotate the Hartree-Fock state correctly
    """
    simulator = cirq.Simulator()
    circuit = cirq.Circuit()
    qubits = cirq.LineQubit.range(4)
    circuit.append([cirq.X(qubits[0]), cirq.X(qubits[1]), cirq.X(qubits[1]),
                    cirq.X(qubits[2]), cirq.X(qubits[3]),
                    cirq.X(qubits[3])])  # alpha-spins are first then beta spins

    wavefunction = numpy.zeros((2 ** 4, 1), dtype=complex)
    wavefunction[10, 0] = 1.0

    dim = 2
    u_generator = numpy.random.random((dim, dim)) + 1j * numpy.random.random(
        (dim, dim))
    u_generator = u_generator - numpy.conj(u_generator).T
    unitary = scipy.linalg.expm(u_generator)

    circuit.append(optimal_givens_decomposition(qubits[:2], unitary))

    fermion_generator = QubitOperator(()) * 0.0
    for i, j in product(range(dim), repeat=2):
        fermion_generator += jordan_wigner(
            FermionOperator(((i, 1), (j, 0)), u_generator[i, j]))

    test_unitary = scipy.linalg.expm(
        get_sparse_operator(fermion_generator, 4).toarray())
    test_final_state = test_unitary.dot(wavefunction)
    cirq_wf = simulator.simulate(circuit).final_state
    assert numpy.allclose(cirq_wf, test_final_state.flatten())
def _test_mat_to_op(hamiltonian_operator, jmin=0.5, jmax=100, tol=1e-8):
    """
    Tests that eigs computed using a function that generates hamiltonian
    operators are correct. This test doesn't check for extra eigs but
    only that the ones that should be there is there.
    @author: kajoel
    """
    from core.lipkin_quasi_spin import hamiltonian, eigs
    from openfermion.transforms import get_sparse_operator

    no_error = True
    for j2 in range(round(2 * jmin), round(2 * jmax) + 1):
        j = j2 / 2
        print("j = " + str(j))
        V = float(np.random.randn(1))
        H = hamiltonian(j, V)
        E = eigs(j, V)
        for i in range(len(H)):
            H_op = hamiltonian_operator(H[i])
            H_op = get_sparse_operator(H_op).toarray()
            E_op = np.linalg.eigvals(H_op)
            # Check that E_op contains all eigs in E[i]
            for E_ in E[i]:
                if all(abs(E_op - E_) > tol):
                    no_error = False
                    print("Max diff: " + str(max(abs(E_op - E_))))

    if no_error:
        print("Success!")
    else:
        print("Fail!")
Exemplo n.º 25
0
    def test_ground_state_particle_nonconserving(self):
        """Test getting the ground state of a Hamiltonian that does not
        conserve particle number."""
        for n_qubits in self.n_qubits_range:
            # Initialize a non-particle-number-conserving Hamiltonian
            quadratic_hamiltonian = random_quadratic_hamiltonian(
                n_qubits, False)

            # Compute the true ground state
            sparse_operator = get_sparse_operator(quadratic_hamiltonian)
            ground_energy, ground_state = get_ground_state(sparse_operator)

            # Compute the ground state using the circuit
            circuit_energy, circuit_state = (
                jw_get_gaussian_state(quadratic_hamiltonian))

            # Check that the energies match
            self.assertAlmostEqual(ground_energy, circuit_energy)

            # Check that the state obtained using the circuit is a ground state
            difference = (sparse_operator * circuit_state -
                          ground_energy * circuit_state)
            discrepancy = 0.
            if difference.nnz:
                discrepancy = max(abs(difference.data))

            self.assertTrue(discrepancy < EQ_TOLERANCE)
Exemplo n.º 26
0
    def test_hf_state_energy_close_to_ground_energy_at_high_density(self):
        grid_length = 8
        dimension = 1
        spinless = True
        n_particles = grid_length**dimension // 2

        # High density -> small length_scale.
        length_scale = 0.25

        grid = Grid(dimension, grid_length, length_scale)
        hamiltonian = jellium_model(grid, spinless)
        hamiltonian_sparse = get_sparse_operator(hamiltonian)

        hf_state = hartree_fock_state_jellium(grid,
                                              n_particles,
                                              spinless,
                                              plane_wave=True)

        restricted_hamiltonian = jw_number_restrict_operator(
            hamiltonian_sparse, n_particles)

        E_g = get_ground_state(restricted_hamiltonian)[0]
        E_HF_plane_wave = expectation(hamiltonian_sparse, hf_state)

        self.assertAlmostEqual(E_g, E_HF_plane_wave, places=5)
Exemplo n.º 27
0
def continuous_logsweep_protocol(init_state: np.ndarray,
                                 system: QuantumSimulatedSystem,
                                 n_energy_steps: int,
                                 mode: str = 'auto') -> np.ndarray:
    '''
    Runs the continuous-evolution QDC LogSweep protocol on the state init_state
    of a QuantumSimulatedSystem.
    For details and caveats, see `qdcnumpy.continuous_energy_sweep_protocol`.

    Couplings are XX, XY, XZ on each of the system's qubits in sequence.
    Energies and linewidths are chosen according to:
        epsilon[0] == e_max
        epsilon[n_energy_steps] == e_min
        epsilon[k] - epsilon[k+1] == (delta[k] + delta[k+1]) / delta_factor
    Where delta_factor is optimized as indicated in appendix B of the paper.

    Args:
        init_state: density matrix, state vector or matrix of state
            coulumn-vectors of the initial state.
        system: object containing Hamiltonian and simulation data.
        n_energy_steps: energy gradation number K.
        mode: Whether to use density matrix or wavefunction simulation. If set
            to 'auto' (default), the choice will be made depending on the input
            type (square matrix -> 'DM', vector or rectangular matrix -> 'WF')

    Returns:
        state (density matrix) after the application of the protocol

    Raises:
        ValueError: if the input state has the wrong form for the mode,
            or if the input system is sparse-encoded
        TypeError: if the input state is not a np.ndarray
    '''
    L = len(system.get_qubits())
    coupl_potentials = [
        transforms.get_sparse_operator(ops.QubitOperator((i, P), ), n_qubits=L)
        for i in range(L) for P in ('X', 'Y', 'Z')
    ]
    e_max_transitions = max(
        perp_norm(cp, system.get_sparse_hamiltonian())
        for cp in coupl_potentials)
    system.eig()

    #  define e_min, e_max using perp_norm on sparse matrices
    e_min = system.ground_state_gap()
    e_max = e_max_transitions

    # define delta_factor
    delta_factor = opt_delta_factor(e_min, e_max, n_energy_steps)

    epsilon_list, delta_list = logsweep_params(e_min, e_max, n_energy_steps,
                                               delta_factor)

    return continuous_energy_sweep_protocol(init_state=init_state,
                                            system=system,
                                            couplings=['X', 'Y', 'Z'],
                                            epsilon_list=epsilon_list,
                                            delta_list=delta_list,
                                            mode=mode)
Exemplo n.º 28
0
def generator(x: List[float]):
    # Must provide imports in the function!
    from scipy.sparse.linalg import expm
    from openfermion.ops import QubitOperator
    from openfermion.transforms import get_sparse_operator
    qop = QubitOperator('X0 Y1') - QubitOperator('Y0 X1')
    qubit_sparse = get_sparse_operator(qop)
    return expm(0.5j * x[0] * qubit_sparse).todense()
Exemplo n.º 29
0
    def test_plane_wave_hamiltonian_integration(self):
        '''
        Key: Spatial dimension.
        Value: List of geometries.
        '''
        geometry_sets = {
                    2: [[('H', (0., 0.)), ('H', (0.8, 0.))], 
                        [('H', (0.1, 0.))]], 
                    3: [[('H', (0., 0., 0.)), ('H', (0.8, 0., 0.))], 
                        [('H', (0.1, 0., 0.))]]
                  }
        
        # [[spatial dimension, fieldline dimension]]
        dims = [[2, 2], [2, 3], [3, 3]]
        length_scale = 1.1
        spinless = True

        for dim in dims:
            
            # If dim[0] == 2, get range(2, 4).
            # If dim[0] == 3, get range(2, 3).
            for length in range(2, 6 - dim[0]):
                for geometry in geometry_sets[dim[0]]:
                    grid = Grid(dimensions=dim[0], scale=length_scale, length=2)
                    h_plane_wave = plane_wave_hamiltonian(
                        grid, geometry, spinless, True, include_constant=False, fieldlines=dim[1])
                    h_dual_basis = plane_wave_hamiltonian(
                        grid, geometry, spinless, False, include_constant=False, fieldlines=dim[1])

                    # Test for Hermiticity
                    plane_wave_operator = get_sparse_operator(h_plane_wave)
                    dual_operator = get_sparse_operator(h_dual_basis)
                    self.assertTrue(is_hermitian((plane_wave_operator)))
                    self.assertTrue(is_hermitian(dual_operator))

                    jw_h_plane_wave = jordan_wigner(h_plane_wave)
                    jw_h_dual_basis = jordan_wigner(h_dual_basis)
                    h_plane_wave_spectrum = eigenspectrum(jw_h_plane_wave)
                    h_dual_basis_spectrum = eigenspectrum(jw_h_dual_basis)

                    max_diff = numpy.amax(
                        h_plane_wave_spectrum - h_dual_basis_spectrum)
                    min_diff = numpy.amin(
                        h_plane_wave_spectrum - h_dual_basis_spectrum)
                    self.assertAlmostEqual(max_diff, 0)
                    self.assertAlmostEqual(min_diff, 0)
Exemplo n.º 30
0
    def test_get_ground_states_by_particle_number_nonhermitian(self):
        # Initialize a non-Hermitian operator
        ferm_op = FermionOperator('0^ 1') + FermionOperator('2^ 1')
        jw_hamiltonian = jordan_wigner(ferm_op)
        sparse_operator = get_sparse_operator(jw_hamiltonian)

        with self.assertRaises(ValueError):
            jw_get_ground_states_by_particle_number(sparse_operator, 0)