Mathematical modeling with Python (2)

1. Differential equation model

Differential equations are mathematical tools that describe the evolution of the state of a system over time and space. Many kinematics and dynamics problems involving variable forces in physics, such as falling objects whose air resistance is a function of velocity, can be solved by differential equations. Differential equations are also widely used in fields such as chemistry, engineering, economics, and demography.

Specifically, a differential equation is a relation involving an unknown function and its derivatives.

The mathematical modeling of differential equations is actually not complicated. The basic process is to analyze what kind of problem the topic belongs to, what differential equation model can be selected, and then how to use the existing differential equation model to model.

1. Numerical solution of differential equations

The numerical solution of the differential equation is to discretize the time and space first, then differentiate it into a difference, establish a recursive relationship, and then repeatedly perform iterative calculations to obtain the value of any time and space.
insert image description here

2. SciPy solves ordinary differential equations (groups)

1. First-order ordinary differential equation (group) model
insert image description here
2. scipy.integrate.odeint() function

function prototype
insert image description here

Parameter explanation
func:callable(y, t, …) or callable(t, y, …)
calculates the derivative of y at point t. If the signature is callable(t, y, ...), then the parameter tfirst must be set to True.
y0:array
The initial condition of y (can be a vector).
t:array
The sequence of time points to be solved for y. The initial point should be the first element of this sequence. This sequence must be monotonically increasing or monotonically decreasing; duplicate values ​​are allowed.
args:tuple, optional
Pass arguments to the arg function func. When the derivative function f ( y , t , p 1 , p 2 , . . ) f(y,t,p1,p2,…)f(y,t,p1,p2,…) includes variable parameters p1,p2… When , the parameters p1, p2… can be passed to the derivative function func by args =(p1,p2,…).

The main return value of odeint
y: array
array with shape (len(t),len(y0), giving the y value at each moment in the time series t.

3. Scipy solves first-order ordinary differential equations

1. scipy.integrate.odeint() Steps to solve the initial value problem of the ordinary differential equation
insert image description here
2. Find the numerical solution of the differential equation
insert image description here

from scipy.integrate import odeint  # 导入 scipy.integrate 模块
import numpy as np
import matplotlib.pyplot as plt

def dy_dt(y, t):  # 定义函数 f(y,t)
    return np.sin(t**2)

y0 = [1]  # y0 = 1 也可以
t = np.arange(-10,10,0.01)  # (start,stop,step)
y = odeint(dy_dt, y0, t)  # 求解微分方程初值问题

# 绘图
plt.plot(t, y)
plt.title("scipy.integrate.odeint")
plt.show()

insert image description here

4. Scipy solves first-order ordinary differential equations

1. Find the numerical solution of the Lorenz equation
insert image description here
2. Programming steps for Lorenz equation problems
insert image description here
3. Code

from scipy.integrate import odeint  # 导入 scipy.integrate 模块
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D


# 导数函数, 求 W=[x,y,z] 点的导数 dW/dt
def lorenz(W, t, p, r, b):
    x, y, z = W  # W=[x,y,z]
    dx_dt = p * (y - x)  # dx/dt = p*(y-x), p: sigma
    dy_dt = x * (r - z) - y  # dy/dt = x*(r-z)-y, r:rho
    dz_dt = x * y - b * z  # dz/dt = x*y - b*z, b;beta
    return np.array([dx_dt, dy_dt, dz_dt])


t = np.arange(0, 30, 0.01)  # 创建时间点 (start,stop,step)
paras = (10.0, 28.0, 3.0)  # 设置 Lorenz 方程中的参数 (p,r,b)

# 调用ode对lorenz进行求解, 用两个不同的初始值 W1、W2 分别求解
W1 = (0.0, 1.00, 0.0)  # 定义初值为 W1
track1 = odeint(lorenz, W1, t, args=(10.0, 28.0, 3.0))  # args 设置导数函数的参数
W2 = (0.0, 1.01, 0.0)  # 定义初值为 W2
track2 = odeint(lorenz, W2, t, args=paras)  # 通过 paras 传递导数函数的参数

# 绘图
fig = plt.figure()
ax = Axes3D(fig, auto_add_to_figure=False)
fig.add_axes(ax)
ax.plot(track1[:, 0], track1[:, 1], track1[:, 2], color='magenta')  # 绘制轨迹 1
ax.plot(track2[:, 0], track2[:, 1], track2[:, 2], color='deepskyblue')  # 绘制轨迹 2
ax.set_title("Lorenz attractor by scipy.integrate.odeint")
plt.show()

4. Results
insert image description here
insert image description here

5. Scipy solves high-order ordinary differential equations

For high-order ordinary differential equations, variable substitution must be performed to convert them into a system of first-order differential equations, and then use odeint to find numerical solutions.
1. Find the numerical solution of the second-order RLC oscillating circuit
insert image description here
2. The programming steps of the second-order differential equation problem
insert image description here
3. Code

from scipy.integrate import odeint  # 导入 scipy.integrate 模块
import numpy as np
import matplotlib.pyplot as plt


# 导数函数,求 Y=[u,v] 点的导数 dY/dt
def deriv(Y, t, a, w):
    u, v = Y  # Y=[u,v]
    dY_dt = [v, -2 * a * v - w * w * u]
    return dY_dt


t = np.arange(0, 20, 0.01)  # 创建时间点 (start,stop,step)
# 设置导数函数中的参数 (a, w)
paras1 = (1, 0.6)  # 过阻尼:a^2 - w^2 > 0
paras2 = (1, 1)  # 临界阻尼:a^2 - w^2 = 0
paras3 = (0.3, 1)  # 欠阻尼:a^2 - w^2 < 0

# 调用ode对进行求解, 用两个不同的初始值 W1、W2 分别求解
Y0 = (1.0, 0.0)  # 定义初值为 Y0=[u0,v0]
Y1 = odeint(deriv, Y0, t, args=paras1)  # args 设置导数函数的参数
Y2 = odeint(deriv, Y0, t, args=paras2)  # args 设置导数函数的参数
Y3 = odeint(deriv, Y0, t, args=paras3)  # args 设置导数函数的参数

# 绘图
plt.plot(t, Y1[:, 0], 'r-', label='u1(t)')
plt.plot(t, Y2[:, 0], 'b-', label='u2(t)')
plt.plot(t, Y3[:, 0], 'g-', label='u3(t)')
plt.plot(t, Y1[:, 1], 'r:', label='v1(t)')
plt.plot(t, Y2[:, 1], 'b:', label='v2(t)')
plt.plot(t, Y3[:, 1], 'g:', label='v3(t)')
plt.axis([0, 20, -0.8, 1.2])
plt.legend(loc='best')
plt.title("Second ODE by scipy.integrate.odeint")
plt.show()

4. Results
insert image description here
insert image description here

2. Differential equation boundary value problem (BVP)

A differential equation is a relation involving an unknown function and its derivatives.

Differential equations are mathematical tools that describe the evolution of the state of a system over time and space.

Differential equations are divided into initial value problems and boundary value problems. The initial value problem is the initial condition of the known differential equation, that is, the function value when the independent variable is zero, which can generally be solved by Euler's method and Longo-Kutta's method. The boundary value problem is the boundary condition of the known differential equation, that is, the function value of the independent variable at the boundary point.

1. Mathematical model of boundary value problems for ordinary differential equations

insert image description here

2. SciPy solves ordinary differential equation boundary value problems

1. The standard form of the BVP problem
insert image description here
2. The scipy.integrate.solve_bvp() function
can solve the two-point boundary value problem (the first type of boundary condition) of the first-order differential equation (group).
insert image description here
The main parameters of solve_bvp:
func: callable fun(x, y, …) derivative function f ( y , x ) f(y,x)f(y,x) , the derivative of y at x, expressed in the form of a function. Can take parameter p.
bc: callable bc(ya, yb, …) Boundary conditions, the function of y on the two-point boundary, expressed in the form of a function. Can take parameter p.
x: array: sequence of initial grids, shape (m,). It must be a monotonically increasing sequence of real numbers, starting and ending at two boundary values ​​xa, xb.
y: array: the initial value of the function value at the grid node, shape (n,m), the i-th column corresponds to x[i].

The main return value of solve_bvp:
sol: PPoly Calculate the y value at the grid node through PPoly (such as cubic continuous spline function) interpolation.
x: array array, the shape is (m,), the final output grid node.
y: array Two-dimensional array, the shape is (n,m), the output y value at the grid node.
yp: array Two-dimensional array, the shape is (n,m), the output y' value at the grid node.

3. First order ordinary differential equation boundary value problem

1. Standardization
insert image description here
2. Programming steps
insert image description here
3. Code

from scipy.integrate import odeint, solve_bvp
import numpy as np
import matplotlib.pyplot as plt


# 1. 求解微分方程组边值问题,DEMO
# y'' + abs(y) = 0, y(0)=0.5, y(4)=-1.5

# 导数函数,计算导数 dY/dx
def dydx(x, y):
    dy0 = y[1]
    dy1 = -abs(y[0])
    return np.vstack((dy0, dy1))


# 计算 边界条件
def boundCond(ya, yb):
    fa = 0.5  # 边界条件 y(xa=0) = 0.5
    fb = -1.5  # 边界条件 y(xb=4) = -1.5
    return np.array([ya[0] - fa, yb[0] - fb])


xa, xb = 0, 4  # 边界点 (xa,xb)
# fa, fb = 0.5, -1.5  # 边界点的 y值
xini = np.linspace(xa, xb, 11)  # 确定 x 的初值
yini = np.zeros((2, xini.size))  # 确定 y 的初值
res = solve_bvp(dydx, boundCond, xini, yini)  # 求解 BVP

xSol = np.linspace(xa, xb, 100)  # 输出的网格节点
ySol = res.sol(xSol)[0]  # 网格节点处的 y 值

plt.plot(xSol, ySol, label='y')
plt.xlabel("x")
plt.ylabel("y")
plt.title("scipy.integrate.solve_bvp")
plt.show()

4. Execution result
insert image description here

4. Shape of water droplet cross section

insert image description here

from scipy.integrate import odeint, solve_bvp
import numpy as np
import matplotlib.pyplot as plt


# 3. 求解微分方程边值问题,水滴的横截面
# 导数函数,计算 h=[h0,h1] 点的导数 dh/dx
def dhdx(x, h):
    # 计算 dh0/dx, dh1/dx 的值
    dh0 = h[1]  # 计算 dh0/dx
    dh1 = (h[0] - 1) * (1 + h[1] * h[1]) ** 1.5  # 计算 dh1/dx
    return np.vstack((dh0, dh1))


# 计算 边界条件
def boundCond(ha, hb):
    # ha = 0  # 边界条件:h0(x=-1) = 0
    # hb = 0  # 边界条件:h0(x=1) = 0
    return np.array([ha[0], hb[0]])


xa, xb = -1, 1  # 边界点 (xa=0, xb=1)
xini = np.linspace(xa, xb, 11)  # 设置 x 的初值
hini = np.zeros((2, xini.size))  # 设置 h 的初值

res = solve_bvp(dhdx, boundCond, xini, hini)  # 求解 BVP
# scipy.integrate.solve_bvp(fun, bc, x, y,..)
#   fun(x, y, ..), 导数函数 f(y,x),y在 x 处的导数。
#   bc(ya, yb, ..), 边界条件,y 在两点边界的函数。
#   x: shape (m),初始网格的序列,起止于两点边界值 xa,xb。
#   y: shape (n,m),网格节点处函数值的初值,第 i 列对应于 x[i]。

xSol = np.linspace(xa, xb, 100)  # 输出的网格节点
hSol = res.sol(xSol)[0]  # 网格节点处的 h 值
plt.plot(xSol, hSol, label='h(x)')
plt.xlabel("x")
plt.ylabel("h(x)")
plt.axis([-1, 1, 0, 1])
plt.title("Cross section of water drop by BVP")
plt.show()

insert image description here

5. Boundary Value Problems for Differential Equations with Unknown Parameters

insert image description here
insert image description here

from scipy.integrate import odeint, solve_bvp
import numpy as np
import matplotlib.pyplot as plt


# 4. 求解微分方程组边值问题,Mathieu 方程
# y0' = y1, y1' = -(lam-2*q*cos(2x))y0)
# y0(0)=1, y1(0)=0, y1(pi)=0

# 导数函数,计算导数 dY/dx
def dydx(x, y, p):  # p 是待定参数
    lam = p[0]
    q = 10
    dy0 = y[1]
    dy1 = -(lam - 2 * q * np.cos(2 * x)) * y[0]
    return np.vstack((dy0, dy1))


# 计算 边界条件
def boundCond(ya, yb, p):
    lam = p[0]
    return np.array([ya[0] - 1, ya[0], yb[0]])


xa, xb = 0, np.pi  # 边界点 (xa,xb)
xini = np.linspace(xa, xb, 11)  # 确定 x 的初值
xSol = np.linspace(xa, xb, 100)  # 输出的网格节点

for k in range(5):
    A = 0.75 * k
    y0ini = np.cos(8 * xini)  # 设置 y0 的初值
    y1ini = -A * np.sin(8 * xini)  # 设置 y1 的初值
    yini = np.vstack((y0ini, y1ini))  # 确定 y=[y0,y1] 的初值
    res = solve_bvp(dydx, boundCond, xini, yini, p=[10])  # 求解 BVP
    y0 = res.sol(xSol)[0]  # 网格节点处的 y 值
    y1 = res.sol(xSol)[1]  # 网格节点处的 y 值
    plt.plot(xSol, y0, '--')
    plt.plot(xSol, y1, '-', label='A = {:.2f}'.format(A))

plt.xlabel("hbu")
plt.ylabel("y")
plt.title("Characteristic function of Mathieu equation")
plt.axis([0, np.pi, -5, 5])
plt.legend(loc='best')
plt.text(2, -4, "hao-hbu", color='whitesmoke')
plt.show()

insert image description here

3. Nonlinear programming

1. Description of the nonlinear programming problem

insert image description here
insert image description here

2.scipy.optimize.brent() solves univariate unconstrained optimization problems

The simplest form of nonlinear programming is one-dimensional search, and the common methods of one-dimensional search are function approximation method and interval contraction method.

The brent() function is the preferred method in the SciPy.optimize module for finding the minimum of univariate unconstrained optimization problems. This is a hybrid method of Newton's method and bisection method, which can guarantee stability and fast convergence.
insert image description here
The main parameters of optimize.brent():
func: callable f(x,args) The objective function f ( x ) f(x)f(x), expressed in the form of a function, can pass parameters through *args args: tuple optional
, Pass the variadic argument p to the objective function f ( x , p ) f(x,p)f(x,p) in the form f(x,*args) .
brack: tuple optional, the starting interval of the search algorithm (not the upper and lower limits of x)

The main return value of optimize.brent():
xmin: Returns the x when the function reaches the minimum value (note that it is a local optimum, not necessarily a global optimum).
fval: returns the optimal value of the function (not returned by default, only returned when full_output is 1).

The usage routine of optimize.brent():

import numpy as np
from scipy.optimize import brent
import matplotlib.pyplot as plt


# 1. Demo1:单变量无约束优化问题(Scipy.optimize.brent)
def objf(x):  # 目标函数
    fx = x ** 2 - 8 * np.sin(2 * x + np.pi)
    return fx


xIni = -5.0
xOpt = brent(objf, brack=(xIni, 2))
print("xIni={:.4f}\tfxIni={:.4f}".format(xIni, objf(xIni)))
print("xOpt={:.4f}\tfxOpt={:.4f}".format(xOpt, objf(xOpt)))

x = np.linspace(-10, 10, 500)
plt.plot(x, objf(x))
plt.xlabel("x")
plt.ylabel("objf(x)")
plt.text(xIni, objf(xIni), "Initial")
plt.text(xOpt, objf(xOpt), "Best")
plt.scatter(xIni, objf(xIni))
plt.scatter(xOpt, objf(xOpt))
plt.show()

operation result:
insert image description here
insert image description here

3.scipy.optimize.fmin() solves multivariable unconstrained optimization problems

The fmin() function is the preferred method in the SciPy.optimize module for solving multivariate unconstrained optimization problems (minimums), using the downhill simplicity method. The downhill simplicity method, also known as the Nelder-Mead method, only uses the objective function value and does not require derivative or second derivative values. It is one of the most important numerical methods for multidimensional unconstrained optimization problems.
insert image description here
insert image description here

from scipy.optimize import brent, fmin, minimize
import numpy as np
# 2. Demo2:多变量无约束优化问题(Scipy.optimize.brent)
# Rosenbrock 测试函数
def objf2(x):  # Rosenbrock benchmark function
    fx = sum(100.0 * (x[1:] - x[:-1] ** 2.0) ** 2.0 + (1 - x[:-1]) ** 2.0)
    return fx
xIni = np.array([-2, -2])
xOpt = fmin(objf2, xIni)
print("xIni={:.4f},{:.4f}\tfxIni={:.4f}".format(xIni[0],xIni[1],objf2(xIni)))
print("xOpt={:.4f},{:.4f}\tfxOpt={:.4f}".format(xOpt[0],xOpt[1],objf2(xOpt)))

insert image description here

4.scipy.optimize.minimize() solves nonlinear programming problems

The minimize() function is a general method for solving multivariable optimization problems in the SciPy.optimize module. It can call a variety of algorithms and supports constrained optimization and unconstrained optimization.
insert image description here
insert image description here
insert image description here
insert image description here

import numpy as np
from scipy.optimize import minimize


# 定义目标函数
def objf3(x):  # Rosenbrock 测试函数
    fx = sum(100.0 * (x[1:] - x[:-1] ** 2.0) ** 2.0 + (1 - x[:-1]) ** 2.0)
    return fx


# 定义边界约束(优化变量的上下限)
b0 = (0.0, None)  # 0.0 <= x[0] <= Inf
b1 = (0.0, 10.0)  # 0.0 <= x[1] <= 10.0
b2 = (-5.0, 100.)  # -5.0 <= x[2] <= 100.0
bnds = (b0, b1, b2)  # 边界约束

# 优化计算
xIni = np.array([1., 2., 3.])
resRosen = minimize(objf3, xIni, method='SLSQP', bounds=bnds)
xOpt = resRosen.x

print("xOpt = {:.4f}, {:.4f}, {:.4f}".format(xOpt[0], xOpt[1], xOpt[2]))
print("min f(x) = {:.4f}".format(objf3(xOpt)))

insert image description here

5. Examples of constrained nonlinear programming problems

insert image description here
insert image description here

import numpy as np
from scipy.optimize import minimize


def objF4(x):  # 定义目标函数
    a, b, c, d = 1, 2, 3, 8
    fx = a * x[0] ** 2 + b * x[1] ** 2 + c * x[2] ** 2 + d
    return fx


# 定义约束条件函数
def constraint1(x):  # 不等式约束 f(x)>=0
    return x[0] ** 2 - x[1] + x[2] ** 2


def constraint2(x):  # 不等式约束 转换为标准形式
    return -(x[0] + x[1] ** 2 + x[2] ** 3 - 20)


def constraint3(x):  # 等式约束
    return -x[0] - x[1] ** 2 + 2


def constraint4(x):  # 等式约束
    return x[1] + 2 * x[2] ** 2 - 3


# 定义边界约束
b = (0.0, None)
bnds = (b, b, b)

# 定义约束条件
con1 = {
    
    'type': 'ineq', 'fun': constraint1}
con2 = {
    
    'type': 'ineq', 'fun': constraint2}
con3 = {
    
    'type': 'eq', 'fun': constraint3}
con4 = {
    
    'type': 'eq', 'fun': constraint4}
cons = ([con1, con2, con3, con4])  # 3个约束条件

# 求解优化问题
x0 = np.array([1., 2., 3.])  # 定义搜索的初值
res = minimize(objF4, x0, method='SLSQP', bounds=bnds, constraints=cons)

print("Optimization problem (res):\t{}".format(res.message))  # 优化是否成功
print("xOpt = {}".format(res.x))  # 自变量的优化值
print("min f(x) = {:.4f}".format(res.fun))  # 目标函数的优化值

insert image description here

Guess you like

Origin blog.csdn.net/m0_46692607/article/details/126798062