libqasm 0.6.7__cp310-cp310-macosx_11_0_arm64.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/types.py ADDED
@@ -0,0 +1,1742 @@
1
+ import functools
2
+ import struct
3
+ import cqasm.v3x.primitives
4
+
5
+
6
+ _typemap = {}
7
+
8
+
9
+ def _cbor_read_intlike(cbor, offset, info):
10
+ """Parses the additional information and reads any additional bytes it
11
+ specifies the existence of, and returns the encoded integer. offset
12
+ should point to the byte immediately following the initial byte. Returns
13
+ the encoded integer and the offset immediately following the object."""
14
+
15
+ # Info less than 24 is a shorthand for the integer itself.
16
+ if info < 24:
17
+ return info, offset
18
+
19
+ # 24 is 8-bit following the info byte.
20
+ if info == 24:
21
+ return cbor[offset], offset + 1
22
+
23
+ # 25 is 16-bit following the info byte.
24
+ if info == 25:
25
+ val, = struct.unpack('>H', cbor[offset:offset+2])
26
+ return val, offset + 2
27
+
28
+ # 26 is 32-bit following the info byte.
29
+ if info == 26:
30
+ val, = struct.unpack('>I', cbor[offset:offset+4])
31
+ return val, offset + 4
32
+
33
+ # 27 is 64-bit following the info byte.
34
+ if info == 27:
35
+ val, = struct.unpack('>Q', cbor[offset:offset+8])
36
+ return val, offset + 8
37
+
38
+ # Info greater than or equal to 28 is illegal. Note that 31 is used for
39
+ # indefinite lengths, so this must be checked prior to calling this
40
+ # method.
41
+ raise ValueError("invalid CBOR: illegal additional info for integer or object length")
42
+
43
+
44
+ def _sub_cbor_to_py(cbor, offset):
45
+ """Converts the CBOR object starting at cbor[offset] to its Python
46
+ representation for as far as tree-gen supports CBOR. Returns this Python
47
+ representation and the offset immediately following the CBOR representation
48
+ thereof. Supported types:
49
+
50
+ - 0: unsigned integer (int)
51
+ - 1: negative integer (int)
52
+ - 2: byte string (bytes)
53
+ - 3: UTF-8 string (str)
54
+ - 4: array (list)
55
+ - 5: map (dict)
56
+ - 6: semantic tag (ignored)
57
+ - 7.20: false (bool)
58
+ - 7.21: true (bool)
59
+ - 7.22: null (NoneType)
60
+ - 7.27: double-precision float (float)
61
+
62
+ Both definite-length and indefinite-length notation is supported for sized
63
+ objects (strings, arrays, maps). A ValueError is thrown if the CBOR is
64
+ invalid or contains unsupported structures."""
65
+
66
+ # Read the initial byte.
67
+ initial = cbor[offset]
68
+ typ = initial >> 5
69
+ info = initial & 0x1F
70
+ offset += 1
71
+
72
+ # Handle unsigned integer (0) and negative integer (1).
73
+ if typ <= 1:
74
+ value, offset = _cbor_read_intlike(cbor, offset, info)
75
+ if typ == 1:
76
+ value = -1 - value
77
+ return value, offset
78
+
79
+ # Handle byte string (2) and UTF-8 string (3).
80
+ if typ <= 3:
81
+
82
+ # Gather components of the string in here.
83
+ if info == 31:
84
+
85
+ # Handle indefinite length strings. These consist of a
86
+ # break-terminated (0xFF) list of definite-length strings of the
87
+ # same type.
88
+ value = []
89
+ while True:
90
+ sub_initial = cbor[offset]; offset += 1
91
+ if sub_initial == 0xFF:
92
+ break
93
+ sub_typ = sub_initial >> 5
94
+ sub_info = sub_initial & 0x1F
95
+ if sub_typ != typ:
96
+ raise ValueError('invalid CBOR: illegal indefinite-length string component')
97
+
98
+ # Seek past definite-length string component. The size in
99
+ # bytes is encoded as an integer.
100
+ size, offset = _cbor_read_intlike(cbor, offset, sub_info)
101
+ value.append(cbor[offset:offset + size])
102
+ offset += size
103
+ value = b''.join(value)
104
+
105
+ else:
106
+
107
+ # Handle definite-length strings. The size in bytes is encoded as
108
+ # an integer.
109
+ size, offset = _cbor_read_intlike(cbor, offset, info)
110
+ value = cbor[offset:offset + size]
111
+ offset += size
112
+
113
+ if typ == 3:
114
+ value = value.decode('UTF-8')
115
+ return value, offset
116
+
117
+ # Handle array (4) and map (5).
118
+ if typ <= 5:
119
+
120
+ # Create result container.
121
+ container = [] if typ == 4 else {}
122
+
123
+ # Handle indefinite length arrays and maps.
124
+ if info == 31:
125
+
126
+ # Read objects/object pairs until we encounter a break.
127
+ while cbor[offset] != 0xFF:
128
+ if typ == 4:
129
+ value, offset = _sub_cbor_to_py(cbor, offset)
130
+ container.append(value)
131
+ else:
132
+ key, offset = _sub_cbor_to_py(cbor, offset)
133
+ if not isinstance(key, str):
134
+ raise ValueError('invalid CBOR: map key is not a UTF-8 string')
135
+ value, offset = _sub_cbor_to_py(cbor, offset)
136
+ container[key] = value
137
+
138
+ # Seek past the break.
139
+ offset += 1
140
+
141
+ else:
142
+
143
+ # Handle definite-length arrays and maps. The amount of
144
+ # objects/object pairs is encoded as an integer.
145
+ size, offset = _cbor_read_intlike(cbor, offset, info)
146
+ for _ in range(size):
147
+ if typ == 4:
148
+ value, offset = _sub_cbor_to_py(cbor, offset)
149
+ container.append(value)
150
+ else:
151
+ key, offset = _sub_cbor_to_py(cbor, offset)
152
+ if not isinstance(key, str):
153
+ raise ValueError('invalid CBOR: map key is not a UTF-8 string')
154
+ value, offset = _sub_cbor_to_py(cbor, offset)
155
+ container[key] = value
156
+
157
+ return container, offset
158
+
159
+ # Handle semantic tags.
160
+ if typ == 6:
161
+
162
+ # We don't use semantic tags for anything, but ignoring them is
163
+ # legal and reading past them is easy enough.
164
+ _, offset = _cbor_read_intlike(cbor, offset, info)
165
+ return _sub_cbor_to_py(cbor, offset)
166
+
167
+ # Handle major type 7. Here, the type is defined by the additional info.
168
+ # Additional info 24 is reserved for having the type specified by the
169
+ # next byte, but all such values are unassigned.
170
+ if info == 20:
171
+ # false
172
+ return False, offset
173
+
174
+ if info == 21:
175
+ # true
176
+ return True, offset
177
+
178
+ if info == 22:
179
+ # null
180
+ return None, offset
181
+
182
+ if info == 23:
183
+ # Undefined value.
184
+ raise ValueError('invalid CBOR: undefined value is not supported')
185
+
186
+ if info == 25:
187
+ # Half-precision float.
188
+ raise ValueError('invalid CBOR: half-precision float is not supported')
189
+
190
+ if info == 26:
191
+ # Single-precision float.
192
+ raise ValueError('invalid CBOR: single-precision float is not supported')
193
+
194
+ if info == 27:
195
+ # Double-precision float.
196
+ value, = struct.unpack('>d', cbor[offset:offset+8])
197
+ return value, offset + 8
198
+
199
+ if info == 31:
200
+ # Break value used for indefinite-length objects.
201
+ raise ValueError('invalid CBOR: unexpected break')
202
+
203
+ raise ValueError('invalid CBOR: unknown type code')
204
+
205
+
206
+ def _cbor_to_py(cbor):
207
+ """Converts the given CBOR object (bytes) to its Python representation for
208
+ as far as tree-gen supports CBOR. Supported types:
209
+
210
+ - 0: unsigned integer (int)
211
+ - 1: negative integer (int)
212
+ - 2: byte string (bytes)
213
+ - 3: UTF-8 string (str)
214
+ - 4: array (list)
215
+ - 5: map (dict)
216
+ - 6: semantic tag (ignored)
217
+ - 7.20: false (bool)
218
+ - 7.21: true (bool)
219
+ - 7.22: null (NoneType)
220
+ - 7.27: double-precision float (float)
221
+
222
+ Both definite-length and indefinite-length notation is supported for sized
223
+ objects (strings, arrays, maps). A ValueError is thrown if the CBOR is
224
+ invalid or contains unsupported structures."""
225
+
226
+ value, length = _sub_cbor_to_py(cbor, 0)
227
+ if length < len(cbor):
228
+ raise ValueError('invalid CBOR: garbage at the end')
229
+ return value
230
+
231
+
232
+ class _Cbor(bytes):
233
+ """Marker class indicating that this bytes object represents CBOR."""
234
+ pass
235
+
236
+
237
+ def _cbor_write_intlike(value, major=0):
238
+ """Converts the given integer to its minimal representation in CBOR. The
239
+ major code can be overridden to write lengths for strings, arrays, and
240
+ maps."""
241
+
242
+ # Negative integers use major code 1.
243
+ if value < 0:
244
+ major = 1
245
+ value = -1 - value
246
+ initial = major << 5
247
+
248
+ # Use the minimal representation.
249
+ if value < 24:
250
+ return struct.pack('>B', initial | value)
251
+ if value < 0x100:
252
+ return struct.pack('>BB', initial | 24, value)
253
+ if value < 0x10000:
254
+ return struct.pack('>BH', initial | 25, value)
255
+ if value < 0x100000000:
256
+ return struct.pack('>BI', initial | 26, value)
257
+ if value < 0x10000000000000000:
258
+ return struct.pack('>BQ', initial | 27, value)
259
+
260
+ raise ValueError('integer too large for CBOR (bigint not supported)')
261
+
262
+
263
+ def _py_to_cbor(value, type_converter=None):
264
+ """Inverse of _cbor_to_py(). type_converter optionally specifies a function
265
+ that takes a value and either converts it to a primitive for serialization,
266
+ converts it to a _Cbor object manually, or raises a TypeError if no
267
+ conversion is known. If no type_converter is specified, a TypeError is
268
+ raised in all cases the type_converter would otherwise be called. The cbor
269
+ serialization is returned using a _Cbor object, which is just a marker class
270
+ behaving just like bytes."""
271
+ if isinstance(value, _Cbor):
272
+ return value
273
+
274
+ if isinstance(value, int):
275
+ return _Cbor(_cbor_write_intlike(value))
276
+
277
+ if isinstance(value, float):
278
+ return _Cbor(struct.pack('>Bd', 0xFB, value))
279
+
280
+ if isinstance(value, str):
281
+ value = value.encode('UTF-8')
282
+ return _Cbor(_cbor_write_intlike(len(value), 3) + value)
283
+
284
+ if isinstance(value, bytes):
285
+ return _Cbor(_cbor_write_intlike(len(value), 2) + value)
286
+
287
+ if value is False:
288
+ return _Cbor(b'\xF4')
289
+
290
+ if value is True:
291
+ return _Cbor(b'\xF5')
292
+
293
+ if value is None:
294
+ return _Cbor(b'\xF6')
295
+
296
+ if isinstance(value, (list, tuple)):
297
+ cbor = [_cbor_write_intlike(len(value), 4)]
298
+ for val in value:
299
+ cbor.append(_py_to_cbor(val, type_converter))
300
+ return _Cbor(b''.join(cbor))
301
+
302
+ if isinstance(value, dict):
303
+ cbor = [_cbor_write_intlike(len(value), 5)]
304
+ for key, val in sorted(value.items()):
305
+ if not isinstance(key, str):
306
+ raise TypeError('dict keys must be strings')
307
+ cbor.append(_py_to_cbor(key, type_converter))
308
+ cbor.append(_py_to_cbor(val, type_converter))
309
+ return _Cbor(b''.join(cbor))
310
+
311
+ if type_converter is not None:
312
+ return _py_to_cbor(type_converter(value))
313
+
314
+ raise TypeError('unsupported type for conversion to cbor: %r' % (value,))
315
+
316
+
317
+ class NotWellFormed(ValueError):
318
+ """Exception class for well-formedness checks."""
319
+
320
+ def __init__(self, msg):
321
+ super().__init__('not well-formed: ' + str(msg))
322
+
323
+
324
+ class Node(object):
325
+ """Base class for nodes."""
326
+
327
+ __slots__ = ['_annot']
328
+
329
+ def __init__(self):
330
+ super().__init__()
331
+ self._annot = {}
332
+
333
+ def __getitem__(self, key):
334
+ """Returns the annotation object with the specified key, or raises
335
+ KeyError if not found."""
336
+ if not isinstance(key, str):
337
+ raise TypeError('indexing a node with something other than an '
338
+ 'annotation key string')
339
+ return self._annot[key]
340
+
341
+ def __setitem__(self, key, val):
342
+ """Assigns the annotation object with the specified key."""
343
+ if not isinstance(key, str):
344
+ raise TypeError('indexing a node with something other than an '
345
+ 'annotation key string')
346
+ self._annot[key] = val
347
+
348
+ def __delitem__(self, key):
349
+ """Deletes the annotation object with the specified key."""
350
+ if not isinstance(key, str):
351
+ raise TypeError('indexing a node with something other than an '
352
+ 'annotation key string')
353
+ del self._annot[key]
354
+
355
+ def __contains__(self, key):
356
+ """Returns whether an annotation exists for the specified key."""
357
+ return key in self._annot
358
+
359
+ @staticmethod
360
+ def find_reachable(self, id_map=None):
361
+ """Returns a dictionary mapping Python id() values to stable sequence
362
+ numbers for all nodes in the tree rooted at this node. If id_map is
363
+ specified, found nodes are appended to it. Note that this is overridden
364
+ by the actual node class implementations; this base function does very
365
+ little."""
366
+ if id_map is None:
367
+ id_map = {}
368
+ return id_map
369
+
370
+ def check_complete(self, id_map=None):
371
+ """Raises NotWellFormed if the tree rooted at this node is not
372
+ well-formed. If id_map is specified, this tree is only a subtree in the
373
+ context of a larger tree, and id_map must be a dict mapping from Python
374
+ id() codes to tree indices for all reachable nodes. Note that this is
375
+ overridden by the actual node class implementations; this base function
376
+ always raises an exception."""
377
+ raise NotWellFormed('found node of abstract type ' + type(self).__name__)
378
+
379
+ def check_well_formed(self):
380
+ """Checks whether the tree starting at this node is well-formed. That
381
+ is:
382
+
383
+ - all One, Link, and Many edges have (at least) one entry;
384
+ - all the One entries internally stored by Any/Many have an entry;
385
+ - all Link and filled OptLink nodes link to a node that's reachable
386
+ from this node;
387
+ - the nodes referred to be One/Maybe only appear once in the tree
388
+ (except through links).
389
+
390
+ If it isn't well-formed, a NotWellFormed is thrown."""
391
+ self.check_complete()
392
+
393
+ def is_well_formed(self):
394
+ """Returns whether the tree starting at this node is well-formed. That
395
+ is:
396
+
397
+ - all One, Link, and Many edges have (at least) one entry;
398
+ - all the One entries internally stored by Any/Many have an entry;
399
+ - all Link and filled OptLink nodes link to a node that's reachable
400
+ from this node;
401
+ - the nodes referred to be One/Maybe only appear once in the tree
402
+ (except through links)."""
403
+ try:
404
+ self.check_well_formed()
405
+ return True
406
+ except NotWellFormed:
407
+ return False
408
+
409
+ def copy(self):
410
+ """Returns a shallow copy of this node. Note that this is overridden by
411
+ the actual node class implementations; this base function always raises
412
+ an exception."""
413
+ raise TypeError('can\'t copy node of abstract type ' + type(self).__name__)
414
+
415
+ def clone(self):
416
+ """Returns a deep copy of this node. Note that this is overridden by
417
+ the actual node class implementations; this base function always raises
418
+ an exception."""
419
+ raise TypeError('can\'t clone node of abstract type ' + type(self).__name__)
420
+
421
+ @classmethod
422
+ def deserialize(cls, cbor):
423
+ """Attempts to deserialize the given cbor object (either as bytes or as
424
+ its Python primitive representation) into a node of this type."""
425
+ if isinstance(cbor, bytes):
426
+ cbor = _cbor_to_py(cbor)
427
+ seq_to_ob = {}
428
+ links = []
429
+ root = cls._deserialize(cbor, seq_to_ob, links)
430
+ for link_setter, seq in links:
431
+ ob = seq_to_ob.get(seq, None)
432
+ if ob is None:
433
+ raise ValueError('found link to nonexistent object')
434
+ link_setter(ob)
435
+ return root
436
+
437
+ def serialize(self):
438
+ """Serializes this node into its cbor representation in the form of a
439
+ bytes object."""
440
+ id_map = self.find_reachable()
441
+ self.check_complete(id_map)
442
+ return _py_to_cbor(self._serialize(id_map))
443
+
444
+ @staticmethod
445
+ def _deserialize(cbor, seq_to_ob, links):
446
+ if not isinstance(cbor, dict):
447
+ raise TypeError('node description object must be a dict')
448
+ typ = cbor.get('@t', None)
449
+ if typ is None:
450
+ raise ValueError('type (@t) field is missing from node serialization')
451
+ node_type = _typemap.get(cbor.get('@t'), None)
452
+ if node_type is None:
453
+ raise ValueError('unknown node type (@t): ' + str(cbor.get('@t')))
454
+ return node_type._deserialize(cbor, seq_to_ob, links)
455
+
456
+
457
+ @functools.total_ordering
458
+ class _Multiple(object):
459
+ """Base class for the Any* and Many* edge helper classes. Inheriting
460
+ classes must set the class constant _T to the node type they are made
461
+ for."""
462
+
463
+ __slots__ = ['_l']
464
+
465
+ def __init__(self, *args, **kwargs):
466
+ super().__init__()
467
+ self._l = list(*args, **kwargs)
468
+ for idx, val in enumerate(self._l):
469
+ if not isinstance(val, self._T):
470
+ raise TypeError(
471
+ 'object {!r} at index {:d} is not an instance of {!r}'
472
+ .format(val, idx, self._T))
473
+
474
+ def __repr__(self):
475
+ return '{}({!r})'.format(type(self).__name__, self._l)
476
+
477
+ def clone(self):
478
+ return self.__class__(map(lambda node: node.clone(), self._l))
479
+
480
+ def __len__(self):
481
+ return len(self._l)
482
+
483
+ def __getitem__(self, idx):
484
+ return self._l[idx]
485
+
486
+ def __setitem__(self, idx, val):
487
+ if not isinstance(val, self._T):
488
+ raise TypeError(
489
+ 'object {!r} is not an instance of {!r}'
490
+ .format(val, idx, self._T))
491
+ self._l[idx] = val
492
+
493
+ def __delitem__(self, idx):
494
+ del self._l[idx]
495
+
496
+ def __iter__(self):
497
+ return iter(self._l)
498
+
499
+ def __reversed__(self):
500
+ return reversed(self._l)
501
+
502
+ def __contains__(self, val):
503
+ return val in self._l
504
+
505
+ def append(self, val):
506
+ if not isinstance(val, self._T):
507
+ raise TypeError(
508
+ 'object {!r} is not an instance of {!r}'
509
+ .format(val, self._T))
510
+ self._l.append(val)
511
+
512
+ def extend(self, iterable):
513
+ for val in iterable:
514
+ self.append(val)
515
+
516
+ def insert(self, idx, val):
517
+ if not isinstance(val, self._T):
518
+ raise TypeError(
519
+ 'object {!r} is not an instance of {!r}'
520
+ .format(val, self._T))
521
+ self._l.insert(idx, val)
522
+
523
+ def remote(self, val):
524
+ self._l.remove(val)
525
+
526
+ def pop(self, idx=-1):
527
+ return self._l.pop(idx)
528
+
529
+ def clear(self):
530
+ self._l.clear()
531
+
532
+ def idx(self, val, start=0, end=-1):
533
+ return self._l.idx(val, start, end)
534
+
535
+ def count(self, val):
536
+ return self._l.count(val)
537
+
538
+ def sort(self, key=None, reverse=False):
539
+ self._l.sort(key=key, reverse=reverse)
540
+
541
+ def reverse(self):
542
+ self._l.reverse()
543
+
544
+ def copy(self):
545
+ return self.__class__(self)
546
+
547
+ def __eq__(self, other):
548
+ if not isinstance(other, _Multiple):
549
+ return False
550
+ return self._l == other._l
551
+
552
+ def __lt__(self, other):
553
+ return self._l < other._l
554
+
555
+ def __iadd__(self, other):
556
+ self.extend(other)
557
+
558
+ def __add__(self, other):
559
+ copy = self.copy()
560
+ copy += other
561
+ return copy
562
+
563
+ def __imul__(self, other):
564
+ self._l *= other
565
+
566
+ def __mul__(self, other):
567
+ copy = self.copy()
568
+ copy *= other
569
+ return copy
570
+
571
+ def __rmul__(self, other):
572
+ copy = self.copy()
573
+ copy *= other
574
+ return copy
575
+
576
+
577
+ class MultiNode(_Multiple):
578
+ """Wrapper for an edge with multiple Node objects."""
579
+
580
+ _T = Node
581
+
582
+
583
+ def _cloned(obj):
584
+ """Attempts to clone the given object by calling its clone() method, if it
585
+ has one."""
586
+ if hasattr(obj, 'clone'):
587
+ return obj.clone()
588
+ return obj
589
+
590
+
591
+ class TypeBase(Node):
592
+ __slots__ = [
593
+ '_attr_size',
594
+ ]
595
+
596
+ def __init__(
597
+ self,
598
+ size=None,
599
+ ):
600
+ super().__init__()
601
+ self.size = size
602
+
603
+ @property
604
+ def size(self):
605
+ return self._attr_size
606
+
607
+ @size.setter
608
+ def size(self, val):
609
+ if val is None:
610
+ del self.size
611
+ return
612
+ if not isinstance(val, cqasm.v3x.primitives.Int):
613
+ # Try to "typecast" if this isn't an obvious mistake.
614
+ if isinstance(val, Node):
615
+ raise TypeError('size must be of type cqasm.v3x.primitives.Int')
616
+ val = cqasm.v3x.primitives.Int(val)
617
+ self._attr_size = val
618
+
619
+ @size.deleter
620
+ def size(self):
621
+ self._attr_size = cqasm.v3x.primitives.Int()
622
+
623
+ @staticmethod
624
+ def _deserialize(cbor, seq_to_ob, links):
625
+ """Attempts to deserialize the given cbor object (in Python primitive
626
+ representation) into a node of this type. All (sub)nodes are added to
627
+ the seq_to_ob dict, indexed by their cbor sequence number. All links are
628
+ registered in the links list by means of a two-tuple of the setter
629
+ function for the link field and the sequence number of the target node.
630
+ """
631
+ if not isinstance(cbor, dict):
632
+ raise TypeError('node description object must be a dict')
633
+ typ = cbor.get('@t', None)
634
+ if typ is None:
635
+ raise ValueError('type (@t) field is missing from node serialization')
636
+ if typ == 'Bool':
637
+ return Bool._deserialize(cbor, seq_to_ob, links)
638
+ if typ == 'Int':
639
+ return Int._deserialize(cbor, seq_to_ob, links)
640
+ if typ == 'Float':
641
+ return Float._deserialize(cbor, seq_to_ob, links)
642
+ if typ == 'Bit':
643
+ return Bit._deserialize(cbor, seq_to_ob, links)
644
+ if typ == 'Qubit':
645
+ return Qubit._deserialize(cbor, seq_to_ob, links)
646
+ if typ == 'BitArray':
647
+ return BitArray._deserialize(cbor, seq_to_ob, links)
648
+ if typ == 'QubitArray':
649
+ return QubitArray._deserialize(cbor, seq_to_ob, links)
650
+ raise ValueError('unknown or unexpected type (@t) found in node serialization')
651
+
652
+ def _serialize(self, id_map):
653
+ """Serializes this node to the Python primitive representation of its
654
+ CBOR serialization. The tree that the node belongs to must be
655
+ well-formed. id_map must match Python id() calls for all nodes to unique
656
+ integers, to use for the sequence number representation of links."""
657
+ cbor = {'@i': id_map[id(self)], '@t': 'TypeBase'}
658
+
659
+ # Serialize the size field.
660
+ if hasattr(self._attr_size, 'serialize_cbor'):
661
+ cbor['size'] = self._attr_size.serialize_cbor()
662
+ else:
663
+ cbor['size'] = cqasm.v3x.primitives.serialize(cqasm.v3x.primitives.Int, self._attr_size)
664
+
665
+ # Serialize annotations.
666
+ for key, val in self._annot.items():
667
+ cbor['{%s}' % key] = _py_to_cbor(cqasm.v3x.primitives.serialize(key, val))
668
+
669
+ return cbor
670
+
671
+
672
+ class MultiTypeBase(_Multiple):
673
+ """Wrapper for an edge with multiple TypeBase objects."""
674
+
675
+ _T = TypeBase
676
+
677
+
678
+ _typemap['TypeBase'] = TypeBase
679
+
680
+ class Bit(TypeBase):
681
+ __slots__ = []
682
+
683
+ def __init__(
684
+ self,
685
+ size=None,
686
+ ):
687
+ super().__init__(size=size)
688
+
689
+ def __eq__(self, other):
690
+ """Equality operator. Ignores annotations!"""
691
+ if not isinstance(other, Bit):
692
+ return False
693
+ if self.size != other.size:
694
+ return False
695
+ return True
696
+
697
+ def dump(self, indent=0, annotations=None, links=1):
698
+ """Returns a debug representation of this tree as a multiline string.
699
+ indent is the number of double spaces prefixed before every line.
700
+ annotations, if specified, must be a set-like object containing the key
701
+ strings of the annotations that are to be printed. links specifies the
702
+ maximum link recursion depth."""
703
+ s = [' '*indent]
704
+ s.append('Bit(')
705
+ if annotations is None:
706
+ annotations = []
707
+ for key in annotations:
708
+ if key in self:
709
+ s.append(' # {}: {}'.format(key, self[key]))
710
+ s.append('\n')
711
+ indent += 1
712
+ s.append(' '*indent)
713
+ s.append('size: ')
714
+ s.append(str(self.size) + '\n')
715
+ indent -= 1
716
+ s.append(' '*indent)
717
+ s.append(')')
718
+ return ''.join(s)
719
+
720
+ __str__ = dump
721
+ __repr__ = dump
722
+
723
+ def find_reachable(self, id_map=None):
724
+ """Returns a dictionary mapping Python id() values to stable sequence
725
+ numbers for all nodes in the tree rooted at this node. If id_map is
726
+ specified, found nodes are appended to it."""
727
+ if id_map is None:
728
+ id_map = {}
729
+ if id(self) in id_map:
730
+ raise NotWellFormed('node {!r} with id {} occurs more than once'.format(self, id(self)))
731
+ id_map[id(self)] = len(id_map)
732
+ return id_map
733
+
734
+ def check_complete(self, id_map=None):
735
+ """Raises NotWellFormed if the tree rooted at this node is not
736
+ well-formed. If id_map is specified, this tree is only a subtree in the
737
+ context of a larger tree, and id_map must be a dict mapping from Python
738
+ id() codes to tree indices for all reachable nodes."""
739
+ if id_map is None:
740
+ id_map = self.find_reachable()
741
+
742
+ def copy(self):
743
+ """Returns a shallow copy of this node."""
744
+ return Bit(
745
+ size=self._attr_size
746
+ )
747
+
748
+ def clone(self):
749
+ """Returns a deep copy of this node. This mimics the C++ interface,
750
+ deficiencies with links included; that is, links always point to the
751
+ original tree. If you're not cloning a subtree in a context where this
752
+ is the desired behavior, you may want to use the copy.deepcopy() from
753
+ the stdlib instead, which should copy links correctly."""
754
+ return Bit(
755
+ size=_cloned(self._attr_size)
756
+ )
757
+
758
+ @staticmethod
759
+ def _deserialize(cbor, seq_to_ob, links):
760
+ """Attempts to deserialize the given cbor object (in Python primitive
761
+ representation) into a node of this type. All (sub)nodes are added to
762
+ the seq_to_ob dict, indexed by their cbor sequence number. All links are
763
+ registered in the links list by means of a two-tuple of the setter
764
+ function for the link field and the sequence number of the target node.
765
+ """
766
+ if not isinstance(cbor, dict):
767
+ raise TypeError('node description object must be a dict')
768
+ typ = cbor.get('@t', None)
769
+ if typ is None:
770
+ raise ValueError('type (@t) field is missing from node serialization')
771
+ if typ != 'Bit':
772
+ raise ValueError('found node serialization for ' + typ + ', but expected Bit')
773
+
774
+ # Deserialize the size field.
775
+ field = cbor.get('size', None)
776
+ if not isinstance(field, dict):
777
+ raise ValueError('missing or invalid serialization of field size')
778
+ if hasattr(cqasm.v3x.primitives.Int, 'deserialize_cbor'):
779
+ f_size = cqasm.v3x.primitives.Int.deserialize_cbor(field)
780
+ else:
781
+ f_size = cqasm.v3x.primitives.deserialize(cqasm.v3x.primitives.Int, field)
782
+
783
+ # Construct the Bit node.
784
+ node = Bit(f_size)
785
+
786
+ # Deserialize annotations.
787
+ for key, val in cbor.items():
788
+ if not (key.startswith('{') and key.endswith('}')):
789
+ continue
790
+ key = key[1:-1]
791
+ node[key] = cqasm.v3x.primitives.deserialize(key, val)
792
+
793
+ # Register node in sequence number lookup.
794
+ seq = cbor.get('@i', None)
795
+ if not isinstance(seq, int):
796
+ raise ValueError('sequence number field (@i) is not an integer or missing from node serialization')
797
+ if seq in seq_to_ob:
798
+ raise ValueError('duplicate sequence number %d' % seq)
799
+ seq_to_ob[seq] = node
800
+
801
+ return node
802
+
803
+ def _serialize(self, id_map):
804
+ """Serializes this node to the Python primitive representation of its
805
+ CBOR serialization. The tree that the node belongs to must be
806
+ well-formed. id_map must match Python id() calls for all nodes to unique
807
+ integers, to use for the sequence number representation of links."""
808
+ cbor = {'@i': id_map[id(self)], '@t': 'Bit'}
809
+
810
+ # Serialize the size field.
811
+ if hasattr(self._attr_size, 'serialize_cbor'):
812
+ cbor['size'] = self._attr_size.serialize_cbor()
813
+ else:
814
+ cbor['size'] = cqasm.v3x.primitives.serialize(cqasm.v3x.primitives.Int, self._attr_size)
815
+
816
+ # Serialize annotations.
817
+ for key, val in self._annot.items():
818
+ cbor['{%s}' % key] = _py_to_cbor(cqasm.v3x.primitives.serialize(key, val))
819
+
820
+ return cbor
821
+
822
+
823
+ class MultiBit(_Multiple):
824
+ """Wrapper for an edge with multiple Bit objects."""
825
+
826
+ _T = Bit
827
+
828
+
829
+ _typemap['Bit'] = Bit
830
+
831
+ class BitArray(TypeBase):
832
+ __slots__ = []
833
+
834
+ def __init__(
835
+ self,
836
+ size=None,
837
+ ):
838
+ super().__init__(size=size)
839
+
840
+ def __eq__(self, other):
841
+ """Equality operator. Ignores annotations!"""
842
+ if not isinstance(other, BitArray):
843
+ return False
844
+ if self.size != other.size:
845
+ return False
846
+ return True
847
+
848
+ def dump(self, indent=0, annotations=None, links=1):
849
+ """Returns a debug representation of this tree as a multiline string.
850
+ indent is the number of double spaces prefixed before every line.
851
+ annotations, if specified, must be a set-like object containing the key
852
+ strings of the annotations that are to be printed. links specifies the
853
+ maximum link recursion depth."""
854
+ s = [' '*indent]
855
+ s.append('BitArray(')
856
+ if annotations is None:
857
+ annotations = []
858
+ for key in annotations:
859
+ if key in self:
860
+ s.append(' # {}: {}'.format(key, self[key]))
861
+ s.append('\n')
862
+ indent += 1
863
+ s.append(' '*indent)
864
+ s.append('size: ')
865
+ s.append(str(self.size) + '\n')
866
+ indent -= 1
867
+ s.append(' '*indent)
868
+ s.append(')')
869
+ return ''.join(s)
870
+
871
+ __str__ = dump
872
+ __repr__ = dump
873
+
874
+ def find_reachable(self, id_map=None):
875
+ """Returns a dictionary mapping Python id() values to stable sequence
876
+ numbers for all nodes in the tree rooted at this node. If id_map is
877
+ specified, found nodes are appended to it."""
878
+ if id_map is None:
879
+ id_map = {}
880
+ if id(self) in id_map:
881
+ raise NotWellFormed('node {!r} with id {} occurs more than once'.format(self, id(self)))
882
+ id_map[id(self)] = len(id_map)
883
+ return id_map
884
+
885
+ def check_complete(self, id_map=None):
886
+ """Raises NotWellFormed if the tree rooted at this node is not
887
+ well-formed. If id_map is specified, this tree is only a subtree in the
888
+ context of a larger tree, and id_map must be a dict mapping from Python
889
+ id() codes to tree indices for all reachable nodes."""
890
+ if id_map is None:
891
+ id_map = self.find_reachable()
892
+
893
+ def copy(self):
894
+ """Returns a shallow copy of this node."""
895
+ return BitArray(
896
+ size=self._attr_size
897
+ )
898
+
899
+ def clone(self):
900
+ """Returns a deep copy of this node. This mimics the C++ interface,
901
+ deficiencies with links included; that is, links always point to the
902
+ original tree. If you're not cloning a subtree in a context where this
903
+ is the desired behavior, you may want to use the copy.deepcopy() from
904
+ the stdlib instead, which should copy links correctly."""
905
+ return BitArray(
906
+ size=_cloned(self._attr_size)
907
+ )
908
+
909
+ @staticmethod
910
+ def _deserialize(cbor, seq_to_ob, links):
911
+ """Attempts to deserialize the given cbor object (in Python primitive
912
+ representation) into a node of this type. All (sub)nodes are added to
913
+ the seq_to_ob dict, indexed by their cbor sequence number. All links are
914
+ registered in the links list by means of a two-tuple of the setter
915
+ function for the link field and the sequence number of the target node.
916
+ """
917
+ if not isinstance(cbor, dict):
918
+ raise TypeError('node description object must be a dict')
919
+ typ = cbor.get('@t', None)
920
+ if typ is None:
921
+ raise ValueError('type (@t) field is missing from node serialization')
922
+ if typ != 'BitArray':
923
+ raise ValueError('found node serialization for ' + typ + ', but expected BitArray')
924
+
925
+ # Deserialize the size field.
926
+ field = cbor.get('size', None)
927
+ if not isinstance(field, dict):
928
+ raise ValueError('missing or invalid serialization of field size')
929
+ if hasattr(cqasm.v3x.primitives.Int, 'deserialize_cbor'):
930
+ f_size = cqasm.v3x.primitives.Int.deserialize_cbor(field)
931
+ else:
932
+ f_size = cqasm.v3x.primitives.deserialize(cqasm.v3x.primitives.Int, field)
933
+
934
+ # Construct the BitArray node.
935
+ node = BitArray(f_size)
936
+
937
+ # Deserialize annotations.
938
+ for key, val in cbor.items():
939
+ if not (key.startswith('{') and key.endswith('}')):
940
+ continue
941
+ key = key[1:-1]
942
+ node[key] = cqasm.v3x.primitives.deserialize(key, val)
943
+
944
+ # Register node in sequence number lookup.
945
+ seq = cbor.get('@i', None)
946
+ if not isinstance(seq, int):
947
+ raise ValueError('sequence number field (@i) is not an integer or missing from node serialization')
948
+ if seq in seq_to_ob:
949
+ raise ValueError('duplicate sequence number %d' % seq)
950
+ seq_to_ob[seq] = node
951
+
952
+ return node
953
+
954
+ def _serialize(self, id_map):
955
+ """Serializes this node to the Python primitive representation of its
956
+ CBOR serialization. The tree that the node belongs to must be
957
+ well-formed. id_map must match Python id() calls for all nodes to unique
958
+ integers, to use for the sequence number representation of links."""
959
+ cbor = {'@i': id_map[id(self)], '@t': 'BitArray'}
960
+
961
+ # Serialize the size field.
962
+ if hasattr(self._attr_size, 'serialize_cbor'):
963
+ cbor['size'] = self._attr_size.serialize_cbor()
964
+ else:
965
+ cbor['size'] = cqasm.v3x.primitives.serialize(cqasm.v3x.primitives.Int, self._attr_size)
966
+
967
+ # Serialize annotations.
968
+ for key, val in self._annot.items():
969
+ cbor['{%s}' % key] = _py_to_cbor(cqasm.v3x.primitives.serialize(key, val))
970
+
971
+ return cbor
972
+
973
+
974
+ class MultiBitArray(_Multiple):
975
+ """Wrapper for an edge with multiple BitArray objects."""
976
+
977
+ _T = BitArray
978
+
979
+
980
+ _typemap['BitArray'] = BitArray
981
+
982
+ class Bool(TypeBase):
983
+ """Type of a boolean."""
984
+
985
+ __slots__ = []
986
+
987
+ def __init__(
988
+ self,
989
+ size=None,
990
+ ):
991
+ super().__init__(size=size)
992
+
993
+ def __eq__(self, other):
994
+ """Equality operator. Ignores annotations!"""
995
+ if not isinstance(other, Bool):
996
+ return False
997
+ if self.size != other.size:
998
+ return False
999
+ return True
1000
+
1001
+ def dump(self, indent=0, annotations=None, links=1):
1002
+ """Returns a debug representation of this tree as a multiline string.
1003
+ indent is the number of double spaces prefixed before every line.
1004
+ annotations, if specified, must be a set-like object containing the key
1005
+ strings of the annotations that are to be printed. links specifies the
1006
+ maximum link recursion depth."""
1007
+ s = [' '*indent]
1008
+ s.append('Bool(')
1009
+ if annotations is None:
1010
+ annotations = []
1011
+ for key in annotations:
1012
+ if key in self:
1013
+ s.append(' # {}: {}'.format(key, self[key]))
1014
+ s.append('\n')
1015
+ indent += 1
1016
+ s.append(' '*indent)
1017
+ s.append('size: ')
1018
+ s.append(str(self.size) + '\n')
1019
+ indent -= 1
1020
+ s.append(' '*indent)
1021
+ s.append(')')
1022
+ return ''.join(s)
1023
+
1024
+ __str__ = dump
1025
+ __repr__ = dump
1026
+
1027
+ def find_reachable(self, id_map=None):
1028
+ """Returns a dictionary mapping Python id() values to stable sequence
1029
+ numbers for all nodes in the tree rooted at this node. If id_map is
1030
+ specified, found nodes are appended to it."""
1031
+ if id_map is None:
1032
+ id_map = {}
1033
+ if id(self) in id_map:
1034
+ raise NotWellFormed('node {!r} with id {} occurs more than once'.format(self, id(self)))
1035
+ id_map[id(self)] = len(id_map)
1036
+ return id_map
1037
+
1038
+ def check_complete(self, id_map=None):
1039
+ """Raises NotWellFormed if the tree rooted at this node is not
1040
+ well-formed. If id_map is specified, this tree is only a subtree in the
1041
+ context of a larger tree, and id_map must be a dict mapping from Python
1042
+ id() codes to tree indices for all reachable nodes."""
1043
+ if id_map is None:
1044
+ id_map = self.find_reachable()
1045
+
1046
+ def copy(self):
1047
+ """Returns a shallow copy of this node."""
1048
+ return Bool(
1049
+ size=self._attr_size
1050
+ )
1051
+
1052
+ def clone(self):
1053
+ """Returns a deep copy of this node. This mimics the C++ interface,
1054
+ deficiencies with links included; that is, links always point to the
1055
+ original tree. If you're not cloning a subtree in a context where this
1056
+ is the desired behavior, you may want to use the copy.deepcopy() from
1057
+ the stdlib instead, which should copy links correctly."""
1058
+ return Bool(
1059
+ size=_cloned(self._attr_size)
1060
+ )
1061
+
1062
+ @staticmethod
1063
+ def _deserialize(cbor, seq_to_ob, links):
1064
+ """Attempts to deserialize the given cbor object (in Python primitive
1065
+ representation) into a node of this type. All (sub)nodes are added to
1066
+ the seq_to_ob dict, indexed by their cbor sequence number. All links are
1067
+ registered in the links list by means of a two-tuple of the setter
1068
+ function for the link field and the sequence number of the target node.
1069
+ """
1070
+ if not isinstance(cbor, dict):
1071
+ raise TypeError('node description object must be a dict')
1072
+ typ = cbor.get('@t', None)
1073
+ if typ is None:
1074
+ raise ValueError('type (@t) field is missing from node serialization')
1075
+ if typ != 'Bool':
1076
+ raise ValueError('found node serialization for ' + typ + ', but expected Bool')
1077
+
1078
+ # Deserialize the size field.
1079
+ field = cbor.get('size', None)
1080
+ if not isinstance(field, dict):
1081
+ raise ValueError('missing or invalid serialization of field size')
1082
+ if hasattr(cqasm.v3x.primitives.Int, 'deserialize_cbor'):
1083
+ f_size = cqasm.v3x.primitives.Int.deserialize_cbor(field)
1084
+ else:
1085
+ f_size = cqasm.v3x.primitives.deserialize(cqasm.v3x.primitives.Int, field)
1086
+
1087
+ # Construct the Bool node.
1088
+ node = Bool(f_size)
1089
+
1090
+ # Deserialize annotations.
1091
+ for key, val in cbor.items():
1092
+ if not (key.startswith('{') and key.endswith('}')):
1093
+ continue
1094
+ key = key[1:-1]
1095
+ node[key] = cqasm.v3x.primitives.deserialize(key, val)
1096
+
1097
+ # Register node in sequence number lookup.
1098
+ seq = cbor.get('@i', None)
1099
+ if not isinstance(seq, int):
1100
+ raise ValueError('sequence number field (@i) is not an integer or missing from node serialization')
1101
+ if seq in seq_to_ob:
1102
+ raise ValueError('duplicate sequence number %d' % seq)
1103
+ seq_to_ob[seq] = node
1104
+
1105
+ return node
1106
+
1107
+ def _serialize(self, id_map):
1108
+ """Serializes this node to the Python primitive representation of its
1109
+ CBOR serialization. The tree that the node belongs to must be
1110
+ well-formed. id_map must match Python id() calls for all nodes to unique
1111
+ integers, to use for the sequence number representation of links."""
1112
+ cbor = {'@i': id_map[id(self)], '@t': 'Bool'}
1113
+
1114
+ # Serialize the size field.
1115
+ if hasattr(self._attr_size, 'serialize_cbor'):
1116
+ cbor['size'] = self._attr_size.serialize_cbor()
1117
+ else:
1118
+ cbor['size'] = cqasm.v3x.primitives.serialize(cqasm.v3x.primitives.Int, self._attr_size)
1119
+
1120
+ # Serialize annotations.
1121
+ for key, val in self._annot.items():
1122
+ cbor['{%s}' % key] = _py_to_cbor(cqasm.v3x.primitives.serialize(key, val))
1123
+
1124
+ return cbor
1125
+
1126
+
1127
+ class MultiBool(_Multiple):
1128
+ """Wrapper for an edge with multiple Bool objects."""
1129
+
1130
+ _T = Bool
1131
+
1132
+
1133
+ _typemap['Bool'] = Bool
1134
+
1135
+ class Float(TypeBase):
1136
+ """Type of a float number (IEEE double)."""
1137
+
1138
+ __slots__ = []
1139
+
1140
+ def __init__(
1141
+ self,
1142
+ size=None,
1143
+ ):
1144
+ super().__init__(size=size)
1145
+
1146
+ def __eq__(self, other):
1147
+ """Equality operator. Ignores annotations!"""
1148
+ if not isinstance(other, Float):
1149
+ return False
1150
+ if self.size != other.size:
1151
+ return False
1152
+ return True
1153
+
1154
+ def dump(self, indent=0, annotations=None, links=1):
1155
+ """Returns a debug representation of this tree as a multiline string.
1156
+ indent is the number of double spaces prefixed before every line.
1157
+ annotations, if specified, must be a set-like object containing the key
1158
+ strings of the annotations that are to be printed. links specifies the
1159
+ maximum link recursion depth."""
1160
+ s = [' '*indent]
1161
+ s.append('Float(')
1162
+ if annotations is None:
1163
+ annotations = []
1164
+ for key in annotations:
1165
+ if key in self:
1166
+ s.append(' # {}: {}'.format(key, self[key]))
1167
+ s.append('\n')
1168
+ indent += 1
1169
+ s.append(' '*indent)
1170
+ s.append('size: ')
1171
+ s.append(str(self.size) + '\n')
1172
+ indent -= 1
1173
+ s.append(' '*indent)
1174
+ s.append(')')
1175
+ return ''.join(s)
1176
+
1177
+ __str__ = dump
1178
+ __repr__ = dump
1179
+
1180
+ def find_reachable(self, id_map=None):
1181
+ """Returns a dictionary mapping Python id() values to stable sequence
1182
+ numbers for all nodes in the tree rooted at this node. If id_map is
1183
+ specified, found nodes are appended to it."""
1184
+ if id_map is None:
1185
+ id_map = {}
1186
+ if id(self) in id_map:
1187
+ raise NotWellFormed('node {!r} with id {} occurs more than once'.format(self, id(self)))
1188
+ id_map[id(self)] = len(id_map)
1189
+ return id_map
1190
+
1191
+ def check_complete(self, id_map=None):
1192
+ """Raises NotWellFormed if the tree rooted at this node is not
1193
+ well-formed. If id_map is specified, this tree is only a subtree in the
1194
+ context of a larger tree, and id_map must be a dict mapping from Python
1195
+ id() codes to tree indices for all reachable nodes."""
1196
+ if id_map is None:
1197
+ id_map = self.find_reachable()
1198
+
1199
+ def copy(self):
1200
+ """Returns a shallow copy of this node."""
1201
+ return Float(
1202
+ size=self._attr_size
1203
+ )
1204
+
1205
+ def clone(self):
1206
+ """Returns a deep copy of this node. This mimics the C++ interface,
1207
+ deficiencies with links included; that is, links always point to the
1208
+ original tree. If you're not cloning a subtree in a context where this
1209
+ is the desired behavior, you may want to use the copy.deepcopy() from
1210
+ the stdlib instead, which should copy links correctly."""
1211
+ return Float(
1212
+ size=_cloned(self._attr_size)
1213
+ )
1214
+
1215
+ @staticmethod
1216
+ def _deserialize(cbor, seq_to_ob, links):
1217
+ """Attempts to deserialize the given cbor object (in Python primitive
1218
+ representation) into a node of this type. All (sub)nodes are added to
1219
+ the seq_to_ob dict, indexed by their cbor sequence number. All links are
1220
+ registered in the links list by means of a two-tuple of the setter
1221
+ function for the link field and the sequence number of the target node.
1222
+ """
1223
+ if not isinstance(cbor, dict):
1224
+ raise TypeError('node description object must be a dict')
1225
+ typ = cbor.get('@t', None)
1226
+ if typ is None:
1227
+ raise ValueError('type (@t) field is missing from node serialization')
1228
+ if typ != 'Float':
1229
+ raise ValueError('found node serialization for ' + typ + ', but expected Float')
1230
+
1231
+ # Deserialize the size field.
1232
+ field = cbor.get('size', None)
1233
+ if not isinstance(field, dict):
1234
+ raise ValueError('missing or invalid serialization of field size')
1235
+ if hasattr(cqasm.v3x.primitives.Int, 'deserialize_cbor'):
1236
+ f_size = cqasm.v3x.primitives.Int.deserialize_cbor(field)
1237
+ else:
1238
+ f_size = cqasm.v3x.primitives.deserialize(cqasm.v3x.primitives.Int, field)
1239
+
1240
+ # Construct the Float node.
1241
+ node = Float(f_size)
1242
+
1243
+ # Deserialize annotations.
1244
+ for key, val in cbor.items():
1245
+ if not (key.startswith('{') and key.endswith('}')):
1246
+ continue
1247
+ key = key[1:-1]
1248
+ node[key] = cqasm.v3x.primitives.deserialize(key, val)
1249
+
1250
+ # Register node in sequence number lookup.
1251
+ seq = cbor.get('@i', None)
1252
+ if not isinstance(seq, int):
1253
+ raise ValueError('sequence number field (@i) is not an integer or missing from node serialization')
1254
+ if seq in seq_to_ob:
1255
+ raise ValueError('duplicate sequence number %d' % seq)
1256
+ seq_to_ob[seq] = node
1257
+
1258
+ return node
1259
+
1260
+ def _serialize(self, id_map):
1261
+ """Serializes this node to the Python primitive representation of its
1262
+ CBOR serialization. The tree that the node belongs to must be
1263
+ well-formed. id_map must match Python id() calls for all nodes to unique
1264
+ integers, to use for the sequence number representation of links."""
1265
+ cbor = {'@i': id_map[id(self)], '@t': 'Float'}
1266
+
1267
+ # Serialize the size field.
1268
+ if hasattr(self._attr_size, 'serialize_cbor'):
1269
+ cbor['size'] = self._attr_size.serialize_cbor()
1270
+ else:
1271
+ cbor['size'] = cqasm.v3x.primitives.serialize(cqasm.v3x.primitives.Int, self._attr_size)
1272
+
1273
+ # Serialize annotations.
1274
+ for key, val in self._annot.items():
1275
+ cbor['{%s}' % key] = _py_to_cbor(cqasm.v3x.primitives.serialize(key, val))
1276
+
1277
+ return cbor
1278
+
1279
+
1280
+ class MultiFloat(_Multiple):
1281
+ """Wrapper for an edge with multiple Float objects."""
1282
+
1283
+ _T = Float
1284
+
1285
+
1286
+ _typemap['Float'] = Float
1287
+
1288
+ class Int(TypeBase):
1289
+ """Type of an integer (signed 64-bit)."""
1290
+
1291
+ __slots__ = []
1292
+
1293
+ def __init__(
1294
+ self,
1295
+ size=None,
1296
+ ):
1297
+ super().__init__(size=size)
1298
+
1299
+ def __eq__(self, other):
1300
+ """Equality operator. Ignores annotations!"""
1301
+ if not isinstance(other, Int):
1302
+ return False
1303
+ if self.size != other.size:
1304
+ return False
1305
+ return True
1306
+
1307
+ def dump(self, indent=0, annotations=None, links=1):
1308
+ """Returns a debug representation of this tree as a multiline string.
1309
+ indent is the number of double spaces prefixed before every line.
1310
+ annotations, if specified, must be a set-like object containing the key
1311
+ strings of the annotations that are to be printed. links specifies the
1312
+ maximum link recursion depth."""
1313
+ s = [' '*indent]
1314
+ s.append('Int(')
1315
+ if annotations is None:
1316
+ annotations = []
1317
+ for key in annotations:
1318
+ if key in self:
1319
+ s.append(' # {}: {}'.format(key, self[key]))
1320
+ s.append('\n')
1321
+ indent += 1
1322
+ s.append(' '*indent)
1323
+ s.append('size: ')
1324
+ s.append(str(self.size) + '\n')
1325
+ indent -= 1
1326
+ s.append(' '*indent)
1327
+ s.append(')')
1328
+ return ''.join(s)
1329
+
1330
+ __str__ = dump
1331
+ __repr__ = dump
1332
+
1333
+ def find_reachable(self, id_map=None):
1334
+ """Returns a dictionary mapping Python id() values to stable sequence
1335
+ numbers for all nodes in the tree rooted at this node. If id_map is
1336
+ specified, found nodes are appended to it."""
1337
+ if id_map is None:
1338
+ id_map = {}
1339
+ if id(self) in id_map:
1340
+ raise NotWellFormed('node {!r} with id {} occurs more than once'.format(self, id(self)))
1341
+ id_map[id(self)] = len(id_map)
1342
+ return id_map
1343
+
1344
+ def check_complete(self, id_map=None):
1345
+ """Raises NotWellFormed if the tree rooted at this node is not
1346
+ well-formed. If id_map is specified, this tree is only a subtree in the
1347
+ context of a larger tree, and id_map must be a dict mapping from Python
1348
+ id() codes to tree indices for all reachable nodes."""
1349
+ if id_map is None:
1350
+ id_map = self.find_reachable()
1351
+
1352
+ def copy(self):
1353
+ """Returns a shallow copy of this node."""
1354
+ return Int(
1355
+ size=self._attr_size
1356
+ )
1357
+
1358
+ def clone(self):
1359
+ """Returns a deep copy of this node. This mimics the C++ interface,
1360
+ deficiencies with links included; that is, links always point to the
1361
+ original tree. If you're not cloning a subtree in a context where this
1362
+ is the desired behavior, you may want to use the copy.deepcopy() from
1363
+ the stdlib instead, which should copy links correctly."""
1364
+ return Int(
1365
+ size=_cloned(self._attr_size)
1366
+ )
1367
+
1368
+ @staticmethod
1369
+ def _deserialize(cbor, seq_to_ob, links):
1370
+ """Attempts to deserialize the given cbor object (in Python primitive
1371
+ representation) into a node of this type. All (sub)nodes are added to
1372
+ the seq_to_ob dict, indexed by their cbor sequence number. All links are
1373
+ registered in the links list by means of a two-tuple of the setter
1374
+ function for the link field and the sequence number of the target node.
1375
+ """
1376
+ if not isinstance(cbor, dict):
1377
+ raise TypeError('node description object must be a dict')
1378
+ typ = cbor.get('@t', None)
1379
+ if typ is None:
1380
+ raise ValueError('type (@t) field is missing from node serialization')
1381
+ if typ != 'Int':
1382
+ raise ValueError('found node serialization for ' + typ + ', but expected Int')
1383
+
1384
+ # Deserialize the size field.
1385
+ field = cbor.get('size', None)
1386
+ if not isinstance(field, dict):
1387
+ raise ValueError('missing or invalid serialization of field size')
1388
+ if hasattr(cqasm.v3x.primitives.Int, 'deserialize_cbor'):
1389
+ f_size = cqasm.v3x.primitives.Int.deserialize_cbor(field)
1390
+ else:
1391
+ f_size = cqasm.v3x.primitives.deserialize(cqasm.v3x.primitives.Int, field)
1392
+
1393
+ # Construct the Int node.
1394
+ node = Int(f_size)
1395
+
1396
+ # Deserialize annotations.
1397
+ for key, val in cbor.items():
1398
+ if not (key.startswith('{') and key.endswith('}')):
1399
+ continue
1400
+ key = key[1:-1]
1401
+ node[key] = cqasm.v3x.primitives.deserialize(key, val)
1402
+
1403
+ # Register node in sequence number lookup.
1404
+ seq = cbor.get('@i', None)
1405
+ if not isinstance(seq, int):
1406
+ raise ValueError('sequence number field (@i) is not an integer or missing from node serialization')
1407
+ if seq in seq_to_ob:
1408
+ raise ValueError('duplicate sequence number %d' % seq)
1409
+ seq_to_ob[seq] = node
1410
+
1411
+ return node
1412
+
1413
+ def _serialize(self, id_map):
1414
+ """Serializes this node to the Python primitive representation of its
1415
+ CBOR serialization. The tree that the node belongs to must be
1416
+ well-formed. id_map must match Python id() calls for all nodes to unique
1417
+ integers, to use for the sequence number representation of links."""
1418
+ cbor = {'@i': id_map[id(self)], '@t': 'Int'}
1419
+
1420
+ # Serialize the size field.
1421
+ if hasattr(self._attr_size, 'serialize_cbor'):
1422
+ cbor['size'] = self._attr_size.serialize_cbor()
1423
+ else:
1424
+ cbor['size'] = cqasm.v3x.primitives.serialize(cqasm.v3x.primitives.Int, self._attr_size)
1425
+
1426
+ # Serialize annotations.
1427
+ for key, val in self._annot.items():
1428
+ cbor['{%s}' % key] = _py_to_cbor(cqasm.v3x.primitives.serialize(key, val))
1429
+
1430
+ return cbor
1431
+
1432
+
1433
+ class MultiInt(_Multiple):
1434
+ """Wrapper for an edge with multiple Int objects."""
1435
+
1436
+ _T = Int
1437
+
1438
+
1439
+ _typemap['Int'] = Int
1440
+
1441
+ class Qubit(TypeBase):
1442
+ __slots__ = []
1443
+
1444
+ def __init__(
1445
+ self,
1446
+ size=None,
1447
+ ):
1448
+ super().__init__(size=size)
1449
+
1450
+ def __eq__(self, other):
1451
+ """Equality operator. Ignores annotations!"""
1452
+ if not isinstance(other, Qubit):
1453
+ return False
1454
+ if self.size != other.size:
1455
+ return False
1456
+ return True
1457
+
1458
+ def dump(self, indent=0, annotations=None, links=1):
1459
+ """Returns a debug representation of this tree as a multiline string.
1460
+ indent is the number of double spaces prefixed before every line.
1461
+ annotations, if specified, must be a set-like object containing the key
1462
+ strings of the annotations that are to be printed. links specifies the
1463
+ maximum link recursion depth."""
1464
+ s = [' '*indent]
1465
+ s.append('Qubit(')
1466
+ if annotations is None:
1467
+ annotations = []
1468
+ for key in annotations:
1469
+ if key in self:
1470
+ s.append(' # {}: {}'.format(key, self[key]))
1471
+ s.append('\n')
1472
+ indent += 1
1473
+ s.append(' '*indent)
1474
+ s.append('size: ')
1475
+ s.append(str(self.size) + '\n')
1476
+ indent -= 1
1477
+ s.append(' '*indent)
1478
+ s.append(')')
1479
+ return ''.join(s)
1480
+
1481
+ __str__ = dump
1482
+ __repr__ = dump
1483
+
1484
+ def find_reachable(self, id_map=None):
1485
+ """Returns a dictionary mapping Python id() values to stable sequence
1486
+ numbers for all nodes in the tree rooted at this node. If id_map is
1487
+ specified, found nodes are appended to it."""
1488
+ if id_map is None:
1489
+ id_map = {}
1490
+ if id(self) in id_map:
1491
+ raise NotWellFormed('node {!r} with id {} occurs more than once'.format(self, id(self)))
1492
+ id_map[id(self)] = len(id_map)
1493
+ return id_map
1494
+
1495
+ def check_complete(self, id_map=None):
1496
+ """Raises NotWellFormed if the tree rooted at this node is not
1497
+ well-formed. If id_map is specified, this tree is only a subtree in the
1498
+ context of a larger tree, and id_map must be a dict mapping from Python
1499
+ id() codes to tree indices for all reachable nodes."""
1500
+ if id_map is None:
1501
+ id_map = self.find_reachable()
1502
+
1503
+ def copy(self):
1504
+ """Returns a shallow copy of this node."""
1505
+ return Qubit(
1506
+ size=self._attr_size
1507
+ )
1508
+
1509
+ def clone(self):
1510
+ """Returns a deep copy of this node. This mimics the C++ interface,
1511
+ deficiencies with links included; that is, links always point to the
1512
+ original tree. If you're not cloning a subtree in a context where this
1513
+ is the desired behavior, you may want to use the copy.deepcopy() from
1514
+ the stdlib instead, which should copy links correctly."""
1515
+ return Qubit(
1516
+ size=_cloned(self._attr_size)
1517
+ )
1518
+
1519
+ @staticmethod
1520
+ def _deserialize(cbor, seq_to_ob, links):
1521
+ """Attempts to deserialize the given cbor object (in Python primitive
1522
+ representation) into a node of this type. All (sub)nodes are added to
1523
+ the seq_to_ob dict, indexed by their cbor sequence number. All links are
1524
+ registered in the links list by means of a two-tuple of the setter
1525
+ function for the link field and the sequence number of the target node.
1526
+ """
1527
+ if not isinstance(cbor, dict):
1528
+ raise TypeError('node description object must be a dict')
1529
+ typ = cbor.get('@t', None)
1530
+ if typ is None:
1531
+ raise ValueError('type (@t) field is missing from node serialization')
1532
+ if typ != 'Qubit':
1533
+ raise ValueError('found node serialization for ' + typ + ', but expected Qubit')
1534
+
1535
+ # Deserialize the size field.
1536
+ field = cbor.get('size', None)
1537
+ if not isinstance(field, dict):
1538
+ raise ValueError('missing or invalid serialization of field size')
1539
+ if hasattr(cqasm.v3x.primitives.Int, 'deserialize_cbor'):
1540
+ f_size = cqasm.v3x.primitives.Int.deserialize_cbor(field)
1541
+ else:
1542
+ f_size = cqasm.v3x.primitives.deserialize(cqasm.v3x.primitives.Int, field)
1543
+
1544
+ # Construct the Qubit node.
1545
+ node = Qubit(f_size)
1546
+
1547
+ # Deserialize annotations.
1548
+ for key, val in cbor.items():
1549
+ if not (key.startswith('{') and key.endswith('}')):
1550
+ continue
1551
+ key = key[1:-1]
1552
+ node[key] = cqasm.v3x.primitives.deserialize(key, val)
1553
+
1554
+ # Register node in sequence number lookup.
1555
+ seq = cbor.get('@i', None)
1556
+ if not isinstance(seq, int):
1557
+ raise ValueError('sequence number field (@i) is not an integer or missing from node serialization')
1558
+ if seq in seq_to_ob:
1559
+ raise ValueError('duplicate sequence number %d' % seq)
1560
+ seq_to_ob[seq] = node
1561
+
1562
+ return node
1563
+
1564
+ def _serialize(self, id_map):
1565
+ """Serializes this node to the Python primitive representation of its
1566
+ CBOR serialization. The tree that the node belongs to must be
1567
+ well-formed. id_map must match Python id() calls for all nodes to unique
1568
+ integers, to use for the sequence number representation of links."""
1569
+ cbor = {'@i': id_map[id(self)], '@t': 'Qubit'}
1570
+
1571
+ # Serialize the size field.
1572
+ if hasattr(self._attr_size, 'serialize_cbor'):
1573
+ cbor['size'] = self._attr_size.serialize_cbor()
1574
+ else:
1575
+ cbor['size'] = cqasm.v3x.primitives.serialize(cqasm.v3x.primitives.Int, self._attr_size)
1576
+
1577
+ # Serialize annotations.
1578
+ for key, val in self._annot.items():
1579
+ cbor['{%s}' % key] = _py_to_cbor(cqasm.v3x.primitives.serialize(key, val))
1580
+
1581
+ return cbor
1582
+
1583
+
1584
+ class MultiQubit(_Multiple):
1585
+ """Wrapper for an edge with multiple Qubit objects."""
1586
+
1587
+ _T = Qubit
1588
+
1589
+
1590
+ _typemap['Qubit'] = Qubit
1591
+
1592
+ class QubitArray(TypeBase):
1593
+ __slots__ = []
1594
+
1595
+ def __init__(
1596
+ self,
1597
+ size=None,
1598
+ ):
1599
+ super().__init__(size=size)
1600
+
1601
+ def __eq__(self, other):
1602
+ """Equality operator. Ignores annotations!"""
1603
+ if not isinstance(other, QubitArray):
1604
+ return False
1605
+ if self.size != other.size:
1606
+ return False
1607
+ return True
1608
+
1609
+ def dump(self, indent=0, annotations=None, links=1):
1610
+ """Returns a debug representation of this tree as a multiline string.
1611
+ indent is the number of double spaces prefixed before every line.
1612
+ annotations, if specified, must be a set-like object containing the key
1613
+ strings of the annotations that are to be printed. links specifies the
1614
+ maximum link recursion depth."""
1615
+ s = [' '*indent]
1616
+ s.append('QubitArray(')
1617
+ if annotations is None:
1618
+ annotations = []
1619
+ for key in annotations:
1620
+ if key in self:
1621
+ s.append(' # {}: {}'.format(key, self[key]))
1622
+ s.append('\n')
1623
+ indent += 1
1624
+ s.append(' '*indent)
1625
+ s.append('size: ')
1626
+ s.append(str(self.size) + '\n')
1627
+ indent -= 1
1628
+ s.append(' '*indent)
1629
+ s.append(')')
1630
+ return ''.join(s)
1631
+
1632
+ __str__ = dump
1633
+ __repr__ = dump
1634
+
1635
+ def find_reachable(self, id_map=None):
1636
+ """Returns a dictionary mapping Python id() values to stable sequence
1637
+ numbers for all nodes in the tree rooted at this node. If id_map is
1638
+ specified, found nodes are appended to it."""
1639
+ if id_map is None:
1640
+ id_map = {}
1641
+ if id(self) in id_map:
1642
+ raise NotWellFormed('node {!r} with id {} occurs more than once'.format(self, id(self)))
1643
+ id_map[id(self)] = len(id_map)
1644
+ return id_map
1645
+
1646
+ def check_complete(self, id_map=None):
1647
+ """Raises NotWellFormed if the tree rooted at this node is not
1648
+ well-formed. If id_map is specified, this tree is only a subtree in the
1649
+ context of a larger tree, and id_map must be a dict mapping from Python
1650
+ id() codes to tree indices for all reachable nodes."""
1651
+ if id_map is None:
1652
+ id_map = self.find_reachable()
1653
+
1654
+ def copy(self):
1655
+ """Returns a shallow copy of this node."""
1656
+ return QubitArray(
1657
+ size=self._attr_size
1658
+ )
1659
+
1660
+ def clone(self):
1661
+ """Returns a deep copy of this node. This mimics the C++ interface,
1662
+ deficiencies with links included; that is, links always point to the
1663
+ original tree. If you're not cloning a subtree in a context where this
1664
+ is the desired behavior, you may want to use the copy.deepcopy() from
1665
+ the stdlib instead, which should copy links correctly."""
1666
+ return QubitArray(
1667
+ size=_cloned(self._attr_size)
1668
+ )
1669
+
1670
+ @staticmethod
1671
+ def _deserialize(cbor, seq_to_ob, links):
1672
+ """Attempts to deserialize the given cbor object (in Python primitive
1673
+ representation) into a node of this type. All (sub)nodes are added to
1674
+ the seq_to_ob dict, indexed by their cbor sequence number. All links are
1675
+ registered in the links list by means of a two-tuple of the setter
1676
+ function for the link field and the sequence number of the target node.
1677
+ """
1678
+ if not isinstance(cbor, dict):
1679
+ raise TypeError('node description object must be a dict')
1680
+ typ = cbor.get('@t', None)
1681
+ if typ is None:
1682
+ raise ValueError('type (@t) field is missing from node serialization')
1683
+ if typ != 'QubitArray':
1684
+ raise ValueError('found node serialization for ' + typ + ', but expected QubitArray')
1685
+
1686
+ # Deserialize the size field.
1687
+ field = cbor.get('size', None)
1688
+ if not isinstance(field, dict):
1689
+ raise ValueError('missing or invalid serialization of field size')
1690
+ if hasattr(cqasm.v3x.primitives.Int, 'deserialize_cbor'):
1691
+ f_size = cqasm.v3x.primitives.Int.deserialize_cbor(field)
1692
+ else:
1693
+ f_size = cqasm.v3x.primitives.deserialize(cqasm.v3x.primitives.Int, field)
1694
+
1695
+ # Construct the QubitArray node.
1696
+ node = QubitArray(f_size)
1697
+
1698
+ # Deserialize annotations.
1699
+ for key, val in cbor.items():
1700
+ if not (key.startswith('{') and key.endswith('}')):
1701
+ continue
1702
+ key = key[1:-1]
1703
+ node[key] = cqasm.v3x.primitives.deserialize(key, val)
1704
+
1705
+ # Register node in sequence number lookup.
1706
+ seq = cbor.get('@i', None)
1707
+ if not isinstance(seq, int):
1708
+ raise ValueError('sequence number field (@i) is not an integer or missing from node serialization')
1709
+ if seq in seq_to_ob:
1710
+ raise ValueError('duplicate sequence number %d' % seq)
1711
+ seq_to_ob[seq] = node
1712
+
1713
+ return node
1714
+
1715
+ def _serialize(self, id_map):
1716
+ """Serializes this node to the Python primitive representation of its
1717
+ CBOR serialization. The tree that the node belongs to must be
1718
+ well-formed. id_map must match Python id() calls for all nodes to unique
1719
+ integers, to use for the sequence number representation of links."""
1720
+ cbor = {'@i': id_map[id(self)], '@t': 'QubitArray'}
1721
+
1722
+ # Serialize the size field.
1723
+ if hasattr(self._attr_size, 'serialize_cbor'):
1724
+ cbor['size'] = self._attr_size.serialize_cbor()
1725
+ else:
1726
+ cbor['size'] = cqasm.v3x.primitives.serialize(cqasm.v3x.primitives.Int, self._attr_size)
1727
+
1728
+ # Serialize annotations.
1729
+ for key, val in self._annot.items():
1730
+ cbor['{%s}' % key] = _py_to_cbor(cqasm.v3x.primitives.serialize(key, val))
1731
+
1732
+ return cbor
1733
+
1734
+
1735
+ class MultiQubitArray(_Multiple):
1736
+ """Wrapper for an edge with multiple QubitArray objects."""
1737
+
1738
+ _T = QubitArray
1739
+
1740
+
1741
+ _typemap['QubitArray'] = QubitArray
1742
+