passagemath-objects 10.6.41__cp314-cp314t-macosx_13_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.
Potentially problematic release.
This version of passagemath-objects might be problematic. Click here for more details.
- passagemath_objects/.dylibs/libgmp.10.dylib +0 -0
- passagemath_objects/__init__.py +3 -0
- passagemath_objects-10.6.41.dist-info/METADATA +115 -0
- passagemath_objects-10.6.41.dist-info/RECORD +280 -0
- passagemath_objects-10.6.41.dist-info/WHEEL +6 -0
- passagemath_objects-10.6.41.dist-info/top_level.txt +3 -0
- sage/all__sagemath_objects.py +37 -0
- sage/arith/all__sagemath_objects.py +5 -0
- sage/arith/long.pxd +411 -0
- sage/arith/numerical_approx.cpython-314t-darwin.so +0 -0
- sage/arith/numerical_approx.pxd +35 -0
- sage/arith/numerical_approx.pyx +75 -0
- sage/arith/power.cpython-314t-darwin.so +0 -0
- sage/arith/power.pxd +31 -0
- sage/arith/power.pyx +127 -0
- sage/categories/action.cpython-314t-darwin.so +0 -0
- sage/categories/action.pxd +29 -0
- sage/categories/action.pyx +641 -0
- sage/categories/algebra_functor.py +745 -0
- sage/categories/all__sagemath_objects.py +33 -0
- sage/categories/basic.py +62 -0
- sage/categories/cartesian_product.py +295 -0
- sage/categories/category.py +3401 -0
- sage/categories/category_cy_helper.cpython-314t-darwin.so +0 -0
- sage/categories/category_cy_helper.pxd +8 -0
- sage/categories/category_cy_helper.pyx +322 -0
- sage/categories/category_singleton.cpython-314t-darwin.so +0 -0
- sage/categories/category_singleton.pxd +3 -0
- sage/categories/category_singleton.pyx +342 -0
- sage/categories/category_types.py +637 -0
- sage/categories/category_with_axiom.py +2876 -0
- sage/categories/covariant_functorial_construction.py +703 -0
- sage/categories/facade_sets.py +228 -0
- sage/categories/functor.cpython-314t-darwin.so +0 -0
- sage/categories/functor.pxd +7 -0
- sage/categories/functor.pyx +691 -0
- sage/categories/homset.py +1338 -0
- sage/categories/homsets.py +364 -0
- sage/categories/isomorphic_objects.py +73 -0
- sage/categories/map.cpython-314t-darwin.so +0 -0
- sage/categories/map.pxd +34 -0
- sage/categories/map.pyx +2112 -0
- sage/categories/morphism.cpython-314t-darwin.so +0 -0
- sage/categories/morphism.pxd +14 -0
- sage/categories/morphism.pyx +895 -0
- sage/categories/objects.py +167 -0
- sage/categories/primer.py +1696 -0
- sage/categories/pushout.py +4834 -0
- sage/categories/quotients.py +64 -0
- sage/categories/realizations.py +200 -0
- sage/categories/sets_cat.py +3228 -0
- sage/categories/sets_with_partial_maps.py +52 -0
- sage/categories/subobjects.py +64 -0
- sage/categories/subquotients.py +21 -0
- sage/categories/with_realizations.py +311 -0
- sage/cpython/__init__.py +19 -0
- sage/cpython/_py2_random.py +619 -0
- sage/cpython/all.py +3 -0
- sage/cpython/atexit.cpython-314t-darwin.so +0 -0
- sage/cpython/atexit.pyx +269 -0
- sage/cpython/builtin_types.cpython-314t-darwin.so +0 -0
- sage/cpython/builtin_types.pyx +7 -0
- sage/cpython/cython_metaclass.cpython-314t-darwin.so +0 -0
- sage/cpython/cython_metaclass.h +117 -0
- sage/cpython/cython_metaclass.pxd +3 -0
- sage/cpython/cython_metaclass.pyx +130 -0
- sage/cpython/debug.cpython-314t-darwin.so +0 -0
- sage/cpython/debug.pyx +302 -0
- sage/cpython/dict_del_by_value.cpython-314t-darwin.so +0 -0
- sage/cpython/dict_del_by_value.pxd +9 -0
- sage/cpython/dict_del_by_value.pyx +191 -0
- sage/cpython/dict_internal.h +245 -0
- sage/cpython/getattr.cpython-314t-darwin.so +0 -0
- sage/cpython/getattr.pxd +9 -0
- sage/cpython/getattr.pyx +439 -0
- sage/cpython/pycore_long.h +97 -0
- sage/cpython/pycore_long.pxd +10 -0
- sage/cpython/python_debug.h +44 -0
- sage/cpython/python_debug.pxd +47 -0
- sage/cpython/pyx_visit.h +13 -0
- sage/cpython/string.cpython-314t-darwin.so +0 -0
- sage/cpython/string.pxd +76 -0
- sage/cpython/string.pyx +34 -0
- sage/cpython/string_impl.h +60 -0
- sage/cpython/type.cpython-314t-darwin.so +0 -0
- sage/cpython/type.pxd +2 -0
- sage/cpython/type.pyx +40 -0
- sage/cpython/wrapperdescr.pxd +67 -0
- sage/ext/all__sagemath_objects.py +3 -0
- sage/ext/ccobject.h +64 -0
- sage/ext/cplusplus.pxd +17 -0
- sage/ext/mod_int.h +30 -0
- sage/ext/mod_int.pxd +24 -0
- sage/ext/stdsage.pxd +39 -0
- sage/groups/all__sagemath_objects.py +1 -0
- sage/groups/group.cpython-314t-darwin.so +0 -0
- sage/groups/group.pxd +14 -0
- sage/groups/group.pyx +322 -0
- sage/groups/old.cpython-314t-darwin.so +0 -0
- sage/groups/old.pxd +14 -0
- sage/groups/old.pyx +219 -0
- sage/libs/all__sagemath_objects.py +3 -0
- sage/libs/gmp/__init__.py +1 -0
- sage/libs/gmp/all.pxd +6 -0
- sage/libs/gmp/binop.pxd +23 -0
- sage/libs/gmp/misc.pxd +8 -0
- sage/libs/gmp/mpf.pxd +88 -0
- sage/libs/gmp/mpn.pxd +57 -0
- sage/libs/gmp/mpq.pxd +57 -0
- sage/libs/gmp/mpz.pxd +202 -0
- sage/libs/gmp/pylong.cpython-314t-darwin.so +0 -0
- sage/libs/gmp/pylong.pxd +12 -0
- sage/libs/gmp/pylong.pyx +150 -0
- sage/libs/gmp/random.pxd +25 -0
- sage/libs/gmp/randomize.pxd +59 -0
- sage/libs/gmp/types.pxd +53 -0
- sage/libs/gmpxx.pxd +19 -0
- sage/misc/abstract_method.py +276 -0
- sage/misc/all__sagemath_objects.py +43 -0
- sage/misc/bindable_class.py +253 -0
- sage/misc/c3_controlled.cpython-314t-darwin.so +0 -0
- sage/misc/c3_controlled.pxd +2 -0
- sage/misc/c3_controlled.pyx +1402 -0
- sage/misc/cachefunc.cpython-314t-darwin.so +0 -0
- sage/misc/cachefunc.pxd +43 -0
- sage/misc/cachefunc.pyx +3781 -0
- sage/misc/call.py +188 -0
- sage/misc/classcall_metaclass.cpython-314t-darwin.so +0 -0
- sage/misc/classcall_metaclass.pxd +14 -0
- sage/misc/classcall_metaclass.pyx +599 -0
- sage/misc/constant_function.cpython-314t-darwin.so +0 -0
- sage/misc/constant_function.pyx +130 -0
- sage/misc/decorators.py +747 -0
- sage/misc/fast_methods.cpython-314t-darwin.so +0 -0
- sage/misc/fast_methods.pxd +20 -0
- sage/misc/fast_methods.pyx +351 -0
- sage/misc/flatten.py +90 -0
- sage/misc/fpickle.cpython-314t-darwin.so +0 -0
- sage/misc/fpickle.pyx +177 -0
- sage/misc/function_mangling.cpython-314t-darwin.so +0 -0
- sage/misc/function_mangling.pxd +11 -0
- sage/misc/function_mangling.pyx +308 -0
- sage/misc/inherit_comparison.cpython-314t-darwin.so +0 -0
- sage/misc/inherit_comparison.pxd +5 -0
- sage/misc/inherit_comparison.pyx +105 -0
- sage/misc/instancedoc.cpython-314t-darwin.so +0 -0
- sage/misc/instancedoc.pyx +331 -0
- sage/misc/lazy_attribute.cpython-314t-darwin.so +0 -0
- sage/misc/lazy_attribute.pyx +607 -0
- sage/misc/lazy_format.py +135 -0
- sage/misc/lazy_import.cpython-314t-darwin.so +0 -0
- sage/misc/lazy_import.pyx +1299 -0
- sage/misc/lazy_import_cache.py +36 -0
- sage/misc/lazy_list.cpython-314t-darwin.so +0 -0
- sage/misc/lazy_list.pxd +19 -0
- sage/misc/lazy_list.pyx +1187 -0
- sage/misc/lazy_string.cpython-314t-darwin.so +0 -0
- sage/misc/lazy_string.pxd +7 -0
- sage/misc/lazy_string.pyx +546 -0
- sage/misc/misc.py +1066 -0
- sage/misc/misc_c.cpython-314t-darwin.so +0 -0
- sage/misc/misc_c.pxd +3 -0
- sage/misc/misc_c.pyx +766 -0
- sage/misc/namespace_package.py +37 -0
- sage/misc/nested_class.cpython-314t-darwin.so +0 -0
- sage/misc/nested_class.pxd +3 -0
- sage/misc/nested_class.pyx +394 -0
- sage/misc/persist.cpython-314t-darwin.so +0 -0
- sage/misc/persist.pyx +1251 -0
- sage/misc/prandom.py +418 -0
- sage/misc/randstate.cpython-314t-darwin.so +0 -0
- sage/misc/randstate.pxd +30 -0
- sage/misc/randstate.pyx +1059 -0
- sage/misc/repr.py +203 -0
- sage/misc/reset.cpython-314t-darwin.so +0 -0
- sage/misc/reset.pyx +196 -0
- sage/misc/sage_ostools.cpython-314t-darwin.so +0 -0
- sage/misc/sage_ostools.pyx +323 -0
- sage/misc/sage_timeit.py +276 -0
- sage/misc/sage_timeit_class.cpython-314t-darwin.so +0 -0
- sage/misc/sage_timeit_class.pyx +120 -0
- sage/misc/sage_unittest.py +637 -0
- sage/misc/sageinspect.py +2768 -0
- sage/misc/session.cpython-314t-darwin.so +0 -0
- sage/misc/session.pyx +392 -0
- sage/misc/superseded.py +557 -0
- sage/misc/test_nested_class.py +228 -0
- sage/misc/timing.py +264 -0
- sage/misc/unknown.py +222 -0
- sage/misc/verbose.py +253 -0
- sage/misc/weak_dict.cpython-314t-darwin.so +0 -0
- sage/misc/weak_dict.pxd +15 -0
- sage/misc/weak_dict.pyx +1231 -0
- sage/modules/all__sagemath_objects.py +1 -0
- sage/modules/module.cpython-314t-darwin.so +0 -0
- sage/modules/module.pxd +5 -0
- sage/modules/module.pyx +329 -0
- sage/rings/all__sagemath_objects.py +3 -0
- sage/rings/integer_fake.h +22 -0
- sage/rings/integer_fake.pxd +55 -0
- sage/sets/all__sagemath_objects.py +3 -0
- sage/sets/pythonclass.cpython-314t-darwin.so +0 -0
- sage/sets/pythonclass.pxd +9 -0
- sage/sets/pythonclass.pyx +247 -0
- sage/structure/__init__.py +4 -0
- sage/structure/all.py +30 -0
- sage/structure/category_object.cpython-314t-darwin.so +0 -0
- sage/structure/category_object.pxd +28 -0
- sage/structure/category_object.pyx +1087 -0
- sage/structure/coerce.cpython-314t-darwin.so +0 -0
- sage/structure/coerce.pxd +44 -0
- sage/structure/coerce.pyx +2107 -0
- sage/structure/coerce_actions.cpython-314t-darwin.so +0 -0
- sage/structure/coerce_actions.pxd +27 -0
- sage/structure/coerce_actions.pyx +988 -0
- sage/structure/coerce_dict.cpython-314t-darwin.so +0 -0
- sage/structure/coerce_dict.pxd +51 -0
- sage/structure/coerce_dict.pyx +1557 -0
- sage/structure/coerce_exceptions.py +23 -0
- sage/structure/coerce_maps.cpython-314t-darwin.so +0 -0
- sage/structure/coerce_maps.pxd +28 -0
- sage/structure/coerce_maps.pyx +718 -0
- sage/structure/debug_options.cpython-314t-darwin.so +0 -0
- sage/structure/debug_options.pxd +6 -0
- sage/structure/debug_options.pyx +54 -0
- sage/structure/dynamic_class.py +541 -0
- sage/structure/element.cpython-314t-darwin.so +0 -0
- sage/structure/element.pxd +272 -0
- sage/structure/element.pyx +4772 -0
- sage/structure/element_wrapper.cpython-314t-darwin.so +0 -0
- sage/structure/element_wrapper.pxd +12 -0
- sage/structure/element_wrapper.pyx +582 -0
- sage/structure/factorization.py +1422 -0
- sage/structure/factorization_integer.py +105 -0
- sage/structure/factory.cpython-314t-darwin.so +0 -0
- sage/structure/factory.pyx +786 -0
- sage/structure/formal_sum.py +489 -0
- sage/structure/gens_py.py +73 -0
- sage/structure/global_options.py +1743 -0
- sage/structure/indexed_generators.py +863 -0
- sage/structure/list_clone.cpython-314t-darwin.so +0 -0
- sage/structure/list_clone.pxd +65 -0
- sage/structure/list_clone.pyx +1867 -0
- sage/structure/list_clone_demo.cpython-314t-darwin.so +0 -0
- sage/structure/list_clone_demo.pyx +248 -0
- sage/structure/list_clone_timings.py +179 -0
- sage/structure/list_clone_timings_cy.cpython-314t-darwin.so +0 -0
- sage/structure/list_clone_timings_cy.pyx +86 -0
- sage/structure/mutability.cpython-314t-darwin.so +0 -0
- sage/structure/mutability.pxd +21 -0
- sage/structure/mutability.pyx +348 -0
- sage/structure/nonexact.py +69 -0
- sage/structure/parent.cpython-314t-darwin.so +0 -0
- sage/structure/parent.pxd +112 -0
- sage/structure/parent.pyx +3093 -0
- sage/structure/parent_base.cpython-314t-darwin.so +0 -0
- sage/structure/parent_base.pxd +13 -0
- sage/structure/parent_base.pyx +44 -0
- sage/structure/parent_gens.cpython-314t-darwin.so +0 -0
- sage/structure/parent_gens.pxd +22 -0
- sage/structure/parent_gens.pyx +377 -0
- sage/structure/parent_old.cpython-314t-darwin.so +0 -0
- sage/structure/parent_old.pxd +25 -0
- sage/structure/parent_old.pyx +294 -0
- sage/structure/proof/__init__.py +1 -0
- sage/structure/proof/all.py +243 -0
- sage/structure/proof/proof.py +300 -0
- sage/structure/richcmp.cpython-314t-darwin.so +0 -0
- sage/structure/richcmp.pxd +213 -0
- sage/structure/richcmp.pyx +495 -0
- sage/structure/sage_object.cpython-314t-darwin.so +0 -0
- sage/structure/sage_object.pxd +3 -0
- sage/structure/sage_object.pyx +988 -0
- sage/structure/sage_object_test.py +19 -0
- sage/structure/sequence.py +937 -0
- sage/structure/set_factories.py +1178 -0
- sage/structure/set_factories_example.py +527 -0
- sage/structure/support_view.py +179 -0
- sage/structure/test_factory.py +56 -0
- sage/structure/unique_representation.py +1359 -0
sage/misc/misc.py
ADDED
|
@@ -0,0 +1,1066 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-objects
|
|
2
|
+
"""
|
|
3
|
+
Miscellaneous functions
|
|
4
|
+
|
|
5
|
+
AUTHORS:
|
|
6
|
+
|
|
7
|
+
- William Stein
|
|
8
|
+
|
|
9
|
+
- William Stein (2006-04-26): added workaround for Windows where most
|
|
10
|
+
users' home directory has a space in it.
|
|
11
|
+
|
|
12
|
+
- Robert Bradshaw (2007-09-20): Ellipsis range/iterator.
|
|
13
|
+
|
|
14
|
+
TESTS:
|
|
15
|
+
|
|
16
|
+
The following test, verifying that :issue:`16181` has been resolved, needs
|
|
17
|
+
to stay at the beginning of this file so that its context is not
|
|
18
|
+
poisoned by other tests::
|
|
19
|
+
|
|
20
|
+
sage: sage.misc.misc.inject_variable('a', 0)
|
|
21
|
+
sage: a
|
|
22
|
+
0
|
|
23
|
+
|
|
24
|
+
Check the fix from :issue:`8323`::
|
|
25
|
+
|
|
26
|
+
sage: 'name' in globals()
|
|
27
|
+
False
|
|
28
|
+
sage: 'func' in globals()
|
|
29
|
+
False
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
# ****************************************************************************
|
|
33
|
+
# Copyright (C) 2006 William Stein <wstein@gmail.com>
|
|
34
|
+
#
|
|
35
|
+
# This program is free software: you can redistribute it and/or modify
|
|
36
|
+
# it under the terms of the GNU General Public License as published by
|
|
37
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
38
|
+
# (at your option) any later version.
|
|
39
|
+
# https://www.gnu.org/licenses/
|
|
40
|
+
# ****************************************************************************
|
|
41
|
+
|
|
42
|
+
import contextlib
|
|
43
|
+
import functools
|
|
44
|
+
import os
|
|
45
|
+
import pdb
|
|
46
|
+
import sys
|
|
47
|
+
import warnings
|
|
48
|
+
|
|
49
|
+
from sage.env import DOT_SAGE, HOSTNAME
|
|
50
|
+
from sage.misc.lazy_import import lazy_import
|
|
51
|
+
|
|
52
|
+
lazy_import("sage.combinat.subset", ["powerset", "subsets", "uniq"],
|
|
53
|
+
deprecation=35564)
|
|
54
|
+
|
|
55
|
+
lazy_import(
|
|
56
|
+
"sage.misc.timing", ["cputime", "GlobalCputime", "walltime"],
|
|
57
|
+
deprecation=35816
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
LOCAL_IDENTIFIER = '%s.%s' % (HOSTNAME, os.getpid())
|
|
61
|
+
|
|
62
|
+
#################################################################
|
|
63
|
+
# File and directory utilities
|
|
64
|
+
#################################################################
|
|
65
|
+
|
|
66
|
+
# We create the DOT_SAGE directory (if it does not exist yet; note in particular
|
|
67
|
+
# that it may already have been created by the bin/sage script) with
|
|
68
|
+
# restrictive permissions, since otherwise possibly just anybody can easily see
|
|
69
|
+
# every command you type.
|
|
70
|
+
|
|
71
|
+
os.makedirs(DOT_SAGE, mode=0o700, exist_ok=True)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def try_read(obj, splitlines=False):
|
|
75
|
+
r"""
|
|
76
|
+
Determine if a given object is a readable file-like object and if so
|
|
77
|
+
read and return its contents.
|
|
78
|
+
|
|
79
|
+
That is, the object has a callable method named ``read()`` which takes
|
|
80
|
+
no arguments (except ``self``) then the method is executed and the
|
|
81
|
+
contents are returned.
|
|
82
|
+
|
|
83
|
+
Alternatively, if the ``splitlines=True`` is given, first ``splitlines()``
|
|
84
|
+
is tried, then if that fails ``read().splitlines()``.
|
|
85
|
+
|
|
86
|
+
If either method fails, ``None`` is returned.
|
|
87
|
+
|
|
88
|
+
INPUT:
|
|
89
|
+
|
|
90
|
+
- ``obj`` -- typically a `file` or `io.BaseIO` object, but any other
|
|
91
|
+
object with a ``read()`` method is accepted
|
|
92
|
+
|
|
93
|
+
- ``splitlines`` -- boolean (default: ``False``); if ``True``, return a
|
|
94
|
+
list of lines instead of a string
|
|
95
|
+
|
|
96
|
+
EXAMPLES::
|
|
97
|
+
|
|
98
|
+
sage: import io
|
|
99
|
+
sage: filename = tmp_filename()
|
|
100
|
+
sage: from sage.misc.misc import try_read
|
|
101
|
+
sage: with open(filename, 'w') as fobj:
|
|
102
|
+
....: _ = fobj.write('a\nb\nc')
|
|
103
|
+
sage: with open(filename) as fobj:
|
|
104
|
+
....: print(try_read(fobj))
|
|
105
|
+
a
|
|
106
|
+
b
|
|
107
|
+
c
|
|
108
|
+
sage: with open(filename) as fobj:
|
|
109
|
+
....: try_read(fobj, splitlines=True)
|
|
110
|
+
['a\n', 'b\n', 'c']
|
|
111
|
+
|
|
112
|
+
The following example is identical to the above example on Python 3,
|
|
113
|
+
but different on Python 2 where ``open != io.open``::
|
|
114
|
+
|
|
115
|
+
sage: with io.open(filename) as fobj:
|
|
116
|
+
....: print(try_read(fobj))
|
|
117
|
+
a
|
|
118
|
+
b
|
|
119
|
+
c
|
|
120
|
+
|
|
121
|
+
I/O buffers::
|
|
122
|
+
|
|
123
|
+
sage: buf = io.StringIO('a\nb\nc')
|
|
124
|
+
sage: print(try_read(buf))
|
|
125
|
+
a
|
|
126
|
+
b
|
|
127
|
+
c
|
|
128
|
+
sage: _ = buf.seek(0); try_read(buf, splitlines=True)
|
|
129
|
+
['a\n', 'b\n', 'c']
|
|
130
|
+
sage: buf = io.BytesIO(b'a\nb\nc')
|
|
131
|
+
sage: try_read(buf) == b'a\nb\nc'
|
|
132
|
+
True
|
|
133
|
+
sage: _ = buf.seek(0)
|
|
134
|
+
sage: try_read(buf, splitlines=True) == [b'a\n', b'b\n', b'c']
|
|
135
|
+
True
|
|
136
|
+
|
|
137
|
+
Custom readable::
|
|
138
|
+
|
|
139
|
+
sage: class MyFile():
|
|
140
|
+
....: def read(self): return 'Hello world!'
|
|
141
|
+
sage: try_read(MyFile())
|
|
142
|
+
'Hello world!'
|
|
143
|
+
sage: try_read(MyFile(), splitlines=True)
|
|
144
|
+
['Hello world!']
|
|
145
|
+
|
|
146
|
+
Not readable::
|
|
147
|
+
|
|
148
|
+
sage: try_read(1) is None
|
|
149
|
+
True
|
|
150
|
+
"""
|
|
151
|
+
|
|
152
|
+
if splitlines:
|
|
153
|
+
try:
|
|
154
|
+
return obj.readlines()
|
|
155
|
+
except (AttributeError, TypeError):
|
|
156
|
+
pass
|
|
157
|
+
|
|
158
|
+
try:
|
|
159
|
+
data = obj.read()
|
|
160
|
+
except (AttributeError, TypeError):
|
|
161
|
+
return
|
|
162
|
+
|
|
163
|
+
if splitlines:
|
|
164
|
+
try:
|
|
165
|
+
data = data.splitlines()
|
|
166
|
+
except (AttributeError, TypeError):
|
|
167
|
+
# Not a string??
|
|
168
|
+
data = [data]
|
|
169
|
+
|
|
170
|
+
return data
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
try:
|
|
174
|
+
# Create the matplotlib config directory.
|
|
175
|
+
os.makedirs(os.environ["MPLCONFIGDIR"], exist_ok=True)
|
|
176
|
+
except KeyError:
|
|
177
|
+
pass
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def exactly_one_is_true(iterable):
|
|
181
|
+
r"""
|
|
182
|
+
Return whether exactly one element of ``iterable`` evaluates ``True``.
|
|
183
|
+
|
|
184
|
+
INPUT:
|
|
185
|
+
|
|
186
|
+
- ``iterable`` -- an iterable object
|
|
187
|
+
|
|
188
|
+
OUTPUT: boolean
|
|
189
|
+
|
|
190
|
+
.. NOTE::
|
|
191
|
+
|
|
192
|
+
The implementation is suggested by
|
|
193
|
+
`stackoverflow entry <https://stackoverflow.com/a/16801605/1052778>`_.
|
|
194
|
+
|
|
195
|
+
EXAMPLES::
|
|
196
|
+
|
|
197
|
+
sage: from sage.misc.misc import exactly_one_is_true
|
|
198
|
+
sage: exactly_one_is_true([])
|
|
199
|
+
False
|
|
200
|
+
sage: exactly_one_is_true([True])
|
|
201
|
+
True
|
|
202
|
+
sage: exactly_one_is_true([False])
|
|
203
|
+
False
|
|
204
|
+
sage: exactly_one_is_true([True, True])
|
|
205
|
+
False
|
|
206
|
+
sage: exactly_one_is_true([False, True])
|
|
207
|
+
True
|
|
208
|
+
sage: exactly_one_is_true([True, False, True])
|
|
209
|
+
False
|
|
210
|
+
sage: exactly_one_is_true([False, True, False])
|
|
211
|
+
True
|
|
212
|
+
"""
|
|
213
|
+
it = iter(iterable)
|
|
214
|
+
return any(it) and not any(it)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def strunc(s, n=60):
|
|
218
|
+
"""
|
|
219
|
+
Truncate at first space after position n, adding '...' if
|
|
220
|
+
nontrivial truncation.
|
|
221
|
+
"""
|
|
222
|
+
n = int(n)
|
|
223
|
+
s = str(s)
|
|
224
|
+
if len(s) > n:
|
|
225
|
+
i = n
|
|
226
|
+
while i < len(s) and s[i] != ' ':
|
|
227
|
+
i += 1
|
|
228
|
+
return s[:i] + " ..."
|
|
229
|
+
return s
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def newton_method_sizes(N):
|
|
233
|
+
r"""
|
|
234
|
+
Return a sequence of integers
|
|
235
|
+
`1 = a_1 \leq a_2 \leq \cdots \leq a_n = N` such that
|
|
236
|
+
`a_j = \lceil a_{j+1} / 2 \rceil` for all `j`.
|
|
237
|
+
|
|
238
|
+
This is useful for Newton-style algorithms that double the
|
|
239
|
+
precision at each stage. For example if you start at precision 1
|
|
240
|
+
and want an answer to precision 17, then it's better to use the
|
|
241
|
+
intermediate stages 1, 2, 3, 5, 9, 17 than to use 1, 2, 4, 8, 16,
|
|
242
|
+
17.
|
|
243
|
+
|
|
244
|
+
INPUT:
|
|
245
|
+
|
|
246
|
+
- ``N`` -- positive integer
|
|
247
|
+
|
|
248
|
+
EXAMPLES::
|
|
249
|
+
|
|
250
|
+
sage: newton_method_sizes(17)
|
|
251
|
+
[1, 2, 3, 5, 9, 17]
|
|
252
|
+
sage: newton_method_sizes(16)
|
|
253
|
+
[1, 2, 4, 8, 16]
|
|
254
|
+
sage: newton_method_sizes(1)
|
|
255
|
+
[1]
|
|
256
|
+
|
|
257
|
+
AUTHORS:
|
|
258
|
+
|
|
259
|
+
- David Harvey (2006-09-09)
|
|
260
|
+
"""
|
|
261
|
+
|
|
262
|
+
N = int(N)
|
|
263
|
+
if N < 1:
|
|
264
|
+
raise ValueError("N (={}) must be a positive integer".format(N))
|
|
265
|
+
|
|
266
|
+
output = []
|
|
267
|
+
while N > 1:
|
|
268
|
+
output.append(N)
|
|
269
|
+
N = (N + 1) >> 1
|
|
270
|
+
|
|
271
|
+
output.append(1)
|
|
272
|
+
output.reverse()
|
|
273
|
+
return output
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
#################################################################
|
|
277
|
+
# Generally useful
|
|
278
|
+
#################################################################
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def compose(f, g):
|
|
282
|
+
r"""
|
|
283
|
+
Return the composition of one-variable functions: `f \circ g`.
|
|
284
|
+
|
|
285
|
+
See also :func:`nest()`
|
|
286
|
+
|
|
287
|
+
INPUT:
|
|
288
|
+
|
|
289
|
+
- ``f`` -- a function of one variable
|
|
290
|
+
- ``g`` -- another function of one variable
|
|
291
|
+
|
|
292
|
+
OUTPUT: a function, such that compose(f,g)(x) = f(g(x))
|
|
293
|
+
|
|
294
|
+
EXAMPLES::
|
|
295
|
+
|
|
296
|
+
sage: def g(x): return 3*x
|
|
297
|
+
sage: def f(x): return x + 1
|
|
298
|
+
sage: h1 = compose(f, g)
|
|
299
|
+
sage: h2 = compose(g, f)
|
|
300
|
+
sage: _ = var('x') # needs sage.symbolic
|
|
301
|
+
sage: h1(x) # needs sage.symbolic
|
|
302
|
+
3*x + 1
|
|
303
|
+
sage: h2(x) # needs sage.symbolic
|
|
304
|
+
3*x + 3
|
|
305
|
+
|
|
306
|
+
::
|
|
307
|
+
|
|
308
|
+
sage: _ = function('f g') # needs sage.symbolic
|
|
309
|
+
sage: _ = var('x') # needs sage.symbolic
|
|
310
|
+
sage: compose(f, g)(x) # needs sage.symbolic
|
|
311
|
+
f(g(x))
|
|
312
|
+
"""
|
|
313
|
+
return lambda x: f(g(x))
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def nest(f, n, x):
|
|
317
|
+
"""
|
|
318
|
+
Return `f(f(...f(x)...))`, where the composition occurs n times.
|
|
319
|
+
|
|
320
|
+
See also :func:`compose()` and :func:`self_compose()`
|
|
321
|
+
|
|
322
|
+
INPUT:
|
|
323
|
+
|
|
324
|
+
- ``f`` -- a function of one variable
|
|
325
|
+
- ``n`` -- nonnegative integer
|
|
326
|
+
- ``x`` -- any input for `f`
|
|
327
|
+
|
|
328
|
+
OUTPUT: `f(f(...f(x)...))`, where the composition occurs n times
|
|
329
|
+
|
|
330
|
+
EXAMPLES::
|
|
331
|
+
|
|
332
|
+
sage: def f(x): return x^2 + 1
|
|
333
|
+
sage: x = var('x') # needs sage.symbolic
|
|
334
|
+
sage: nest(f, 3, x) # needs sage.symbolic
|
|
335
|
+
((x^2 + 1)^2 + 1)^2 + 1
|
|
336
|
+
|
|
337
|
+
::
|
|
338
|
+
|
|
339
|
+
sage: _ = function('f') # needs sage.symbolic
|
|
340
|
+
sage: _ = var('x') # needs sage.symbolic
|
|
341
|
+
sage: nest(f, 10, x) # needs sage.symbolic
|
|
342
|
+
f(f(f(f(f(f(f(f(f(f(x))))))))))
|
|
343
|
+
|
|
344
|
+
::
|
|
345
|
+
|
|
346
|
+
sage: _ = function('f') # needs sage.symbolic
|
|
347
|
+
sage: _ = var('x') # needs sage.symbolic
|
|
348
|
+
sage: nest(f, 0, x) # needs sage.symbolic
|
|
349
|
+
x
|
|
350
|
+
"""
|
|
351
|
+
from sage.rings.integer import Integer
|
|
352
|
+
|
|
353
|
+
n = Integer(n)
|
|
354
|
+
|
|
355
|
+
if n < 0:
|
|
356
|
+
raise ValueError("n must be a nonnegative integer, not {}.".format(n))
|
|
357
|
+
|
|
358
|
+
for i in range(n):
|
|
359
|
+
x = f(x)
|
|
360
|
+
return x
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
#################################################################
|
|
364
|
+
# The A \ b operator
|
|
365
|
+
#################################################################
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
class BackslashOperator:
|
|
369
|
+
r"""
|
|
370
|
+
Implement Matlab-style backslash operator for solving systems::
|
|
371
|
+
|
|
372
|
+
A \ b
|
|
373
|
+
|
|
374
|
+
The preparser converts this to multiplications using
|
|
375
|
+
``BackslashOperator()``.
|
|
376
|
+
|
|
377
|
+
EXAMPLES::
|
|
378
|
+
|
|
379
|
+
sage: preparse("A \\ matrix(QQ,2,1,[1/3,'2/3'])")
|
|
380
|
+
"A * BackslashOperator() * matrix(QQ,Integer(2),Integer(1),[Integer(1)/Integer(3),'2/3'])"
|
|
381
|
+
sage: preparse("A \\ matrix(QQ,2,1,[1/3,2*3])")
|
|
382
|
+
'A * BackslashOperator() * matrix(QQ,Integer(2),Integer(1),[Integer(1)/Integer(3),Integer(2)*Integer(3)])'
|
|
383
|
+
sage: preparse("A \\ B + C")
|
|
384
|
+
'A * BackslashOperator() * B + C'
|
|
385
|
+
sage: preparse("A \\ eval('C+D')")
|
|
386
|
+
"A * BackslashOperator() * eval('C+D')"
|
|
387
|
+
sage: preparse("A \\ x / 5")
|
|
388
|
+
'A * BackslashOperator() * x / Integer(5)'
|
|
389
|
+
sage: preparse("A^3 \\ b")
|
|
390
|
+
'A**Integer(3) * BackslashOperator() * b'
|
|
391
|
+
"""
|
|
392
|
+
|
|
393
|
+
def __rmul__(self, left):
|
|
394
|
+
"""
|
|
395
|
+
EXAMPLES::
|
|
396
|
+
|
|
397
|
+
sage: # needs sage.modules
|
|
398
|
+
sage: A = random_matrix(ZZ, 4)
|
|
399
|
+
sage: while A.rank() != 4:
|
|
400
|
+
....: A = random_matrix(ZZ, 4)
|
|
401
|
+
sage: B = random_matrix(ZZ, 4)
|
|
402
|
+
sage: temp = A * BackslashOperator()
|
|
403
|
+
doctest:...:
|
|
404
|
+
DeprecationWarning: the backslash operator has been deprecated
|
|
405
|
+
See https://github.com/sagemath/sage/issues/36394 for details.
|
|
406
|
+
sage: temp.left is A
|
|
407
|
+
True
|
|
408
|
+
sage: X = temp * B
|
|
409
|
+
doctest:...:
|
|
410
|
+
DeprecationWarning: the backslash operator has been deprecated; use A.solve_right(B) instead
|
|
411
|
+
See https://github.com/sagemath/sage/issues/36394 for details.
|
|
412
|
+
sage: A * X == B
|
|
413
|
+
True
|
|
414
|
+
"""
|
|
415
|
+
from sage.misc.superseded import deprecation
|
|
416
|
+
|
|
417
|
+
deprecation(36394, 'the backslash operator has been deprecated')
|
|
418
|
+
self.left = left
|
|
419
|
+
return self
|
|
420
|
+
|
|
421
|
+
def __mul__(self, right):
|
|
422
|
+
r"""
|
|
423
|
+
EXAMPLES::
|
|
424
|
+
|
|
425
|
+
sage: # needs scipy sage.modules
|
|
426
|
+
sage: A = matrix(RDF, 5, 5, 2)
|
|
427
|
+
sage: b = vector(RDF, 5, range(5))
|
|
428
|
+
sage: v = A \ b
|
|
429
|
+
doctest:...:
|
|
430
|
+
DeprecationWarning: the backslash operator has been deprecated; use A.solve_right(B) instead
|
|
431
|
+
See https://github.com/sagemath/sage/issues/36394 for details.
|
|
432
|
+
sage: v.zero_at(1e-19) # On at least one platform, we get a "negative zero"
|
|
433
|
+
(0.0, 0.5, 1.0, 1.5, 2.0)
|
|
434
|
+
sage: v = A._backslash_(b)
|
|
435
|
+
doctest:...:
|
|
436
|
+
DeprecationWarning: the backslash operator has been deprecated; use A.solve_right(B) instead
|
|
437
|
+
See https://github.com/sagemath/sage/issues/36394 for details.
|
|
438
|
+
sage: v.zero_at(1e-19)
|
|
439
|
+
(0.0, 0.5, 1.0, 1.5, 2.0)
|
|
440
|
+
sage: v = A * BackslashOperator() * b
|
|
441
|
+
doctest:...:
|
|
442
|
+
DeprecationWarning: the backslash operator has been deprecated; use A.solve_right(B) instead
|
|
443
|
+
See https://github.com/sagemath/sage/issues/36394 for details.
|
|
444
|
+
sage: v.zero_at(1e-19)
|
|
445
|
+
(0.0, 0.5, 1.0, 1.5, 2.0)
|
|
446
|
+
"""
|
|
447
|
+
from sage.misc.superseded import deprecation
|
|
448
|
+
|
|
449
|
+
deprecation(36394, 'the backslash operator has been deprecated')
|
|
450
|
+
return self.left._backslash_(right)
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
#################################################################
|
|
454
|
+
# is_iterator function
|
|
455
|
+
#################################################################
|
|
456
|
+
def is_iterator(it) -> bool:
|
|
457
|
+
"""
|
|
458
|
+
Test if it is an iterator.
|
|
459
|
+
|
|
460
|
+
The mantra ``if hasattr(it, 'next')`` was used to tests if ``it`` is an
|
|
461
|
+
iterator. This is not quite correct since ``it`` could have a ``next``
|
|
462
|
+
methods with a different semantic.
|
|
463
|
+
|
|
464
|
+
EXAMPLES::
|
|
465
|
+
|
|
466
|
+
sage: it = iter([1,2,3])
|
|
467
|
+
sage: is_iterator(it)
|
|
468
|
+
True
|
|
469
|
+
|
|
470
|
+
sage: class wrong():
|
|
471
|
+
....: def __init__(self): self.n = 5
|
|
472
|
+
....: def __next__(self):
|
|
473
|
+
....: self.n -= 1
|
|
474
|
+
....: if self.n == 0: raise StopIteration
|
|
475
|
+
....: return self.n
|
|
476
|
+
sage: x = wrong()
|
|
477
|
+
sage: is_iterator(x)
|
|
478
|
+
False
|
|
479
|
+
sage: list(x)
|
|
480
|
+
Traceback (most recent call last):
|
|
481
|
+
...
|
|
482
|
+
TypeError: 'wrong' object is not iterable
|
|
483
|
+
|
|
484
|
+
sage: class good(wrong):
|
|
485
|
+
....: def __iter__(self): return self
|
|
486
|
+
sage: x = good()
|
|
487
|
+
sage: is_iterator(x)
|
|
488
|
+
True
|
|
489
|
+
sage: list(x)
|
|
490
|
+
[4, 3, 2, 1]
|
|
491
|
+
|
|
492
|
+
sage: P = Partitions(3)
|
|
493
|
+
sage: is_iterator(P)
|
|
494
|
+
False
|
|
495
|
+
sage: is_iterator(iter(P))
|
|
496
|
+
True
|
|
497
|
+
"""
|
|
498
|
+
# see trac #7398 for a discussion
|
|
499
|
+
try:
|
|
500
|
+
return it is iter(it)
|
|
501
|
+
except Exception:
|
|
502
|
+
return False
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
#################################################################
|
|
506
|
+
# Useful but hard to classify
|
|
507
|
+
#################################################################
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
def random_sublist(X, s):
|
|
511
|
+
"""
|
|
512
|
+
Return a pseudo-random sublist of the list X where the probability
|
|
513
|
+
of including a particular element is s.
|
|
514
|
+
|
|
515
|
+
INPUT:
|
|
516
|
+
|
|
517
|
+
- ``X`` -- list
|
|
518
|
+
|
|
519
|
+
- ``s`` -- floating point number between 0 and 1
|
|
520
|
+
|
|
521
|
+
OUTPUT: list
|
|
522
|
+
|
|
523
|
+
EXAMPLES::
|
|
524
|
+
|
|
525
|
+
sage: from sage.misc.misc import is_sublist
|
|
526
|
+
sage: S = [1,7,3,4,18]
|
|
527
|
+
sage: sublist = random_sublist(S, 0.5); sublist # random
|
|
528
|
+
[1, 3, 4]
|
|
529
|
+
sage: is_sublist(sublist, S)
|
|
530
|
+
True
|
|
531
|
+
sage: sublist = random_sublist(S, 0.5); sublist # random
|
|
532
|
+
[1, 3]
|
|
533
|
+
sage: is_sublist(sublist, S)
|
|
534
|
+
True
|
|
535
|
+
"""
|
|
536
|
+
import sage.misc.prandom as random
|
|
537
|
+
|
|
538
|
+
return [a for a in X if random.random() <= s]
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
def is_sublist(X, Y):
|
|
542
|
+
"""
|
|
543
|
+
Test whether ``X`` is a sublist of ``Y``.
|
|
544
|
+
|
|
545
|
+
EXAMPLES::
|
|
546
|
+
|
|
547
|
+
sage: from sage.misc.misc import is_sublist
|
|
548
|
+
sage: S = [1, 7, 3, 4, 18]
|
|
549
|
+
sage: is_sublist([1, 7], S)
|
|
550
|
+
True
|
|
551
|
+
sage: is_sublist([1, 3, 4], S)
|
|
552
|
+
True
|
|
553
|
+
sage: is_sublist([1, 4, 3], S)
|
|
554
|
+
False
|
|
555
|
+
sage: is_sublist(S, S)
|
|
556
|
+
True
|
|
557
|
+
"""
|
|
558
|
+
X_i = 0
|
|
559
|
+
for Y_i, y in enumerate(Y):
|
|
560
|
+
if X_i == len(X):
|
|
561
|
+
return True
|
|
562
|
+
if y == X[X_i]:
|
|
563
|
+
X_i += 1
|
|
564
|
+
return X_i == len(X)
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
def some_tuples(elements, repeat, bound, max_samples=None):
|
|
568
|
+
r"""
|
|
569
|
+
Return an iterator over at most ``bound`` number of ``repeat``-tuples of
|
|
570
|
+
``elements``.
|
|
571
|
+
|
|
572
|
+
INPUT:
|
|
573
|
+
|
|
574
|
+
- ``elements`` -- an iterable
|
|
575
|
+
- ``repeat`` -- integer (default: ``None``); the length of the tuples to be returned.
|
|
576
|
+
If ``None``, just returns entries from ``elements``.
|
|
577
|
+
- ``bound`` -- the maximum number of tuples returned (ignored if ``max_samples`` given)
|
|
578
|
+
- ``max_samples`` -- nonnegative integer (default: ``None``); if given,
|
|
579
|
+
then a sample of the possible tuples will be returned,
|
|
580
|
+
instead of the first few in the standard order
|
|
581
|
+
|
|
582
|
+
OUTPUT:
|
|
583
|
+
|
|
584
|
+
If ``max_samples`` is not provided, an iterator over the first
|
|
585
|
+
``bound`` tuples of length ``repeat``, in the standard nested-for-loop order.
|
|
586
|
+
|
|
587
|
+
If ``max_samples`` is provided, a list of at most ``max_samples`` tuples,
|
|
588
|
+
sampled uniformly from the possibilities. In this case, ``elements``
|
|
589
|
+
must be finite.
|
|
590
|
+
|
|
591
|
+
TESTS::
|
|
592
|
+
|
|
593
|
+
sage: from sage.misc.misc import some_tuples
|
|
594
|
+
sage: l = some_tuples([0,1,2,3], 2, 3)
|
|
595
|
+
sage: l
|
|
596
|
+
<itertools.islice object at ...>
|
|
597
|
+
sage: len(list(l))
|
|
598
|
+
3
|
|
599
|
+
|
|
600
|
+
sage: l = some_tuples(range(50), 3, 10)
|
|
601
|
+
sage: len(list(l))
|
|
602
|
+
10
|
|
603
|
+
|
|
604
|
+
sage: l = some_tuples(range(3), 2, None, max_samples=10)
|
|
605
|
+
sage: len(list(l))
|
|
606
|
+
9
|
|
607
|
+
"""
|
|
608
|
+
if max_samples is None:
|
|
609
|
+
from itertools import islice, product
|
|
610
|
+
|
|
611
|
+
P = elements if repeat is None else product(elements, repeat=repeat)
|
|
612
|
+
return islice(P, int(bound))
|
|
613
|
+
else:
|
|
614
|
+
if not (hasattr(elements, '__len__') and hasattr(elements, '__getitem__')):
|
|
615
|
+
elements = list(elements)
|
|
616
|
+
n = len(elements)
|
|
617
|
+
N = n if repeat is None else n**repeat
|
|
618
|
+
if N <= max_samples:
|
|
619
|
+
from itertools import product
|
|
620
|
+
|
|
621
|
+
return elements if repeat is None else product(elements, repeat=repeat)
|
|
622
|
+
return _some_tuples_sampling(elements, repeat, max_samples, n)
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
def _some_tuples_sampling(elements, repeat, max_samples, n):
|
|
626
|
+
"""
|
|
627
|
+
Internal function for :func:`some_tuples`.
|
|
628
|
+
|
|
629
|
+
TESTS::
|
|
630
|
+
|
|
631
|
+
sage: from sage.misc.misc import _some_tuples_sampling
|
|
632
|
+
sage: l = list(_some_tuples_sampling(range(3), 3, 2, 3))
|
|
633
|
+
sage: len(l)
|
|
634
|
+
2
|
|
635
|
+
sage: all(len(tup) == 3 for tup in l)
|
|
636
|
+
True
|
|
637
|
+
sage: all(el in range(3) for tup in l for el in tup)
|
|
638
|
+
True
|
|
639
|
+
sage: l = list(_some_tuples_sampling(range(20), None, 4, 20))
|
|
640
|
+
sage: len(l)
|
|
641
|
+
4
|
|
642
|
+
sage: all(el in range(20) for el in l)
|
|
643
|
+
True
|
|
644
|
+
"""
|
|
645
|
+
from sage.rings.integer import Integer
|
|
646
|
+
import sage.misc.prandom as random
|
|
647
|
+
|
|
648
|
+
N = n if repeat is None else n**repeat
|
|
649
|
+
# We sample on range(N) and create tuples manually since we don't want to create the list of all possible tuples in memory
|
|
650
|
+
for a in random.sample(range(N), max_samples):
|
|
651
|
+
if repeat is None:
|
|
652
|
+
yield elements[a]
|
|
653
|
+
else:
|
|
654
|
+
yield tuple(elements[j] for j in Integer(a).digits(n, padto=repeat))
|
|
655
|
+
|
|
656
|
+
|
|
657
|
+
#################################################################
|
|
658
|
+
# Misc.
|
|
659
|
+
#################################################################
|
|
660
|
+
|
|
661
|
+
|
|
662
|
+
def exists(S, P):
|
|
663
|
+
"""
|
|
664
|
+
If S contains an element x such that P(x) is ``True``, this function
|
|
665
|
+
returns ``True`` and the element x. Otherwise it returns ``False`` and
|
|
666
|
+
None.
|
|
667
|
+
|
|
668
|
+
Note that this function is NOT suitable to be used in an
|
|
669
|
+
if-statement or in any place where a boolean expression is
|
|
670
|
+
expected. For those situations, use the Python built-in
|
|
671
|
+
|
|
672
|
+
any(P(x) for x in S)
|
|
673
|
+
|
|
674
|
+
INPUT:
|
|
675
|
+
|
|
676
|
+
- ``S`` -- object (that supports enumeration)
|
|
677
|
+
|
|
678
|
+
- ``P`` -- function that returns ``True`` or ``False``
|
|
679
|
+
|
|
680
|
+
OUTPUT:
|
|
681
|
+
|
|
682
|
+
- ``bool`` -- whether or not P is ``True`` for some element
|
|
683
|
+
x of S
|
|
684
|
+
|
|
685
|
+
- ``object`` -- x
|
|
686
|
+
|
|
687
|
+
EXAMPLES: lambda functions are very useful when using the exists
|
|
688
|
+
function::
|
|
689
|
+
|
|
690
|
+
sage: exists([1,2,5], lambda x : x > 7)
|
|
691
|
+
(False, None)
|
|
692
|
+
sage: exists([1,2,5], lambda x : x > 3)
|
|
693
|
+
(True, 5)
|
|
694
|
+
|
|
695
|
+
The following example is similar to one in the MAGMA handbook. We
|
|
696
|
+
check whether certain integers are a sum of two (small) cubes::
|
|
697
|
+
|
|
698
|
+
sage: cubes = [t**3 for t in range(-10,11)]
|
|
699
|
+
sage: exists([(x,y) for x in cubes for y in cubes], lambda v : v[0]+v[1] == 218)
|
|
700
|
+
(True, (-125, 343))
|
|
701
|
+
sage: exists([(x,y) for x in cubes for y in cubes], lambda v : v[0]+v[1] == 219)
|
|
702
|
+
(False, None)
|
|
703
|
+
"""
|
|
704
|
+
for x in S:
|
|
705
|
+
if P(x):
|
|
706
|
+
return True, x
|
|
707
|
+
return False, None
|
|
708
|
+
|
|
709
|
+
|
|
710
|
+
def forall(S, P):
|
|
711
|
+
"""
|
|
712
|
+
If `P(x)` is true every x in S, return ``True`` and ``None``. If there is
|
|
713
|
+
some element x in S such that P is not ``True``, return ``False`` and `x`.
|
|
714
|
+
|
|
715
|
+
Note that this function is NOT suitable to be used in an
|
|
716
|
+
if-statement or in any place where a boolean expression is
|
|
717
|
+
expected. For those situations, use the Python built-in
|
|
718
|
+
|
|
719
|
+
all(P(x) for x in S)
|
|
720
|
+
|
|
721
|
+
INPUT:
|
|
722
|
+
|
|
723
|
+
- ``S`` -- object (that supports enumeration)
|
|
724
|
+
|
|
725
|
+
- ``P`` -- function that returns ``True`` or ``False``
|
|
726
|
+
|
|
727
|
+
OUTPUT:
|
|
728
|
+
|
|
729
|
+
- ``bool`` -- whether or not P is ``True`` for all elements
|
|
730
|
+
of S
|
|
731
|
+
|
|
732
|
+
- ``object`` -- x
|
|
733
|
+
|
|
734
|
+
EXAMPLES: lambda functions are very useful when using the forall
|
|
735
|
+
function. As a toy example we test whether certain integers are
|
|
736
|
+
greater than 3.
|
|
737
|
+
|
|
738
|
+
::
|
|
739
|
+
|
|
740
|
+
sage: forall([1,2,5], lambda x : x > 3)
|
|
741
|
+
(False, 1)
|
|
742
|
+
sage: forall([1,2,5], lambda x : x > 0)
|
|
743
|
+
(True, None)
|
|
744
|
+
|
|
745
|
+
Next we ask whether every positive integer less than 100 is a
|
|
746
|
+
product of at most 2 prime factors::
|
|
747
|
+
|
|
748
|
+
sage: forall(range(1,100), lambda n : len(factor(n)) <= 2)
|
|
749
|
+
(False, 30)
|
|
750
|
+
|
|
751
|
+
The answer is no, and 30 is a counterexample. However, every
|
|
752
|
+
positive integer 100 is a product of at most 3 primes.
|
|
753
|
+
|
|
754
|
+
::
|
|
755
|
+
|
|
756
|
+
sage: forall(range(1,100), lambda n : len(factor(n)) <= 3)
|
|
757
|
+
(True, None)
|
|
758
|
+
"""
|
|
759
|
+
for x in S:
|
|
760
|
+
if not P(x):
|
|
761
|
+
return False, x
|
|
762
|
+
return True, None
|
|
763
|
+
|
|
764
|
+
|
|
765
|
+
#################################################################
|
|
766
|
+
# debug tracing
|
|
767
|
+
#################################################################
|
|
768
|
+
set_trace = pdb.set_trace
|
|
769
|
+
|
|
770
|
+
|
|
771
|
+
#################################################################
|
|
772
|
+
# Word wrap lines
|
|
773
|
+
#################################################################
|
|
774
|
+
def word_wrap(s, ncols=85):
|
|
775
|
+
t = []
|
|
776
|
+
if ncols == 0:
|
|
777
|
+
return s
|
|
778
|
+
for x in s.split('\n'):
|
|
779
|
+
if not x or x.lstrip()[:5] == 'sage:':
|
|
780
|
+
t.append(x)
|
|
781
|
+
continue
|
|
782
|
+
while len(x) > ncols:
|
|
783
|
+
k = ncols
|
|
784
|
+
while k > 0 and x[k] != ' ':
|
|
785
|
+
k -= 1
|
|
786
|
+
if k == 0:
|
|
787
|
+
k = ncols
|
|
788
|
+
end = '\\'
|
|
789
|
+
else:
|
|
790
|
+
end = ''
|
|
791
|
+
t.append(x[:k] + end)
|
|
792
|
+
x = x[k:]
|
|
793
|
+
k = 0
|
|
794
|
+
while k < len(x) and x[k] == ' ':
|
|
795
|
+
k += 1
|
|
796
|
+
x = x[k:]
|
|
797
|
+
t.append(x)
|
|
798
|
+
return '\n'.join(t)
|
|
799
|
+
|
|
800
|
+
|
|
801
|
+
def pad_zeros(s, size=3):
|
|
802
|
+
"""
|
|
803
|
+
EXAMPLES::
|
|
804
|
+
|
|
805
|
+
sage: pad_zeros(100)
|
|
806
|
+
'100'
|
|
807
|
+
sage: pad_zeros(10)
|
|
808
|
+
'010'
|
|
809
|
+
sage: pad_zeros(10, 5)
|
|
810
|
+
'00010'
|
|
811
|
+
sage: pad_zeros(389, 5)
|
|
812
|
+
'00389'
|
|
813
|
+
sage: pad_zeros(389, 10)
|
|
814
|
+
'0000000389'
|
|
815
|
+
"""
|
|
816
|
+
return "0" * (size - len(str(s))) + str(s)
|
|
817
|
+
|
|
818
|
+
|
|
819
|
+
def is_in_string(line, pos):
|
|
820
|
+
r"""
|
|
821
|
+
Return ``True`` if the character at position ``pos`` in ``line`` occurs
|
|
822
|
+
within a string.
|
|
823
|
+
|
|
824
|
+
EXAMPLES::
|
|
825
|
+
|
|
826
|
+
sage: from sage.misc.misc import is_in_string
|
|
827
|
+
sage: line = 'test(\'#\')'
|
|
828
|
+
sage: is_in_string(line, line.rfind('#'))
|
|
829
|
+
True
|
|
830
|
+
sage: is_in_string(line, line.rfind(')'))
|
|
831
|
+
False
|
|
832
|
+
"""
|
|
833
|
+
i = 0
|
|
834
|
+
in_single_quote = False
|
|
835
|
+
in_double_quote = False
|
|
836
|
+
in_triple_quote = False
|
|
837
|
+
|
|
838
|
+
def in_quote():
|
|
839
|
+
return in_single_quote or in_double_quote or in_triple_quote
|
|
840
|
+
|
|
841
|
+
while i < pos:
|
|
842
|
+
# Update quote parsing
|
|
843
|
+
# We only do this if this quote isn't backquoted itself,
|
|
844
|
+
# which is the case if the previous character isn't
|
|
845
|
+
# a backslash, or it is but both previous characters
|
|
846
|
+
# are backslashes.
|
|
847
|
+
if line[i - 1 : i] != '\\' or line[i - 2 : i] == '\\\\':
|
|
848
|
+
if line[i : i + 3] in ['"""', "'''"]:
|
|
849
|
+
if not in_quote():
|
|
850
|
+
in_triple_quote = True
|
|
851
|
+
elif in_triple_quote:
|
|
852
|
+
in_triple_quote = False
|
|
853
|
+
elif line[i] == "'":
|
|
854
|
+
if not in_quote():
|
|
855
|
+
in_single_quote = True
|
|
856
|
+
elif in_single_quote:
|
|
857
|
+
in_single_quote = False
|
|
858
|
+
elif line[i] == '"':
|
|
859
|
+
if not in_quote():
|
|
860
|
+
in_double_quote = True
|
|
861
|
+
elif in_double_quote:
|
|
862
|
+
in_double_quote = False
|
|
863
|
+
i += 1
|
|
864
|
+
return in_quote()
|
|
865
|
+
|
|
866
|
+
|
|
867
|
+
def get_main_globals():
|
|
868
|
+
"""
|
|
869
|
+
Return the main global namespace.
|
|
870
|
+
|
|
871
|
+
EXAMPLES::
|
|
872
|
+
|
|
873
|
+
sage: from sage.misc.misc import get_main_globals
|
|
874
|
+
sage: G = get_main_globals()
|
|
875
|
+
sage: bla = 1
|
|
876
|
+
sage: G['bla']
|
|
877
|
+
1
|
|
878
|
+
sage: bla = 2
|
|
879
|
+
sage: G['bla']
|
|
880
|
+
2
|
|
881
|
+
sage: G['ble'] = 5
|
|
882
|
+
sage: ble
|
|
883
|
+
5
|
|
884
|
+
|
|
885
|
+
This is analogous to :func:`globals`, except that it can be called
|
|
886
|
+
from any function, even if it is in a Python module::
|
|
887
|
+
|
|
888
|
+
sage: def f():
|
|
889
|
+
....: G = get_main_globals()
|
|
890
|
+
....: assert G['bli'] == 14
|
|
891
|
+
....: G['blo'] = 42
|
|
892
|
+
sage: bli = 14
|
|
893
|
+
sage: f()
|
|
894
|
+
sage: blo
|
|
895
|
+
42
|
|
896
|
+
|
|
897
|
+
ALGORITHM:
|
|
898
|
+
|
|
899
|
+
The main global namespace is discovered by going up the frame
|
|
900
|
+
stack until the frame for the :mod:`__main__` module is found.
|
|
901
|
+
Should this frame not be found (this should not occur in normal
|
|
902
|
+
operation), an exception "ValueError: call stack is not deep
|
|
903
|
+
enough" will be raised by ``_getframe``.
|
|
904
|
+
|
|
905
|
+
See :meth:`inject_variable_test` for a real test that this works
|
|
906
|
+
within deeply nested calls in a function defined in a Python
|
|
907
|
+
module.
|
|
908
|
+
"""
|
|
909
|
+
import sys
|
|
910
|
+
|
|
911
|
+
depth = 0
|
|
912
|
+
while True:
|
|
913
|
+
G = sys._getframe(depth).f_globals
|
|
914
|
+
if G.get("__name__", None) == "__main__":
|
|
915
|
+
break
|
|
916
|
+
depth += 1
|
|
917
|
+
return G
|
|
918
|
+
|
|
919
|
+
|
|
920
|
+
def inject_variable(name, value, warn=True):
|
|
921
|
+
"""
|
|
922
|
+
Inject a variable into the main global namespace.
|
|
923
|
+
|
|
924
|
+
INPUT:
|
|
925
|
+
|
|
926
|
+
- ``name`` -- string
|
|
927
|
+
- ``value`` -- anything
|
|
928
|
+
- ``warn`` -- boolean (default: ``False``)
|
|
929
|
+
|
|
930
|
+
EXAMPLES::
|
|
931
|
+
|
|
932
|
+
sage: from sage.misc.misc import inject_variable
|
|
933
|
+
sage: inject_variable("a", 314)
|
|
934
|
+
sage: a
|
|
935
|
+
314
|
|
936
|
+
|
|
937
|
+
A warning is issued the first time an existing value is overwritten::
|
|
938
|
+
|
|
939
|
+
sage: inject_variable("a", 271)
|
|
940
|
+
doctest:...: RuntimeWarning: redefining global value `a`
|
|
941
|
+
sage: a
|
|
942
|
+
271
|
|
943
|
+
sage: inject_variable("a", 272)
|
|
944
|
+
sage: a
|
|
945
|
+
272
|
|
946
|
+
|
|
947
|
+
That's because warn seem to not reissue twice the same warning::
|
|
948
|
+
|
|
949
|
+
sage: from warnings import warn
|
|
950
|
+
sage: warn("blah")
|
|
951
|
+
doctest:...: UserWarning: blah
|
|
952
|
+
sage: warn("blah")
|
|
953
|
+
|
|
954
|
+
Warnings can be disabled::
|
|
955
|
+
|
|
956
|
+
sage: b = 3
|
|
957
|
+
sage: inject_variable("b", 42, warn=False)
|
|
958
|
+
sage: b
|
|
959
|
+
42
|
|
960
|
+
|
|
961
|
+
Use with care!
|
|
962
|
+
"""
|
|
963
|
+
assert isinstance(name, str)
|
|
964
|
+
# Using globals() does not work, even in Cython, because
|
|
965
|
+
# inject_variable is called not only from the interpreter, but
|
|
966
|
+
# also from functions in various modules.
|
|
967
|
+
G = get_main_globals()
|
|
968
|
+
if name in G and warn:
|
|
969
|
+
warnings.warn(
|
|
970
|
+
"redefining global value `%s`" % name, RuntimeWarning, stacklevel=2
|
|
971
|
+
)
|
|
972
|
+
G[name] = value
|
|
973
|
+
|
|
974
|
+
|
|
975
|
+
def inject_variable_test(name, value, depth):
|
|
976
|
+
"""
|
|
977
|
+
A function for testing deep calls to ``inject_variable``.
|
|
978
|
+
|
|
979
|
+
EXAMPLES::
|
|
980
|
+
|
|
981
|
+
sage: from sage.misc.misc import inject_variable_test
|
|
982
|
+
sage: inject_variable_test("a0", 314, 0)
|
|
983
|
+
sage: a0
|
|
984
|
+
314
|
|
985
|
+
sage: inject_variable_test("a1", 314, 1)
|
|
986
|
+
sage: a1
|
|
987
|
+
314
|
|
988
|
+
sage: inject_variable_test("a2", 314, 2)
|
|
989
|
+
sage: a2
|
|
990
|
+
314
|
|
991
|
+
sage: inject_variable_test("a2", 271, 2)
|
|
992
|
+
doctest:...: RuntimeWarning: redefining global value `a2`
|
|
993
|
+
sage: a2
|
|
994
|
+
271
|
|
995
|
+
"""
|
|
996
|
+
if depth == 0:
|
|
997
|
+
inject_variable(name, value)
|
|
998
|
+
else:
|
|
999
|
+
inject_variable_test(name, value, depth - 1)
|
|
1000
|
+
|
|
1001
|
+
|
|
1002
|
+
# from https://stackoverflow.com/questions/4103773/efficient-way-of-having-a-function-only-execute-once-in-a-loop
|
|
1003
|
+
def run_once(func):
|
|
1004
|
+
"""
|
|
1005
|
+
Run a function (successfully) only once.
|
|
1006
|
+
|
|
1007
|
+
The running can be reset by setting the ``has_run`` attribute to False
|
|
1008
|
+
|
|
1009
|
+
TESTS::
|
|
1010
|
+
|
|
1011
|
+
sage: from sage.repl.ipython_extension import run_once
|
|
1012
|
+
sage: @run_once
|
|
1013
|
+
....: def foo(work):
|
|
1014
|
+
....: if work:
|
|
1015
|
+
....: return 'foo worked'
|
|
1016
|
+
....: raise RuntimeError("foo didn't work")
|
|
1017
|
+
sage: foo(False)
|
|
1018
|
+
Traceback (most recent call last):
|
|
1019
|
+
...
|
|
1020
|
+
RuntimeError: foo didn't work
|
|
1021
|
+
sage: foo(True)
|
|
1022
|
+
'foo worked'
|
|
1023
|
+
sage: foo(False)
|
|
1024
|
+
sage: foo(True)
|
|
1025
|
+
"""
|
|
1026
|
+
|
|
1027
|
+
@functools.wraps(func)
|
|
1028
|
+
def wrapper(*args, **kwargs):
|
|
1029
|
+
if not wrapper.has_run:
|
|
1030
|
+
result = func(*args, **kwargs)
|
|
1031
|
+
wrapper.has_run = True
|
|
1032
|
+
return result
|
|
1033
|
+
|
|
1034
|
+
wrapper.has_run = False
|
|
1035
|
+
return wrapper
|
|
1036
|
+
|
|
1037
|
+
|
|
1038
|
+
@contextlib.contextmanager
|
|
1039
|
+
def increase_recursion_limit(increment):
|
|
1040
|
+
r"""
|
|
1041
|
+
Context manager to temporarily change the Python maximum recursion depth.
|
|
1042
|
+
|
|
1043
|
+
INPUT:
|
|
1044
|
+
|
|
1045
|
+
- ``increment`` -- increment to add to the current limit
|
|
1046
|
+
|
|
1047
|
+
EXAMPLES::
|
|
1048
|
+
|
|
1049
|
+
sage: from sage.misc.misc import increase_recursion_limit
|
|
1050
|
+
sage: def rec(n): None if n == 0 else rec(n-1)
|
|
1051
|
+
sage: rec(10000)
|
|
1052
|
+
Traceback (most recent call last):
|
|
1053
|
+
...
|
|
1054
|
+
RecursionError: maximum recursion depth exceeded...
|
|
1055
|
+
sage: with increase_recursion_limit(10000): rec(10000)
|
|
1056
|
+
sage: rec(10000)
|
|
1057
|
+
Traceback (most recent call last):
|
|
1058
|
+
...
|
|
1059
|
+
RecursionError: maximum recursion depth exceeded...
|
|
1060
|
+
"""
|
|
1061
|
+
old_limit = sys.getrecursionlimit()
|
|
1062
|
+
sys.setrecursionlimit(old_limit + increment)
|
|
1063
|
+
try:
|
|
1064
|
+
yield
|
|
1065
|
+
finally:
|
|
1066
|
+
sys.setrecursionlimit(old_limit)
|