Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem extracting Statevector when using a binded parametric controlled gate #7410

Closed
edaruizgu opened this issue Dec 14, 2021 · 3 comments · Fixed by #11032
Closed

Problem extracting Statevector when using a binded parametric controlled gate #7410

edaruizgu opened this issue Dec 14, 2021 · 3 comments · Fixed by #11032
Labels
bug Something isn't working

Comments

@edaruizgu
Copy link

edaruizgu commented Dec 14, 2021

Environment

  • Qiskit Terra version:
    'qiskit-terra': '0.19.1'
    'qiskit': '0.33.1'
  • Python version:
    3.9.7
  • Operating system:
    Windows 10 Pro

What is happening?

I'm trying to implement a Parametric Hadamard Test.

I have already my parametric evolution gate exp(−iθH) where θ is the parameter.

When I defined the controlled-gate with Gate.control(1) and add it to the main circuit. I'm unable to correctly bind the parameters after and I can not get the state vector after the binded circuit.

How can we reproduce the issue?

thetas = ParameterVector('T', length=1)
it = iter(theta)

# Define Hadamard Test
qc = QuantumCircuit(3)
qc.initialize(psi_0, [1,2])

qc.h(0)

# Apply control gate

tr_g_k = tr_g(dt=next(it))  # tr_g is the evolution gate $\exp(-i\theta H)$
tr_g_c = tr_g_k.control(1)

qc.append(tr_g_c, [0,1,2])

qc.h(0)
# --------------------------------------------------------
# Get the StateVector

qc_b = qc.bind_parameters({theta: [np.pi]})

simulator = Aer.get_backend('aer_simulator')

qc_bt = transpile(qc_b, simulator)

qc_bt.save_statevector()

result = simulator.run(qc_bt).result()
statevector = result.get_statevector(qc_bt)

When running the circuit I get:

TypeError: ParameterExpression with unbound parameters ({ParameterVectorElement(T[0])}) cannot be cast to a float.

I have tried without the control, i.e, only the evolution in the qubit 1 and 2 and it works. I think it's because the control, but so far, I have not been able to solve it.

I tried .with the to_matrix() method of CircuitStateFn of Opflow, and I get the same error.

What should happen?

The circuit should bind the parameres correctly and it should give me the statevector at the end.

Any suggestions?

No response

@edaruizgu edaruizgu added the bug Something isn't working label Dec 14, 2021
@jakelishman
Copy link
Member

Please can you provide a complete reproducible example, including all imports and custom functions, which we can run to reproduce the error? Ideally this should be as little code as you're able to get it to. I can't run your example because of the missing tr_g function - I tried to make something like your description, but this doesn't have any errors:

import qiskit
from qiskit.circuit import ParameterVector, QuantumCircuit
from qiskit.circuit.library import PauliEvolutionGate
from qiskit.quantum_info import Pauli

t = ParameterVector("t", 1)[0]
evolution_gate = PauliEvolutionGate(Pauli("X"), t)

qc = QuantumCircuit(2)
qc.append(evolution_gate.control(1), [0, 1], [])

simulator = qiskit.Aer.get_backend("aer_simulator")
transpiled = qiskit.transpile(qc.assign_parameters({t: 0.5}), simulator)
transpiled.save_statevector()
result = simulator.run(transpiled).result()

@edaruizgu
Copy link
Author

edaruizgu commented Dec 14, 2021

Thanks for the reply. Here there is a reproducible example with all the functions.

My original custom gate tr_g has crx gates. When I change them to cp gates, the problem does not appear.
( it's possible to see this if one uncomments the line #qc_c.cp(dt, 1, 0) and comment qc_c.crx(dt, 1, 0) )

The circuits qc and transpiled are printed in order to notice that when crx gates are used the parameter t does not bind.

from qiskit import Aer
from qiskit import QuantumCircuit
from qiskit import transpile
from qiskit.circuit import ParameterVector

def custom_gate(dt):
    qc_c = QuantumCircuit(2)
    qc_c.cx(0,1)
    qc_c.crx(dt, 1, 0)
    #qc_c.cp(dt, 1, 0)
    qc_c.cx(0,1)
    cg = qc_c.to_gate()
    return cg


t = ParameterVector('T', length=1)[0]
qc = QuantumCircuit(3)

cg = custom_gate(dt=t)
ccg = cg.control(1)
qc.append(ccg, [0,1,2])

print(qc)

simulator = Aer.get_backend("aer_simulator")
transpiled = transpile(qc.assign_parameters({t: 0.5}), simulator)

print(transpiled)

transpiled.save_statevector()
result = simulator.run(transpiled).result()

print(result.get_statevector())

@jakelishman
Copy link
Member

Thanks, that's great. The problem here is that the parameter binding isn't getting passed into the defined gate's definition through the control:

In [1]: from qiskit import QuantumCircuit
   ...: from qiskit.circuit import Parameter
   ...:
   ...: def custom_gate(dt):
   ...:     qc_c = QuantumCircuit(2)
   ...:     qc_c.crx(dt, 1, 0)
   ...:     return qc_c.to_gate()
   ...:
   ...: t = Parameter("t")
   ...:
   ...: qc = QuantumCircuit(3)
   ...: qc.append(custom_gate(t).control(), [0, 1, 2])
   ...: assigned = qc.assign_parameters({t: 0.5})
   ...: print(qc.draw())
   ...: print()
   ...: print(assigned.draw())
   ...: print()
   ...: print(assigned.decompose().draw())

q_0: ────────■────────
     ┌───────┴───────┐
q_1: ┤0              ├
     │  circuit-1(t) │
q_2: ┤1              ├
     └───────────────┘


q_0: ─────────■─────────
     ┌────────┴────────┐
q_1: ┤0                ├
     │  circuit-1(0.5) │
q_2: ┤1                ├
     └─────────────────┘


q_0: ─■─────────■───────────■───────────■───────────■─────────
      │P(π/2) ┌─┴─┐┌────────┴────────┐┌─┴─┐┌────────┴────────┐
q_1: ─■───────┤ X ├┤ U(-0.5*t,0,0,0) ├┤ X ├┤ U(t/2,-π/2,0,0) ├
              └─┬─┘└─────────────────┘└─┬─┘└─────────────────┘
q_2: ───────────■───────────────────────■─────────────────────

Terra typically over-relies on us storing the same instruction object in many different places, and only updating a parameter in one place to change them all. Here, I would expect that somewhere the instruction is being copied when the inner circuit definition is made, and that prevents things from working correctly. This shouldn't be too hard to fix, hopefully.

yonizim added a commit to yonizim/qiskit-terra that referenced this issue Dec 26, 2021
rrodenbusch added a commit to rrodenbusch/qiskit-terra that referenced this issue Nov 10, 2022
… global_phase gamma and

maintain base_gate, CU, parameters
Added qiskit.CUGate.__deepcopy__ to copy the CUGate parameters
Added CU3 to CU equivalence to the equivalence library
Added test case test_assign_cugate to test_parameters.TestParameters
Fixes Issue Qiskit#7410 Qiskit#7410
Fixes Issue Qiskit#7326 Qiskit#7326
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
2 participants