switching to high quality piper tts and added label translations
This commit is contained in:
@@ -0,0 +1,286 @@
|
||||
"""Definitions of monomial orderings. """
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
__all__ = ["lex", "grlex", "grevlex", "ilex", "igrlex", "igrevlex"]
|
||||
|
||||
from sympy.core import Symbol
|
||||
from sympy.utilities.iterables import iterable
|
||||
|
||||
class MonomialOrder:
|
||||
"""Base class for monomial orderings. """
|
||||
|
||||
alias: str | None = None
|
||||
is_global: bool | None = None
|
||||
is_default = False
|
||||
|
||||
def __repr__(self):
|
||||
return self.__class__.__name__ + "()"
|
||||
|
||||
def __str__(self):
|
||||
return self.alias
|
||||
|
||||
def __call__(self, monomial):
|
||||
raise NotImplementedError
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.__class__ == other.__class__
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.__class__)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not (self == other)
|
||||
|
||||
class LexOrder(MonomialOrder):
|
||||
"""Lexicographic order of monomials. """
|
||||
|
||||
alias = 'lex'
|
||||
is_global = True
|
||||
is_default = True
|
||||
|
||||
def __call__(self, monomial):
|
||||
return monomial
|
||||
|
||||
class GradedLexOrder(MonomialOrder):
|
||||
"""Graded lexicographic order of monomials. """
|
||||
|
||||
alias = 'grlex'
|
||||
is_global = True
|
||||
|
||||
def __call__(self, monomial):
|
||||
return (sum(monomial), monomial)
|
||||
|
||||
class ReversedGradedLexOrder(MonomialOrder):
|
||||
"""Reversed graded lexicographic order of monomials. """
|
||||
|
||||
alias = 'grevlex'
|
||||
is_global = True
|
||||
|
||||
def __call__(self, monomial):
|
||||
return (sum(monomial), tuple(reversed([-m for m in monomial])))
|
||||
|
||||
class ProductOrder(MonomialOrder):
|
||||
"""
|
||||
A product order built from other monomial orders.
|
||||
|
||||
Given (not necessarily total) orders O1, O2, ..., On, their product order
|
||||
P is defined as M1 > M2 iff there exists i such that O1(M1) = O2(M2),
|
||||
..., Oi(M1) = Oi(M2), O{i+1}(M1) > O{i+1}(M2).
|
||||
|
||||
Product orders are typically built from monomial orders on different sets
|
||||
of variables.
|
||||
|
||||
ProductOrder is constructed by passing a list of pairs
|
||||
[(O1, L1), (O2, L2), ...] where Oi are MonomialOrders and Li are callables.
|
||||
Upon comparison, the Li are passed the total monomial, and should filter
|
||||
out the part of the monomial to pass to Oi.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
We can use a lexicographic order on x_1, x_2 and also on
|
||||
y_1, y_2, y_3, and their product on {x_i, y_i} as follows:
|
||||
|
||||
>>> from sympy.polys.orderings import lex, grlex, ProductOrder
|
||||
>>> P = ProductOrder(
|
||||
... (lex, lambda m: m[:2]), # lex order on x_1 and x_2 of monomial
|
||||
... (grlex, lambda m: m[2:]) # grlex on y_1, y_2, y_3
|
||||
... )
|
||||
>>> P((2, 1, 1, 0, 0)) > P((1, 10, 0, 2, 0))
|
||||
True
|
||||
|
||||
Here the exponent `2` of `x_1` in the first monomial
|
||||
(`x_1^2 x_2 y_1`) is bigger than the exponent `1` of `x_1` in the
|
||||
second monomial (`x_1 x_2^10 y_2^2`), so the first monomial is greater
|
||||
in the product ordering.
|
||||
|
||||
>>> P((2, 1, 1, 0, 0)) < P((2, 1, 0, 2, 0))
|
||||
True
|
||||
|
||||
Here the exponents of `x_1` and `x_2` agree, so the grlex order on
|
||||
`y_1, y_2, y_3` is used to decide the ordering. In this case the monomial
|
||||
`y_2^2` is ordered larger than `y_1`, since for the grlex order the degree
|
||||
of the monomial is most important.
|
||||
"""
|
||||
|
||||
def __init__(self, *args):
|
||||
self.args = args
|
||||
|
||||
def __call__(self, monomial):
|
||||
return tuple(O(lamda(monomial)) for (O, lamda) in self.args)
|
||||
|
||||
def __repr__(self):
|
||||
contents = [repr(x[0]) for x in self.args]
|
||||
return self.__class__.__name__ + '(' + ", ".join(contents) + ')'
|
||||
|
||||
def __str__(self):
|
||||
contents = [str(x[0]) for x in self.args]
|
||||
return self.__class__.__name__ + '(' + ", ".join(contents) + ')'
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, ProductOrder):
|
||||
return False
|
||||
return self.args == other.args
|
||||
|
||||
def __hash__(self):
|
||||
return hash((self.__class__, self.args))
|
||||
|
||||
@property
|
||||
def is_global(self):
|
||||
if all(o.is_global is True for o, _ in self.args):
|
||||
return True
|
||||
if all(o.is_global is False for o, _ in self.args):
|
||||
return False
|
||||
return None
|
||||
|
||||
class InverseOrder(MonomialOrder):
|
||||
"""
|
||||
The "inverse" of another monomial order.
|
||||
|
||||
If O is any monomial order, we can construct another monomial order iO
|
||||
such that `A >_{iO} B` if and only if `B >_O A`. This is useful for
|
||||
constructing local orders.
|
||||
|
||||
Note that many algorithms only work with *global* orders.
|
||||
|
||||
For example, in the inverse lexicographic order on a single variable `x`,
|
||||
high powers of `x` count as small:
|
||||
|
||||
>>> from sympy.polys.orderings import lex, InverseOrder
|
||||
>>> ilex = InverseOrder(lex)
|
||||
>>> ilex((5,)) < ilex((0,))
|
||||
True
|
||||
"""
|
||||
|
||||
def __init__(self, O):
|
||||
self.O = O
|
||||
|
||||
def __str__(self):
|
||||
return "i" + str(self.O)
|
||||
|
||||
def __call__(self, monomial):
|
||||
def inv(l):
|
||||
if iterable(l):
|
||||
return tuple(inv(x) for x in l)
|
||||
return -l
|
||||
return inv(self.O(monomial))
|
||||
|
||||
@property
|
||||
def is_global(self):
|
||||
if self.O.is_global is True:
|
||||
return False
|
||||
if self.O.is_global is False:
|
||||
return True
|
||||
return None
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, InverseOrder) and other.O == self.O
|
||||
|
||||
def __hash__(self):
|
||||
return hash((self.__class__, self.O))
|
||||
|
||||
lex = LexOrder()
|
||||
grlex = GradedLexOrder()
|
||||
grevlex = ReversedGradedLexOrder()
|
||||
ilex = InverseOrder(lex)
|
||||
igrlex = InverseOrder(grlex)
|
||||
igrevlex = InverseOrder(grevlex)
|
||||
|
||||
_monomial_key = {
|
||||
'lex': lex,
|
||||
'grlex': grlex,
|
||||
'grevlex': grevlex,
|
||||
'ilex': ilex,
|
||||
'igrlex': igrlex,
|
||||
'igrevlex': igrevlex
|
||||
}
|
||||
|
||||
def monomial_key(order=None, gens=None):
|
||||
"""
|
||||
Return a function defining admissible order on monomials.
|
||||
|
||||
The result of a call to :func:`monomial_key` is a function which should
|
||||
be used as a key to :func:`sorted` built-in function, to provide order
|
||||
in a set of monomials of the same length.
|
||||
|
||||
Currently supported monomial orderings are:
|
||||
|
||||
1. lex - lexicographic order (default)
|
||||
2. grlex - graded lexicographic order
|
||||
3. grevlex - reversed graded lexicographic order
|
||||
4. ilex, igrlex, igrevlex - the corresponding inverse orders
|
||||
|
||||
If the ``order`` input argument is not a string but has ``__call__``
|
||||
attribute, then it will pass through with an assumption that the
|
||||
callable object defines an admissible order on monomials.
|
||||
|
||||
If the ``gens`` input argument contains a list of generators, the
|
||||
resulting key function can be used to sort SymPy ``Expr`` objects.
|
||||
|
||||
"""
|
||||
if order is None:
|
||||
order = lex
|
||||
|
||||
if isinstance(order, Symbol):
|
||||
order = str(order)
|
||||
|
||||
if isinstance(order, str):
|
||||
try:
|
||||
order = _monomial_key[order]
|
||||
except KeyError:
|
||||
raise ValueError("supported monomial orderings are 'lex', 'grlex' and 'grevlex', got %r" % order)
|
||||
if hasattr(order, '__call__'):
|
||||
if gens is not None:
|
||||
def _order(expr):
|
||||
return order(expr.as_poly(*gens).degree_list())
|
||||
return _order
|
||||
return order
|
||||
else:
|
||||
raise ValueError("monomial ordering specification must be a string or a callable, got %s" % order)
|
||||
|
||||
class _ItemGetter:
|
||||
"""Helper class to return a subsequence of values."""
|
||||
|
||||
def __init__(self, seq):
|
||||
self.seq = tuple(seq)
|
||||
|
||||
def __call__(self, m):
|
||||
return tuple(m[idx] for idx in self.seq)
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, _ItemGetter):
|
||||
return False
|
||||
return self.seq == other.seq
|
||||
|
||||
def build_product_order(arg, gens):
|
||||
"""
|
||||
Build a monomial order on ``gens``.
|
||||
|
||||
``arg`` should be a tuple of iterables. The first element of each iterable
|
||||
should be a string or monomial order (will be passed to monomial_key),
|
||||
the others should be subsets of the generators. This function will build
|
||||
the corresponding product order.
|
||||
|
||||
For example, build a product of two grlex orders:
|
||||
|
||||
>>> from sympy.polys.orderings import build_product_order
|
||||
>>> from sympy.abc import x, y, z, t
|
||||
|
||||
>>> O = build_product_order((("grlex", x, y), ("grlex", z, t)), [x, y, z, t])
|
||||
>>> O((1, 2, 3, 4))
|
||||
((3, (1, 2)), (7, (3, 4)))
|
||||
|
||||
"""
|
||||
gens2idx = {}
|
||||
for i, g in enumerate(gens):
|
||||
gens2idx[g] = i
|
||||
order = []
|
||||
for expr in arg:
|
||||
name = expr[0]
|
||||
var = expr[1:]
|
||||
|
||||
def makelambda(var):
|
||||
return _ItemGetter(gens2idx[g] for g in var)
|
||||
order.append((monomial_key(name), makelambda(var)))
|
||||
return ProductOrder(*order)
|
||||
Reference in New Issue
Block a user