[issue42557] Make asyncio.__main__ reusable, also adding a preamble feature.
Change by Berry Schoenmakers : -- keywords: +patch pull_requests: +22889 stage: -> patch review pull_request: https://github.com/python/cpython/pull/24055 ___ Python tracker <https://bugs.python.org/issue42557> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue42557] Make asyncio.__main__ reusable, also adding a preamble feature.
New submission from Berry Schoenmakers : The async REPL introduced in Python 3.8 is very nice for quick tests and experiments, supporting top-level "await" (see https://bugs.python.org/issue37028). I'm using it often when developing code that heavily relies on Python's asyncio module. A drawback of the basic interface when launching it with "python -m asyncio" is that one usually still needs to enter a couple of statements to load the package you're working on, etc. To overcome this I've added a __main__.py to the mpyc package such that entering "python -m mpyc" will launch the async REPL like this: asyncio REPL 3.10.0a2 (tags/v3.10.0a2:114ee5d, Nov 3 2020, 00:37:42) [MSC v.1927 64 bit (AMD64)] on win32 Use "await" directly instead of "asyncio.run()". Type "help", "copyright", "credits" or "license" for more information. >>> import asyncio >>> from mpyc.runtime import mpc >>> secint = mpc.SecInt() >>> secfxp = mpc.SecFxp() >>> secfld256 = mpc.SecFld(256) >>> This enables the async REPL but also a "preamble" with some additional code is executed. To program mpyc.__main__.py, however, I basically had to copy asyncio.__main__.py and make a few changes throughout the code. It works alright, but to take advantage of future improvements to asyncio.__main__.py it would be very convenient if asyncio.__main__.py becomes reusable. With the added feature for specifying a "preamble", programming something like mpyc.__main__.py requires just a few lines of code: import asyncio.__main__ if __name__ == '__main__': preamble = ('from mpyc.runtime import mpc', 'secint = mpc.SecInt()', 'secfxp = mpc.SecFxp()', 'secfld256 = mpc.SecFld(256)') asyncio.__main__.main(preamble) The attachment contains the current version of mpyc.__main__.py, which to a large extent duplicates code from asyncio.__main__.py. A couple of, I think, minor changes are applied to make the code reusable, and to add the preamble feature. Would be nice if asyncio.__main__.py is updated in this manner in Python 3.10 such that package developers can tailor it to their needs? -- components: asyncio files: __main__.py messages: 382419 nosy: asvetlov, lschoe, vstinner, yselivanov priority: normal severity: normal status: open title: Make asyncio.__main__ reusable, also adding a preamble feature. type: enhancement versions: Python 3.10 Added file: https://bugs.python.org/file49652/__main__.py ___ Python tracker <https://bugs.python.org/issue42557> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue38237] Expose meaningful keyword arguments for pow()
Berry Schoenmakers added the comment: Maybe a use case in this direction: int(x, base=10). Because, if you type int(x='3', base=12) you get TypeError: 'x' is an invalid keyword argument for int() and x needs to be a positional-only to program this yourself. -- ___ Python tracker <https://bugs.python.org/issue38237> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue38237] Expose meaningful keyword arguments for pow()
Berry Schoenmakers added the comment: There seems to be a slight mixup with the built-in pow() function in Python 3.8.2. Currently, under https://docs.python.org/3/library/functions.html#pow it says: Changed in version 3.9: Allow keyword arguments. Formerly, only positional arguments were supported. I think this should be into "Changed in version 3.8 ... ", as pow(3,4, mod=5) actually works in Python 3.8.2. The "What’s New In Python 3.8" also needs to be changed accordingly. In https://docs.python.org/3/whatsnew/3.8.html#positional-only-parameters it says: One use case for this notation is that it allows pure Python functions to fully emulate behaviors of existing C coded functions. For example, the built-in pow() function does not accept keyword arguments: def pow(x, y, z=None, /): "Emulate the built in pow() function" r = x ** y return r if z is None else r%z This example can simply be dropped now. -- nosy: +lschoe ___ Python tracker <https://bugs.python.org/issue38237> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue38599] Deprecate creation of asyncio object when the loop is not running
Berry Schoenmakers added the comment: Well, I'm basically using a run method defined as a shorthand for self.loop.run_until_complete (without closing loop, reusing it throughout). It would be nice if asyncio.run could simply be used instead, but I understand you're saying this is easier said than done, which is fine with me. Thanks. -- ___ Python tracker <https://bugs.python.org/issue38599> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue38599] Deprecate creation of asyncio object when the loop is not running
Berry Schoenmakers added the comment: The current implementation of asyncio.run() is focused quite a bit on one-shot use. After the call returns, the default event loop is even gone: calling asyncio.get_event_loop() gives "RuntimeError: There is no current event loop in thread 'MainThread'." It would be nice if asyncio.run() uses the default loop if it's available (and not running), and that the default loop remains intact after the call returns. This way multiple calls to asyncio.run() that all use the default loop are supported, maybe using an asyncio.Queue (or whatever) across these calls---attaching everything to the same (default) loop. I find this very useful, for instance when writing unit tests. -- nosy: +lschoe ___ Python tracker <https://bugs.python.org/issue38599> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue36027] Support negative exponents in pow() where a modulus is specified.
Berry Schoenmakers added the comment: In pure Python this seems to be the better option to compute inverses: def modinv(a, m): # assuming m > 0 b = m s, s1 = 1, 0 while b: a, (q, b) = b, divmod(a, b) s, s1 = s1, s - q * s1 if a != 1: raise ValueError('inverse does not exist') return s if s >= 0 else s + m Binary xgcd algorithms coded in pure Python run much slower. -- ___ Python tracker <https://bugs.python.org/issue36027> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue36027] Consider adding modular multiplicative inverse to the math module
Berry Schoenmakers added the comment: > Is there a clear reason for your expectation that the xgcd-based algorithm > should be faster? Yeah, good question. Maybe I'm assuming too much, like assuming that it should be faster;) It may depend a lot on the constants indeed, but ultimately the xgcd style should prevail. So the pow-based algorithm needs to do log(p) full-size muls, plus log(p) modular reductions. Karatsuba helps a bit to speed up the muls, but as far as I know it only kicks in for quite sizeable inputs. I forgot how Python is dealing with the modular reductions, but presumably that's done without divisions. The xgcd-based algorithm needs to do a division per iteration, but the numbers are getting smaller over the course of the algorithm. And, the worst-case behavior occurs for things involving Fibonacci numbers only. In any case, the overall bit complexity is quadratic, even if division is quadratic. There may be a few expensive divisions along the way, but these also reduce the numbers a lot in size, which leads to good amortized complexity for each iteration. -- ___ Python tracker <https://bugs.python.org/issue36027> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue36027] Consider adding modular multiplicative inverse to the math module
Berry Schoenmakers added the comment: > ... to see `pow(a, p-2, p)` beat a pure Python xgcd for computing the inverse. OK, I'm indeed assuming that modinv() is implemented efficiently, in CPython, like pow() is. Then, it should be considerably faster, maybe like this: >>> timeit.timeit("gmpy2.invert(1023,p)", "import gmpy2; p=2**61-1") 0.18928535383349754 >>> timeit.timeit("gmpy2.invert(1023,p)", "import gmpy2; p=2**127-1") 0.290736872836419 >>> timeit.timeit("gmpy2.invert(1023,p)", "import gmpy2; p=2**521-1") 0.3317484429071 >>> timeit.timeit("gmpy2.powmod(1023,p-2,p)", "import gmpy2; p=2**61-1") 0.8771009990597349 >>> timeit.timeit("gmpy2.powmod(1023,p-2,p)", "import gmpy2; p=2**127-1") 3.460449585430979 >>> timeit.timeit("gmpy2.powmod(1023,p-2,p)", "import gmpy2; p=2**521-1") 84.3872797652 -- ___ Python tracker <https://bugs.python.org/issue36027> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue36027] Consider adding modular multiplicative inverse to the math module
Berry Schoenmakers added the comment: Agreed, extending pow(value, n, modulus) to negative n would be a great addition! To have modinv(value, modulus) next to that also makes a lot of sense to me, as this would avoid lots of confusion among users who are not so experienced with modular arithmetic. I know from working with generations of students and programmers how easy it is to make mistakes here (including lots of mistakes that I made myself;) One would implement pow() for negative n, anyway, by first computing the modular inverse and then raising it to the power -n. So, to expose the modinv() function to the outside world won't cost much effort. Modular powers, in particular, are often very confusing. Like for a prime modulus p, all of pow(a, -1,p), pow(a, p-2, p), pow(a, -p, p) are equal to eachother, but a common mistake is to take pow(a, p-1, p) instead. For a composite modulus things get much trickier still, as the exponent is then reduced in terms of the Euler phi function. And, even if you are not confused by these things, it's still a bit subtle that you have to use pow(a, -1,p) instead of pow(a, p-2, p) to let the modular inverse be computed efficiently. With modinv() available separately, one would expect --and get-- an efficient implementation with minimal overhead (e.g., not implemented via a complete extended-gcd). -- nosy: +lschoe ___ Python tracker <https://bugs.python.org/issue36027> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue35996] Optional modulus argument for new math.prod() function
Berry Schoenmakers added the comment: I had the same reservations but after rethinking it several times concluded that the modulus argument would fit really well. Indeed, Mathematica doesn't support the Modulus option for the Product[] function. But they don't even support it for the Power[] function, one needs to use PowerMod[] for that. Python has the extra option for its built-in pow(), and sensibly restricts this to the case of integer arguments only. To do modular arithmetic, even with big numbers, in Python is really nice and easy using the % operator. And it's all pretty efficient as well. The only exception where efficiency becomes an issue is the pow() function. To maintain that balance with the new prod() function around, the modulus argument would do the job. We can continue to do all modular arithmetic in a natural way, yielding programs that are perfectly readable and with very decent performance, now with prod() in the language as well. Taking larger modular products is a common thing to do in modern crypto, and Python is a popular platform for this. Next to the example of prod_i g[i]**s[i] mod z, which is like a Pedersen multi-commitment, it also arises when computing Lagrange coefficients (used in Shamir secret sharing) and related determinants for Vandermonde matrices. One would also be able to things like prod(range(1, n), n) == n - 1 for Wilson's primality test. (Extending the factorial() function with a modulus argument would be taking things too far, probably, but the modular version would now be available anyway via prod().) So, my feeling is that there are sufficiently many use cases around. And, I'm kind of assuming that it's not too much effort to add a modulus argument to prod(), but maybe that's not really the case. -- ___ Python tracker <https://bugs.python.org/issue35996> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue35996] Optional modulus argument for new math.prod() function
New submission from Berry Schoenmakers : It's nice to see the arrival of the prod() function, see PR11359. Just as for the built-in pow(x, y[, z]) function it would be very useful to have an optional argument z for computing integer products modulo z. Typical use case in cryptography would be: prod((pow(x, y, z) for x, y in zip(g, s)), z) to compute the product of all (potentially many) g[i]**s[i]'s modulo z. And, just as with the use of pow(), the intermediate values for prod() may in general grow quickly, hence modular reduction is essential to limit time and space usage. Maybe an interesting option to add at this stage? -- components: Library (Lib) messages: 335557 nosy: lschoe, rhettinger priority: normal severity: normal status: open title: Optional modulus argument for new math.prod() function type: performance versions: Python 3.8 ___ Python tracker <https://bugs.python.org/issue35996> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue35606] Add prod() function to the math module
Berry Schoenmakers added the comment: Thanks for the suggestion, Mark. I was not so sure, and the Nosy List for this issue is already quite extensive, so considered you guys as an appropriate audience for my first comment on this platform. But I will also look into opening a separate issue later today. -- ___ Python tracker <https://bugs.python.org/issue35606> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue35606] Add prod() function to the math module
Berry Schoenmakers added the comment: Nice to see the arrival of the prod() function. Just as for the built-in pow(x, y[, z]) function it would be very useful to have an optional argument z for computing products modulo z. Typical use case in cryptography would be: prod((pow(x, y, z) for x, y in zip(g, s)), z) to compute the product of all (potentially many) g[i]**s[i]'s modulo z. And, just as with the use of pow(), the intermediate values for prod() may in general grow quickly, hence modular reduction is essential to limit time and space usage. -- nosy: +lschoe ___ Python tracker <https://bugs.python.org/issue35606> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com