Closed jason-jk-kang closed 3 years ago
Could you post an example code?
If you specify your commandprinter
as part of the engine_list
parameter of the MainEngine
in your program, the commands should be transferred automatically to the next one (which would be in your case the IBM backend)
For example, in this block of code, I am computing the expectation value of a hamiltonian using ProjectQ's simulator. I would like to use IBM's simulator, or IBM's machine. However, if I simply replace the compiler_engine (line 82) with uccsd_trotter_engine(ibm_backend()) then it will not work.
Thank you.
import os
from numpy import array, concatenate, zeros
from numpy.random import randn
from scipy.optimize import minimize
from openfermion.config import *
from openfermionprojectq import *
from openfermion.hamiltonians import MolecularData
from openfermion.transforms import jordan_wigner, get_fermion_operator, get_sparse_operator
from openfermion.utils import uccsd_singlet_paramsize
from projectq.ops import X, All, Measure
from projectq.backends import CommandPrinter, CircuitDrawer, IBMBackend
from pyscf import mp, fci
from openfermionpyscf import run_pyscf
def energy_objective(packed_amplitudes):
Evaluate the energy of a UCCSD singlet wavefunction with packed_amplitudes
Args:
packed_amplitudes(ndarray): Compact array that stores the unique
amplitudes for a UCCSD singlet wavefunction.
Returns:
energy(float): Energy corresponding to the given amplitudes
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"
# Set Jordan-Wigner initial state with correct number of electrons
wavefunction = compiler_engine.allocate_qureg(molecule.n_qubits)
for i in range(molecule.n_electrons):
X | wavefunction[i]
# Build the circuit and act it on the wavefunction
evolution_operator = uccsd_singlet_evolution(packed_amplitudes,
molecule.n_qubits,
molecule.n_electrons)
evolution_operator | wavefunction
compiler_engine.flush()
# Evaluate the energy and reset wavefunction
energy = compiler_engine.backend.get_expectation_value(qubit_hamiltonian, wavefunction)
All(Measure) | wavefunction
compiler_engine.flush()
return energy
# Load saved file for H3.
basis = 'sto-3g'
spin = 2
# Set calculation parameters.
run_scf = 1
run_mp2 = 1
run_cisd = 0
run_ccsd = 0
run_fci = 1
delete_input = True
delete_output = True
# Set Hamiltonian parameters.
active_space_start = 1
active_space_stop = 3
geometry = [('H', (0., 0., 0.)), ('H', (0., 0., 0.7414)), ('H', (0., 0., 3.3))]
# Generate and populate instance of MolecularData.
molecule = MolecularData(geometry, basis, spin, description="h3")
molecule = run_pyscf(molecule,
run_scf=run_scf,
run_mp2=run_mp2,
run_cisd=run_cisd,
run_ccsd=run_ccsd,
run_fci=run_fci)
# Use a Jordan-Wigner encoding, and compress to remove 0 imaginary components
molecular_hamiltonian = molecule.get_molecular_hamiltonian(
occupied_indices=range(active_space_start),
active_indices=range(active_space_start, active_space_stop))
fermion_hamiltonian = get_fermion_operator(molecular_hamiltonian)
qubit_hamiltonian = jordan_wigner(fermion_hamiltonian)
qubit_hamiltonian.compress()
compiler_engine = uccsd_trotter_engine()
n_amplitudes = uccsd_singlet_paramsize(molecule.n_qubits, molecule.n_electrons)
initial_amplitudes = [0.01] * n_amplitudes
initial_energy = energy_objective(initial_amplitudes)
# Run VQE Optimization to find new CCSD parameters
opt_result = minimize(energy_objective, initial_amplitudes,
method="CG", options={'disp':True})
opt_energy, opt_amplitudes = opt_result.fun, opt_result.x
print("\n Results for {}:".format(molecule.name))
print("Optimal UCCSD Singlet Energy: {}".format(opt_energy))
print("Optimal UCCSD Singlet Amplitudes: {}".format(opt_amplitudes))
print("Classical CCSD Energy: {} Hartrees".format(molecule.ccsd_energy))
print("Exact FCI Energy: {} Hartrees".format(molecule.fci_energy))
print("Initial Energy of UCCSD with CCSD amplitudes: {} Hartrees".format(initial_energy))
compiler_engine = uccsd_trotter_engine(CommandPrinter())
wavefunction = compiler_engine.allocate_qureg(molecule.n_qubits)
for i in range(molecule.n_electrons):
X | wavefunction[i]
# Build the circuit and act it on the wavefunction
evolution_operator = uccsd_singlet_evolution(opt_amplitudes,
molecule.n_qubits,
molecule.n_electrons)
evolution_operator | wavefunction
compiler_engine.flush()
`
Sorry I missed following through with this issue.
Actually, the uccsd_trotter_engine
function does not allow you to add arbitrary compiler engines in the engine list passed to the MainEngine
constructor.
What you could do is use the insert_engine
function from the projectq.meta
module:
backend = IBMBackend()
compiler_engine = uccsd_trotter_engine(backend)
cmd_printer = CommandPrinter()
insert_engine(backend, cmd_printer)
Thank you for following up! However, now when I run it by specifying the backend as such, I receive the error
File "/home/jasonkang/anaconda3/lib/python3.7/site-packages/projectq/cengines/_main.py", line 286, in send "\n" + repr(last_line[-2])) TypeError: __init__() missing 2 required positional arguments: 'doc' and 'pos'
Are you sure ProjectQ's uccsd_trotter_engine is still compatible with the IBM backend?
Bumping - any help is appreciated!
The way ProjectQ communicates with the IBM quantum experience indeed needs to be patched.
We will probably need to use the qiskit-ibmq-provider
Python module which will require that people install at least qiskit-terra
(and some other dependencies) to make it work.
I will try to get something out soon, although I cannot make any promises right now. If you are willing to help fix this issue, I am more than happy to help you along the way though.
The issues with the Qiskit QE API should be fixed in the latest version. Re-open this issue if that is not the case.
Hi,
I am wondering how it may be possible to pass commands between engines. I have a commandprinter() and I want to interface it with an IBM Backend. The documentation indicates that IBM Backend can receive commands, but how do I access the command list that is printed previously by commandprinter()? Thank you.