m2m模型翻译
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

472 lines
15 KiB

"""
This module contains functions for two multivariate resultants. These
are:
- Dixon's resultant.
- Macaulay's resultant.
Multivariate resultants are used to identify whether a multivariate
system has common roots. That is when the resultant is equal to zero.
"""
from sympy.core.mul import (Mul, prod)
from sympy.matrices.dense import (Matrix, diag)
from sympy.polys.polytools import (Poly, degree_list, rem)
from sympy.simplify.simplify import simplify
from sympy.tensor.indexed import IndexedBase
from sympy.polys.monomials import itermonomials, monomial_deg
from sympy.polys.orderings import monomial_key
from sympy.polys.polytools import poly_from_expr, total_degree
from sympy.functions.combinatorial.factorials import binomial
from itertools import combinations_with_replacement
from sympy.utilities.exceptions import sympy_deprecation_warning
class DixonResultant():
"""
A class for retrieving the Dixon's resultant of a multivariate
system.
Examples
========
>>> from sympy import symbols
>>> from sympy.polys.multivariate_resultants import DixonResultant
>>> x, y = symbols('x, y')
>>> p = x + y
>>> q = x ** 2 + y ** 3
>>> h = x ** 2 + y
>>> dixon = DixonResultant(variables=[x, y], polynomials=[p, q, h])
>>> poly = dixon.get_dixon_polynomial()
>>> matrix = dixon.get_dixon_matrix(polynomial=poly)
>>> matrix
Matrix([
[ 0, 0, -1, 0, -1],
[ 0, -1, 0, -1, 0],
[-1, 0, 1, 0, 0],
[ 0, -1, 0, 0, 1],
[-1, 0, 0, 1, 0]])
>>> matrix.det()
0
See Also
========
Notebook in examples: sympy/example/notebooks.
References
==========
.. [1] [Kapur1994]_
.. [2] [Palancz08]_
"""
def __init__(self, polynomials, variables):
"""
A class that takes two lists, a list of polynomials and list of
variables. Returns the Dixon matrix of the multivariate system.
Parameters
----------
polynomials : list of polynomials
A list of m n-degree polynomials
variables: list
A list of all n variables
"""
self.polynomials = polynomials
self.variables = variables
self.n = len(self.variables)
self.m = len(self.polynomials)
a = IndexedBase("alpha")
# A list of n alpha variables (the replacing variables)
self.dummy_variables = [a[i] for i in range(self.n)]
# A list of the d_max of each variable.
self._max_degrees = [max(degree_list(poly)[i] for poly in self.polynomials)
for i in range(self.n)]
@property
def max_degrees(self):
sympy_deprecation_warning(
"""
The max_degrees property of DixonResultant is deprecated.
""",
deprecated_since_version="1.5",
active_deprecations_target="deprecated-dixonresultant-properties",
)
return self._max_degrees
def get_dixon_polynomial(self):
r"""
Returns
=======
dixon_polynomial: polynomial
Dixon's polynomial is calculated as:
delta = Delta(A) / ((x_1 - a_1) ... (x_n - a_n)) where,
A = |p_1(x_1,... x_n), ..., p_n(x_1,... x_n)|
|p_1(a_1,... x_n), ..., p_n(a_1,... x_n)|
|... , ..., ...|
|p_1(a_1,... a_n), ..., p_n(a_1,... a_n)|
"""
if self.m != (self.n + 1):
raise ValueError('Method invalid for given combination.')
# First row
rows = [self.polynomials]
temp = list(self.variables)
for idx in range(self.n):
temp[idx] = self.dummy_variables[idx]
substitution = {var: t for var, t in zip(self.variables, temp)}
rows.append([f.subs(substitution) for f in self.polynomials])
A = Matrix(rows)
terms = zip(self.variables, self.dummy_variables)
product_of_differences = Mul(*[a - b for a, b in terms])
dixon_polynomial = (A.det() / product_of_differences).factor()
return poly_from_expr(dixon_polynomial, self.dummy_variables)[0]
def get_upper_degree(self):
sympy_deprecation_warning(
"""
The get_upper_degree() method of DixonResultant is deprecated. Use
get_max_degrees() instead.
""",
deprecated_since_version="1.5",
active_deprecations_target="deprecated-dixonresultant-properties"
)
list_of_products = [self.variables[i] ** self._max_degrees[i]
for i in range(self.n)]
product = prod(list_of_products)
product = Poly(product).monoms()
return monomial_deg(*product)
def get_max_degrees(self, polynomial):
r"""
Returns a list of the maximum degree of each variable appearing
in the coefficients of the Dixon polynomial. The coefficients are
viewed as polys in $x_1, x_2, \dots, x_n$.
"""
deg_lists = [degree_list(Poly(poly, self.variables))
for poly in polynomial.coeffs()]
max_degrees = [max(degs) for degs in zip(*deg_lists)]
return max_degrees
def get_dixon_matrix(self, polynomial):
r"""
Construct the Dixon matrix from the coefficients of polynomial
\alpha. Each coefficient is viewed as a polynomial of x_1, ...,
x_n.
"""
max_degrees = self.get_max_degrees(polynomial)
# list of column headers of the Dixon matrix.
monomials = itermonomials(self.variables, max_degrees)
monomials = sorted(monomials, reverse=True,
key=monomial_key('lex', self.variables))
dixon_matrix = Matrix([[Poly(c, *self.variables).coeff_monomial(m)
for m in monomials]
for c in polynomial.coeffs()])
# remove columns if needed
if dixon_matrix.shape[0] != dixon_matrix.shape[1]:
keep = [column for column in range(dixon_matrix.shape[-1])
if any(element != 0 for element
in dixon_matrix[:, column])]
dixon_matrix = dixon_matrix[:, keep]
return dixon_matrix
def KSY_precondition(self, matrix):
"""
Test for the validity of the Kapur-Saxena-Yang precondition.
The precondition requires that the column corresponding to the
monomial 1 = x_1 ^ 0 * x_2 ^ 0 * ... * x_n ^ 0 is not a linear
combination of the remaining ones. In SymPy notation this is
the last column. For the precondition to hold the last non-zero
row of the rref matrix should be of the form [0, 0, ..., 1].
"""
if matrix.is_zero_matrix:
return False
m, n = matrix.shape
# simplify the matrix and keep only its non-zero rows
matrix = simplify(matrix.rref()[0])
rows = [i for i in range(m) if any(matrix[i, j] != 0 for j in range(n))]
matrix = matrix[rows,:]
condition = Matrix([[0]*(n-1) + [1]])
if matrix[-1,:] == condition:
return True
else:
return False
def delete_zero_rows_and_columns(self, matrix):
"""Remove the zero rows and columns of the matrix."""
rows = [
i for i in range(matrix.rows) if not matrix.row(i).is_zero_matrix]
cols = [
j for j in range(matrix.cols) if not matrix.col(j).is_zero_matrix]
return matrix[rows, cols]
def product_leading_entries(self, matrix):
"""Calculate the product of the leading entries of the matrix."""
res = 1
for row in range(matrix.rows):
for el in matrix.row(row):
if el != 0:
res = res * el
break
return res
def get_KSY_Dixon_resultant(self, matrix):
"""Calculate the Kapur-Saxena-Yang approach to the Dixon Resultant."""
matrix = self.delete_zero_rows_and_columns(matrix)
_, U, _ = matrix.LUdecomposition()
matrix = self.delete_zero_rows_and_columns(simplify(U))
return self.product_leading_entries(matrix)
class MacaulayResultant():
"""
A class for calculating the Macaulay resultant. Note that the
polynomials must be homogenized and their coefficients must be
given as symbols.
Examples
========
>>> from sympy import symbols
>>> from sympy.polys.multivariate_resultants import MacaulayResultant
>>> x, y, z = symbols('x, y, z')
>>> a_0, a_1, a_2 = symbols('a_0, a_1, a_2')
>>> b_0, b_1, b_2 = symbols('b_0, b_1, b_2')
>>> c_0, c_1, c_2,c_3, c_4 = symbols('c_0, c_1, c_2, c_3, c_4')
>>> f = a_0 * y - a_1 * x + a_2 * z
>>> g = b_1 * x ** 2 + b_0 * y ** 2 - b_2 * z ** 2
>>> h = c_0 * y * z ** 2 - c_1 * x ** 3 + c_2 * x ** 2 * z - c_3 * x * z ** 2 + c_4 * z ** 3
>>> mac = MacaulayResultant(polynomials=[f, g, h], variables=[x, y, z])
>>> mac.monomial_set
[x**4, x**3*y, x**3*z, x**2*y**2, x**2*y*z, x**2*z**2, x*y**3,
x*y**2*z, x*y*z**2, x*z**3, y**4, y**3*z, y**2*z**2, y*z**3, z**4]
>>> matrix = mac.get_matrix()
>>> submatrix = mac.get_submatrix(matrix)
>>> submatrix
Matrix([
[-a_1, a_0, a_2, 0],
[ 0, -a_1, 0, 0],
[ 0, 0, -a_1, 0],
[ 0, 0, 0, -a_1]])
See Also
========
Notebook in examples: sympy/example/notebooks.
References
==========
.. [1] [Bruce97]_
.. [2] [Stiller96]_
"""
def __init__(self, polynomials, variables):
"""
Parameters
==========
variables: list
A list of all n variables
polynomials : list of SymPy polynomials
A list of m n-degree polynomials
"""
self.polynomials = polynomials
self.variables = variables
self.n = len(variables)
# A list of the d_max of each polynomial.
self.degrees = [total_degree(poly, *self.variables) for poly
in self.polynomials]
self.degree_m = self._get_degree_m()
self.monomials_size = self.get_size()
# The set T of all possible monomials of degree degree_m
self.monomial_set = self.get_monomials_of_certain_degree(self.degree_m)
def _get_degree_m(self):
r"""
Returns
=======
degree_m: int
The degree_m is calculated as 1 + \sum_1 ^ n (d_i - 1),
where d_i is the degree of the i polynomial
"""
return 1 + sum(d - 1 for d in self.degrees)
def get_size(self):
r"""
Returns
=======
size: int
The size of set T. Set T is the set of all possible
monomials of the n variables for degree equal to the
degree_m
"""
return binomial(self.degree_m + self.n - 1, self.n - 1)
def get_monomials_of_certain_degree(self, degree):
"""
Returns
=======
monomials: list
A list of monomials of a certain degree.
"""
monomials = [Mul(*monomial) for monomial
in combinations_with_replacement(self.variables,
degree)]
return sorted(monomials, reverse=True,
key=monomial_key('lex', self.variables))
def get_row_coefficients(self):
"""
Returns
=======
row_coefficients: list
The row coefficients of Macaulay's matrix
"""
row_coefficients = []
divisible = []
for i in range(self.n):
if i == 0:
degree = self.degree_m - self.degrees[i]
monomial = self.get_monomials_of_certain_degree(degree)
row_coefficients.append(monomial)
else:
divisible.append(self.variables[i - 1] **
self.degrees[i - 1])
degree = self.degree_m - self.degrees[i]
poss_rows = self.get_monomials_of_certain_degree(degree)
for div in divisible:
for p in poss_rows:
if rem(p, div) == 0:
poss_rows = [item for item in poss_rows
if item != p]
row_coefficients.append(poss_rows)
return row_coefficients
def get_matrix(self):
"""
Returns
=======
macaulay_matrix: Matrix
The Macaulay numerator matrix
"""
rows = []
row_coefficients = self.get_row_coefficients()
for i in range(self.n):
for multiplier in row_coefficients[i]:
coefficients = []
poly = Poly(self.polynomials[i] * multiplier,
*self.variables)
for mono in self.monomial_set:
coefficients.append(poly.coeff_monomial(mono))
rows.append(coefficients)
macaulay_matrix = Matrix(rows)
return macaulay_matrix
def get_reduced_nonreduced(self):
r"""
Returns
=======
reduced: list
A list of the reduced monomials
non_reduced: list
A list of the monomials that are not reduced
Definition
==========
A polynomial is said to be reduced in x_i, if its degree (the
maximum degree of its monomials) in x_i is less than d_i. A
polynomial that is reduced in all variables but one is said
simply to be reduced.
"""
divisible = []
for m in self.monomial_set:
temp = []
for i, v in enumerate(self.variables):
temp.append(bool(total_degree(m, v) >= self.degrees[i]))
divisible.append(temp)
reduced = [i for i, r in enumerate(divisible)
if sum(r) < self.n - 1]
non_reduced = [i for i, r in enumerate(divisible)
if sum(r) >= self.n -1]
return reduced, non_reduced
def get_submatrix(self, matrix):
r"""
Returns
=======
macaulay_submatrix: Matrix
The Macaulay denominator matrix. Columns that are non reduced are kept.
The row which contains one of the a_{i}s is dropped. a_{i}s
are the coefficients of x_i ^ {d_i}.
"""
reduced, non_reduced = self.get_reduced_nonreduced()
# if reduced == [], then det(matrix) should be 1
if reduced == []:
return diag([1])
# reduced != []
reduction_set = [v ** self.degrees[i] for i, v
in enumerate(self.variables)]
ais = list([self.polynomials[i].coeff(reduction_set[i])
for i in range(self.n)])
reduced_matrix = matrix[:, reduced]
keep = []
for row in range(reduced_matrix.rows):
check = [ai in reduced_matrix[row, :] for ai in ais]
if True not in check:
keep.append(row)
return matrix[keep, non_reduced]