Switch DAGCircuit wires property to a set instead of a list (#3934)
Switch DAGCircuit wires property to a set instead of a list (#3934)

* Switch DAGCircuit wires property to a set instead of a list

Right now the wires property of a DAGCircuit object is a list, however
the way the property is used there is no need for ordering. Instead how
it's mostly used is to check if a wire is already a member of the list
and to iterate over it. None of these require wires to be a list and
using a list means the membership check is expensive especially for
larger qubit counts since 'x in list()' is O(n) as it has to iterate
over the list. Switching to a set() makes this O(1) (in the normal case)
because it just checks the hash of the object.

* Use OrderedSet instead of set

This commit pivots from set to OrderedSet because the wires property
needs to maintain insertion ordering. We still get the benefits of the
O(1) lookup from set but because it uses a list internally we also keep
the insertion order.

* Switch from ordered set back to set() with a property

This commit stop using OrderedSet because we can achieve similar
performance without an external dependency. Instead it changes wires to
be a private attribute and makes a property wires() which will return a
sorted bit list. This way we get the benefits of lookup time inside
of a dagcircuit object but when something outside needs an ordered list
of bits they can continue using the property as today.

* Preserve insertion order instead of canonical sort

For the output of the wires property we need to preserve the insertion
order instead of returning the sorted order. The insertion order is
preserved via qargs and cargs so this just leverages those to return a
sorted order instead of trying to preserve ordering via the _wires
attribute directly.

* Remove unecessary extra traversal on substitue_node_with_dag

Currently the substitute_node_with_dag method unecessarily traveres the
wire list twice to generate a list of quantum wires and classical wires
only to combine them in a single list right after. As the number of bits
in a circuit grows this gets increasingly expensive since we're running
isinstance 2*number of bits times when we never need to run it.

* Fix lint

Co-authored-by: Kevin Krsulich <78cdb98aeddd45630046ff39f0a19d75c82aaaa7@ibm.com>
QISKit/qiskit-sdk-py,QISKit/qiskit-sdk-py,QISKit/qiskit-sdk-py