Bases: object
Customize the process of synthesis, optimization and mapping
In this class, we meant to provide the users with a direct path to design the
process by which they could transform a unitary matrix to a quantum circuit
and/or optimize a quantum circuit.
Initialize a QCDA process
A QCDA process is defined by a list of synthesis, optimization and mapping.
Experienced users could customize the process for certain purposes.
Parameters:
-
process
(list, default:
None
)
–
A customized list of Synthesis, Optimization and Mapping
Source code in QuICT/qcda/qcda.py
| def __init__(self, process: List = None):
"""Initialize a QCDA process
A QCDA process is defined by a list of synthesis, optimization and mapping.
Experienced users could customize the process for certain purposes.
Args:
process (list, optional): A customized list of Synthesis, Optimization and Mapping
"""
self.process = []
if process is not None:
self.process = process
|
add_default_optimization
add_default_optimization(level: str = 'light', keep_phase: bool = False)
Generate the default optimization process
The default optimization process contains the CommutativeOptimization.
Parameters:
-
level
(str, default:
'light'
)
–
Optimizing level. Support light, heavy level.
-
keep_phase
(bool, default:
False
)
–
whether to keep the global phase as a GPhase gate in the output
Source code in QuICT/qcda/qcda.py
| def add_default_optimization(self, level: str = "light", keep_phase: bool = False):
"""Generate the default optimization process
The default optimization process contains the CommutativeOptimization.
Args:
level (str, optional): Optimizing level. Support `light`, `heavy` level.
keep_phase (bool, optional): whether to keep the global phase as a GPhase gate in the output
"""
self.add_method(CommutativeOptimization(keep_phase=keep_phase))
self.add_method(CliffordRzOptimization(level=level, keep_phase=keep_phase))
|
add_gate_transform(target_instruction: InstructionSet = None, keep_phase: bool = False)
Add GateTransform for some target InstructionSet
GateTransform would transform the gates in the original Circuit/CompositeGate to a certain InstructionSet.
Parameters:
-
target_instruction
(InstructionSet, default:
None
)
–
The target InstructionSet
-
keep_phase
(bool, default:
False
)
–
whether to keep the global phase as a GPhase gate in the output
Source code in QuICT/qcda/qcda.py
| def add_gate_transform(self, target_instruction: InstructionSet = None, keep_phase: bool = False):
"""Add GateTransform for some target InstructionSet
GateTransform would transform the gates in the original Circuit/CompositeGate to a certain InstructionSet.
Args:
target_instruction (InstructionSet): The target InstructionSet
keep_phase (bool): whether to keep the global phase as a GPhase gate in the output
"""
assert target_instruction is not None, ValueError("No InstructionSet provided for Synthesis")
self.add_method(GateTransform(target_instruction, keep_phase=keep_phase))
|
add_mapping
add_mapping(layout: Layout = None, method: str = 'sabre')
Generate the default mapping process
The default mapping process contains the Mapping
Parameters:
-
layout
(Layout, default:
None
)
–
Topology of the target physical device
-
method
(str, default:
'sabre'
)
–
used mapping method in ['sabre', 'vf2']
Source code in QuICT/qcda/qcda.py
| def add_mapping(self, layout: Layout = None, method: str = "sabre"):
"""Generate the default mapping process
The default mapping process contains the Mapping
Args:
layout (Layout): Topology of the target physical device
method (str, optional): used mapping method in ['sabre', 'vf2']
"""
assert layout is not None, ValueError("No Layout provided for Mapping")
assert method in ["sabre", "vf2"], ValueError("Invalid mapping method")
mapping_dict = {
"sabre": SABREMapping(layout),
"vf2": VF2Mapping(layout),
}
self.add_method(mapping_dict[method])
|
add_method
Adding a specific method to the process
Parameters:
Source code in QuICT/qcda/qcda.py
| def add_method(self, method=None):
"""Adding a specific method to the process
Args:
method: Some QCDA method
"""
self.process.append(method)
|
auto_compile
auto_compile(circuit: Circuit, quantum_machine_info: VirtualQuantumMachine, keep_phase=False) -> Tuple[Circuit, List[int], List[int]]
Auto-Compile the circuit with the given quantum machine info. Normally follow the steps:
- Optimization
- Mapping
- Local KAK Decomposition
- Gate Transform
- Optimization
Parameters:
-
circuit
(CompositeGate / Circuit)
–
the target CompositeGate or Circuit
-
quantum_machine_info
(VirtualQuantumMachine)
–
the information about target quantum machine.
-
keep_phase
(bool, default:
False
)
–
whether to keep the global phase as a GPhase gate in the output
Return
compiled_circuit (CompositeGate/Circuit): The compiled CompositeGate or Circuit.
logic2phy (List[int]): The mapping of logical qubits to physical qubits.
phy2logic (List[int]): The mapping of physical qubits to logical qubits at the end of circuit.
Source code in QuICT/qcda/qcda.py
| def auto_compile(
self, circuit: Circuit, quantum_machine_info: VirtualQuantumMachine, keep_phase=False
) -> Tuple[Circuit, List[int], List[int]]:
"""Auto-Compile the circuit with the given quantum machine info. Normally follow the steps:
1. Optimization
2. Mapping
3. Local KAK Decomposition
4. Gate Transform
5. Optimization
Args:
circuit (CompositeGate/Circuit): the target CompositeGate or Circuit
quantum_machine_info (VirtualQuantumMachine): the information about target quantum machine.
keep_phase (bool): whether to keep the global phase as a GPhase gate in the output
Return:
compiled_circuit (CompositeGate/Circuit): The compiled CompositeGate or Circuit.
logic2phy (List[int]): The mapping of logical qubits to physical qubits.
phy2logic (List[int]): The mapping of physical qubits to logical qubits at the end of circuit.
"""
qm_iset = quantum_machine_info.instruction_set
qm_layout = quantum_machine_info.layout
qm_process = []
# Step 1: optimization algorithm for common circuit
circuit.decomposition()
circuit.flatten()
if circuit.count_gate_by_gatetype(GateType.cx) == circuit.size():
qm_process.append(CnotWithoutAncilla())
else:
gate_types = circuit.get_all_gatetype()
qm_process.append(self._choice_opt_algorithm(gate_types))
# Step 2: Mapping if layout is not all-connected
if qm_layout is not None:
mapping = SABREMapping(qm_layout, initial_iterations=10, swap_iterations=10)
qm_process.append(mapping)
if qm_iset is not None:
# Step 3: Local KAK Decomposition
if qm_iset.two_qubit_gate in [GateType.rxx, GateType.ryy, GateType.rzz]:
qm_process.append(LocalKAKDecomposition(target="rot", keep_phase=keep_phase))
else:
qm_process.append(LocalKAKDecomposition(target="cx", keep_phase=keep_phase))
# Step 4: Gate Transform by the given instruction set
qm_process.append(GateTransform(qm_iset, keep_phase=keep_phase))
# Step 5: Start the auto QCDA process:
logger.info("QCDA Now processing GateDecomposition.")
for process in qm_process:
logger.info(f"QCDA Now processing {process.__class__.__name__}.")
circuit = process.execute(circuit)
# Step 6: Depending on the special instruction set gate, choice best optimization algorithm.
if qm_iset is not None or qm_layout is not None:
post_opt_process = self._choice_opt_algorithm(circuit.get_all_gatetype(), keep_phase=keep_phase)
logger.info(f"QCDA Now processing {post_opt_process.__class__.__name__}.")
circuit = post_opt_process.execute(circuit)
logic2phy = mapping.logic2phy if qm_layout is not None else None
phy2logic = mapping.phy2logic if qm_layout is not None else None
return circuit, logic2phy, phy2logic
|
compile
compile(circuit: Union[Circuit, CompositeGate]) -> Union[Circuit, CompositeGate]
Compile the circuit with the given process
Parameters:
Returns:
-
Union[Circuit, CompositeGate]
–
Union[Circuit, CompositeGate]: the resulting CompositeGate or Circuit
Source code in QuICT/qcda/qcda.py
| def compile(self, circuit: Union[Circuit, CompositeGate]) -> Union[Circuit, CompositeGate]:
"""Compile the circuit with the given process
Args:
circuit (Union[Circuit, CompositeGate]): the target CompositeGate or Circuit
Returns:
Union[Circuit, CompositeGate]: the resulting CompositeGate or Circuit
"""
logger.info("QCDA Now processing GateDecomposition.")
circuit.decomposition()
circuit.flatten()
for process in self.process:
logger.info(f"QCDA Now processing {process.__class__.__name__}.")
circuit = process.execute(circuit)
return circuit
|