tequilahub / tequila

A High-Level Abstraction Framework for Quantum Algorithms
MIT License
362 stars 101 forks source link

PyZX with parameterized circuits? #218

Closed jjgoings closed 2 years ago

jjgoings commented 2 years ago

I was following along with the PyZX+Tequila tutorial here, and saw that some extra care must be utilized when working with parameterized circuits. I was wondering if it is possible to use a PyZX optimized circuit for a parameterized objective function. For example, I am trying VQE with hydrogen:

import tequila as tq
import pyzx as zx

# Define molecule
geomstring="H 0.0 0.0 0.0\n H 0.0 0.0 0.74"
mol = tq.Molecule(geometry=geomstring, backend='pyscf', basis_set='sto3g')

# get the qubit hamiltonian
H = mol.make_hamiltonian()

# get the ansatz (circuit)
U = mol.make_ansatz(name='UCCSD')

# extract variables to use PyZX
variables=U.extract_variables()
M = {variables[i]:float(i) for i in range(len(variables))}

# do circuit optimization with PyZX
c = tq.convert_to_pyzx(U, variables=M)
print(c.stats())
c = c.to_basic_gates()
g = c.to_graph()
zx.full_reduce(g, quiet=False)
g.normalize() # Makes the graph more suitable for displaying
c_optimized = zx.extract_circuit(g.copy())
print(c_optimized.stats())

U_opt = tq.convert_from_pyzx(c_optimized)

# define the expectation value
E = tq.ExpectationValue(H=H, U=U_opt)

# minimize the expectation value
result = tq.minimize(E)

however, this dies when I get to the optimization, e.g.

Traceback (most recent call last):
  File "test.py", line 34, in <module>
    result = tq.minimize(E)
  File "/X/miniconda3/lib/python3.8/site-packages/tequila/optimizers/__init__.py", line 133, in minimize
    return v.minimize(
  File "/X/miniconda3/lib/python3.8/site-packages/tequila/optimizers/optimizer_scipy.py", line 426, in minimize
    return optimizer(objective=objective,
  File "/X/miniconda3/lib/python3.8/site-packages/tequila/optimizers/optimizer_scipy.py", line 149, in __call__
    param_keys, param_values = zip(*active_angles.items())
ValueError: not enough values to unpack (expected 2, got 0)

I have a feeling this is because the new Tequila circuit no longer contains information about the variables/parameters, so it's uncertain what to optimize. It might also be that PyZX simply cannot handle parameterized circuit optimization if it is working with gates that have fixed values.

So anyway, if I'd like to use PyZX to optimize parameterized circuits that I can use with Tequila, what is the best way forward?

kottmanj commented 2 years ago

Hi Joshua.

The problem is, as you already guessed, the same as for the QASM2 translation (tequila support for both was actually implemented within the same project). PyZX and QASM2 are not supporting parametrized (with variables) gates - they might now, but back then it wasn't possible. We still enabled the translation of tequila circuits to PyZX for analysis purposes (but we can not reimport with variables at this time).

What happens is: c = tq.convert_to_pyzx(U, variables=M) -> here the circuit is translated but all variables are fixed to the values given in M so if you re-import it later with U_opt = tq.convert_from_pyzx(c_optimized) you get a circuit that has no variables (therefore the tequila optimizer can not optimize anything). Replacing variables with "unique" floats lie "1.2345001", "1.2345002" etc was not an option since pyzx might change angles (or multiply by pi) as far as I remember. So it was too dangerous to add that as a default solution to the package, but you might utilize this manually.

However: If you are simulating with qulacs, the circuit optimization will not speed-up your simulation (probably even will make it slower due to optimization overhead). So currently we optimize variables with the non-pyzx-optimized circuits and use pyzx just for circuit analysis.

kottmanj commented 2 years ago

okay, I just tried my suggestion, would not advice it. PyZX changes too much (e.g. the Rx rotations that are the basis-changes for the Y terms in the generator strings are translated into ...Rz.... which makes really hard to figure out which Rz should carry variables after the optimization).

The only way moving forward here (as far as I see) is too wait untill PyZX supports variables.

If you still want to use PyZX for analysis, I noticed one thing in your M: The first variable is set to "0" which will cause PyZX to remove that gate entirely. Would suggest to optimize the plain tequila circuit U first, and then use the optimized variables M=result.variables to translate to PyZX and figure out, how short your circuit could have been.

jjgoings commented 2 years ago

Thanks, that's really helpful, even if it's not ideal. I agree, I tried using pyzx on a small parameterized circuit with "fixed" variables, and I wasn't even sure the result was correct, and it looked nothing like my hand-optimized circuit.