diff --git a/requirements/requirements-extra.txt b/requirements/requirements-extra.txt index 63e1f992..f1997ff8 100644 --- a/requirements/requirements-extra.txt +++ b/requirements/requirements-extra.txt @@ -1,6 +1,6 @@ # extra dependencies for ci -qiskit<1.0 -qiskit-aer<1.0 +qiskit +qiskit-aer qiskit-nature mitiq cirq diff --git a/setup.py b/setup.py index 8e176a49..1208cae5 100644 --- a/setup.py +++ b/setup.py @@ -22,8 +22,8 @@ "tensorflow": ["tensorflow<2.16"], "jax": ["jax", "jaxlib"], "torch": ["torch"], - "qiskit": ["qiskit<1.0"], - "cloud": ["qiskit<1.0", "mthree"], + "qiskit": ["qiskit"], + "cloud": ["qiskit", "mthree"], }, classifiers=[ "Programming Language :: Python :: 3", diff --git a/tensorcircuit/translation.py b/tensorcircuit/translation.py index bc827ac8..820ed521 100644 --- a/tensorcircuit/translation.py +++ b/tensorcircuit/translation.py @@ -356,10 +356,11 @@ def qir2qiskit( def _translate_qiskit_params( - gate_info: CircuitInstruction, binding_params: Any + gate_info: Any, binding_params: Any ) -> List[float]: parameters = [] - for p in gate_info.operation.params: + operation = gate_info.operation if hasattr(gate_info, "operation") else gate_info[0] + for p in operation.params: if isinstance(p, ParameterVectorElement): parameters.append(binding_params[p.index]) elif isinstance(p, Parameter): @@ -468,8 +469,10 @@ def qiskit2tc( tc_circuit: Any = Circ(**circuit_params) for gate_info in qc.data: - idx = [qc.find_bit(qb).index for qb in gate_info.qubits] - gate_name = gate_info[0].name + qubits = gate_info.qubits if hasattr(gate_info, "qubits") else gate_info[1] + idx = [qb.index if hasattr(qb, "index") else qc.find_bit(qb).index for qb in qubits] + operation = gate_info.operation if hasattr(gate_info, "operation") else gate_info[0] + gate_name = operation.name parameters = _translate_qiskit_params(gate_info, binding_params) if gate_name in [ "h", @@ -536,14 +539,14 @@ def qiskit2tc( if (gate_name[-i] == "o") & (gate_name[-i - 1] == "_"): break if i == len(gate_name) - 1: - base_gate = gate_info[0].base_gate + base_gate = operation.base_gate ctrl_state = [1] * base_gate.num_qubits idx = idx[: -base_gate.num_qubits] + idx[-base_gate.num_qubits :][::-1] tc_circuit.multicontrol( *idx, ctrl=ctrl_state, unitary=base_gate.to_matrix() ) else: - base_gate = gate_info[0].base_gate + base_gate = operation.base_gate ctrl_state = ctrl_str2ctrl_state( gate_name[-i + 1 :], len(idx) - base_gate.num_qubits ) @@ -566,11 +569,11 @@ def qiskit2tc( elif gate_name == "initialize": # already taken care of when initializing continue - elif not hasattr(gate_info[0], "__array__"): + elif not hasattr(operation, "__array__"): # an instruction containing a lot of gates. # the condition is based on # https://github.com/Qiskit/qiskit-terra/blob/2f5944d60140ceb6e30d5b891e8ffec735247ce9/qiskit/circuit/gate.py#L43 - qiskit_circuit = gate_info[0].definition + qiskit_circuit = operation.definition if qiskit_circuit is None: logger.warning( f"qiskit to tc translation doesn't support {gate_name} instruction, skipping" @@ -580,7 +583,7 @@ def qiskit2tc( tc_circuit.append(c, idx) else: # unitary gate idx_inverse = (x for x in idx[::-1]) - tc_circuit.any(*idx_inverse, unitary=gate_info[0].to_matrix()) + tc_circuit.any(*idx_inverse, unitary=operation.to_matrix()) return tc_circuit diff --git a/tests/test_circuit.py b/tests/test_circuit.py index 81f20762..2387f639 100644 --- a/tests/test_circuit.py +++ b/tests/test_circuit.py @@ -1653,3 +1653,15 @@ def test_circuit_copy(backend): c1 = c.copy() c.rz(0, theta=0.1) assert c1.gate_count() == 1 + +def test_qiskit_circuitinstruction_conversion(): + c = tc.Circuit(2) + c.x(0) + c.cx(0, 1) + q_circuit = c.to_qiskit() + + # This should succeed without raising AttributeError for 'index' or 'qubits' + c_ = tc.Circuit.from_qiskit(q_circuit) + + # Verify the circuits are equivalent + np.testing.assert_allclose(c.state(), c_.state(), atol=1e-8)