We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Timeslots should have informative representation
<!-- ⚠️ If you do not respect this template, your issue will be closed -->
<!-- ⚠️ Make sure to browse the opened and closed issues to confirm this idea does not exist. -->

### What is the expected enhancement?
Currently `Interval`, `Timeslot` and `TimeslotCollection` have the standard python object representation. This should be replaced with an informative implementation of `__repr__`. As `TimeslotCollection` contains `Timeslot`s and `Timeslot`s contain `Interval`s the hierarchal nature of these data structure should be used to derive representations.

### Example
A possible representation might look like

Interval:
`(t0, tf)` eg. `(0, 10)`

Timeslot: Is an interval on a channel
`(channel, repr(interval))`: `(DriveChannel(0), (0, 10))`

TimeslotCollection: Is a dictionary of timeslots. Ie. it groups together intervals on channels.

`{channel1: [repr(interval1_c1), repr(interval2_c1), ...]), channel2: [repr(interval1_c2), repr(interval2_c2), ...]}`

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `qiskit/pulse/timeslots.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 
3 # This code is part of Qiskit.
4 #
5 # (C) Copyright IBM 2017, 2019.
6 #
7 # This code is licensed under the Apache License, Version 2.0. You may
8 # obtain a copy of this license in the LICENSE.txt file in the root directory
9 # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
10 #
11 # Any modifications or derivative works of this code must retain this
12 # copyright notice, and modified files need to carry a notice indicating
13 # that they have been altered from the originals.
14 
15 """
16 Timeslots for channels.
17 """
18 from collections import defaultdict
19 import itertools
20 from typing import List, Tuple
21 
22 from .channels import Channel
23 from .exceptions import PulseError
24 
25 
26 # pylint: disable=missing-return-doc
27 
28 
29 class Interval:
30     """Time interval."""
31 
32     def __init__(self, begin: int, end: int):
33         """Create an interval = (begin, end))
34 
35         Args:
36             begin: begin time of this interval
37             end: end time of this interval
38 
39         Raises:
40             PulseError: when invalid time or duration is specified
41         """
42         if begin < 0:
43             raise PulseError("Cannot create Interval with negative begin time")
44         if end < 0:
45             raise PulseError("Cannot create Interval with negative end time")
46         self._begin = begin
47         self._end = end
48 
49     @property
50     def begin(self):
51         """Begin time of this interval."""
52         return self._begin
53 
54     @property
55     def end(self):
56         """End time of this interval."""
57         return self._end
58 
59     @property
60     def duration(self):
61         """Duration of this interval."""
62         return self._end - self._begin
63 
64     def has_overlap(self, interval: 'Interval') -> bool:
65         """Check if self has overlap with `interval`.
66 
67         Args:
68             interval: interval to be examined
69 
70         Returns:
71             bool: True if self has overlap with `interval` otherwise False
72         """
73         if self.begin < interval.end and interval.begin < self.end:
74             return True
75         return False
76 
77     def shift(self, time: int) -> 'Interval':
78         """Return a new interval shifted by `time` from self
79 
80         Args:
81             time: time to be shifted
82 
83         Returns:
84             Interval: interval shifted by `time`
85         """
86         return Interval(self._begin + time, self._end + time)
87 
88     def __eq__(self, other):
89         """Two intervals are the same if they have the same begin and end.
90 
91         Args:
92             other (Interval): other Interval
93 
94         Returns:
95             bool: are self and other equal.
96         """
97         if self._begin == other._begin and self._end == other._end:
98             return True
99         return False
100 
101 
102 class Timeslot:
103     """Named tuple of (Interval, Channel)."""
104 
105     def __init__(self, interval: Interval, channel: Channel):
106         self._interval = interval
107         self._channel = channel
108 
109     @property
110     def interval(self):
111         """Interval of this time slot."""
112         return self._interval
113 
114     @property
115     def channel(self):
116         """Channel of this time slot."""
117         return self._channel
118 
119     def shift(self, time: int) -> 'Timeslot':
120         """Return a new Timeslot shifted by `time`.
121 
122         Args:
123             time: time to be shifted
124         """
125         return Timeslot(self.interval.shift(time), self.channel)
126 
127     def __eq__(self, other) -> bool:
128         """Two time-slots are the same if they have the same interval and channel.
129 
130         Args:
131             other (Timeslot): other Timeslot
132         """
133         if self.interval == other.interval and self.channel == other.channel:
134             return True
135         return False
136 
137 
138 class TimeslotCollection:
139     """Collection of `Timeslot`s."""
140 
141     def __init__(self, *timeslots: List[Timeslot]):
142         """Create a new time-slot collection.
143 
144         Args:
145             *timeslots: list of time slots
146         Raises:
147             PulseError: when overlapped time slots are specified
148         """
149         self._table = defaultdict(list)
150 
151         for slot in timeslots:
152             for interval in self._table[slot.channel]:
153                 if slot.interval.has_overlap(interval):
154                     raise PulseError("Cannot create TimeslotCollection from overlapped timeslots")
155             self._table[slot.channel].append(slot.interval)
156 
157         self._timeslots = tuple(timeslots)
158 
159     @property
160     def timeslots(self) -> Tuple[Timeslot]:
161         """`Timeslot`s in collection."""
162         return self._timeslots
163 
164     @property
165     def channels(self) -> Tuple[Timeslot]:
166         """Channels within the timeslot collection."""
167         return tuple(self._table.keys())
168 
169     @property
170     def start_time(self) -> int:
171         """Return earliest start time in this collection."""
172         return self.ch_start_time(*self.channels)
173 
174     @property
175     def stop_time(self) -> int:
176         """Return maximum time of timeslots over all channels."""
177         return self.ch_stop_time(*self.channels)
178 
179     @property
180     def duration(self) -> int:
181         """Return maximum duration of timeslots over all channels."""
182         return self.stop_time
183 
184     def ch_start_time(self, *channels: List[Channel]) -> int:
185         """Return earliest start time in this collection.
186 
187         Args:
188             *channels: Channels over which to obtain start_time.
189         """
190         intervals = list(itertools.chain(*(self._table[chan] for chan in channels
191                                            if chan in self._table)))
192         if intervals:
193             return min(interval.begin for interval in intervals)
194         return 0
195 
196     def ch_stop_time(self, *channels: List[Channel]) -> int:
197         """Return maximum time of timeslots over all channels.
198 
199         Args:
200             *channels: Channels over which to obtain stop time.
201         """
202         intervals = list(itertools.chain(*(self._table[chan] for chan in channels
203                                            if chan in self._table)))
204         if intervals:
205             return max(interval.end for interval in intervals)
206         return 0
207 
208     def ch_duration(self, *channels: List[Channel]) -> int:
209         """Return maximum duration of timeslots over all channels.
210 
211         Args:
212             *channels: Channels over which to obtain the duration.
213         """
214         return self.ch_stop_time(*channels)
215 
216     def is_mergeable_with(self, timeslots: 'TimeslotCollection') -> bool:
217         """Return if self is mergeable with `timeslots`.
218 
219         Args:
220             timeslots: TimeslotCollection to be checked
221         """
222         for slot in timeslots.timeslots:
223             if slot.channel in self.channels:
224                 for interval in self._table[slot.channel]:
225                     if slot.interval.has_overlap(interval):
226                         return False
227         return True
228 
229     def merged(self, timeslots: 'TimeslotCollection') -> 'TimeslotCollection':
230         """Return a new TimeslotCollection merged with a specified `timeslots`
231 
232         Args:
233             timeslots: TimeslotCollection to be merged
234         """
235         slots = [Timeslot(slot.interval, slot.channel) for slot in self.timeslots]
236         slots.extend([Timeslot(slot.interval, slot.channel) for slot in timeslots.timeslots])
237         return TimeslotCollection(*slots)
238 
239     def shift(self, time: int) -> 'TimeslotCollection':
240         """Return a new TimeslotCollection shifted by `time`.
241 
242         Args:
243             time: time to be shifted by
244         """
245         slots = [Timeslot(slot.interval.shift(time), slot.channel) for slot in self.timeslots]
246         return TimeslotCollection(*slots)
247 
248     def __eq__(self, other) -> bool:
249         """Two time-slot collections are the same if they have the same time-slots.
250 
251         Args:
252             other (TimeslotCollection): other TimeslotCollection
253         """
254         if self.timeslots == other.timeslots:
255             return True
256         return False
257
```
--- 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()

```

diff --git a/qiskit/pulse/timeslots.py b/qiskit/pulse/timeslots.py
--- a/qiskit/pulse/timeslots.py
+++ b/qiskit/pulse/timeslots.py
@@ -98,6 +98,10 @@
             return True
         return False
 
+    def __repr__(self):
+        """Return a readable representation of Interval Object"""
+        return "{}({}, {})".format(self.__class__.__name__, self.begin, self.end)
+
 
 class Timeslot:
     """Named tuple of (Interval, Channel)."""
@@ -134,6 +138,12 @@
             return True
         return False
 
+    def __repr__(self):
+        """Return a readable representation of Timeslot Object"""
+        return "{}({}, {})".format(self.__class__.__name__,
+                                   self.channel,
+                                   (self.interval.begin, self.interval.end))
+
 
 class TimeslotCollection:
     """Collection of `Timeslot`s."""
@@ -254,3 +264,10 @@
         if self.timeslots == other.timeslots:
             return True
         return False
+
+    def __repr__(self):
+        """Return a readable representation of TimeslotCollection Object"""
+        rep = dict()
+        for key, val in self._table.items():
+            rep[key] = [(interval.begin, interval.end) for interval in val]
+        return self.__class__.__name__ + str(rep)

{"golden_diff": "diff --git a/qiskit/pulse/timeslots.py b/qiskit/pulse/timeslots.py\n--- a/qiskit/pulse/timeslots.py\n+++ b/qiskit/pulse/timeslots.py\n@@ -98,6 +98,10 @@\n             return True\n         return False\n \n+    def __repr__(self):\n+        \"\"\"Return a readable representation of Interval Object\"\"\"\n+        return \"{}({}, {})\".format(self.__class__.__name__, self.begin, self.end)\n+\n \n class Timeslot:\n     \"\"\"Named tuple of (Interval, Channel).\"\"\"\n@@ -134,6 +138,12 @@\n             return True\n         return False\n \n+    def __repr__(self):\n+        \"\"\"Return a readable representation of Timeslot Object\"\"\"\n+        return \"{}({}, {})\".format(self.__class__.__name__,\n+                                   self.channel,\n+                                   (self.interval.begin, self.interval.end))\n+\n \n class TimeslotCollection:\n     \"\"\"Collection of `Timeslot`s.\"\"\"\n@@ -254,3 +264,10 @@\n         if self.timeslots == other.timeslots:\n             return True\n         return False\n+\n+    def __repr__(self):\n+        \"\"\"Return a readable representation of TimeslotCollection Object\"\"\"\n+        rep = dict()\n+        for key, val in self._table.items():\n+            rep[key] = [(interval.begin, interval.end) for interval in val]\n+        return self.__class__.__name__ + str(rep)\n", "issue": "Timeslots should have informative representation\n<!-- \u26a0\ufe0f If you do not respect this template, your issue will be closed -->\r\n<!-- \u26a0\ufe0f Make sure to browse the opened and closed issues to confirm this idea does not exist. -->\r\n\r\n### What is the expected enhancement?\r\nCurrently `Interval`, `Timeslot` and `TimeslotCollection` have the standard python object representation. This should be replaced with an informative implementation of `__repr__`. As `TimeslotCollection` contains `Timeslot`s and `Timeslot`s contain `Interval`s the hierarchal nature of these data structure should be used to derive representations.\r\n\r\n### Example\r\nA possible representation might look like\r\n\r\nInterval:\r\n`(t0, tf)` eg. `(0, 10)`\r\n\r\nTimeslot: Is an interval on a channel\r\n`(channel, repr(interval))`: `(DriveChannel(0), (0, 10))`\r\n\r\nTimeslotCollection: Is a dictionary of timeslots. Ie. it groups together intervals on channels.\r\n\r\n`{channel1: [repr(interval1_c1), repr(interval2_c1), ...]), channel2: [repr(interval1_c2), repr(interval2_c2), ...]}`\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\n# This code is part of Qiskit.\n#\n# (C) Copyright IBM 2017, 2019.\n#\n# This code is licensed under the Apache License, Version 2.0. You may\n# obtain a copy of this license in the LICENSE.txt file in the root directory\n# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.\n#\n# Any modifications or derivative works of this code must retain this\n# copyright notice, and modified files need to carry a notice indicating\n# that they have been altered from the originals.\n\n\"\"\"\nTimeslots for channels.\n\"\"\"\nfrom collections import defaultdict\nimport itertools\nfrom typing import List, Tuple\n\nfrom .channels import Channel\nfrom .exceptions import PulseError\n\n\n# pylint: disable=missing-return-doc\n\n\nclass Interval:\n    \"\"\"Time interval.\"\"\"\n\n    def __init__(self, begin: int, end: int):\n        \"\"\"Create an interval = (begin, end))\n\n        Args:\n            begin: begin time of this interval\n            end: end time of this interval\n\n        Raises:\n            PulseError: when invalid time or duration is specified\n        \"\"\"\n        if begin < 0:\n            raise PulseError(\"Cannot create Interval with negative begin time\")\n        if end < 0:\n            raise PulseError(\"Cannot create Interval with negative end time\")\n        self._begin = begin\n        self._end = end\n\n    @property\n    def begin(self):\n        \"\"\"Begin time of this interval.\"\"\"\n        return self._begin\n\n    @property\n    def end(self):\n        \"\"\"End time of this interval.\"\"\"\n        return self._end\n\n    @property\n    def duration(self):\n        \"\"\"Duration of this interval.\"\"\"\n        return self._end - self._begin\n\n    def has_overlap(self, interval: 'Interval') -> bool:\n        \"\"\"Check if self has overlap with `interval`.\n\n        Args:\n            interval: interval to be examined\n\n        Returns:\n            bool: True if self has overlap with `interval` otherwise False\n        \"\"\"\n        if self.begin < interval.end and interval.begin < self.end:\n            return True\n        return False\n\n    def shift(self, time: int) -> 'Interval':\n        \"\"\"Return a new interval shifted by `time` from self\n\n        Args:\n            time: time to be shifted\n\n        Returns:\n            Interval: interval shifted by `time`\n        \"\"\"\n        return Interval(self._begin + time, self._end + time)\n\n    def __eq__(self, other):\n        \"\"\"Two intervals are the same if they have the same begin and end.\n\n        Args:\n            other (Interval): other Interval\n\n        Returns:\n            bool: are self and other equal.\n        \"\"\"\n        if self._begin == other._begin and self._end == other._end:\n            return True\n        return False\n\n\nclass Timeslot:\n    \"\"\"Named tuple of (Interval, Channel).\"\"\"\n\n    def __init__(self, interval: Interval, channel: Channel):\n        self._interval = interval\n        self._channel = channel\n\n    @property\n    def interval(self):\n        \"\"\"Interval of this time slot.\"\"\"\n        return self._interval\n\n    @property\n    def channel(self):\n        \"\"\"Channel of this time slot.\"\"\"\n        return self._channel\n\n    def shift(self, time: int) -> 'Timeslot':\n        \"\"\"Return a new Timeslot shifted by `time`.\n\n        Args:\n            time: time to be shifted\n        \"\"\"\n        return Timeslot(self.interval.shift(time), self.channel)\n\n    def __eq__(self, other) -> bool:\n        \"\"\"Two time-slots are the same if they have the same interval and channel.\n\n        Args:\n            other (Timeslot): other Timeslot\n        \"\"\"\n        if self.interval == other.interval and self.channel == other.channel:\n            return True\n        return False\n\n\nclass TimeslotCollection:\n    \"\"\"Collection of `Timeslot`s.\"\"\"\n\n    def __init__(self, *timeslots: List[Timeslot]):\n        \"\"\"Create a new time-slot collection.\n\n        Args:\n            *timeslots: list of time slots\n        Raises:\n            PulseError: when overlapped time slots are specified\n        \"\"\"\n        self._table = defaultdict(list)\n\n        for slot in timeslots:\n            for interval in self._table[slot.channel]:\n                if slot.interval.has_overlap(interval):\n                    raise PulseError(\"Cannot create TimeslotCollection from overlapped timeslots\")\n            self._table[slot.channel].append(slot.interval)\n\n        self._timeslots = tuple(timeslots)\n\n    @property\n    def timeslots(self) -> Tuple[Timeslot]:\n        \"\"\"`Timeslot`s in collection.\"\"\"\n        return self._timeslots\n\n    @property\n    def channels(self) -> Tuple[Timeslot]:\n        \"\"\"Channels within the timeslot collection.\"\"\"\n        return tuple(self._table.keys())\n\n    @property\n    def start_time(self) -> int:\n        \"\"\"Return earliest start time in this collection.\"\"\"\n        return self.ch_start_time(*self.channels)\n\n    @property\n    def stop_time(self) -> int:\n        \"\"\"Return maximum time of timeslots over all channels.\"\"\"\n        return self.ch_stop_time(*self.channels)\n\n    @property\n    def duration(self) -> int:\n        \"\"\"Return maximum duration of timeslots over all channels.\"\"\"\n        return self.stop_time\n\n    def ch_start_time(self, *channels: List[Channel]) -> int:\n        \"\"\"Return earliest start time in this collection.\n\n        Args:\n            *channels: Channels over which to obtain start_time.\n        \"\"\"\n        intervals = list(itertools.chain(*(self._table[chan] for chan in channels\n                                           if chan in self._table)))\n        if intervals:\n            return min(interval.begin for interval in intervals)\n        return 0\n\n    def ch_stop_time(self, *channels: List[Channel]) -> int:\n        \"\"\"Return maximum time of timeslots over all channels.\n\n        Args:\n            *channels: Channels over which to obtain stop time.\n        \"\"\"\n        intervals = list(itertools.chain(*(self._table[chan] for chan in channels\n                                           if chan in self._table)))\n        if intervals:\n            return max(interval.end for interval in intervals)\n        return 0\n\n    def ch_duration(self, *channels: List[Channel]) -> int:\n        \"\"\"Return maximum duration of timeslots over all channels.\n\n        Args:\n            *channels: Channels over which to obtain the duration.\n        \"\"\"\n        return self.ch_stop_time(*channels)\n\n    def is_mergeable_with(self, timeslots: 'TimeslotCollection') -> bool:\n        \"\"\"Return if self is mergeable with `timeslots`.\n\n        Args:\n            timeslots: TimeslotCollection to be checked\n        \"\"\"\n        for slot in timeslots.timeslots:\n            if slot.channel in self.channels:\n                for interval in self._table[slot.channel]:\n                    if slot.interval.has_overlap(interval):\n                        return False\n        return True\n\n    def merged(self, timeslots: 'TimeslotCollection') -> 'TimeslotCollection':\n        \"\"\"Return a new TimeslotCollection merged with a specified `timeslots`\n\n        Args:\n            timeslots: TimeslotCollection to be merged\n        \"\"\"\n        slots = [Timeslot(slot.interval, slot.channel) for slot in self.timeslots]\n        slots.extend([Timeslot(slot.interval, slot.channel) for slot in timeslots.timeslots])\n        return TimeslotCollection(*slots)\n\n    def shift(self, time: int) -> 'TimeslotCollection':\n        \"\"\"Return a new TimeslotCollection shifted by `time`.\n\n        Args:\n            time: time to be shifted by\n        \"\"\"\n        slots = [Timeslot(slot.interval.shift(time), slot.channel) for slot in self.timeslots]\n        return TimeslotCollection(*slots)\n\n    def __eq__(self, other) -> bool:\n        \"\"\"Two time-slot collections are the same if they have the same time-slots.\n\n        Args:\n            other (TimeslotCollection): other TimeslotCollection\n        \"\"\"\n        if self.timeslots == other.timeslots:\n            return True\n        return False\n", "path": "qiskit/pulse/timeslots.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\n# This code is part of Qiskit.\n#\n# (C) Copyright IBM 2017, 2019.\n#\n# This code is licensed under the Apache License, Version 2.0. You may\n# obtain a copy of this license in the LICENSE.txt file in the root directory\n# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.\n#\n# Any modifications or derivative works of this code must retain this\n# copyright notice, and modified files need to carry a notice indicating\n# that they have been altered from the originals.\n\n\"\"\"\nTimeslots for channels.\n\"\"\"\nfrom collections import defaultdict\nimport itertools\nfrom typing import List, Tuple\n\nfrom .channels import Channel\nfrom .exceptions import PulseError\n\n\n# pylint: disable=missing-return-doc\n\n\nclass Interval:\n    \"\"\"Time interval.\"\"\"\n\n    def __init__(self, begin: int, end: int):\n        \"\"\"Create an interval = (begin, end))\n\n        Args:\n            begin: begin time of this interval\n            end: end time of this interval\n\n        Raises:\n            PulseError: when invalid time or duration is specified\n        \"\"\"\n        if begin < 0:\n            raise PulseError(\"Cannot create Interval with negative begin time\")\n        if end < 0:\n            raise PulseError(\"Cannot create Interval with negative end time\")\n        self._begin = begin\n        self._end = end\n\n    @property\n    def begin(self):\n        \"\"\"Begin time of this interval.\"\"\"\n        return self._begin\n\n    @property\n    def end(self):\n        \"\"\"End time of this interval.\"\"\"\n        return self._end\n\n    @property\n    def duration(self):\n        \"\"\"Duration of this interval.\"\"\"\n        return self._end - self._begin\n\n    def has_overlap(self, interval: 'Interval') -> bool:\n        \"\"\"Check if self has overlap with `interval`.\n\n        Args:\n            interval: interval to be examined\n\n        Returns:\n            bool: True if self has overlap with `interval` otherwise False\n        \"\"\"\n        if self.begin < interval.end and interval.begin < self.end:\n            return True\n        return False\n\n    def shift(self, time: int) -> 'Interval':\n        \"\"\"Return a new interval shifted by `time` from self\n\n        Args:\n            time: time to be shifted\n\n        Returns:\n            Interval: interval shifted by `time`\n        \"\"\"\n        return Interval(self._begin + time, self._end + time)\n\n    def __eq__(self, other):\n        \"\"\"Two intervals are the same if they have the same begin and end.\n\n        Args:\n            other (Interval): other Interval\n\n        Returns:\n            bool: are self and other equal.\n        \"\"\"\n        if self._begin == other._begin and self._end == other._end:\n            return True\n        return False\n\n    def __repr__(self):\n        \"\"\"Return a readable representation of Interval Object\"\"\"\n        return \"{}({}, {})\".format(self.__class__.__name__, self.begin, self.end)\n\n\nclass Timeslot:\n    \"\"\"Named tuple of (Interval, Channel).\"\"\"\n\n    def __init__(self, interval: Interval, channel: Channel):\n        self._interval = interval\n        self._channel = channel\n\n    @property\n    def interval(self):\n        \"\"\"Interval of this time slot.\"\"\"\n        return self._interval\n\n    @property\n    def channel(self):\n        \"\"\"Channel of this time slot.\"\"\"\n        return self._channel\n\n    def shift(self, time: int) -> 'Timeslot':\n        \"\"\"Return a new Timeslot shifted by `time`.\n\n        Args:\n            time: time to be shifted\n        \"\"\"\n        return Timeslot(self.interval.shift(time), self.channel)\n\n    def __eq__(self, other) -> bool:\n        \"\"\"Two time-slots are the same if they have the same interval and channel.\n\n        Args:\n            other (Timeslot): other Timeslot\n        \"\"\"\n        if self.interval == other.interval and self.channel == other.channel:\n            return True\n        return False\n\n    def __repr__(self):\n        \"\"\"Return a readable representation of Timeslot Object\"\"\"\n        return \"{}({}, {})\".format(self.__class__.__name__,\n                                   self.channel,\n                                   (self.interval.begin, self.interval.end))\n\n\nclass TimeslotCollection:\n    \"\"\"Collection of `Timeslot`s.\"\"\"\n\n    def __init__(self, *timeslots: List[Timeslot]):\n        \"\"\"Create a new time-slot collection.\n\n        Args:\n            *timeslots: list of time slots\n        Raises:\n            PulseError: when overlapped time slots are specified\n        \"\"\"\n        self._table = defaultdict(list)\n\n        for slot in timeslots:\n            for interval in self._table[slot.channel]:\n                if slot.interval.has_overlap(interval):\n                    raise PulseError(\"Cannot create TimeslotCollection from overlapped timeslots\")\n            self._table[slot.channel].append(slot.interval)\n\n        self._timeslots = tuple(timeslots)\n\n    @property\n    def timeslots(self) -> Tuple[Timeslot]:\n        \"\"\"`Timeslot`s in collection.\"\"\"\n        return self._timeslots\n\n    @property\n    def channels(self) -> Tuple[Timeslot]:\n        \"\"\"Channels within the timeslot collection.\"\"\"\n        return tuple(self._table.keys())\n\n    @property\n    def start_time(self) -> int:\n        \"\"\"Return earliest start time in this collection.\"\"\"\n        return self.ch_start_time(*self.channels)\n\n    @property\n    def stop_time(self) -> int:\n        \"\"\"Return maximum time of timeslots over all channels.\"\"\"\n        return self.ch_stop_time(*self.channels)\n\n    @property\n    def duration(self) -> int:\n        \"\"\"Return maximum duration of timeslots over all channels.\"\"\"\n        return self.stop_time\n\n    def ch_start_time(self, *channels: List[Channel]) -> int:\n        \"\"\"Return earliest start time in this collection.\n\n        Args:\n            *channels: Channels over which to obtain start_time.\n        \"\"\"\n        intervals = list(itertools.chain(*(self._table[chan] for chan in channels\n                                           if chan in self._table)))\n        if intervals:\n            return min(interval.begin for interval in intervals)\n        return 0\n\n    def ch_stop_time(self, *channels: List[Channel]) -> int:\n        \"\"\"Return maximum time of timeslots over all channels.\n\n        Args:\n            *channels: Channels over which to obtain stop time.\n        \"\"\"\n        intervals = list(itertools.chain(*(self._table[chan] for chan in channels\n                                           if chan in self._table)))\n        if intervals:\n            return max(interval.end for interval in intervals)\n        return 0\n\n    def ch_duration(self, *channels: List[Channel]) -> int:\n        \"\"\"Return maximum duration of timeslots over all channels.\n\n        Args:\n            *channels: Channels over which to obtain the duration.\n        \"\"\"\n        return self.ch_stop_time(*channels)\n\n    def is_mergeable_with(self, timeslots: 'TimeslotCollection') -> bool:\n        \"\"\"Return if self is mergeable with `timeslots`.\n\n        Args:\n            timeslots: TimeslotCollection to be checked\n        \"\"\"\n        for slot in timeslots.timeslots:\n            if slot.channel in self.channels:\n                for interval in self._table[slot.channel]:\n                    if slot.interval.has_overlap(interval):\n                        return False\n        return True\n\n    def merged(self, timeslots: 'TimeslotCollection') -> 'TimeslotCollection':\n        \"\"\"Return a new TimeslotCollection merged with a specified `timeslots`\n\n        Args:\n            timeslots: TimeslotCollection to be merged\n        \"\"\"\n        slots = [Timeslot(slot.interval, slot.channel) for slot in self.timeslots]\n        slots.extend([Timeslot(slot.interval, slot.channel) for slot in timeslots.timeslots])\n        return TimeslotCollection(*slots)\n\n    def shift(self, time: int) -> 'TimeslotCollection':\n        \"\"\"Return a new TimeslotCollection shifted by `time`.\n\n        Args:\n            time: time to be shifted by\n        \"\"\"\n        slots = [Timeslot(slot.interval.shift(time), slot.channel) for slot in self.timeslots]\n        return TimeslotCollection(*slots)\n\n    def __eq__(self, other) -> bool:\n        \"\"\"Two time-slot collections are the same if they have the same time-slots.\n\n        Args:\n            other (TimeslotCollection): other TimeslotCollection\n        \"\"\"\n        if self.timeslots == other.timeslots:\n            return True\n        return False\n\n    def __repr__(self):\n        \"\"\"Return a readable representation of TimeslotCollection Object\"\"\"\n        rep = dict()\n        for key, val in self._table.items():\n            rep[key] = [(interval.begin, interval.end) for interval in val]\n        return self.__class__.__name__ + str(rep)\n", "path": "qiskit/pulse/timeslots.py"}]}