HW-aware Synthesis of MCX
This example shows that implementation of multiple control-x (MCX) logic, using the Classiq synthesis engine, yields different circuit results for different quantum hardware.
The fictitious hardware created here demonstrates how to insert your own custom-designed machine. For comparison, create two types of hardware with cx, u
basis gates. The difference between them manifests in the connectivity map: one has linear connectivity while the other has all-to-all connectivity.
from classiq import (
CX,
Constraints,
CustomHardwareSettings,
H,
OptimizationParameter,
Output,
Preferences,
QArray,
QBit,
X,
allocate,
control,
create_model,
qfunc,
set_constraints,
set_preferences,
show,
synthesize,
write_qmod,
)
# define MCX quantum function
@qfunc
def my_mcx(cntrl: QArray[QBit], target: QBit) -> None:
control(cntrl, lambda: X(target))
# define the MCX parameters within the quantum 'main' function
@qfunc
def main(cntrl: Output[QArray[QBit]], target: Output[QBit]) -> None:
allocate(15, cntrl)
allocate(1, target)
my_mcx(cntrl, target)
# build a model
model = create_model(main)
# define the hardware parameters
max_width = 18
linear_connectivity = [[qubit, qubit + 1] for qubit in range(max_width - 1)]
preferences_linear = Preferences(
custom_hardware_settings=CustomHardwareSettings(
basis_gates=["cx", "u"],
connectivity_map=linear_connectivity,
),
random_seed=-1,
)
preferences_all_to_all = Preferences(
custom_hardware_settings=CustomHardwareSettings(basis_gates=["cx", "u"]),
random_seed=-1,
)
# define synthesis engine constraints
constraints = Constraints(optimization_parameter="depth", max_width=max_width)
# define models with different preferences
model = set_constraints(model, constraints)
model_linear = set_preferences(model, preferences_linear)
model_all_to_all = set_preferences(model, preferences_all_to_all)
# write models to files
write_qmod(model_linear, "hardware_aware_mcx_linear")
write_qmod(model_all_to_all, "hardware_aware_mcx_all_to_all")
# synthesize to create quantum programs and view circuits:
qprog_linear = synthesize(model_linear)
show(qprog_linear)
qprog_all_to_all = synthesize(model_all_to_all)
show(qprog_all_to_all)
Opening: https://platform.classiq.io/circuit/49c8fa89-91ad-4802-ae00-2fba8f3257e7?version=0.41.0.dev39%2B79c8fd0855
Opening: https://platform.classiq.io/circuit/14a11412-f9e4-4779-ac98-339dccc1efe3?version=0.41.0.dev39%2B79c8fd0855
Comparison of the two circuits shows that applying MCx using different connectivity maps yields different implementation.
Using "all-to-all" connectivity, the synthesis engine chooses as the best implementation a recourse based on "Maslov2015" [1] that was written on the Classiq platform. Using that, the manufactured circuit has 18 qubits; i.e., it uses two auxiliary qubits. The total depth of the circuit is 936.
When using linear connectivity, the best implementation chosen by the synthesis engine is, in fact, different: an algorithm developed by Classiq, which is better suited for this map. Here, the manufactured circuit uses 17 qubits with only one auxiliary and has a depth of 1257 gates.
References
[1]: Maslov, D., 2016. Advantages of using relative-phase Toffoli gates with an application to multiple control Toffoli optimization. Physical Review A, 93(2), p.022311.