libqasm 1.2.1__cp313-cp313-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
cqasm/v3x/semantic.py ADDED
@@ -0,0 +1,3453 @@
1
+ import functools
2
+ import struct
3
+ import cqasm.v3x.instruction
4
+ import cqasm.v3x.primitives
5
+ import cqasm.v3x.types
6
+ import cqasm.v3x.values
7
+
8
+
9
+ _typemap = {}
10
+
11
+
12
+ def _cbor_read_intlike(cbor, offset, info):
13
+ """Parses the additional information and reads any additional bytes it
14
+ specifies the existence of, and returns the encoded integer. offset
15
+ should point to the byte immediately following the initial byte. Returns
16
+ the encoded integer and the offset immediately following the object."""
17
+
18
+ # Info less than 24 is a shorthand for the integer itself.
19
+ if info < 24:
20
+ return info, offset
21
+
22
+ # 24 is 8-bit following the info byte.
23
+ if info == 24:
24
+ return cbor[offset], offset + 1
25
+
26
+ # 25 is 16-bit following the info byte.
27
+ if info == 25:
28
+ val, = struct.unpack('>H', cbor[offset:offset+2])
29
+ return val, offset + 2
30
+
31
+ # 26 is 32-bit following the info byte.
32
+ if info == 26:
33
+ val, = struct.unpack('>I', cbor[offset:offset+4])
34
+ return val, offset + 4
35
+
36
+ # 27 is 64-bit following the info byte.
37
+ if info == 27:
38
+ val, = struct.unpack('>Q', cbor[offset:offset+8])
39
+ return val, offset + 8
40
+
41
+ # Info greater than or equal to 28 is illegal. Note that 31 is used for
42
+ # indefinite lengths, so this must be checked prior to calling this
43
+ # method.
44
+ raise ValueError("invalid CBOR: illegal additional info for integer or object length")
45
+
46
+
47
+ def _sub_cbor_to_py(cbor, offset):
48
+ """Converts the CBOR object starting at cbor[offset] to its Python
49
+ representation for as far as tree-gen supports CBOR. Returns this Python
50
+ representation and the offset immediately following the CBOR representation
51
+ thereof. Supported types:
52
+
53
+ - 0: unsigned integer (int)
54
+ - 1: negative integer (int)
55
+ - 2: byte string (bytes)
56
+ - 3: UTF-8 string (str)
57
+ - 4: array (list)
58
+ - 5: map (dict)
59
+ - 6: semantic tag (ignored)
60
+ - 7.20: false (bool)
61
+ - 7.21: true (bool)
62
+ - 7.22: null (NoneType)
63
+ - 7.27: double-precision float (float)
64
+
65
+ Both definite-length and indefinite-length notation is supported for sized
66
+ objects (strings, arrays, maps). A ValueError is thrown if the CBOR is
67
+ invalid or contains unsupported structures."""
68
+
69
+ # Read the initial byte.
70
+ initial = cbor[offset]
71
+ typ = initial >> 5
72
+ info = initial & 0x1F
73
+ offset += 1
74
+
75
+ # Handle unsigned integer (0) and negative integer (1).
76
+ if typ <= 1:
77
+ value, offset = _cbor_read_intlike(cbor, offset, info)
78
+ if typ == 1:
79
+ value = -1 - value
80
+ return value, offset
81
+
82
+ # Handle byte string (2) and UTF-8 string (3).
83
+ if typ <= 3:
84
+
85
+ # Gather components of the string in here.
86
+ if info == 31:
87
+
88
+ # Handle indefinite length strings. These consist of a
89
+ # break-terminated (0xFF) list of definite-length strings of the
90
+ # same type.
91
+ value = []
92
+ while True:
93
+ sub_initial = cbor[offset]; offset += 1
94
+ if sub_initial == 0xFF:
95
+ break
96
+ sub_typ = sub_initial >> 5
97
+ sub_info = sub_initial & 0x1F
98
+ if sub_typ != typ:
99
+ raise ValueError('invalid CBOR: illegal indefinite-length string component')
100
+
101
+ # Seek past definite-length string component. The size in
102
+ # bytes is encoded as an integer.
103
+ size, offset = _cbor_read_intlike(cbor, offset, sub_info)
104
+ value.append(cbor[offset:offset + size])
105
+ offset += size
106
+ value = b''.join(value)
107
+
108
+ else:
109
+
110
+ # Handle definite-length strings. The size in bytes is encoded as
111
+ # an integer.
112
+ size, offset = _cbor_read_intlike(cbor, offset, info)
113
+ value = cbor[offset:offset + size]
114
+ offset += size
115
+
116
+ if typ == 3:
117
+ value = value.decode('UTF-8')
118
+ return value, offset
119
+
120
+ # Handle array (4) and map (5).
121
+ if typ <= 5:
122
+
123
+ # Create result container.
124
+ container = [] if typ == 4 else {}
125
+
126
+ # Handle indefinite length arrays and maps.
127
+ if info == 31:
128
+
129
+ # Read objects/object pairs until we encounter a break.
130
+ while cbor[offset] != 0xFF:
131
+ if typ == 4:
132
+ value, offset = _sub_cbor_to_py(cbor, offset)
133
+ container.append(value)
134
+ else:
135
+ key, offset = _sub_cbor_to_py(cbor, offset)
136
+ if not isinstance(key, str):
137
+ raise ValueError('invalid CBOR: map key is not a UTF-8 string')
138
+ value, offset = _sub_cbor_to_py(cbor, offset)
139
+ container[key] = value
140
+
141
+ # Seek past the break.
142
+ offset += 1
143
+
144
+ else:
145
+
146
+ # Handle definite-length arrays and maps. The amount of
147
+ # objects/object pairs is encoded as an integer.
148
+ size, offset = _cbor_read_intlike(cbor, offset, info)
149
+ for _ in range(size):
150
+ if typ == 4:
151
+ value, offset = _sub_cbor_to_py(cbor, offset)
152
+ container.append(value)
153
+ else:
154
+ key, offset = _sub_cbor_to_py(cbor, offset)
155
+ if not isinstance(key, str):
156
+ raise ValueError('invalid CBOR: map key is not a UTF-8 string')
157
+ value, offset = _sub_cbor_to_py(cbor, offset)
158
+ container[key] = value
159
+
160
+ return container, offset
161
+
162
+ # Handle semantic tags.
163
+ if typ == 6:
164
+
165
+ # We don't use semantic tags for anything, but ignoring them is
166
+ # legal and reading past them is easy enough.
167
+ _, offset = _cbor_read_intlike(cbor, offset, info)
168
+ return _sub_cbor_to_py(cbor, offset)
169
+
170
+ # Handle major type 7. Here, the type is defined by the additional info.
171
+ # Additional info 24 is reserved for having the type specified by the
172
+ # next byte, but all such values are unassigned.
173
+ if info == 20:
174
+ # false
175
+ return False, offset
176
+
177
+ if info == 21:
178
+ # true
179
+ return True, offset
180
+
181
+ if info == 22:
182
+ # null
183
+ return None, offset
184
+
185
+ if info == 23:
186
+ # Undefined value.
187
+ raise ValueError('invalid CBOR: undefined value is not supported')
188
+
189
+ if info == 25:
190
+ # Half-precision float.
191
+ raise ValueError('invalid CBOR: half-precision float is not supported')
192
+
193
+ if info == 26:
194
+ # Single-precision float.
195
+ raise ValueError('invalid CBOR: single-precision float is not supported')
196
+
197
+ if info == 27:
198
+ # Double-precision float.
199
+ value, = struct.unpack('>d', cbor[offset:offset+8])
200
+ return value, offset + 8
201
+
202
+ if info == 31:
203
+ # Break value used for indefinite-length objects.
204
+ raise ValueError('invalid CBOR: unexpected break')
205
+
206
+ raise ValueError('invalid CBOR: unknown type code')
207
+
208
+
209
+ def _cbor_to_py(cbor):
210
+ """Converts the given CBOR object (bytes) to its Python representation for
211
+ as far as tree-gen supports CBOR. Supported types:
212
+
213
+ - 0: unsigned integer (int)
214
+ - 1: negative integer (int)
215
+ - 2: byte string (bytes)
216
+ - 3: UTF-8 string (str)
217
+ - 4: array (list)
218
+ - 5: map (dict)
219
+ - 6: semantic tag (ignored)
220
+ - 7.20: false (bool)
221
+ - 7.21: true (bool)
222
+ - 7.22: null (NoneType)
223
+ - 7.27: double-precision float (float)
224
+
225
+ Both definite-length and indefinite-length notation is supported for sized
226
+ objects (strings, arrays, maps). A ValueError is thrown if the CBOR is
227
+ invalid or contains unsupported structures."""
228
+
229
+ value, length = _sub_cbor_to_py(cbor, 0)
230
+ if length < len(cbor):
231
+ raise ValueError('invalid CBOR: garbage at the end')
232
+ return value
233
+
234
+
235
+ class _Cbor(bytes):
236
+ """Marker class indicating that this bytes object represents CBOR."""
237
+ pass
238
+
239
+
240
+ def _cbor_write_intlike(value, major=0):
241
+ """Converts the given integer to its minimal representation in CBOR. The
242
+ major code can be overridden to write lengths for strings, arrays, and
243
+ maps."""
244
+
245
+ # Negative integers use major code 1.
246
+ if value < 0:
247
+ major = 1
248
+ value = -1 - value
249
+ initial = major << 5
250
+
251
+ # Use the minimal representation.
252
+ if value < 24:
253
+ return struct.pack('>B', initial | value)
254
+ if value < 0x100:
255
+ return struct.pack('>BB', initial | 24, value)
256
+ if value < 0x10000:
257
+ return struct.pack('>BH', initial | 25, value)
258
+ if value < 0x100000000:
259
+ return struct.pack('>BI', initial | 26, value)
260
+ if value < 0x10000000000000000:
261
+ return struct.pack('>BQ', initial | 27, value)
262
+
263
+ raise ValueError('integer too large for CBOR (bigint not supported)')
264
+
265
+
266
+ def _py_to_cbor(value, type_converter=None):
267
+ """Inverse of _cbor_to_py(). type_converter optionally specifies a function
268
+ that takes a value and either converts it to a primitive for serialization,
269
+ converts it to a _Cbor object manually, or raises a TypeError if no
270
+ conversion is known. If no type_converter is specified, a TypeError is
271
+ raised in all cases the type_converter would otherwise be called. The cbor
272
+ serialization is returned using a _Cbor object, which is just a marker class
273
+ behaving just like bytes."""
274
+ if isinstance(value, _Cbor):
275
+ return value
276
+
277
+ if isinstance(value, int):
278
+ return _Cbor(_cbor_write_intlike(value))
279
+
280
+ if isinstance(value, float):
281
+ return _Cbor(struct.pack('>Bd', 0xFB, value))
282
+
283
+ if isinstance(value, str):
284
+ value = value.encode('UTF-8')
285
+ return _Cbor(_cbor_write_intlike(len(value), 3) + value)
286
+
287
+ if isinstance(value, bytes):
288
+ return _Cbor(_cbor_write_intlike(len(value), 2) + value)
289
+
290
+ if value is False:
291
+ return _Cbor(b'\xF4')
292
+
293
+ if value is True:
294
+ return _Cbor(b'\xF5')
295
+
296
+ if value is None:
297
+ return _Cbor(b'\xF6')
298
+
299
+ if isinstance(value, (list, tuple)):
300
+ cbor = [_cbor_write_intlike(len(value), 4)]
301
+ for val in value:
302
+ cbor.append(_py_to_cbor(val, type_converter))
303
+ return _Cbor(b''.join(cbor))
304
+
305
+ if isinstance(value, dict):
306
+ cbor = [_cbor_write_intlike(len(value), 5)]
307
+ for key, val in sorted(value.items()):
308
+ if not isinstance(key, str):
309
+ raise TypeError('dict keys must be strings')
310
+ cbor.append(_py_to_cbor(key, type_converter))
311
+ cbor.append(_py_to_cbor(val, type_converter))
312
+ return _Cbor(b''.join(cbor))
313
+
314
+ if type_converter is not None:
315
+ return _py_to_cbor(type_converter(value))
316
+
317
+ raise TypeError('unsupported type for conversion to cbor: %r' % (value,))
318
+
319
+
320
+ class NotWellFormed(ValueError):
321
+ """Exception class for well-formedness checks."""
322
+
323
+ def __init__(self, msg):
324
+ super().__init__('not well-formed: ' + str(msg))
325
+
326
+
327
+ class Node(object):
328
+ """Base class for nodes."""
329
+
330
+ __slots__ = ['_annot']
331
+
332
+ def __init__(self):
333
+ super().__init__()
334
+ self._annot = {}
335
+
336
+ def __getitem__(self, key):
337
+ """Returns the annotation object with the specified key, or raises
338
+ KeyError if not found."""
339
+ if not isinstance(key, str):
340
+ raise TypeError('indexing a node with something other than an '
341
+ 'annotation key string')
342
+ return self._annot[key]
343
+
344
+ def __setitem__(self, key, val):
345
+ """Assigns the annotation object with the specified key."""
346
+ if not isinstance(key, str):
347
+ raise TypeError('indexing a node with something other than an '
348
+ 'annotation key string')
349
+ self._annot[key] = val
350
+
351
+ def __delitem__(self, key):
352
+ """Deletes the annotation object with the specified key."""
353
+ if not isinstance(key, str):
354
+ raise TypeError('indexing a node with something other than an '
355
+ 'annotation key string')
356
+ del self._annot[key]
357
+
358
+ def __contains__(self, key):
359
+ """Returns whether an annotation exists for the specified key."""
360
+ return key in self._annot
361
+
362
+ @staticmethod
363
+ def find_reachable(self, id_map=None):
364
+ """Returns a dictionary mapping Python id() values to stable sequence
365
+ numbers for all nodes in the tree rooted at this node. If id_map is
366
+ specified, found nodes are appended to it. Note that this is overridden
367
+ by the actual node class implementations; this base function does very
368
+ little."""
369
+ if id_map is None:
370
+ id_map = {}
371
+ return id_map
372
+
373
+ def check_complete(self, id_map=None):
374
+ """Raises NotWellFormed if the tree rooted at this node is not
375
+ well-formed. If id_map is specified, this tree is only a subtree in the
376
+ context of a larger tree, and id_map must be a dict mapping from Python
377
+ id() codes to tree indices for all reachable nodes. Note that this is
378
+ overridden by the actual node class implementations; this base function
379
+ always raises an exception."""
380
+ raise NotWellFormed('found node of abstract type ' + type(self).__name__)
381
+
382
+ def check_well_formed(self):
383
+ """Checks whether the tree starting at this node is well-formed. That
384
+ is:
385
+
386
+ - all One, Link, and Many edges have (at least) one entry;
387
+ - all the One entries internally stored by Any/Many have an entry;
388
+ - all Link and filled OptLink nodes link to a node that's reachable
389
+ from this node;
390
+ - the nodes referred to be One/Maybe only appear once in the tree
391
+ (except through links).
392
+
393
+ If it isn't well-formed, a NotWellFormed is thrown."""
394
+ self.check_complete()
395
+
396
+ def is_well_formed(self):
397
+ """Returns whether the tree starting at this node is well-formed. That
398
+ is:
399
+
400
+ - all One, Link, and Many edges have (at least) one entry;
401
+ - all the One entries internally stored by Any/Many have an entry;
402
+ - all Link and filled OptLink nodes link to a node that's reachable
403
+ from this node;
404
+ - the nodes referred to be One/Maybe only appear once in the tree
405
+ (except through links)."""
406
+ try:
407
+ self.check_well_formed()
408
+ return True
409
+ except NotWellFormed:
410
+ return False
411
+
412
+ def copy(self):
413
+ """Returns a shallow copy of this node. Note that this is overridden by
414
+ the actual node class implementations; this base function always raises
415
+ an exception."""
416
+ raise TypeError('can\'t copy node of abstract type ' + type(self).__name__)
417
+
418
+ def clone(self):
419
+ """Returns a deep copy of this node. Note that this is overridden by
420
+ the actual node class implementations; this base function always raises
421
+ an exception."""
422
+ raise TypeError('can\'t clone node of abstract type ' + type(self).__name__)
423
+
424
+ @classmethod
425
+ def deserialize(cls, cbor):
426
+ """Attempts to deserialize the given cbor object (either as bytes or as
427
+ its Python primitive representation) into a node of this type."""
428
+ if isinstance(cbor, bytes):
429
+ cbor = _cbor_to_py(cbor)
430
+ seq_to_ob = {}
431
+ links = []
432
+ root = cls._deserialize(cbor, seq_to_ob, links)
433
+ for link_setter, seq in links:
434
+ ob = seq_to_ob.get(seq, None)
435
+ if ob is None:
436
+ raise ValueError('found link to nonexistent object')
437
+ link_setter(ob)
438
+ return root
439
+
440
+ def serialize(self):
441
+ """Serializes this node into its cbor representation in the form of a
442
+ bytes object."""
443
+ id_map = self.find_reachable()
444
+ self.check_complete(id_map)
445
+ return _py_to_cbor(self._serialize(id_map))
446
+
447
+ @staticmethod
448
+ def _deserialize(cbor, seq_to_ob, links):
449
+ if not isinstance(cbor, dict):
450
+ raise TypeError('node description object must be a dict')
451
+ typ = cbor.get('@t', None)
452
+ if typ is None:
453
+ raise ValueError('type (@t) field is missing from node serialization')
454
+ node_type = _typemap.get(cbor.get('@t'), None)
455
+ if node_type is None:
456
+ raise ValueError('unknown node type (@t): ' + str(cbor.get('@t')))
457
+ return node_type._deserialize(cbor, seq_to_ob, links)
458
+
459
+
460
+ @functools.total_ordering
461
+ class _Multiple(object):
462
+ """Base class for the Any* and Many* edge helper classes. Inheriting
463
+ classes must set the class constant _T to the node type they are made
464
+ for."""
465
+
466
+ __slots__ = ['_l']
467
+
468
+ def __init__(self, *args, **kwargs):
469
+ super().__init__()
470
+ self._l = list(*args, **kwargs)
471
+ for idx, val in enumerate(self._l):
472
+ if not isinstance(val, self._T):
473
+ raise TypeError(
474
+ 'object {!r} at index {:d} is not an instance of {!r}'
475
+ .format(val, idx, self._T))
476
+
477
+ def __repr__(self):
478
+ return '{}({!r})'.format(type(self).__name__, self._l)
479
+
480
+ def clone(self):
481
+ return self.__class__(map(lambda node: node.clone(), self._l))
482
+
483
+ def __len__(self):
484
+ return len(self._l)
485
+
486
+ def __getitem__(self, idx):
487
+ return self._l[idx]
488
+
489
+ def __setitem__(self, idx, val):
490
+ if not isinstance(val, self._T):
491
+ raise TypeError(
492
+ 'object {!r} is not an instance of {!r}'
493
+ .format(val, idx, self._T))
494
+ self._l[idx] = val
495
+
496
+ def __delitem__(self, idx):
497
+ del self._l[idx]
498
+
499
+ def __iter__(self):
500
+ return iter(self._l)
501
+
502
+ def __reversed__(self):
503
+ return reversed(self._l)
504
+
505
+ def __contains__(self, val):
506
+ return val in self._l
507
+
508
+ def append(self, val):
509
+ if not isinstance(val, self._T):
510
+ raise TypeError(
511
+ 'object {!r} is not an instance of {!r}'
512
+ .format(val, self._T))
513
+ self._l.append(val)
514
+
515
+ def extend(self, iterable):
516
+ for val in iterable:
517
+ self.append(val)
518
+
519
+ def insert(self, idx, val):
520
+ if not isinstance(val, self._T):
521
+ raise TypeError(
522
+ 'object {!r} is not an instance of {!r}'
523
+ .format(val, self._T))
524
+ self._l.insert(idx, val)
525
+
526
+ def remote(self, val):
527
+ self._l.remove(val)
528
+
529
+ def pop(self, idx=-1):
530
+ return self._l.pop(idx)
531
+
532
+ def clear(self):
533
+ self._l.clear()
534
+
535
+ def idx(self, val, start=0, end=-1):
536
+ return self._l.idx(val, start, end)
537
+
538
+ def count(self, val):
539
+ return self._l.count(val)
540
+
541
+ def sort(self, key=None, reverse=False):
542
+ self._l.sort(key=key, reverse=reverse)
543
+
544
+ def reverse(self):
545
+ self._l.reverse()
546
+
547
+ def copy(self):
548
+ return self.__class__(self)
549
+
550
+ def __eq__(self, other):
551
+ if not isinstance(other, _Multiple):
552
+ return False
553
+ return self._l == other._l
554
+
555
+ def __lt__(self, other):
556
+ return self._l < other._l
557
+
558
+ def __iadd__(self, other):
559
+ self.extend(other)
560
+
561
+ def __add__(self, other):
562
+ copy = self.copy()
563
+ copy += other
564
+ return copy
565
+
566
+ def __imul__(self, other):
567
+ self._l *= other
568
+
569
+ def __mul__(self, other):
570
+ copy = self.copy()
571
+ copy *= other
572
+ return copy
573
+
574
+ def __rmul__(self, other):
575
+ copy = self.copy()
576
+ copy *= other
577
+ return copy
578
+
579
+
580
+ class MultiNode(_Multiple):
581
+ """Wrapper for an edge with multiple Node objects."""
582
+
583
+ _T = Node
584
+
585
+
586
+ def _cloned(obj):
587
+ """Attempts to clone the given object by calling its clone() method, if it
588
+ has one."""
589
+ if hasattr(obj, 'clone'):
590
+ return obj.clone()
591
+ return obj
592
+
593
+
594
+ class Annotated(Node):
595
+ """Represents a node that carries annotation data."""
596
+
597
+ __slots__ = [
598
+ '_attr_annotations',
599
+ ]
600
+
601
+ def __init__(
602
+ self,
603
+ annotations=None,
604
+ ):
605
+ super().__init__()
606
+ self.annotations = annotations
607
+
608
+ @property
609
+ def annotations(self):
610
+ return self._attr_annotations
611
+
612
+ @annotations.setter
613
+ def annotations(self, val):
614
+ if val is None:
615
+ del self.annotations
616
+ return
617
+ if not isinstance(val, MultiAnnotationData):
618
+ # Try to "typecast" if this isn't an obvious mistake.
619
+ if isinstance(val, Node):
620
+ raise TypeError('annotations must be of type MultiAnnotationData')
621
+ val = MultiAnnotationData(val)
622
+ self._attr_annotations = val
623
+
624
+ @annotations.deleter
625
+ def annotations(self):
626
+ self._attr_annotations = MultiAnnotationData()
627
+
628
+ @staticmethod
629
+ def _deserialize(cbor, seq_to_ob, links):
630
+ """Attempts to deserialize the given cbor object (in Python primitive
631
+ representation) into a node of this type. All (sub)nodes are added to
632
+ the seq_to_ob dict, indexed by their cbor sequence number. All links are
633
+ registered in the links list by means of a two-tuple of the setter
634
+ function for the link field and the sequence number of the target node.
635
+ """
636
+ if not isinstance(cbor, dict):
637
+ raise TypeError('node description object must be a dict')
638
+ typ = cbor.get('@t', None)
639
+ if typ is None:
640
+ raise ValueError('type (@t) field is missing from node serialization')
641
+ if typ == 'Gate':
642
+ return Gate._deserialize(cbor, seq_to_ob, links)
643
+ if typ == 'Variable':
644
+ return Variable._deserialize(cbor, seq_to_ob, links)
645
+ if typ == 'GateInstruction':
646
+ return GateInstruction._deserialize(cbor, seq_to_ob, links)
647
+ if typ == 'NonGateInstruction':
648
+ return NonGateInstruction._deserialize(cbor, seq_to_ob, links)
649
+ if typ == 'AsmDeclaration':
650
+ return AsmDeclaration._deserialize(cbor, seq_to_ob, links)
651
+ raise ValueError('unknown or unexpected type (@t) found in node serialization')
652
+
653
+ def _serialize(self, id_map):
654
+ """Serializes this node to the Python primitive representation of its
655
+ CBOR serialization. The tree that the node belongs to must be
656
+ well-formed. id_map must match Python id() calls for all nodes to unique
657
+ integers, to use for the sequence number representation of links."""
658
+ cbor = {'@i': id_map[id(self)], '@t': 'Annotated'}
659
+
660
+ # Serialize the annotations field.
661
+ field = {'@T': '*'}
662
+ lst = []
663
+ for el in self._attr_annotations:
664
+ el = el._serialize(id_map)
665
+ el['@T'] = '1'
666
+ lst.append(el)
667
+ field['@d'] = lst
668
+ cbor['annotations'] = field
669
+
670
+ # Serialize annotations.
671
+ for key, val in self._annot.items():
672
+ cbor['{%s}' % key] = _py_to_cbor(cqasm.v3x.primitives.serialize(key, val))
673
+
674
+ return cbor
675
+
676
+
677
+ class MultiAnnotated(_Multiple):
678
+ """Wrapper for an edge with multiple Annotated objects."""
679
+
680
+ _T = Annotated
681
+
682
+
683
+ _typemap['Annotated'] = Annotated
684
+
685
+ class AnnotationData(Node):
686
+ """Represents an annotation."""
687
+
688
+ __slots__ = [
689
+ '_attr_interface',
690
+ '_attr_operation',
691
+ '_attr_operands',
692
+ ]
693
+
694
+ def __init__(
695
+ self,
696
+ interface=None,
697
+ operation=None,
698
+ operands=None,
699
+ ):
700
+ super().__init__()
701
+ self.interface = interface
702
+ self.operation = operation
703
+ self.operands = operands
704
+
705
+ @property
706
+ def interface(self):
707
+ """The interface this annotation is intended for. If a target doesn't
708
+ support an interface, it should silently ignore the annotation."""
709
+ return self._attr_interface
710
+
711
+ @interface.setter
712
+ def interface(self, val):
713
+ if val is None:
714
+ del self.interface
715
+ return
716
+ if not isinstance(val, cqasm.v3x.primitives.Str):
717
+ # Try to "typecast" if this isn't an obvious mistake.
718
+ if isinstance(val, Node):
719
+ raise TypeError('interface must be of type cqasm.v3x.primitives.Str')
720
+ val = cqasm.v3x.primitives.Str(val)
721
+ self._attr_interface = val
722
+
723
+ @interface.deleter
724
+ def interface(self):
725
+ self._attr_interface = cqasm.v3x.primitives.Str()
726
+
727
+ @property
728
+ def operation(self):
729
+ """The operation within the interface that this annotation is intended
730
+ for. If a target supports the corresponding interface but not the
731
+ operation, it should throw an error."""
732
+ return self._attr_operation
733
+
734
+ @operation.setter
735
+ def operation(self, val):
736
+ if val is None:
737
+ del self.operation
738
+ return
739
+ if not isinstance(val, cqasm.v3x.primitives.Str):
740
+ # Try to "typecast" if this isn't an obvious mistake.
741
+ if isinstance(val, Node):
742
+ raise TypeError('operation must be of type cqasm.v3x.primitives.Str')
743
+ val = cqasm.v3x.primitives.Str(val)
744
+ self._attr_operation = val
745
+
746
+ @operation.deleter
747
+ def operation(self):
748
+ self._attr_operation = cqasm.v3x.primitives.Str()
749
+
750
+ @property
751
+ def operands(self):
752
+ """Any operands attached to the annotation."""
753
+ return self._attr_operands
754
+
755
+ @operands.setter
756
+ def operands(self, val):
757
+ if val is None:
758
+ del self.operands
759
+ return
760
+ if not isinstance(val, cqasm.v3x.values.MultiNode):
761
+ # Try to "typecast" if this isn't an obvious mistake.
762
+ if isinstance(val, Node):
763
+ raise TypeError('operands must be of type cqasm.v3x.values.MultiNode')
764
+ val = cqasm.v3x.values.MultiNode(val)
765
+ self._attr_operands = val
766
+
767
+ @operands.deleter
768
+ def operands(self):
769
+ self._attr_operands = cqasm.v3x.values.MultiNode()
770
+
771
+ def __eq__(self, other):
772
+ """Equality operator. Ignores annotations!"""
773
+ if not isinstance(other, AnnotationData):
774
+ return False
775
+ if self.interface != other.interface:
776
+ return False
777
+ if self.operation != other.operation:
778
+ return False
779
+ if self.operands != other.operands:
780
+ return False
781
+ return True
782
+
783
+ def dump(self, indent=0, annotations=None, links=1):
784
+ """Returns a debug representation of this tree as a multiline string.
785
+ indent is the number of double spaces prefixed before every line.
786
+ annotations, if specified, must be a set-like object containing the key
787
+ strings of the annotations that are to be printed. links specifies the
788
+ maximum link recursion depth."""
789
+ s = [' '*indent]
790
+ s.append('AnnotationData(')
791
+ if annotations is None:
792
+ annotations = []
793
+ for key in annotations:
794
+ if key in self:
795
+ s.append(' # {}: {}'.format(key, self[key]))
796
+ s.append('\n')
797
+ indent += 1
798
+ s.append(' '*indent)
799
+ s.append('interface: ')
800
+ s.append(str(self.interface) + '\n')
801
+ s.append(' '*indent)
802
+ s.append('operation: ')
803
+ s.append(str(self.operation) + '\n')
804
+ s.append(' '*indent)
805
+ s.append('operands: ')
806
+ if not self.operands:
807
+ s.append('-\n')
808
+ else:
809
+ s.append('[\n')
810
+ for child in self.operands:
811
+ s.append(child.dump(indent + 1, annotations, links) + '\n')
812
+ s.append(' '*indent + ']\n')
813
+ indent -= 1
814
+ s.append(' '*indent)
815
+ s.append(')')
816
+ return ''.join(s)
817
+
818
+ __str__ = dump
819
+ __repr__ = dump
820
+
821
+ def find_reachable(self, id_map=None):
822
+ """Returns a dictionary mapping Python id() values to stable sequence
823
+ numbers for all nodes in the tree rooted at this node. If id_map is
824
+ specified, found nodes are appended to it."""
825
+ if id_map is None:
826
+ id_map = {}
827
+ if id(self) in id_map:
828
+ raise NotWellFormed('node {!r} with id {} occurs more than once'.format(self, id(self)))
829
+ id_map[id(self)] = len(id_map)
830
+ for el in self._attr_operands:
831
+ el.find_reachable(id_map)
832
+ return id_map
833
+
834
+ def check_complete(self, id_map=None):
835
+ """Raises NotWellFormed if the tree rooted at this node is not
836
+ well-formed. If id_map is specified, this tree is only a subtree in the
837
+ context of a larger tree, and id_map must be a dict mapping from Python
838
+ id() codes to tree indices for all reachable nodes."""
839
+ if id_map is None:
840
+ id_map = self.find_reachable()
841
+ for child in self._attr_operands:
842
+ child.check_complete(id_map)
843
+
844
+ def copy(self):
845
+ """Returns a shallow copy of this node."""
846
+ return AnnotationData(
847
+ interface=self._attr_interface,
848
+ operation=self._attr_operation,
849
+ operands=self._attr_operands.copy()
850
+ )
851
+
852
+ def clone(self):
853
+ """Returns a deep copy of this node. This mimics the C++ interface,
854
+ deficiencies with links included; that is, links always point to the
855
+ original tree. If you're not cloning a subtree in a context where this
856
+ is the desired behavior, you may want to use the copy.deepcopy() from
857
+ the stdlib instead, which should copy links correctly."""
858
+ return AnnotationData(
859
+ interface=_cloned(self._attr_interface),
860
+ operation=_cloned(self._attr_operation),
861
+ operands=_cloned(self._attr_operands)
862
+ )
863
+
864
+ @staticmethod
865
+ def _deserialize(cbor, seq_to_ob, links):
866
+ """Attempts to deserialize the given cbor object (in Python primitive
867
+ representation) into a node of this type. All (sub)nodes are added to
868
+ the seq_to_ob dict, indexed by their cbor sequence number. All links are
869
+ registered in the links list by means of a two-tuple of the setter
870
+ function for the link field and the sequence number of the target node.
871
+ """
872
+ if not isinstance(cbor, dict):
873
+ raise TypeError('node description object must be a dict')
874
+ typ = cbor.get('@t', None)
875
+ if typ is None:
876
+ raise ValueError('type (@t) field is missing from node serialization')
877
+ if typ != 'AnnotationData':
878
+ raise ValueError('found node serialization for ' + typ + ', but expected AnnotationData')
879
+
880
+ # Deserialize the interface field.
881
+ field = cbor.get('interface', None)
882
+ if not isinstance(field, dict):
883
+ raise ValueError('missing or invalid serialization of field interface')
884
+ if hasattr(cqasm.v3x.primitives.Str, 'deserialize_cbor'):
885
+ f_interface = cqasm.v3x.primitives.Str.deserialize_cbor(field)
886
+ else:
887
+ f_interface = cqasm.v3x.primitives.deserialize(cqasm.v3x.primitives.Str, field)
888
+
889
+ # Deserialize the operation field.
890
+ field = cbor.get('operation', None)
891
+ if not isinstance(field, dict):
892
+ raise ValueError('missing or invalid serialization of field operation')
893
+ if hasattr(cqasm.v3x.primitives.Str, 'deserialize_cbor'):
894
+ f_operation = cqasm.v3x.primitives.Str.deserialize_cbor(field)
895
+ else:
896
+ f_operation = cqasm.v3x.primitives.deserialize(cqasm.v3x.primitives.Str, field)
897
+
898
+ # Deserialize the operands field.
899
+ field = cbor.get('operands', None)
900
+ if not isinstance(field, dict):
901
+ raise ValueError('missing or invalid serialization of field operands')
902
+ if field.get('@T') != '*':
903
+ raise ValueError('unexpected edge type for field operands')
904
+ data = field.get('@d', None)
905
+ if not isinstance(data, list):
906
+ raise ValueError('missing serialization of Any/Many contents')
907
+ f_operands = cqasm.v3x.values.MultiNode()
908
+ for element in data:
909
+ if element.get('@T') != '1':
910
+ raise ValueError('unexpected edge type for Any/Many element')
911
+ f_operands.append(cqasm.v3x.values.Node._deserialize(element, seq_to_ob, links))
912
+
913
+ # Construct the AnnotationData node.
914
+ node = AnnotationData(f_interface, f_operation, f_operands)
915
+
916
+ # Deserialize annotations.
917
+ for key, val in cbor.items():
918
+ if not (key.startswith('{') and key.endswith('}')):
919
+ continue
920
+ key = key[1:-1]
921
+ node[key] = cqasm.v3x.primitives.deserialize(key, val)
922
+
923
+ # Register node in sequence number lookup.
924
+ seq = cbor.get('@i', None)
925
+ if not isinstance(seq, int):
926
+ raise ValueError('sequence number field (@i) is not an integer or missing from node serialization')
927
+ if seq in seq_to_ob:
928
+ raise ValueError('duplicate sequence number %d' % seq)
929
+ seq_to_ob[seq] = node
930
+
931
+ return node
932
+
933
+ def _serialize(self, id_map):
934
+ """Serializes this node to the Python primitive representation of its
935
+ CBOR serialization. The tree that the node belongs to must be
936
+ well-formed. id_map must match Python id() calls for all nodes to unique
937
+ integers, to use for the sequence number representation of links."""
938
+ cbor = {'@i': id_map[id(self)], '@t': 'AnnotationData'}
939
+
940
+ # Serialize the interface field.
941
+ if hasattr(self._attr_interface, 'serialize_cbor'):
942
+ cbor['interface'] = self._attr_interface.serialize_cbor()
943
+ else:
944
+ cbor['interface'] = cqasm.v3x.primitives.serialize(cqasm.v3x.primitives.Str, self._attr_interface)
945
+
946
+ # Serialize the operation field.
947
+ if hasattr(self._attr_operation, 'serialize_cbor'):
948
+ cbor['operation'] = self._attr_operation.serialize_cbor()
949
+ else:
950
+ cbor['operation'] = cqasm.v3x.primitives.serialize(cqasm.v3x.primitives.Str, self._attr_operation)
951
+
952
+ # Serialize the operands field.
953
+ field = {'@T': '*'}
954
+ lst = []
955
+ for el in self._attr_operands:
956
+ el = el._serialize(id_map)
957
+ el['@T'] = '1'
958
+ lst.append(el)
959
+ field['@d'] = lst
960
+ cbor['operands'] = field
961
+
962
+ # Serialize annotations.
963
+ for key, val in self._annot.items():
964
+ cbor['{%s}' % key] = _py_to_cbor(cqasm.v3x.primitives.serialize(key, val))
965
+
966
+ return cbor
967
+
968
+
969
+ class MultiAnnotationData(_Multiple):
970
+ """Wrapper for an edge with multiple AnnotationData objects."""
971
+
972
+ _T = AnnotationData
973
+
974
+
975
+ _typemap['AnnotationData'] = AnnotationData
976
+
977
+ class Statement(Annotated):
978
+ __slots__ = []
979
+
980
+ def __init__(
981
+ self,
982
+ annotations=None,
983
+ ):
984
+ super().__init__(annotations=annotations)
985
+
986
+ @staticmethod
987
+ def _deserialize(cbor, seq_to_ob, links):
988
+ """Attempts to deserialize the given cbor object (in Python primitive
989
+ representation) into a node of this type. All (sub)nodes are added to
990
+ the seq_to_ob dict, indexed by their cbor sequence number. All links are
991
+ registered in the links list by means of a two-tuple of the setter
992
+ function for the link field and the sequence number of the target node.
993
+ """
994
+ if not isinstance(cbor, dict):
995
+ raise TypeError('node description object must be a dict')
996
+ typ = cbor.get('@t', None)
997
+ if typ is None:
998
+ raise ValueError('type (@t) field is missing from node serialization')
999
+ if typ == 'GateInstruction':
1000
+ return GateInstruction._deserialize(cbor, seq_to_ob, links)
1001
+ if typ == 'NonGateInstruction':
1002
+ return NonGateInstruction._deserialize(cbor, seq_to_ob, links)
1003
+ if typ == 'AsmDeclaration':
1004
+ return AsmDeclaration._deserialize(cbor, seq_to_ob, links)
1005
+ raise ValueError('unknown or unexpected type (@t) found in node serialization')
1006
+
1007
+ def _serialize(self, id_map):
1008
+ """Serializes this node to the Python primitive representation of its
1009
+ CBOR serialization. The tree that the node belongs to must be
1010
+ well-formed. id_map must match Python id() calls for all nodes to unique
1011
+ integers, to use for the sequence number representation of links."""
1012
+ cbor = {'@i': id_map[id(self)], '@t': 'Statement'}
1013
+
1014
+ # Serialize the annotations field.
1015
+ field = {'@T': '*'}
1016
+ lst = []
1017
+ for el in self._attr_annotations:
1018
+ el = el._serialize(id_map)
1019
+ el['@T'] = '1'
1020
+ lst.append(el)
1021
+ field['@d'] = lst
1022
+ cbor['annotations'] = field
1023
+
1024
+ # Serialize annotations.
1025
+ for key, val in self._annot.items():
1026
+ cbor['{%s}' % key] = _py_to_cbor(cqasm.v3x.primitives.serialize(key, val))
1027
+
1028
+ return cbor
1029
+
1030
+
1031
+ class MultiStatement(_Multiple):
1032
+ """Wrapper for an edge with multiple Statement objects."""
1033
+
1034
+ _T = Statement
1035
+
1036
+
1037
+ _typemap['Statement'] = Statement
1038
+
1039
+ class Instruction(Statement):
1040
+ __slots__ = []
1041
+
1042
+ def __init__(
1043
+ self,
1044
+ annotations=None,
1045
+ ):
1046
+ super().__init__(annotations=annotations)
1047
+
1048
+ @staticmethod
1049
+ def _deserialize(cbor, seq_to_ob, links):
1050
+ """Attempts to deserialize the given cbor object (in Python primitive
1051
+ representation) into a node of this type. All (sub)nodes are added to
1052
+ the seq_to_ob dict, indexed by their cbor sequence number. All links are
1053
+ registered in the links list by means of a two-tuple of the setter
1054
+ function for the link field and the sequence number of the target node.
1055
+ """
1056
+ if not isinstance(cbor, dict):
1057
+ raise TypeError('node description object must be a dict')
1058
+ typ = cbor.get('@t', None)
1059
+ if typ is None:
1060
+ raise ValueError('type (@t) field is missing from node serialization')
1061
+ if typ == 'GateInstruction':
1062
+ return GateInstruction._deserialize(cbor, seq_to_ob, links)
1063
+ if typ == 'NonGateInstruction':
1064
+ return NonGateInstruction._deserialize(cbor, seq_to_ob, links)
1065
+ if typ == 'AsmDeclaration':
1066
+ return AsmDeclaration._deserialize(cbor, seq_to_ob, links)
1067
+ raise ValueError('unknown or unexpected type (@t) found in node serialization')
1068
+
1069
+ def _serialize(self, id_map):
1070
+ """Serializes this node to the Python primitive representation of its
1071
+ CBOR serialization. The tree that the node belongs to must be
1072
+ well-formed. id_map must match Python id() calls for all nodes to unique
1073
+ integers, to use for the sequence number representation of links."""
1074
+ cbor = {'@i': id_map[id(self)], '@t': 'Instruction'}
1075
+
1076
+ # Serialize the annotations field.
1077
+ field = {'@T': '*'}
1078
+ lst = []
1079
+ for el in self._attr_annotations:
1080
+ el = el._serialize(id_map)
1081
+ el['@T'] = '1'
1082
+ lst.append(el)
1083
+ field['@d'] = lst
1084
+ cbor['annotations'] = field
1085
+
1086
+ # Serialize annotations.
1087
+ for key, val in self._annot.items():
1088
+ cbor['{%s}' % key] = _py_to_cbor(cqasm.v3x.primitives.serialize(key, val))
1089
+
1090
+ return cbor
1091
+
1092
+
1093
+ class MultiInstruction(_Multiple):
1094
+ """Wrapper for an edge with multiple Instruction objects."""
1095
+
1096
+ _T = Instruction
1097
+
1098
+
1099
+ _typemap['Instruction'] = Instruction
1100
+
1101
+ class AsmDeclaration(Instruction):
1102
+ __slots__ = [
1103
+ '_attr_backend_name',
1104
+ '_attr_backend_code',
1105
+ ]
1106
+
1107
+ def __init__(
1108
+ self,
1109
+ backend_name=None,
1110
+ backend_code=None,
1111
+ annotations=None,
1112
+ ):
1113
+ super().__init__(annotations=annotations)
1114
+ self.backend_name = backend_name
1115
+ self.backend_code = backend_code
1116
+
1117
+ @property
1118
+ def backend_name(self):
1119
+ return self._attr_backend_name
1120
+
1121
+ @backend_name.setter
1122
+ def backend_name(self, val):
1123
+ if val is None:
1124
+ del self.backend_name
1125
+ return
1126
+ if not isinstance(val, cqasm.v3x.primitives.Str):
1127
+ # Try to "typecast" if this isn't an obvious mistake.
1128
+ if isinstance(val, Node):
1129
+ raise TypeError('backend_name must be of type cqasm.v3x.primitives.Str')
1130
+ val = cqasm.v3x.primitives.Str(val)
1131
+ self._attr_backend_name = val
1132
+
1133
+ @backend_name.deleter
1134
+ def backend_name(self):
1135
+ self._attr_backend_name = cqasm.v3x.primitives.Str()
1136
+
1137
+ @property
1138
+ def backend_code(self):
1139
+ return self._attr_backend_code
1140
+
1141
+ @backend_code.setter
1142
+ def backend_code(self, val):
1143
+ if val is None:
1144
+ del self.backend_code
1145
+ return
1146
+ if not isinstance(val, cqasm.v3x.primitives.Str):
1147
+ # Try to "typecast" if this isn't an obvious mistake.
1148
+ if isinstance(val, Node):
1149
+ raise TypeError('backend_code must be of type cqasm.v3x.primitives.Str')
1150
+ val = cqasm.v3x.primitives.Str(val)
1151
+ self._attr_backend_code = val
1152
+
1153
+ @backend_code.deleter
1154
+ def backend_code(self):
1155
+ self._attr_backend_code = cqasm.v3x.primitives.Str()
1156
+
1157
+ def __eq__(self, other):
1158
+ """Equality operator. Ignores annotations!"""
1159
+ if not isinstance(other, AsmDeclaration):
1160
+ return False
1161
+ if self.backend_name != other.backend_name:
1162
+ return False
1163
+ if self.backend_code != other.backend_code:
1164
+ return False
1165
+ if self.annotations != other.annotations:
1166
+ return False
1167
+ return True
1168
+
1169
+ def dump(self, indent=0, annotations=None, links=1):
1170
+ """Returns a debug representation of this tree as a multiline string.
1171
+ indent is the number of double spaces prefixed before every line.
1172
+ annotations, if specified, must be a set-like object containing the key
1173
+ strings of the annotations that are to be printed. links specifies the
1174
+ maximum link recursion depth."""
1175
+ s = [' '*indent]
1176
+ s.append('AsmDeclaration(')
1177
+ if annotations is None:
1178
+ annotations = []
1179
+ for key in annotations:
1180
+ if key in self:
1181
+ s.append(' # {}: {}'.format(key, self[key]))
1182
+ s.append('\n')
1183
+ indent += 1
1184
+ s.append(' '*indent)
1185
+ s.append('backend_name: ')
1186
+ s.append(str(self.backend_name) + '\n')
1187
+ s.append(' '*indent)
1188
+ s.append('backend_code: ')
1189
+ s.append(str(self.backend_code) + '\n')
1190
+ s.append(' '*indent)
1191
+ s.append('annotations: ')
1192
+ if not self.annotations:
1193
+ s.append('-\n')
1194
+ else:
1195
+ s.append('[\n')
1196
+ for child in self.annotations:
1197
+ s.append(child.dump(indent + 1, annotations, links) + '\n')
1198
+ s.append(' '*indent + ']\n')
1199
+ indent -= 1
1200
+ s.append(' '*indent)
1201
+ s.append(')')
1202
+ return ''.join(s)
1203
+
1204
+ __str__ = dump
1205
+ __repr__ = dump
1206
+
1207
+ def find_reachable(self, id_map=None):
1208
+ """Returns a dictionary mapping Python id() values to stable sequence
1209
+ numbers for all nodes in the tree rooted at this node. If id_map is
1210
+ specified, found nodes are appended to it."""
1211
+ if id_map is None:
1212
+ id_map = {}
1213
+ if id(self) in id_map:
1214
+ raise NotWellFormed('node {!r} with id {} occurs more than once'.format(self, id(self)))
1215
+ id_map[id(self)] = len(id_map)
1216
+ for el in self._attr_annotations:
1217
+ el.find_reachable(id_map)
1218
+ return id_map
1219
+
1220
+ def check_complete(self, id_map=None):
1221
+ """Raises NotWellFormed if the tree rooted at this node is not
1222
+ well-formed. If id_map is specified, this tree is only a subtree in the
1223
+ context of a larger tree, and id_map must be a dict mapping from Python
1224
+ id() codes to tree indices for all reachable nodes."""
1225
+ if id_map is None:
1226
+ id_map = self.find_reachable()
1227
+ for child in self._attr_annotations:
1228
+ child.check_complete(id_map)
1229
+
1230
+ def copy(self):
1231
+ """Returns a shallow copy of this node."""
1232
+ return AsmDeclaration(
1233
+ backend_name=self._attr_backend_name,
1234
+ backend_code=self._attr_backend_code,
1235
+ annotations=self._attr_annotations.copy()
1236
+ )
1237
+
1238
+ def clone(self):
1239
+ """Returns a deep copy of this node. This mimics the C++ interface,
1240
+ deficiencies with links included; that is, links always point to the
1241
+ original tree. If you're not cloning a subtree in a context where this
1242
+ is the desired behavior, you may want to use the copy.deepcopy() from
1243
+ the stdlib instead, which should copy links correctly."""
1244
+ return AsmDeclaration(
1245
+ backend_name=_cloned(self._attr_backend_name),
1246
+ backend_code=_cloned(self._attr_backend_code),
1247
+ annotations=_cloned(self._attr_annotations)
1248
+ )
1249
+
1250
+ @staticmethod
1251
+ def _deserialize(cbor, seq_to_ob, links):
1252
+ """Attempts to deserialize the given cbor object (in Python primitive
1253
+ representation) into a node of this type. All (sub)nodes are added to
1254
+ the seq_to_ob dict, indexed by their cbor sequence number. All links are
1255
+ registered in the links list by means of a two-tuple of the setter
1256
+ function for the link field and the sequence number of the target node.
1257
+ """
1258
+ if not isinstance(cbor, dict):
1259
+ raise TypeError('node description object must be a dict')
1260
+ typ = cbor.get('@t', None)
1261
+ if typ is None:
1262
+ raise ValueError('type (@t) field is missing from node serialization')
1263
+ if typ != 'AsmDeclaration':
1264
+ raise ValueError('found node serialization for ' + typ + ', but expected AsmDeclaration')
1265
+
1266
+ # Deserialize the backend_name field.
1267
+ field = cbor.get('backend_name', None)
1268
+ if not isinstance(field, dict):
1269
+ raise ValueError('missing or invalid serialization of field backend_name')
1270
+ if hasattr(cqasm.v3x.primitives.Str, 'deserialize_cbor'):
1271
+ f_backend_name = cqasm.v3x.primitives.Str.deserialize_cbor(field)
1272
+ else:
1273
+ f_backend_name = cqasm.v3x.primitives.deserialize(cqasm.v3x.primitives.Str, field)
1274
+
1275
+ # Deserialize the backend_code field.
1276
+ field = cbor.get('backend_code', None)
1277
+ if not isinstance(field, dict):
1278
+ raise ValueError('missing or invalid serialization of field backend_code')
1279
+ if hasattr(cqasm.v3x.primitives.Str, 'deserialize_cbor'):
1280
+ f_backend_code = cqasm.v3x.primitives.Str.deserialize_cbor(field)
1281
+ else:
1282
+ f_backend_code = cqasm.v3x.primitives.deserialize(cqasm.v3x.primitives.Str, field)
1283
+
1284
+ # Deserialize the annotations field.
1285
+ field = cbor.get('annotations', None)
1286
+ if not isinstance(field, dict):
1287
+ raise ValueError('missing or invalid serialization of field annotations')
1288
+ if field.get('@T') != '*':
1289
+ raise ValueError('unexpected edge type for field annotations')
1290
+ data = field.get('@d', None)
1291
+ if not isinstance(data, list):
1292
+ raise ValueError('missing serialization of Any/Many contents')
1293
+ f_annotations = MultiAnnotationData()
1294
+ for element in data:
1295
+ if element.get('@T') != '1':
1296
+ raise ValueError('unexpected edge type for Any/Many element')
1297
+ f_annotations.append(AnnotationData._deserialize(element, seq_to_ob, links))
1298
+
1299
+ # Construct the AsmDeclaration node.
1300
+ node = AsmDeclaration(f_backend_name, f_backend_code, f_annotations)
1301
+
1302
+ # Deserialize annotations.
1303
+ for key, val in cbor.items():
1304
+ if not (key.startswith('{') and key.endswith('}')):
1305
+ continue
1306
+ key = key[1:-1]
1307
+ node[key] = cqasm.v3x.primitives.deserialize(key, val)
1308
+
1309
+ # Register node in sequence number lookup.
1310
+ seq = cbor.get('@i', None)
1311
+ if not isinstance(seq, int):
1312
+ raise ValueError('sequence number field (@i) is not an integer or missing from node serialization')
1313
+ if seq in seq_to_ob:
1314
+ raise ValueError('duplicate sequence number %d' % seq)
1315
+ seq_to_ob[seq] = node
1316
+
1317
+ return node
1318
+
1319
+ def _serialize(self, id_map):
1320
+ """Serializes this node to the Python primitive representation of its
1321
+ CBOR serialization. The tree that the node belongs to must be
1322
+ well-formed. id_map must match Python id() calls for all nodes to unique
1323
+ integers, to use for the sequence number representation of links."""
1324
+ cbor = {'@i': id_map[id(self)], '@t': 'AsmDeclaration'}
1325
+
1326
+ # Serialize the backend_name field.
1327
+ if hasattr(self._attr_backend_name, 'serialize_cbor'):
1328
+ cbor['backend_name'] = self._attr_backend_name.serialize_cbor()
1329
+ else:
1330
+ cbor['backend_name'] = cqasm.v3x.primitives.serialize(cqasm.v3x.primitives.Str, self._attr_backend_name)
1331
+
1332
+ # Serialize the backend_code field.
1333
+ if hasattr(self._attr_backend_code, 'serialize_cbor'):
1334
+ cbor['backend_code'] = self._attr_backend_code.serialize_cbor()
1335
+ else:
1336
+ cbor['backend_code'] = cqasm.v3x.primitives.serialize(cqasm.v3x.primitives.Str, self._attr_backend_code)
1337
+
1338
+ # Serialize the annotations field.
1339
+ field = {'@T': '*'}
1340
+ lst = []
1341
+ for el in self._attr_annotations:
1342
+ el = el._serialize(id_map)
1343
+ el['@T'] = '1'
1344
+ lst.append(el)
1345
+ field['@d'] = lst
1346
+ cbor['annotations'] = field
1347
+
1348
+ # Serialize annotations.
1349
+ for key, val in self._annot.items():
1350
+ cbor['{%s}' % key] = _py_to_cbor(cqasm.v3x.primitives.serialize(key, val))
1351
+
1352
+ return cbor
1353
+
1354
+
1355
+ class MultiAsmDeclaration(_Multiple):
1356
+ """Wrapper for an edge with multiple AsmDeclaration objects."""
1357
+
1358
+ _T = AsmDeclaration
1359
+
1360
+
1361
+ _typemap['AsmDeclaration'] = AsmDeclaration
1362
+
1363
+ class Block(Node):
1364
+ __slots__ = [
1365
+ '_attr_statements',
1366
+ ]
1367
+
1368
+ def __init__(
1369
+ self,
1370
+ statements=None,
1371
+ ):
1372
+ super().__init__()
1373
+ self.statements = statements
1374
+
1375
+ @property
1376
+ def statements(self):
1377
+ return self._attr_statements
1378
+
1379
+ @statements.setter
1380
+ def statements(self, val):
1381
+ if val is None:
1382
+ del self.statements
1383
+ return
1384
+ if not isinstance(val, MultiStatement):
1385
+ # Try to "typecast" if this isn't an obvious mistake.
1386
+ if isinstance(val, Node):
1387
+ raise TypeError('statements must be of type MultiStatement')
1388
+ val = MultiStatement(val)
1389
+ self._attr_statements = val
1390
+
1391
+ @statements.deleter
1392
+ def statements(self):
1393
+ self._attr_statements = MultiStatement()
1394
+
1395
+ def __eq__(self, other):
1396
+ """Equality operator. Ignores annotations!"""
1397
+ if not isinstance(other, Block):
1398
+ return False
1399
+ if self.statements != other.statements:
1400
+ return False
1401
+ return True
1402
+
1403
+ def dump(self, indent=0, annotations=None, links=1):
1404
+ """Returns a debug representation of this tree as a multiline string.
1405
+ indent is the number of double spaces prefixed before every line.
1406
+ annotations, if specified, must be a set-like object containing the key
1407
+ strings of the annotations that are to be printed. links specifies the
1408
+ maximum link recursion depth."""
1409
+ s = [' '*indent]
1410
+ s.append('Block(')
1411
+ if annotations is None:
1412
+ annotations = []
1413
+ for key in annotations:
1414
+ if key in self:
1415
+ s.append(' # {}: {}'.format(key, self[key]))
1416
+ s.append('\n')
1417
+ indent += 1
1418
+ s.append(' '*indent)
1419
+ s.append('statements: ')
1420
+ if not self.statements:
1421
+ s.append('-\n')
1422
+ else:
1423
+ s.append('[\n')
1424
+ for child in self.statements:
1425
+ s.append(child.dump(indent + 1, annotations, links) + '\n')
1426
+ s.append(' '*indent + ']\n')
1427
+ indent -= 1
1428
+ s.append(' '*indent)
1429
+ s.append(')')
1430
+ return ''.join(s)
1431
+
1432
+ __str__ = dump
1433
+ __repr__ = dump
1434
+
1435
+ def find_reachable(self, id_map=None):
1436
+ """Returns a dictionary mapping Python id() values to stable sequence
1437
+ numbers for all nodes in the tree rooted at this node. If id_map is
1438
+ specified, found nodes are appended to it."""
1439
+ if id_map is None:
1440
+ id_map = {}
1441
+ if id(self) in id_map:
1442
+ raise NotWellFormed('node {!r} with id {} occurs more than once'.format(self, id(self)))
1443
+ id_map[id(self)] = len(id_map)
1444
+ for el in self._attr_statements:
1445
+ el.find_reachable(id_map)
1446
+ return id_map
1447
+
1448
+ def check_complete(self, id_map=None):
1449
+ """Raises NotWellFormed if the tree rooted at this node is not
1450
+ well-formed. If id_map is specified, this tree is only a subtree in the
1451
+ context of a larger tree, and id_map must be a dict mapping from Python
1452
+ id() codes to tree indices for all reachable nodes."""
1453
+ if id_map is None:
1454
+ id_map = self.find_reachable()
1455
+ for child in self._attr_statements:
1456
+ child.check_complete(id_map)
1457
+
1458
+ def copy(self):
1459
+ """Returns a shallow copy of this node."""
1460
+ return Block(
1461
+ statements=self._attr_statements.copy()
1462
+ )
1463
+
1464
+ def clone(self):
1465
+ """Returns a deep copy of this node. This mimics the C++ interface,
1466
+ deficiencies with links included; that is, links always point to the
1467
+ original tree. If you're not cloning a subtree in a context where this
1468
+ is the desired behavior, you may want to use the copy.deepcopy() from
1469
+ the stdlib instead, which should copy links correctly."""
1470
+ return Block(
1471
+ statements=_cloned(self._attr_statements)
1472
+ )
1473
+
1474
+ @staticmethod
1475
+ def _deserialize(cbor, seq_to_ob, links):
1476
+ """Attempts to deserialize the given cbor object (in Python primitive
1477
+ representation) into a node of this type. All (sub)nodes are added to
1478
+ the seq_to_ob dict, indexed by their cbor sequence number. All links are
1479
+ registered in the links list by means of a two-tuple of the setter
1480
+ function for the link field and the sequence number of the target node.
1481
+ """
1482
+ if not isinstance(cbor, dict):
1483
+ raise TypeError('node description object must be a dict')
1484
+ typ = cbor.get('@t', None)
1485
+ if typ is None:
1486
+ raise ValueError('type (@t) field is missing from node serialization')
1487
+ if typ != 'Block':
1488
+ raise ValueError('found node serialization for ' + typ + ', but expected Block')
1489
+
1490
+ # Deserialize the statements field.
1491
+ field = cbor.get('statements', None)
1492
+ if not isinstance(field, dict):
1493
+ raise ValueError('missing or invalid serialization of field statements')
1494
+ if field.get('@T') != '*':
1495
+ raise ValueError('unexpected edge type for field statements')
1496
+ data = field.get('@d', None)
1497
+ if not isinstance(data, list):
1498
+ raise ValueError('missing serialization of Any/Many contents')
1499
+ f_statements = MultiStatement()
1500
+ for element in data:
1501
+ if element.get('@T') != '1':
1502
+ raise ValueError('unexpected edge type for Any/Many element')
1503
+ f_statements.append(Statement._deserialize(element, seq_to_ob, links))
1504
+
1505
+ # Construct the Block node.
1506
+ node = Block(f_statements)
1507
+
1508
+ # Deserialize annotations.
1509
+ for key, val in cbor.items():
1510
+ if not (key.startswith('{') and key.endswith('}')):
1511
+ continue
1512
+ key = key[1:-1]
1513
+ node[key] = cqasm.v3x.primitives.deserialize(key, val)
1514
+
1515
+ # Register node in sequence number lookup.
1516
+ seq = cbor.get('@i', None)
1517
+ if not isinstance(seq, int):
1518
+ raise ValueError('sequence number field (@i) is not an integer or missing from node serialization')
1519
+ if seq in seq_to_ob:
1520
+ raise ValueError('duplicate sequence number %d' % seq)
1521
+ seq_to_ob[seq] = node
1522
+
1523
+ return node
1524
+
1525
+ def _serialize(self, id_map):
1526
+ """Serializes this node to the Python primitive representation of its
1527
+ CBOR serialization. The tree that the node belongs to must be
1528
+ well-formed. id_map must match Python id() calls for all nodes to unique
1529
+ integers, to use for the sequence number representation of links."""
1530
+ cbor = {'@i': id_map[id(self)], '@t': 'Block'}
1531
+
1532
+ # Serialize the statements field.
1533
+ field = {'@T': '*'}
1534
+ lst = []
1535
+ for el in self._attr_statements:
1536
+ el = el._serialize(id_map)
1537
+ el['@T'] = '1'
1538
+ lst.append(el)
1539
+ field['@d'] = lst
1540
+ cbor['statements'] = field
1541
+
1542
+ # Serialize annotations.
1543
+ for key, val in self._annot.items():
1544
+ cbor['{%s}' % key] = _py_to_cbor(cqasm.v3x.primitives.serialize(key, val))
1545
+
1546
+ return cbor
1547
+
1548
+
1549
+ class MultiBlock(_Multiple):
1550
+ """Wrapper for an edge with multiple Block objects."""
1551
+
1552
+ _T = Block
1553
+
1554
+
1555
+ _typemap['Block'] = Block
1556
+
1557
+ class Gate(Annotated):
1558
+ """A gate can be a named gate or a composition of gate modifiers acting on a
1559
+ gate. pow is the only gate modifier that has an operand."""
1560
+
1561
+ __slots__ = [
1562
+ '_attr_name',
1563
+ '_attr_gate',
1564
+ '_attr_parameters',
1565
+ ]
1566
+
1567
+ def __init__(
1568
+ self,
1569
+ name=None,
1570
+ gate=None,
1571
+ parameters=None,
1572
+ annotations=None,
1573
+ ):
1574
+ super().__init__(annotations=annotations)
1575
+ self.name = name
1576
+ self.gate = gate
1577
+ self.parameters = parameters
1578
+
1579
+ @property
1580
+ def name(self):
1581
+ return self._attr_name
1582
+
1583
+ @name.setter
1584
+ def name(self, val):
1585
+ if val is None:
1586
+ del self.name
1587
+ return
1588
+ if not isinstance(val, cqasm.v3x.primitives.Str):
1589
+ # Try to "typecast" if this isn't an obvious mistake.
1590
+ if isinstance(val, Node):
1591
+ raise TypeError('name must be of type cqasm.v3x.primitives.Str')
1592
+ val = cqasm.v3x.primitives.Str(val)
1593
+ self._attr_name = val
1594
+
1595
+ @name.deleter
1596
+ def name(self):
1597
+ self._attr_name = cqasm.v3x.primitives.Str()
1598
+
1599
+ @property
1600
+ def gate(self):
1601
+ return self._attr_gate
1602
+
1603
+ @gate.setter
1604
+ def gate(self, val):
1605
+ if val is None:
1606
+ del self.gate
1607
+ return
1608
+ if not isinstance(val, Gate):
1609
+ # Try to "typecast" if this isn't an obvious mistake.
1610
+ if isinstance(val, Node):
1611
+ raise TypeError('gate must be of type Gate')
1612
+ val = Gate(val)
1613
+ self._attr_gate = val
1614
+
1615
+ @gate.deleter
1616
+ def gate(self):
1617
+ self._attr_gate = None
1618
+
1619
+ @property
1620
+ def parameters(self):
1621
+ return self._attr_parameters
1622
+
1623
+ @parameters.setter
1624
+ def parameters(self, val):
1625
+ if val is None:
1626
+ del self.parameters
1627
+ return
1628
+ if not isinstance(val, cqasm.v3x.values.MultiValueBase):
1629
+ # Try to "typecast" if this isn't an obvious mistake.
1630
+ if isinstance(val, Node):
1631
+ raise TypeError('parameters must be of type cqasm.v3x.values.MultiValueBase')
1632
+ val = cqasm.v3x.values.MultiValueBase(val)
1633
+ self._attr_parameters = val
1634
+
1635
+ @parameters.deleter
1636
+ def parameters(self):
1637
+ self._attr_parameters = cqasm.v3x.values.MultiValueBase()
1638
+
1639
+ def __eq__(self, other):
1640
+ """Equality operator. Ignores annotations!"""
1641
+ if not isinstance(other, Gate):
1642
+ return False
1643
+ if self.name != other.name:
1644
+ return False
1645
+ if self.gate != other.gate:
1646
+ return False
1647
+ if self.parameters != other.parameters:
1648
+ return False
1649
+ if self.annotations != other.annotations:
1650
+ return False
1651
+ return True
1652
+
1653
+ def dump(self, indent=0, annotations=None, links=1):
1654
+ """Returns a debug representation of this tree as a multiline string.
1655
+ indent is the number of double spaces prefixed before every line.
1656
+ annotations, if specified, must be a set-like object containing the key
1657
+ strings of the annotations that are to be printed. links specifies the
1658
+ maximum link recursion depth."""
1659
+ s = [' '*indent]
1660
+ s.append('Gate(')
1661
+ if annotations is None:
1662
+ annotations = []
1663
+ for key in annotations:
1664
+ if key in self:
1665
+ s.append(' # {}: {}'.format(key, self[key]))
1666
+ s.append('\n')
1667
+ indent += 1
1668
+ s.append(' '*indent)
1669
+ s.append('name: ')
1670
+ s.append(str(self.name) + '\n')
1671
+ s.append(' '*indent)
1672
+ s.append('gate: ')
1673
+ if self.gate is None:
1674
+ s.append('-\n')
1675
+ else:
1676
+ s.append('<\n')
1677
+ s.append(self.gate.dump(indent + 1, annotations, links) + '\n')
1678
+ s.append(' '*indent + '>\n')
1679
+ s.append(' '*indent)
1680
+ s.append('parameters: ')
1681
+ if not self.parameters:
1682
+ s.append('-\n')
1683
+ else:
1684
+ s.append('[\n')
1685
+ for child in self.parameters:
1686
+ s.append(child.dump(indent + 1, annotations, links) + '\n')
1687
+ s.append(' '*indent + ']\n')
1688
+ s.append(' '*indent)
1689
+ s.append('annotations: ')
1690
+ if not self.annotations:
1691
+ s.append('-\n')
1692
+ else:
1693
+ s.append('[\n')
1694
+ for child in self.annotations:
1695
+ s.append(child.dump(indent + 1, annotations, links) + '\n')
1696
+ s.append(' '*indent + ']\n')
1697
+ indent -= 1
1698
+ s.append(' '*indent)
1699
+ s.append(')')
1700
+ return ''.join(s)
1701
+
1702
+ __str__ = dump
1703
+ __repr__ = dump
1704
+
1705
+ def find_reachable(self, id_map=None):
1706
+ """Returns a dictionary mapping Python id() values to stable sequence
1707
+ numbers for all nodes in the tree rooted at this node. If id_map is
1708
+ specified, found nodes are appended to it."""
1709
+ if id_map is None:
1710
+ id_map = {}
1711
+ if id(self) in id_map:
1712
+ raise NotWellFormed('node {!r} with id {} occurs more than once'.format(self, id(self)))
1713
+ id_map[id(self)] = len(id_map)
1714
+ if self._attr_gate is not None:
1715
+ self._attr_gate.find_reachable(id_map)
1716
+ for el in self._attr_parameters:
1717
+ el.find_reachable(id_map)
1718
+ for el in self._attr_annotations:
1719
+ el.find_reachable(id_map)
1720
+ return id_map
1721
+
1722
+ def check_complete(self, id_map=None):
1723
+ """Raises NotWellFormed if the tree rooted at this node is not
1724
+ well-formed. If id_map is specified, this tree is only a subtree in the
1725
+ context of a larger tree, and id_map must be a dict mapping from Python
1726
+ id() codes to tree indices for all reachable nodes."""
1727
+ if id_map is None:
1728
+ id_map = self.find_reachable()
1729
+ if self._attr_gate is not None:
1730
+ self._attr_gate.check_complete(id_map)
1731
+ for child in self._attr_parameters:
1732
+ child.check_complete(id_map)
1733
+ for child in self._attr_annotations:
1734
+ child.check_complete(id_map)
1735
+
1736
+ def copy(self):
1737
+ """Returns a shallow copy of this node."""
1738
+ return Gate(
1739
+ name=self._attr_name,
1740
+ gate=self._attr_gate,
1741
+ parameters=self._attr_parameters.copy(),
1742
+ annotations=self._attr_annotations.copy()
1743
+ )
1744
+
1745
+ def clone(self):
1746
+ """Returns a deep copy of this node. This mimics the C++ interface,
1747
+ deficiencies with links included; that is, links always point to the
1748
+ original tree. If you're not cloning a subtree in a context where this
1749
+ is the desired behavior, you may want to use the copy.deepcopy() from
1750
+ the stdlib instead, which should copy links correctly."""
1751
+ return Gate(
1752
+ name=_cloned(self._attr_name),
1753
+ gate=_cloned(self._attr_gate),
1754
+ parameters=_cloned(self._attr_parameters),
1755
+ annotations=_cloned(self._attr_annotations)
1756
+ )
1757
+
1758
+ @staticmethod
1759
+ def _deserialize(cbor, seq_to_ob, links):
1760
+ """Attempts to deserialize the given cbor object (in Python primitive
1761
+ representation) into a node of this type. All (sub)nodes are added to
1762
+ the seq_to_ob dict, indexed by their cbor sequence number. All links are
1763
+ registered in the links list by means of a two-tuple of the setter
1764
+ function for the link field and the sequence number of the target node.
1765
+ """
1766
+ if not isinstance(cbor, dict):
1767
+ raise TypeError('node description object must be a dict')
1768
+ typ = cbor.get('@t', None)
1769
+ if typ is None:
1770
+ raise ValueError('type (@t) field is missing from node serialization')
1771
+ if typ != 'Gate':
1772
+ raise ValueError('found node serialization for ' + typ + ', but expected Gate')
1773
+
1774
+ # Deserialize the name field.
1775
+ field = cbor.get('name', None)
1776
+ if not isinstance(field, dict):
1777
+ raise ValueError('missing or invalid serialization of field name')
1778
+ if hasattr(cqasm.v3x.primitives.Str, 'deserialize_cbor'):
1779
+ f_name = cqasm.v3x.primitives.Str.deserialize_cbor(field)
1780
+ else:
1781
+ f_name = cqasm.v3x.primitives.deserialize(cqasm.v3x.primitives.Str, field)
1782
+
1783
+ # Deserialize the gate field.
1784
+ field = cbor.get('gate', None)
1785
+ if not isinstance(field, dict):
1786
+ raise ValueError('missing or invalid serialization of field gate')
1787
+ if field.get('@T') != '?':
1788
+ raise ValueError('unexpected edge type for field gate')
1789
+ if field.get('@t', None) is None:
1790
+ f_gate = None
1791
+ else:
1792
+ f_gate = Gate._deserialize(field, seq_to_ob, links)
1793
+
1794
+ # Deserialize the parameters field.
1795
+ field = cbor.get('parameters', None)
1796
+ if not isinstance(field, dict):
1797
+ raise ValueError('missing or invalid serialization of field parameters')
1798
+ if field.get('@T') != '*':
1799
+ raise ValueError('unexpected edge type for field parameters')
1800
+ data = field.get('@d', None)
1801
+ if not isinstance(data, list):
1802
+ raise ValueError('missing serialization of Any/Many contents')
1803
+ f_parameters = cqasm.v3x.values.MultiValueBase()
1804
+ for element in data:
1805
+ if element.get('@T') != '1':
1806
+ raise ValueError('unexpected edge type for Any/Many element')
1807
+ f_parameters.append(cqasm.v3x.values.ValueBase._deserialize(element, seq_to_ob, links))
1808
+
1809
+ # Deserialize the annotations field.
1810
+ field = cbor.get('annotations', None)
1811
+ if not isinstance(field, dict):
1812
+ raise ValueError('missing or invalid serialization of field annotations')
1813
+ if field.get('@T') != '*':
1814
+ raise ValueError('unexpected edge type for field annotations')
1815
+ data = field.get('@d', None)
1816
+ if not isinstance(data, list):
1817
+ raise ValueError('missing serialization of Any/Many contents')
1818
+ f_annotations = MultiAnnotationData()
1819
+ for element in data:
1820
+ if element.get('@T') != '1':
1821
+ raise ValueError('unexpected edge type for Any/Many element')
1822
+ f_annotations.append(AnnotationData._deserialize(element, seq_to_ob, links))
1823
+
1824
+ # Construct the Gate node.
1825
+ node = Gate(f_name, f_gate, f_parameters, f_annotations)
1826
+
1827
+ # Deserialize annotations.
1828
+ for key, val in cbor.items():
1829
+ if not (key.startswith('{') and key.endswith('}')):
1830
+ continue
1831
+ key = key[1:-1]
1832
+ node[key] = cqasm.v3x.primitives.deserialize(key, val)
1833
+
1834
+ # Register node in sequence number lookup.
1835
+ seq = cbor.get('@i', None)
1836
+ if not isinstance(seq, int):
1837
+ raise ValueError('sequence number field (@i) is not an integer or missing from node serialization')
1838
+ if seq in seq_to_ob:
1839
+ raise ValueError('duplicate sequence number %d' % seq)
1840
+ seq_to_ob[seq] = node
1841
+
1842
+ return node
1843
+
1844
+ def _serialize(self, id_map):
1845
+ """Serializes this node to the Python primitive representation of its
1846
+ CBOR serialization. The tree that the node belongs to must be
1847
+ well-formed. id_map must match Python id() calls for all nodes to unique
1848
+ integers, to use for the sequence number representation of links."""
1849
+ cbor = {'@i': id_map[id(self)], '@t': 'Gate'}
1850
+
1851
+ # Serialize the name field.
1852
+ if hasattr(self._attr_name, 'serialize_cbor'):
1853
+ cbor['name'] = self._attr_name.serialize_cbor()
1854
+ else:
1855
+ cbor['name'] = cqasm.v3x.primitives.serialize(cqasm.v3x.primitives.Str, self._attr_name)
1856
+
1857
+ # Serialize the gate field.
1858
+ field = {'@T': '?'}
1859
+ if self._attr_gate is None:
1860
+ field['@t'] = None
1861
+ else:
1862
+ field.update(self._attr_gate._serialize(id_map))
1863
+ cbor['gate'] = field
1864
+
1865
+ # Serialize the parameters field.
1866
+ field = {'@T': '*'}
1867
+ lst = []
1868
+ for el in self._attr_parameters:
1869
+ el = el._serialize(id_map)
1870
+ el['@T'] = '1'
1871
+ lst.append(el)
1872
+ field['@d'] = lst
1873
+ cbor['parameters'] = field
1874
+
1875
+ # Serialize the annotations field.
1876
+ field = {'@T': '*'}
1877
+ lst = []
1878
+ for el in self._attr_annotations:
1879
+ el = el._serialize(id_map)
1880
+ el['@T'] = '1'
1881
+ lst.append(el)
1882
+ field['@d'] = lst
1883
+ cbor['annotations'] = field
1884
+
1885
+ # Serialize annotations.
1886
+ for key, val in self._annot.items():
1887
+ cbor['{%s}' % key] = _py_to_cbor(cqasm.v3x.primitives.serialize(key, val))
1888
+
1889
+ return cbor
1890
+
1891
+
1892
+ class MultiGate(_Multiple):
1893
+ """Wrapper for an edge with multiple Gate objects."""
1894
+
1895
+ _T = Gate
1896
+
1897
+
1898
+ _typemap['Gate'] = Gate
1899
+
1900
+ class GateInstruction(Instruction):
1901
+ """A gate, or a composition of gate modifiers and a gate"""
1902
+
1903
+ __slots__ = [
1904
+ '_attr_instruction_ref',
1905
+ '_attr_gate',
1906
+ '_attr_operands',
1907
+ ]
1908
+
1909
+ def __init__(
1910
+ self,
1911
+ instruction_ref=None,
1912
+ gate=None,
1913
+ operands=None,
1914
+ annotations=None,
1915
+ ):
1916
+ super().__init__(annotations=annotations)
1917
+ self.instruction_ref = instruction_ref
1918
+ self.gate = gate
1919
+ self.operands = operands
1920
+
1921
+ @property
1922
+ def instruction_ref(self):
1923
+ return self._attr_instruction_ref
1924
+
1925
+ @instruction_ref.setter
1926
+ def instruction_ref(self, val):
1927
+ if val is None:
1928
+ del self.instruction_ref
1929
+ return
1930
+ if not isinstance(val, cqasm.v3x.instruction.InstructionRef):
1931
+ # Try to "typecast" if this isn't an obvious mistake.
1932
+ if isinstance(val, Node):
1933
+ raise TypeError('instruction_ref must be of type cqasm.v3x.instruction.InstructionRef')
1934
+ val = cqasm.v3x.instruction.InstructionRef(val)
1935
+ self._attr_instruction_ref = val
1936
+
1937
+ @instruction_ref.deleter
1938
+ def instruction_ref(self):
1939
+ self._attr_instruction_ref = cqasm.v3x.instruction.InstructionRef()
1940
+
1941
+ @property
1942
+ def gate(self):
1943
+ return self._attr_gate
1944
+
1945
+ @gate.setter
1946
+ def gate(self, val):
1947
+ if val is None:
1948
+ del self.gate
1949
+ return
1950
+ if not isinstance(val, Gate):
1951
+ # Try to "typecast" if this isn't an obvious mistake.
1952
+ if isinstance(val, Node):
1953
+ raise TypeError('gate must be of type Gate')
1954
+ val = Gate(val)
1955
+ self._attr_gate = val
1956
+
1957
+ @gate.deleter
1958
+ def gate(self):
1959
+ self._attr_gate = None
1960
+
1961
+ @property
1962
+ def operands(self):
1963
+ return self._attr_operands
1964
+
1965
+ @operands.setter
1966
+ def operands(self, val):
1967
+ if val is None:
1968
+ del self.operands
1969
+ return
1970
+ if not isinstance(val, cqasm.v3x.values.MultiValueBase):
1971
+ # Try to "typecast" if this isn't an obvious mistake.
1972
+ if isinstance(val, Node):
1973
+ raise TypeError('operands must be of type cqasm.v3x.values.MultiValueBase')
1974
+ val = cqasm.v3x.values.MultiValueBase(val)
1975
+ self._attr_operands = val
1976
+
1977
+ @operands.deleter
1978
+ def operands(self):
1979
+ self._attr_operands = cqasm.v3x.values.MultiValueBase()
1980
+
1981
+ def __eq__(self, other):
1982
+ """Equality operator. Ignores annotations!"""
1983
+ if not isinstance(other, GateInstruction):
1984
+ return False
1985
+ if self.instruction_ref != other.instruction_ref:
1986
+ return False
1987
+ if self.gate != other.gate:
1988
+ return False
1989
+ if self.operands != other.operands:
1990
+ return False
1991
+ if self.annotations != other.annotations:
1992
+ return False
1993
+ return True
1994
+
1995
+ def dump(self, indent=0, annotations=None, links=1):
1996
+ """Returns a debug representation of this tree as a multiline string.
1997
+ indent is the number of double spaces prefixed before every line.
1998
+ annotations, if specified, must be a set-like object containing the key
1999
+ strings of the annotations that are to be printed. links specifies the
2000
+ maximum link recursion depth."""
2001
+ s = [' '*indent]
2002
+ s.append('GateInstruction(')
2003
+ if annotations is None:
2004
+ annotations = []
2005
+ for key in annotations:
2006
+ if key in self:
2007
+ s.append(' # {}: {}'.format(key, self[key]))
2008
+ s.append('\n')
2009
+ indent += 1
2010
+ s.append(' '*indent)
2011
+ s.append('instruction_ref: ')
2012
+ s.append(str(self.instruction_ref) + '\n')
2013
+ s.append(' '*indent)
2014
+ s.append('gate: ')
2015
+ if self.gate is None:
2016
+ s.append('!MISSING\n')
2017
+ else:
2018
+ s.append('<\n')
2019
+ s.append(self.gate.dump(indent + 1, annotations, links) + '\n')
2020
+ s.append(' '*indent + '>\n')
2021
+ s.append(' '*indent)
2022
+ s.append('operands: ')
2023
+ if not self.operands:
2024
+ s.append('-\n')
2025
+ else:
2026
+ s.append('[\n')
2027
+ for child in self.operands:
2028
+ s.append(child.dump(indent + 1, annotations, links) + '\n')
2029
+ s.append(' '*indent + ']\n')
2030
+ s.append(' '*indent)
2031
+ s.append('annotations: ')
2032
+ if not self.annotations:
2033
+ s.append('-\n')
2034
+ else:
2035
+ s.append('[\n')
2036
+ for child in self.annotations:
2037
+ s.append(child.dump(indent + 1, annotations, links) + '\n')
2038
+ s.append(' '*indent + ']\n')
2039
+ indent -= 1
2040
+ s.append(' '*indent)
2041
+ s.append(')')
2042
+ return ''.join(s)
2043
+
2044
+ __str__ = dump
2045
+ __repr__ = dump
2046
+
2047
+ def find_reachable(self, id_map=None):
2048
+ """Returns a dictionary mapping Python id() values to stable sequence
2049
+ numbers for all nodes in the tree rooted at this node. If id_map is
2050
+ specified, found nodes are appended to it."""
2051
+ if id_map is None:
2052
+ id_map = {}
2053
+ if id(self) in id_map:
2054
+ raise NotWellFormed('node {!r} with id {} occurs more than once'.format(self, id(self)))
2055
+ id_map[id(self)] = len(id_map)
2056
+ if self._attr_gate is not None:
2057
+ self._attr_gate.find_reachable(id_map)
2058
+ for el in self._attr_operands:
2059
+ el.find_reachable(id_map)
2060
+ for el in self._attr_annotations:
2061
+ el.find_reachable(id_map)
2062
+ return id_map
2063
+
2064
+ def check_complete(self, id_map=None):
2065
+ """Raises NotWellFormed if the tree rooted at this node is not
2066
+ well-formed. If id_map is specified, this tree is only a subtree in the
2067
+ context of a larger tree, and id_map must be a dict mapping from Python
2068
+ id() codes to tree indices for all reachable nodes."""
2069
+ if id_map is None:
2070
+ id_map = self.find_reachable()
2071
+ if self._attr_gate is None:
2072
+ raise NotWellFormed('gate is required but not set')
2073
+ if self._attr_gate is not None:
2074
+ self._attr_gate.check_complete(id_map)
2075
+ for child in self._attr_operands:
2076
+ child.check_complete(id_map)
2077
+ for child in self._attr_annotations:
2078
+ child.check_complete(id_map)
2079
+
2080
+ def copy(self):
2081
+ """Returns a shallow copy of this node."""
2082
+ return GateInstruction(
2083
+ instruction_ref=self._attr_instruction_ref,
2084
+ gate=self._attr_gate,
2085
+ operands=self._attr_operands.copy(),
2086
+ annotations=self._attr_annotations.copy()
2087
+ )
2088
+
2089
+ def clone(self):
2090
+ """Returns a deep copy of this node. This mimics the C++ interface,
2091
+ deficiencies with links included; that is, links always point to the
2092
+ original tree. If you're not cloning a subtree in a context where this
2093
+ is the desired behavior, you may want to use the copy.deepcopy() from
2094
+ the stdlib instead, which should copy links correctly."""
2095
+ return GateInstruction(
2096
+ instruction_ref=_cloned(self._attr_instruction_ref),
2097
+ gate=_cloned(self._attr_gate),
2098
+ operands=_cloned(self._attr_operands),
2099
+ annotations=_cloned(self._attr_annotations)
2100
+ )
2101
+
2102
+ @staticmethod
2103
+ def _deserialize(cbor, seq_to_ob, links):
2104
+ """Attempts to deserialize the given cbor object (in Python primitive
2105
+ representation) into a node of this type. All (sub)nodes are added to
2106
+ the seq_to_ob dict, indexed by their cbor sequence number. All links are
2107
+ registered in the links list by means of a two-tuple of the setter
2108
+ function for the link field and the sequence number of the target node.
2109
+ """
2110
+ if not isinstance(cbor, dict):
2111
+ raise TypeError('node description object must be a dict')
2112
+ typ = cbor.get('@t', None)
2113
+ if typ is None:
2114
+ raise ValueError('type (@t) field is missing from node serialization')
2115
+ if typ != 'GateInstruction':
2116
+ raise ValueError('found node serialization for ' + typ + ', but expected GateInstruction')
2117
+
2118
+ # Deserialize the instruction_ref field.
2119
+ field = cbor.get('instruction_ref', None)
2120
+ if not isinstance(field, dict):
2121
+ raise ValueError('missing or invalid serialization of field instruction_ref')
2122
+ if hasattr(cqasm.v3x.instruction.InstructionRef, 'deserialize_cbor'):
2123
+ f_instruction_ref = cqasm.v3x.instruction.InstructionRef.deserialize_cbor(field)
2124
+ else:
2125
+ f_instruction_ref = cqasm.v3x.primitives.deserialize(cqasm.v3x.instruction.InstructionRef, field)
2126
+
2127
+ # Deserialize the gate field.
2128
+ field = cbor.get('gate', None)
2129
+ if not isinstance(field, dict):
2130
+ raise ValueError('missing or invalid serialization of field gate')
2131
+ if field.get('@T') != '1':
2132
+ raise ValueError('unexpected edge type for field gate')
2133
+ if field.get('@t', None) is None:
2134
+ f_gate = None
2135
+ else:
2136
+ f_gate = Gate._deserialize(field, seq_to_ob, links)
2137
+
2138
+ # Deserialize the operands field.
2139
+ field = cbor.get('operands', None)
2140
+ if not isinstance(field, dict):
2141
+ raise ValueError('missing or invalid serialization of field operands')
2142
+ if field.get('@T') != '*':
2143
+ raise ValueError('unexpected edge type for field operands')
2144
+ data = field.get('@d', None)
2145
+ if not isinstance(data, list):
2146
+ raise ValueError('missing serialization of Any/Many contents')
2147
+ f_operands = cqasm.v3x.values.MultiValueBase()
2148
+ for element in data:
2149
+ if element.get('@T') != '1':
2150
+ raise ValueError('unexpected edge type for Any/Many element')
2151
+ f_operands.append(cqasm.v3x.values.ValueBase._deserialize(element, seq_to_ob, links))
2152
+
2153
+ # Deserialize the annotations field.
2154
+ field = cbor.get('annotations', None)
2155
+ if not isinstance(field, dict):
2156
+ raise ValueError('missing or invalid serialization of field annotations')
2157
+ if field.get('@T') != '*':
2158
+ raise ValueError('unexpected edge type for field annotations')
2159
+ data = field.get('@d', None)
2160
+ if not isinstance(data, list):
2161
+ raise ValueError('missing serialization of Any/Many contents')
2162
+ f_annotations = MultiAnnotationData()
2163
+ for element in data:
2164
+ if element.get('@T') != '1':
2165
+ raise ValueError('unexpected edge type for Any/Many element')
2166
+ f_annotations.append(AnnotationData._deserialize(element, seq_to_ob, links))
2167
+
2168
+ # Construct the GateInstruction node.
2169
+ node = GateInstruction(f_instruction_ref, f_gate, f_operands, f_annotations)
2170
+
2171
+ # Deserialize annotations.
2172
+ for key, val in cbor.items():
2173
+ if not (key.startswith('{') and key.endswith('}')):
2174
+ continue
2175
+ key = key[1:-1]
2176
+ node[key] = cqasm.v3x.primitives.deserialize(key, val)
2177
+
2178
+ # Register node in sequence number lookup.
2179
+ seq = cbor.get('@i', None)
2180
+ if not isinstance(seq, int):
2181
+ raise ValueError('sequence number field (@i) is not an integer or missing from node serialization')
2182
+ if seq in seq_to_ob:
2183
+ raise ValueError('duplicate sequence number %d' % seq)
2184
+ seq_to_ob[seq] = node
2185
+
2186
+ return node
2187
+
2188
+ def _serialize(self, id_map):
2189
+ """Serializes this node to the Python primitive representation of its
2190
+ CBOR serialization. The tree that the node belongs to must be
2191
+ well-formed. id_map must match Python id() calls for all nodes to unique
2192
+ integers, to use for the sequence number representation of links."""
2193
+ cbor = {'@i': id_map[id(self)], '@t': 'GateInstruction'}
2194
+
2195
+ # Serialize the instruction_ref field.
2196
+ if hasattr(self._attr_instruction_ref, 'serialize_cbor'):
2197
+ cbor['instruction_ref'] = self._attr_instruction_ref.serialize_cbor()
2198
+ else:
2199
+ cbor['instruction_ref'] = cqasm.v3x.primitives.serialize(cqasm.v3x.instruction.InstructionRef, self._attr_instruction_ref)
2200
+
2201
+ # Serialize the gate field.
2202
+ field = {'@T': '1'}
2203
+ if self._attr_gate is None:
2204
+ field['@t'] = None
2205
+ else:
2206
+ field.update(self._attr_gate._serialize(id_map))
2207
+ cbor['gate'] = field
2208
+
2209
+ # Serialize the operands field.
2210
+ field = {'@T': '*'}
2211
+ lst = []
2212
+ for el in self._attr_operands:
2213
+ el = el._serialize(id_map)
2214
+ el['@T'] = '1'
2215
+ lst.append(el)
2216
+ field['@d'] = lst
2217
+ cbor['operands'] = field
2218
+
2219
+ # Serialize the annotations field.
2220
+ field = {'@T': '*'}
2221
+ lst = []
2222
+ for el in self._attr_annotations:
2223
+ el = el._serialize(id_map)
2224
+ el['@T'] = '1'
2225
+ lst.append(el)
2226
+ field['@d'] = lst
2227
+ cbor['annotations'] = field
2228
+
2229
+ # Serialize annotations.
2230
+ for key, val in self._annot.items():
2231
+ cbor['{%s}' % key] = _py_to_cbor(cqasm.v3x.primitives.serialize(key, val))
2232
+
2233
+ return cbor
2234
+
2235
+
2236
+ class MultiGateInstruction(_Multiple):
2237
+ """Wrapper for an edge with multiple GateInstruction objects."""
2238
+
2239
+ _T = GateInstruction
2240
+
2241
+
2242
+ _typemap['GateInstruction'] = GateInstruction
2243
+
2244
+ class NonGateInstruction(Instruction):
2245
+ """A non-gate instruction: init, measure, reset, barrier, wait..."""
2246
+
2247
+ __slots__ = [
2248
+ '_attr_instruction_ref',
2249
+ '_attr_name',
2250
+ '_attr_operands',
2251
+ '_attr_parameters',
2252
+ ]
2253
+
2254
+ def __init__(
2255
+ self,
2256
+ instruction_ref=None,
2257
+ name=None,
2258
+ operands=None,
2259
+ parameters=None,
2260
+ annotations=None,
2261
+ ):
2262
+ super().__init__(annotations=annotations)
2263
+ self.instruction_ref = instruction_ref
2264
+ self.name = name
2265
+ self.operands = operands
2266
+ self.parameters = parameters
2267
+
2268
+ @property
2269
+ def instruction_ref(self):
2270
+ return self._attr_instruction_ref
2271
+
2272
+ @instruction_ref.setter
2273
+ def instruction_ref(self, val):
2274
+ if val is None:
2275
+ del self.instruction_ref
2276
+ return
2277
+ if not isinstance(val, cqasm.v3x.instruction.InstructionRef):
2278
+ # Try to "typecast" if this isn't an obvious mistake.
2279
+ if isinstance(val, Node):
2280
+ raise TypeError('instruction_ref must be of type cqasm.v3x.instruction.InstructionRef')
2281
+ val = cqasm.v3x.instruction.InstructionRef(val)
2282
+ self._attr_instruction_ref = val
2283
+
2284
+ @instruction_ref.deleter
2285
+ def instruction_ref(self):
2286
+ self._attr_instruction_ref = cqasm.v3x.instruction.InstructionRef()
2287
+
2288
+ @property
2289
+ def name(self):
2290
+ return self._attr_name
2291
+
2292
+ @name.setter
2293
+ def name(self, val):
2294
+ if val is None:
2295
+ del self.name
2296
+ return
2297
+ if not isinstance(val, cqasm.v3x.primitives.Str):
2298
+ # Try to "typecast" if this isn't an obvious mistake.
2299
+ if isinstance(val, Node):
2300
+ raise TypeError('name must be of type cqasm.v3x.primitives.Str')
2301
+ val = cqasm.v3x.primitives.Str(val)
2302
+ self._attr_name = val
2303
+
2304
+ @name.deleter
2305
+ def name(self):
2306
+ self._attr_name = cqasm.v3x.primitives.Str()
2307
+
2308
+ @property
2309
+ def operands(self):
2310
+ return self._attr_operands
2311
+
2312
+ @operands.setter
2313
+ def operands(self, val):
2314
+ if val is None:
2315
+ del self.operands
2316
+ return
2317
+ if not isinstance(val, cqasm.v3x.values.MultiValueBase):
2318
+ # Try to "typecast" if this isn't an obvious mistake.
2319
+ if isinstance(val, Node):
2320
+ raise TypeError('operands must be of type cqasm.v3x.values.MultiValueBase')
2321
+ val = cqasm.v3x.values.MultiValueBase(val)
2322
+ self._attr_operands = val
2323
+
2324
+ @operands.deleter
2325
+ def operands(self):
2326
+ self._attr_operands = cqasm.v3x.values.MultiValueBase()
2327
+
2328
+ @property
2329
+ def parameters(self):
2330
+ return self._attr_parameters
2331
+
2332
+ @parameters.setter
2333
+ def parameters(self, val):
2334
+ if val is None:
2335
+ del self.parameters
2336
+ return
2337
+ if not isinstance(val, cqasm.v3x.values.MultiValueBase):
2338
+ # Try to "typecast" if this isn't an obvious mistake.
2339
+ if isinstance(val, Node):
2340
+ raise TypeError('parameters must be of type cqasm.v3x.values.MultiValueBase')
2341
+ val = cqasm.v3x.values.MultiValueBase(val)
2342
+ self._attr_parameters = val
2343
+
2344
+ @parameters.deleter
2345
+ def parameters(self):
2346
+ self._attr_parameters = cqasm.v3x.values.MultiValueBase()
2347
+
2348
+ def __eq__(self, other):
2349
+ """Equality operator. Ignores annotations!"""
2350
+ if not isinstance(other, NonGateInstruction):
2351
+ return False
2352
+ if self.instruction_ref != other.instruction_ref:
2353
+ return False
2354
+ if self.name != other.name:
2355
+ return False
2356
+ if self.operands != other.operands:
2357
+ return False
2358
+ if self.parameters != other.parameters:
2359
+ return False
2360
+ if self.annotations != other.annotations:
2361
+ return False
2362
+ return True
2363
+
2364
+ def dump(self, indent=0, annotations=None, links=1):
2365
+ """Returns a debug representation of this tree as a multiline string.
2366
+ indent is the number of double spaces prefixed before every line.
2367
+ annotations, if specified, must be a set-like object containing the key
2368
+ strings of the annotations that are to be printed. links specifies the
2369
+ maximum link recursion depth."""
2370
+ s = [' '*indent]
2371
+ s.append('NonGateInstruction(')
2372
+ if annotations is None:
2373
+ annotations = []
2374
+ for key in annotations:
2375
+ if key in self:
2376
+ s.append(' # {}: {}'.format(key, self[key]))
2377
+ s.append('\n')
2378
+ indent += 1
2379
+ s.append(' '*indent)
2380
+ s.append('instruction_ref: ')
2381
+ s.append(str(self.instruction_ref) + '\n')
2382
+ s.append(' '*indent)
2383
+ s.append('name: ')
2384
+ s.append(str(self.name) + '\n')
2385
+ s.append(' '*indent)
2386
+ s.append('operands: ')
2387
+ if not self.operands:
2388
+ s.append('-\n')
2389
+ else:
2390
+ s.append('[\n')
2391
+ for child in self.operands:
2392
+ s.append(child.dump(indent + 1, annotations, links) + '\n')
2393
+ s.append(' '*indent + ']\n')
2394
+ s.append(' '*indent)
2395
+ s.append('parameters: ')
2396
+ if not self.parameters:
2397
+ s.append('-\n')
2398
+ else:
2399
+ s.append('[\n')
2400
+ for child in self.parameters:
2401
+ s.append(child.dump(indent + 1, annotations, links) + '\n')
2402
+ s.append(' '*indent + ']\n')
2403
+ s.append(' '*indent)
2404
+ s.append('annotations: ')
2405
+ if not self.annotations:
2406
+ s.append('-\n')
2407
+ else:
2408
+ s.append('[\n')
2409
+ for child in self.annotations:
2410
+ s.append(child.dump(indent + 1, annotations, links) + '\n')
2411
+ s.append(' '*indent + ']\n')
2412
+ indent -= 1
2413
+ s.append(' '*indent)
2414
+ s.append(')')
2415
+ return ''.join(s)
2416
+
2417
+ __str__ = dump
2418
+ __repr__ = dump
2419
+
2420
+ def find_reachable(self, id_map=None):
2421
+ """Returns a dictionary mapping Python id() values to stable sequence
2422
+ numbers for all nodes in the tree rooted at this node. If id_map is
2423
+ specified, found nodes are appended to it."""
2424
+ if id_map is None:
2425
+ id_map = {}
2426
+ if id(self) in id_map:
2427
+ raise NotWellFormed('node {!r} with id {} occurs more than once'.format(self, id(self)))
2428
+ id_map[id(self)] = len(id_map)
2429
+ for el in self._attr_operands:
2430
+ el.find_reachable(id_map)
2431
+ for el in self._attr_parameters:
2432
+ el.find_reachable(id_map)
2433
+ for el in self._attr_annotations:
2434
+ el.find_reachable(id_map)
2435
+ return id_map
2436
+
2437
+ def check_complete(self, id_map=None):
2438
+ """Raises NotWellFormed if the tree rooted at this node is not
2439
+ well-formed. If id_map is specified, this tree is only a subtree in the
2440
+ context of a larger tree, and id_map must be a dict mapping from Python
2441
+ id() codes to tree indices for all reachable nodes."""
2442
+ if id_map is None:
2443
+ id_map = self.find_reachable()
2444
+ for child in self._attr_operands:
2445
+ child.check_complete(id_map)
2446
+ for child in self._attr_parameters:
2447
+ child.check_complete(id_map)
2448
+ for child in self._attr_annotations:
2449
+ child.check_complete(id_map)
2450
+
2451
+ def copy(self):
2452
+ """Returns a shallow copy of this node."""
2453
+ return NonGateInstruction(
2454
+ instruction_ref=self._attr_instruction_ref,
2455
+ name=self._attr_name,
2456
+ operands=self._attr_operands.copy(),
2457
+ parameters=self._attr_parameters.copy(),
2458
+ annotations=self._attr_annotations.copy()
2459
+ )
2460
+
2461
+ def clone(self):
2462
+ """Returns a deep copy of this node. This mimics the C++ interface,
2463
+ deficiencies with links included; that is, links always point to the
2464
+ original tree. If you're not cloning a subtree in a context where this
2465
+ is the desired behavior, you may want to use the copy.deepcopy() from
2466
+ the stdlib instead, which should copy links correctly."""
2467
+ return NonGateInstruction(
2468
+ instruction_ref=_cloned(self._attr_instruction_ref),
2469
+ name=_cloned(self._attr_name),
2470
+ operands=_cloned(self._attr_operands),
2471
+ parameters=_cloned(self._attr_parameters),
2472
+ annotations=_cloned(self._attr_annotations)
2473
+ )
2474
+
2475
+ @staticmethod
2476
+ def _deserialize(cbor, seq_to_ob, links):
2477
+ """Attempts to deserialize the given cbor object (in Python primitive
2478
+ representation) into a node of this type. All (sub)nodes are added to
2479
+ the seq_to_ob dict, indexed by their cbor sequence number. All links are
2480
+ registered in the links list by means of a two-tuple of the setter
2481
+ function for the link field and the sequence number of the target node.
2482
+ """
2483
+ if not isinstance(cbor, dict):
2484
+ raise TypeError('node description object must be a dict')
2485
+ typ = cbor.get('@t', None)
2486
+ if typ is None:
2487
+ raise ValueError('type (@t) field is missing from node serialization')
2488
+ if typ != 'NonGateInstruction':
2489
+ raise ValueError('found node serialization for ' + typ + ', but expected NonGateInstruction')
2490
+
2491
+ # Deserialize the instruction_ref field.
2492
+ field = cbor.get('instruction_ref', None)
2493
+ if not isinstance(field, dict):
2494
+ raise ValueError('missing or invalid serialization of field instruction_ref')
2495
+ if hasattr(cqasm.v3x.instruction.InstructionRef, 'deserialize_cbor'):
2496
+ f_instruction_ref = cqasm.v3x.instruction.InstructionRef.deserialize_cbor(field)
2497
+ else:
2498
+ f_instruction_ref = cqasm.v3x.primitives.deserialize(cqasm.v3x.instruction.InstructionRef, field)
2499
+
2500
+ # Deserialize the name field.
2501
+ field = cbor.get('name', None)
2502
+ if not isinstance(field, dict):
2503
+ raise ValueError('missing or invalid serialization of field name')
2504
+ if hasattr(cqasm.v3x.primitives.Str, 'deserialize_cbor'):
2505
+ f_name = cqasm.v3x.primitives.Str.deserialize_cbor(field)
2506
+ else:
2507
+ f_name = cqasm.v3x.primitives.deserialize(cqasm.v3x.primitives.Str, field)
2508
+
2509
+ # Deserialize the operands field.
2510
+ field = cbor.get('operands', None)
2511
+ if not isinstance(field, dict):
2512
+ raise ValueError('missing or invalid serialization of field operands')
2513
+ if field.get('@T') != '*':
2514
+ raise ValueError('unexpected edge type for field operands')
2515
+ data = field.get('@d', None)
2516
+ if not isinstance(data, list):
2517
+ raise ValueError('missing serialization of Any/Many contents')
2518
+ f_operands = cqasm.v3x.values.MultiValueBase()
2519
+ for element in data:
2520
+ if element.get('@T') != '1':
2521
+ raise ValueError('unexpected edge type for Any/Many element')
2522
+ f_operands.append(cqasm.v3x.values.ValueBase._deserialize(element, seq_to_ob, links))
2523
+
2524
+ # Deserialize the parameters field.
2525
+ field = cbor.get('parameters', None)
2526
+ if not isinstance(field, dict):
2527
+ raise ValueError('missing or invalid serialization of field parameters')
2528
+ if field.get('@T') != '*':
2529
+ raise ValueError('unexpected edge type for field parameters')
2530
+ data = field.get('@d', None)
2531
+ if not isinstance(data, list):
2532
+ raise ValueError('missing serialization of Any/Many contents')
2533
+ f_parameters = cqasm.v3x.values.MultiValueBase()
2534
+ for element in data:
2535
+ if element.get('@T') != '1':
2536
+ raise ValueError('unexpected edge type for Any/Many element')
2537
+ f_parameters.append(cqasm.v3x.values.ValueBase._deserialize(element, seq_to_ob, links))
2538
+
2539
+ # Deserialize the annotations field.
2540
+ field = cbor.get('annotations', None)
2541
+ if not isinstance(field, dict):
2542
+ raise ValueError('missing or invalid serialization of field annotations')
2543
+ if field.get('@T') != '*':
2544
+ raise ValueError('unexpected edge type for field annotations')
2545
+ data = field.get('@d', None)
2546
+ if not isinstance(data, list):
2547
+ raise ValueError('missing serialization of Any/Many contents')
2548
+ f_annotations = MultiAnnotationData()
2549
+ for element in data:
2550
+ if element.get('@T') != '1':
2551
+ raise ValueError('unexpected edge type for Any/Many element')
2552
+ f_annotations.append(AnnotationData._deserialize(element, seq_to_ob, links))
2553
+
2554
+ # Construct the NonGateInstruction node.
2555
+ node = NonGateInstruction(f_instruction_ref, f_name, f_operands, f_parameters, f_annotations)
2556
+
2557
+ # Deserialize annotations.
2558
+ for key, val in cbor.items():
2559
+ if not (key.startswith('{') and key.endswith('}')):
2560
+ continue
2561
+ key = key[1:-1]
2562
+ node[key] = cqasm.v3x.primitives.deserialize(key, val)
2563
+
2564
+ # Register node in sequence number lookup.
2565
+ seq = cbor.get('@i', None)
2566
+ if not isinstance(seq, int):
2567
+ raise ValueError('sequence number field (@i) is not an integer or missing from node serialization')
2568
+ if seq in seq_to_ob:
2569
+ raise ValueError('duplicate sequence number %d' % seq)
2570
+ seq_to_ob[seq] = node
2571
+
2572
+ return node
2573
+
2574
+ def _serialize(self, id_map):
2575
+ """Serializes this node to the Python primitive representation of its
2576
+ CBOR serialization. The tree that the node belongs to must be
2577
+ well-formed. id_map must match Python id() calls for all nodes to unique
2578
+ integers, to use for the sequence number representation of links."""
2579
+ cbor = {'@i': id_map[id(self)], '@t': 'NonGateInstruction'}
2580
+
2581
+ # Serialize the instruction_ref field.
2582
+ if hasattr(self._attr_instruction_ref, 'serialize_cbor'):
2583
+ cbor['instruction_ref'] = self._attr_instruction_ref.serialize_cbor()
2584
+ else:
2585
+ cbor['instruction_ref'] = cqasm.v3x.primitives.serialize(cqasm.v3x.instruction.InstructionRef, self._attr_instruction_ref)
2586
+
2587
+ # Serialize the name field.
2588
+ if hasattr(self._attr_name, 'serialize_cbor'):
2589
+ cbor['name'] = self._attr_name.serialize_cbor()
2590
+ else:
2591
+ cbor['name'] = cqasm.v3x.primitives.serialize(cqasm.v3x.primitives.Str, self._attr_name)
2592
+
2593
+ # Serialize the operands field.
2594
+ field = {'@T': '*'}
2595
+ lst = []
2596
+ for el in self._attr_operands:
2597
+ el = el._serialize(id_map)
2598
+ el['@T'] = '1'
2599
+ lst.append(el)
2600
+ field['@d'] = lst
2601
+ cbor['operands'] = field
2602
+
2603
+ # Serialize the parameters field.
2604
+ field = {'@T': '*'}
2605
+ lst = []
2606
+ for el in self._attr_parameters:
2607
+ el = el._serialize(id_map)
2608
+ el['@T'] = '1'
2609
+ lst.append(el)
2610
+ field['@d'] = lst
2611
+ cbor['parameters'] = field
2612
+
2613
+ # Serialize the annotations field.
2614
+ field = {'@T': '*'}
2615
+ lst = []
2616
+ for el in self._attr_annotations:
2617
+ el = el._serialize(id_map)
2618
+ el['@T'] = '1'
2619
+ lst.append(el)
2620
+ field['@d'] = lst
2621
+ cbor['annotations'] = field
2622
+
2623
+ # Serialize annotations.
2624
+ for key, val in self._annot.items():
2625
+ cbor['{%s}' % key] = _py_to_cbor(cqasm.v3x.primitives.serialize(key, val))
2626
+
2627
+ return cbor
2628
+
2629
+
2630
+ class MultiNonGateInstruction(_Multiple):
2631
+ """Wrapper for an edge with multiple NonGateInstruction objects."""
2632
+
2633
+ _T = NonGateInstruction
2634
+
2635
+
2636
+ _typemap['NonGateInstruction'] = NonGateInstruction
2637
+
2638
+ class Program(Node):
2639
+ __slots__ = [
2640
+ '_attr_api_version',
2641
+ '_attr_version',
2642
+ '_attr_block',
2643
+ '_attr_variables',
2644
+ ]
2645
+
2646
+ def __init__(
2647
+ self,
2648
+ api_version=None,
2649
+ version=None,
2650
+ block=None,
2651
+ variables=None,
2652
+ ):
2653
+ super().__init__()
2654
+ self.api_version = api_version
2655
+ self.version = version
2656
+ self.block = block
2657
+ self.variables = variables
2658
+
2659
+ @property
2660
+ def api_version(self):
2661
+ """API version. This may be greater than or equal to the file version.
2662
+ This controls which fields of the tree are used, where such usage
2663
+ depends on the version."""
2664
+ return self._attr_api_version
2665
+
2666
+ @api_version.setter
2667
+ def api_version(self, val):
2668
+ if val is None:
2669
+ del self.api_version
2670
+ return
2671
+ if not isinstance(val, cqasm.v3x.primitives.Version):
2672
+ # Try to "typecast" if this isn't an obvious mistake.
2673
+ if isinstance(val, Node):
2674
+ raise TypeError('api_version must be of type cqasm.v3x.primitives.Version')
2675
+ val = cqasm.v3x.primitives.Version(val)
2676
+ self._attr_api_version = val
2677
+
2678
+ @api_version.deleter
2679
+ def api_version(self):
2680
+ self._attr_api_version = cqasm.v3x.primitives.Version()
2681
+
2682
+ @property
2683
+ def version(self):
2684
+ """File version."""
2685
+ return self._attr_version
2686
+
2687
+ @version.setter
2688
+ def version(self, val):
2689
+ if val is None:
2690
+ del self.version
2691
+ return
2692
+ if not isinstance(val, Version):
2693
+ # Try to "typecast" if this isn't an obvious mistake.
2694
+ if isinstance(val, Node):
2695
+ raise TypeError('version must be of type Version')
2696
+ val = Version(val)
2697
+ self._attr_version = val
2698
+
2699
+ @version.deleter
2700
+ def version(self):
2701
+ self._attr_version = None
2702
+
2703
+ @property
2704
+ def block(self):
2705
+ """Global scope block."""
2706
+ return self._attr_block
2707
+
2708
+ @block.setter
2709
+ def block(self, val):
2710
+ if val is None:
2711
+ del self.block
2712
+ return
2713
+ if not isinstance(val, Block):
2714
+ # Try to "typecast" if this isn't an obvious mistake.
2715
+ if isinstance(val, Node):
2716
+ raise TypeError('block must be of type Block')
2717
+ val = Block(val)
2718
+ self._attr_block = val
2719
+
2720
+ @block.deleter
2721
+ def block(self):
2722
+ self._attr_block = None
2723
+
2724
+ @property
2725
+ def variables(self):
2726
+ """The list of variables."""
2727
+ return self._attr_variables
2728
+
2729
+ @variables.setter
2730
+ def variables(self, val):
2731
+ if val is None:
2732
+ del self.variables
2733
+ return
2734
+ if not isinstance(val, MultiVariable):
2735
+ # Try to "typecast" if this isn't an obvious mistake.
2736
+ if isinstance(val, Node):
2737
+ raise TypeError('variables must be of type MultiVariable')
2738
+ val = MultiVariable(val)
2739
+ self._attr_variables = val
2740
+
2741
+ @variables.deleter
2742
+ def variables(self):
2743
+ self._attr_variables = MultiVariable()
2744
+
2745
+ def __eq__(self, other):
2746
+ """Equality operator. Ignores annotations!"""
2747
+ if not isinstance(other, Program):
2748
+ return False
2749
+ if self.api_version != other.api_version:
2750
+ return False
2751
+ if self.version != other.version:
2752
+ return False
2753
+ if self.block != other.block:
2754
+ return False
2755
+ if self.variables != other.variables:
2756
+ return False
2757
+ return True
2758
+
2759
+ def dump(self, indent=0, annotations=None, links=1):
2760
+ """Returns a debug representation of this tree as a multiline string.
2761
+ indent is the number of double spaces prefixed before every line.
2762
+ annotations, if specified, must be a set-like object containing the key
2763
+ strings of the annotations that are to be printed. links specifies the
2764
+ maximum link recursion depth."""
2765
+ s = [' '*indent]
2766
+ s.append('Program(')
2767
+ if annotations is None:
2768
+ annotations = []
2769
+ for key in annotations:
2770
+ if key in self:
2771
+ s.append(' # {}: {}'.format(key, self[key]))
2772
+ s.append('\n')
2773
+ indent += 1
2774
+ s.append(' '*indent)
2775
+ s.append('api_version: ')
2776
+ s.append(str(self.api_version) + '\n')
2777
+ s.append(' '*indent)
2778
+ s.append('version: ')
2779
+ if self.version is None:
2780
+ s.append('!MISSING\n')
2781
+ else:
2782
+ s.append('<\n')
2783
+ s.append(self.version.dump(indent + 1, annotations, links) + '\n')
2784
+ s.append(' '*indent + '>\n')
2785
+ s.append(' '*indent)
2786
+ s.append('block: ')
2787
+ if self.block is None:
2788
+ s.append('!MISSING\n')
2789
+ else:
2790
+ s.append('<\n')
2791
+ s.append(self.block.dump(indent + 1, annotations, links) + '\n')
2792
+ s.append(' '*indent + '>\n')
2793
+ s.append(' '*indent)
2794
+ s.append('variables: ')
2795
+ if not self.variables:
2796
+ s.append('-\n')
2797
+ else:
2798
+ s.append('[\n')
2799
+ for child in self.variables:
2800
+ s.append(child.dump(indent + 1, annotations, links) + '\n')
2801
+ s.append(' '*indent + ']\n')
2802
+ indent -= 1
2803
+ s.append(' '*indent)
2804
+ s.append(')')
2805
+ return ''.join(s)
2806
+
2807
+ __str__ = dump
2808
+ __repr__ = dump
2809
+
2810
+ def find_reachable(self, id_map=None):
2811
+ """Returns a dictionary mapping Python id() values to stable sequence
2812
+ numbers for all nodes in the tree rooted at this node. If id_map is
2813
+ specified, found nodes are appended to it."""
2814
+ if id_map is None:
2815
+ id_map = {}
2816
+ if id(self) in id_map:
2817
+ raise NotWellFormed('node {!r} with id {} occurs more than once'.format(self, id(self)))
2818
+ id_map[id(self)] = len(id_map)
2819
+ if self._attr_version is not None:
2820
+ self._attr_version.find_reachable(id_map)
2821
+ if self._attr_block is not None:
2822
+ self._attr_block.find_reachable(id_map)
2823
+ for el in self._attr_variables:
2824
+ el.find_reachable(id_map)
2825
+ return id_map
2826
+
2827
+ def check_complete(self, id_map=None):
2828
+ """Raises NotWellFormed if the tree rooted at this node is not
2829
+ well-formed. If id_map is specified, this tree is only a subtree in the
2830
+ context of a larger tree, and id_map must be a dict mapping from Python
2831
+ id() codes to tree indices for all reachable nodes."""
2832
+ if id_map is None:
2833
+ id_map = self.find_reachable()
2834
+ if self._attr_version is None:
2835
+ raise NotWellFormed('version is required but not set')
2836
+ if self._attr_version is not None:
2837
+ self._attr_version.check_complete(id_map)
2838
+ if self._attr_block is None:
2839
+ raise NotWellFormed('block is required but not set')
2840
+ if self._attr_block is not None:
2841
+ self._attr_block.check_complete(id_map)
2842
+ for child in self._attr_variables:
2843
+ child.check_complete(id_map)
2844
+
2845
+ def copy(self):
2846
+ """Returns a shallow copy of this node."""
2847
+ return Program(
2848
+ api_version=self._attr_api_version,
2849
+ version=self._attr_version,
2850
+ block=self._attr_block,
2851
+ variables=self._attr_variables.copy()
2852
+ )
2853
+
2854
+ def clone(self):
2855
+ """Returns a deep copy of this node. This mimics the C++ interface,
2856
+ deficiencies with links included; that is, links always point to the
2857
+ original tree. If you're not cloning a subtree in a context where this
2858
+ is the desired behavior, you may want to use the copy.deepcopy() from
2859
+ the stdlib instead, which should copy links correctly."""
2860
+ return Program(
2861
+ api_version=_cloned(self._attr_api_version),
2862
+ version=_cloned(self._attr_version),
2863
+ block=_cloned(self._attr_block),
2864
+ variables=_cloned(self._attr_variables)
2865
+ )
2866
+
2867
+ @staticmethod
2868
+ def _deserialize(cbor, seq_to_ob, links):
2869
+ """Attempts to deserialize the given cbor object (in Python primitive
2870
+ representation) into a node of this type. All (sub)nodes are added to
2871
+ the seq_to_ob dict, indexed by their cbor sequence number. All links are
2872
+ registered in the links list by means of a two-tuple of the setter
2873
+ function for the link field and the sequence number of the target node.
2874
+ """
2875
+ if not isinstance(cbor, dict):
2876
+ raise TypeError('node description object must be a dict')
2877
+ typ = cbor.get('@t', None)
2878
+ if typ is None:
2879
+ raise ValueError('type (@t) field is missing from node serialization')
2880
+ if typ != 'Program':
2881
+ raise ValueError('found node serialization for ' + typ + ', but expected Program')
2882
+
2883
+ # Deserialize the api_version field.
2884
+ field = cbor.get('api_version', None)
2885
+ if not isinstance(field, dict):
2886
+ raise ValueError('missing or invalid serialization of field api_version')
2887
+ if hasattr(cqasm.v3x.primitives.Version, 'deserialize_cbor'):
2888
+ f_api_version = cqasm.v3x.primitives.Version.deserialize_cbor(field)
2889
+ else:
2890
+ f_api_version = cqasm.v3x.primitives.deserialize(cqasm.v3x.primitives.Version, field)
2891
+
2892
+ # Deserialize the version field.
2893
+ field = cbor.get('version', None)
2894
+ if not isinstance(field, dict):
2895
+ raise ValueError('missing or invalid serialization of field version')
2896
+ if field.get('@T') != '1':
2897
+ raise ValueError('unexpected edge type for field version')
2898
+ if field.get('@t', None) is None:
2899
+ f_version = None
2900
+ else:
2901
+ f_version = Version._deserialize(field, seq_to_ob, links)
2902
+
2903
+ # Deserialize the block field.
2904
+ field = cbor.get('block', None)
2905
+ if not isinstance(field, dict):
2906
+ raise ValueError('missing or invalid serialization of field block')
2907
+ if field.get('@T') != '1':
2908
+ raise ValueError('unexpected edge type for field block')
2909
+ if field.get('@t', None) is None:
2910
+ f_block = None
2911
+ else:
2912
+ f_block = Block._deserialize(field, seq_to_ob, links)
2913
+
2914
+ # Deserialize the variables field.
2915
+ field = cbor.get('variables', None)
2916
+ if not isinstance(field, dict):
2917
+ raise ValueError('missing or invalid serialization of field variables')
2918
+ if field.get('@T') != '*':
2919
+ raise ValueError('unexpected edge type for field variables')
2920
+ data = field.get('@d', None)
2921
+ if not isinstance(data, list):
2922
+ raise ValueError('missing serialization of Any/Many contents')
2923
+ f_variables = MultiVariable()
2924
+ for element in data:
2925
+ if element.get('@T') != '1':
2926
+ raise ValueError('unexpected edge type for Any/Many element')
2927
+ f_variables.append(Variable._deserialize(element, seq_to_ob, links))
2928
+
2929
+ # Construct the Program node.
2930
+ node = Program(f_api_version, f_version, f_block, f_variables)
2931
+
2932
+ # Deserialize annotations.
2933
+ for key, val in cbor.items():
2934
+ if not (key.startswith('{') and key.endswith('}')):
2935
+ continue
2936
+ key = key[1:-1]
2937
+ node[key] = cqasm.v3x.primitives.deserialize(key, val)
2938
+
2939
+ # Register node in sequence number lookup.
2940
+ seq = cbor.get('@i', None)
2941
+ if not isinstance(seq, int):
2942
+ raise ValueError('sequence number field (@i) is not an integer or missing from node serialization')
2943
+ if seq in seq_to_ob:
2944
+ raise ValueError('duplicate sequence number %d' % seq)
2945
+ seq_to_ob[seq] = node
2946
+
2947
+ return node
2948
+
2949
+ def _serialize(self, id_map):
2950
+ """Serializes this node to the Python primitive representation of its
2951
+ CBOR serialization. The tree that the node belongs to must be
2952
+ well-formed. id_map must match Python id() calls for all nodes to unique
2953
+ integers, to use for the sequence number representation of links."""
2954
+ cbor = {'@i': id_map[id(self)], '@t': 'Program'}
2955
+
2956
+ # Serialize the api_version field.
2957
+ if hasattr(self._attr_api_version, 'serialize_cbor'):
2958
+ cbor['api_version'] = self._attr_api_version.serialize_cbor()
2959
+ else:
2960
+ cbor['api_version'] = cqasm.v3x.primitives.serialize(cqasm.v3x.primitives.Version, self._attr_api_version)
2961
+
2962
+ # Serialize the version field.
2963
+ field = {'@T': '1'}
2964
+ if self._attr_version is None:
2965
+ field['@t'] = None
2966
+ else:
2967
+ field.update(self._attr_version._serialize(id_map))
2968
+ cbor['version'] = field
2969
+
2970
+ # Serialize the block field.
2971
+ field = {'@T': '1'}
2972
+ if self._attr_block is None:
2973
+ field['@t'] = None
2974
+ else:
2975
+ field.update(self._attr_block._serialize(id_map))
2976
+ cbor['block'] = field
2977
+
2978
+ # Serialize the variables field.
2979
+ field = {'@T': '*'}
2980
+ lst = []
2981
+ for el in self._attr_variables:
2982
+ el = el._serialize(id_map)
2983
+ el['@T'] = '1'
2984
+ lst.append(el)
2985
+ field['@d'] = lst
2986
+ cbor['variables'] = field
2987
+
2988
+ # Serialize annotations.
2989
+ for key, val in self._annot.items():
2990
+ cbor['{%s}' % key] = _py_to_cbor(cqasm.v3x.primitives.serialize(key, val))
2991
+
2992
+ return cbor
2993
+
2994
+
2995
+ class MultiProgram(_Multiple):
2996
+ """Wrapper for an edge with multiple Program objects."""
2997
+
2998
+ _T = Program
2999
+
3000
+
3001
+ _typemap['Program'] = Program
3002
+
3003
+ class Variable(Annotated):
3004
+ __slots__ = [
3005
+ '_attr_name',
3006
+ '_attr_typ',
3007
+ ]
3008
+
3009
+ def __init__(
3010
+ self,
3011
+ name=None,
3012
+ typ=None,
3013
+ annotations=None,
3014
+ ):
3015
+ super().__init__(annotations=annotations)
3016
+ self.name = name
3017
+ self.typ = typ
3018
+
3019
+ @property
3020
+ def name(self):
3021
+ return self._attr_name
3022
+
3023
+ @name.setter
3024
+ def name(self, val):
3025
+ if val is None:
3026
+ del self.name
3027
+ return
3028
+ if not isinstance(val, cqasm.v3x.primitives.Str):
3029
+ # Try to "typecast" if this isn't an obvious mistake.
3030
+ if isinstance(val, Node):
3031
+ raise TypeError('name must be of type cqasm.v3x.primitives.Str')
3032
+ val = cqasm.v3x.primitives.Str(val)
3033
+ self._attr_name = val
3034
+
3035
+ @name.deleter
3036
+ def name(self):
3037
+ self._attr_name = cqasm.v3x.primitives.Str()
3038
+
3039
+ @property
3040
+ def typ(self):
3041
+ return self._attr_typ
3042
+
3043
+ @typ.setter
3044
+ def typ(self, val):
3045
+ if val is None:
3046
+ del self.typ
3047
+ return
3048
+ if not isinstance(val, cqasm.v3x.types.TypeBase):
3049
+ # Try to "typecast" if this isn't an obvious mistake.
3050
+ if isinstance(val, Node):
3051
+ raise TypeError('typ must be of type cqasm.v3x.types.TypeBase')
3052
+ val = cqasm.v3x.types.TypeBase(val)
3053
+ self._attr_typ = val
3054
+
3055
+ @typ.deleter
3056
+ def typ(self):
3057
+ self._attr_typ = None
3058
+
3059
+ def __eq__(self, other):
3060
+ """Equality operator. Ignores annotations!"""
3061
+ if not isinstance(other, Variable):
3062
+ return False
3063
+ if self.name != other.name:
3064
+ return False
3065
+ if self.typ != other.typ:
3066
+ return False
3067
+ if self.annotations != other.annotations:
3068
+ return False
3069
+ return True
3070
+
3071
+ def dump(self, indent=0, annotations=None, links=1):
3072
+ """Returns a debug representation of this tree as a multiline string.
3073
+ indent is the number of double spaces prefixed before every line.
3074
+ annotations, if specified, must be a set-like object containing the key
3075
+ strings of the annotations that are to be printed. links specifies the
3076
+ maximum link recursion depth."""
3077
+ s = [' '*indent]
3078
+ s.append('Variable(')
3079
+ if annotations is None:
3080
+ annotations = []
3081
+ for key in annotations:
3082
+ if key in self:
3083
+ s.append(' # {}: {}'.format(key, self[key]))
3084
+ s.append('\n')
3085
+ indent += 1
3086
+ s.append(' '*indent)
3087
+ s.append('name: ')
3088
+ s.append(str(self.name) + '\n')
3089
+ s.append(' '*indent)
3090
+ s.append('typ: ')
3091
+ if self.typ is None:
3092
+ s.append('!MISSING\n')
3093
+ else:
3094
+ s.append('<\n')
3095
+ s.append(self.typ.dump(indent + 1, annotations, links) + '\n')
3096
+ s.append(' '*indent + '>\n')
3097
+ s.append(' '*indent)
3098
+ s.append('annotations: ')
3099
+ if not self.annotations:
3100
+ s.append('-\n')
3101
+ else:
3102
+ s.append('[\n')
3103
+ for child in self.annotations:
3104
+ s.append(child.dump(indent + 1, annotations, links) + '\n')
3105
+ s.append(' '*indent + ']\n')
3106
+ indent -= 1
3107
+ s.append(' '*indent)
3108
+ s.append(')')
3109
+ return ''.join(s)
3110
+
3111
+ __str__ = dump
3112
+ __repr__ = dump
3113
+
3114
+ def find_reachable(self, id_map=None):
3115
+ """Returns a dictionary mapping Python id() values to stable sequence
3116
+ numbers for all nodes in the tree rooted at this node. If id_map is
3117
+ specified, found nodes are appended to it."""
3118
+ if id_map is None:
3119
+ id_map = {}
3120
+ if id(self) in id_map:
3121
+ raise NotWellFormed('node {!r} with id {} occurs more than once'.format(self, id(self)))
3122
+ id_map[id(self)] = len(id_map)
3123
+ if self._attr_typ is not None:
3124
+ self._attr_typ.find_reachable(id_map)
3125
+ for el in self._attr_annotations:
3126
+ el.find_reachable(id_map)
3127
+ return id_map
3128
+
3129
+ def check_complete(self, id_map=None):
3130
+ """Raises NotWellFormed if the tree rooted at this node is not
3131
+ well-formed. If id_map is specified, this tree is only a subtree in the
3132
+ context of a larger tree, and id_map must be a dict mapping from Python
3133
+ id() codes to tree indices for all reachable nodes."""
3134
+ if id_map is None:
3135
+ id_map = self.find_reachable()
3136
+ if self._attr_typ is None:
3137
+ raise NotWellFormed('typ is required but not set')
3138
+ if self._attr_typ is not None:
3139
+ self._attr_typ.check_complete(id_map)
3140
+ for child in self._attr_annotations:
3141
+ child.check_complete(id_map)
3142
+
3143
+ def copy(self):
3144
+ """Returns a shallow copy of this node."""
3145
+ return Variable(
3146
+ name=self._attr_name,
3147
+ typ=self._attr_typ,
3148
+ annotations=self._attr_annotations.copy()
3149
+ )
3150
+
3151
+ def clone(self):
3152
+ """Returns a deep copy of this node. This mimics the C++ interface,
3153
+ deficiencies with links included; that is, links always point to the
3154
+ original tree. If you're not cloning a subtree in a context where this
3155
+ is the desired behavior, you may want to use the copy.deepcopy() from
3156
+ the stdlib instead, which should copy links correctly."""
3157
+ return Variable(
3158
+ name=_cloned(self._attr_name),
3159
+ typ=_cloned(self._attr_typ),
3160
+ annotations=_cloned(self._attr_annotations)
3161
+ )
3162
+
3163
+ @staticmethod
3164
+ def _deserialize(cbor, seq_to_ob, links):
3165
+ """Attempts to deserialize the given cbor object (in Python primitive
3166
+ representation) into a node of this type. All (sub)nodes are added to
3167
+ the seq_to_ob dict, indexed by their cbor sequence number. All links are
3168
+ registered in the links list by means of a two-tuple of the setter
3169
+ function for the link field and the sequence number of the target node.
3170
+ """
3171
+ if not isinstance(cbor, dict):
3172
+ raise TypeError('node description object must be a dict')
3173
+ typ = cbor.get('@t', None)
3174
+ if typ is None:
3175
+ raise ValueError('type (@t) field is missing from node serialization')
3176
+ if typ != 'Variable':
3177
+ raise ValueError('found node serialization for ' + typ + ', but expected Variable')
3178
+
3179
+ # Deserialize the name field.
3180
+ field = cbor.get('name', None)
3181
+ if not isinstance(field, dict):
3182
+ raise ValueError('missing or invalid serialization of field name')
3183
+ if hasattr(cqasm.v3x.primitives.Str, 'deserialize_cbor'):
3184
+ f_name = cqasm.v3x.primitives.Str.deserialize_cbor(field)
3185
+ else:
3186
+ f_name = cqasm.v3x.primitives.deserialize(cqasm.v3x.primitives.Str, field)
3187
+
3188
+ # Deserialize the typ field.
3189
+ field = cbor.get('typ', None)
3190
+ if not isinstance(field, dict):
3191
+ raise ValueError('missing or invalid serialization of field typ')
3192
+ if field.get('@T') != '1':
3193
+ raise ValueError('unexpected edge type for field typ')
3194
+ if field.get('@t', None) is None:
3195
+ f_typ = None
3196
+ else:
3197
+ f_typ = cqasm.v3x.types.TypeBase._deserialize(field, seq_to_ob, links)
3198
+
3199
+ # Deserialize the annotations field.
3200
+ field = cbor.get('annotations', None)
3201
+ if not isinstance(field, dict):
3202
+ raise ValueError('missing or invalid serialization of field annotations')
3203
+ if field.get('@T') != '*':
3204
+ raise ValueError('unexpected edge type for field annotations')
3205
+ data = field.get('@d', None)
3206
+ if not isinstance(data, list):
3207
+ raise ValueError('missing serialization of Any/Many contents')
3208
+ f_annotations = MultiAnnotationData()
3209
+ for element in data:
3210
+ if element.get('@T') != '1':
3211
+ raise ValueError('unexpected edge type for Any/Many element')
3212
+ f_annotations.append(AnnotationData._deserialize(element, seq_to_ob, links))
3213
+
3214
+ # Construct the Variable node.
3215
+ node = Variable(f_name, f_typ, f_annotations)
3216
+
3217
+ # Deserialize annotations.
3218
+ for key, val in cbor.items():
3219
+ if not (key.startswith('{') and key.endswith('}')):
3220
+ continue
3221
+ key = key[1:-1]
3222
+ node[key] = cqasm.v3x.primitives.deserialize(key, val)
3223
+
3224
+ # Register node in sequence number lookup.
3225
+ seq = cbor.get('@i', None)
3226
+ if not isinstance(seq, int):
3227
+ raise ValueError('sequence number field (@i) is not an integer or missing from node serialization')
3228
+ if seq in seq_to_ob:
3229
+ raise ValueError('duplicate sequence number %d' % seq)
3230
+ seq_to_ob[seq] = node
3231
+
3232
+ return node
3233
+
3234
+ def _serialize(self, id_map):
3235
+ """Serializes this node to the Python primitive representation of its
3236
+ CBOR serialization. The tree that the node belongs to must be
3237
+ well-formed. id_map must match Python id() calls for all nodes to unique
3238
+ integers, to use for the sequence number representation of links."""
3239
+ cbor = {'@i': id_map[id(self)], '@t': 'Variable'}
3240
+
3241
+ # Serialize the name field.
3242
+ if hasattr(self._attr_name, 'serialize_cbor'):
3243
+ cbor['name'] = self._attr_name.serialize_cbor()
3244
+ else:
3245
+ cbor['name'] = cqasm.v3x.primitives.serialize(cqasm.v3x.primitives.Str, self._attr_name)
3246
+
3247
+ # Serialize the typ field.
3248
+ field = {'@T': '1'}
3249
+ if self._attr_typ is None:
3250
+ field['@t'] = None
3251
+ else:
3252
+ field.update(self._attr_typ._serialize(id_map))
3253
+ cbor['typ'] = field
3254
+
3255
+ # Serialize the annotations field.
3256
+ field = {'@T': '*'}
3257
+ lst = []
3258
+ for el in self._attr_annotations:
3259
+ el = el._serialize(id_map)
3260
+ el['@T'] = '1'
3261
+ lst.append(el)
3262
+ field['@d'] = lst
3263
+ cbor['annotations'] = field
3264
+
3265
+ # Serialize annotations.
3266
+ for key, val in self._annot.items():
3267
+ cbor['{%s}' % key] = _py_to_cbor(cqasm.v3x.primitives.serialize(key, val))
3268
+
3269
+ return cbor
3270
+
3271
+
3272
+ class MultiVariable(_Multiple):
3273
+ """Wrapper for an edge with multiple Variable objects."""
3274
+
3275
+ _T = Variable
3276
+
3277
+
3278
+ _typemap['Variable'] = Variable
3279
+
3280
+ class Version(Node):
3281
+ __slots__ = [
3282
+ '_attr_items',
3283
+ ]
3284
+
3285
+ def __init__(
3286
+ self,
3287
+ items=None,
3288
+ ):
3289
+ super().__init__()
3290
+ self.items = items
3291
+
3292
+ @property
3293
+ def items(self):
3294
+ return self._attr_items
3295
+
3296
+ @items.setter
3297
+ def items(self, val):
3298
+ if val is None:
3299
+ del self.items
3300
+ return
3301
+ if not isinstance(val, cqasm.v3x.primitives.Version):
3302
+ # Try to "typecast" if this isn't an obvious mistake.
3303
+ if isinstance(val, Node):
3304
+ raise TypeError('items must be of type cqasm.v3x.primitives.Version')
3305
+ val = cqasm.v3x.primitives.Version(val)
3306
+ self._attr_items = val
3307
+
3308
+ @items.deleter
3309
+ def items(self):
3310
+ self._attr_items = cqasm.v3x.primitives.Version()
3311
+
3312
+ def __eq__(self, other):
3313
+ """Equality operator. Ignores annotations!"""
3314
+ if not isinstance(other, Version):
3315
+ return False
3316
+ if self.items != other.items:
3317
+ return False
3318
+ return True
3319
+
3320
+ def dump(self, indent=0, annotations=None, links=1):
3321
+ """Returns a debug representation of this tree as a multiline string.
3322
+ indent is the number of double spaces prefixed before every line.
3323
+ annotations, if specified, must be a set-like object containing the key
3324
+ strings of the annotations that are to be printed. links specifies the
3325
+ maximum link recursion depth."""
3326
+ s = [' '*indent]
3327
+ s.append('Version(')
3328
+ if annotations is None:
3329
+ annotations = []
3330
+ for key in annotations:
3331
+ if key in self:
3332
+ s.append(' # {}: {}'.format(key, self[key]))
3333
+ s.append('\n')
3334
+ indent += 1
3335
+ s.append(' '*indent)
3336
+ s.append('items: ')
3337
+ s.append(str(self.items) + '\n')
3338
+ indent -= 1
3339
+ s.append(' '*indent)
3340
+ s.append(')')
3341
+ return ''.join(s)
3342
+
3343
+ __str__ = dump
3344
+ __repr__ = dump
3345
+
3346
+ def find_reachable(self, id_map=None):
3347
+ """Returns a dictionary mapping Python id() values to stable sequence
3348
+ numbers for all nodes in the tree rooted at this node. If id_map is
3349
+ specified, found nodes are appended to it."""
3350
+ if id_map is None:
3351
+ id_map = {}
3352
+ if id(self) in id_map:
3353
+ raise NotWellFormed('node {!r} with id {} occurs more than once'.format(self, id(self)))
3354
+ id_map[id(self)] = len(id_map)
3355
+ return id_map
3356
+
3357
+ def check_complete(self, id_map=None):
3358
+ """Raises NotWellFormed if the tree rooted at this node is not
3359
+ well-formed. If id_map is specified, this tree is only a subtree in the
3360
+ context of a larger tree, and id_map must be a dict mapping from Python
3361
+ id() codes to tree indices for all reachable nodes."""
3362
+ if id_map is None:
3363
+ id_map = self.find_reachable()
3364
+
3365
+ def copy(self):
3366
+ """Returns a shallow copy of this node."""
3367
+ return Version(
3368
+ items=self._attr_items
3369
+ )
3370
+
3371
+ def clone(self):
3372
+ """Returns a deep copy of this node. This mimics the C++ interface,
3373
+ deficiencies with links included; that is, links always point to the
3374
+ original tree. If you're not cloning a subtree in a context where this
3375
+ is the desired behavior, you may want to use the copy.deepcopy() from
3376
+ the stdlib instead, which should copy links correctly."""
3377
+ return Version(
3378
+ items=_cloned(self._attr_items)
3379
+ )
3380
+
3381
+ @staticmethod
3382
+ def _deserialize(cbor, seq_to_ob, links):
3383
+ """Attempts to deserialize the given cbor object (in Python primitive
3384
+ representation) into a node of this type. All (sub)nodes are added to
3385
+ the seq_to_ob dict, indexed by their cbor sequence number. All links are
3386
+ registered in the links list by means of a two-tuple of the setter
3387
+ function for the link field and the sequence number of the target node.
3388
+ """
3389
+ if not isinstance(cbor, dict):
3390
+ raise TypeError('node description object must be a dict')
3391
+ typ = cbor.get('@t', None)
3392
+ if typ is None:
3393
+ raise ValueError('type (@t) field is missing from node serialization')
3394
+ if typ != 'Version':
3395
+ raise ValueError('found node serialization for ' + typ + ', but expected Version')
3396
+
3397
+ # Deserialize the items field.
3398
+ field = cbor.get('items', None)
3399
+ if not isinstance(field, dict):
3400
+ raise ValueError('missing or invalid serialization of field items')
3401
+ if hasattr(cqasm.v3x.primitives.Version, 'deserialize_cbor'):
3402
+ f_items = cqasm.v3x.primitives.Version.deserialize_cbor(field)
3403
+ else:
3404
+ f_items = cqasm.v3x.primitives.deserialize(cqasm.v3x.primitives.Version, field)
3405
+
3406
+ # Construct the Version node.
3407
+ node = Version(f_items)
3408
+
3409
+ # Deserialize annotations.
3410
+ for key, val in cbor.items():
3411
+ if not (key.startswith('{') and key.endswith('}')):
3412
+ continue
3413
+ key = key[1:-1]
3414
+ node[key] = cqasm.v3x.primitives.deserialize(key, val)
3415
+
3416
+ # Register node in sequence number lookup.
3417
+ seq = cbor.get('@i', None)
3418
+ if not isinstance(seq, int):
3419
+ raise ValueError('sequence number field (@i) is not an integer or missing from node serialization')
3420
+ if seq in seq_to_ob:
3421
+ raise ValueError('duplicate sequence number %d' % seq)
3422
+ seq_to_ob[seq] = node
3423
+
3424
+ return node
3425
+
3426
+ def _serialize(self, id_map):
3427
+ """Serializes this node to the Python primitive representation of its
3428
+ CBOR serialization. The tree that the node belongs to must be
3429
+ well-formed. id_map must match Python id() calls for all nodes to unique
3430
+ integers, to use for the sequence number representation of links."""
3431
+ cbor = {'@i': id_map[id(self)], '@t': 'Version'}
3432
+
3433
+ # Serialize the items field.
3434
+ if hasattr(self._attr_items, 'serialize_cbor'):
3435
+ cbor['items'] = self._attr_items.serialize_cbor()
3436
+ else:
3437
+ cbor['items'] = cqasm.v3x.primitives.serialize(cqasm.v3x.primitives.Version, self._attr_items)
3438
+
3439
+ # Serialize annotations.
3440
+ for key, val in self._annot.items():
3441
+ cbor['{%s}' % key] = _py_to_cbor(cqasm.v3x.primitives.serialize(key, val))
3442
+
3443
+ return cbor
3444
+
3445
+
3446
+ class MultiVersion(_Multiple):
3447
+ """Wrapper for an edge with multiple Version objects."""
3448
+
3449
+ _T = Version
3450
+
3451
+
3452
+ _typemap['Version'] = Version
3453
+