lean-python 0.1.0__py3-none-any.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.
lean_python/runtime.py ADDED
@@ -0,0 +1,1400 @@
1
+ """Runtime of the Python code generated by lean-python.
2
+
3
+ The functions named ``lean_*`` (and the libm names) are the C names of Lean's externs and
4
+ follow ``lean.h``: arguments marked borrowed there are not consumed, results are owned.
5
+
6
+ Values:
7
+
8
+ - ``Nat``, ``Int``, boxed scalars and fixed-width integers are ``int``; ``Float`` and
9
+ ``Float32`` are ``float``; ``String`` is ``bytes`` holding UTF-8.
10
+ - A constructor without fields is its tag (an ``int``); other constructors are ``Ctor``.
11
+ - ``Array``, ``ByteArray`` and ``FloatArray`` are ``LArray``, ``LByteArray``, ``LFloatArray``.
12
+ - ``Ctor`` and the arrays carry a reference count ``rc``, maintained by the ``inc``/``dec``
13
+ instructions of the IR, so updates of uniquely referenced values happen in place as in C.
14
+ Closures, thunks, tasks and references do not carry one: values read out of them are
15
+ always counted as shared.
16
+ """
17
+
18
+ import importlib
19
+ import math
20
+ import struct
21
+ import sys
22
+
23
+ PERSISTENT = 1 << 62
24
+
25
+ sys.setrecursionlimit(1_000_000)
26
+
27
+
28
+ class Ctor:
29
+ __slots__ = ("objs", "rc", "sc", "tag")
30
+
31
+ def __init__(self, tag, objs):
32
+ self.tag = tag
33
+ self.rc = 1
34
+ self.objs = objs
35
+ self.sc = {}
36
+
37
+ def __repr__(self):
38
+ return f"Ctor({self.tag}, {self.objs!r}, {self.sc!r})"
39
+
40
+
41
+ class LArray:
42
+ __slots__ = ("data", "rc")
43
+
44
+ def __init__(self, data):
45
+ self.rc = 1
46
+ self.data = data
47
+
48
+ def __repr__(self):
49
+ return f"LArray({self.data!r})"
50
+
51
+
52
+ class LByteArray:
53
+ __slots__ = ("data", "rc")
54
+
55
+ def __init__(self, data):
56
+ self.rc = 1
57
+ self.data = data
58
+
59
+
60
+ class LFloatArray:
61
+ __slots__ = ("data", "rc")
62
+
63
+ def __init__(self, data):
64
+ self.rc = 1
65
+ self.data = data
66
+
67
+
68
+ class Closure:
69
+ __slots__ = ("arity", "fixed", "fn")
70
+
71
+ def __init__(self, fn, arity, fixed):
72
+ self.fn = fn
73
+ self.arity = arity
74
+ self.fixed = fixed
75
+
76
+
77
+ class Thunk:
78
+ __slots__ = ("done", "fn", "value")
79
+
80
+ def __init__(self, fn, value=None, done=False):
81
+ self.fn = fn
82
+ self.value = value
83
+ self.done = done
84
+
85
+
86
+ class Task:
87
+ __slots__ = ("value",)
88
+
89
+ def __init__(self, value):
90
+ self.value = value
91
+
92
+
93
+ class Ref:
94
+ __slots__ = ("value",)
95
+
96
+ def __init__(self, value):
97
+ self.value = value
98
+
99
+
100
+ _RC = (Ctor, LArray, LByteArray, LFloatArray)
101
+
102
+ # Classes of external objects with a reference count, and what to do when it reaches 0.
103
+ _FINALIZERS = {}
104
+
105
+
106
+ def register_external(cls, finalize):
107
+ global _RC
108
+ _RC = (*_RC, cls)
109
+ _FINALIZERS[cls] = finalize
110
+
111
+
112
+ # ---------------------------------------------------------------------------
113
+ # Reference counting
114
+
115
+
116
+ def lean_inc(x):
117
+ if x.__class__ in _RC:
118
+ x.rc += 1
119
+
120
+
121
+ def lean_inc_n(x, n):
122
+ if x.__class__ in _RC:
123
+ x.rc += n
124
+
125
+
126
+ def lean_inc_ret(x):
127
+ if x.__class__ in _RC:
128
+ x.rc += 1
129
+ return x
130
+
131
+
132
+ def lean_dec(x):
133
+ if x.__class__ in _RC:
134
+ x.rc -= 1
135
+ if x.rc == 0:
136
+ _free(x)
137
+
138
+
139
+ def _free(x):
140
+ stack = [x]
141
+ while stack:
142
+ o = stack.pop()
143
+ if o.__class__ is Ctor:
144
+ children = o.objs
145
+ elif o.__class__ is LArray:
146
+ children = o.data
147
+ else:
148
+ fin = _FINALIZERS.get(o.__class__)
149
+ if fin is not None:
150
+ fin(o)
151
+ continue
152
+ for c in children:
153
+ if c.__class__ in _RC:
154
+ c.rc -= 1
155
+ if c.rc == 0:
156
+ stack.append(c)
157
+
158
+
159
+ def lean_is_exclusive(x):
160
+ return x.__class__ in _RC and x.rc == 1
161
+
162
+
163
+ def lean_is_shared(x):
164
+ return not (x.__class__ in _RC and x.rc == 1)
165
+
166
+
167
+ def lean_mark_persistent(x):
168
+ stack = [x]
169
+ while stack:
170
+ o = stack.pop()
171
+ if o.__class__ is Ctor:
172
+ if o.rc != PERSISTENT:
173
+ o.rc = PERSISTENT
174
+ stack.extend(o.objs)
175
+ elif o.__class__ is LArray:
176
+ if o.rc != PERSISTENT:
177
+ o.rc = PERSISTENT
178
+ stack.extend(o.data)
179
+ elif o.__class__ in _RC:
180
+ o.rc = PERSISTENT
181
+ return x
182
+
183
+
184
+ def lean_obj_tag(x):
185
+ if isinstance(x, int):
186
+ return x
187
+ return x.tag
188
+
189
+
190
+ def lean_reset(y, n):
191
+ if y.__class__ is Ctor and y.rc == 1:
192
+ objs = y.objs
193
+ for i in range(n):
194
+ lean_dec(objs[i])
195
+ return y
196
+ lean_dec(y)
197
+ return 0
198
+
199
+
200
+ def lean_reuse(y, tag, upd, objs):
201
+ if isinstance(y, int):
202
+ return Ctor(tag, objs)
203
+ y.objs = objs
204
+ if upd:
205
+ y.tag = tag
206
+ return y
207
+
208
+
209
+ # ---------------------------------------------------------------------------
210
+ # Panics
211
+
212
+
213
+ def _eprint(msg):
214
+ sys.stdout.flush()
215
+ sys.stderr.write(msg + "\n")
216
+ sys.stderr.flush()
217
+
218
+
219
+ def _panic(msg):
220
+ _eprint(msg)
221
+
222
+
223
+ def lean_panic_fn(default, msg):
224
+ _panic(_s(msg))
225
+ return default
226
+
227
+
228
+ def lean_panic_fn_borrowed(default, msg):
229
+ lean_inc(default)
230
+ _panic(_s(msg))
231
+ return default
232
+
233
+
234
+ def lean_internal_panic(msg):
235
+ _eprint(f"INTERNAL PANIC: {msg}")
236
+ sys.exit(1)
237
+
238
+
239
+ def lean_internal_panic_unreachable():
240
+ lean_internal_panic("unreachable code has been reached")
241
+
242
+
243
+ def lean_dbg_trace(msg, fn):
244
+ _eprint(_s(msg))
245
+ return lean_apply(fn, [0])
246
+
247
+
248
+ def lean_dbg_trace_if_shared(s, a):
249
+ if lean_is_shared(a):
250
+ _eprint(f"shared RC {_s(s)}")
251
+ return a
252
+
253
+
254
+ # ---------------------------------------------------------------------------
255
+ # Closures
256
+
257
+
258
+ def lean_apply(f, args):
259
+ while True:
260
+ fixed = f.fixed
261
+ for a in fixed:
262
+ lean_inc(a)
263
+ need = f.arity - len(fixed)
264
+ n = len(args)
265
+ if n < need:
266
+ return Closure(f.fn, f.arity, fixed + args)
267
+ if n == need:
268
+ return f.fn(*fixed, *args)
269
+ r = f.fn(*fixed, *args[:need])
270
+ args = args[need:]
271
+ f = r
272
+
273
+
274
+ def lean_py_extern(module, attr):
275
+ return getattr(importlib.import_module(module), attr)
276
+
277
+
278
+ # ---------------------------------------------------------------------------
279
+ # Lists
280
+
281
+
282
+ def _list_to_py(xs):
283
+ out = []
284
+ while xs.__class__ is Ctor:
285
+ out.append(xs.objs[0])
286
+ xs = xs.objs[1]
287
+ return out
288
+
289
+
290
+ def _py_to_list(items):
291
+ r = 0
292
+ for x in reversed(items):
293
+ r = Ctor(1, [x, r])
294
+ return r
295
+
296
+
297
+ # ---------------------------------------------------------------------------
298
+ # Nat and Int
299
+
300
+
301
+ def lean_nat_add(a, b):
302
+ return a + b
303
+
304
+
305
+ def lean_nat_sub(a, b):
306
+ return a - b if a > b else 0
307
+
308
+
309
+ def lean_nat_mul(a, b):
310
+ return a * b
311
+
312
+
313
+ def lean_nat_div(a, b):
314
+ return a // b if b else 0
315
+
316
+
317
+ def lean_nat_mod(a, b):
318
+ return a % b if b else a
319
+
320
+
321
+ def lean_nat_pow(a, b):
322
+ return a**b
323
+
324
+
325
+ def lean_nat_gcd(a, b):
326
+ return math.gcd(a, b)
327
+
328
+
329
+ def lean_nat_lcm(a, b):
330
+ return math.lcm(a, b)
331
+
332
+
333
+ def lean_nat_log2(a):
334
+ return a.bit_length() - 1 if a > 0 else 0
335
+
336
+
337
+ def lean_nat_land(a, b):
338
+ return a & b
339
+
340
+
341
+ def lean_nat_lor(a, b):
342
+ return a | b
343
+
344
+
345
+ def lean_nat_lxor(a, b):
346
+ return a ^ b
347
+
348
+
349
+ def lean_nat_shiftl(a, b):
350
+ return a << b
351
+
352
+
353
+ def lean_nat_shiftr(a, b):
354
+ return a >> b
355
+
356
+
357
+ def lean_nat_dec_eq(a, b):
358
+ return a == b
359
+
360
+
361
+ def lean_nat_dec_lt(a, b):
362
+ return a < b
363
+
364
+
365
+ def lean_nat_dec_le(a, b):
366
+ return a <= b
367
+
368
+
369
+ def lean_nat_pred(a):
370
+ return a - 1 if a > 0 else 0
371
+
372
+
373
+ def lean_nat_succ(a):
374
+ return a + 1
375
+
376
+
377
+ def lean_nat_to_int(a):
378
+ return a
379
+
380
+
381
+ def lean_nat_abs(a):
382
+ return -a if a < 0 else a
383
+
384
+
385
+ def lean_int_neg_succ_of_nat(a):
386
+ return -a - 1
387
+
388
+
389
+ def lean_int_to_nat(a):
390
+ return max(0, a)
391
+
392
+
393
+ def lean_int_neg(a):
394
+ return -a
395
+
396
+
397
+ def lean_int_add(a, b):
398
+ return a + b
399
+
400
+
401
+ def lean_int_sub(a, b):
402
+ return a - b
403
+
404
+
405
+ def lean_int_mul(a, b):
406
+ return a * b
407
+
408
+
409
+ def lean_int_div(a, b):
410
+ if b == 0:
411
+ return 0
412
+ q = abs(a) // abs(b)
413
+ return q if (a < 0) == (b < 0) else -q
414
+
415
+
416
+ def lean_int_mod(a, b):
417
+ if b == 0:
418
+ return a
419
+ r = abs(a) % abs(b)
420
+ return -r if a < 0 else r
421
+
422
+
423
+ def lean_int_ediv(a, b):
424
+ if b == 0:
425
+ return 0
426
+ r = a % abs(b)
427
+ return (a - r) // b
428
+
429
+
430
+ def lean_int_emod(a, b):
431
+ if b == 0:
432
+ return a
433
+ return a % abs(b)
434
+
435
+
436
+ def lean_int_dec_eq(a, b):
437
+ return a == b
438
+
439
+
440
+ def lean_int_dec_lt(a, b):
441
+ return a < b
442
+
443
+
444
+ def lean_int_dec_le(a, b):
445
+ return a <= b
446
+
447
+
448
+ def lean_int_dec_nonneg(a):
449
+ return a >= 0
450
+
451
+
452
+ def lean_int_pow(a, b):
453
+ return a**b
454
+
455
+
456
+ def lean_int_land(a, b):
457
+ return a & b
458
+
459
+
460
+ def lean_int_lor(a, b):
461
+ return a | b
462
+
463
+
464
+ def lean_int_xor(a, b):
465
+ return a ^ b
466
+
467
+
468
+ def lean_int_shift_right(a, b):
469
+ return a >> b
470
+
471
+
472
+ def lean_cstr_to_nat(s):
473
+ return int(s)
474
+
475
+
476
+ def lean_big_usize_to_nat(a):
477
+ return a
478
+
479
+
480
+ def lean_usize_to_nat(a):
481
+ return a
482
+
483
+
484
+ def lean_unsigned_to_nat(a):
485
+ return a
486
+
487
+
488
+ def lean_system_platform_nbits(_unit=0):
489
+ return 64
490
+
491
+
492
+ # ---------------------------------------------------------------------------
493
+ # Fixed-width integers
494
+
495
+ _WIDTHS = {"uint8": 8, "uint16": 16, "uint32": 32, "uint64": 64, "usize": 64}
496
+
497
+
498
+ def _define_uint(name, bits):
499
+ mask = (1 << bits) - 1
500
+ g = globals()
501
+ g[f"lean_{name}_of_nat"] = lambda a: a & mask
502
+ g[f"lean_{name}_of_nat_mk"] = lambda a: a & mask
503
+ g[f"lean_{name}_to_nat"] = lambda a: a
504
+ g[f"lean_{name}_add"] = lambda a, b: (a + b) & mask
505
+ g[f"lean_{name}_sub"] = lambda a, b: (a - b) & mask
506
+ g[f"lean_{name}_mul"] = lambda a, b: (a * b) & mask
507
+ g[f"lean_{name}_div"] = lambda a, b: a // b if b else 0
508
+ g[f"lean_{name}_mod"] = lambda a, b: a % b if b else a
509
+ g[f"lean_{name}_land"] = lambda a, b: a & b
510
+ g[f"lean_{name}_lor"] = lambda a, b: a | b
511
+ g[f"lean_{name}_xor"] = lambda a, b: a ^ b
512
+ g[f"lean_{name}_shift_left"] = lambda a, b: (a << (b % bits)) & mask
513
+ g[f"lean_{name}_shift_right"] = lambda a, b: a >> (b % bits)
514
+ g[f"lean_{name}_complement"] = lambda a: a ^ mask
515
+ g[f"lean_{name}_neg"] = lambda a: (-a) & mask
516
+ g[f"lean_{name}_log2"] = lambda a: a.bit_length() - 1 if a > 0 else 0
517
+ g[f"lean_{name}_dec_eq"] = lambda a, b: a == b
518
+ g[f"lean_{name}_dec_lt"] = lambda a, b: a < b
519
+ g[f"lean_{name}_dec_le"] = lambda a, b: a <= b
520
+ g[f"lean_{name}_to_float"] = lambda a: float(a)
521
+ g[f"lean_{name}_to_float32"] = lambda a: _f32(float(a))
522
+ for other, obits in _WIDTHS.items():
523
+ if other != name:
524
+ omask = (1 << obits) - 1
525
+ g[f"lean_{name}_to_{other}"] = lambda a, omask=omask: a & omask
526
+
527
+
528
+ for _n, _b in _WIDTHS.items():
529
+ _define_uint(_n, _b)
530
+
531
+
532
+ _SWIDTHS = {"int8": 8, "int16": 16, "int32": 32, "int64": 64, "isize": 64}
533
+
534
+
535
+ def _define_sint(name, bits):
536
+ mask = (1 << bits) - 1
537
+ half = 1 << (bits - 1)
538
+
539
+ def val(a):
540
+ return a - (1 << bits) if a >= half else a
541
+
542
+ g = globals()
543
+ g[f"lean_{name}_of_int"] = lambda a: a & mask
544
+ g[f"lean_{name}_of_nat"] = lambda a: a & mask
545
+ g[f"lean_{name}_to_int"] = val
546
+ g[f"lean_{name}_add"] = lambda a, b: (a + b) & mask
547
+ g[f"lean_{name}_sub"] = lambda a, b: (a - b) & mask
548
+ g[f"lean_{name}_mul"] = lambda a, b: (a * b) & mask
549
+ g[f"lean_{name}_div"] = lambda a, b: lean_int_div(val(a), val(b)) & mask
550
+ g[f"lean_{name}_mod"] = lambda a, b: lean_int_mod(val(a), val(b)) & mask
551
+ g[f"lean_{name}_neg"] = lambda a: (-a) & mask
552
+ g[f"lean_{name}_land"] = lambda a, b: a & b
553
+ g[f"lean_{name}_lor"] = lambda a, b: a | b
554
+ g[f"lean_{name}_xor"] = lambda a, b: a ^ b
555
+ g[f"lean_{name}_shift_left"] = lambda a, b: (a << (val(b) % bits)) & mask
556
+ g[f"lean_{name}_shift_right"] = lambda a, b: (val(a) >> (val(b) % bits)) & mask
557
+ g[f"lean_{name}_complement"] = lambda a: a ^ mask
558
+ g[f"lean_{name}_abs"] = lambda a: abs(val(a)) & mask
559
+ g[f"lean_{name}_dec_eq"] = lambda a, b: a == b
560
+ g[f"lean_{name}_dec_lt"] = lambda a, b: val(a) < val(b)
561
+ g[f"lean_{name}_dec_le"] = lambda a, b: val(a) <= val(b)
562
+ g[f"lean_{name}_to_float"] = lambda a: float(val(a))
563
+ g[f"lean_{name}_to_float32"] = lambda a: _f32(float(val(a)))
564
+ for other, obits in _SWIDTHS.items():
565
+ if other != name:
566
+ omask = (1 << obits) - 1
567
+ g[f"lean_{name}_to_{other}"] = lambda a, omask=omask: val(a) & omask
568
+ for other, obits in _WIDTHS.items():
569
+ omask = (1 << obits) - 1
570
+ g[f"lean_{name}_to_{other}"] = lambda a, omask=omask: val(a) & omask
571
+
572
+
573
+ for _n, _b in _SWIDTHS.items():
574
+ _define_sint(_n, _b)
575
+
576
+
577
+ def lean_bool_to_uint64(a):
578
+ return 1 if a else 0
579
+
580
+
581
+ # ---------------------------------------------------------------------------
582
+ # Float and Float32
583
+
584
+ _F32 = struct.Struct("<f")
585
+ _F64 = struct.Struct("<d")
586
+ _U32 = struct.Struct("<I")
587
+ _U64 = struct.Struct("<Q")
588
+
589
+
590
+ def _f32(x):
591
+ try:
592
+ return _F32.unpack(_F32.pack(x))[0]
593
+ except OverflowError:
594
+ return math.copysign(math.inf, x)
595
+
596
+
597
+ def _float_str(a):
598
+ if math.isnan(a):
599
+ return b"NaN"
600
+ if math.isinf(a):
601
+ return b"inf" if a > 0 else b"-inf"
602
+ return f"{a:.6f}".encode()
603
+
604
+
605
+ def lean_float_to_string(a):
606
+ return _float_str(a)
607
+
608
+
609
+ def lean_float32_to_string(a):
610
+ return _float_str(a)
611
+
612
+
613
+ def _to_uint(a, bits):
614
+ if math.isnan(a) or a <= 0:
615
+ return 0
616
+ m = (1 << bits) - 1
617
+ if a >= float(1 << bits):
618
+ return m
619
+ return int(a)
620
+
621
+
622
+ def _to_int(a, bits):
623
+ if math.isnan(a):
624
+ return 0
625
+ lo = -(1 << (bits - 1))
626
+ hi = (1 << (bits - 1)) - 1
627
+ if a <= lo:
628
+ v = lo
629
+ elif a >= float(hi):
630
+ v = hi
631
+ else:
632
+ v = int(a)
633
+ return v & ((1 << bits) - 1)
634
+
635
+
636
+ def _div(a, b):
637
+ try:
638
+ return a / b
639
+ except ZeroDivisionError:
640
+ if math.isnan(a) or a == 0:
641
+ return math.nan
642
+ return math.copysign(math.inf, a) * math.copysign(1.0, b)
643
+
644
+
645
+ def _libm(f):
646
+ def g(*args):
647
+ try:
648
+ return f(*args)
649
+ except ValueError:
650
+ return math.nan
651
+ except OverflowError:
652
+ return math.inf
653
+
654
+ return g
655
+
656
+
657
+ def _libm32(f):
658
+ def g(*args):
659
+ return _f32(f(*args))
660
+
661
+ return g
662
+
663
+
664
+ def _define_float(p, rnd):
665
+ g = globals()
666
+ g[f"lean_{p}_add"] = lambda a, b: rnd(a + b)
667
+ g[f"lean_{p}_sub"] = lambda a, b: rnd(a - b)
668
+ g[f"lean_{p}_mul"] = lambda a, b: rnd(a * b)
669
+ g[f"lean_{p}_div"] = lambda a, b: rnd(_div(a, b))
670
+ g[f"lean_{p}_negate"] = lambda a: -a
671
+ g[f"lean_{p}_beq"] = lambda a, b: a == b
672
+ g[f"lean_{p}_decLt"] = lambda a, b: a < b
673
+ g[f"lean_{p}_decLe"] = lambda a, b: a <= b
674
+ g[f"lean_{p}_isnan"] = math.isnan
675
+ g[f"lean_{p}_isfinite"] = lambda a: math.isfinite(a)
676
+ g[f"lean_{p}_isinf"] = lambda a: math.isinf(a)
677
+ g[f"lean_{p}_of_nat"] = lambda a: rnd(_nat_to_float(a))
678
+ g[f"lean_{p}_of_int"] = lambda a: rnd(_int_to_float(a))
679
+ for name, bits in (("uint8", 8), ("uint16", 16), ("uint32", 32), ("uint64", 64), ("usize", 64)):
680
+ g[f"lean_{p}_to_{name}"] = lambda a, bits=bits: _to_uint(a, bits)
681
+ for name, bits in (("int8", 8), ("int16", 16), ("int32", 32), ("int64", 64), ("isize", 64)):
682
+ g[f"lean_{p}_to_{name}"] = lambda a, bits=bits: _to_int(a, bits)
683
+ g[f"lean_{p}_scaleb"] = lambda a, b: rnd(_scaleb(a, b))
684
+ g[f"lean_{p}_frexp"] = lambda a: Ctor(0, [rnd(_frexp(a)[0]), _frexp(a)[1]])
685
+
686
+
687
+ def _nat_to_float(a):
688
+ try:
689
+ return float(a)
690
+ except OverflowError:
691
+ return math.inf
692
+
693
+
694
+ def _int_to_float(a):
695
+ try:
696
+ return float(a)
697
+ except OverflowError:
698
+ return math.copysign(math.inf, a)
699
+
700
+
701
+ def _scaleb(a, b):
702
+ try:
703
+ return math.ldexp(a, b)
704
+ except OverflowError:
705
+ return math.copysign(math.inf, a)
706
+
707
+
708
+ def _frexp(a):
709
+ if not math.isfinite(a):
710
+ return (a, 0)
711
+ return math.frexp(a)
712
+
713
+
714
+ _define_float("float", lambda x: x)
715
+ _define_float("float32", _f32)
716
+
717
+
718
+ def lean_float_of_bits(u):
719
+ return _F64.unpack(_U64.pack(u))[0]
720
+
721
+
722
+ def lean_float_to_bits(a):
723
+ return _U64.unpack(_F64.pack(a))[0]
724
+
725
+
726
+ def lean_float32_of_bits(u):
727
+ return _F32.unpack(_U32.pack(u))[0]
728
+
729
+
730
+ def lean_float32_to_bits(a):
731
+ return _U32.unpack(_F32.pack(a))[0]
732
+
733
+
734
+ def lean_float_to_float32(a):
735
+ return _f32(a)
736
+
737
+
738
+ def lean_float32_to_float(a):
739
+ return a
740
+
741
+
742
+ def lean_float_of_scientific(m, sign, e):
743
+ try:
744
+ if sign:
745
+ return float(m) / (10**e) if e < 400 else _float_div_big(m, e)
746
+ return float(m * 10**e)
747
+ except OverflowError:
748
+ return math.inf
749
+
750
+
751
+ def _float_div_big(m, e):
752
+ from fractions import Fraction
753
+
754
+ return float(Fraction(m, 10**e))
755
+
756
+
757
+ for _name, _f in (
758
+ ("sin", math.sin),
759
+ ("cos", math.cos),
760
+ ("tan", math.tan),
761
+ ("asin", math.asin),
762
+ ("acos", math.acos),
763
+ ("atan", math.atan),
764
+ ("atan2", math.atan2),
765
+ ("sinh", math.sinh),
766
+ ("cosh", math.cosh),
767
+ ("tanh", math.tanh),
768
+ ("asinh", math.asinh),
769
+ ("acosh", math.acosh),
770
+ ("atanh", math.atanh),
771
+ ("exp", math.exp),
772
+ ("exp2", lambda x: 2.0**x),
773
+ ("log", math.log),
774
+ ("log2", math.log2),
775
+ ("log10", math.log10),
776
+ ("pow", math.pow),
777
+ ("sqrt", math.sqrt),
778
+ ("cbrt", math.cbrt),
779
+ ("ceil", lambda x: float(math.ceil(x)) if math.isfinite(x) else x),
780
+ ("floor", lambda x: float(math.floor(x)) if math.isfinite(x) else x),
781
+ ("round", lambda x: float(math.floor(abs(x) + 0.5)) * math.copysign(1.0, x) if math.isfinite(x) else x),
782
+ ("fabs", math.fabs),
783
+ ("fmod", math.fmod),
784
+ ("fma", math.fma),
785
+ ):
786
+ globals()[_name] = _libm(_f)
787
+ globals()[_name + "f"] = _libm32(_libm(_f))
788
+
789
+ # ---------------------------------------------------------------------------
790
+ # Strings (UTF-8 bytes)
791
+
792
+
793
+ def _s(b):
794
+ return b.decode("utf-8", "surrogatepass")
795
+
796
+
797
+ def _is_first(c):
798
+ return (c & 0x80) == 0 or (c & 0xE0) == 0xC0 or (c & 0xF0) == 0xE0 or (c & 0xF8) == 0xF0
799
+
800
+
801
+ def _char_size(c):
802
+ if c & 0x80 == 0:
803
+ return 1
804
+ if (c & 0xE0) == 0xC0:
805
+ return 2
806
+ if (c & 0xF0) == 0xE0:
807
+ return 3
808
+ if (c & 0xF8) == 0xF0:
809
+ return 4
810
+ return 1
811
+
812
+
813
+ def _get_core(s, i):
814
+ size = len(s)
815
+ c = s[i]
816
+ if c & 0x80 == 0:
817
+ return c
818
+ if (c & 0xE0) == 0xC0 and i + 1 < size:
819
+ r = ((c & 0x1F) << 6) | (s[i + 1] & 0x3F)
820
+ if r >= 0x80:
821
+ return r
822
+ if (c & 0xF0) == 0xE0 and i + 2 < size:
823
+ r = ((c & 0x0F) << 12) | ((s[i + 1] & 0x3F) << 6) | (s[i + 2] & 0x3F)
824
+ if r >= 0x800 and not (0xD800 <= r <= 0xDFFF):
825
+ return r
826
+ if (c & 0xF8) == 0xF0 and i + 3 < size:
827
+ r = ((c & 0x07) << 18) | ((s[i + 1] & 0x3F) << 12) | ((s[i + 2] & 0x3F) << 6) | (s[i + 3] & 0x3F)
828
+ if 0x10000 <= r <= 0x10FFFF:
829
+ return r
830
+ return None
831
+
832
+
833
+ def _enc(c):
834
+ return chr(c).encode("utf-8", "surrogatepass")
835
+
836
+
837
+ _DEFAULT_CHAR = 65
838
+
839
+
840
+ def lean_mk_string(s):
841
+ return s
842
+
843
+
844
+ def lean_string_mk(cs):
845
+ return "".join(chr(c) for c in _list_to_py(cs)).encode("utf-8", "surrogatepass")
846
+
847
+
848
+ def lean_string_data(s):
849
+ return _py_to_list([ord(c) for c in _s(s)])
850
+
851
+
852
+ def lean_string_length(s):
853
+ if s.isascii():
854
+ return len(s)
855
+ return len(_s(s))
856
+
857
+
858
+ def lean_string_utf8_byte_size(s):
859
+ return len(s)
860
+
861
+
862
+ def lean_string_push(s, c):
863
+ return s + _enc(c)
864
+
865
+
866
+ def lean_string_append(a, b):
867
+ return a + b
868
+
869
+
870
+ def lean_string_utf8_get(s, i):
871
+ if i >= len(s):
872
+ return _DEFAULT_CHAR
873
+ r = _get_core(s, i)
874
+ return _DEFAULT_CHAR if r is None else r
875
+
876
+
877
+ def lean_string_utf8_get_fast(s, i):
878
+ c = s[i]
879
+ if c & 0x80 == 0:
880
+ return c
881
+ r = _get_core(s, i)
882
+ return _DEFAULT_CHAR if r is None else r
883
+
884
+
885
+ def lean_string_utf8_get_opt(s, i):
886
+ if i >= len(s):
887
+ return 0
888
+ r = _get_core(s, i)
889
+ return 0 if r is None else Ctor(1, [r])
890
+
891
+
892
+ def lean_string_utf8_get_bang(s, i):
893
+ if i >= len(s):
894
+ _panic("PANIC at String.get! Init.Data.String.Basic:0:0: index out of bounds")
895
+ return _DEFAULT_CHAR
896
+ r = _get_core(s, i)
897
+ return _DEFAULT_CHAR if r is None else r
898
+
899
+
900
+ def lean_string_utf8_next(s, i):
901
+ if i >= len(s):
902
+ return i + 1
903
+ return i + _char_size(s[i])
904
+
905
+
906
+ def lean_string_utf8_next_fast(s, i):
907
+ return i + _char_size(s[i])
908
+
909
+
910
+ def lean_string_utf8_prev(s, i):
911
+ if i == 0:
912
+ return 0
913
+ if i > len(s):
914
+ return i - 1
915
+ i -= 1
916
+ while not _is_first(s[i]):
917
+ i -= 1
918
+ return i
919
+
920
+
921
+ def lean_string_utf8_at_end(s, i):
922
+ return i >= len(s)
923
+
924
+
925
+ def lean_string_is_valid_pos(s, i):
926
+ if i > len(s):
927
+ return False
928
+ if i == len(s):
929
+ return True
930
+ return _is_first(s[i])
931
+
932
+
933
+ def lean_string_utf8_extract(s, b, e):
934
+ sz = len(s)
935
+ if b >= e or b >= sz:
936
+ return b""
937
+ if not _is_first(s[b]):
938
+ return b""
939
+ e = min(e, sz)
940
+ if e < sz and not _is_first(s[e]):
941
+ e = sz
942
+ return s[b:e]
943
+
944
+
945
+ def lean_string_utf8_extract_fast(s, b, e):
946
+ return s[b:e]
947
+
948
+
949
+ def lean_string_utf8_set(s, i, c):
950
+ sz = len(s)
951
+ if i >= sz:
952
+ return s
953
+ old = s[i]
954
+ if not _is_first(old):
955
+ return s
956
+ n = min(_char_size(old), sz - i)
957
+ return s[:i] + _enc(c) + s[i + n :]
958
+
959
+
960
+ def lean_string_get_byte_fast(s, i):
961
+ return s[i]
962
+
963
+
964
+ def lean_string_dec_eq(a, b):
965
+ return a == b
966
+
967
+
968
+ def lean_string_dec_lt(a, b):
969
+ return a < b
970
+
971
+
972
+ def lean_string_lt(a, b):
973
+ return a < b
974
+
975
+
976
+ def lean_string_memcmp(s1, s2, lstart, rstart, length):
977
+ return s1[lstart : lstart + length] == s2[rstart : rstart + length]
978
+
979
+
980
+ def lean_string_of_usize(n):
981
+ return str(n).encode()
982
+
983
+
984
+ def lean_string_to_utf8(s):
985
+ return LByteArray(bytearray(s))
986
+
987
+
988
+ def lean_string_from_utf8_unchecked(a):
989
+ return bytes(a.data)
990
+
991
+
992
+ def lean_string_validate_utf8(a):
993
+ try:
994
+ bytes(a.data).decode("utf-8")
995
+ return True
996
+ except UnicodeDecodeError:
997
+ return False
998
+
999
+
1000
+ _M64 = (1 << 64) - 1
1001
+
1002
+
1003
+ def _murmur64a(data, seed):
1004
+ m = 0xC6A4A7935BD1E995
1005
+ r = 47
1006
+ n = len(data)
1007
+ h = (seed ^ (n * m)) & _M64
1008
+ nblocks = n // 8
1009
+ for i in range(nblocks):
1010
+ k = int.from_bytes(data[8 * i : 8 * i + 8], "little")
1011
+ k = (k * m) & _M64
1012
+ k ^= k >> r
1013
+ k = (k * m) & _M64
1014
+ h ^= k
1015
+ h = (h * m) & _M64
1016
+ tail = data[8 * nblocks :]
1017
+ if tail:
1018
+ for i in range(len(tail) - 1, -1, -1):
1019
+ h ^= tail[i] << (8 * i)
1020
+ h = (h * m) & _M64
1021
+ h ^= h >> r
1022
+ h = (h * m) & _M64
1023
+ h ^= h >> r
1024
+ return h
1025
+
1026
+
1027
+ def lean_string_hash(s):
1028
+ return _murmur64a(s, 11)
1029
+
1030
+
1031
+ def lean_uint64_mix_hash(a, b):
1032
+ m = 0xC6A4A7935BD1E995
1033
+ r = 47
1034
+ b = (b * m) & _M64
1035
+ b ^= b >> r
1036
+ b = (b * m) & _M64
1037
+ a ^= b
1038
+ a = (a * m) & _M64
1039
+ return a
1040
+
1041
+
1042
+ # ---------------------------------------------------------------------------
1043
+ # Arrays
1044
+
1045
+
1046
+ def _array_exclusive(a):
1047
+ if a.rc == 1:
1048
+ return a
1049
+ data = a.data
1050
+ for x in data:
1051
+ lean_inc(x)
1052
+ lean_dec(a)
1053
+ return LArray(list(data))
1054
+
1055
+
1056
+ def lean_array_mk(xs):
1057
+ items = _list_to_py(xs)
1058
+ for x in items:
1059
+ lean_inc(x)
1060
+ lean_dec(xs)
1061
+ return LArray(items)
1062
+
1063
+
1064
+ def lean_array_to_list(a):
1065
+ for x in a.data:
1066
+ lean_inc(x)
1067
+ return _py_to_list(a.data)
1068
+
1069
+
1070
+ def lean_mk_empty_array_with_capacity(cap):
1071
+ return LArray([])
1072
+
1073
+
1074
+ def lean_mk_array(n, v):
1075
+ if n == 0:
1076
+ lean_dec(v)
1077
+ return LArray([])
1078
+ lean_inc_n(v, n - 1)
1079
+ return LArray([v] * n)
1080
+
1081
+
1082
+ def lean_array_get_size(a):
1083
+ return len(a.data)
1084
+
1085
+
1086
+ def lean_array_size(a):
1087
+ return len(a.data)
1088
+
1089
+
1090
+ def lean_array_fget(a, i):
1091
+ x = a.data[i]
1092
+ lean_inc(x)
1093
+ return x
1094
+
1095
+
1096
+ def lean_array_fget_borrowed(a, i):
1097
+ return a.data[i]
1098
+
1099
+
1100
+ def lean_array_uget(a, i):
1101
+ x = a.data[i]
1102
+ lean_inc(x)
1103
+ return x
1104
+
1105
+
1106
+ def lean_array_uget_borrowed(a, i):
1107
+ return a.data[i]
1108
+
1109
+
1110
+ def lean_array_get(default, a, i):
1111
+ if i < len(a.data):
1112
+ lean_dec(default)
1113
+ x = a.data[i]
1114
+ lean_inc(x)
1115
+ return x
1116
+ _panic_oob()
1117
+ return default
1118
+
1119
+
1120
+ def lean_array_get_borrowed(default, a, i):
1121
+ if i < len(a.data):
1122
+ return a.data[i]
1123
+ _panic_oob()
1124
+ return default
1125
+
1126
+
1127
+ def _panic_oob():
1128
+ _eprint("Error: index out of bounds")
1129
+
1130
+
1131
+ def lean_array_push(a, v):
1132
+ a = _array_exclusive(a)
1133
+ a.data.append(v)
1134
+ return a
1135
+
1136
+
1137
+ def lean_array_fset(a, i, v):
1138
+ a = _array_exclusive(a)
1139
+ old = a.data[i]
1140
+ a.data[i] = v
1141
+ lean_dec(old)
1142
+ return a
1143
+
1144
+
1145
+ def lean_array_uset(a, i, v):
1146
+ return lean_array_fset(a, i, v)
1147
+
1148
+
1149
+ def lean_array_set(a, i, v):
1150
+ if i >= len(a.data):
1151
+ lean_dec(v)
1152
+ _panic_oob()
1153
+ return a
1154
+ return lean_array_fset(a, i, v)
1155
+
1156
+
1157
+ def lean_array_fswap(a, i, j):
1158
+ a = _array_exclusive(a)
1159
+ d = a.data
1160
+ d[i], d[j] = d[j], d[i]
1161
+ return a
1162
+
1163
+
1164
+ def lean_array_swap(a, i, j):
1165
+ n = len(a.data)
1166
+ if i >= n or j >= n:
1167
+ return a
1168
+ return lean_array_fswap(a, i, j)
1169
+
1170
+
1171
+ def lean_array_pop(a):
1172
+ a = _array_exclusive(a)
1173
+ if a.data:
1174
+ lean_dec(a.data.pop())
1175
+ return a
1176
+
1177
+
1178
+ def lean_array_uswap(a, i, j):
1179
+ return lean_array_fswap(a, i, j)
1180
+
1181
+
1182
+ def lean_array_propagate_mark(a):
1183
+ return a
1184
+
1185
+
1186
+ def lean_copy_array(a):
1187
+ for x in a.data:
1188
+ lean_inc(x)
1189
+ return LArray(list(a.data))
1190
+
1191
+
1192
+ def lean_array_extract(a, start, stop):
1193
+ d = a.data
1194
+ stop = min(stop, len(d))
1195
+ if start >= stop:
1196
+ return LArray([])
1197
+ items = d[start:stop]
1198
+ for x in items:
1199
+ lean_inc(x)
1200
+ return LArray(items)
1201
+
1202
+
1203
+ # ---------------------------------------------------------------------------
1204
+ # ByteArray and FloatArray
1205
+
1206
+
1207
+ def _sarray_exclusive(a, cls):
1208
+ if a.rc == 1:
1209
+ return a
1210
+ lean_dec(a)
1211
+ return cls(a.data.copy())
1212
+
1213
+
1214
+ def lean_byte_array_mk(xs):
1215
+ return LByteArray(bytearray(xs.data))
1216
+
1217
+
1218
+ def lean_byte_array_data(a):
1219
+ return LArray(list(a.data))
1220
+
1221
+
1222
+ def lean_mk_empty_byte_array(cap):
1223
+ return LByteArray(bytearray())
1224
+
1225
+
1226
+ def lean_byte_array_size(a):
1227
+ return len(a.data)
1228
+
1229
+
1230
+ def lean_sarray_size(a):
1231
+ return len(a.data)
1232
+
1233
+
1234
+ def lean_byte_array_get(a, i):
1235
+ return a.data[i] if i < len(a.data) else 0
1236
+
1237
+
1238
+ def lean_byte_array_fget(a, i):
1239
+ return a.data[i]
1240
+
1241
+
1242
+ def lean_byte_array_uget(a, i):
1243
+ return a.data[i]
1244
+
1245
+
1246
+ def lean_byte_array_push(a, v):
1247
+ a = _sarray_exclusive(a, LByteArray)
1248
+ a.data.append(v)
1249
+ return a
1250
+
1251
+
1252
+ def lean_byte_array_set(a, i, v):
1253
+ if i >= len(a.data):
1254
+ return a
1255
+ a = _sarray_exclusive(a, LByteArray)
1256
+ a.data[i] = v
1257
+ return a
1258
+
1259
+
1260
+ def lean_byte_array_fset(a, i, v):
1261
+ a = _sarray_exclusive(a, LByteArray)
1262
+ a.data[i] = v
1263
+ return a
1264
+
1265
+
1266
+ def lean_byte_array_uset(a, i, v):
1267
+ return lean_byte_array_fset(a, i, v)
1268
+
1269
+
1270
+ def lean_byte_array_copy_slice(src, src_off, dest, dest_off, length, exact):
1271
+ ssz = len(src.data)
1272
+ dsz = len(dest.data)
1273
+ src_off = min(src_off, ssz)
1274
+ length = min(length, ssz - src_off)
1275
+ dest_off = min(dest_off, dsz)
1276
+ chunk = src.data[src_off : src_off + length]
1277
+ r = _sarray_exclusive(dest, LByteArray)
1278
+ if dest_off + length > dsz:
1279
+ r.data.extend(bytes(dest_off + length - dsz))
1280
+ r.data[dest_off : dest_off + length] = chunk
1281
+ return r
1282
+
1283
+
1284
+ def lean_byte_array_hash(a):
1285
+ return _murmur64a(bytes(a.data), 11)
1286
+
1287
+
1288
+ def lean_float_array_mk(xs):
1289
+ return LFloatArray(list(xs.data))
1290
+
1291
+
1292
+ def lean_float_array_data(a):
1293
+ return LArray(list(a.data))
1294
+
1295
+
1296
+ def lean_mk_empty_float_array(cap):
1297
+ return LFloatArray([])
1298
+
1299
+
1300
+ def lean_float_array_size(a):
1301
+ return len(a.data)
1302
+
1303
+
1304
+ def lean_float_array_get(a, i):
1305
+ return a.data[i] if i < len(a.data) else 0.0
1306
+
1307
+
1308
+ def lean_float_array_fget(a, i):
1309
+ return a.data[i]
1310
+
1311
+
1312
+ def lean_float_array_uget(a, i):
1313
+ return a.data[i]
1314
+
1315
+
1316
+ def lean_float_array_push(a, v):
1317
+ a = _sarray_exclusive(a, LFloatArray)
1318
+ a.data.append(v)
1319
+ return a
1320
+
1321
+
1322
+ def lean_float_array_set(a, i, v):
1323
+ if i >= len(a.data):
1324
+ return a
1325
+ a = _sarray_exclusive(a, LFloatArray)
1326
+ a.data[i] = v
1327
+ return a
1328
+
1329
+
1330
+ def lean_float_array_fset(a, i, v):
1331
+ a = _sarray_exclusive(a, LFloatArray)
1332
+ a.data[i] = v
1333
+ return a
1334
+
1335
+
1336
+ def lean_float_array_uset(a, i, v):
1337
+ return lean_float_array_fset(a, i, v)
1338
+
1339
+
1340
+ # ---------------------------------------------------------------------------
1341
+ # Thunks and tasks (run synchronously)
1342
+
1343
+
1344
+ def lean_mk_thunk(c):
1345
+ return Thunk(c)
1346
+
1347
+
1348
+ def lean_thunk_pure(v):
1349
+ return Thunk(None, v, True)
1350
+
1351
+
1352
+ def _thunk_force(t):
1353
+ if not t.done:
1354
+ t.value = lean_mark_persistent(lean_apply(t.fn, [0]))
1355
+ t.done = True
1356
+ t.fn = None
1357
+ return t.value
1358
+
1359
+
1360
+ def lean_thunk_get_own(t):
1361
+ v = _thunk_force(t)
1362
+ lean_inc(v)
1363
+ return v
1364
+
1365
+
1366
+ def lean_thunk_get(t):
1367
+ return _thunk_force(t)
1368
+
1369
+
1370
+ def lean_task_pure(v):
1371
+ return Task(lean_mark_persistent(v))
1372
+
1373
+
1374
+ def lean_task_spawn(c, prio=0):
1375
+ return Task(lean_mark_persistent(lean_apply(c, [0])))
1376
+
1377
+
1378
+ def lean_task_get_own(t):
1379
+ v = t.value
1380
+ lean_inc(v)
1381
+ return v
1382
+
1383
+
1384
+ def lean_task_get(t):
1385
+ return t.value
1386
+
1387
+
1388
+ def lean_task_map(f, t, prio=0, sync=0):
1389
+ return Task(lean_mark_persistent(lean_apply(f, [t.value])))
1390
+
1391
+
1392
+ def lean_task_bind(t, f, prio=0, sync=0):
1393
+ return lean_apply(f, [t.value])
1394
+
1395
+
1396
+ def lean_io_wait(t, _w=0):
1397
+ return t.value
1398
+
1399
+
1400
+ from lean_python.io_externs import *