Skip to content

Commit 0d1f67d

Browse files
committed
enh: add mg(), a gfunc mathifier
1 parent 3860ef8 commit 0d1f67d

File tree

3 files changed

+27
-2
lines changed

3 files changed

+27
-2
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1437,6 +1437,8 @@ For convenience, we introduce some special cases:
14371437
14381438
*Added in v0.13.1:* ``primes`` and ``fibonacci``.
14391439
1440+
*Added in v0.14.0:* ``mg``, a decorator to mathify a gfunc, so that it will ``m()`` the generator instances it makes. Combo with ``imemoize`` for great justice, e.g. ``a = mg(imemoize(s(1, 2, ...)))``.
1441+
14401442
We provide a compact syntax to create lazy constant, arithmetic, geometric and power sequences: ``s(...)``. Numeric (``int``, ``float``, ``mpmath``) and symbolic (SymPy) formats are supported. We avoid accumulating roundoff error when used with floating-point formats.
14411443
14421444
We also provide arithmetic operation support for iterables (termwise). To make any iterable infix math aware, use ``m(iterable)``. The arithmetic is lazy; it just plans computations, returning a new lazy mathematical sequence. To extract values, iterate over the result. (Note this implies that expressions consisting of thousands of operations will overflow Python's call stack. In practice this shouldn't be a problem.)

unpythonic/mathseq.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
(currently, the Fibonacci numbers and the prime numbers).
1919
"""
2020

21-
__all__ = ["s", "m", "almosteq",
21+
__all__ = ["s", "m", "mg", "almosteq",
2222
"sadd", "ssub", "sabs", "spos", "sneg", "sinvert", "smul", "spow",
2323
"struediv", "sfloordiv", "smod", "sdivmod",
2424
"sround", "strunc", "sfloor", "sceil",
@@ -27,6 +27,7 @@
2727
"fibonacci", "primes"]
2828

2929
from itertools import repeat, takewhile, count
30+
from functools import wraps
3031
from operator import add as primitive_add, mul as primitive_mul, \
3132
pow as primitive_pow, mod as primitive_mod, \
3233
floordiv as primitive_floordiv, truediv as primitive_truediv, \
@@ -507,6 +508,23 @@ def __ror__(self, other):
507508
return sor(other, self)
508509
# TODO: conversion (bool, complex, int, float) and comparison operators? Do we want those?
509510

511+
def mg(gfunc):
512+
"""Decorator: make gfunc m() the returned generator instances.
513+
514+
Return a new gfunc, which passes all its arguments to the original ``gfunc``.
515+
516+
Example::
517+
518+
a = mg(imemoize(s(1, 2, ...)))
519+
assert last(take(5, a())) == 5
520+
assert last(take(5, a())) == 5
521+
assert last(take(5, a() + a())) == 10
522+
"""
523+
@wraps(gfunc)
524+
def mathify(*args, **kwargs):
525+
return m(gfunc(*args, **kwargs))
526+
return mathify
527+
510528
# The *settings mechanism is used by round and pow.
511529
# These are recursive to support iterables containing iterables (e.g. an iterable of math sequences).
512530
def _make_termwise_stream_unop(op, *settings):

unpythonic/test/test_mathseq.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from math import floor, log2
55
from operator import mul
66

7-
from ..mathseq import s, m, sadd, smul, spow, cauchyprod, primes, fibonacci
7+
from ..mathseq import s, m, mg, sadd, smul, spow, cauchyprod, primes, fibonacci
88
from ..it import take, last
99
from ..fold import scanl
1010
from ..gmemo import imemoize
@@ -233,6 +233,11 @@ def ulp(x): # Unit in the Last Place
233233
factorials = imemoize(scanl(mul, 1, s(1, 2, ...))) # 0!, 1!, 2!, ...
234234
assert last(take(6, factorials())) == 120
235235

236+
a = mg(imemoize(s(1, 2, ...)))
237+
assert last(take(5, a())) == 5
238+
assert last(take(5, a())) == 5
239+
assert last(take(5, a() + a())) == 10
240+
236241
print("All tests PASSED")
237242

238243
if __name__ == '__main__':

0 commit comments

Comments
 (0)