隱式方程組的Python數值解作法

隱式方程組的Python數值解作法

假設有一對$(x, y)$存在下列隱式(implicit)關係:

$y^{3}+2^{x}+5y^{2}-7x=2$

$sin(x)y+x^{2}y-xy^{3}=0$

這個方程組不好解,因為他們的顯式方程組(explicit equation set)不那麼明顯。如果以紙筆求出數值解,則需要先猜一組初始值,然後微分該方程組後代入初始值。以微分後得到的值為根據做進一步猜測,如此往復。求數值解的過程非常機械化且無聊,所以我們可以利用計算機幫我們完成這件討厭的工作。

作法

求數值解是一種最佳化算法。在電腦上手刻最佳化算法是非常不智的,就好像為了喝一瓶牛奶而培養微生物,然後祈禱它某一天會演化成乳牛。Python的套件optuna可以直接尋找數值解。

首先讓我們載入套件

# 載入必須套件
import optuna
optuna.logging.set_verbosity(optuna.logging.WARNING) # disable optuna warning
import numpy as np

# 安裝:python -m pip install optuna numpy


接下來我們要建立一個方程式objective 讓電腦知道最佳化的目標是什麼

# 目標函數
def objective(trial):
    x = trial.suggest_float('x', -10, 10) # 假設 x ∈ [-10, 10]
    y = trial.suggest_float('y', -10, 10) # 假設 y ∈ [-10, 10]
    loss_1 = y**3 + 2**x + 5*(y**2) - 7*x - 2
    loss_2 = np.sin(x)*y + (x**2)*y - x*(y**3)
    loss = np.array([loss_1, loss_2])
    return np.linalg.norm(loss) # L2 norm


然後optuna.optimize 就能夠透過不斷的嘗試找出 objective 的最佳解

# 最小化目標函數
sampler = optuna.samplers.TPESampler()
study = optuna.create_study(sampler=sampler, direction='minimize') # objectvie 越小越好
study.optimize(objective, n_trials=1000)

# 印出(x, y)的最佳值
print(study.best_params)
# output: {'x': 0.03111622282627699, 'y': -0.5141155663560733}

# 印出objective的最佳值
print(study.best_value)
# output: 0.016032011887374697


尋找數值解時也有一些需要注意的地方

  • 如果有大於兩種loss,請確保所有的losses的scale不要差太多。
  • 如果找不到解,可以檢查輸入值的範圍是否合適。除非萬不得已,不要輕易增加n_trials
  • 如果對於第一次找到的解不滿意,可以以第一次的解為基礎,以比較小的搜尋範圍再找一次解。

以下是根據第一次的結果,在比較小的(x, y)範圍內做最佳化的範例:

# 在比較小的(x, y)範圍內做最佳化
def objective2(trial):
    x = trial.suggest_float('x', -0.5, 0.5) 
    y = trial.suggest_float('y', -1, 0)
    loss_1 = y**3 + 2**x + 5*(y**2) - 7*x - 2
    loss_2 = np.sin(x)*y + (x**2)*y - x*(y**3)
    loss = np.array([loss_1, loss_2])
    return np.linalg.norm(loss) # L2 norm
    
  # 最小化目標函數
sampler = optuna.samplers.TPESampler()
study = optuna.create_study(sampler=sampler, direction='minimize')
study.optimize(objective, n_trials=1000)

# 印出(x, y)的最佳值
print(study.best_params)
# output: {'x': 0.005506817001806399, 'y': -0.4787724094168787}

# 印出objective的最佳值
print(study.best_value)
# output: 0.0026264689619759475

結語

工程上經常有許多隱式方程組,可能是過度複雜的並聯電路、或是需要查表的離散測量值。雖然也存在有簡單的作法。例如忽略所有的二次交叉項,這些值在真實的物理上通常都很小,但總是比較不準確。使用計算機找數值解曾經非常複雜,因為沒有好的套件提供最佳化算法。而Optuna為Python和計算機補上了這個空缺。

參考

  1. Optuna https://optuna.org/

所有文章分類

隱式方程組的Python數值解作法

訂閱我吧

不再錯過每一篇新文章

*

Yi-Lung Chiu