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

feat: handle IfElseOp in qiskit_to_tk #437

Merged
merged 50 commits into from
Jan 23, 2025
Merged

feat: handle IfElseOp in qiskit_to_tk #437

merged 50 commits into from
Jan 23, 2025

Conversation

CalMacCQ
Copy link
Contributor

@CalMacCQ CalMacCQ commented Dec 17, 2024

Description

Converting a qiskit IfElseOp as two conditional pytket CircBoxes. This sort of control flow is probably better expressed in the HUGR data structure than as a pytket Circuit/CircBox.

Theres a C.I. failure for one of the tests I added that I can't reproduce locally -> https://github.com/CQCL/pytket-qiskit/actions/runs/12811218709/job/35720030508#step:7:786

Needs more diverse test cases before merging and we also need to decide if we want to handle more complex conditions.

NOTE: For now I've restricted to conditions on a single bit but we should generalise this. This PR is already quite busy.

Looking at the qiskit docs they also have switch-case as well as for and while loops which we may want to support in the future.

https://docs.quantum.ibm.com/guides/classical-feedforward-and-control-flow

Example

# define qiskit program
qubits = QuantumRegister(2)
clbits = ClassicalRegister(2)
circuit = QuantumCircuit(qubits, clbits)
(q0, q1) = qubits
(c0, c1) = clbits

circuit.h(q0)
circuit.measure(q0, c0)

with circuit.if_test((c0, 1)) as else_:
    circuit.h(q1)
with else_:
    circuit.x(q1)
circuit.measure(q1, c1)

Now the corresponding pytket circuit looks like

tkc = qiskit_to_tk(circuit)

circuit

The If and Else boxes contain a single $H$ and $X$ gate respectively.

I thought about putting string representing the conditon inside the "If" label however this could be awkward. Hopefully its clear from the diagram whats going on.

This conversion ended up being slighly tricker than I expected because the qiskit circuits which define the true_body and false_body do not have registers. Managed to get around this by using the register from the circuit containing the IfElseOp and cleaning up empty wires with Circuit.remove_blank_wires to ensure the CircBox is of the correct size.

Related issues

closes #415

Checklist

  • I have performed a self-review of my code.
  • I have commented hard-to-understand parts of my code.
  • I have made corresponding changes to the public API documentation.
  • I have added tests that prove my fix is effective or that my feature works.
  • I have updated the changelog with any user-facing changes.

@CalMacCQ CalMacCQ requested a review from cqc-melf as a code owner December 17, 2024 14:37
@CalMacCQ CalMacCQ marked this pull request as draft December 17, 2024 14:55
@CalMacCQ
Copy link
Contributor Author

CalMacCQ commented Dec 31, 2024

The test case I added is now working after 52458ab.

I'll need to add more diverse test cases before I'm confident in merging this as well as negate the "else" condition properly and see what the story is for more complex conditions.

@CalMacCQ CalMacCQ changed the title [DRAFT] feat: handle IfElseOp in qiskit_to_tk feat: handle IfElseOp in qiskit_to_tk Dec 31, 2024
@CalMacCQ CalMacCQ added enhancement New feature or request circuit_conversion Issues and pull requests related to coverting qiskit circuits to pytket and vice versa labels Jan 1, 2025

# Coniditions must be on a single bit (for now)
assert len(if_else_op.condition) == 2
if not isinstance(if_else_op.condition[0], Clbit):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I said in the description I've restricted to the case of single bit conditions for now. However it should be easy enough to generalise for conditons on values of entire registers in a follow up PR.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we check that len(bits) == 1, or perhaps change the signature of this function to take a single Bit?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer the former suggestion as the restriction to a single bit should be removable soon

@CalMacCQ CalMacCQ marked this pull request as ready for review January 16, 2025 14:53
@CalMacCQ CalMacCQ requested a review from cqc-alec January 16, 2025 14:53
Copy link
Collaborator

@cqc-alec cqc-alec left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description says that this closes #366 , but this does not change tk_to_qiskit a all does it? Did you intend to address that direction as well?

assert tkc.n_gates_of_type(OpType.Conditional) == 2
if_cond, else_cond = tuple(tkc.commands_of_type(OpType.Conditional))

if_circ = if_cond.op.op.get_circuit()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mypy check is failing. Probably need to assert that op is a Conditional.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this was the issue. It doesn't matter anymore as I've redone the test.

circ = circ_builder.circuit()

# Coniditions must be on a single bit (for now)
assert len(if_else_op.condition) == 2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to raise an exception rather than assert -- assert is best reserved for catching internal logic errors.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I considered this. I should add an exception to do things properly.

My assumption was that the object returned from if_else_op.condition would always be of length 2 however this may not be true.

I think for conditions on multiple bits this could be longer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see cebf4dd


# Coniditions must be on a single bit (for now)
assert len(if_else_op.condition) == 2
if not isinstance(if_else_op.condition[0], Clbit):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we check that len(bits) == 1, or perhaps change the signature of this function to take a single Bit?

args=qubits,
condition_bits=bits,
# TODO: handle conditions over multiple bits/registers?
condition_value=not bool(if_else_op.condition[1]),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is if_else_op.condition[1] an int? Can we check that it is 0 or 1?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a check in cebf4dd


expected_circ.Measure(q1_tk[0], c1_tk[0])

assert tket_circ_if_else == expected_circ
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A similar test including an else condition would be good to add.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turned the two branch test into an explicit equality check in a40732d

@CalMacCQ CalMacCQ requested a review from cqc-alec January 22, 2025 17:05
@cqc-alec cqc-alec merged commit 47e842a into main Jan 23, 2025
4 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
circuit_conversion Issues and pull requests related to coverting qiskit circuits to pytket and vice versa enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support QuantumCircuit.if_test in qiskit_to_tk
4 participants