本帖最后由 白冥 于 2025-1-27 22:34 编辑
本贴提供了一个自定义模块来处理数学单位、符号以及其组合运算,并能计算导数。它的设计目的是让用户能够使用面向对象的方式定义、组合、运算和求导数,适用于符号计算、数值计算和优化等场景。本贴将对该模块中的各个类、函数进行详细介绍,帮助用户理解如何使用该模块进行各种数学操作。
目录
1. 模块简介
2. 类定义
○ Unit类
○ _Constant类
○ Symbol类
○ 运算符类:_Add、_Sub、_Mul、_Div、_Pow
○ 函数类:_Exp、_Log、_Sin、_Cos
3. 函数定义 ○ exp函数 ○ log函数 ○ sin函数 ○ cos函数
4. 核心函数
○ derivative 函数
○ to_lambda 函数
○ Newton 函数
5. 示例代码
○ 简单数学运算
○ 求导数
○ 使用 Newton 求解方程
6. 常见问题与解决方案
一、模块介绍
此模块的核心思想是通过面向对象的方式实现数学运算的符号表示。通过对数学表达式建模,使得可以对表达式进行各种运算、求导和数值化。特别适用于数学建模、符号计算、数值计算和求解优化问题等场景。
该模块支持如下操作:
- 定义常量、符号、变量。
- 支持加法、减法、乘法、除法、幂运算等数学运算符。
- 支持导数计算。
- 可以通过 to_lambda 将符号表达式转换为 Python 函数进行数值计算。
- 提供了一个 Newton 函数来求解方程的数值解。
二、类定义
2.1 Unit类
Unit类是所有数学单位(符号、常量等)的基类。它定义了基本的运算符重载,如加法、减法、乘法、除法和幂运算,允许数学单位之间进行数学运算。同时,Unit类也定义了derivative方法和to_lambda方法,这两个方法分别用于求导和将符号表达式转化为 Python 可执行的函数。
- import math
- class Unit:
- def __new__(cls,*units):
- unit=super().__new__(cls)
- unit.units=units
- return unit
- def __add__(self,other):
- if isinstance(other,(int,float)):
- return _Add(self,_Constant(other))
- return _Add(self,other)
- def __sub__(self,other):
- if isinstance(other,(int,float)):
- return _Sub(self,_Constant(other))
- return _Sub(self,other)
- def __mul__(self,other):
- if isinstance(other,(int,float)):
- return _Mul(self,_Constant(other))
- return _Mul(self,other)
- def __truediv__(self,other):
- if isinstance(other,(int,float)):
- return _Div(self,_Constant(other))
- return _Div(self,other)
- def __pow__(self,other):
- if not isinstance(other,(int,float)):
- raise ValueError("Not a standard power function")
- return _Pow(self,_Constant(other))
- def derivative(self,var):
- return None
- def to_lambda(self,var):
- return lambda x: None
- def __getattr__(self, name):
- raise AttributeError(f"'{self.__class__.__name__}' class has no attribute '{name}'. Direct instantiation is not allowed.")
复制代码
__new__方法:
●用于初始化类的实例,接收若干个单位作为参数(例如,常量或符号)。
●不允许直接实例化 Unit 类, Unit 类只能被子类继承。
运算符重载:
●__add__ :实现加法。
●__sub__ :实现减法。
●__mul__ :实现乘法。
●__truediv__ :实现除法。
●__pow__ :实现幂运算。
derivative和to_lambda:
●derivative:返回当前单位对指定变量的导数。
●to_lambda:返回一个Python Lambda函数,将符号表达式转化为数值计算的函数。
2.2 _Constant类
_Constant类表示常量。它继承自Unit类,并重写了derivative和to_lambda方法。
- class _Constant(Unit):
- def __new__(cls,value):
- if cls is _Constant:
- raise TypeError("Cannot instantiate _Constant directly.")
- unit=super().__new__(cls)
- unit.value=value
- return unit
- def derivative(self,var):
- return _Constant(0)
- def to_lambda(self,var):
- return lambda x: self.value
- def __add__(self,other):
- if isinstance(other,(int,float)):
- return _Constant(self.value+other)
- return super().__add__(other)
- def __sub__(self,other):
- if isinstance(other,(int,float)):
- return _Constant(self.value-other)
- return super().__sub__(other)
- def __mul__(self,other):
- if isinstance(other,(int,float)):
- return _Constant(self.value*other)
- return super().__mul__(other)
- def __truediv__(self,other):
- if isinstance(other,(int,float)):
- return _Constant(self.value/other)
- return super().__truediv__(other)
- def __pow__(self,other):
- if not isinstance(other,(int,float)):
- raise ValueError("Not a standard power function")
- return _Constant(self.value**other)
复制代码
derivative方法:
●常数的导数是0,因此derivative方法返回一个常数0 。
to_lambda方法:
●常数的Lambda函数就是一个恒定的数值,因此to_lambda返回一个返回常量值的 Lambda 函数。
2.3 Symbol类
Symbol类表示符号或变量。它继承自Unit类,表示数学表达式中的符号,如x、y等。
- class Symbol(Unit):
- def __new__(cls,name):
- unit=super().__new__(cls)
- unit.name=name
- return unit
- def derivative(self,var):
- if self.name==var.name:
- return _Constant(1)
- return _Constant(0)
- def to_lambda(self,var):
- if self.name==var.name:
- return lambda x: x
- return lambda x: self
复制代码
derivative 方法:
●Symbol 对变量的导数遵循标准的求导法则:
◆如果符号是目标变量,则导数为 1。
◆否则,导数为 0。
to_lambda 方法:
●将符号转化为 Lambda 函数,表示一个以 x 为输入的变量函数。
2.4 运算符类:_Add、_Sub、_Mul、_Div、_Pow
这些类分别实现了加法、减法、乘法、除法和幂运算。这些类的设计方式与Unit类相似,并实现了与运算符相关的derivative和to_lambda方法。
- class _Add(Unit):
- def __new__(cls,unit_0,unit_1):
- if cls is _Add:
- raise TypeError("Cannot instantiate _Add directly.")
- return super().__new__(cls,unit_0,unit_1)
- def derivative(self,var):
- u,v=self.units
- der_u=u.derivative(var)
- der_v=v.derivative(var)
- return der_u+der_v
- def to_lambda(self,var):
- u,v=self.units
- f=u.to_lambda(var)
- g=v.to_lambda(var)
- return lambda x: f(x)+g(x)
- class _Sub(Unit):
- def __new__(cls,unit_0,unit_1):
- if cls is _Sub:
- raise TypeError("Cannot instantiate _Sub directly.")
- return super().__new__(cls,unit_0,unit_1)
- def derivative(self,var):
- u,v=self.units
- der_u=u.derivative(var)
- der_v=v.derivative(var)
- return der_u-der_v
- def to_lambda(self,var):
- u,v=self.units
- f=u.to_lambda(var)
- g=v.to_lambda(var)
- return lambda x: f(x)-g(x)
- class _Mul(Unit):
- def __new__(cls,unit_0,unit_1):
- if cls is _Mul:
- raise TypeError("Cannot instantiate _Mul directly.")
- return super().__new__(cls,unit_0,unit_1)
- def derivative(self,var):
- u,v=self.units
- der_u=u.derivative(var)
- der_v=v.derivative(var)
- return der_u*v+u*der_v
- def to_lambda(self,var):
- u,v=self.units
- f=u.to_lambda(var)
- g=v.to_lambda(var)
- return lambda x: f(x)*g(x)
- class _Div(Unit):
- def __new__(cls,unit_0,unit_1):
- if cls is _Div:
- raise TypeError("Cannot instantiate _Div directly.")
- return super().__new__(cls,unit_0,unit_1)
- def derivative(self,var):
- u,v=self.units
- der_u=u.derivative(var)
- der_v=v.derivative(var)
- return (der_u*v-u*der_v)/v**_Constant(2)
- def to_lambda(self,var):
- u,v=self.units
- f=u.to_lambda(var)
- g=v.to_lambda(var)
- return lambda x: f(x)/g(x)
- class _Pow(Unit):
- def __new__(cls,base,exp):
- if cls is _Pow:
- raise TypeError("Cannot instantiate _Pow directly.")
- return super().__new__(cls,base,exp)
- def derivative(self, var):
- u, a = self.units
- der_u=u.derivative(var)
- return a*(u**(a-1))*der_u
- def to_lambda(self,var):
- u, a = self.units
- f=u.to_lambda(var)
- return lambda x: f(x)**a.value
复制代码
derivative 方法:
●对于加法、减法和乘法,采用导数的基本法则,分别进行逐项求导。
●对于除法,使用商法则。
●对于幂运算,使用幂函数求导公式。
to_lambda 方法:
●将运算表达式转化为 Lambda 函数,依次将其组成的两个单位转化为 Lambda 函数,然后进行对应的运算。
2.5 函数类:_Exp、_Log、_Sin、_Cos
这些类分别实现了指数函数、对数函数、正弦函数和余弦函数。
- class _Exp(Unit):
- def __new__(cls,base,exp):
- if cls is _Exp:
- raise TypeError("Cannot instantiate _Exp directly.")
- return super().__new__(cls,base,exp)
- def derivative(self, var):
- a,u=self.units
- der_u=u.derivative(var)
- return (a**u)*log(_Constant(math.e),a)*der_u
- def to_lambda(self,var):
- a,u = self.units
- f=u.to_lambda(var)
- return lambda x: a.value**f(x)
- class _Log(Unit):
- def __new__(cls,base,antilog):
- if cls is _Log:
- raise TypeError("Cannot instantiate _Log directly.")
- return super().__new__(cls,base,antilog)
- def derivative(self, var):
- a,u=self.units
- der_u=u.derivative(var)
- return der_u/(u*log(_Constant(math.e),a))
- def to_lambda(self,var):
- a,u = self.units
- f=u.to_lambda(var)
- return lambda x: math.log(f(x),a.value)
- class _Sin(Unit):
- def __new__(cls,radian):
- if cls is _Sin:
- raise TypeError("Cannot instantiate _Sin directly.")
- return super().__new__(cls,radian)
- def derivative(self, var):
- u = self.units[0]
- der_u=u.derivative(var)
- return cos(u)*der_u
- def to_lambda(self,var):
- u = self.units[0]
- f=u.to_lambda(var)
- return lambda x: math.sin(f(x))
- class _Cos(Unit):
- def __new__(cls,radian):
- if cls is _Cos:
- raise TypeError("Cannot instantiate _Cos directly.")
- return super().__new__(cls,radian)
- def derivative(self, var):
- u = self.units[0]
- der_u=u.derivative(var)
- return -sin(u)*der_u
- def to_lambda(self,var):
- u = self.units[0]
- f=u.to_lambda(var)
- return lambda x: math.cos(f(x))
复制代码
derivative 方法:
●对于指数函数,使用链式法则。
●对于对数函数,使用对数求导公式。
●对于正弦和余弦函数,使用标准的三角函数求导公式。
to_lambda 方法:
●依照数学函数的定义,返回相应的 Lambda 函数。
三、函数定义:exp,log,sin,cos函数
这些是用于构建特定数学函数的便捷函数
- def exp(base,exp):
- if not isinstance(base,(int,float)):
- raise ValueError("Not a standard exponential function")
- if isinstance(exp,(int,float)):
- return _Constant(base**exp)
- return _Exp(_Constant(base),exp)
- def log(base,antilog):
- if not isinstance(base,(int,float)):
- raise ValueError("Not a standard logarithmic function")
- if isinstance(antilog,(int,float)):
- return _Constant(math.log(antilog,base))
- if base<0:
- raise ValueError("Undefined")
- if base==1:
- raise ValueError("Meaningless")
- return _Log(_Constant(base),antilog)
- def sin(radian):
- if isinstance(radian,(int,float)):
- return _Constant(math.sin(radian))
- return _Sin(radian)
- def cos(radian):
- if isinstance(radian,(int,float)):
- return _Constant(math.cos(radian))
- return _Cos(radian)
复制代码
exp(base, exp):表示 base 的 exp 次幂。
log(base, antilog):表示以 base 为底,antilog 为真数的对数。
sin(radian):表示 radian 的正弦值。
cos(radian):表示 radian 的余弦值。
四、核心函数
4.1 derivative函数
该函数用于计算数学表达式的导数。它接受两个参数:
●expr:一个表示数学表达式的Unit对象。
●var:一个表示变量的Symbol对象。
4.2 to_lambda函数
该函数用于将数学表达式转化为Lambda函数。返回的Lambda函数可以接受一个数值输入,并返回相应的计算结果。
4.3 Newton函数
该函数实现了牛顿法(Newton's method)用于求解方程的根。输入:
●x_0 :初始猜测值。
●expr :一个表示方程的数学表达式。
●var :方程中的变量。
●tol :精度容忍度。
●max_time :最大迭代次数。
返回方程的数值解,或者如果在最大迭代次数内无法收敛,则返回 None 。
- def derivative(expr,var):
- return expr.derivative(var)
- def to_lambda(expr,var):
- return expr.to_lambda(var)
- def Newton(x_0,expr,var,tol,max_time):
- x_i=x_0
- f=to_lambda(expr,var)
- der_f=to_lambda(derivative(expr,var))
- for _ in range(max_time):
- x_i_1=x_i-f(x_i)/der_f(x_i)
- if abs(x_i_1-x_i)<tol:
- return x_i_1
- x_i=x_i_1
- return None
复制代码
五、示例代码:
5.1 简单数学运算
- # 定义符号
- x = Symbol('x')
- # 定义表达式
- expr = x ** 2 + 5 * x + exp(2, x)
- # 生成lambda函数
- f = to_lambda(expr, x)
- # 输出函数值
- print(f(1)) # 输出:8
复制代码
5.2 求导函数
- # 定义符号
- x = Symbol('x')
- # 定义表达式
- expr = sin(x) * cos(x)
- # 求导
- deriv = derivative(expr, x)
- # 输出导数
- print(deriv) # 输出:cos(x)**2 - sin(x)**2
复制代码
5.3 使用Newton方法求解方程
- # 定义符号
- x = Symbol('x')
- # 定义方程 f(x) = x^2 - 2
- expr = x**2 - _Constant(2)
- # 使用牛顿法求解
- root = Newton(1.0, expr, x, 1e-6, 100)
- # 输出结果
- print(root) # 输出:1.414213562373095
复制代码
六、常见问题与解决方案
问题 1:如何定义新的数学单位?
用户可以通过继承 Unit 类创建新的数学单位,并实现必要的方法如 derivative 和 to_lambda 。
问题 2:为什么我的运算结果不符合预期?
确保符号和常量的使用方法正确,并检查导数的计算规则是否适用。
问题 3:如何处理无法收敛的方程?
在使用 Newton 方法时,可以增加 max_time 参数或调整初始猜测值来提高收敛性。
|