Repository: Qiskit/qiskit (python)

Issue:
Unnecessary check and exception in `GateDirection` pass
### Environment

- **Qiskit Terra version**: 0.25
- **Python version**: 3.9
- **Operating system**: MacOS


### What is happening?

The `GateDirection` transpiler pass has an unnecessary check that input circuits only contain 1 register:

https://github.com/Qiskit/qiskit/blob/main/qiskit/transpiler/passes/utils/gate_direction.py#L328-L332


### How can we reproduce the issue?

```python
from qiskit.circuit import QuantumRegister, QuantumCircuit
from qiskit.transpiler import PassManager, CouplingMap
from qiskit.transpiler.passes import GateDirection

q1 = QuantumRegister(1)
q2 = QuantumRegister(1)
qc = QuantumCircuit(q1, q2)
qc.cx(1, 0)
qc.cx(0, 1)

cmap = CouplingMap([[0, 1]])
pm = PassManager([GateDirection(coupling_map=cmap)])
pm.run(qc)
```
raises 
```
TranspilerError: "GateDirection expects a single qreg input DAG,but input DAG had qregs: OrderedDict([('q67', QuantumRegister(1, 'q67')), ('q68', QuantumRegister(1, 'q68'))])."
```

### What should happen?

If the check is removed it works as you would expect:
```python

class GateDirectionFixed(GateDirection):
    
    def run(self, dag):
        layout_map = {bit: i for i, bit in enumerate(dag.qubits)}
        if self.target is None:
            return self._run_coupling_map(dag, layout_map)
        return self._run_target(dag, layout_map)

pm = PassManager([GateDirectionFixed(coupling_map=cmap)])
pm.run(qc).draw()
```
```
     ┌───┐     ┌───┐     
q77: ┤ H ├──■──┤ H ├──■──
     ├───┤┌─┴─┐├───┤┌─┴─┐
q78: ┤ H ├┤ X ├┤ H ├┤ X ├
     └───┘└───┘└───┘└───┘
```

### Any suggestions?

Remove the incorrect check for a single register from the `GateDirection.run` method

Pull request description:
Fix GateDirection pass
<!--
⚠️ If you do not respect this template, your pull request will be closed.
⚠️ Your pull request title should be short detailed and understandable for all.
⚠️ Also, please add a release note file using reno if the change needs to be
  documented in the release notes.
⚠️ If your pull request fixes an open issue, please link to the issue.

- [x] I have added the tests to cover my changes.
- [x] I have updated the documentation accordingly.
- [x] I have read the CONTRIBUTING document.
-->

### Summary

Fixes #10824 

### Details and comments




Patch:
diff --git a/crates/accelerate/src/sabre_layout.rs b/crates/accelerate/src/sabre_layout.rs
index ce49e9115..decfe590c 100644
--- a/crates/accelerate/src/sabre_layout.rs
+++ b/crates/accelerate/src/sabre_layout.rs
@@ -11,6 +11,7 @@
 // that they have been altered from the originals.
 #![allow(clippy::too_many_arguments)]
 
+use hashbrown::HashSet;
 use ndarray::prelude::*;
 use numpy::{IntoPyArray, PyArray, PyReadonlyArray2};
 use pyo3::prelude::*;
@@ -28,6 +29,7 @@ use crate::sabre_swap::swap_map::SwapMap;
 use crate::sabre_swap::{build_swap_map_inner, Heuristic, NodeBlockResults, SabreResult};
 
 #[pyfunction]
+#[pyo3(signature = (dag, neighbor_table, distance_matrix, heuristic, max_iterations, num_swap_trials, num_random_trials, seed=None, partial_layouts=vec![]))]
 pub fn sabre_layout_and_routing(
     py: Python,
     dag: &SabreDAG,
@@ -36,20 +38,24 @@ pub fn sabre_layout_and_routing(
     heuristic: &Heuristic,
     max_iterations: usize,
     num_swap_trials: usize,
-    num_layout_trials: usize,
+    num_random_trials: usize,
     seed: Option<u64>,
+    mut partial_layouts: Vec<Vec<Option<u32>>>,
 ) -> (NLayout, PyObject, (SwapMap, PyObject, NodeBlockResults)) {
     let run_in_parallel = getenv_use_multiple_threads();
+    let mut starting_layouts: Vec<Vec<Option<u32>>> =
+        (0..num_random_trials).map(|_| vec![]).collect();
+    starting_layouts.append(&mut partial_layouts);
     let outer_rng = match seed {
         Some(seed) => Pcg64Mcg::seed_from_u64(seed),
         None => Pcg64Mcg::from_entropy(),
     };
     let seed_vec: Vec<u64> = outer_rng
         .sample_iter(&rand::distributions::Standard)
-        .take(num_layout_trials)
+        .take(starting_layouts.len())
         .collect();
     let dist = distance_matrix.as_array();
-    let res = if run_in_parallel && num_layout_trials > 1 {
+    let res = if run_in_parallel && starting_layouts.len() > 1 {
         seed_vec
             .into_par_iter()
             .enumerate()
@@ -65,6 +71,7 @@ pub fn sabre_layout_and_routing(
                         max_iterations,
                         num_swap_trials,
                         run_in_parallel,
+                        &starting_layouts[index],
                     ),
                 )
             })
@@ -79,7 +86,8 @@ pub fn sabre_layout_and_routing(
     } else {
         seed_vec
             .into_iter()
-            .map(|seed_trial| {
+            .enumerate()
+            .map(|(index, seed_trial)| {
                 layout_trial(
                     dag,
                     neighbor_table,
@@ -89,6 +97,7 @@ pub fn sabre_layout_and_routing(
                     max_iterations,
                     num_swap_trials,
                     run_in_parallel,
+                    &starting_layouts[index],
                 )
             })
             .min_by_key(|(_, _, result)| result.map.map.values().map(|x| x.len()).sum::<usize>())
@@ -114,15 +123,38 @@ fn layout_trial(
     max_iterations: usize,
     num_swap_trials: usize,
     run_swap_in_parallel: bool,
+    starting_layout: &[Option<u32>],
 ) -> (NLayout, Vec<PhysicalQubit>, SabreResult) {
     let num_physical_qubits: u32 = distance_matrix.shape()[0].try_into().unwrap();
     let mut rng = Pcg64Mcg::seed_from_u64(seed);
 
     // Pick a random initial layout including a full ancilla allocation.
     let mut initial_layout = {
-        let mut physical_qubits: Vec<PhysicalQubit> =
-            (0..num_physical_qubits).map(PhysicalQubit::new).collect();
-        physical_qubits.shuffle(&mut rng);
+        let physical_qubits: Vec<PhysicalQubit> = if !starting_layout.is_empty() {
+            let used_bits: HashSet<u32> = starting_layout
+                .iter()
+                .filter_map(|x| x.as_ref())
+                .copied()
+                .collect();
+            let mut free_bits: Vec<u32> = (0..num_physical_qubits)
+                .filter(|x| !used_bits.contains(x))
+                .collect();
+            free_bits.shuffle(&mut rng);
+            (0..num_physical_qubits)
+                .map(|x| {
+                    let bit_index = match starting_layout.get(x as usize) {
+                        Some(phys) => phys.unwrap_or_else(|| free_bits.pop().unwrap()),
+                        None => free_bits.pop().unwrap(),
+                    };
+                    PhysicalQubit::new(bit_index)
+                })
+                .collect()
+        } else {
+            let mut physical_qubits: Vec<PhysicalQubit> =
+                (0..num_physical_qubits).map(PhysicalQubit::new).collect();
+            physical_qubits.shuffle(&mut rng);
+            physical_qubits
+        };
         NLayout::from_virtual_to_physical(physical_qubits).unwrap()
     };
 
diff --git a/qiskit/circuit/classical/expr/__init__.py b/qiskit/circuit/classical/expr/__init__.py
index d0302aeb6..d2cd4bc50 100644
--- a/qiskit/circuit/classical/expr/__init__.py
+++ b/qiskit/circuit/classical/expr/__init__.py
@@ -104,6 +104,7 @@ Similarly, the binary operations and relations have helper functions defined.
 
 .. autofunction:: bit_and
 .. autofunction:: bit_or
+.. autofunction:: bit_xor
 .. autofunction:: logic_and
 .. autofunction:: logic_or
 .. autofunction:: equal
diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py
index f5f33fd85..f60223698 100644
--- a/qiskit/dagcircuit/dagcircuit.py
+++ b/qiskit/dagcircuit/dagcircuit.py
@@ -45,7 +45,6 @@ from qiskit.circuit.parameterexpression import ParameterExpression
 from qiskit.dagcircuit.exceptions import DAGCircuitError
 from qiskit.dagcircuit.dagnode import DAGNode, DAGOpNode, DAGInNode, DAGOutNode
 from qiskit.circuit.bit import Bit
-from qiskit.utils.deprecation import deprecate_func
 
 
 BitLocations = namedtuple("BitLocations", ("index", "registers"))
@@ -608,14 +607,6 @@ class DAGCircuit:
         else:
             self._op_names[op.name] -= 1
 
-    @deprecate_func(
-        additional_msg="Instead, use :meth:`~copy_empty_like()`, which acts identically.",
-        since="0.20.0",
-    )
-    def _copy_circuit_metadata(self):
-        """DEPRECATED"""
-        return self.copy_empty_like()
-
     def copy_empty_like(self):
         """Return a copy of self with the same structure but empty.
 
diff --git a/qiskit/opflow/operator_globals.py b/qiskit/opflow/operator_globals.py
index a5afcd9cf..ac0c624c7 100644
--- a/qiskit/opflow/operator_globals.py
+++ b/qiskit/opflow/operator_globals.py
@@ -14,6 +14,8 @@
 Operator Globals
 """
 
+import warnings
+
 from qiskit.quantum_info import Pauli
 from qiskit.circuit.library import CXGate, SGate, TGate, HGate, SwapGate, CZGate
 
@@ -48,22 +50,30 @@ def make_immutable(obj):
     return obj
 
 
-# 1-Qubit Paulis
-X = make_immutable(PauliOp(Pauli("X")))
-Y = make_immutable(PauliOp(Pauli("Y")))
-Z = make_immutable(PauliOp(Pauli("Z")))
-I = make_immutable(PauliOp(Pauli("I")))
+# All the deprecation warnings triggered by these object creations correctly blame `qiskit.opflow`
+# and so are not shown to users by default. However, since they are eagerly triggered at `import
+# qiskit.opflow`, they obscure the one "true" warning of the import when downstream testing code is
+# running with all warnings showing.  The true warning that really needs attention becomes easy to
+# overlook because there's so many that the downstream code didn't explicitly call.
+with warnings.catch_warnings():
+    warnings.filterwarnings("ignore", category=DeprecationWarning, module=r"qiskit\.opflow\.")
+
+    # 1-Qubit Paulis
+    X = make_immutable(PauliOp(Pauli("X")))
+    Y = make_immutable(PauliOp(Pauli("Y")))
+    Z = make_immutable(PauliOp(Pauli("Z")))
+    I = make_immutable(PauliOp(Pauli("I")))
 
-# Clifford+T, and some other common non-parameterized gates
-CX = make_immutable(CircuitOp(CXGate()))
-S = make_immutable(CircuitOp(SGate()))
-H = make_immutable(CircuitOp(HGate()))
-T = make_immutable(CircuitOp(TGate()))
-Swap = make_immutable(CircuitOp(SwapGate()))
-CZ = make_immutable(CircuitOp(CZGate()))
+    # Clifford+T, and some other common non-parameterized gates
+    CX = make_immutable(CircuitOp(CXGate()))
+    S = make_immutable(CircuitOp(SGate()))
+    H = make_immutable(CircuitOp(HGate()))
+    T = make_immutable(CircuitOp(TGate()))
+    Swap = make_immutable(CircuitOp(SwapGate()))
+    CZ = make_immutable(CircuitOp(CZGate()))
 
-# 1-Qubit states
-Zero = make_immutable(DictStateFn("0"))
-One = make_immutable(DictStateFn("1"))
-Plus = make_immutable(H.compose(Zero))
-Minus = make_immutable(H.compose(X).compose(Zero))
+    # 1-Qubit states
+    Zero = make_immutable(DictStateFn("0"))
+    One = make_immutable(DictStateFn("1"))
+    Plus = make_immutable(H.compose(Zero))
+    Minus = make_immutable(H.compose(X).compose(Zero))
diff --git a/qiskit/synthesis/evolution/suzuki_trotter.py b/qiskit/synthesis/evolution/suzuki_trotter.py
index b8dd766c3..43c7d0e79 100644
--- a/qiskit/synthesis/evolution/suzuki_trotter.py
+++ b/qiskit/synthesis/evolution/suzuki_trotter.py
@@ -18,7 +18,7 @@ import numpy as np
 
 from qiskit.circuit.quantumcircuit import QuantumCircuit
 from qiskit.quantum_info.operators import SparsePauliOp, Pauli
-from qiskit.utils.deprecation import deprecate_arg
+
 
 from .product_formula import ProductFormula
 
@@ -51,17 +51,6 @@ class SuzukiTrotter(ProductFormula):
         `arXiv:math-ph/0506007 <https://arxiv.org/pdf/math-ph/0506007.pdf>`_
     """
 
-    @deprecate_arg(
-        "order",
-        deprecation_description=(
-            "Setting `order` to an odd number in the constructor of SuzukiTrotter"
-        ),
-        additional_msg=(
-            "Suzuki product formulae are symmetric and therefore only defined for even orders."
-        ),
-        since="0.20.0",
-        predicate=lambda order: order % 2 == 1,
-    )
     def __init__(
         self,
         order: int = 2,
@@ -83,11 +72,15 @@ class SuzukiTrotter(ProductFormula):
             atomic_evolution: A function to construct the circuit for the evolution of single
                 Pauli string. Per default, a single Pauli evolution is decomposed in a CX chain
                 and a single qubit Z rotation.
+        Raises:
+            ValueError: If order is not even
         """
-        # TODO replace deprecation warning by the following error and add unit test for odd
-        # if order % 2 == 1:
-        #   raise ValueError("Suzuki product formulae are symmetric and therefore only defined "
-        #                  "for even orders.")
+
+        if order % 2 == 1:
+            raise ValueError(
+                "Suzuki product formulae are symmetric and therefore only defined "
+                "for even orders."
+            )
         super().__init__(order, reps, insert_barriers, cx_structure, atomic_evolution)
 
     def synthesize(self, evolution):
diff --git a/qiskit/transpiler/coupling.py b/qiskit/transpiler/coupling.py
index 903341d1f..774f79329 100644
--- a/qiskit/transpiler/coupling.py
+++ b/qiskit/transpiler/coupling.py
@@ -27,7 +27,6 @@ import rustworkx as rx
 from rustworkx.visualization import graphviz_draw
 
 from qiskit.transpiler.exceptions import CouplingError
-from qiskit.utils.deprecation import deprecate_func
 
 
 class CouplingMap:
@@ -125,21 +124,6 @@ class CouplingMap:
         self._dist_matrix = None  # invalidate
         self._is_symmetric = None  # invalidate
 
-    @deprecate_func(
-        additional_msg=(
-            "Instead, use :meth:`~reduce`. It does the same thing, but preserves nodelist order."
-        ),
-        since="0.20.0",
-    )
-    def subgraph(self, nodelist):
-        """Return a CouplingMap object for a subgraph of self.
-
-        nodelist (list): list of integer node labels
-        """
-        subcoupling = CouplingMap()
-        subcoupling.graph = self.graph.subgraph(nodelist)
-        return subcoupling
-
     @property
     def physical_qubits(self):
         """Returns a sorted list of physical_qubits"""
diff --git a/qiskit/transpiler/passes/layout/sabre_layout.py b/qiskit/transpiler/passes/layout/sabre_layout.py
index 6e521c05d..62af8fd57 100644
--- a/qiskit/transpiler/passes/layout/sabre_layout.py
+++ b/qiskit/transpiler/passes/layout/sabre_layout.py
@@ -16,6 +16,7 @@
 import copy
 import dataclasses
 import logging
+import functools
 import time
 
 import numpy as np
@@ -74,6 +75,34 @@ class SabreLayout(TransformationPass):
     layout pass. When specified this will use the specified routing pass to select an
     initial layout only and will not run multiple seed trials.
 
+    In addition to starting with a random initial `Layout` the pass can also take in
+    an additional list of starting layouts which will be used for additional
+    trials. If the ``sabre_starting_layouts`` is present in the property set
+    when this pass is run, that will be used for additional trials. There will still
+    be ``layout_trials`` of full random starting layouts run and the contents of
+    ``sabre_starting_layouts`` will be run in addition to those. The output which results
+    in the lowest amount of swap gates (whether from the random trials or the property
+    set starting point) will be used. The value for this property set field should be a
+    list of :class:`.Layout` objects representing the starting layouts to use. If a
+    virtual qubit is missing from an :class:`.Layout` object in the list a random qubit
+    will be selected.
+
+    Property Set Fields Read
+    ------------------------
+
+    ``sabre_starting_layouts`` (``list[Layout]``)
+        An optional list of :class:`~.Layout` objects to use for additional layout trials. This is
+        in addition to the full random trials specified with the ``layout_trials`` argument.
+
+    Property Set Values Written
+    ---------------------------
+
+    ``layout`` (:class:`.Layout`)
+        The chosen initial mapping of virtual to physical qubits, including the ancilla allocation.
+
+    ``final_layout`` (:class:`.Layout`)
+        A permutation of how swaps have been applied to the input qubits at the end of the circuit.
+
     **References:**
 
     [1] Li, Gushu, Yufei Ding, and Yuan Xie. "Tackling the qubit mapping problem
@@ -232,8 +261,12 @@ class SabreLayout(TransformationPass):
             target.make_symmetric()
         else:
             target = self.coupling_map
-
-        components = disjoint_utils.run_pass_over_connected_components(dag, target, self._inner_run)
+        inner_run = self._inner_run
+        if "sabre_starting_layouts" in self.property_set:
+            inner_run = functools.partial(
+                self._inner_run, starting_layouts=self.property_set["sabre_starting_layouts"]
+            )
+        components = disjoint_utils.run_pass_over_connected_components(dag, target, inner_run)
         self.property_set["layout"] = Layout(
             {
                 component.dag.qubits[logic]: component.coupling_map.graph[phys]
@@ -314,7 +347,7 @@ class SabreLayout(TransformationPass):
         disjoint_utils.combine_barriers(mapped_dag, retain_uuid=False)
         return mapped_dag
 
-    def _inner_run(self, dag, coupling_map):
+    def _inner_run(self, dag, coupling_map, starting_layouts=None):
         if not coupling_map.is_symmetric:
             # deepcopy is needed here to avoid modifications updating
             # shared references in passes which require directional
@@ -323,8 +356,26 @@ class SabreLayout(TransformationPass):
             coupling_map.make_symmetric()
         neighbor_table = NeighborTable(rx.adjacency_matrix(coupling_map.graph))
         dist_matrix = coupling_map.distance_matrix
+        original_qubit_indices = {bit: index for index, bit in enumerate(dag.qubits)}
+        partial_layouts = []
+        if starting_layouts is not None:
+            coupling_map_reverse_mapping = {
+                coupling_map.graph[x]: x for x in coupling_map.graph.node_indices()
+            }
+            for layout in starting_layouts:
+                virtual_bits = layout.get_virtual_bits()
+                out_layout = [None] * len(dag.qubits)
+                for bit, phys in virtual_bits.items():
+                    pos = original_qubit_indices.get(bit, None)
+                    if pos is None:
+                        continue
+                    out_layout[pos] = coupling_map_reverse_mapping[phys]
+                partial_layouts.append(out_layout)
+
         sabre_dag, circuit_to_dag_dict = _build_sabre_dag(
-            dag, coupling_map.size(), {bit: index for index, bit in enumerate(dag.qubits)}
+            dag,
+            coupling_map.size(),
+            original_qubit_indices,
         )
         sabre_start = time.perf_counter()
         (initial_layout, final_permutation, sabre_result) = sabre_layout_and_routing(
@@ -336,6 +387,7 @@ class SabreLayout(TransformationPass):
             self.swap_trials,
             self.layout_trials,
             self.seed,
+            partial_layouts,
         )
         sabre_stop = time.perf_counter()
         logger.debug(
diff --git a/qiskit/transpiler/passes/utils/gate_direction.py b/qiskit/transpiler/passes/utils/gate_direction.py
index 262538a2f..a259106d3 100644
--- a/qiskit/transpiler/passes/utils/gate_direction.py
+++ b/qiskit/transpiler/passes/utils/gate_direction.py
@@ -60,6 +60,10 @@ class GateDirection(TransformationPass):
              │  RZX │  =       ├───┤│  RZX │├───┤
         q_1: ┤1     ├     q_1: ┤ H ├┤0     ├┤ H ├
              └──────┘          └───┘└──────┘└───┘
+
+    This pass assumes that the positions of the qubits in the :attr:`.DAGCircuit.qubits` attribute
+    are the physical qubit indicies. For example if ``dag.qubits[0]`` is qubit 0 in the
+    :class:`.CouplingMap` or :class:`.Target`.
     """
 
     _KNOWN_REPLACEMENTS = frozenset(["cx", "cz", "ecr", "swap", "rzx", "rxx", "ryy", "rzz"])
@@ -325,11 +329,6 @@ class GateDirection(TransformationPass):
                 cx nodes.
         """
         layout_map = {bit: i for i, bit in enumerate(dag.qubits)}
-        if len(dag.qregs) > 1:
-            raise TranspilerError(
-                "GateDirection expects a single qreg input DAG,"
-                "but input DAG had qregs: {}.".format(dag.qregs)
-            )
         if self.target is None:
             return self._run_coupling_map(dag, layout_map)
         return self._run_target(dag, layout_map)
diff --git a/qiskit/visualization/circuit/latex.py b/qiskit/visualization/circuit/latex.py
index 67a6afe38..66e172b1e 100644
--- a/qiskit/visualization/circuit/latex.py
+++ b/qiskit/visualization/circuit/latex.py
@@ -19,13 +19,13 @@ import re
 from warnings import warn
 
 import numpy as np
-from qiskit.circuit import Clbit, Qubit, ClassicalRegister, QuantumRegister, QuantumCircuit
+from qiskit.circuit import Clbit, Qubit, ClassicalRegister
 from qiskit.circuit.classical import expr
 from qiskit.circuit.controlledgate import ControlledGate
 from qiskit.circuit.library.standard_gates import SwapGate, XGate, ZGate, RZZGate, U1Gate, PhaseGate
 from qiskit.circuit.measure import Measure
 from qiskit.circuit.tools.pi_check import pi_check
-from qiskit.utils.deprecation import deprecate_arg
+
 
 from .qcstyle import load_style
 from ._utils import (
@@ -49,10 +49,6 @@ class QCircuitImage:
     Thanks to Eric Sabo for the initial implementation for Qiskit.
     """
 
-    @deprecate_arg("gregs", since="0.20.0")
-    @deprecate_arg("cregs", since="0.20.0")
-    @deprecate_arg("layout", since="0.20.0")
-    @deprecate_arg("global_phase", since="0.20.0")
     def __init__(  # pylint: disable=bad-docstring-quotes
         self,
         qubits,
@@ -62,12 +58,8 @@ class QCircuitImage:
         style=None,
         reverse_bits=False,
         plot_barriers=True,
-        layout=None,
         initial_state=False,
         cregbundle=None,
-        global_phase=None,
-        qregs=None,
-        cregs=None,
         with_layout=False,
         circuit=None,
     ):
@@ -82,36 +74,14 @@ class QCircuitImage:
             reverse_bits (bool): when True, reverse the bit ordering of the registers
             plot_barriers (bool): Enable/disable drawing barriers in the output
                circuit. Defaults to True.
-            layout (Layout or None): If present, the layout information will be
-               included.
             initial_state (bool): Optional. Adds |0> in the beginning of the line. Default: `False`.
             cregbundle (bool): Optional. If set True bundle classical registers.
-            global_phase (float): Optional, the global phase for the circuit.
             circuit (QuantumCircuit): the circuit that's being displayed
         Raises:
             ImportError: If pylatexenc is not installed
         """
-        del layout
-        del global_phase
-        # This check should be removed when the 4 deprecations above are removed
-        if circuit is None:
-            warn(
-                "The 'circuit' kwarg to the QCircuitImage class must be a valid "
-                "QuantumCircuit and not None. A new circuit is being created using "
-                "the qubits and clbits for rendering the drawing.",
-                DeprecationWarning,
-                2,
-            )
-            circ = QuantumCircuit(qubits, clbits)
-            for reg in qregs or []:
-                bits = [qubits[circ._qubit_indices[q].index] for q in reg]
-                circ.add_register(QuantumRegister(None, reg.name, list(bits)))
-            for reg in cregs or []:
-                bits = [clbits[circ._clbit_indices[q].index] for q in reg]
-                circ.add_register(ClassicalRegister(None, reg.name, list(bits)))
-            self._circuit = circ
-        else:
-            self._circuit = circuit
+
+        self._circuit = circuit
         self._qubits = qubits
         self._clbits = clbits
 
diff --git a/releasenotes/notes/fix-gate-direction-d8bc96b62b27dba8.yaml b/releasenotes/notes/fix-gate-direction-d8bc96b62b27dba8.yaml
new file mode 100644
index 000000000..54d29206c
--- /dev/null
+++ b/releasenotes/notes/fix-gate-direction-d8bc96b62b27dba8.yaml
@@ -0,0 +1,7 @@
+---
+fixes:
+  - |
+    Fixes a bug with the :class:`.GateDirection` transpiler pass where it
+    unnecessarily raised an exception for input DAGs with more than 1
+    quantum register.
+    Fixed `#10824 <https://github.com/Qiskit/qiskit/issues/10824>`__.
diff --git a/releasenotes/notes/removed_deprecation_0.20-17b0ea6a3980eb4f.yaml b/releasenotes/notes/removed_deprecation_0.20-17b0ea6a3980eb4f.yaml
new file mode 100644
index 000000000..e5a6faff0
--- /dev/null
+++ b/releasenotes/notes/removed_deprecation_0.20-17b0ea6a3980eb4f.yaml
@@ -0,0 +1,18 @@
+---
+upgrade:
+  - |
+    The class constructor arguments `qregs`, `cregs`, 
+    `layout` and `global_phase` for :class:`.visualization.QCircuitImage`
+    are removed, as they were deprecated in 0.20.
+    
+  - |
+    In :class:`.transpiler.CouplingMap` method `subgraph` is removed
+    as deprecated in 0.20. :meth:`~reduce` can be used in place of method `subgraph`.
+  
+  - |
+    The parameter `order` in :class:`.synthesis.SuzukiTrotter`
+    constructor raises an exception instead of deprecation warning when
+    set in an odd number. Suzuki product formulae are symmetric and
+    therefore only defined for even orders.
+      
+    
\ No newline at end of file
diff --git a/releasenotes/notes/seed-sabre-with-layout-17d46e1a6f516b0e.yaml b/releasenotes/notes/seed-sabre-with-layout-17d46e1a6f516b0e.yaml
new file mode 100644
index 000000000..fa6a12b9c
--- /dev/null
+++ b/releasenotes/notes/seed-sabre-with-layout-17d46e1a6f516b0e.yaml
@@ -0,0 +1,38 @@
+---
+features:
+  - |
+    Added support to the :class:`.SabreLayout` pass to add trials with specified
+    starting layouts. The :class:`.SabreLayout` transpiler pass typically
+    runs multiple layout trials that all start with fully random layouts which
+    then use a routing pass to permute that layout instead of inserting swaps
+    to find a layout which will result in fewer swap gates. This new feature
+    enables running an :class:`.AnalysisPass` prior to :class:`.SabreLayout`
+    which sets the ``"sabre_starting_layout"`` field in the property set
+    to provide the :class:`.SabreLayout` with additional starting layouts
+    to use in its internal trials. For example, if you wanted to run
+    :class:`.DenseLayout` as the starting point for one trial in
+    :class:`.SabreLayout` you would do something like::
+
+        from qiskit.providers.fake_provider import FakeSherbrooke
+        from qiskit.transpiler import AnalysisPass, PassManager
+        from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
+        from qiskit.transpiler.passes import DenseLayout
+
+        class SabreDenseLayoutTrial(AnalysisPass):
+
+          def __init__(self, target):
+              self.dense_pass = DenseLayout(target=target)
+              super().__init__()
+
+          def run(self, dag):
+              self.dense_pass.run(dag)
+              self.property_set["sabre_starting_layouts"] = [self.dense_pass.property_set["layout"]]
+
+        backend = FakeSherbrooke()
+        opt_level_1 = generate_preset_pass_manager(1, backend)
+        pre_layout = PassManager([SabreDenseLayoutTrial(backend.target)])
+        opt_level_1.pre_layout = pre_layout
+
+    Then when the ``opt_level_1`` :class:`.StagedPassManager` is run with a circuit the output
+    of the :class:`.DenseLayout` pass will be used for one of the :class:`.SabreLayout` trials
+    in addition to the 5 fully random trials that run by default in optimization level 1.


Test patch:
diff --git a/test/python/dagcircuit/test_dagcircuit.py b/test/python/dagcircuit/test_dagcircuit.py
index 02df668c0..7f7375178 100644
--- a/test/python/dagcircuit/test_dagcircuit.py
+++ b/test/python/dagcircuit/test_dagcircuit.py
@@ -410,7 +410,7 @@ class TestDagWireRemoval(QiskitTestCase):
         self.assert_cregs_equal(self.original_cregs)
         self.assert_clbits_equal(self.original_clbits, excluding={self.individual_clbit})
 
-    def test_copy_circuit_metadata(self):
+    def test_copy_empty_like(self):
         """Copy dag circuit metadata with copy_empty_like."""
         result_dag = self.dag.copy_empty_like()
         self.assertEqual(self.dag.name, result_dag.name)
diff --git a/test/python/transpiler/test_coupling.py b/test/python/transpiler/test_coupling.py
index f573d9abc..7c75e309c 100644
--- a/test/python/transpiler/test_coupling.py
+++ b/test/python/transpiler/test_coupling.py
@@ -442,16 +442,6 @@ class CouplingTest(QiskitTestCase):
         ]
         self.assertEqual(set(edges), set(expected))
 
-    def test_subgraph(self):
-        coupling = CouplingMap.from_line(6, bidirectional=False)
-        with self.assertWarns(DeprecationWarning):
-            subgraph = coupling.subgraph([4, 2, 3, 5])
-        self.assertEqual(subgraph.size(), 4)
-        self.assertEqual([0, 1, 2, 3], subgraph.physical_qubits)
-        edge_list = subgraph.get_edges()
-        expected = [(0, 1), (1, 2), (2, 3)]
-        self.assertEqual(expected, edge_list, f"{edge_list} does not match {expected}")
-
     def test_implements_iter(self):
         """Test that the object is implicitly iterable."""
         coupling = CouplingMap.from_line(3)
diff --git a/test/python/transpiler/test_gate_direction.py b/test/python/transpiler/test_gate_direction.py
index a45568efd..ef23ea53f 100644
--- a/test/python/transpiler/test_gate_direction.py
+++ b/test/python/transpiler/test_gate_direction.py
@@ -101,6 +101,26 @@ class TestGateDirection(QiskitTestCase):
 
         self.assertEqual(dag, after)
 
+    def test_multi_register(self):
+        """The CX is in the right direction
+        qr0:---(+)---
+                |
+        qr1:----.----
+
+        CouplingMap map: [0] -> [1]
+        """
+        qr1 = QuantumRegister(1, "qr1")
+        qr2 = QuantumRegister(1, "qr2")
+        circuit = QuantumCircuit(qr1, qr2)
+        circuit.cx(qr1, qr2)
+        coupling = CouplingMap([[0, 1]])
+        dag = circuit_to_dag(circuit)
+
+        pass_ = GateDirection(coupling)
+        after = pass_.run(dag)
+
+        self.assertEqual(dag, after)
+
     def test_direction_flip(self):
         """Flip a CX
         qr0:----.----
diff --git a/test/python/transpiler/test_sabre_layout.py b/test/python/transpiler/test_sabre_layout.py
index ff9788521..38c17b442 100644
--- a/test/python/transpiler/test_sabre_layout.py
+++ b/test/python/transpiler/test_sabre_layout.py
@@ -15,8 +15,8 @@
 import unittest
 
 from qiskit import QuantumRegister, QuantumCircuit
-from qiskit.transpiler import CouplingMap
-from qiskit.transpiler.passes import SabreLayout
+from qiskit.transpiler import CouplingMap, AnalysisPass, PassManager
+from qiskit.transpiler.passes import SabreLayout, DenseLayout
 from qiskit.transpiler.exceptions import TranspilerError
 from qiskit.converters import circuit_to_dag
 from qiskit.test import QiskitTestCase
@@ -94,6 +94,41 @@ class TestSabreLayout(QiskitTestCase):
         layout = pass_.property_set["layout"]
         self.assertEqual([layout[q] for q in circuit.qubits], [7, 8, 12, 6, 11, 13])
 
+    def test_6q_circuit_20q_coupling_with_partial(self):
+        """Test finds layout for 6q circuit on 20q device."""
+        #       ┌───┐┌───┐┌───┐┌───┐┌───┐
+        # q0_0: ┤ X ├┤ X ├┤ X ├┤ X ├┤ X ├
+        #       └─┬─┘└─┬─┘└─┬─┘└─┬─┘└─┬─┘
+        # q0_1: ──┼────■────┼────┼────┼──
+        #         │  ┌───┐  │    │    │
+        # q0_2: ──┼──┤ X ├──┼────■────┼──
+        #         │  └───┘  │         │
+        # q1_0: ──■─────────┼─────────┼──
+        #            ┌───┐  │         │
+        # q1_1: ─────┤ X ├──┼─────────■──
+        #            └───┘  │
+        # q1_2: ────────────■────────────
+        qr0 = QuantumRegister(3, "q0")
+        qr1 = QuantumRegister(3, "q1")
+        circuit = QuantumCircuit(qr0, qr1)
+        circuit.cx(qr1[0], qr0[0])
+        circuit.cx(qr0[1], qr0[0])
+        circuit.cx(qr1[2], qr0[0])
+        circuit.x(qr0[2])
+        circuit.cx(qr0[2], qr0[0])
+        circuit.x(qr1[1])
+        circuit.cx(qr1[1], qr0[0])
+
+        pm = PassManager(
+            [
+                DensePartialSabreTrial(CouplingMap(self.cmap20)),
+                SabreLayout(CouplingMap(self.cmap20), seed=0, swap_trials=32, layout_trials=0),
+            ]
+        )
+        pm.run(circuit)
+        layout = pm.property_set["layout"]
+        self.assertEqual([layout[q] for q in circuit.qubits], [1, 3, 5, 2, 6, 0])
+
     def test_6q_circuit_20q_coupling_with_target(self):
         """Test finds layout for 6q circuit on 20q device."""
         #       ┌───┐┌───┐┌───┐┌───┐┌───┐
@@ -218,6 +253,18 @@ barrier q18585[5],q18585[2],q18585[8],q18585[3],q18585[6];
         )
 
 
+class DensePartialSabreTrial(AnalysisPass):
+    """Pass to run dense layout as a sabre trial."""
+
+    def __init__(self, cmap):
+        self.dense_pass = DenseLayout(cmap)
+        super().__init__()
+
+    def run(self, dag):
+        self.dense_pass.run(dag)
+        self.property_set["sabre_starting_layouts"] = [self.dense_pass.property_set["layout"]]
+
+
 class TestDisjointDeviceSabreLayout(QiskitTestCase):
     """Test SabreLayout with a disjoint coupling map."""
 
@@ -319,6 +366,28 @@ class TestDisjointDeviceSabreLayout(QiskitTestCase):
         with self.assertRaises(TranspilerError):
             layout_routing_pass(qc)
 
+    def test_with_partial_layout(self):
+        """Test a partial layout with a disjoint connectivity graph."""
+        qc = QuantumCircuit(8, name="double dhz")
+        qc.h(0)
+        qc.cz(0, 1)
+        qc.cz(0, 2)
+        qc.h(3)
+        qc.cx(3, 4)
+        qc.cx(3, 5)
+        qc.cx(3, 6)
+        qc.cx(3, 7)
+        qc.measure_all()
+        pm = PassManager(
+            [
+                DensePartialSabreTrial(self.dual_grid_cmap),
+                SabreLayout(self.dual_grid_cmap, seed=123456, swap_trials=1, layout_trials=1),
+            ]
+        )
+        pm.run(qc)
+        layout = pm.property_set["layout"]
+        self.assertEqual([layout[q] for q in qc.qubits], [3, 1, 2, 5, 4, 6, 7, 8])
+
 
 if __name__ == "__main__":
     unittest.main()