def _build_subcircuit(self, gatedefs, basis, gate_name, gate_params, gate_args, gate_condition): """Build DAGCircuit for a given user-defined gate node. gatedefs = dictionary of Gate AST nodes for user-defined gates gate_name = name of gate to expand to target_basis (nd["name"]) gate_params = list of gate parameters (nd["params"]) gate_args = list of gate arguments (nd["qargs"]) gate_condition = None or tuple (string, int) (nd["condition"]) Returns (subcircuit, wires) where subcircuit is the DAGCircuit corresponding to the user-defined gate node expanded to target_basis and wires is the list of input wires to the subcircuit in order corresponding to the gate's arguments. """ children = [Id(gate_name, 0, "")] if gate_params: children.append(ExpressionList(list(map(Real, gate_params)))) new_wires = [("q", j) for j in range(len(gate_args))] children.append( PrimaryList( list( map(lambda x: IndexedId([Id(x[0], 0, ""), Int(x[1])]), new_wires)))) gate_node = CustomUnitary(children) id_int = [Id("q", 0, ""), Int(len(gate_args))] # Make a list of register declaration nodes reg_nodes = [Qreg([IndexedId(id_int)])] # Add an If node when there is a condition present if gate_condition: gate_node = If([ Id(gate_condition[0], 0, ""), Int(gate_condition[1]), gate_node ]) new_wires += [ (gate_condition[0], j) for j in range(self.dag_circuit.cregs[gate_condition[0]]) ] reg_nodes.append( Creg([ IndexedId([ Id(gate_condition[0], 0, ""), Int(self.dag_circuit.cregs[gate_condition[0]]) ]) ])) # Build the whole program's AST sub_ast = Program(gatedefs + reg_nodes + [gate_node]) # Interpret the AST to give a new DAGCircuit over backend basis sub_circuit = Unroller(sub_ast, DAGBackend(basis)).execute() return sub_circuit, new_wires
def expand_gates(self, basis=None): """Expand all gate nodes to the given basis. If basis is empty, each custom gate node is replaced by its implementation over U and CX. If basis contains names, then those custom gates are not expanded. For example, if "u3" is in basis, then the gate "u3" will not be expanded wherever it occurs. This member function replicates the behavior of the unroller module without using the OpenQASM parser. """ if basis is None: basis = self.backend.basis if not isinstance(self.backend, DAGBackend): raise UnrollerError("expand_gates only accepts a DAGBackend!!") # Build the Gate AST nodes for user-defined gates gatedefs = [] for name, gate in self.dag_circuit.gates.items(): children = [Id(name, 0, "")] if gate["n_args"] > 0: children.append( ExpressionList( list(map(lambda x: Id(x, 0, ""), gate["args"])))) children.append( IdList(list(map(lambda x: Id(x, 0, ""), gate["bits"])))) children.append(gate["body"]) gatedefs.append(Gate(children)) # Walk through the DAG and examine each node builtins = ["U", "CX", "measure", "reset", "barrier"] simulator_builtins = ['snapshot', 'save', 'load', 'noise'] topological_sorted_list = list( nx.topological_sort(self.dag_circuit.multi_graph)) for node in topological_sorted_list: current_node = self.dag_circuit.multi_graph.node[node] if current_node["type"] == "op" and \ current_node["name"] not in builtins + basis + simulator_builtins and \ not self.dag_circuit.gates[current_node["name"]]["opaque"]: subcircuit, wires = self._build_subcircuit( gatedefs, basis, current_node["name"], current_node["params"], current_node["qargs"], current_node["condition"]) self.dag_circuit.substitute_circuit_one( node, subcircuit, wires) return self.dag_circuit