Skip to content

Optimizing MCX Gates, Preparing for Future Hardware Today

View on GitHub

This tutorial describes how to use the Classiq platform to create MCX gates, including one with 14 controls. Then, it demonstrates a much more complex example with 50 control qubits.

Quantum Resources Are Valuable, Yet Limited

Quantum computers offer tantalizing promises to those who can harness their power. And although today’s computers are not quite able to solve real-world problems, those who are able to optimize for the available hardware can reap rewards sooner than those who wait. The MCX gate is an important quantum gate used in a variety of circuits, such as the Grover operator, logical AND operator, state preparation algorithms, and arithmetic comparators. The ability to adapt implementations of MCX gates to meet the hardware constraints—limited qubit count, fidelities, gate count, and so on—is not trivial.

Creating a 14-Control MCX Gate with Classiq

To create an MCX gate with 14 control qubits using Classiq, we first define a quantum function called my_mcx whose arguments are an array of qubits (of any size) for control and a single qubit argument for the target:

from math import pi

from classiq import *
@qfunc
def my_mcx(cntrl: QArray[QBit], target: QBit) -> None:
    control(cntrl, lambda: X(target))

To create an MCX gate with 14 control qubits, we create a quantum main function that executes our my_mcx function with 14 qubits allocated to the control argument:

@qfunc
def main(cntrl: Output[QArray[QBit]], target: Output[QBit]) -> None:
    allocate(14, cntrl)
    allocate(1, target)
    my_mcx(cntrl, target)

To build our model we use the create_model function:

qmod_1 = create_model(main)

To constrain a circuit to only 20 qubits and optimize for circuit depth, we pass the maximum width and optimization parameter to a Constraints object and update our model:

MAX_WIDTH_1 = 20
qmod_1 = set_constraints(
    qmod_1,
    max_width=MAX_WIDTH_1,
    optimization_parameter=OptimizationParameter.DEPTH,
)
write_qmod(qmod_1, "mcx_14_ctrl_depth")

We can now synthesize our model, create a quantum program, and view it:

qprog_1 = synthesize(qmod_1)
show(qprog_1)
Opening: https://platform.classiq.io/circuit/2twMjpEyXaa5ITbFfaUmcF3gNw2?version=0.70.0

Additionally, to get the transpiled circuit from our qprog object and print its depth:

circuit = QuantumProgram.from_qprog(qprog_1)
print(f"Synthesized MCX depth is {circuit.transpiled_circuit.depth}")
Synthesized MCX depth is 94

Optimizing MCX for Every Occasion

Classiq automatically optimizes the quantum circuit and each MCX gate to a plethora of possible situations. To characterize each setting we pass our constraints and preferences to the synthesis request using the Constraints and Preferences objects.

For Different Hardware

MAX_WIDTH_2 = 21

qmod_2 = create_model(main)
qmod_2 = set_constraints(
    qmod_2,
    max_width=MAX_WIDTH_2,
    optimization_parameter=OptimizationParameter.DEPTH,
)
qmod_2 = set_preferences(
    qmod_2,
    backend_service_provider="IBM Quantum",
    backend_name="ibm_brisbane",
)
write_qmod(qmod_2, "mcx_14_ctrl_hardware")

qprog_2 = synthesize(qmod_2)
circuit = QuantumProgram.from_qprog(qprog_2)

print(f"Synthesized MCX depth is {circuit.transpiled_circuit.depth}")
circuit.show()
Synthesized MCX depth is 391
Opening: https://platform.classiq.io/circuit/2twMm2ILGVtcnr4Wi54O2lD6OV0?version=0.70.0

For CX Gates

MAX_WIDTH_3 = 19

qmod_3 = create_model(main)
qmod_3 = set_constraints(
    qmod_3,
    max_width=MAX_WIDTH_3,
    optimization_parameter="cx",
)
qmod_3 = set_preferences(
    qmod_3,
    custom_hardware_settings=CustomHardwareSettings(basis_gates=["cx", "u"]),
)
write_qmod(qmod_3, "mcx_14_ctrl_cx")

qprog_3 = synthesize(qmod_3)
circuit = QuantumProgram.from_qprog(qprog_3)

print(f"Synthesized MCX cx-count is {circuit.transpiled_circuit.count_ops['cx']}")
circuit.show()
Synthesized MCX cx-count is 156
Opening: https://platform.classiq.io/circuit/2twMnB3T8fg8NYZvbBcLTZgffx1?version=0.70.0

Beyond 14 Controls

The power of the Classiq synthesis engine is far greater than creating optimized, 14-control MCX gates in an instant. For example, the following code creates an MCX gate with 50 control qubits:

@qfunc
def main(cntrl: Output[QArray[QBit]], target: Output[QBit]) -> None:
    allocate(50, cntrl)
    allocate(1, target)
    my_mcx(cntrl, target)


qmod_4 = create_model(main)

write_qmod(qmod_4, "mcx_50_ctrl")

qprog_4 = synthesize(qmod_4)
show(qprog_4)
Opening: https://platform.classiq.io/circuit/2twMo5GYe0iMRFOs1YqC6kwVr41?version=0.70.0