Buckets:
MisterAI/LocalAI_Demo_backends / cpu-diffusers.upgrade-tmp /venv /lib /python3.10 /site-packages /sympy /polys /distributedmodules.py
| r""" | |
| Sparse distributed elements of free modules over multivariate (generalized) | |
| polynomial rings. | |
| This code and its data structures are very much like the distributed | |
| polynomials, except that the first "exponent" of the monomial is | |
| a module generator index. That is, the multi-exponent ``(i, e_1, ..., e_n)`` | |
| represents the "monomial" `x_1^{e_1} \cdots x_n^{e_n} f_i` of the free module | |
| `F` generated by `f_1, \ldots, f_r` over (a localization of) the ring | |
| `K[x_1, \ldots, x_n]`. A module element is simply stored as a list of terms | |
| ordered by the monomial order. Here a term is a pair of a multi-exponent and a | |
| coefficient. In general, this coefficient should never be zero (since it can | |
| then be omitted). The zero module element is stored as an empty list. | |
| The main routines are ``sdm_nf_mora`` and ``sdm_groebner`` which can be used | |
| to compute, respectively, weak normal forms and standard bases. They work with | |
| arbitrary (not necessarily global) monomial orders. | |
| In general, product orders have to be used to construct valid monomial orders | |
| for modules. However, ``lex`` can be used as-is. | |
| Note that the "level" (number of variables, i.e. parameter u+1 in | |
| distributedpolys.py) is never needed in this code. | |
| The main reference for this file is [SCA], | |
| "A Singular Introduction to Commutative Algebra". | |
| """ | |
| from itertools import permutations | |
| from sympy.polys.monomials import ( | |
| monomial_mul, monomial_lcm, monomial_div, monomial_deg | |
| ) | |
| from sympy.polys.polytools import Poly | |
| from sympy.polys.polyutils import parallel_dict_from_expr | |
| from sympy.core.singleton import S | |
| from sympy.core.sympify import sympify | |
| # Additional monomial tools. | |
| def sdm_monomial_mul(M, X): | |
| """ | |
| Multiply tuple ``X`` representing a monomial of `K[X]` into the tuple | |
| ``M`` representing a monomial of `F`. | |
| Examples | |
| ======== | |
| Multiplying `xy^3` into `x f_1` yields `x^2 y^3 f_1`: | |
| >>> from sympy.polys.distributedmodules import sdm_monomial_mul | |
| >>> sdm_monomial_mul((1, 1, 0), (1, 3)) | |
| (1, 2, 3) | |
| """ | |
| return (M[0],) + monomial_mul(X, M[1:]) | |
| def sdm_monomial_deg(M): | |
| """ | |
| Return the total degree of ``M``. | |
| Examples | |
| ======== | |
| For example, the total degree of `x^2 y f_5` is 3: | |
| >>> from sympy.polys.distributedmodules import sdm_monomial_deg | |
| >>> sdm_monomial_deg((5, 2, 1)) | |
| 3 | |
| """ | |
| return monomial_deg(M[1:]) | |
| def sdm_monomial_lcm(A, B): | |
| r""" | |
| Return the "least common multiple" of ``A`` and ``B``. | |
| IF `A = M e_j` and `B = N e_j`, where `M` and `N` are polynomial monomials, | |
| this returns `\lcm(M, N) e_j`. Note that ``A`` and ``B`` involve distinct | |
| monomials. | |
| Otherwise the result is undefined. | |
| Examples | |
| ======== | |
| >>> from sympy.polys.distributedmodules import sdm_monomial_lcm | |
| >>> sdm_monomial_lcm((1, 2, 3), (1, 0, 5)) | |
| (1, 2, 5) | |
| """ | |
| return (A[0],) + monomial_lcm(A[1:], B[1:]) | |
| def sdm_monomial_divides(A, B): | |
| """ | |
| Does there exist a (polynomial) monomial X such that XA = B? | |
| Examples | |
| ======== | |
| Positive examples: | |
| In the following examples, the monomial is given in terms of x, y and the | |
| generator(s), f_1, f_2 etc. The tuple form of that monomial is used in | |
| the call to sdm_monomial_divides. | |
| Note: the generator appears last in the expression but first in the tuple | |
| and other factors appear in the same order that they appear in the monomial | |
| expression. | |
| `A = f_1` divides `B = f_1` | |
| >>> from sympy.polys.distributedmodules import sdm_monomial_divides | |
| >>> sdm_monomial_divides((1, 0, 0), (1, 0, 0)) | |
| True | |
| `A = f_1` divides `B = x^2 y f_1` | |
| >>> sdm_monomial_divides((1, 0, 0), (1, 2, 1)) | |
| True | |
| `A = xy f_5` divides `B = x^2 y f_5` | |
| >>> sdm_monomial_divides((5, 1, 1), (5, 2, 1)) | |
| True | |
| Negative examples: | |
| `A = f_1` does not divide `B = f_2` | |
| >>> sdm_monomial_divides((1, 0, 0), (2, 0, 0)) | |
| False | |
| `A = x f_1` does not divide `B = f_1` | |
| >>> sdm_monomial_divides((1, 1, 0), (1, 0, 0)) | |
| False | |
| `A = xy^2 f_5` does not divide `B = y f_5` | |
| >>> sdm_monomial_divides((5, 1, 2), (5, 0, 1)) | |
| False | |
| """ | |
| return A[0] == B[0] and all(a <= b for a, b in zip(A[1:], B[1:])) | |
| # The actual distributed modules code. | |
| def sdm_LC(f, K): | |
| """Returns the leading coefficient of ``f``. """ | |
| if not f: | |
| return K.zero | |
| else: | |
| return f[0][1] | |
| def sdm_to_dict(f): | |
| """Make a dictionary from a distributed polynomial. """ | |
| return dict(f) | |
| def sdm_from_dict(d, O): | |
| """ | |
| Create an sdm from a dictionary. | |
| Here ``O`` is the monomial order to use. | |
| Examples | |
| ======== | |
| >>> from sympy.polys.distributedmodules import sdm_from_dict | |
| >>> from sympy.polys import QQ, lex | |
| >>> dic = {(1, 1, 0): QQ(1), (1, 0, 0): QQ(2), (0, 1, 0): QQ(0)} | |
| >>> sdm_from_dict(dic, lex) | |
| [((1, 1, 0), 1), ((1, 0, 0), 2)] | |
| """ | |
| return sdm_strip(sdm_sort(list(d.items()), O)) | |
| def sdm_sort(f, O): | |
| """Sort terms in ``f`` using the given monomial order ``O``. """ | |
| return sorted(f, key=lambda term: O(term[0]), reverse=True) | |
| def sdm_strip(f): | |
| """Remove terms with zero coefficients from ``f`` in ``K[X]``. """ | |
| return [ (monom, coeff) for monom, coeff in f if coeff ] | |
| def sdm_add(f, g, O, K): | |
| """ | |
| Add two module elements ``f``, ``g``. | |
| Addition is done over the ground field ``K``, monomials are ordered | |
| according to ``O``. | |
| Examples | |
| ======== | |
| All examples use lexicographic order. | |
| `(xy f_1) + (f_2) = f_2 + xy f_1` | |
| >>> from sympy.polys.distributedmodules import sdm_add | |
| >>> from sympy.polys import lex, QQ | |
| >>> sdm_add([((1, 1, 1), QQ(1))], [((2, 0, 0), QQ(1))], lex, QQ) | |
| [((2, 0, 0), 1), ((1, 1, 1), 1)] | |
| `(xy f_1) + (-xy f_1)` = 0` | |
| >>> sdm_add([((1, 1, 1), QQ(1))], [((1, 1, 1), QQ(-1))], lex, QQ) | |
| [] | |
| `(f_1) + (2f_1) = 3f_1` | |
| >>> sdm_add([((1, 0, 0), QQ(1))], [((1, 0, 0), QQ(2))], lex, QQ) | |
| [((1, 0, 0), 3)] | |
| `(yf_1) + (xf_1) = xf_1 + yf_1` | |
| >>> sdm_add([((1, 0, 1), QQ(1))], [((1, 1, 0), QQ(1))], lex, QQ) | |
| [((1, 1, 0), 1), ((1, 0, 1), 1)] | |
| """ | |
| h = dict(f) | |
| for monom, c in g: | |
| if monom in h: | |
| coeff = h[monom] + c | |
| if not coeff: | |
| del h[monom] | |
| else: | |
| h[monom] = coeff | |
| else: | |
| h[monom] = c | |
| return sdm_from_dict(h, O) | |
| def sdm_LM(f): | |
| r""" | |
| Returns the leading monomial of ``f``. | |
| Only valid if `f \ne 0`. | |
| Examples | |
| ======== | |
| >>> from sympy.polys.distributedmodules import sdm_LM, sdm_from_dict | |
| >>> from sympy.polys import QQ, lex | |
| >>> dic = {(1, 2, 3): QQ(1), (4, 0, 0): QQ(1), (4, 0, 1): QQ(1)} | |
| >>> sdm_LM(sdm_from_dict(dic, lex)) | |
| (4, 0, 1) | |
| """ | |
| return f[0][0] | |
| def sdm_LT(f): | |
| r""" | |
| Returns the leading term of ``f``. | |
| Only valid if `f \ne 0`. | |
| Examples | |
| ======== | |
| >>> from sympy.polys.distributedmodules import sdm_LT, sdm_from_dict | |
| >>> from sympy.polys import QQ, lex | |
| >>> dic = {(1, 2, 3): QQ(1), (4, 0, 0): QQ(2), (4, 0, 1): QQ(3)} | |
| >>> sdm_LT(sdm_from_dict(dic, lex)) | |
| ((4, 0, 1), 3) | |
| """ | |
| return f[0] | |
| def sdm_mul_term(f, term, O, K): | |
| """ | |
| Multiply a distributed module element ``f`` by a (polynomial) term ``term``. | |
| Multiplication of coefficients is done over the ground field ``K``, and | |
| monomials are ordered according to ``O``. | |
| Examples | |
| ======== | |
| `0 f_1 = 0` | |
| >>> from sympy.polys.distributedmodules import sdm_mul_term | |
| >>> from sympy.polys import lex, QQ | |
| >>> sdm_mul_term([((1, 0, 0), QQ(1))], ((0, 0), QQ(0)), lex, QQ) | |
| [] | |
| `x 0 = 0` | |
| >>> sdm_mul_term([], ((1, 0), QQ(1)), lex, QQ) | |
| [] | |
| `(x) (f_1) = xf_1` | |
| >>> sdm_mul_term([((1, 0, 0), QQ(1))], ((1, 0), QQ(1)), lex, QQ) | |
| [((1, 1, 0), 1)] | |
| `(2xy) (3x f_1 + 4y f_2) = 8xy^2 f_2 + 6x^2y f_1` | |
| >>> f = [((2, 0, 1), QQ(4)), ((1, 1, 0), QQ(3))] | |
| >>> sdm_mul_term(f, ((1, 1), QQ(2)), lex, QQ) | |
| [((2, 1, 2), 8), ((1, 2, 1), 6)] | |
| """ | |
| X, c = term | |
| if not f or not c: | |
| return [] | |
| else: | |
| if K.is_one(c): | |
| return [ (sdm_monomial_mul(f_M, X), f_c) for f_M, f_c in f ] | |
| else: | |
| return [ (sdm_monomial_mul(f_M, X), f_c * c) for f_M, f_c in f ] | |
| def sdm_zero(): | |
| """Return the zero module element.""" | |
| return [] | |
| def sdm_deg(f): | |
| """ | |
| Degree of ``f``. | |
| This is the maximum of the degrees of all its monomials. | |
| Invalid if ``f`` is zero. | |
| Examples | |
| ======== | |
| >>> from sympy.polys.distributedmodules import sdm_deg | |
| >>> sdm_deg([((1, 2, 3), 1), ((10, 0, 1), 1), ((2, 3, 4), 4)]) | |
| 7 | |
| """ | |
| return max(sdm_monomial_deg(M[0]) for M in f) | |
| # Conversion | |
| def sdm_from_vector(vec, O, K, **opts): | |
| """ | |
| Create an sdm from an iterable of expressions. | |
| Coefficients are created in the ground field ``K``, and terms are ordered | |
| according to monomial order ``O``. Named arguments are passed on to the | |
| polys conversion code and can be used to specify for example generators. | |
| Examples | |
| ======== | |
| >>> from sympy.polys.distributedmodules import sdm_from_vector | |
| >>> from sympy.abc import x, y, z | |
| >>> from sympy.polys import QQ, lex | |
| >>> sdm_from_vector([x**2+y**2, 2*z], lex, QQ) | |
| [((1, 0, 0, 1), 2), ((0, 2, 0, 0), 1), ((0, 0, 2, 0), 1)] | |
| """ | |
| dics, gens = parallel_dict_from_expr(sympify(vec), **opts) | |
| dic = {} | |
| for i, d in enumerate(dics): | |
| for k, v in d.items(): | |
| dic[(i,) + k] = K.convert(v) | |
| return sdm_from_dict(dic, O) | |
| def sdm_to_vector(f, gens, K, n=None): | |
| """ | |
| Convert sdm ``f`` into a list of polynomial expressions. | |
| The generators for the polynomial ring are specified via ``gens``. The rank | |
| of the module is guessed, or passed via ``n``. The ground field is assumed | |
| to be ``K``. | |
| Examples | |
| ======== | |
| >>> from sympy.polys.distributedmodules import sdm_to_vector | |
| >>> from sympy.abc import x, y, z | |
| >>> from sympy.polys import QQ | |
| >>> f = [((1, 0, 0, 1), QQ(2)), ((0, 2, 0, 0), QQ(1)), ((0, 0, 2, 0), QQ(1))] | |
| >>> sdm_to_vector(f, [x, y, z], QQ) | |
| [x**2 + y**2, 2*z] | |
| """ | |
| dic = sdm_to_dict(f) | |
| dics = {} | |
| for k, v in dic.items(): | |
| dics.setdefault(k[0], []).append((k[1:], v)) | |
| n = n or len(dics) | |
| res = [] | |
| for k in range(n): | |
| if k in dics: | |
| res.append(Poly(dict(dics[k]), gens=gens, domain=K).as_expr()) | |
| else: | |
| res.append(S.Zero) | |
| return res | |
| # Algorithms. | |
| def sdm_spoly(f, g, O, K, phantom=None): | |
| """ | |
| Compute the generalized s-polynomial of ``f`` and ``g``. | |
| The ground field is assumed to be ``K``, and monomials ordered according to | |
| ``O``. | |
| This is invalid if either of ``f`` or ``g`` is zero. | |
| If the leading terms of `f` and `g` involve different basis elements of | |
| `F`, their s-poly is defined to be zero. Otherwise it is a certain linear | |
| combination of `f` and `g` in which the leading terms cancel. | |
| See [SCA, defn 2.3.6] for details. | |
| If ``phantom`` is not ``None``, it should be a pair of module elements on | |
| which to perform the same operation(s) as on ``f`` and ``g``. The in this | |
| case both results are returned. | |
| Examples | |
| ======== | |
| >>> from sympy.polys.distributedmodules import sdm_spoly | |
| >>> from sympy.polys import QQ, lex | |
| >>> f = [((2, 1, 1), QQ(1)), ((1, 0, 1), QQ(1))] | |
| >>> g = [((2, 3, 0), QQ(1))] | |
| >>> h = [((1, 2, 3), QQ(1))] | |
| >>> sdm_spoly(f, h, lex, QQ) | |
| [] | |
| >>> sdm_spoly(f, g, lex, QQ) | |
| [((1, 2, 1), 1)] | |
| """ | |
| if not f or not g: | |
| return sdm_zero() | |
| LM1 = sdm_LM(f) | |
| LM2 = sdm_LM(g) | |
| if LM1[0] != LM2[0]: | |
| return sdm_zero() | |
| LM1 = LM1[1:] | |
| LM2 = LM2[1:] | |
| lcm = monomial_lcm(LM1, LM2) | |
| m1 = monomial_div(lcm, LM1) | |
| m2 = monomial_div(lcm, LM2) | |
| c = K.quo(-sdm_LC(f, K), sdm_LC(g, K)) | |
| r1 = sdm_add(sdm_mul_term(f, (m1, K.one), O, K), | |
| sdm_mul_term(g, (m2, c), O, K), O, K) | |
| if phantom is None: | |
| return r1 | |
| r2 = sdm_add(sdm_mul_term(phantom[0], (m1, K.one), O, K), | |
| sdm_mul_term(phantom[1], (m2, c), O, K), O, K) | |
| return r1, r2 | |
| def sdm_ecart(f): | |
| """ | |
| Compute the ecart of ``f``. | |
| This is defined to be the difference of the total degree of `f` and the | |
| total degree of the leading monomial of `f` [SCA, defn 2.3.7]. | |
| Invalid if f is zero. | |
| Examples | |
| ======== | |
| >>> from sympy.polys.distributedmodules import sdm_ecart | |
| >>> sdm_ecart([((1, 2, 3), 1), ((1, 0, 1), 1)]) | |
| 0 | |
| >>> sdm_ecart([((2, 2, 1), 1), ((1, 5, 1), 1)]) | |
| 3 | |
| """ | |
| return sdm_deg(f) - sdm_monomial_deg(sdm_LM(f)) | |
| def sdm_nf_mora(f, G, O, K, phantom=None): | |
| r""" | |
| Compute a weak normal form of ``f`` with respect to ``G`` and order ``O``. | |
| The ground field is assumed to be ``K``, and monomials ordered according to | |
| ``O``. | |
| Weak normal forms are defined in [SCA, defn 2.3.3]. They are not unique. | |
| This function deterministically computes a weak normal form, depending on | |
| the order of `G`. | |
| The most important property of a weak normal form is the following: if | |
| `R` is the ring associated with the monomial ordering (if the ordering is | |
| global, we just have `R = K[x_1, \ldots, x_n]`, otherwise it is a certain | |
| localization thereof), `I` any ideal of `R` and `G` a standard basis for | |
| `I`, then for any `f \in R`, we have `f \in I` if and only if | |
| `NF(f | G) = 0`. | |
| This is the generalized Mora algorithm for computing weak normal forms with | |
| respect to arbitrary monomial orders [SCA, algorithm 2.3.9]. | |
| If ``phantom`` is not ``None``, it should be a pair of "phantom" arguments | |
| on which to perform the same computations as on ``f``, ``G``, both results | |
| are then returned. | |
| """ | |
| from itertools import repeat | |
| h = f | |
| T = list(G) | |
| if phantom is not None: | |
| # "phantom" variables with suffix p | |
| hp = phantom[0] | |
| Tp = list(phantom[1]) | |
| phantom = True | |
| else: | |
| Tp = repeat([]) | |
| phantom = False | |
| while h: | |
| # TODO better data structure!!! | |
| Th = [(g, sdm_ecart(g), gp) for g, gp in zip(T, Tp) | |
| if sdm_monomial_divides(sdm_LM(g), sdm_LM(h))] | |
| if not Th: | |
| break | |
| g, _, gp = min(Th, key=lambda x: x[1]) | |
| if sdm_ecart(g) > sdm_ecart(h): | |
| T.append(h) | |
| if phantom: | |
| Tp.append(hp) | |
| if phantom: | |
| h, hp = sdm_spoly(h, g, O, K, phantom=(hp, gp)) | |
| else: | |
| h = sdm_spoly(h, g, O, K) | |
| if phantom: | |
| return h, hp | |
| return h | |
| def sdm_nf_buchberger(f, G, O, K, phantom=None): | |
| r""" | |
| Compute a weak normal form of ``f`` with respect to ``G`` and order ``O``. | |
| The ground field is assumed to be ``K``, and monomials ordered according to | |
| ``O``. | |
| This is the standard Buchberger algorithm for computing weak normal forms with | |
| respect to *global* monomial orders [SCA, algorithm 1.6.10]. | |
| If ``phantom`` is not ``None``, it should be a pair of "phantom" arguments | |
| on which to perform the same computations as on ``f``, ``G``, both results | |
| are then returned. | |
| """ | |
| from itertools import repeat | |
| h = f | |
| T = list(G) | |
| if phantom is not None: | |
| # "phantom" variables with suffix p | |
| hp = phantom[0] | |
| Tp = list(phantom[1]) | |
| phantom = True | |
| else: | |
| Tp = repeat([]) | |
| phantom = False | |
| while h: | |
| try: | |
| g, gp = next((g, gp) for g, gp in zip(T, Tp) | |
| if sdm_monomial_divides(sdm_LM(g), sdm_LM(h))) | |
| except StopIteration: | |
| break | |
| if phantom: | |
| h, hp = sdm_spoly(h, g, O, K, phantom=(hp, gp)) | |
| else: | |
| h = sdm_spoly(h, g, O, K) | |
| if phantom: | |
| return h, hp | |
| return h | |
| def sdm_nf_buchberger_reduced(f, G, O, K): | |
| r""" | |
| Compute a reduced normal form of ``f`` with respect to ``G`` and order ``O``. | |
| The ground field is assumed to be ``K``, and monomials ordered according to | |
| ``O``. | |
| In contrast to weak normal forms, reduced normal forms *are* unique, but | |
| their computation is more expensive. | |
| This is the standard Buchberger algorithm for computing reduced normal forms | |
| with respect to *global* monomial orders [SCA, algorithm 1.6.11]. | |
| The ``pantom`` option is not supported, so this normal form cannot be used | |
| as a normal form for the "extended" groebner algorithm. | |
| """ | |
| h = sdm_zero() | |
| g = f | |
| while g: | |
| g = sdm_nf_buchberger(g, G, O, K) | |
| if g: | |
| h = sdm_add(h, [sdm_LT(g)], O, K) | |
| g = g[1:] | |
| return h | |
| def sdm_groebner(G, NF, O, K, extended=False): | |
| """ | |
| Compute a minimal standard basis of ``G`` with respect to order ``O``. | |
| The algorithm uses a normal form ``NF``, for example ``sdm_nf_mora``. | |
| The ground field is assumed to be ``K``, and monomials ordered according | |
| to ``O``. | |
| Let `N` denote the submodule generated by elements of `G`. A standard | |
| basis for `N` is a subset `S` of `N`, such that `in(S) = in(N)`, where for | |
| any subset `X` of `F`, `in(X)` denotes the submodule generated by the | |
| initial forms of elements of `X`. [SCA, defn 2.3.2] | |
| A standard basis is called minimal if no subset of it is a standard basis. | |
| One may show that standard bases are always generating sets. | |
| Minimal standard bases are not unique. This algorithm computes a | |
| deterministic result, depending on the particular order of `G`. | |
| If ``extended=True``, also compute the transition matrix from the initial | |
| generators to the groebner basis. That is, return a list of coefficient | |
| vectors, expressing the elements of the groebner basis in terms of the | |
| elements of ``G``. | |
| This functions implements the "sugar" strategy, see | |
| Giovini et al: "One sugar cube, please" OR Selection strategies in | |
| Buchberger algorithm. | |
| """ | |
| # The critical pair set. | |
| # A critical pair is stored as (i, j, s, t) where (i, j) defines the pair | |
| # (by indexing S), s is the sugar of the pair, and t is the lcm of their | |
| # leading monomials. | |
| P = [] | |
| # The eventual standard basis. | |
| S = [] | |
| Sugars = [] | |
| def Ssugar(i, j): | |
| """Compute the sugar of the S-poly corresponding to (i, j).""" | |
| LMi = sdm_LM(S[i]) | |
| LMj = sdm_LM(S[j]) | |
| return max(Sugars[i] - sdm_monomial_deg(LMi), | |
| Sugars[j] - sdm_monomial_deg(LMj)) \ | |
| + sdm_monomial_deg(sdm_monomial_lcm(LMi, LMj)) | |
| ourkey = lambda p: (p[2], O(p[3]), p[1]) | |
| def update(f, sugar, P): | |
| """Add f with sugar ``sugar`` to S, update P.""" | |
| if not f: | |
| return P | |
| k = len(S) | |
| S.append(f) | |
| Sugars.append(sugar) | |
| LMf = sdm_LM(f) | |
| def removethis(pair): | |
| i, j, s, t = pair | |
| if LMf[0] != t[0]: | |
| return False | |
| tik = sdm_monomial_lcm(LMf, sdm_LM(S[i])) | |
| tjk = sdm_monomial_lcm(LMf, sdm_LM(S[j])) | |
| return tik != t and tjk != t and sdm_monomial_divides(tik, t) and \ | |
| sdm_monomial_divides(tjk, t) | |
| # apply the chain criterion | |
| P = [p for p in P if not removethis(p)] | |
| # new-pair set | |
| N = [(i, k, Ssugar(i, k), sdm_monomial_lcm(LMf, sdm_LM(S[i]))) | |
| for i in range(k) if LMf[0] == sdm_LM(S[i])[0]] | |
| # TODO apply the product criterion? | |
| N.sort(key=ourkey) | |
| remove = set() | |
| for i, p in enumerate(N): | |
| for j in range(i + 1, len(N)): | |
| if sdm_monomial_divides(p[3], N[j][3]): | |
| remove.add(j) | |
| # TODO mergesort? | |
| P.extend(reversed([p for i, p in enumerate(N) if i not in remove])) | |
| P.sort(key=ourkey, reverse=True) | |
| # NOTE reverse-sort, because we want to pop from the end | |
| return P | |
| # Figure out the number of generators in the ground ring. | |
| try: | |
| # NOTE: we look for the first non-zero vector, take its first monomial | |
| # the number of generators in the ring is one less than the length | |
| # (since the zeroth entry is for the module generators) | |
| numgens = len(next(x[0] for x in G if x)[0]) - 1 | |
| except StopIteration: | |
| # No non-zero elements in G ... | |
| if extended: | |
| return [], [] | |
| return [] | |
| # This list will store expressions of the elements of S in terms of the | |
| # initial generators | |
| coefficients = [] | |
| # First add all the elements of G to S | |
| for i, f in enumerate(G): | |
| P = update(f, sdm_deg(f), P) | |
| if extended and f: | |
| coefficients.append(sdm_from_dict({(i,) + (0,)*numgens: K(1)}, O)) | |
| # Now carry out the buchberger algorithm. | |
| while P: | |
| i, j, s, t = P.pop() | |
| f, g = S[i], S[j] | |
| if extended: | |
| sp, coeff = sdm_spoly(f, g, O, K, | |
| phantom=(coefficients[i], coefficients[j])) | |
| h, hcoeff = NF(sp, S, O, K, phantom=(coeff, coefficients)) | |
| if h: | |
| coefficients.append(hcoeff) | |
| else: | |
| h = NF(sdm_spoly(f, g, O, K), S, O, K) | |
| P = update(h, Ssugar(i, j), P) | |
| # Finally interreduce the standard basis. | |
| # (TODO again, better data structures) | |
| S = {(tuple(f), i) for i, f in enumerate(S)} | |
| for (a, ai), (b, bi) in permutations(S, 2): | |
| A = sdm_LM(a) | |
| B = sdm_LM(b) | |
| if sdm_monomial_divides(A, B) and (b, bi) in S and (a, ai) in S: | |
| S.remove((b, bi)) | |
| L = sorted(((list(f), i) for f, i in S), key=lambda p: O(sdm_LM(p[0])), | |
| reverse=True) | |
| res = [x[0] for x in L] | |
| if extended: | |
| return res, [coefficients[i] for _, i in L] | |
| return res | |
Xet Storage Details
- Size:
- 21.8 kB
- Xet hash:
- 6e79e53b2fa91177335f4ae129d87f1f8327af650aa63f9c657a08cfc4b2a534
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.