【Python】【原创】自定义符号运算模块及其使用案例
本帖最后由 白冥 于 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
der_u=u.derivative(var)
return cos(u)*der_u
def to_lambda(self,var):
u = self.units
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
der_u=u.derivative(var)
return -sin(u)*der_u
def to_lambda(self,var):
u = self.units
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参数或调整初始猜测值来提高收敛性。
头好痒,感觉要长出脑子了.jpg 嗯?这是哪个论坛?好吧,我以为我点进了博客园;P 感覺是比較硬核的內容捏, 不過大概也是有友友可以用上的捏:loveliness: 额,在这里发Python合适吗,而且这个太基础了吧,感觉用c会更顺眼点 好硬合的内容,我在泥潭学技术.jpg,先码住了 QAQ 刚从隔壁帖子出来 今天是第二次长脑子了jpg 自己重载运算符的时候,感觉还是很容易出现边界或者特殊值的问题的 泥潭尊素卧虎藏龙,代码大佬满天飞惹{:6_190:} https://img.gamemale.com/album/202408/03/102121ubl2b4leibsmzs7s.gif别卷了别卷了,你这是要拿ACM金奖吗 本质上应该还是C++里面的重载,不过python可能写起来更简单 介素在?真不想放假了在家还天天学这些惹,饶了我吧,我放假只想搞瑟瑟:'(
页:
[1]