def transpile(dag, basis_gates='u1,u2,u3,cx,id', coupling_map=None, initial_layout=None, get_layout=False, format='dag', seed=None, pass_manager=None): """Transform a dag circuit into another dag circuit (transpile), through consecutive passes on the dag. Args: dag (DAGCircuit): dag circuit to transform via transpilation basis_gates (str): a comma separated string for the target basis gates coupling_map (list): A graph of coupling:: [ [control0(int), target0(int)], [control1(int), target1(int)], ] eg. [[0, 2], [1, 2], [1, 3], [3, 4]} initial_layout (dict): A mapping of qubit to qubit:: { ("q", start(int)): ("q", final(int)), ... } eg. { ("q", 0): ("q", 0), ("q", 1): ("q", 1), ("q", 2): ("q", 2), ("q", 3): ("q", 3) } get_layout (bool): flag for returning the final layout after mapping format (str): The target format of the compilation: {'dag', 'json', 'qasm'} seed (int): random seed for the swap mapper pass_manager (PassManager): pass manager instance for the transpilation process If None, a default set of passes are run. Otherwise, the passes defined in it will run. If contains no passes in it, no dag transformations occur. Returns: DAGCircuit: transformed dag DAGCircuit, dict: transformed dag along with the final layout on backend qubits Raises: TranspilerError: if the format is not valid. """ # TODO: `basis_gates` will be removed after we have the unroller pass. # TODO: `coupling_map`, `initial_layout`, `get_layout`, `seed` removed after mapper pass. # TODO: move this to the mapper pass num_qubits = sum(dag.qregs.values()) if num_qubits == 1 or coupling_map == "all-to-all": coupling_map = None final_layout = None if pass_manager: # run the passes specified by the pass manager # TODO return the property set too. See #1086 dag = pass_manager.run_passes(dag) else: # default set of passes # TODO: move each step here to a pass, and use a default passmanager below basis = basis_gates.split(',') if basis_gates else [] dag_unroller = DagUnroller(dag, DAGBackend(basis)) dag = dag_unroller.expand_gates() # if a coupling map is given compile to the map if coupling_map: logger.info("pre-mapping properties: %s", dag.property_summary()) # Insert swap gates coupling = Coupling(coupling_list2dict(coupling_map)) removed_meas = remove_last_measurements(dag) logger.info("measurements moved: %s", removed_meas) logger.info("initial layout: %s", initial_layout) dag, final_layout, last_layout = swap_mapper(dag, coupling, initial_layout, trials=20, seed=seed) logger.info("final layout: %s", final_layout) # Expand swaps dag_unroller = DagUnroller(dag, DAGBackend(basis)) dag = dag_unroller.expand_gates() # Change cx directions dag = direction_mapper(dag, coupling) # Simplify cx gates cx_cancellation(dag) # Simplify single qubit gates dag = optimize_1q_gates(dag) return_last_measurements(dag, removed_meas, last_layout) logger.info("post-mapping properties: %s", dag.property_summary()) # choose output format # TODO: do we need all of these formats, or just the dag? if format == 'dag': compiled_circuit = dag elif format == 'json': # FIXME: JsonBackend is wrongly taking an ordered dict as basis, not list dag_unroller = DagUnroller(dag, JsonBackend(dag.basis)) compiled_circuit = dag_unroller.execute() elif format == 'qasm': compiled_circuit = dag.qasm() else: raise TranspilerError('unrecognized circuit format') if get_layout: return compiled_circuit, final_layout return compiled_circuit
def compile(circuits, backend, config=None, basis_gates=None, coupling_map=None, initial_layout=None, shots=1024, max_credits=10, seed=None, qobj_id=None, hpc=None, skip_transpiler=False): """Compile a list of circuits into a qobj. Args: circuits (QuantumCircuit or list[QuantumCircuit]): circuits to compile backend (BaseBackend or str): a backend to compile for config (dict): dictionary of parameters (e.g. noise) used by runner basis_gates (str): comma-separated basis gate set to compile to coupling_map (list): coupling map (perhaps custom) to target in mapping initial_layout (list): initial layout of qubits in mapping shots (int): number of repetitions of each circuit, for sampling max_credits (int): maximum credits to use seed (int): random seed for simulators qobj_id (int): identifier for the generated qobj hpc (dict): HPC simulator parameters skip_transpiler (bool): If True, bypass most of the compilation process and creates a qobj with minimal check nor translation Returns: Qobj: the qobj to be run on the backends Raises: TranspilerError: in case of bad compile options, e.g. the hpc options. """ # pylint: disable=redefined-builtin # Check for valid parameters for the experiments. if hpc is not None and \ not all(key in hpc for key in ('multi_shot_optimization', 'omp_num_threads')): raise TranspilerError('Unknown HPC parameter format!') if isinstance(circuits, QuantumCircuit): circuits = [circuits] if isinstance(backend, str): try: backend = Aer.get_backend(backend) except KeyError: backend = IBMQ.get_backend(backend) pass_manager = None # default pass manager which executes predetermined passes if skip_transpiler: # empty pass manager which does nothing pass_manager = PassManager() backend_conf = backend.configuration() backend_name = backend_conf['name'] basis_gates = basis_gates or backend_conf['basis_gates'] coupling_map = coupling_map or backend_conf['coupling_map'] qobj_config = deepcopy(config or {}) qobj_config.update({ 'shots': shots, 'max_credits': max_credits, 'memory_slots': 0 }) qobj = Qobj(qobj_id=qobj_id or str(uuid.uuid4()), config=QobjConfig(**qobj_config), experiments=[], header=QobjHeader(backend_name=backend_name)) if seed: qobj.config.seed = seed qobj.experiments = parallel_map(_build_exp_parallel, list(range(len(circuits))), task_args=(circuits, backend), task_kwargs={ 'initial_layout': initial_layout, 'basis_gates': basis_gates, 'config': config, 'coupling_map': coupling_map, 'seed': seed, 'pass_manager': pass_manager }) qobj.config.memory_slots = max(experiment.config.memory_slots for experiment in qobj.experiments) qobj.config.n_qubits = max(experiment.config.n_qubits for experiment in qobj.experiments) return qobj
def transpile(circuits, backend, basis_gates=None, coupling_map=None, initial_layout=None, seed_mapper=None, hpc=None, pass_manager=None): """transpile a list of circuits into a dags. Args: circuits (QuantumCircuit or list[QuantumCircuit]): circuits to compile backend (BaseBackend): a backend to compile for basis_gates (str): comma-separated basis gate set to compile to coupling_map (list): coupling map (perhaps custom) to target in mapping initial_layout (list): initial layout of qubits in mapping seed_mapper (int): random seed for the swap_mapper hpc (dict): HPC simulator parameters pass_manager (PassManager): a pass_manager for the transpiler stage Returns: dags: a list of dags. Raises: TranspilerError: in case of bad compile options, e.g. the hpc options. """ if isinstance(circuits, QuantumCircuit): circuits = [circuits] # FIXME: THIS NEEDS TO BE CLEANED UP -- some things to decide for list of circuits: # 1. do all circuits have same coupling map? # 2. do all circuit have the same basis set? # 3. do they all have same registers etc? backend_conf = backend.configuration() # Check for valid parameters for the experiments. if hpc is not None and \ not all(key in hpc for key in ('multi_shot_optimization', 'omp_num_threads')): raise TranspilerError('Unknown HPC parameter format!') basis_gates = basis_gates or backend_conf['basis_gates'] coupling_map = coupling_map or backend_conf['coupling_map'] # step 1: Making the list of dag circuits dags = _circuits_2_dags(circuits) # step 2: Transpile all the dags # FIXME: Work-around for transpiling multiple circuits with different qreg names. # Make compile take a list of initial_layouts. _initial_layout = initial_layout # Pick a good initial layout if coupling_map is not already satisfied # otherwise keep it as q[i]->q[i]. # TODO: move this inside mapper pass. initial_layouts = [] for dag in dags: if (initial_layout is None and not backend.configuration()['simulator'] and not _matches_coupling_map(dag, coupling_map)): _initial_layout = _pick_best_layout(dag, backend) initial_layouts.append(_initial_layout) dags = _dags_2_dags(dags, basis_gates=basis_gates, coupling_map=coupling_map, initial_layouts=initial_layouts, seed_mapper=seed_mapper, pass_manager=pass_manager) # TODO: change it to circuits # TODO: make it parallel return dags
def compile(circuits, backend, config=None, basis_gates=None, coupling_map=None, initial_layout=None, shots=1024, max_credits=10, seed=None, qobj_id=None, hpc=None, pass_manager=None): """Compile a list of circuits into a qobj. Args: circuits (QuantumCircuit or list[QuantumCircuit]): circuits to compile backend (BaseBackend): a backend to compile for config (dict): dictionary of parameters (e.g. noise) used by runner basis_gates (str): comma-separated basis gate set to compile to coupling_map (list): coupling map (perhaps custom) to target in mapping initial_layout (list): initial layout of qubits in mapping shots (int): number of repetitions of each circuit, for sampling max_credits (int): maximum credits to use seed (int): random seed for simulators qobj_id (int): identifier for the generated qobj hpc (dict): HPC simulator parameters pass_manager (PassManager): a pass_manager for the transpiler stage Returns: QobjExperiment: Experiment to be wrapped in a Qobj. Raises: TranspilerError: in case of bad compile options, e.g. the hpc options. """ if isinstance(circuits, QuantumCircuit): circuits = [circuits] # FIXME: THIS NEEDS TO BE CLEANED UP -- some things to decide for list of circuits: # 1. do all circuits have same coupling map? # 2. do all circuit have the same basis set? # 3. do they all have same registers etc? backend_conf = backend.configuration() backend_name = backend_conf['name'] # Check for valid parameters for the experiments. if hpc is not None and \ not all(key in hpc for key in ('multi_shot_optimization', 'omp_num_threads')): raise TranspilerError('Unknown HPC parameter format!') basis_gates = basis_gates or backend_conf['basis_gates'] coupling_map = coupling_map or backend_conf['coupling_map'] # step 1: Making the list of dag circuits dags = _circuits_2_dags(circuits) # step 2: Transpile all the dags # FIXME: Work-around for transpiling multiple circuits with different qreg names. # Make compile take a list of initial_layouts. _initial_layout = initial_layout # Pick a good initial layout if coupling_map is not already satisfied # otherwise keep it as q[i]->q[i]. # TODO: move this inside mapper pass. initial_layouts = [] for dag in dags: if (initial_layout is None and not backend.configuration()['simulator'] and not _matches_coupling_map(dag, coupling_map)): _initial_layout = _pick_best_layout(dag, backend) initial_layouts.append(_initial_layout) dags = _transpile_dags(dags, basis_gates=basis_gates, coupling_map=coupling_map, initial_layouts=initial_layouts, seed=seed, pass_manager=pass_manager) # step 3: Making a qobj qobj = _dags_2_qobj(dags, backend_name=backend_name, config=config, shots=shots, max_credits=max_credits, qobj_id=qobj_id, basis_gates=basis_gates, coupling_map=coupling_map, seed=seed) return qobj
def compile(circuits, backend, config=None, basis_gates=None, coupling_map=None, initial_layout=None, shots=1024, max_credits=10, seed=None, qobj_id=None, hpc=None, pass_manager=None): """Compile a list of circuits into a qobj. Args: circuits (QuantumCircuit or list[QuantumCircuit]): circuits to compile backend (BaseBackend): a backend to compile for config (dict): dictionary of parameters (e.g. noise) used by runner basis_gates (str): comma-separated basis gate set to compile to coupling_map (list): coupling map (perhaps custom) to target in mapping initial_layout (list): initial layout of qubits in mapping shots (int): number of repetitions of each circuit, for sampling max_credits (int): maximum credits to use seed (int): random seed for simulators qobj_id (int): identifier for the generated qobj hpc (dict): HPC simulator parameters pass_manager (PassManager): a pass_manager for the transpiler stage Returns: Qobj: the Qobj to be run on the backends Raises: TranspilerError: in case of bad compile options, e.g. the hpc options. """ if isinstance(circuits, QuantumCircuit): circuits = [circuits] backend_conf = backend.configuration backend_name = backend_conf['name'] # Step 1: create the Qobj, with empty experiments. # Copy the configuration: the values in `config` have prefern qobj_config = deepcopy(config or {}) # TODO: "memory_slots" is required by the qobj schema in the top-level # qobj.config, and is user-defined. At the moment is set to the maximum # number of *register* slots for the circuits, in order to have `measure` # behave properly until the transition is over; and each circuit stores # its memory_slots in its configuration. qobj_config.update({ 'shots': shots, 'max_credits': max_credits, 'memory_slots': 0 }) qobj = Qobj(id=qobj_id or str(uuid.uuid4()), config=QobjConfig(**qobj_config), experiments=[], header=QobjHeader(backend_name=backend_name)) if seed: qobj.config.seed = seed # Check for valid parameters for the experiments. if hpc is not None and \ not all(key in hpc for key in ('multi_shot_optimization', 'omp_num_threads')): raise TranspilerError('Unknown HPC parameter format!') basis_gates = basis_gates or backend_conf['basis_gates'] coupling_map = coupling_map or backend_conf['coupling_map'] # Step 2 and 3: transpile and populate the circuits for circuit in circuits: experiment = _compile_single_circuit(circuit, backend, config, basis_gates, coupling_map, initial_layout, seed, pass_manager) # Step 3c: add the Experiment to the Qobj qobj.experiments.append(experiment) # Update the `memory_slots` value. # TODO: remove when `memory_slots` can be provided by the user. qobj.config.memory_slots = max(experiment.config.memory_slots for experiment in qobj.experiments) return qobj
def transpile(dag_circuit, basis_gates='u1,u2,u3,cx,id', coupling_map=None, initial_layout=None, get_layout=False, format='dag', seed=None, pass_manager=None): """Transform a dag circuit into another dag circuit (transpile), through consecutive passes on the dag. Args: dag_circuit (DAGCircuit): dag circuit to transform via transpilation basis_gates (str): a comma seperated string for the target basis gates coupling_map (list): A graph of coupling:: [ [control0(int), target0(int)], [control1(int), target1(int)], ] eg. [[0, 2], [1, 2], [1, 3], [3, 4]} initial_layout (dict): A mapping of qubit to qubit:: { ("q", start(int)): ("q", final(int)), ... } eg. { ("q", 0): ("q", 0), ("q", 1): ("q", 1), ("q", 2): ("q", 2), ("q", 3): ("q", 3) } get_layout (bool): flag for returning the layout format (str): The target format of the compilation: {'dag', 'json', 'qasm'} seed (int): random seed for simulators pass_manager (PassManager): pass manager instance for the tranpilation process If None, a default set of passes are run. Otherwise, the passes defined in it will run. If contains no passes in it, no dag transformations occur. Returns: object: If get_layout == False, the compiled circuit in the specified format. If get_layout == True, a tuple is returned, with the second element being the layout. Raises: TranspilerError: if the format is not valid. """ final_layout = None if pass_manager: # run the passes specified by the pass manager for pass_ in pass_manager.passes(): pass_.run(dag_circuit) else: # default set of passes # TODO: move each step here to a pass, and use a default passmanager below basis = basis_gates.split(',') if basis_gates else [] dag_unroller = DagUnroller(dag_circuit, DAGBackend(basis)) dag_circuit = dag_unroller.expand_gates() # if a coupling map is given compile to the map if coupling_map: logger.info("pre-mapping properties: %s", dag_circuit.property_summary()) # Insert swap gates coupling = Coupling(coupling_list2dict(coupling_map)) logger.info("initial layout: %s", initial_layout) dag_circuit, final_layout = swap_mapper(dag_circuit, coupling, initial_layout, trials=20, seed=seed) logger.info("final layout: %s", final_layout) # Expand swaps dag_unroller = DagUnroller(dag_circuit, DAGBackend(basis)) dag_circuit = dag_unroller.expand_gates() # Change cx directions dag_circuit = direction_mapper(dag_circuit, coupling) # Simplify cx gates cx_cancellation(dag_circuit) # Simplify single qubit gates dag_circuit = optimize_1q_gates(dag_circuit) logger.info("post-mapping properties: %s", dag_circuit.property_summary()) # choose output format # TODO: do we need all of these formats, or just the dag? if format == 'dag': compiled_circuit = dag_circuit elif format == 'json': # FIXME: JsonBackend is wrongly taking an ordered dict as basis, not list dag_unroller = DagUnroller(dag_circuit, JsonBackend(dag_circuit.basis)) compiled_circuit = dag_unroller.execute() elif format == 'qasm': compiled_circuit = dag_circuit.qasm() else: raise TranspilerError('unrecognized circuit format') if get_layout: return compiled_circuit, final_layout return compiled_circuit
def compile(circuits, backend, config=None, basis_gates=None, coupling_map=None, initial_layout=None, shots=1024, max_credits=10, seed=None, qobj_id=None, hpc=None, pass_manager=None): """Compile a list of circuits into a qobj. Args: circuits (QuantumCircuit or list[QuantumCircuit]): circuits to compile backend (BaseBackend): a backend to compile for config (dict): dictionary of parameters (e.g. noise) used by runner basis_gates (str): comma-separated basis gate set to compile to coupling_map (list): coupling map (perhaps custom) to target in mapping initial_layout (list): initial layout of qubits in mapping shots (int): number of repetitions of each circuit, for sampling max_credits (int): maximum credits to use seed (int): random seed for simulators qobj_id (int): identifier for the generated qobj hpc (dict): HPC simulator parameters pass_manager (PassManager): a pass_manager for the transpiler stage Returns: obj: the qobj to be run on the backends Raises: TranspilerError: in case of bad compile options, e.g. the hpc options. """ if isinstance(circuits, QuantumCircuit): circuits = [circuits] backend_conf = backend.configuration backend_name = backend_conf['name'] qobj = {} # step 1: populate the qobj-level `id` qobj_id = qobj_id or str(uuid.uuid4()) qobj['id'] = qobj_id # step 2: populate the qobj-level `config` qobj['config'] = { 'max_credits': max_credits, 'shots': shots, 'backend_name': backend_name } if hpc is not None and \ not all(key in hpc for key in ('multi_shot_optimization', 'omp_num_threads')): raise TranspilerError('Unknown HPC parameter format!') # step 3: populate the `circuits` in qobj, after compiling each circuit qobj['circuits'] = [] if not basis_gates: basis_gates = backend_conf['basis_gates'] if not coupling_map: coupling_map = backend_conf['coupling_map'] for circuit in circuits: job = {} # step 1: populate the circuit-level `name` job["name"] = circuit.name # step 2: populate the circuit-level `config` if config is None: config = {} job["config"] = copy.deepcopy(config) # TODO: A better solution is to have options to enable/disable optimizations num_qubits = sum((len(qreg) for qreg in circuit.get_qregs().values())) if num_qubits == 1 or coupling_map == "all-to-all": coupling_map = None job["config"]["coupling_map"] = coupling_map job["config"]["basis_gates"] = basis_gates job["config"]["seed"] = seed # step 3: populate the circuit `instructions` after compilation # step 3a: circuit -> dag dag_circuit = DAGCircuit.fromQuantumCircuit(circuit) # TODO: move this inside the mapper pass # pick a good initial layout if coupling_map is not already satisfied # otherwise keep it as q[i]->q[i] if (initial_layout is None and not backend_conf['simulator'] and not _matches_coupling_map(circuit.data, coupling_map)): initial_layout = _pick_best_layout(backend, num_qubits, circuit.get_qregs()) # step 3b: transpile (dag -> dag) dag_circuit, final_layout = transpile(dag_circuit, basis_gates=basis_gates, coupling_map=coupling_map, initial_layout=initial_layout, get_layout=True, seed=seed, pass_manager=pass_manager) # step 3c: dag -> json # TODO: populate the Qobj object when Qobj class exists # the compiled circuit to be run saved as a dag # we assume that transpile() has already expanded gates # to the target basis, so we just need to generate json list_layout = [[k, v] for k, v in final_layout.items() ] if final_layout else None job["config"]["layout"] = list_layout json_circuit = DagUnroller(dag_circuit, JsonBackend(dag_circuit.basis)).execute() job["compiled_circuit"] = json_circuit # set eval_symbols=True to evaluate each symbolic expression # TODO after transition to qobj, we can drop this job["compiled_circuit_qasm"] = dag_circuit.qasm(qeflag=True, eval_symbols=True) # add job to the qobj qobj["circuits"].append(job) return qobj
def compile(circuits, backend, config=None, basis_gates=None, coupling_map=None, initial_layout=None, shots=1024, max_credits=10, seed=None, qobj_id=None, hpc=None, pass_manager=None): """Compile a list of circuits into a qobj. Args: circuits (QuantumCircuit or list[QuantumCircuit]): circuits to compile backend (BaseBackend): a backend to compile for config (dict): dictionary of parameters (e.g. noise) used by runner basis_gates (str): comma-separated basis gate set to compile to coupling_map (list): coupling map (perhaps custom) to target in mapping initial_layout (list): initial layout of qubits in mapping shots (int): number of repetitions of each circuit, for sampling max_credits (int): maximum credits to use seed (int): random seed for simulators qobj_id (int): identifier for the generated qobj hpc (dict): HPC simulator parameters pass_manager (PassManager): a pass_manager for the transpiler stage Returns: Qobj: the Qobj to be run on the backends Raises: TranspilerError: in case of bad compile options, e.g. the hpc options. """ if isinstance(circuits, QuantumCircuit): circuits = [circuits] backend_conf = backend.configuration backend_name = backend_conf['name'] # Step 1: create the Qobj, with empty experiments. # Copy the configuration: the values in `config` have prefern qobj_config = deepcopy(config or {}) # TODO: "register_slots" is required by the qobj schema in the top-level # qobj.config. In this implementation, is overridden by the individual # experiment.config entries (hence the 0 should never be used). qobj_config.update({ 'shots': shots, 'max_credits': max_credits, 'register_slots': 0 }) qobj = Qobj(id=qobj_id or str(uuid.uuid4()), config=QobjConfig(**qobj_config), experiments=[], header=QobjHeader(backend_name=backend_name)) if seed: qobj.config.seed = seed # Check for valid parameters for the experiments. if hpc is not None and \ not all(key in hpc for key in ('multi_shot_optimization', 'omp_num_threads')): raise TranspilerError('Unknown HPC parameter format!') basis_gates = basis_gates or backend_conf['basis_gates'] coupling_map = coupling_map or backend_conf['coupling_map'] # Step 2 and 3: transpile and populate the circuits for circuit in circuits: # TODO: A better solution is to have options to enable/disable optimizations num_qubits = sum((len(qreg) for qreg in circuit.get_qregs().values())) if num_qubits == 1 or coupling_map == "all-to-all": coupling_map = None # Step 2a: circuit -> dag dag_circuit = DAGCircuit.fromQuantumCircuit(circuit) # TODO: move this inside the mapper pass # pick a good initial layout if coupling_map is not already satisfied # otherwise keep it as q[i]->q[i] if (initial_layout is None and not backend_conf['simulator'] and not _matches_coupling_map(circuit.data, coupling_map)): initial_layout = _pick_best_layout(backend, num_qubits, circuit.get_qregs()) # Step 2b: transpile (dag -> dag) dag_circuit, final_layout = transpile(dag_circuit, basis_gates=basis_gates, coupling_map=coupling_map, initial_layout=initial_layout, get_layout=True, seed=seed, pass_manager=pass_manager) # Step 2c: dag -> json # the compiled circuit to be run saved as a dag # we assume that transpile() has already expanded gates # to the target basis, so we just need to generate json list_layout = [[k, v] for k, v in final_layout.items() ] if final_layout else None json_circuit = DagUnroller(dag_circuit, JsonBackend(dag_circuit.basis)).execute() # Step 3a: create the Experiment based on json_circuit experiment = QobjExperiment.from_dict(json_circuit) # Step 3b: populate the Experiment configuration and header experiment.header.name = circuit.name # TODO: place in header or config? experiment_config = deepcopy(config or {}) experiment_config.update({ 'coupling_map': coupling_map, 'basis_gates': basis_gates, 'layout': list_layout, 'register_slots': sum(register.size for register in circuit.get_cregs().values()) }) experiment.config = QobjItem(**experiment_config) # set eval_symbols=True to evaluate each symbolic expression # TODO after transition to qobj, we can drop this experiment.header.compiled_circuit_qasm = dag_circuit.qasm( qeflag=True, eval_symbols=True) # Step 3c: add the Experiment to the Qobj qobj.experiments.append(experiment) return qobj
def compile(circuits, backend, config=None, basis_gates=None, coupling_map=None, initial_layout=None, shots=1024, max_credits=10, seed=None, qobj_id=None, hpc=None, pass_manager=None): """Compile a list of circuits into a qobj. Args: circuits (QuantumCircuit or list[QuantumCircuit]): circuits to compile backend (BaseBackend): a backend to compile for config (dict): dictionary of parameters (e.g. noise) used by runner basis_gates (str): comma-separated basis gate set to compile to coupling_map (list): coupling map (perhaps custom) to target in mapping initial_layout (list): initial layout of qubits in mapping shots (int): number of repetitions of each circuit, for sampling max_credits (int): maximum credits to use seed (int): random seed for simulators qobj_id (int): identifier for the generated qobj hpc (dict): HPC simulator parameters pass_manager (PassManager): a pass_manager for the transpiler stage Returns: Qobj: the Qobj to be run on the backends Raises: TranspilerError: in case of bad compile options, e.g. the hpc options. """ if isinstance(circuits, QuantumCircuit): circuits = [circuits] backend_conf = backend.configuration backend_name = backend_conf['name'] # Step 1: create the Qobj, with empty circuits qobj = Qobj(id=qobj_id or str(uuid.uuid4()), config=QobjConfig(max_credits=max_credits, shots=shots, backend_name=backend_name), circuits=[]) # Check for valid parameters for the experiments. if hpc is not None and \ not all(key in hpc for key in ('multi_shot_optimization', 'omp_num_threads')): raise TranspilerError('Unknown HPC parameter format!') basis_gates = basis_gates or backend_conf['basis_gates'] coupling_map = coupling_map or backend_conf['coupling_map'] for circuit in circuits: # Step 1: create the experiment configuration. config = config or {} circuit_config = copy.deepcopy(config) # TODO: A better solution is to have options to enable/disable optimizations num_qubits = sum((len(qreg) for qreg in circuit.get_qregs().values())) if num_qubits == 1 or coupling_map == "all-to-all": coupling_map = None circuit_config["coupling_map"] = coupling_map circuit_config["basis_gates"] = basis_gates circuit_config["seed"] = seed circuit_config["layout"] = None # set during step 3. # Step 2: create the QobjExperiment, with empty compiled circuits. experiment = QobjExperiment( name=circuit.name, config=QobjExperimentConfig(**circuit_config), compiled_circuit=None, compiled_circuit_qasm=None) # Step 3: populate the circuit `instructions` after compilation # Step 3a: circuit -> dag dag_circuit = DAGCircuit.fromQuantumCircuit(circuit) # TODO: move this inside the mapper pass # pick a good initial layout if coupling_map is not already satisfied # otherwise keep it as q[i]->q[i] if (initial_layout is None and not backend_conf['simulator'] and not _matches_coupling_map(circuit.data, coupling_map)): initial_layout = _pick_best_layout(backend, num_qubits, circuit.get_qregs()) # Step 3b: transpile (dag -> dag) dag_circuit, final_layout = transpile(dag_circuit, basis_gates=basis_gates, coupling_map=coupling_map, initial_layout=initial_layout, get_layout=True, seed=seed, pass_manager=pass_manager) # Step 3c: dag -> json # the compiled circuit to be run saved as a dag # we assume that transpile() has already expanded gates # to the target basis, so we just need to generate json list_layout = [[k, v] for k, v in final_layout.items() ] if final_layout else None experiment.config.layout = list_layout json_circuit = DagUnroller(dag_circuit, JsonBackend(dag_circuit.basis)).execute() experiment.compiled_circuit = QobjCompiledCircuit.from_dict( json_circuit) # set eval_symbols=True to evaluate each symbolic expression # TODO after transition to qobj, we can drop this experiment.compiled_circuit_qasm = dag_circuit.qasm(qeflag=True, eval_symbols=True) # add job to the qobj qobj.circuits.append(experiment) return qobj