解集#
这是 solveset
求解器中的模块。它包含了有关我们新的求解方程模块的常见问题。
备注
For a beginner-friendly guide focused on solving common types of equations, refer to Solve Equations.
solve()有什么问题:#
SymPy already has a pretty powerful solve
function. But it has some
deficiencies. For example:
对于各种类型的解决方案,它没有一致的输出—它需要一致地返回许多类型的解决方案:
单一解决方案: \(x = 1\)
多种解决方案: \(x^2 = 1\)
无解决方案: \(x^2 + 1 = 0 ; x \in \mathbb{{R}}\)
溶液间隔: \(\lfloor x \rfloor = 0\)
Infinitely many solutions: \(\sin(x) = 0\)
具有点解的多元函数: \(x^2 + y^2 = 0\)
具有非点解的多元函数: \(x^2 + y^2 = 1\)
方程组: \(x + y = 1\) 和 \(x - y = 0\)
关系型: \(x > 0\)
最重要的案子:“我们不知道”
The input API has a lot of parameters and it can be difficult to use.
有些情况下,比如用临界点求函数的最大值和最小值,在这种情况下,重要的是要知道它是否返回了所有的解。
solve
不能保证这一点。
为什么选择Solveset?#
solveset
has an alternative consistent input and output interface:solveset
returns a set object and a set object takes care of all types of output. For cases where it does not "know" all the solutions aConditionSet
with a partial solution is returned. For input it only takes the equation, the variables to solve for and the optional argumentdomain
over which the equation is to be solved.solveset
可以返回无穷多个解。例如求解 \(\sin{{(x)}} = 0\) 收益率 \(\{{2 n \pi | n \in \mathbb{{Z}}\}} \cup \{{2 n \pi + \pi | n \in \mathbb{{Z}}\}}\) 而solve
只返回 \([0, \pi]\) .在复域和实域中的方程求解器之间有一个明确的代码级和接口级分离。例如求解 \(e^x = 1\) 什么时候? \(x\) 是要在复杂域中求解的,返回所有解的集合,即 \(\{{2 n i \pi | n \in \mathbb{{Z}}\}}\) ,如果 \(x\) 只有在实域中才能解决 \(\{{0\}}\) 返回。
为什么我们使用集合作为输出类型?#
SymPy has a well developed sets module, which can represent most of the set containers in mathematics such as:
表示一组有限的离散数。
将实间隔表示为一个集合。
表示集合的笛卡尔积。
表示数学函数下集合的图像
>>> from sympy import ImageSet, S, Lambda >>> from sympy.abc import x >>> squares = ImageSet(Lambda(x, x**2), S.Naturals) # {x**2 for x in N} >>> 4 in squares True表示Argand平面中某个区域中所有复数的集合。
表示满足给定条件的元素集。
还可以设置预定义的类:
它能够进行数学中的大多数集合运算:
Union
Intersection
Complement
SymmetricDifference
使用集合作为解算器的输出的主要原因是它可以一致地表示许多类型的解决方案。对于单变量情况,它可以表示:
无解(空集)。
有限多解
FiniteSet
)无穷多解,可数和不可数无限解(使用
ImageSet
模块)。
Interval
对于像有理数集这样的方程,也可能有奇怪的解。
没有其他Python对象(list、dictionary、generator、Python集)提供我们的sets模块试图模拟的数学集的灵活性。使用集合的第二个原因是,它们与数学家所处理的实体很接近,而且对它们进行推理更容易。Set对象尽可能符合python约定,即。, x in A
和 for i in A
两种方法都可以计算出来。使用更接近数学实体的对象的另一个优点是,用户不必“学习”我们的表示,她可以从她的数学经验中转移她的期望。
对于多变量情况,我们将解表示为n维空间中的一组点,一个点由 FiniteSet
有序元组,这是 \(\mathbb{{R}}^n\) 或 \(\mathbb{{C}}^n\) .
请注意,将军 FiniteSet
是无序的,但是 FiniteSet
由于元组是有序的,所以它的唯一参数变为有序。因此,在返回解决方案时,元组中的顺序映射到预定义的变量顺序。
例如:
>>> from sympy import FiniteSet
>>> FiniteSet(1, 2, 3) # Unordered
{1, 2, 3}
>>> FiniteSet((1, 2, 3)) # Ordered
{(1, 2, 3)}
为什么不使用dicts作为输出?
字典很容易编程处理,但在数学上它们不是很精确,使用它们会很快导致不一致和许多混乱。例如:
在很多情况下,我们不知道完整解,我们可能会输出一个偏解,考虑一下方程 \(fg = 0\) . 该方程的解是以下两个方程解的并: \(f = 0\) , \(g = 0\) . 假设我们能够解决 \(f = 0\) 但是解决 \(g = 0\) 尚不支持。在这种情况下,我们不能表示给定方程的部分解 \(fg = 0\) 使用dicts。使用
ConditionSet
对象:\(sol_f \cup \{{x | x ∊ \mathbb{{R}} ∧ g = 0\}}\) 在哪里 \(sol_f\) 是方程的解 \(f = 0\) .
使用dict可能会导致令人惊讶的结果,比如:
solve(Eq(x**2, 1), x) != solve(Eq(y**2, 1), y)
从数学上讲,这没有道理。使用
FiniteSet
这里解决了问题。它也不能代表方程的解 \(|x| < 1\) ,它是Argand平面中半径为1的磁盘。这个问题通过使用实现为
ComplexRegion
.
的输入API solveset
#
solveset
has simpler input API, unlike solve
. It takes a maximum of
three arguments:
solveset(equation, variable=None, domain=S.Complexes)
- Equation
The equation to solve.
- Variable
The variable for which the equation is to be solved.
- 域
求解方程的区域。
solveset
removes the flags
argument of solve
, which had made the
input API more complicated and output API inconsistent.
这个域的争论是关于什么的?#
Solveset被设计为独立于要求解的变量的假设,而是使用 domain
参数来决定要将方程分派到的解算器,即 solveset_real
或 solveset_complex
. 跟以前的不一样 solve
考虑了变量的假设。
>>> from sympy import solveset, S
>>> from sympy.abc import x
>>> solveset(x**2 + 1, x) # domain=S.Complexes is default
{-I, I}
>>> solveset(x**2 + 1, x, domain=S.Reals)
EmptySet
解集求解方程的一般方法是什么?#
Solveset使用各种方法求解方程,下面是方法的简要概述:
这个
domain
参数首先被认为是知道用户感兴趣的域来获得解决方案。如果给定函数是关系函数 (
>=
,<=
,>
,<
),那么这个域是真实的solve_univariate_inequality
并返回解决方案。解不等式的复杂解,比如 \(x^2 < 0\) 尚不支持。基于
domain
,将方程分派到两个函数中的一个solveset_real
或solveset_complex
,分别在复域或实域求解给定方程。如果给定表达式是两个或多个函数的乘积,例如 \(gh = 0\) ,则给定方程的解是方程解的并 \(g = 0\) 和 \(h = 0\) ,当且仅当两者 \(g\) 和 \(h\) 对于有限输入是有限的。所以,这个解是递归建立的。
如果函数是三角函数或双曲函数,则函数
_solve_real_trig
,它通过将其转换为复指数形式来求解它。现在检查函数是否存在
Piecewise
表达式,如果是,则将其转换为显式表达式和集对,然后递归求解。相应的解算器现在尝试使用例程来反转方程
invert_real
和invert_complex
. 这些例程是基于数学逆的概念(虽然不完全是)。它简化了实值/复值方程 \(f(x) = y\) 对于一组方程式: \(\{{g(x) = h_1(y), g(x) = h_2(y), ..., g(x) = h_n(y) \}}\) 在哪里? \(g(x)\) 是一个比 \(f(x)\) . 在这方面还需要做一些工作来找到更复杂表达式的倒数。反演后,对方程组进行根或Abs(模量)的检查,然后采用该方法
_solve_radical
尝试简化字根,通过删除它使用技术,如平方,立方等,和_solve_abs
通过考虑正变量和负变量,迭代求解嵌套模。如果上述方法均不成功,则多项式方法如下:
有理函数的求解方法,
_solve_as_rational
,称为。基于域,相应的多边形解算器_solve_as_poly_real
或_solve_as_poly_complex
被调用来解决f
作为多项式。基本方法
_solve_as_poly
如果已经是一个多项式方程,或者,随着变量的变化,可以用多项式技术来求解方程。由最终解决方案返回
solveset
是上面找到的解决方案集与输入域的交集。
我们如何操作并返回无限解?#
在我们的领域,我们使用真实的
ImageSet
类返回无限解。ImageSet
是一个数学函数下的集合的图像。例如,表示方程的解 \(\sin{{(x)}} = 0\) ,我们可以使用ImageSet
AS:>>> from sympy import ImageSet, Lambda, pi, S, Dummy, pprint >>> n = Dummy('n') >>> pprint(ImageSet(Lambda(n, 2*pi*n), S.Integers), use_unicode=True) {2⋅n⋅π │ n ∊ ℤ}哪里
n
是一个虚拟变量。它基本上是函数下的整数集的图像 \(2\pi n\) 。在复杂域中,我们使用复杂集,它被实现为
ComplexRegion
在集合模块中类,表示Argand平面中的无限解。例如表示方程的解 \(|z| = 1\) ,这是一个单位圆,我们可以使用ComplexRegion
AS:>>> from sympy import ComplexRegion, FiniteSet, Interval, pi, pprint >>> pprint(ComplexRegion(FiniteSet(1)*Interval(0, 2*pi), polar=True), use_unicode=True) {r⋅(ⅈ⋅sin(θ) + cos(θ)) │ r, θ ∊ {1} × [0, 2⋅π)}何处
FiniteSet
在ProductSet
值的范围 \(r\) ,它是圆的半径和Interval
是指 \(\theta\) ,从 \(x\) 表示Argand平面中单位圆的轴。对于非极坐标形式,我们也有表示非极坐标形式的注记法。例如,为了表示Argand平面中的前两个象限,我们可以编写
ComplexRegion
AS:>>> from sympy import ComplexRegion, Interval, pi, oo, pprint >>> pprint(ComplexRegion(Interval(-oo, oo)*Interval(0, oo)), use_unicode=True) {x + y⋅ⅈ │ x, y ∊ (-∞, ∞) × [0, ∞)}其中间隔是 \(x\) 和 \(y\) 对于复数集合 \(x + iy\) .
怎么会呢 solveset
确保不会返回任何错误的解决方案?#
计算机代数系统中的解算器是基于启发式算法的,所以通常很难保证100%的正确性,在所有可能的情况下。但是,仍然有很多情况下我们可以确保正确性。Solveset会尽可能地验证正确性。例如:
考虑一下这个等式 \(|x| = n\) . 一个简单的方法来解决这个方程会返回
{{-n, n}}
作为它的解决方案,这是不正确的{{-n, n}}
当且仅当n
是肯定的。Solveset也返回此信息以确保正确性。>>> from sympy import symbols, S, pprint, solveset >>> x, n = symbols('x, n') >>> pprint(solveset(abs(x) - n, x, domain=S.Reals), use_unicode=True) {x │ x ∊ {-n, n} ∧ (n ∈ [0, ∞))}但是,在这方面还有很多工作要做。
基于搜索的解算器和分步求解#
注:此项正在开发中。
引进后
ConditionSet
方程组的求解可以看作是集合变换。这是我们可以用来解方程的抽象视图。
对给定集合应用各种集合变换。
定义解决方案可用性的度量标准,或者定义某些解决方案优于其他解决方案的概念。
不同的转换将是树的节点。
适当的搜索技术可以得到最佳解。
ConditionSet
使我们能够以如下形式表示未赋值的方程和不等式 \(\{{x|f(x)=0; x \in S\}}\) 和 \(\{{x|f(x)>0; x \in S\}}\) 但更强大的是ConditionSet
它允许我们把中间步骤写成集到集的转换。一些转换包括:
成分: \(\{{x|f(g(x))=0;x \in S\}} \Rightarrow \{{x|g(x)=y; x \in S, y \in \{{z|f(z)=0; z \in S\}}\}}\)
- 多项式解算器: \(\{{x | P(x) = 0;x \in S\}} \Rightarrow \{{x_1,x_2, ... ,x_n\}} \cap S\) ,
在哪里? \(x_i\) 是 \(P(x)\) .
反转解算器: \(\{{x|f(x)=0;x \in S\}} \Rightarrow \{{g(0)| \text{{ all g such that }} f(g(x)) = x\}}\)
- 对数组合: \(\{{x| \log(f(x)) + \log(g(x));x \in S\}}\)
\(\Rightarrow \{x| \log(f(x).g(x)); x \in S\} \text{ if } f(x) > 0 \text{ and } g(x) > 0\) \(\Rightarrow \{x| \log(f(x)) + \log(g(x));x \in S\} \text{ otherwise}\)
- 产品解决方案: \(\{{x|f(x)g(x)=0; x \in S\}}\)
\(\Rightarrow \{x|f(x)=0; x \in S\} U \{x|g(x)=0; x \in S\}\) \(\text{ given } f(x) \text{ and } g(x) \text{ are bounded.}\) \(\Rightarrow \{x|f(x)g(x)=0; x \in S\}, \text{ otherwise}\)
由于输出类型与输入类型相同,因此这些转换的任何组合也是有效的转换。我们的目标是找到正确的组合序列(给定原子),将给定的条件集转换为一个不是条件集的集合,即有限集、区间、整数集及其并集、交集、补集或映象集。我们可以给每个集合指定一个成本函数,这样,对我们来说,集合的形式越理想,成本函数的值就越小。这样,我们的问题就简化为在图上寻找从初始条件集到最小值集的路径,其中原子变换形成了边。
我们如何处理只有部分解决方案已知的情况?#
创建一个通用方程解算器,它可以解出我们在数学中遇到的每一个方程,这是计算机代数系统中解算器的理想情况。当未解决或只能不完全解决的情况下
ConditionSet
用作未赋值的解算集对象。注意,从数学上讲,找到一个方程的完整解集是不可判定的。看到了吗 Richardson's theorem .
ConditionSet
基本上是满足给定条件的一组元素。例如,要在实域中表示方程的解:\[(x^2-4)(\sin(x)+x)\]我们可以将其表示为:
\(\{-2, 2\} ∪ \{x | x \in \mathbb{R} ∧ x + \sin(x) = 0\}\)
What is the plan for solve and solveset?#
There are still a few things solveset
can't do, which solve
can, such
as solving nonlinear multivariate & LambertW type equations. Hence, it's not
yet a perfect replacement for solve
. As the algorithms in solveset
mature, solveset
may be able to be used within solve
to replace some of
its algorithms.
在solveset中如何处理符号参数?#
Solveset还处于发展的初始阶段,所以对于所有的情况,符号参数的处理都不是很好,但是在这方面已经做了一些工作来描述我们对符号参数的思想。例如,考虑 \(|x| = n\) 真的吗 \(x\) 在哪里 \(n\) 是符号参数。Solveset返回 \(x\) 考虑符号参数的域 \(n\) 也:
\[([0, \infty) \cap \{n\}) \cup ((-\infty, 0] \cap \{-n\}).\]这只是意味着 \(n\) 只有当解决方案属于
Interval
\([0, \infty)\) 和 \(-n\) 只有当 \(-n\) 属于Interval
\((- \infty, 0]\) .还有其他的案例需要解决,比如解决 \(2^x + (a - 2)\) 对于 \(x\) 在哪里? \(a\) 是符号参数。到现在为止,它返回的解是 \(\mathbb{{R}}\) ,这是微不足道的,因为它没有揭示 \(a\) 在解决方案中。
最近,我们还实现了一个函数来查找表达式在一个非空的有限集(与区间的交集)中的域。它是处理符号参数的有用补充。例如:
>>> from sympy import Symbol, FiniteSet, Interval, not_empty_in, sqrt, oo >>> from sympy.abc import x >>> not_empty_in(FiniteSet(x/2).intersect(Interval(0, 1)), x) Interval(0, 2) >>> not_empty_in(FiniteSet(x, x**2).intersect(Interval(1, 2)), x) Union(Interval(1, 2), Interval(-sqrt(2), -1))
工具书类#
解算集模块引用#
使用 solveset()
解一个变量的方程或表达式(假定等于0)。解一个方程 \(x^2 == 1\) 具体操作如下:
>>> from sympy import solveset
>>> from sympy import Symbol, Eq
>>> x = Symbol('x')
>>> solveset(Eq(x**2, 1), x)
{-1, 1}
或者,可以手动将方程重写为等于0的表达式:
>>> solveset(x**2 - 1, x)
{-1, 1}
第一个论点 solveset()
是一个表达式(等于零)或一个方程,第二个参数是我们要解方程的符号。
- sympy.solvers.solveset.solveset(f, symbol=None, domain=Complexes)[源代码]#
以集合为输出解给定的不等式或方程
- 参数:
f :Expr或关系型。
目标方程或不等式
符号 :符号
求解方程的变量
域 :设置
方程求解的区域
- 返回:
集合
A set of values for \(symbol\) for which \(f\) is True or is equal to zero. An
EmptySet
is returned if \(f\) is False or nonzero. AConditionSet
is returned as unsolved object if algorithms to evaluate complete solution are not yet implemented.solveset
claims to be complete in the solution set that it returns.- 加薪:
NotImplementedError
求解复域不等式的算法尚未实现。
ValueError
输入无效。
RuntimeError
这是一个bug,请向github问题跟踪者报告。
笔记
Python interprets 0 and 1 as False and True, respectively, but in this function they refer to solutions of an expression. So 0 and 1 return the domain and EmptySet, respectively, while True and False return the opposite (as they are assumed to be solutions of relational expressions).
实例
>>> from sympy import exp, sin, Symbol, pprint, S, Eq >>> from sympy.solvers.solveset import solveset, solveset_real
默认域很复杂。不指定域将导致在复杂域中求解方程(这不受符号假设的影响):
>>> x = Symbol('x') >>> pprint(solveset(exp(x) - 1, x), use_unicode=False) {2*n*I*pi | n in Integers}
>>> x = Symbol('x', real=True) >>> pprint(solveset(exp(x) - 1, x), use_unicode=False) {2*n*I*pi | n in Integers}
If you want to use
solveset
to solve the equation in the real domain, provide a real domain. (Usingsolveset_real
does this automatically.)
>>> R = S.Reals >>> x = Symbol('x') >>> solveset(exp(x) - 1, x, R) {0} >>> solveset_real(exp(x) - 1, x) {0}
解决方案不受符号假设的影响:
>>> p = Symbol('p', positive=True) >>> pprint(solveset(p**2 - 4)) {-2, 2}
When a
ConditionSet
is returned, symbols with assumptions that would alter the set are replaced with more generic symbols:>>> i = Symbol('i', imaginary=True) >>> solveset(Eq(i**2 + i*sin(i), 1), i, domain=S.Reals) ConditionSet(_R, Eq(_R**2 + _R*sin(_R) - 1, 0), Reals)
不等式只能在实域上求解。使用复杂域会导致NotImplementedError。
>>> solveset(exp(x) > 1, x, R) Interval.open(0, oo)
参见
solveset_real
实域求解器
solveset_complex
复杂域求解器
- sympy.solvers.solveset.invert_real(f_x, y, x)[源代码]#
Inverts a real-valued function. Same as
invert_complex()
, but sets the domain toS.Reals
before inverting.
- sympy.solvers.solveset.invert_complex(f_x, y, x, domain=Complexes)[源代码]#
Reduce the complex valued equation \(f(x) = y\) to a set of equations
\[\left\{g(x) = h_1(y),\ g(x) = h_2(y),\ \dots,\ g(x) = h_n(y) \right\}\]where \(g(x)\) is a simpler function than \(f(x)\). The return value is a tuple \((g(x), \mathrm{set}_h)\), where \(g(x)\) is a function of \(x\) and \(\mathrm{set}_h\) is the set of function \(\left\{h_1(y), h_2(y), \dots, h_n(y)\right\}\). Here, \(y\) is not necessarily a symbol.
\(\mathrm{set}_h\) contains the functions, along with the information about the domain in which they are valid, through set operations. For instance, if \(y = |x| - n\) is inverted in the real domain, then \(\mathrm{set}_h\) is not simply \(\{-n, n\}\) as the nature of \(n\) is unknown; rather, it is:
- $$ left(left[0, inftyright) cap left{nright}right) cup
left(left(-infty, 0right] cap left{- nright}right)$$
By default, the complex domain is used which means that inverting even seemingly simple functions like \(\exp(x)\) will give very different results from those obtained in the real domain. (In the case of \(\exp(x)\), the inversion via \(\log\) is multi-valued in the complex domain, having infinitely many branches.)
If you are working with real values only (or you are not sure which function to use) you should probably set the domain to
S.Reals
(or useinvert_real
which does that automatically).实例
>>> from sympy.solvers.solveset import invert_complex, invert_real >>> from sympy.abc import x, y >>> from sympy import exp
什么时候exp(x)==y?
>>> invert_complex(exp(x), y, x) (x, ImageSet(Lambda(_n, I*(2*_n*pi + arg(y)) + log(Abs(y))), Integers)) >>> invert_real(exp(x), y, x) (x, Intersection({log(y)}, Reals))
什么时候exp(x)==1?
>>> invert_complex(exp(x), 1, x) (x, ImageSet(Lambda(_n, 2*_n*I*pi), Integers)) >>> invert_real(exp(x), 1, x) (x, {0})
- sympy.solvers.solveset.domain_check(f, symbol, p)[源代码]#
如果点p是无穷大的,或者f的任何子表达式是无穷大的,或者在用p替换符号后变成无穷大,则返回False。如果这些条件都不满足,则返回True。
实例
>>> from sympy import Mul, oo >>> from sympy.abc import x >>> from sympy.solvers.solveset import domain_check >>> g = 1/(1 + (1/(x + 1))**2) >>> domain_check(g, x, -1) False >>> domain_check(x**2, x, 0) True >>> domain_check(1/x, x, oo) False
该函数依赖于一个假设,即方程的原始形式没有通过自动简化而改变。
>>> domain_check(x/x, x, 0) # x/x is automatically simplified to 1 True
要处理自动评估,请使用evaluate=False:
>>> domain_check(Mul(x, 1/x, evaluate=False), x, 0) False
- sympy.solvers.solveset.solvify(f, symbol, domain)[源代码]#
使用solveset解算方程,并根据 \(solve\) 输出API。
- 返回:
我们根据返回的解决方案类型对输出进行分类 \(solveset\) .
- 加薪:
NotImplementedError
输入条件是一个输入。
解决方案|输出
FiniteSet |列表
ImageSet,|列表(如果 `f` 是周期性的)结合|
Union | list (with FiniteSet)
清空您的空列表
其他|无
实例
>>> from sympy.solvers.solveset import solvify >>> from sympy.abc import x >>> from sympy import S, tan, sin, exp >>> solvify(x**2 - 9, x, S.Reals) [-3, 3] >>> solvify(sin(x) - 1, x, S.Reals) [pi/2] >>> solvify(tan(x), x, S.Reals) [0] >>> solvify(exp(x) - 1, x, S.Complexes)
>>> solvify(exp(x) - 1, x, S.Reals) [0]
- sympy.solvers.solveset.linear_eq_to_matrix(equations, *symbols)[源代码]#
Converts a given System of Equations into Matrix form. Here \(equations\) must be a linear system of equations in \(symbols\). Element
M[i, j]
corresponds to the coefficient of the jth symbol in the ith equation.矩阵形式对应于增广矩阵形式。例如:
\[4x+2y+3z=1\]\[3x+y+z=-6\]\[2x+4y+9z=2\]This system will return \(A\) and \(b\) as:
- $$ A = left[begin{array}{ccc}
4 & 2 & 3 \ 3 & 1 & 1 \ 2 & 4 & 9 end{array}right] b = left[begin{array}{c} 1 \ -6 \ 2 end{array}right] $$
The only simplification performed is to convert
Eq(a, b)
\(\Rightarrow a - b\).- 加薪:
NonlinearError
方程包含一个非线性项。
ValueError
符号未给出或不唯一。
实例
>>> from sympy import linear_eq_to_matrix, symbols >>> c, x, y, z = symbols('c, x, y, z')
符号的系数(数值或符号)将作为矩阵返回:
>>> eqns = [c*x + z - 1 - c, y + z, x - y] >>> A, b = linear_eq_to_matrix(eqns, [x, y, z]) >>> A Matrix([ [c, 0, 1], [0, 1, 1], [1, -1, 0]]) >>> b Matrix([ [c + 1], [ 0], [ 0]])
此例程不会简化表达式,如果遇到非线性,则会引发错误:
>>> eqns = [ ... (x**2 - 3*x)/(x - 3) - 3, ... y**2 - 3*y - y*(y - 4) + x - 4] >>> linear_eq_to_matrix(eqns, [x, y]) Traceback (most recent call last): ... NonlinearError: symbol-dependent term can be ignored using `strict=False`
Simplifying these equations will discard the removable singularity in the first and reveal the linear structure of the second:
>>> [e.simplify() for e in eqns] [x - 3, x + y - 4]
Any such simplification needed to eliminate nonlinear terms must be done before calling this routine.
- sympy.solvers.solveset.linsolve(system, *symbols)[源代码]#
Solve system of \(N\) linear equations with \(M\) variables; both underdetermined and overdetermined systems are supported. The possible number of solutions is zero, one or infinite. Zero solutions throws a ValueError, whereas infinite solutions are represented parametrically in terms of the given symbols. For unique solution a
FiniteSet
of ordered tuples is returned.All standard input formats are supported: For the given set of equations, the respective input types are given below:
\[3x+2y-z=1\]\[2x-2y+4z=-2\]\[2x-y+2z=0\]Augmented matrix form,
system
given below:
- $$ text{system} = left[{array}{cccc}
3 & 2 & -1 & 1\ 2 & -2 & 4 & -2\ 2 & -1 & 2 & 0 end{array}right] $$
system = Matrix([[3, 2, -1, 1], [2, -2, 4, -2], [2, -1, 2, 0]])
List of equations form
system = [3x + 2y - z - 1, 2x - 2y + 4z + 2, 2x - y + 2z]
Input \(A\) and \(b\) in matrix form (from \(Ax = b\)) are given as:
- $$ A = left[begin{array}{ccc}
3 & 2 & -1 \ 2 & -2 & 4 \ 2 & -1 & 2 end{array}right] b = left[begin{array}{c} 1 \ -2 \ 0 end{array}right] $$
A = Matrix([[3, 2, -1], [2, -2, 4], [2, -1, 2]]) b = Matrix([[1], [-2], [0]]) system = (A, b)
符号总是可以传递的,但实际上只有在以下情况下才需要:1)传递方程组;2)系统作为欠定矩阵传递,并且希望控制结果中自由变量的名称。如果没有为案例1使用符号,则会引发错误,但是如果没有为案例2提供符号,则会提供内部生成的符号。当为情况2提供符号时,至少应该有与矩阵A中的列一样多的符号。
这里使用的算法是Gauss-Jordan消去法,它在消去后得到一行阶梯形矩阵。
- 返回:
包含一个有限集的值的有序集
未知数 \(system\) 有解决办法。(包装
FiniteSet中的元组用于保持一致性
整个解集的输出格式。)
如果线性系统不一致,则返回EmptySet。
- 加薪:
ValueError
输入无效。没有给出符号。
实例
>>> from sympy import Matrix, linsolve, symbols >>> x, y, z = symbols("x, y, z") >>> A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 10]]) >>> b = Matrix([3, 6, 9]) >>> A Matrix([ [1, 2, 3], [4, 5, 6], [7, 8, 10]]) >>> b Matrix([ [3], [6], [9]]) >>> linsolve((A, b), [x, y, z]) {(-1, 2, 0)}
参数化解决方案:如果系统未确定,函数将根据给定符号返回参数解。免费的将原封不动地退还。e、 g.在下面的系统中, \(z\) 作为变量z的解返回;它可以采用任何值。
>>> A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) >>> b = Matrix([3, 6, 9]) >>> linsolve((A, b), x, y, z) {(z - 1, 2 - 2*z, z)}
If no symbols are given, internally generated symbols will be used. The
tau0
in the third position indicates (as before) that the third variable -- whatever it is named -- can take on any value:>>> linsolve((A, b)) {(tau0 - 1, 2 - 2*tau0, tau0)}
List of equations as input
>>> Eqns = [3*x + 2*y - z - 1, 2*x - 2*y + 4*z + 2, - x + y/2 - z] >>> linsolve(Eqns, x, y, z) {(1, -2, -2)}
Augmented matrix as input
>>> aug = Matrix([[2, 1, 3, 1], [2, 6, 8, 3], [6, 8, 18, 5]]) >>> aug Matrix([ [2, 1, 3, 1], [2, 6, 8, 3], [6, 8, 18, 5]]) >>> linsolve(aug, x, y, z) {(3/10, 2/5, 0)}
符号系数求解
>>> a, b, c, d, e, f = symbols('a, b, c, d, e, f') >>> eqns = [a*x + b*y - c, d*x + e*y - f] >>> linsolve(eqns, x, y) {((-b*f + c*e)/(a*e - b*d), (a*f - c*d)/(a*e - b*d))}
退化系统以给定符号集的形式返回解。
>>> system = Matrix(([0, 0, 0], [0, 0, 0], [0, 0, 0])) >>> linsolve(system, x, y) {(x, y)}
对于空系统,linsolve返回空集
>>> linsolve([], x) EmptySet
An error is raised if any nonlinearity is detected, even if it could be removed with expansion
>>> linsolve([x*(1/x - 1)], x) Traceback (most recent call last): ... NonlinearError: nonlinear term: 1/x
>>> linsolve([x*(y + 1)], x, y) Traceback (most recent call last): ... NonlinearError: nonlinear cross-term: x*(y + 1)
>>> linsolve([x**2 - 1], x) Traceback (most recent call last): ... NonlinearError: nonlinear term: x**2
- sympy.solvers.solveset.nonlinsolve(system, *symbols)[源代码]#
Solve system of \(N\) nonlinear equations with \(M\) variables, which means both under and overdetermined systems are supported. Positive dimensional system is also supported (A system with infinitely many solutions is said to be positive-dimensional). In a positive dimensional system the solution will be dependent on at least one symbol. Returns both real solution and complex solution (if they exist).
- 参数:
系统 :公式列表
目标方程组
符号 :符号列表
符号应按顺序排列,如列表
- 返回:
A
FiniteSet
of ordered tuple of values of \(symbols\) for which the \(system\)有解决办法。元组中值的顺序与
参数 \(symbols\) .
Please note that general
FiniteSet
is unordered, the solutionreturned here is not simply a
FiniteSet
of solutions, rather itis a
FiniteSet
of ordered tuple, i.e. the first and onlyargument to
FiniteSet
is a tuple of solutions, which isordered, and, hence ,the returned solution is ordered.
还要注意,解决方案也可以作为有序元组返回,
FiniteSet is just a wrapper
{}
around the tuple. It has no other意义除了它只是用来保持一致性
整个解集的输出格式。
For the given set of equations, the respective input types
如下所示:
\[xy - 1 = 0\]\[4x^2 + y^2 - 5 = 0\]system = [x*y - 1, 4*x**2 + y**2 - 5] symbols = [x, y]
- 加薪:
ValueError
输入无效。没有给出符号。
AttributeError
输入符号不是 \(Symbol\) 类型。
实例
>>> from sympy import symbols, nonlinsolve >>> x, y, z = symbols('x, y, z', real=True) >>> nonlinsolve([x*y - 1, 4*x**2 + y**2 - 5], [x, y]) {(-1, -1), (-1/2, -2), (1/2, 2), (1, 1)}
正维度系统及其补充:
>>> from sympy import pprint >>> from sympy.polys.polytools import is_zero_dimensional >>> a, b, c, d = symbols('a, b, c, d', extended_real=True) >>> eq1 = a + b + c + d >>> eq2 = a*b + b*c + c*d + d*a >>> eq3 = a*b*c + b*c*d + c*d*a + d*a*b >>> eq4 = a*b*c*d - 1 >>> system = [eq1, eq2, eq3, eq4] >>> is_zero_dimensional(system) False >>> pprint(nonlinsolve(system, [a, b, c, d]), use_unicode=False) -1 1 1 -1 {(---, -d, -, {d} \ {0}), (-, -d, ---, {d} \ {0})} d d d d >>> nonlinsolve([(x+y)**2 - 4, x + y - 2], [x, y]) {(2 - y, y)}
2. If some of the equations are non-polynomial then \(nonlinsolve\) will call the
substitution
function and return real and complex solutions, if present.>>> from sympy import exp, sin >>> nonlinsolve([exp(x) - sin(y), y**2 - 4], [x, y]) {(ImageSet(Lambda(_n, I*(2*_n*pi + pi) + log(sin(2))), Integers), -2), (ImageSet(Lambda(_n, 2*_n*I*pi + log(sin(2))), Integers), 2)}
3. If system is non-linear polynomial and zero-dimensional then it returns both solution (real and complex solutions, if present) using
solve_poly_system()
:>>> from sympy import sqrt >>> nonlinsolve([x**2 - 2*y**2 -2, x*y - 2], [x, y]) {(-2, -1), (2, 1), (-sqrt(2)*I, sqrt(2)*I), (sqrt(2)*I, -sqrt(2)*I)}
4.
nonlinsolve
can solve some linear (zero or positive dimensional) system (because it uses thesympy.polys.polytools.groebner()
function to get the groebner basis and then uses thesubstitution
function basis as the new \(system\)). But it is not recommended to solve linear system usingnonlinsolve
, becauselinsolve()
is better for general linear systems.>>> nonlinsolve([x + 2*y -z - 3, x - y - 4*z + 9, y + z - 4], [x, y, z]) {(3*z - 5, 4 - z, z)}
5. System having polynomial equations and only real solution is solved using
solve_poly_system()
:>>> e1 = sqrt(x**2 + y**2) - 10 >>> e2 = sqrt(y**2 + (-x + 10)**2) - 3 >>> nonlinsolve((e1, e2), (x, y)) {(191/20, -3*sqrt(391)/20), (191/20, 3*sqrt(391)/20)} >>> nonlinsolve([x**2 + 2/y - 2, x + y - 3], [x, y]) {(1, 2), (1 - sqrt(5), 2 + sqrt(5)), (1 + sqrt(5), 2 - sqrt(5))} >>> nonlinsolve([x**2 + 2/y - 2, x + y - 3], [y, x]) {(2, 1), (2 - sqrt(5), 1 + sqrt(5)), (2 + sqrt(5), 1 - sqrt(5))}
6. It is better to use symbols instead of trigonometric functions or
Function
. For example, replace \(\sin(x)\) with a symbol, replace \(f(x)\) with a symbol and so on. Get a solution fromnonlinsolve
and then usesolveset()
to get the value of \(x\).How Nonlinsolve Is Better Than Old Solver
_solve_system
:1. A positive dimensional system solver: nonlinsolve can return solution for positive dimensional system. It finds the Groebner Basis of the positive dimensional system(calling it as basis) then we can start solving equation(having least number of variable first in the basis) using solveset and substituting that solved solutions into other equation(of basis) to get solution in terms of minimum variables. Here the important thing is how we are substituting the known values and in which equations.
2. Real and complex solutions: nonlinsolve returns both real and complex solution. If all the equations in the system are polynomial then using
solve_poly_system()
both real and complex solution is returned. If all the equations in the system are not polynomial equation then goes tosubstitution
method with this polynomial and non polynomial equation(s), to solve for unsolved variables. Here to solve for particular variable solveset_real and solveset_complex is used. For both real and complex solution_solve_using_known_values
is used insidesubstitution
(substitution
will be called when any non-polynomial equation is present). If a solution is valid its general solution is added to the final result.3.
Complement
andIntersection
will be added: nonlinsolve maintains dict for complements and intersections. If solveset find complements or/and intersections with any interval or set during the execution ofsubstitution
function, then complement or/and intersection for that variable is added before returning final solution.
转溶质#
- sympy.solvers.solveset._transolve(f, symbol, domain)[源代码]#
求解超越方程的函数。它是帮助
solveset
应该在内部使用。_transolve
当前支持以下类型的表达式:指数方程
对数方程
- 参数:
f :任何需要求解的超越方程。
这需要一个表达式,假定它等于
0
.符号 :为其求解方程的变量。
这必须是一流的
Symbol
.域 :求解方程的集合。
这必须是一流的
Set
.- 返回:
集合
的一组值
symbol
为此f
等于零。安EmptySet
如果返回f
在各自领域没有解决方案。AConditionSet
如果尚未实现评估完整解决方案的算法,则返回为未解决的对象。
如何使用
_transolve
_transolve
不应作为独立函数使用,因为它假定方程 (f
)symbol
来自solveset
可能已经做了一些修改。使用_transolve
作为一个独立函数 (f
)symbol
应该像过去一样solveset
.实例
>>> from sympy.solvers.solveset import _transolve as transolve >>> from sympy.solvers.solvers import _tsolve as tsolve >>> from sympy import symbols, S, pprint >>> x = symbols('x', real=True) # assumption added >>> transolve(5**(x - 3) - 3**(2*x + 1), x, S.Reals) {-(log(3) + 3*log(5))/(-log(5) + 2*log(3))}
怎么用?
_transolve
作品_transolve
使用两种类型的辅助函数来求解特定类的方程:识别辅助项:确定给定的方程是否属于某类方程。返回
True
或False
.求解辅助对象:一旦确定了一个方程,相应的辅助对象要么解出该方程,要么返回一个形式的方程
solveset
最好能应付。模块背后的理念
目的
_transolve
就是把生成式中还不是多项式的方程组取出来,通过有效的变换将它们重新构造为多项式,或者直接求解它们。为此,每一类支持的超越函数都使用一对辅助函数。一个确定方程的超越形式,另一个要么解决它,要么把它改写成一个可以通过solveset
. 例如,一个 \(ab^{{f(x)}} - cd^{{g(x)}} = 0\) 可以转换为 \(\log(a) + f(x)\log(b) - \log(c) - g(x)\log(d) = 0\) (在某些假设下)这可以用solveset
如果 \(f(x)\) 和 \(g(x)\) 都是多项式形式。怎么用?
_transolve
比_tsolve
更好的输出
_transolve
以更简化的形式提供表达式。考虑一个简单的指数方程
>>> f = 3**(2*x) - 2**(x + 3) >>> pprint(transolve(f, x, S.Reals), use_unicode=False) -3*log(2) {------------------} -2*log(3) + log(2) >>> pprint(tsolve(f, x), use_unicode=False) / 3 \ | --------| | log(2/9)| [-log\2 /]
可扩展
API
_transolve
被设计为易于扩展,即求解给定方程类的代码封装在助手中,而不是与_transolve
本身。模块化
_transolve
被设计成模块化,即,对于每一类方程,都实现了一个用于识别和求解的单独助手。这使得更改或修改直接在helpers中实现的任何方法都很容易,而不会干扰API的实际结构。更快的计算
通过求解方程
_transolve
比_tsolve
. 在solve
,试图通过计算各种可能性得到解决方案。这一系列的尝试使解决有点慢。在_transolve
,只有在确定了特定类型的方程后才开始计算。如何添加新的方程类
添加一个新的方程求解器类需要三个步骤:
确定方程式的类型
确定它们所属的一类方程的类型:它可以是
Add
,Pow
等类型。每种类型都使用单独的内部函数。编写识别和求解助手,并在给定类型的方程的例程中使用它们(如有必要,在添加之后)。比如:def add_type(lhs, rhs, x): .... if _is_exponential(lhs, x): new_eq = _solve_exponential(lhs, rhs, x) .... rhs, lhs = eq.as_independent(x) if lhs.is_Add: result = add_type(lhs, rhs, x)
定义标识助手。
定义求解辅助对象。
除此之外,在添加方程解算器时还需要注意以下几点:
命名约定:标识助手的名称应为
_is_class
其中class将是方程式类的名称或缩写。求解助手将命名为_solve_class
. 例如:对于指数方程_is_exponential
和_solve_expo
.识别帮助器应采用两个输入参数,即要检查的方程和正在寻求解决方案的变量,而求解助手则需要一个额外的域参数。
一定要考虑角落的情况。
为每个助手添加测试。
将描述所实现方法的docstring添加到助手中。帮助者的文件应确定:
帮手的目的,
用于识别和求解方程的方法,
正确性的证明
helpers的返回值
- sympy.solvers.solveset._is_exponential(f, symbol)[源代码]#
返回
True
如果一个或多个术语包含symbol
只有指数,否则False
.- 参数:
f :表达式
要检查的方程式
符号 :符号
检查方程式的变量
实例
>>> from sympy import symbols, cos, exp >>> from sympy.solvers.solveset import _is_exponential as check >>> x, y = symbols('x y') >>> check(y, y) False >>> check(x**y - 1, y) True >>> check(x**y*2**y - 1, y) True >>> check(exp(x + 3) + 3**x, x) True >>> check(cos(2**x), x) False
帮手背后的哲学
该函数提取方程的每个项并检查它是否为指数形式的w.r.t
symbol
.
- sympy.solvers.solveset._solve_exponential(lhs, rhs, symbol, domain)[源代码]#
求解(支持的)指数方程的辅助函数。
指数方程是(当前)最多两个项的和,其中一个或两个项的幂次与符号相关。
例如
\[5^{2x+3}-5^{3x-1}\]\[4^{5-9x}-e^{2-x}\]- 参数:
左侧、右侧 :表达式
要解的指数方程, \(lhs = rhs\)
符号 :符号
求解方程的变量
域 :设置
求解方程的集合。
- 返回:
满足给定方程的一组解。
A
ConditionSet
如果方程不可解或如果假设没有正确定义,在这种情况下
不同的风格
ConditionSet
返回用期望的假设解方程。
实例
>>> from sympy.solvers.solveset import _solve_exponential as solve_expo >>> from sympy import symbols, S >>> x = symbols('x', real=True) >>> a, b = symbols('a b') >>> solve_expo(2**x + 3**x - 5**x, 0, x, S.Reals) # not solvable ConditionSet(x, Eq(2**x + 3**x - 5**x, 0), Reals) >>> solve_expo(a**x - b**x, 0, x, S.Reals) # solvable but incorrect assumptions ConditionSet(x, (a > 0) & (b > 0), {0}) >>> solve_expo(3**(2*x) - 2**(x + 3), 0, x, S.Reals) {-3*log(2)/(-2*log(3) + log(2))} >>> solve_expo(2**x - 4**x, 0, x, S.Reals) {0}
方法正确性证明
对数函数是指数函数的倒数。指数和对数之间的定义关系是:
\[{\log_bx}=y\n如果\n空间b^y=x\]因此,如果给我们一个带指数项的方程,我们可以把每个项都转换成相应的对数形式。这是通过取对数并用对数恒等式展开方程来实现的,这样就可以很容易地用
solveset
.例如:
\[3^{2x}=2^{x+3}\]两边取对数将把方程简化为
\[(2x)\log(3)=(x+3)\log(2)\]这张表格很容易交出来
solveset
.
- sympy.solvers.solveset._solve_logarithm(lhs, rhs, symbol, domain)[源代码]#
帮助求解可化为单个实例的对数方程 \(\log\) .
对数方程是(当前)包含 \(\log\) 可以简化为单个的术语 \(\log\) 使用各种对数恒等式的项或常数。
例如:
\[\对数(x)+\log(x-4)\]可以简化为:
\[\对数(x(x-4))\]- 参数:
左侧、右侧 :表达式
要求解的对数方程, \(lhs = rhs\)
符号 :符号
求解方程的变量
域 :设置
求解方程的集合。
- 返回:
满足给定方程的一组解。
A
ConditionSet
如果方程不可解。
实例
>>> from sympy import symbols, log, S >>> from sympy.solvers.solveset import _solve_logarithm as solve_log >>> x = symbols('x') >>> f = log(x - 3) + log(x + 3) >>> solve_log(f, 0, x, S.Reals) {-sqrt(10), sqrt(10)}
正确性证明
对数是另一种写指数的方法,由
\[{\log_bx}=y\n如果\n空间b^y=x\]当方程的一侧包含一个对数时,可以通过将方程改写为上面定义的等效指数方程来求解该方程。但是如果一个边包含多个对数,我们需要使用对数的性质将它压缩成一个单一的对数。
举个例子
\[\对数(2x)-15=0\]包含单对数,因此我们可以直接将其重写为指数形式
\[x=\frac{e^{15}}{2}\]但是如果方程有一个以上的对数
\[\对数(x-3)+\log(x+3)=0\]我们用对数恒等式把它转换成约化形式
使用,
\[\对数(a)+\log(b)=\log(ab)\]方程变成了,
\[\对数((x-3)(x+3))\]这个方程包含一个对数,可以通过重写指数来求解。
- sympy.solvers.solveset._is_logarithmic(f, symbol)[源代码]#
返回
True
如果方程的形式是 \(a\log(f(x)) + b\log(g(x)) + ... + c\) 其他的False
.- 参数:
f :表达式
要检查的方程式
符号 :符号
检查方程式的变量
- 返回:
True
如果方程是对数的,否则False
.
实例
>>> from sympy import symbols, tan, log >>> from sympy.solvers.solveset import _is_logarithmic as check >>> x, y = symbols('x y') >>> check(log(x + 2) - log(x + 3), x) True >>> check(tan(log(2*x)), x) False >>> check(x*log(x), x) False >>> check(x + log(x), x) False >>> check(y + log(x), x) True
帮手背后的哲学
函数提取每个项并检查它是否是对数w.r.t
symbol
.
丢番图方程#
见 丢番图
不平等#
见 不等式解算器
常微分方程#
见 ODE .
偏微分方程#
见 PDE .