极简 Sylvester 结式消元介绍
Resultant
两个一元多项式在一个域或者交换环上的 Resultant 为它们对应的 Sylvester matrix 的行列式。
记两个一元多项式 f(x),g(x) 为
f(x)=a0xn+a1xn−1+...+ang(x)=b0xm+b1xm−1+...+bn
其的 Sylvester matrix 构造方式如下
- 取 f(x) 的系数,依次在左上角起向下构造 m 行,每行右移一格补零
- 取 g(x) 的系数,依次在左下角起向下构造 n 行,每行右移一格补零
具体表示为
R(f,g)=⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎡a00⋮0b00⋮0a1a00b1b00⋯⋯⋱⋯⋯⋯⋱⋯anan−1a0bmbm−1b00ana10bmb1⋯⋯⋱⋯⋯⋯⋱⋯00⋮an00⋮bm⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎤
然后定义结式 res(f,g)=det(R(f,g))
其有如下重要性质
- 多项式 f 和 g 有公共根的充要条件就是 R(f,g)=0
也就是根据这个性质,其在 ctf 中解决一些方程消元的问题有着重要的地位
example:
一个简单的例子,设
f(x)=x2−2x+1g(x)=x−1
我们知道 deg(f)=2,deg(g)=1,所以只要让 f(x) 从左上角起向下构造 1 行,g(x) 从左下角起向下构造 2 行,那么我们可以构造一个 3×3 的矩阵,即
⎣⎢⎡110−2−1110−1⎦⎥⎤
简单的计算一下行列式可以发现是 0,然后简单验算一下它们全是用共根 1。
Sylvester 结式消元
假设现在有二元多项式
f(x,y)=a0xmyn+aixm−1yn−1+...+ang(x,y)=b0xiyj+bixi−1yj−1+...+bm
我们可以考虑将 x 视为常数,构造 Sylvester matrix,然后计算行列式,这样子就会得到消去 x 的新式子,然后对该式子求解即可得到 y,最后进行回代就可以计算出 x。
python 实现
根据结式的定义,我们可以很容易写出代码来实现计算两个多项式的 Sylvester matrix
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| from sympy import Matrix, Poly from sympy.abc import x, y, z
def sylvester_matrix(f, g, x): F = Poly(f, x) G = Poly(g, x) a = F.all_coeffs() b = G.all_coeffs() m = F.degree() n = G.degree()
def b_row(cf, c, l): rows = [] pad_l = l - len(cf) for i in range(c): row = [0]*i + cf + [0]*(pad_l - i) rows.append(row) return rows
row_f = b_row(a, n, m + n) row_g = b_row(b, m, m + n) return Matrix(row_f + row_g)
|
可以简单测试一下,假设有一元多项式
f(x,y)=7x+xy+123yg(x,y)=4y+x5+6xy2
我们直接调用上面的代码
1 2 3 4
| f = 7 * x + x * y + 123 * y g = 4 * y + x**5 + 6 * x * y**2 R = sylvester_matrix(f, g, x).det() print(R)
|
得到
−738y7−20660∗y6−28153273675y5−1010576y4−1758218y3+48020y2+67228y
可以和 sage 比对一下
1 2 3 4 5
| R.<x, y> = QQ[] f = 7 * x + x * y + 123 * y g = 4 * y + x**5 + 6 * x * y**2 f.sylvester_matrix(g,x).det()
|
实际上是一样的,如果要实际使用并且解这个方程的话其实还是推荐用 sage 了,因为自己写的肯定没 sage 好的啦 XD