prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Implement equality for CircuitDag
  Implement `__eq__` for CircuitDag using `networkx.is_isomorphic()`.  Use the node_match argument of is_isomorphic: `node_match=lambda n: n.val`.
  
  This may be useful for #830.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `cirq/circuits/circuit_dag.py`
  Content:
  ```
  1 # Copyright 2018 The ops Developers
  2 #
  3 # Licensed under the Apache License, Version 2.0 (the "License");
  4 # you may not use this file except in compliance with the License.
  5 # You may obtain a copy of the License at
  6 #
  7 #     https://www.apache.org/licenses/LICENSE-2.0
  8 #
  9 # Unless required by applicable law or agreed to in writing, software
  10 # distributed under the License is distributed on an "AS IS" BASIS,
  11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 # See the License for the specific language governing permissions and
  13 # limitations under the License.
  14 
  15 from typing import Any, Callable, Generic, Iterator, TypeVar
  16 
  17 import networkx
  18 
  19 from cirq import ops, devices
  20 from cirq.circuits import circuit
  21 
  22 
  23 T = TypeVar('T')
  24 
  25 class Unique(Generic[T]):
  26     """A wrapper for a value that doesn't compare equal to other instances.
  27 
  28     For example: 5 == 5 but Unique(5) != Unique(5).
  29 
  30     Unique is used by CircuitDag to wrap operations because nodes in a graph
  31     are considered the same node if they compare equal to each other.  X(q0)
  32     in one moment of a Circuit and X(q0) in another moment of the Circuit are
  33     wrapped by Unique(X(q0)) so they are distinct nodes in the graph.
  34     """
  35     def __init__(self, val: T) -> None:
  36         self.val = val
  37 
  38     def __repr__(self):
  39         return 'Unique({}, {!r})'.format(id(self), self.val)
  40 
  41 
  42 def _disjoint_qubits(op1: ops.Operation, op2: ops.Operation) -> bool:
  43     """Returns true only if the operations have qubits in common."""
  44     return not set(op1.qubits) & set(op2.qubits)
  45 
  46 
  47 class CircuitDag(networkx.DiGraph):
  48     """A representation of a Circuit as a directed acyclic graph.
  49 
  50     Nodes of the graph are instances of Unique containing each operation of a
  51     circuit.
  52 
  53     Edges of the graph are tuples of nodes.  Each edge specifies a required
  54     application order between two operations.  The first must be applied before
  55     the second.
  56 
  57     The graph is maximalist (transitive completion).
  58     """
  59 
  60     disjoint_qubits = staticmethod(_disjoint_qubits)
  61 
  62     def __init__(self,
  63                  can_reorder: Callable[[ops.Operation, ops.Operation],
  64                                        bool] = _disjoint_qubits,
  65                  incoming_graph_data: Any = None,
  66                  device: devices.Device = devices.UnconstrainedDevice
  67                  ) -> None:
  68         """Initializes a CircuitDag.
  69 
  70         Args:
  71             can_reorder: A predicate that determines if two operations may be
  72                 reordered.  Graph edges are created for pairs of operations
  73                 where this returns False.
  74 
  75                 The default predicate allows reordering only when the operations
  76                 don't share common qubits.
  77             incoming_graph_data: Data in initialize the graph.  This can be any
  78                 value supported by networkx.DiGraph() e.g. an edge list or
  79                 another graph.
  80             device: Hardware that the circuit should be able to run on.
  81         """
  82         super().__init__(incoming_graph_data)
  83         self.can_reorder = can_reorder
  84         self.device = device
  85 
  86     @staticmethod
  87     def make_node(op: ops.Operation) -> Unique:
  88         return Unique(op)
  89 
  90     @staticmethod
  91     def from_circuit(circuit: circuit.Circuit,
  92                      can_reorder: Callable[[ops.Operation, ops.Operation],
  93                                            bool] = _disjoint_qubits
  94                      ) -> 'CircuitDag':
  95         return CircuitDag.from_ops(circuit.all_operations(),
  96                                    can_reorder=can_reorder,
  97                                    device=circuit.device)
  98 
  99     @staticmethod
  100     def from_ops(*operations: ops.OP_TREE,
  101                  can_reorder: Callable[[ops.Operation, ops.Operation],
  102                                        bool] = _disjoint_qubits,
  103                  device: devices.Device = devices.UnconstrainedDevice
  104                  ) -> 'CircuitDag':
  105         dag = CircuitDag(can_reorder=can_reorder, device=device)
  106         for op in ops.flatten_op_tree(operations):
  107             dag.append(op)
  108         return dag
  109 
  110     def append(self, op: ops.Operation) -> None:
  111         new_node = self.make_node(op)
  112         self.add_edges_from([(node, new_node)
  113                              for node in self.nodes
  114                              if not self.can_reorder(node.val, new_node.val)])
  115         self.add_node(new_node)
  116 
  117     def ordered_nodes(self) -> Iterator[Unique[ops.Operation]]:
  118         if not self.nodes:
  119             return
  120         g = self.copy()
  121 
  122         def get_root_node(some_node: Unique[ops.Operation]
  123                           ) -> Unique[ops.Operation]:
  124             pred = g.pred
  125             while pred[some_node]:
  126                 some_node = next(iter(pred[some_node]))
  127             return some_node
  128 
  129         def get_first_node() -> Unique[ops.Operation]:
  130             return get_root_node(next(iter(g.nodes)))
  131 
  132         def get_next_node(succ: networkx.classes.coreviews.AtlasView
  133                           ) -> Unique[ops.Operation]:
  134             if succ:
  135                 return get_root_node(next(iter(succ)))
  136             else:
  137                 return get_first_node()
  138 
  139         node = get_first_node()
  140         while True:
  141             yield node
  142             succ = g.succ[node]
  143             g.remove_node(node)
  144 
  145             if not g.nodes:
  146                 return
  147 
  148             node = get_next_node(succ)
  149 
  150     def all_operations(self) -> Iterator[ops.Operation]:
  151         return (node.val for node in self.ordered_nodes())
  152 
  153     def to_circuit(self) -> circuit.Circuit:
  154         return circuit.Circuit.from_ops(
  155                     self.all_operations(),
  156                     strategy=circuit.InsertStrategy.EARLIEST,
  157                     device=self.device)
  158
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/cirq/circuits/circuit_dag.py b/cirq/circuits/circuit_dag.py
  --- a/cirq/circuits/circuit_dag.py
  +++ b/cirq/circuits/circuit_dag.py
  @@ -12,8 +12,9 @@
   # See the License for the specific language governing permissions and
   # limitations under the License.
   
  -from typing import Any, Callable, Generic, Iterator, TypeVar
  +from typing import Any, Callable, Dict, Generic, Iterator, TypeVar
   
  +import functools
   import networkx
   
   from cirq import ops, devices
  @@ -22,6 +23,7 @@
   
   T = TypeVar('T')
   
  +@functools.total_ordering
   class Unique(Generic[T]):
       """A wrapper for a value that doesn't compare equal to other instances.
   
  @@ -38,6 +40,11 @@
       def __repr__(self):
           return 'Unique({}, {!r})'.format(id(self), self.val)
   
  +    def __lt__(self, other):
  +        if not isinstance(other, type(self)):
  +            return NotImplemented
  +        return id(self) < id(other)
  +
   
   def _disjoint_qubits(op1: ops.Operation, op2: ops.Operation) -> bool:
       """Returns true only if the operations have qubits in common."""
  @@ -114,6 +121,24 @@
                                if not self.can_reorder(node.val, new_node.val)])
           self.add_node(new_node)
   
  +    def __eq__(self, other):
  +        if not isinstance(other, type(self)):
  +            return NotImplemented
  +        g1 = self.copy()
  +        g2 = other.copy()
  +        for node, attr in g1.nodes.items():
  +            attr['val'] = node.val
  +        for node, attr in g2.nodes.items():
  +            attr['val'] = node.val
  +        def node_match(attr1: Dict[Any, Any], attr2: Dict[Any, Any]) -> bool:
  +            return attr1['val'] == attr2['val']
  +        return networkx.is_isomorphic(g1, g2, node_match=node_match)
  +
  +    def __ne__(self, other):
  +        return not self == other
  +
  +    __hash__ = None  # type: ignore
  +
       def ordered_nodes(self) -> Iterator[Unique[ops.Operation]]:
           if not self.nodes:
               return
  
verification_info: {"golden_diff": "diff --git a/cirq/circuits/circuit_dag.py b/cirq/circuits/circuit_dag.py\n--- a/cirq/circuits/circuit_dag.py\n+++ b/cirq/circuits/circuit_dag.py\n@@ -12,8 +12,9 @@\n # See the License for the specific language governing permissions and\n # limitations under the License.\n \n-from typing import Any, Callable, Generic, Iterator, TypeVar\n+from typing import Any, Callable, Dict, Generic, Iterator, TypeVar\n \n+import functools\n import networkx\n \n from cirq import ops, devices\n@@ -22,6 +23,7 @@\n \n T = TypeVar('T')\n \n+@functools.total_ordering\n class Unique(Generic[T]):\n     \"\"\"A wrapper for a value that doesn't compare equal to other instances.\n \n@@ -38,6 +40,11 @@\n     def __repr__(self):\n         return 'Unique({}, {!r})'.format(id(self), self.val)\n \n+    def __lt__(self, other):\n+        if not isinstance(other, type(self)):\n+            return NotImplemented\n+        return id(self) < id(other)\n+\n \n def _disjoint_qubits(op1: ops.Operation, op2: ops.Operation) -> bool:\n     \"\"\"Returns true only if the operations have qubits in common.\"\"\"\n@@ -114,6 +121,24 @@\n                              if not self.can_reorder(node.val, new_node.val)])\n         self.add_node(new_node)\n \n+    def __eq__(self, other):\n+        if not isinstance(other, type(self)):\n+            return NotImplemented\n+        g1 = self.copy()\n+        g2 = other.copy()\n+        for node, attr in g1.nodes.items():\n+            attr['val'] = node.val\n+        for node, attr in g2.nodes.items():\n+            attr['val'] = node.val\n+        def node_match(attr1: Dict[Any, Any], attr2: Dict[Any, Any]) -> bool:\n+            return attr1['val'] == attr2['val']\n+        return networkx.is_isomorphic(g1, g2, node_match=node_match)\n+\n+    def __ne__(self, other):\n+        return not self == other\n+\n+    __hash__ = None  # type: ignore\n+\n     def ordered_nodes(self) -> Iterator[Unique[ops.Operation]]:\n         if not self.nodes:\n             return\n", "issue": "Implement equality for CircuitDag\nImplement `__eq__` for CircuitDag using `networkx.is_isomorphic()`.  Use the node_match argument of is_isomorphic: `node_match=lambda n: n.val`.\r\n\r\nThis may be useful for #830.\n", "before_files": [{"content": "# Copyright 2018 The ops Developers\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom typing import Any, Callable, Generic, Iterator, TypeVar\n\nimport networkx\n\nfrom cirq import ops, devices\nfrom cirq.circuits import circuit\n\n\nT = TypeVar('T')\n\nclass Unique(Generic[T]):\n    \"\"\"A wrapper for a value that doesn't compare equal to other instances.\n\n    For example: 5 == 5 but Unique(5) != Unique(5).\n\n    Unique is used by CircuitDag to wrap operations because nodes in a graph\n    are considered the same node if they compare equal to each other.  X(q0)\n    in one moment of a Circuit and X(q0) in another moment of the Circuit are\n    wrapped by Unique(X(q0)) so they are distinct nodes in the graph.\n    \"\"\"\n    def __init__(self, val: T) -> None:\n        self.val = val\n\n    def __repr__(self):\n        return 'Unique({}, {!r})'.format(id(self), self.val)\n\n\ndef _disjoint_qubits(op1: ops.Operation, op2: ops.Operation) -> bool:\n    \"\"\"Returns true only if the operations have qubits in common.\"\"\"\n    return not set(op1.qubits) & set(op2.qubits)\n\n\nclass CircuitDag(networkx.DiGraph):\n    \"\"\"A representation of a Circuit as a directed acyclic graph.\n\n    Nodes of the graph are instances of Unique containing each operation of a\n    circuit.\n\n    Edges of the graph are tuples of nodes.  Each edge specifies a required\n    application order between two operations.  The first must be applied before\n    the second.\n\n    The graph is maximalist (transitive completion).\n    \"\"\"\n\n    disjoint_qubits = staticmethod(_disjoint_qubits)\n\n    def __init__(self,\n                 can_reorder: Callable[[ops.Operation, ops.Operation],\n                                       bool] = _disjoint_qubits,\n                 incoming_graph_data: Any = None,\n                 device: devices.Device = devices.UnconstrainedDevice\n                 ) -> None:\n        \"\"\"Initializes a CircuitDag.\n\n        Args:\n            can_reorder: A predicate that determines if two operations may be\n                reordered.  Graph edges are created for pairs of operations\n                where this returns False.\n\n                The default predicate allows reordering only when the operations\n                don't share common qubits.\n            incoming_graph_data: Data in initialize the graph.  This can be any\n                value supported by networkx.DiGraph() e.g. an edge list or\n                another graph.\n            device: Hardware that the circuit should be able to run on.\n        \"\"\"\n        super().__init__(incoming_graph_data)\n        self.can_reorder = can_reorder\n        self.device = device\n\n    @staticmethod\n    def make_node(op: ops.Operation) -> Unique:\n        return Unique(op)\n\n    @staticmethod\n    def from_circuit(circuit: circuit.Circuit,\n                     can_reorder: Callable[[ops.Operation, ops.Operation],\n                                           bool] = _disjoint_qubits\n                     ) -> 'CircuitDag':\n        return CircuitDag.from_ops(circuit.all_operations(),\n                                   can_reorder=can_reorder,\n                                   device=circuit.device)\n\n    @staticmethod\n    def from_ops(*operations: ops.OP_TREE,\n                 can_reorder: Callable[[ops.Operation, ops.Operation],\n                                       bool] = _disjoint_qubits,\n                 device: devices.Device = devices.UnconstrainedDevice\n                 ) -> 'CircuitDag':\n        dag = CircuitDag(can_reorder=can_reorder, device=device)\n        for op in ops.flatten_op_tree(operations):\n            dag.append(op)\n        return dag\n\n    def append(self, op: ops.Operation) -> None:\n        new_node = self.make_node(op)\n        self.add_edges_from([(node, new_node)\n                             for node in self.nodes\n                             if not self.can_reorder(node.val, new_node.val)])\n        self.add_node(new_node)\n\n    def ordered_nodes(self) -> Iterator[Unique[ops.Operation]]:\n        if not self.nodes:\n            return\n        g = self.copy()\n\n        def get_root_node(some_node: Unique[ops.Operation]\n                          ) -> Unique[ops.Operation]:\n            pred = g.pred\n            while pred[some_node]:\n                some_node = next(iter(pred[some_node]))\n            return some_node\n\n        def get_first_node() -> Unique[ops.Operation]:\n            return get_root_node(next(iter(g.nodes)))\n\n        def get_next_node(succ: networkx.classes.coreviews.AtlasView\n                          ) -> Unique[ops.Operation]:\n            if succ:\n                return get_root_node(next(iter(succ)))\n            else:\n                return get_first_node()\n\n        node = get_first_node()\n        while True:\n            yield node\n            succ = g.succ[node]\n            g.remove_node(node)\n\n            if not g.nodes:\n                return\n\n            node = get_next_node(succ)\n\n    def all_operations(self) -> Iterator[ops.Operation]:\n        return (node.val for node in self.ordered_nodes())\n\n    def to_circuit(self) -> circuit.Circuit:\n        return circuit.Circuit.from_ops(\n                    self.all_operations(),\n                    strategy=circuit.InsertStrategy.EARLIEST,\n                    device=self.device)\n", "path": "cirq/circuits/circuit_dag.py"}], "after_files": [{"content": "# Copyright 2018 The ops Developers\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom typing import Any, Callable, Dict, Generic, Iterator, TypeVar\n\nimport functools\nimport networkx\n\nfrom cirq import ops, devices\nfrom cirq.circuits import circuit\n\n\nT = TypeVar('T')\n\n@functools.total_ordering\nclass Unique(Generic[T]):\n    \"\"\"A wrapper for a value that doesn't compare equal to other instances.\n\n    For example: 5 == 5 but Unique(5) != Unique(5).\n\n    Unique is used by CircuitDag to wrap operations because nodes in a graph\n    are considered the same node if they compare equal to each other.  X(q0)\n    in one moment of a Circuit and X(q0) in another moment of the Circuit are\n    wrapped by Unique(X(q0)) so they are distinct nodes in the graph.\n    \"\"\"\n    def __init__(self, val: T) -> None:\n        self.val = val\n\n    def __repr__(self):\n        return 'Unique({}, {!r})'.format(id(self), self.val)\n\n    def __lt__(self, other):\n        if not isinstance(other, type(self)):\n            return NotImplemented\n        return id(self) < id(other)\n\n\ndef _disjoint_qubits(op1: ops.Operation, op2: ops.Operation) -> bool:\n    \"\"\"Returns true only if the operations have qubits in common.\"\"\"\n    return not set(op1.qubits) & set(op2.qubits)\n\n\nclass CircuitDag(networkx.DiGraph):\n    \"\"\"A representation of a Circuit as a directed acyclic graph.\n\n    Nodes of the graph are instances of Unique containing each operation of a\n    circuit.\n\n    Edges of the graph are tuples of nodes.  Each edge specifies a required\n    application order between two operations.  The first must be applied before\n    the second.\n\n    The graph is maximalist (transitive completion).\n    \"\"\"\n\n    disjoint_qubits = staticmethod(_disjoint_qubits)\n\n    def __init__(self,\n                 can_reorder: Callable[[ops.Operation, ops.Operation],\n                                       bool] = _disjoint_qubits,\n                 incoming_graph_data: Any = None,\n                 device: devices.Device = devices.UnconstrainedDevice\n                 ) -> None:\n        \"\"\"Initializes a CircuitDag.\n\n        Args:\n            can_reorder: A predicate that determines if two operations may be\n                reordered.  Graph edges are created for pairs of operations\n                where this returns False.\n\n                The default predicate allows reordering only when the operations\n                don't share common qubits.\n            incoming_graph_data: Data in initialize the graph.  This can be any\n                value supported by networkx.DiGraph() e.g. an edge list or\n                another graph.\n            device: Hardware that the circuit should be able to run on.\n        \"\"\"\n        super().__init__(incoming_graph_data)\n        self.can_reorder = can_reorder\n        self.device = device\n\n    @staticmethod\n    def make_node(op: ops.Operation) -> Unique:\n        return Unique(op)\n\n    @staticmethod\n    def from_circuit(circuit: circuit.Circuit,\n                     can_reorder: Callable[[ops.Operation, ops.Operation],\n                                           bool] = _disjoint_qubits\n                     ) -> 'CircuitDag':\n        return CircuitDag.from_ops(circuit.all_operations(),\n                                   can_reorder=can_reorder,\n                                   device=circuit.device)\n\n    @staticmethod\n    def from_ops(*operations: ops.OP_TREE,\n                 can_reorder: Callable[[ops.Operation, ops.Operation],\n                                       bool] = _disjoint_qubits,\n                 device: devices.Device = devices.UnconstrainedDevice\n                 ) -> 'CircuitDag':\n        dag = CircuitDag(can_reorder=can_reorder, device=device)\n        for op in ops.flatten_op_tree(operations):\n            dag.append(op)\n        return dag\n\n    def append(self, op: ops.Operation) -> None:\n        new_node = self.make_node(op)\n        self.add_edges_from([(node, new_node)\n                             for node in self.nodes\n                             if not self.can_reorder(node.val, new_node.val)])\n        self.add_node(new_node)\n\n    def __eq__(self, other):\n        if not isinstance(other, type(self)):\n            return NotImplemented\n        g1 = self.copy()\n        g2 = other.copy()\n        for node, attr in g1.nodes.items():\n            attr['val'] = node.val\n        for node, attr in g2.nodes.items():\n            attr['val'] = node.val\n        def node_match(attr1: Dict[Any, Any], attr2: Dict[Any, Any]) -> bool:\n            return attr1['val'] == attr2['val']\n        return networkx.is_isomorphic(g1, g2, node_match=node_match)\n\n    def __ne__(self, other):\n        return not self == other\n\n    __hash__ = None  # type: ignore\n\n    def ordered_nodes(self) -> Iterator[Unique[ops.Operation]]:\n        if not self.nodes:\n            return\n        g = self.copy()\n\n        def get_root_node(some_node: Unique[ops.Operation]\n                          ) -> Unique[ops.Operation]:\n            pred = g.pred\n            while pred[some_node]:\n                some_node = next(iter(pred[some_node]))\n            return some_node\n\n        def get_first_node() -> Unique[ops.Operation]:\n            return get_root_node(next(iter(g.nodes)))\n\n        def get_next_node(succ: networkx.classes.coreviews.AtlasView\n                          ) -> Unique[ops.Operation]:\n            if succ:\n                return get_root_node(next(iter(succ)))\n            else:\n                return get_first_node()\n\n        node = get_first_node()\n        while True:\n            yield node\n            succ = g.succ[node]\n            g.remove_node(node)\n\n            if not g.nodes:\n                return\n\n            node = get_next_node(succ)\n\n    def all_operations(self) -> Iterator[ops.Operation]:\n        return (node.val for node in self.ordered_nodes())\n\n    def to_circuit(self) -> circuit.Circuit:\n        return circuit.Circuit.from_ops(\n                    self.all_operations(),\n                    strategy=circuit.InsertStrategy.EARLIEST,\n                    device=self.device)\n", "path": "cirq/circuits/circuit_dag.py"}]}