丢番图

备注

对于专注于解决丢番图方程的初学者友好指南,请参阅 代数求解丢番图方程

丢番图方程

“丢番图”一词源自于丢番图,一位生活在公元250年左右亚历山大城的数学家。他常被称为“代数之父”,在其著名著作《算术》中提出了150个问题,标志着数论领域的早期开端,该领域研究整数及其性质。丢番图方程在数论中起着核心且重要的作用。

我们将形如 \(f(x_1, x_2, \ldots x_n) = 0\) 的方程称为“丢番图方程”,其中 \(n \geq 2\)\(x_1, x_2, \ldots x_n\) 是整数变量。如果我们能找到 \(n\) 个整数 \(a_1, a_2, \ldots a_n\) 使得 \(x_1 = a_1, x_2 = a_2, \ldots x_n = a_n\) 满足上述方程,我们称该方程是可解的。你可以在 [1][2] 中阅读更多关于丢番图方程的内容。

目前,可以使用 diophantine() 以及丢番图模块的其他辅助函数来求解以下五种类型的丢番图方程。

  • 线性丢番图方程:\(a_1x_1 + a_2x_2 + \ldots + a_nx_n = b\)

  • 一般二元二次方程:\(ax^2 + bxy + cy^2 + dx + ey + f = 0\)

  • 齐次三元二次方程:\(ax^2 + by^2 + cz^2 + dxy + eyz + fzx = 0\)

  • 扩展的毕达哥拉斯方程:\(a_{1}x_{1}^2 + a_{2}x_{2}^2 + \ldots + a_{n}x_{n}^2 = a_{n+1}x_{n+1}^2\)

  • 一般平方和:\(x_{1}^2 + x_{2}^2 + \ldots + x_{n}^2 = k\)

模块结构

此模块包含 diophantine() 和用于求解某些丢番图方程所需的辅助函数。其结构如下。

当一个方程被传递给 diophantine() 时,它会尝试分解方程(如果可能的话),并通过分别调用 diop_solve() 来求解每个因子给出的方程。然后,所有结果通过 merge_solution() 合并。

diop_solve() 内部使用 classify_diop() 来确定给定方程的类型(以及一些其他细节),然后根据返回的类型调用适当的求解函数。例如,如果 classify_diop() 返回方程类型为“线性”,那么 diop_solve() 将调用 diop_linear() 来求解方程。

每个函数,diop_linear()diop_quadratic()diop_ternary_quadratic()diop_general_pythagorean()diop_general_sum_of_squares(),都解决了一种特定类型的方程,其类型可以通过函数名称轻松猜测。

除了这些功能之外,“Diophantine 模块”中还有相当多的其他功能,所有这些功能都列在用户功能和内部功能下。

教程

首先,让我们导入 Diophantine 模块的最高 API。

>>> from sympy.solvers.diophantine import diophantine

在我们开始解方程之前,我们需要定义变量。

>>> from sympy import symbols
>>> x, y, z = symbols("x, y, z", integer=True)

让我们从解决最简单的丢番图方程类型开始,即线性丢番图方程。让我们解 \(2x + 3y = 5\)。注意,尽管我们在上面以这种形式写出方程,但当我们将其输入到丢番图模块中的任何函数时,它需要以 \(eq = 0\) 的形式输入。

>>> diophantine(2*x + 3*y - 5)
{(3*t_0 - 5, 5 - 2*t_0)}

请注意,在最高API的下一级,我们可以通过调用 diop_solve() 来解决完全相同的方程。

>>> from sympy.solvers.diophantine.diophantine import diop_solve
>>> diop_solve(2*x + 3*y - 5)
(3*t_0 - 5, 5 - 2*t_0)

注意它返回的是一个元组而不是一个集合。diophantine() 总是返回一个元组集合。但是 diop_solve() 可能返回一个单独的元组或一个元组集合,这取决于给定方程的类型。

我们也可以通过调用 diop_linear() 来解决这个方程,这是 diop_solve() 在内部调用的方法。

>>> from sympy.solvers.diophantine.diophantine import diop_linear
>>> diop_linear(2*x + 3*y - 5)
(3*t_0 - 5, 5 - 2*t_0)

如果给定的方程没有解,那么输出将如下所示。

>>> diophantine(2*x + 4*y - 3)
set()
>>> diop_solve(2*x + 4*y - 3)
(None, None)
>>> diop_linear(2*x + 4*y - 3)
(None, None)

请注意,除了最高级别的API外,在没有解决方案的情况下,将返回一个包含 \(None\) 的元组。元组的大小与变量的数量相同。此外,可以通过传递自定义参数来专门设置解决方案中使用的参数。考虑以下示例:

>>> m = symbols("m", integer=True)
>>> diop_solve(2*x + 3*y - 5, m)
(3*m_0 - 5, 5 - 2*m_0)

对于线性丢番图方程,自定义参数是用于解中每个自由变量的前缀。考虑以下示例:

>>> diop_solve(2*x + 3*y - 5*z + 7, m)
(m_0, m_0 + 5*m_1 - 14, m_0 + 3*m_1 - 7)

在上述解决方案中,m_0 和 m_1 是独立的自由变量。

请注意,目前用户只能为线性丢番图方程和二元二次方程设置参数。

让我们尝试解决一个二元二次方程,这是一个具有两个变量且次数为二的方程。在尝试解决这些方程之前,了解与方程相关的各种情况会非常有帮助。请参考 [3][4] 以获取不同情况和解的性质的详细分析。让我们定义 \(\Delta = b^2 - 4ac\) 相对于二元二次方程 \(ax^2 + bxy + cy^2 + dx + ey + f = 0\)

\(\Delta < 0\) 时,可能没有解或只有有限个解。

>>> diophantine(x**2 - 4*x*y + 8*y**2 - 3*x + 7*y - 5)
{(2, 1), (5, 1)}

在上式中,\(\Delta = (-4)^2 - 4*1*8 = -16\),因此只存在有限个解。

\(\Delta = 0\) 时,我们可能既没有解,也可能有参数化解。

>>> diophantine(3*x**2 - 6*x*y + 3*y**2 - 3*x + 7*y - 5)
set()
>>> diophantine(x**2 - 4*x*y + 4*y**2 - 3*x + 7*y - 5)
{(-2*t**2 - 7*t + 10, -t**2 - 3*t + 5)}
>>> diophantine(x**2 + 2*x*y + y**2 - 3*x - 3*y)
{(t_0, -t_0), (t_0, 3 - t_0)}

最有趣的例子是当 \(\Delta > 0\) 且它不是一个完全平方数时。在这种情况下,方程要么没有解,要么有无限多个解。考虑以下 \(\Delta = 8\) 的情况。

>>> diophantine(x**2 - 4*x*y + 2*y**2 - 3*x + 7*y - 5)
set()
>>> from sympy import sqrt
>>> n = symbols("n", integer=True)
>>> s = diophantine(x**2 -  2*y**2 - 2*x - 4*y, n)
>>> x_1, y_1 = s.pop()
>>> x_2, y_2 = s.pop()
>>> x_n = -(-2*sqrt(2) + 3)**n/2 + sqrt(2)*(-2*sqrt(2) + 3)**n/2 - sqrt(2)*(2*sqrt(2) + 3)**n/2 - (2*sqrt(2) + 3)**n/2 + 1
>>> x_1 == x_n or x_2 == x_n
True
>>> y_n = -sqrt(2)*(-2*sqrt(2) + 3)**n/4 + (-2*sqrt(2) + 3)**n/2 + sqrt(2)*(2*sqrt(2) + 3)**n/4 + (2*sqrt(2) + 3)**n/2 - 1
>>> y_1 == y_n or y_2 == y_n
True

这里 \(n\) 是一个整数。尽管 x_n 和 y_n 可能看起来不像整数,但将特定值代入 n(并简化)表明它们确实是。例如,考虑以下示例,我们将 n 设为 9。

>>> from sympy import simplify
>>> simplify(x_n.subs({n: 9}))
-9369318

任何形式的二元二次方程 \(ax^2 + bxy + cy^2 + dx + ey + f = 0\) 都可以被转换为等价形式 \(X^2 - DY^2 = N\)

>>> from sympy.solvers.diophantine.diophantine import find_DN, diop_DN, transformation_to_DN
>>> find_DN(x**2 - 3*x*y + y**2 - 7*x + 5*y - 3)
(5, 920)

因此,上述方程在经过线性变换后等价于方程 \(X^2 - 5Y^2 = 920\)。如果我们想要找到这个线性变换,我们可以使用 transformation_to_DN()

>>> A, B = transformation_to_DN(x**2 - 3*x*y + y**2 - 7*x + 5*y - 3)

这里 A 是一个 2 X 2 的矩阵,B 是一个 2 X 1 的矩阵,使得变换

\[\begin{split}\begin{bmatrix} X\\Y \end{bmatrix} = A \begin{bmatrix} x\\y \end{bmatrix} + B\end{split}\]

给出方程 \(X^2 -5Y^2 = 920\)\(A\)\(B\) 的值如下。

>>> A
Matrix([
[1/10, 3/10],
[   0,  1/5]])
>>> B
Matrix([
[  1/5],
[-11/5]])

我们可以通过传递 \(D\)\(N\)diop_DN() 来解形如 \(X^2 - DY^2 = N\) 的方程。

>>> diop_DN(5, 920)
[]

不幸的是,我们的方程没有解。

现在让我们转向齐次三元二次方程。这些方程的形式为 \(ax^2 + by^2 + cz^2 + dxy + eyz + fzx = 0\)。这类方程要么有无限多的解,要么没有解(除了明显的解 (0, 0, 0))

>>> diophantine(3*x**2 + 4*y**2 - 5*z**2 + 4*x*y + 6*y*z + 7*z*x)
{(0, 0, 0)}
>>> diophantine(3*x**2 + 4*y**2 - 5*z**2 + 4*x*y - 7*y*z + 7*z*x)
{(-16*p**2 + 28*p*q + 20*q**2, 3*p**2 + 38*p*q - 25*q**2, 4*p**2 - 24*p*q + 68*q**2)}

如果你只对一个基础解感兴趣,而不是参数化的通解(更准确地说,是通解之一),你可以使用 diop_ternary_quadratic()

>>> from sympy.solvers.diophantine.diophantine import diop_ternary_quadratic
>>> diop_ternary_quadratic(3*x**2 + 4*y**2 - 5*z**2 + 4*x*y - 7*y*z + 7*z*x)
(-4, 5, 1)

diop_ternary_quadratic() 首先将给定的方程转换为等价的 \(w^2 = AX^2 + BY^2\) 形式的方程,然后使用 descent() 来求解后者。你可以参考 transformation_to_normal() 的文档来了解更多关于此的内容。通过使用上述的 descent(),方程 \(w^2 = AX^2 + BY^2\) 可以更容易地求解。

>>> from sympy.solvers.diophantine.diophantine import descent
>>> descent(3, 1) # solves the equation w**2 = 3*Y**2 + Z**2
(1, 0, 1)

这里解决方案元组按顺序为 (w, Y, Z)

扩展的勾股方程,\(a_{1}x_{1}^2 + a_{2}x_{2}^2 + \ldots + a_{n}x_{n}^2 = a_{n+1}x_{n+1}^2\) 和一般的平方和方程,\(x_{1}^2 + x_{2}^2 + \ldots + x_{n}^2 = k\) 也可以使用Diophantine模块来求解。

>>> from sympy.abc import a, b, c, d, e, f
>>> diophantine(9*a**2 + 16*b**2 + c**2 + 49*d**2 + 4*e**2 - 25*f**2)
{(70*t1**2 + 70*t2**2 + 70*t3**2 + 70*t4**2 - 70*t5**2, 105*t1*t5, 420*t2*t5, 60*t3*t5, 210*t4*t5, 42*t1**2 + 42*t2**2 + 42*t3**2 + 42*t4**2 + 42*t5**2)}

函数 diop_general_pythagorean() 也可以直接调用来解决相同的方程。你可以调用 diop_general_pythagorean() 或者使用高级API。对于一般的平方和,这也是成立的,但调用 diop_general_sum_of_squares() 的一个优势是你可以控制返回多少个解。

>>> from sympy.solvers.diophantine.diophantine import diop_general_sum_of_squares
>>> eq = a**2 + b**2 + c**2 + d**2 - 18
>>> diophantine(eq)
{(0, 0, 3, 3), (0, 1, 1, 4), (1, 2, 2, 3)}
>>> diop_general_sum_of_squares(eq, 2)
{(0, 0, 3, 3), (1, 2, 2, 3)}

sum_of_squares() 例程将提供一个迭代器,返回解,并且可以控制解是否包含零(不包含零的解首先返回):

>>> from sympy.solvers.diophantine.diophantine import sum_of_squares
>>> sos = sum_of_squares(18, 4, zeros=True)
>>> next(sos)
(1, 2, 2, 3)
>>> next(sos)
(0, 0, 3, 3)

简单的埃及分数也可以通过Diophantine模块找到。例如,以下是可能将1/2表示为两个单位分数之和的方法:

>>> from sympy import Eq, S
>>> diophantine(Eq(1/x + 1/y, S(1)/2))
{(-2, 1), (1, -2), (3, 6), (4, 4), (6, 3)}

要更深入地理解 Diophantine 模块,请参考以下博客。

https://thilinaatsympy.wordpress.com/

参考文献

用户功能

此函数通过 from sympy import * 导入到全局命名空间中:

sympy.solvers.diophantine.diophantine.diophantine(eq, param=t, syms=None, permute=False)[源代码][源代码]

通过将丢番图方程 eq 转换为等于零的项的乘积,简化其求解过程。

示例

>>> from sympy import diophantine
>>> from sympy.abc import a, b
>>> eq = a**4 + b**4 - (2**4 + 3**4)
>>> diophantine(eq)
{(2, 3)}
>>> diophantine(eq, permute=True)
{(-3, -2), (-3, 2), (-2, -3), (-2, 3), (2, -3), (2, 3), (3, -2), (3, 2)}
>>> from sympy.abc import x, y, z
>>> diophantine(x**2 - y**2)
{(t_0, -t_0), (t_0, t_0)}
>>> diophantine(x*(2*x + 3*y - z))
{(0, n1, n2), (t_0, t_1, 2*t_0 + 3*t_1)}
>>> diophantine(x**2 + 3*x*y + 4*x)
{(0, n1), (-3*t_0 - 4, t_0)}

并且这个函数是通过 from sympy.solvers.diophantine import * 导入的:

sympy.solvers.diophantine.diophantine.classify_diop(eq, _dict=True)[源代码][源代码]

内部函数

这些函数旨在在 Diophantine 模块中内部使用。

sympy.solvers.diophantine.diophantine.base_solution_linear(c, a, b, t=None)[源代码][源代码]

返回线性方程 \(ax + by = c\) 的基本解。

示例

>>> from sympy.solvers.diophantine.diophantine import base_solution_linear
>>> from sympy.abc import t
>>> base_solution_linear(5, 2, 3) # equation 2*x + 3*y = 5
(-5, 5)
>>> base_solution_linear(0, 5, 7) # equation 5*x + 7*y = 0
(0, 0)
>>> base_solution_linear(5, 2, 3, t) # equation 2*x + 3*y = 5
(3*t - 5, 5 - 2*t)
>>> base_solution_linear(0, 5, 7, t) # equation 5*x + 7*y = 0
(7*t, -5*t)
sympy.solvers.diophantine.diophantine.cornacchia(
a: int,
b: int,
m: int,
) set[tuple[int, int]][源代码][源代码]

解决 \(ax^2 + by^2 = m\) 其中 \(\gcd(a, b) = 1 = \gcd(a, m)\)\(a, b > 0\)

参考文献

[1]
  1. Nitaj, “L’algorithme de Cornacchia”

[2]

通过Cornacchia方法求解丢番图方程 ax**2 + by**2 = m,[在线],可获取地址: http://www.numbertheory.org/php/cornacchia.html

示例

>>> from sympy.solvers.diophantine.diophantine import cornacchia
>>> cornacchia(2, 3, 35) # equation 2x**2 + 3y**2 = 35
{(2, 3), (4, 1)}
>>> cornacchia(1, 1, 25) # equation x**2 + y**2 = 25
{(4, 3)}
sympy.solvers.diophantine.diophantine.transformation_to_normal(eq)[源代码][源代码]

返回将一般三元二次方程 eq (\(ax^2 + by^2 + cz^2 + dxy + eyz + fxz\)) 转换为无交叉项形式 \(ax^2 + by^2 + cz^2 = 0\) 的变换矩阵。这并不用于求解三元二次方程;它仅是为了完整性而实现的。

sympy.solvers.diophantine.diophantine.diop_ternary_quadratic(eq, parameterize=False)[源代码][源代码]

求解一般二次三元形式,\(ax^2 + by^2 + cz^2 + fxy + gyz + hxz = 0\)

返回一个元组 \((x, y, z)\),这是上述方程的一个基本解。如果没有解,则返回 \((None, None, None)\)

示例

>>> from sympy.abc import x, y, z
>>> from sympy.solvers.diophantine.diophantine import diop_ternary_quadratic
>>> diop_ternary_quadratic(x**2 + 3*y**2 - z**2)
(1, 0, 1)
>>> diop_ternary_quadratic(4*x**2 + 5*y**2 - z**2)
(1, 0, 2)
>>> diop_ternary_quadratic(45*x**2 - 7*y**2 - 8*x*y - z**2)
(28, 45, 105)
>>> diop_ternary_quadratic(x**2 - 49*y**2 - z**2 + 13*z*y -8*x*y)
(9, 1, 5)
sympy.solvers.diophantine.diophantine.square_factor(a)[源代码][源代码]

返回一个整数 \(c\),使得 \(a = c^2k, \ c,k \in Z\)。其中 \(k\) 是无平方因子。\(a\) 可以是一个整数或一个因子字典。

示例

>>> from sympy.solvers.diophantine.diophantine import square_factor
>>> square_factor(24)
2
>>> square_factor(-36*3)
6
>>> square_factor(1)
1
>>> square_factor({3: 2, 2: 1, -1: 1})  # -18
3
sympy.solvers.diophantine.diophantine.descent(A, B)[源代码][源代码]

使用带有格基约化的拉格朗日下降法返回非平凡解 (x, y, z) 给 \(x^2 = Ay^2 + Bz^2\)。假设 \(A\)\(B\) 对于存在这样的解是有效的。

这比普通的拉格朗日下降算法更快,因为使用了高斯消元法。

参考文献

[1]

Cremona, J. E., Rusin, D. (2003). 有理二次曲线的有效解法。计算数学,72(243),1417-1441。https://doi.org/10.1090/S0025-5718-02-01480-1

示例

>>> from sympy.solvers.diophantine.diophantine import descent
>>> descent(3, 1) # x**2 = 3*y**2 + z**2
(1, 0, 1)

\((x, y, z) = (1, 0, 1)\) 是上述方程的一个解。

>>> descent(41, -113)
(-16, -3, 1)
sympy.solvers.diophantine.diophantine.diop_general_pythagorean(eq, param=m)[源代码][源代码]

解决一般勾股方程,\(a_{1}^2x_{1}^2 + a_{2}^2x_{2}^2 + . . . + a_{n}^2x_{n}^2 - a_{n + 1}^2x_{n + 1}^2 = 0\)

返回一个元组,其中包含方程的参数化解,按与输入变量相同的顺序排序。

示例

>>> from sympy.solvers.diophantine.diophantine import diop_general_pythagorean
>>> from sympy.abc import a, b, c, d, e
>>> diop_general_pythagorean(a**2 + b**2 + c**2 - d**2)
(m1**2 + m2**2 - m3**2, 2*m1*m3, 2*m2*m3, m1**2 + m2**2 + m3**2)
>>> diop_general_pythagorean(9*a**2 - 4*b**2 + 16*c**2 + 25*d**2 + e**2)
(10*m1**2  + 10*m2**2  + 10*m3**2 - 10*m4**2, 15*m1**2  + 15*m2**2  + 15*m3**2  + 15*m4**2, 15*m1*m4, 12*m2*m4, 60*m3*m4)
sympy.solvers.diophantine.diophantine.diop_general_sum_of_squares(eq, limit=1)[源代码][源代码]

求解方程 \(x_{1}^2 + x_{2}^2 + . . . + x_{n}^2 - k = 0\)

最多返回 limit 个解决方案。

示例

>>> from sympy.solvers.diophantine.diophantine import diop_general_sum_of_squares
>>> from sympy.abc import a, b, c, d, e
>>> diop_general_sum_of_squares(a**2 + b**2 + c**2 + d**2 + e**2 - 2345)
{(15, 22, 22, 24, 24)}
sympy.solvers.diophantine.diophantine.diop_general_sum_of_even_powers(eq, limit=1)[源代码][源代码]

求解方程 \(x_{1}^e + x_{2}^e + . . . + x_{n}^e - k = 0\) 其中 \(e\) 是一个偶数整数次幂。

最多返回 limit 个解决方案。

示例

>>> from sympy.solvers.diophantine.diophantine import diop_general_sum_of_even_powers
>>> from sympy.abc import a, b
>>> diop_general_sum_of_even_powers(a**4 + b**4 - (2**4 + 3**4))
{(2, 3)}
sympy.solvers.diophantine.diophantine.power_representation(n, p, k, zeros=False)[源代码][源代码]

返回一个生成器,用于查找整数的 k-元组 \((n_{1}, n_{2}, . . . n_{k})\),使得 \(n = n_{1}^p + n_{2}^p + . . . n_{k}^p\)

示例

>>> from sympy.solvers.diophantine.diophantine import power_representation

将 1729 表示为两个立方之和:

>>> f = power_representation(1729, 3, 2)
>>> next(f)
(9, 10)
>>> next(f)
(1, 12)

如果标志 \(zeros\) 为 True,解可能包含带有零的元组;任何此类解将在不带零的解之后生成:

>>> list(power_representation(125, 2, 3, zeros=True))
[(5, 6, 8), (3, 4, 10), (0, 5, 10), (0, 2, 11)]

对于偶数 \(p\),可以使用 \(permute_sign\) 函数来获取所有带符号的值:

>>> from sympy.utilities.iterables import permute_signs
>>> list(permute_signs((1, 12)))
[(1, 12), (-1, 12), (1, -12), (-1, -12)]

所有可能的带符号排列也可以获得:

>>> from sympy.utilities.iterables import signed_permutations
>>> list(signed_permutations((1, 12)))
[(1, 12), (-1, 12), (1, -12), (-1, -12), (12, 1), (-12, 1), (12, -1), (-12, -1)]
sympy.solvers.diophantine.diophantine.partition(n, k=None, zeros=False)[源代码][源代码]

返回一个生成器,可用于生成整数 \(n\) 的分区。

示例

>>> from sympy.solvers.diophantine.diophantine import partition
>>> f = partition(5)
>>> next(f)
(1, 1, 1, 1, 1)
>>> next(f)
(1, 1, 1, 2)
>>> g = partition(5, 3)
>>> next(g)
(1, 1, 3)
>>> next(g)
(1, 2, 2)
>>> g = partition(5, 3, zeros=True)
>>> next(g)
(0, 0, 5)
sympy.solvers.diophantine.diophantine.sum_of_three_squares(n)[源代码][源代码]

返回一个三元组 \((a, b, c)\),使得 \(a^2 + b^2 + c^2 = n\)\(a, b, c \geq 0\)

如果存在 \(a, m \in \mathbb{Z}\) 使得 \(n = 4^a(8m + 7)\),则返回 None。详见 [1]

参数:
n整数

非负整数

返回:
(int, int, int) | None : 满足 a**2 + b**2 + c**2 = n 的非负整数三元组 (a, b, c)3-元组非负整数

a,b,c 按升序排列。如果没有这样的 (a,b,c),则为 None

Raises:
ValueError

如果 n 是一个负整数

参见

power_representation

sum_of_three_squares(n)power_representation(n, 2, 3, zeros=True) 输出的解决方案之一。

参考文献

[1]

将一个数表示为三个平方数的和,[在线],可用链接: https://schorn.ch/lagrange.html

示例

>>> from sympy.solvers.diophantine.diophantine import sum_of_three_squares
>>> sum_of_three_squares(44542)
(18, 37, 207)
sympy.solvers.diophantine.diophantine.sum_of_four_squares(n)[源代码][源代码]

返回一个4元组 \((a, b, c, d)\),使得 \(a^2 + b^2 + c^2 + d^2 = n\)。其中 \(a, b, c, d \geq 0\)

参数:
n整数

非负整数

返回:
(int, int, int, int) : 4 元组非负整数 (a, b, c, d) 满足 a**2 + b**2 + c**2 + d**2 = n4元组非负整数

a,b,c,d 按升序排列。

Raises:
ValueError

如果 n 是一个负整数

参见

power_representation

sum_of_four_squares(n)power_representation(n, 2, 4, zeros=True) 输出的解决方案之一。

参考文献

[1]

将一个数表示为四个平方和,[在线],可用:https://schorn.ch/lagrange.html

示例

>>> from sympy.solvers.diophantine.diophantine import sum_of_four_squares
>>> sum_of_four_squares(3456)
(8, 8, 32, 48)
>>> sum_of_four_squares(1294585930293)
(0, 1234, 2161, 1137796)
sympy.solvers.diophantine.diophantine.sum_of_powers(n, p, k, zeros=False)[源代码]

返回一个生成器,用于查找整数的 k-元组 \((n_{1}, n_{2}, . . . n_{k})\),使得 \(n = n_{1}^p + n_{2}^p + . . . n_{k}^p\)

示例

>>> from sympy.solvers.diophantine.diophantine import power_representation

将 1729 表示为两个立方之和:

>>> f = power_representation(1729, 3, 2)
>>> next(f)
(9, 10)
>>> next(f)
(1, 12)

如果标志 \(zeros\) 为 True,解可能包含带有零的元组;任何此类解将在不带零的解之后生成:

>>> list(power_representation(125, 2, 3, zeros=True))
[(5, 6, 8), (3, 4, 10), (0, 5, 10), (0, 2, 11)]

对于偶数 \(p\),可以使用 \(permute_sign\) 函数来获取所有带符号的值:

>>> from sympy.utilities.iterables import permute_signs
>>> list(permute_signs((1, 12)))
[(1, 12), (-1, 12), (1, -12), (-1, -12)]

所有可能的带符号排列也可以获得:

>>> from sympy.utilities.iterables import signed_permutations
>>> list(signed_permutations((1, 12)))
[(1, 12), (-1, 12), (1, -12), (-1, -12), (12, 1), (-12, 1), (12, -1), (-12, -1)]
sympy.solvers.diophantine.diophantine.sum_of_squares(n, k, zeros=False)[源代码][源代码]

返回一个生成器,该生成器生成非负值的 k-元组,其平方和为 n。如果 zeros 为 False(默认),则解决方案将不包含零。元组中的非负元素按顺序排列。

  • 如果 k == 1 且 n 是平方数,则返回 (n,)。

  • 如果 k == 2,那么 n 只能写成平方和的形式,如果 n 的因数分解中所有形式为 4*k + 3 的素数都有偶数次幂。如果 n 是素数,那么它只能写成两个平方和的形式,如果它是 4*k + 1 的形式。

  • 如果 k == 3,那么 n 可以写成平方和的形式,如果它不具有 4**m*(8*k + 7) 的形式。

  • 所有整数都可以写成四个平方的和。

  • 如果 k > 4,那么 n 可以被划分,并且每个部分可以写成 4 个平方的和;如果 n 不能被 4 整除,那么 n 只能写成平方和,如果可以写成额外的部分的平方和。例如,如果 k = 6,那么 n 被分成两部分,第一部分写成 4 个平方的和,第二部分写成 2 个平方的和——这只有在满足上述 k = 2 的条件时才能做到,因此这将自动拒绝 n 的某些划分。

示例

>>> from sympy.solvers.diophantine.diophantine import sum_of_squares
>>> list(sum_of_squares(25, 2))
[(3, 4)]
>>> list(sum_of_squares(25, 2, True))
[(3, 4), (0, 5)]
>>> list(sum_of_squares(25, 4))
[(1, 2, 2, 4)]
sympy.solvers.diophantine.diophantine.merge_solution(var, var_t, solution)[源代码][源代码]

这用于从子方程的解中构建完整解。

sympy.solvers.diophantine.diophantine.divisible(a, b)[源代码][源代码]

如果 a 能被 b 整除则返回 \(True\),否则返回 \(False\)

sympy.solvers.diophantine.diophantine.PQa(P_0, Q_0, D)[源代码][源代码]

返回解决佩尔方程所需的有用信息。

参考文献

[1]

解决广义Pell方程 x^2 - Dy^2 = N,John P. Robertson,2004年7月31日,第4 - 8页。https://web.archive.org/web/20160323033128/http://www.jpr2718.org/pell.pdf

示例

>>> from sympy.solvers.diophantine.diophantine import PQa
>>> pqa = PQa(13, 4, 5) # (13 + sqrt(5))/4
>>> next(pqa) # (P_0, Q_0, a_0, A_0, B_0, G_0)
(13, 4, 3, 3, 1, -1)
>>> next(pqa) # (P_1, Q_1, a_1, A_1, B_1, G_1)
(-1, 1, 1, 4, 1, 3)
sympy.solvers.diophantine.diophantine.equivalent(u, v, r, s, D, N)[源代码][源代码]

如果两个解 \((u, v)\)\((r, s)\) 属于 \(x^2 - Dy^2 = N\) 的同一等价类,则返回 True,否则返回 False。

参考文献

[1]

解决广义Pell方程 x**2 - D*y**2 = N,John P. Robertson,2004年7月31日,第12页。https://web.archive.org/web/20160323033128/http://www.jpr2718.org/pell.pdf

示例

>>> from sympy.solvers.diophantine.diophantine import equivalent
>>> equivalent(18, 5, -18, -5, 13, -1)
True
>>> equivalent(3, 1, -18, 393, 109, -4)
False
sympy.solvers.diophantine.diophantine.parametrize_ternary_quadratic(eq)[源代码][源代码]

返回三元二次方程 eq 的参数化通解,其形式为 \(ax^2 + by^2 + cz^2 + fxy + gyz + hxz = 0\)

注释

考虑在前面的2参数解决方案中的 pq ,并观察到给定的一对参数可以表示多个解决方案。如果 \(p\)q 不是互质的,这是显而易见的,因为公因子也将是解值的公因子。但即使 pq 是互质的,这也可能是真的:

>>> sol = Tuple(*_)
>>> p, q = ordered(sol.free_symbols)
>>> sol.subs([(p, 3), (q, 2)])
(6, 12, 12)
>>> sol.subs([(q, 1), (p, 1)])
(-1, 2, 2)
>>> sol.subs([(q, 0), (p, 1)])
(2, -4, 4)
>>> sol.subs([(q, 1), (p, 0)])
(-3, -6, 6)

除了符号和一个公因子外,这些等价于 (1, 2, 2) 的解。

参考文献

[1]

Diophantine方程的算法解法,Nigel P. Smart,伦敦数学学会学生教材41,剑桥大学出版社,剑桥,1998年。

示例

>>> from sympy import Tuple, ordered
>>> from sympy.abc import x, y, z
>>> from sympy.solvers.diophantine.diophantine import parametrize_ternary_quadratic

参数化解决方案可能返回三个参数:

>>> parametrize_ternary_quadratic(2*x**2 + y**2 - 2*z**2)
(p**2 - 2*q**2, -2*p**2 + 4*p*q - 4*p*r - 4*q**2, p**2 - 4*p*q + 2*q**2 - 4*q*r)

也可能只有两个参数:

>>> parametrize_ternary_quadratic(4*x**2 + 2*y**2 - 3*z**2)
(2*p**2 - 3*q**2, -4*p**2 + 12*p*q - 6*q**2, 4*p**2 - 8*p*q + 6*q**2)
sympy.solvers.diophantine.diophantine.diop_ternary_quadratic_normal(
eq,
parameterize=False,
)[源代码][源代码]

求解二次三元丢番图方程,\(ax^2 + by^2 + cz^2 = 0\)

示例

>>> from sympy.abc import x, y, z
>>> from sympy.solvers.diophantine.diophantine import diop_ternary_quadratic_normal
>>> diop_ternary_quadratic_normal(x**2 + 3*y**2 - z**2)
(1, 0, 1)
>>> diop_ternary_quadratic_normal(4*x**2 + 5*y**2 - z**2)
(1, 0, 2)
>>> diop_ternary_quadratic_normal(34*x**2 - 3*y**2 - 301*z**2)
(4, 9, 1)
sympy.solvers.diophantine.diophantine.ldescent(A, B)[源代码][源代码]

使用拉格朗日方法返回 \(w^2 = Ax^2 + By^2\) 的一个非平凡解;如果没有这样的解,则返回 None。

参数:
A整数
B整数

非零整数

返回:
(int, int, int) | None : 一个元组 \((w_0, x_0, y_0)\),它是上述方程的解。一个元组

参考文献

[1]

Diophantine方程的算法解法,Nigel P. Smart,伦敦数学学会学生教材41,剑桥大学出版社,剑桥,1998年。

[2]

Cremona, J. E., Rusin, D. (2003). 有理二次曲线的有效解法。计算数学,72(243),1417-1441。https://doi.org/10.1090/S0025-5718-02-01480-1

示例

>>> from sympy.solvers.diophantine.diophantine import ldescent
>>> ldescent(1, 1) # w^2 = x^2 + y^2
(1, 1, 0)
>>> ldescent(4, -7) # w^2 = 4x^2 - 7y^2
(2, -1, 0)

这意味着 \(x = -1, y = 0\)\(w = 2\) 是方程 \(w^2 = 4x^2 - 7y^2\) 的一个解。

>>> ldescent(5, -1) # w^2 = 5x^2 - y^2
(2, 1, -1)
sympy.solvers.diophantine.diophantine.gaussian_reduce(
w: int,
a: int,
b: int,
) tuple[int, int][源代码][源代码]

返回同余式 \(X^2 - aZ^2 \equiv 0 \pmod{b}\) 的一个简化解 \((x, z)\),使得 \(x^2 + |a|z^2\) 尽可能小。这里 w 是同余式 \(x^2 \equiv a \pmod{b}\) 的一个解。

此函数仅用于 descent()

参数:
w整数

w 使得 \(w^2 \equiv a \pmod{b}\)

a整数

无平方因子的非零整数

b整数

无平方因子的非零整数

参考文献

[2]

Cremona, J. E., Rusin, D. (2003). 有理二次曲线的有效解法。计算数学,72(243),1417-1441。https://doi.org/10.1090/S0025-5718-02-01480-1

示例

>>> from sympy.solvers.diophantine.diophantine import gaussian_reduce
>>> from sympy.ntheory.residue_ntheory import sqrt_mod
>>> a, b = 19, 101
>>> gaussian_reduce(sqrt_mod(a, b), a, b) # 1**2 - 19*(-4)**2 = -303
(1, -4)
>>> a, b = 11, 14
>>> x, z = gaussian_reduce(sqrt_mod(a, b), a, b)
>>> (x**2 - a*z**2) % b == 0
True

它并不总是返回最小的解决方案。

>>> a, b = 6, 95
>>> min_x, min_z = 1, 4
>>> x, z = gaussian_reduce(sqrt_mod(a, b), a, b)
>>> (x**2 - a*z**2) % b == 0 and (min_x**2 - a*min_z**2) % b == 0
True
>>> min_x**2 + abs(a)*min_z**2 < x**2 + abs(a)*z**2
True
sympy.solvers.diophantine.diophantine.holzer(x, y, z, a, b, c)[源代码][源代码]

简化方程 \(ax^2 + by^2 = cz^2\) 的解 \((x, y, z)\),其中 \(a, b, c > 0\)\(z^2 \geq \mid ab \mid\),得到一个新的简化解 \((x', y', z')\),使得 \(z'^2 \leq \mid ab \mid\)

该算法是对Mordell的简化方法的解释,如Cremona和Rusin的论文[R46b3645dda18-1]_第8页所述,以及参考文献[R46b3645dda18-2]_中Mordell的工作。

参考文献

[1]

Cremona, J. E., Rusin, D. (2003). 有理二次曲线的有效解法。计算数学,72(243),1417-1441。https://doi.org/10.1090/S0025-5718-02-01480-1

[2]

丢番图方程,L. J. Mordell,第48页。

sympy.solvers.diophantine.diophantine.prime_as_sum_of_two_squares(p)[源代码][源代码]

将一个质数 \(p\) 表示为两个平方的唯一和;这只有在质数同余于 1 mod 4 时才能完成。

参数:
p整数

一个模 4 余 1 的素数

返回:
(int, int) | None : 一对正整数 (x, y) 满足 x**2 + y**2 = p一对正整数

如果 p 不与 1 模 4 同余,则为 None。

Raises:
ValueError

如果 p 不是质数

示例

>>> from sympy.solvers.diophantine.diophantine import prime_as_sum_of_two_squares
>>> prime_as_sum_of_two_squares(7)  # can't be done
>>> prime_as_sum_of_two_squares(5)
(1, 2)
sympy.solvers.diophantine.diophantine.reconstruct(A, B, z)[源代码][源代码]

从方程的平方自由正规形式 \(a'*x^2 + b'*y^2 + c'*z^2\) 的解的 \(z\) 值中重建等价解 \(ax^2 + by^2 + cz^2\)\(z\) 值,其中 \(a'\), \(b'\)\(c'\) 是平方自由的且 \(gcd(a', b', c') == 1\)

内部类

这些类旨在在 Diophantine 模块中内部使用。

class sympy.solvers.diophantine.diophantine.DiophantineSolutionSet(symbols_seq, parameters)[源代码][源代码]

特定丢番图方程的一组解的容器。

基本表示形式是一组元组,每个元组表示一个解决方案。

参数:
符号列表

原始方程中的自由符号列表。

参数: 列表

解决方案中使用的参数列表。

方法

__call__(*args)

add(solution)

clear

从该集合中移除所有元素。

copy

返回集合的浅拷贝。

difference

返回两个或更多集合的差集作为一个新集合。

difference_update

从此集合中移除另一个集合的所有元素。

discard

如果元素是集合的成员,则将其移除。

intersection

返回两个集合的交集作为一个新的集合。

intersection_update

更新一个集合,使其包含自身与另一个集合的交集。

isdisjoint

如果两个集合的交集为空,则返回 True。

issubset

报告另一个集合是否包含此集合。

issuperset

报告此集合是否包含另一个集合。

pop

移除并返回一个任意集合元素。

remove

从集合中移除一个元素;它必须是成员。

symmetric_difference

返回两个集合的对称差作为一个新集合。

symmetric_difference_update

用自身与另一个集合的对称差更新集合。

union

返回集合的并集作为一个新集合。

update(*solutions)

dict_iterator

subs

示例

添加解决方案:

>>> from sympy.solvers.diophantine.diophantine import DiophantineSolutionSet
>>> from sympy.abc import x, y, t, u
>>> s1 = DiophantineSolutionSet([x, y], [t, u])
>>> s1
set()
>>> s1.add((2, 3))
>>> s1.add((-1, u))
>>> s1
{(-1, u), (2, 3)}
>>> s2 = DiophantineSolutionSet([x, y], [t, u])
>>> s2.add((3, 4))
>>> s1.update(*s2)
>>> s1
{(-1, u), (2, 3), (3, 4)}

将解决方案转换为字典:

>>> list(s1.dict_iterator())
[{x: -1, y: u}, {x: 2, y: 3}, {x: 3, y: 4}]

替换值:

>>> s3 = DiophantineSolutionSet([x, y], [t, u])
>>> s3.add((t**2, t + u))
>>> s3
{(t**2, t + u)}
>>> s3.subs({t: 2, u: 3})
{(4, 5)}
>>> s3.subs(t, -1)
{(1, u - 1)}
>>> s3.subs(t, 3)
{(9, u + 3)}

在特定值处的评估。位置参数按照与参数相同的顺序给出:

>>> s3(-2, 3)
{(4, 1)}
>>> s3(5)
{(25, u + 5)}
>>> s3(None, 2)
{(t**2, t + 2)}
class sympy.solvers.diophantine.diophantine.DiophantineEquationType(
equation,
free_symbols=None,
)[源代码][源代码]

特定丢番图方程类型的内部表示。

参数:
方程

正在求解的丢番图方程。

自由符号列表(可选)

正在求解的符号。

属性:
总学位

方程中所有项的次数的最大值

同质

方程是否包含一个0次项

homogeneous_order

方程中是否包含任何作为求解符号的系数

维度

正在求解的符号数量

方法

matches()

确定给定的方程是否可以匹配到特定的方程类型。

pre_solve

解决

matches()[源代码][源代码]

确定给定的方程是否可以匹配到特定的方程类型。

class sympy.solvers.diophantine.diophantine.Univariate(equation, free_symbols=None)[源代码][源代码]

单变量丢番图方程的表示。

单变量丢番图方程是形如 \(a_{0} + a_{1}x + a_{2}x^2 + .. + a_{n}x^n = 0\) 的方程,其中 \(a_{1}, a_{2}, ..a_{n}\) 是整数常数,\(x\) 是整数变量。

属性:
n_parameters
参数

方法

matches()

pre_solve

解决

示例

>>> from sympy.solvers.diophantine.diophantine import Univariate
>>> from sympy.abc import x
>>> Univariate((x - 2)*(x - 3)**2).solve() # solves equation (x - 2)*(x - 3)**2 == 0
{(2,), (3,)}
class sympy.solvers.diophantine.diophantine.Linear(equation, free_symbols=None)[源代码][源代码]

线性丢番图方程的表示。

线性丢番图方程是形如 \(a_{1}x_{1} + a_{2}x_{2} + .. + a_{n}x_{n} = 0\) 的方程,其中 \(a_{1}, a_{2}, ..a_{n}\) 是整数常数,\(x_{1}, x_{2}, ..x_{n}\) 是整数变量。

属性:
n_parameters
参数

方法

matches()

pre_solve

解决

示例

>>> from sympy.solvers.diophantine.diophantine import Linear
>>> from sympy.abc import x, y, z
>>> l1 = Linear(2*x - 3*y - 5)
>>> l1.matches() # is this equation linear
True
>>> l1.solve() # solves equation 2*x - 3*y - 5 == 0
{(3*t_0 - 5, 2*t_0 - 5)}

这里 x = -3*t_0 - 5 且 y = -2*t_0 - 5

>>> Linear(2*x - 3*y - 4*z -3).solve()
{(t_0, 2*t_0 + 4*t_1 + 3, -t_0 - 3*t_1 - 3)}
class sympy.solvers.diophantine.diophantine.BinaryQuadratic(equation, free_symbols=None)[源代码][源代码]

二元二次丢番图方程的表示。

二元二次丢番图方程是形如 \(Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0\) 的方程,其中 \(A, B, C, D, E, F\) 是整数常数,\(x\)\(y\) 是整数变量。

属性:
n_parameters
参数

方法

matches()

pre_solve

解决

参考文献

[1]

解决 Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0 的方法,[在线],可访问:https://www.alpertron.com.ar/METHODS.HTM

[2]

求解方程 ax^2+ bxy + cy^2 + dx + ey + f= 0, [在线], 可获取: https://web.archive.org/web/20160323033111/http://www.jpr2718.org/ax2p.pdf

示例

>>> from sympy.abc import x, y
>>> from sympy.solvers.diophantine.diophantine import BinaryQuadratic
>>> b1 = BinaryQuadratic(x**3 + y**2 + 1)
>>> b1.matches()
False
>>> b2 = BinaryQuadratic(x**2 + y**2 + 2*x + 2*y + 2)
>>> b2.matches()
True
>>> b2.solve()
{(-1, -1)}
class sympy.solvers.diophantine.diophantine.InhomogeneousTernaryQuadratic(
equation,
free_symbols=None,
)[源代码][源代码]

非齐次三元二次型的表示。

目前没有为这种方程类型实现求解器。

属性:
n_parameters
参数

方法

matches()

pre_solve

解决

class sympy.solvers.diophantine.diophantine.HomogeneousTernaryQuadraticNormal(
equation,
free_symbols=None,
)[源代码][源代码]

齐次三元二次正规丢番图方程的表示。

属性:
n_parameters
参数

方法

matches()

pre_solve

解决

示例

>>> from sympy.abc import x, y, z
>>> from sympy.solvers.diophantine.diophantine import HomogeneousTernaryQuadraticNormal
>>> HomogeneousTernaryQuadraticNormal(4*x**2 - 5*y**2 + z**2).solve()
{(1, 2, 4)}
class sympy.solvers.diophantine.diophantine.HomogeneousTernaryQuadratic(
equation,
free_symbols=None,
)[源代码][源代码]

齐次三元二次丢番图方程的表示。

属性:
n_parameters
参数

方法

matches()

pre_solve

解决

示例

>>> from sympy.abc import x, y, z
>>> from sympy.solvers.diophantine.diophantine import HomogeneousTernaryQuadratic
>>> HomogeneousTernaryQuadratic(x**2 + y**2 - 3*z**2 + x*y).solve()
{(-1, 2, 1)}
>>> HomogeneousTernaryQuadratic(3*x**2 + y**2 - 3*z**2 + 5*x*y + y*z).solve()
{(3, 12, 13)}
class sympy.solvers.diophantine.diophantine.InhomogeneousGeneralQuadratic(
equation,
free_symbols=None,
)[源代码][源代码]

非均匀一般二次型的表示。

目前没有为这种方程类型实现求解器。

属性:
n_parameters
参数

方法

matches()

pre_solve

解决

class sympy.solvers.diophantine.diophantine.HomogeneousGeneralQuadratic(
equation,
free_symbols=None,
)[源代码][源代码]

同质一般二次型的表示。

目前没有为这种方程类型实现求解器。

属性:
n_parameters
参数

方法

matches()

pre_solve

解决

class sympy.solvers.diophantine.diophantine.GeneralSumOfSquares(equation, free_symbols=None)[源代码][源代码]

丢番图方程的表示

\(x_{1}^2 + x_{2}^2 + . . . + x_{n}^2 - k = 0\).

属性:
n_parameters
参数

方法

matches()

pre_solve

解决

参考文献

[1]

将一个整数表示为三个平方和,[在线],可用:https://www.proofwiki.org/wiki/Integer_as_Sum_of_Three_Squares

示例

>>> from sympy.solvers.diophantine.diophantine import GeneralSumOfSquares
>>> from sympy.abc import a, b, c, d, e
>>> GeneralSumOfSquares(a**2 + b**2 + c**2 + d**2 + e**2 - 2345).solve()
{(15, 22, 22, 24, 24)}

默认情况下只返回1个解决方案。使用 \(limit\) 关键字获取更多:

>>> sorted(GeneralSumOfSquares(a**2 + b**2 + c**2 + d**2 + e**2 - 2345).solve(limit=3))
[(15, 22, 22, 24, 24), (16, 19, 24, 24, 24), (16, 20, 22, 23, 26)]
class sympy.solvers.diophantine.diophantine.GeneralPythagorean(equation, free_symbols=None)[源代码][源代码]

一般勾股方程的表示形式,\(a_{1}^2x_{1}^2 + a_{2}^2x_{2}^2 + . . . + a_{n}^2x_{n}^2 - a_{n + 1}^2x_{n + 1}^2 = 0\)

属性:
n_parameters
参数

方法

matches()

pre_solve

解决

示例

>>> from sympy.solvers.diophantine.diophantine import GeneralPythagorean
>>> from sympy.abc import a, b, c, d, e, x, y, z, t
>>> GeneralPythagorean(a**2 + b**2 + c**2 - d**2).solve()
{(t_0**2 + t_1**2 - t_2**2, 2*t_0*t_2, 2*t_1*t_2, t_0**2 + t_1**2 + t_2**2)}
>>> GeneralPythagorean(9*a**2 - 4*b**2 + 16*c**2 + 25*d**2 + e**2).solve(parameters=[x, y, z, t])
{(-10*t**2 + 10*x**2 + 10*y**2 + 10*z**2, 15*t**2 + 15*x**2 + 15*y**2 + 15*z**2, 15*t*x, 12*t*y, 60*t*z)}
class sympy.solvers.diophantine.diophantine.CubicThue(equation, free_symbols=None)[源代码][源代码]

立方 Thue 丢番图方程的表示。

一个三次Thue丢番图方程是一个形如 \(f(x, y) = r\) 的三次多项式,其中 \(x\)\(y\) 是整数,\(r\) 是有理数。

目前没有为这种方程类型实现求解器。

属性:
n_parameters
参数

方法

matches()

pre_solve

解决

示例

>>> from sympy.abc import x, y
>>> from sympy.solvers.diophantine.diophantine import CubicThue
>>> c1 = CubicThue(x**3 + y**2 + 1)
>>> c1.matches()
True
class sympy.solvers.diophantine.diophantine.GeneralSumOfEvenPowers(
equation,
free_symbols=None,
)[源代码][源代码]

丢番图方程的表示

\(x_{1}^e + x_{2}^e + . . . + x_{n}^e - k = 0\)

其中 \(e\) 是一个偶数、整数次幂。

属性:
n_parameters
参数

方法

matches()

pre_solve

解决

示例

>>> from sympy.solvers.diophantine.diophantine import GeneralSumOfEvenPowers
>>> from sympy.abc import a, b
>>> GeneralSumOfEvenPowers(a**4 + b**4 - (2**4 + 3**4)).solve()
{(2, 3)}