2.4 等式與假設系統#
本節目標#
- 理解 SymPy 中
=只是賦值、==是結構比較,真正的「數學等式」要用Eq - 學會用
solve()解Eq形式的方程 - 掌握假設系統:
Symbol('x', positive=True)宣告符號性質 - 學會
ask()詢問性質、refine()利用假設化簡 - 體會假設如何讓
simplify()變聰明( \(\sqrt{x^2} = x\) 需要 \(x \ge 0\) )
從數學開始:等式與符號的性質#
數學中寫 \(x^2 = 4\) 是一個「命題」——可以為真或為假。但在 Python 裡:
x = 4是賦值:把 4 綁到變數名xx == 4是結構比較:回傳 Python 的True/False- SymPy 表達式之間的
==比較的是語法樹,不是數學相等:
from sympy import Symbol
x = Symbol('x')
print((x + 1)**2 == x**2 + 2*x + 1) # False!語法樹不同
即使兩式數學上恆等,== 也回傳 False。所以 SymPy 提供 Eq(a, b) 來表達數學等式 \(a = b\) 。
另一個重要觀念:符號是有「身分證」的。數學上我們說「 \(x > 0\) 」來限定符號的範圍,SymPy 的假設系統就是在 Symbol 物件上記錄這些性質。
Eq:表達數學等式#
from sympy import Eq, symbols, sin
x = symbols('x')
eq = Eq(x**2, 4)
print(eq) # Eq(x**2, 4)
print(eq.lhs) # x**2(左邊)
print(eq.rhs) # 4(右邊)
Eq 是一個 SymPy 物件,可以當作 solve()、dsolve() 的輸入:
from sympy import solve
print(solve(Eq(x**2, 4), x)) # [-2, 2]
print(solve(Eq(sin(x), S(1)/2), x))
# [pi/6, 5*pi/6]
不傳 Eq 時,solve(expr, x) 預設解 expr = 0,兩種寫法等價:
print(solve(x**2 - 4, x)) # [-2, 2]
假設系統:Symbol 的身分證#
宣告符號時可以附加假設:
from sympy import Symbol, sqrt
x = Symbol('x') # 無假設:x 可以是任何複數
p = Symbol('x', positive=True) # x > 0
n = Symbol('n', integer=True) # n 是整數
r = Symbol('r', real=True) # r 是實數
假設立刻影響化簡行為。經典例子: \(\sqrt{x^2}\) 。
\[ \sqrt{x^2} = |x| = \begin{cases} x, & x \ge 0 \\ -x, & x < 0 \end{cases} \]
所以在「不知正負」時不能化簡;在「 \(x \ge 0\) 」時才能寫成 \(x\) :
print(sqrt(x**2)) # sqrt(x**2),不動
print(sqrt(p**2)) # x(因為 p 是正的!)
這不是 SymPy 挑剔,而是數學上的嚴謹:若 \(x = -3\) ,則 \(\sqrt{x^2} = 3 \ne -3\) 。
ask():詢問符號的性質#
ask() 對假設系統提問,回傳 True、False 或 None(無法判斷):
from sympy import ask, Q
x = Symbol('x', positive=True)
y = Symbol('y')
print(ask(Q.positive(x))) # True
print(ask(Q.positive(y))) # None(不知道)
print(ask(Q.integer(x))) # False
print(ask(Q.positive(x + 1))) # True(可由 x>0 推出 x+1>0)
print(ask(Q.even(2*x))) # None?—— 若 x 是整數則是
搭配假設能做邏輯推理:
n = Symbol('n', integer=True)
print(ask(Q.even(2*n))) # True(2n 必為偶數)
print(ask(Q.odd(n**2))) # None(奇偶未知)
k = Symbol('k', odd=True)
print(ask(Q.even(k**2 + 1))) # True(奇平方+1 必為偶)
refine():利用假設化簡表達式#
refine() 依假設把表達式化成更精確的形式:
from sympy import refine, Abs, sqrt
r = Symbol('r', real=True)
print(refine(Abs(r)**2, Q.positive(r))) # r**2
print(refine(sqrt(r**2), Q.positive(r))) # r
沒有足夠假設時,refine() 保持原樣——這正是保守而正確的行為。
假設讓 simplify() 變聰明#
比較同一個表達式在不同假設下的化簡結果:
from sympy import simplify, sqrt, log, exp, Symbol
xa = Symbol('x') # 無假設
xp = Symbol('x', positive=True) # x > 0
print(simplify(sqrt(xa**2))) # sqrt(x**2),不動
print(simplify(sqrt(xp**2))) # x
print(simplify(log(exp(xa)))) # exp(x)(複數域上有歧義,保守)
print(simplify(log(exp(xp)))) # x
背後機制:simplify() 及各專用函數在化簡前會查詢假設系統,若化簡步驟「在給定假設下恆成立」才執行。這讓同一行程式碼能表現出數學上嚴謹的多種行為。
常用的假設關鍵字:positive、negative、nonnegative、real、integer、even、odd、rational、nonzero。
動手實驗:不同假設下 \(\sqrt{x^2 y^2}\) 的化簡結果#
from sympy import Symbol, sqrt, simplify, refine, Q
# 情況 1:x, y 都無假設
x = Symbol('x')
y = Symbol('y')
print(simplify(sqrt(x**2 * y**2)))
# sqrt(x**2*y**2)(不動)
# 情況 2:只有 x 為正
xp = Symbol('x', positive=True)
print(simplify(sqrt(xp**2 * y**2)))
# y*sqrt(x**2)?—— 觀察 y 仍未化簡
# 情況 3:x, y 都為正
yp = Symbol('y', positive=True)
print(simplify(sqrt(xp**2 * yp**2)))
# x*y
# 情況 4:x, y 都是實數(但不知正負)
xr = Symbol('x', real=True)
yr = Symbol('y', real=True)
print(simplify(sqrt(xr**2 * yr**2)))
# 不動:實數但可能為負,sqrt(x^2)=|x| 而非 x
# 用 refine 與 ask 進一步探究
print(refine(sqrt(xr**2), Q.positive(xr))) # x
print(ask(Q.positive(sqrt(xr**2)), Q.nonnegative(xr))) # True
觀察重點:
- 兩變數都正時,才能完全化成 \(x \cdot y\)
- 只有一個正時,另一個保持保守
- 「實數」假設不足以化成 \(xy\) ,但足以保證 \(\sqrt{x^2y^2} \ge 0\)
實驗延伸:
- 把
y宣告為negative=True, \(\sqrt{x^2 y^2}\) 會化成什麼?(提示:應為 \(-xy\) ?還是不動?思考後再執行驗證) - 用
ask驗證:若 \(x\) 為正整數,則 \(x^2 + 1\) 是否必為正、是否可能為偶數? - 對 \(\log(x^2)\) 分別在「無假設」「正數」「非零實數」假設下做
expand,比較結果。 - 建構一個例子:某化簡在無假設時錯誤地給出結果、加了假設後才正確——試著用 \(\sqrt{x^2}\) 的數值代入 \(x=-3\) 說明為什麼保守是必要的。
小結與練習#
本節學會了:
=是賦值、==比較語法樹、數學等式用Eq;solve()可直接吃Eq- 假設系統:宣告
Symbol(..., positive=True)等性質,讓符號帶數學身分 ask(Q.positive(...), ...)詢問性質,refine()依假設化簡- 假設讓
simplify()嚴謹地變聰明: \(\sqrt{x^2} = x\) 只在 \(x \ge 0\) 時成立
練習:
- 用
Eq與solve解 \(x^3 - 3x + 1 = 0\) ,觀察根的形式(會出現三角函數表示)。 - 宣告
n = Symbol('n', integer=True, positive=True),用ask驗證 \(n(n+1)\) 恆為偶數。 - 分別在
x為正、負、實數三種假設下化簡 \(\sqrt{x^2} \cdot \sqrt{y^2}\) ,整理成表。 - 用
refine化簡 \(\cos^2 x + \sin^2 x\) (提示:搭配Q.real(x)),觀察與simplify的差異。