GameMale
登陆 / 注册 搜索

USERCENTER

SEARCHSITE

搜索

查看: 1723|回复: 11
收起左侧

[技术交流] 【Python】【原创】自定义符号运算模块及其使用案例

[复制链接] |关注本帖

邪恶的面具海盗弯钩神秘的红茶冒险用绷带魔法石碑箭术卷轴质量效应三部曲

     楼主| 白冥 发表于 2025-1-22 18:24:46 | 显示全部楼层 |阅读模式 <
    本帖最后由 白冥 于 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 可执行的函数。

    1. import math
    2. class Unit:
    3.     def __new__(cls,*units):
    4.         unit=super().__new__(cls)
    5.         unit.units=units
    6.         return unit
    7.     def __add__(self,other):
    8.         if isinstance(other,(int,float)):
    9.             return _Add(self,_Constant(other))
    10.         return _Add(self,other)
    11.     def __sub__(self,other):
    12.         if isinstance(other,(int,float)):
    13.             return _Sub(self,_Constant(other))
    14.         return _Sub(self,other)
    15.     def __mul__(self,other):
    16.         if isinstance(other,(int,float)):
    17.             return _Mul(self,_Constant(other))
    18.         return _Mul(self,other)
    19.     def __truediv__(self,other):
    20.         if isinstance(other,(int,float)):
    21.             return _Div(self,_Constant(other))
    22.         return _Div(self,other)
    23.     def __pow__(self,other):
    24.         if not isinstance(other,(int,float)):
    25.             raise ValueError("Not a standard power function")
    26.         return _Pow(self,_Constant(other))
    27.     def derivative(self,var):
    28.         return None
    29.     def to_lambda(self,var):
    30.         return lambda x: None
    31.     def __getattr__(self, name):
    32.         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方法。

    1. class _Constant(Unit):
    2.     def __new__(cls,value):
    3.         if cls is _Constant:
    4.             raise TypeError("Cannot instantiate _Constant directly.")
    5.         unit=super().__new__(cls)
    6.         unit.value=value
    7.         return unit
    8.     def derivative(self,var):
    9.         return _Constant(0)
    10.     def to_lambda(self,var):
    11.         return lambda x: self.value
    12.     def __add__(self,other):
    13.         if isinstance(other,(int,float)):
    14.             return _Constant(self.value+other)
    15.         return super().__add__(other)
    16.     def __sub__(self,other):
    17.         if isinstance(other,(int,float)):
    18.             return _Constant(self.value-other)
    19.         return super().__sub__(other)
    20.     def __mul__(self,other):
    21.         if isinstance(other,(int,float)):
    22.             return _Constant(self.value*other)
    23.         return super().__mul__(other)
    24.     def __truediv__(self,other):
    25.         if isinstance(other,(int,float)):
    26.             return _Constant(self.value/other)
    27.         return super().__truediv__(other)
    28.     def __pow__(self,other):
    29.         if not isinstance(other,(int,float)):
    30.             raise ValueError("Not a standard power function")
    31.         return _Constant(self.value**other)
    复制代码


            derivative方法:
                ●常数的导数是0,因此derivative方法返回一个常数0 。
            to_lambda方法:
                ●常数的Lambda函数就是一个恒定的数值,因此to_lambda返回一个返回常量值的 Lambda 函数。

        2.3 Symbol类
             Symbol类表示符号或变量。它继承自Unit类,表示数学表达式中的符号,如x、y等。

    1. class Symbol(Unit):
    2.     def __new__(cls,name):
    3.         unit=super().__new__(cls)
    4.         unit.name=name
    5.         return unit
    6.     def derivative(self,var):
    7.         if self.name==var.name:
    8.             return _Constant(1)
    9.         return _Constant(0)
    10.     def to_lambda(self,var):
    11.         if self.name==var.name:
    12.             return lambda x: x
    13.         return lambda x: self
    复制代码


            derivative  方法:
                ●Symbol  对变量的导数遵循标准的求导法则:
                    ◆如果符号是目标变量,则导数为 1。
                    ◆否则,导数为 0。
            to_lambda  方法:
                ●将符号转化为 Lambda 函数,表示一个以  x  为输入的变量函数。

        2.4 运算符类:_Add、_Sub、_Mul、_Div、_Pow
            这些类分别实现了加法、减法、乘法、除法和幂运算。这些类的设计方式与Unit类相似,并实现了与运算符相关的derivative和to_lambda方法。

    1. class _Add(Unit):
    2.     def __new__(cls,unit_0,unit_1):
    3.         if cls is _Add:
    4.             raise TypeError("Cannot instantiate _Add directly.")
    5.         return super().__new__(cls,unit_0,unit_1)
    6.     def derivative(self,var):
    7.         u,v=self.units
    8.         der_u=u.derivative(var)
    9.         der_v=v.derivative(var)
    10.         return der_u+der_v
    11.     def to_lambda(self,var):
    12.         u,v=self.units
    13.         f=u.to_lambda(var)
    14.         g=v.to_lambda(var)
    15.         return lambda x: f(x)+g(x)
    16. class _Sub(Unit):
    17.     def __new__(cls,unit_0,unit_1):
    18.         if cls is _Sub:
    19.             raise TypeError("Cannot instantiate _Sub directly.")
    20.         return super().__new__(cls,unit_0,unit_1)
    21.     def derivative(self,var):
    22.         u,v=self.units
    23.         der_u=u.derivative(var)
    24.         der_v=v.derivative(var)
    25.         return der_u-der_v
    26.     def to_lambda(self,var):
    27.         u,v=self.units
    28.         f=u.to_lambda(var)
    29.         g=v.to_lambda(var)
    30.         return lambda x: f(x)-g(x)
    31. class _Mul(Unit):
    32.     def __new__(cls,unit_0,unit_1):
    33.         if cls is _Mul:
    34.             raise TypeError("Cannot instantiate _Mul directly.")
    35.         return super().__new__(cls,unit_0,unit_1)
    36.     def derivative(self,var):
    37.         u,v=self.units
    38.         der_u=u.derivative(var)
    39.         der_v=v.derivative(var)
    40.         return der_u*v+u*der_v
    41.     def to_lambda(self,var):
    42.         u,v=self.units
    43.         f=u.to_lambda(var)
    44.         g=v.to_lambda(var)
    45.         return lambda x: f(x)*g(x)
    46. class _Div(Unit):
    47.     def __new__(cls,unit_0,unit_1):
    48.         if cls is _Div:
    49.             raise TypeError("Cannot instantiate _Div directly.")
    50.         return super().__new__(cls,unit_0,unit_1)
    51.     def derivative(self,var):
    52.         u,v=self.units
    53.         der_u=u.derivative(var)
    54.         der_v=v.derivative(var)
    55.         return (der_u*v-u*der_v)/v**_Constant(2)
    56.     def to_lambda(self,var):
    57.         u,v=self.units
    58.         f=u.to_lambda(var)
    59.         g=v.to_lambda(var)
    60.         return lambda x: f(x)/g(x)
    61. class _Pow(Unit):
    62.     def __new__(cls,base,exp):
    63.         if cls is _Pow:
    64.             raise TypeError("Cannot instantiate _Pow directly.")
    65.         return super().__new__(cls,base,exp)
    66.     def derivative(self, var):
    67.         u, a = self.units
    68.         der_u=u.derivative(var)
    69.         return a*(u**(a-1))*der_u
    70.     def to_lambda(self,var):
    71.         u, a = self.units
    72.         f=u.to_lambda(var)
    73.         return lambda x: f(x)**a.value
    复制代码


            derivative  方法:
                ●对于加法、减法和乘法,采用导数的基本法则,分别进行逐项求导。
                ●对于除法,使用商法则。
                ●对于幂运算,使用幂函数求导公式。
            to_lambda  方法:
                ●将运算表达式转化为 Lambda 函数,依次将其组成的两个单位转化为 Lambda 函数,然后进行对应的运算。

        2.5 函数类:_Exp、_Log、_Sin、_Cos
            这些类分别实现了指数函数、对数函数、正弦函数和余弦函数。

    1. class _Exp(Unit):
    2.     def __new__(cls,base,exp):
    3.         if cls is _Exp:
    4.             raise TypeError("Cannot instantiate _Exp directly.")
    5.         return super().__new__(cls,base,exp)
    6.     def derivative(self, var):
    7.         a,u=self.units
    8.         der_u=u.derivative(var)
    9.         return (a**u)*log(_Constant(math.e),a)*der_u
    10.     def to_lambda(self,var):
    11.         a,u = self.units
    12.         f=u.to_lambda(var)
    13.         return lambda x: a.value**f(x)
    14. class _Log(Unit):
    15.     def __new__(cls,base,antilog):
    16.         if cls is _Log:
    17.             raise TypeError("Cannot instantiate _Log directly.")
    18.         return super().__new__(cls,base,antilog)
    19.     def derivative(self, var):
    20.         a,u=self.units
    21.         der_u=u.derivative(var)
    22.         return der_u/(u*log(_Constant(math.e),a))
    23.     def to_lambda(self,var):
    24.         a,u = self.units
    25.         f=u.to_lambda(var)
    26.         return lambda x: math.log(f(x),a.value)
    27. class _Sin(Unit):
    28.     def __new__(cls,radian):
    29.         if cls is _Sin:
    30.             raise TypeError("Cannot instantiate _Sin directly.")
    31.         return super().__new__(cls,radian)
    32.     def derivative(self, var):
    33.         u = self.units[0]
    34.         der_u=u.derivative(var)
    35.         return cos(u)*der_u
    36.     def to_lambda(self,var):
    37.         u = self.units[0]
    38.         f=u.to_lambda(var)
    39.         return lambda x: math.sin(f(x))
    40. class _Cos(Unit):
    41.     def __new__(cls,radian):
    42.         if cls is _Cos:
    43.             raise TypeError("Cannot instantiate _Cos directly.")
    44.         return super().__new__(cls,radian)
    45.     def derivative(self, var):
    46.         u = self.units[0]
    47.             der_u=u.derivative(var)
    48.         return -sin(u)*der_u
    49.     def to_lambda(self,var):
    50.         u = self.units[0]
    51.         f=u.to_lambda(var)
    52.         return lambda x: math.cos(f(x))
    复制代码


            derivative  方法:
                ●对于指数函数,使用链式法则。
                ●对于对数函数,使用对数求导公式。
                ●对于正弦和余弦函数,使用标准的三角函数求导公式。
            to_lambda  方法:
                ●依照数学函数的定义,返回相应的 Lambda 函数。

    三、函数定义:exp,log,sin,cos函数
            这些是用于构建特定数学函数的便捷函数

    1. def exp(base,exp):
    2.     if not isinstance(base,(int,float)):
    3.         raise ValueError("Not a standard exponential function")
    4.     if isinstance(exp,(int,float)):
    5.         return _Constant(base**exp)
    6.     return _Exp(_Constant(base),exp)
    7. def log(base,antilog):
    8.     if not isinstance(base,(int,float)):
    9.         raise ValueError("Not a standard logarithmic function")
    10.     if isinstance(antilog,(int,float)):
    11.         return _Constant(math.log(antilog,base))
    12.     if base<0:
    13.         raise ValueError("Undefined")
    14.     if base==1:
    15.         raise ValueError("Meaningless")
    16.     return _Log(_Constant(base),antilog)
    17. def sin(radian):
    18.     if isinstance(radian,(int,float)):
    19.         return _Constant(math.sin(radian))
    20.     return _Sin(radian)
    21. def cos(radian):
    22.     if isinstance(radian,(int,float)):
    23.         return _Constant(math.cos(radian))
    24.     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 。
    1. def derivative(expr,var):
    2.     return expr.derivative(var)
    3. def to_lambda(expr,var):
    4.     return expr.to_lambda(var)
    5. def Newton(x_0,expr,var,tol,max_time):
    6.     x_i=x_0
    7.     f=to_lambda(expr,var)
    8.     der_f=to_lambda(derivative(expr,var))
    9.     for _ in range(max_time):
    10.         x_i_1=x_i-f(x_i)/der_f(x_i)
    11.         if abs(x_i_1-x_i)<tol:
    12.             return x_i_1
    13.         x_i=x_i_1
    14.     return None
    复制代码


    五、示例代码:
        5.1 简单数学运算

    1. # 定义符号
    2. x = Symbol('x')

    3. # 定义表达式
    4. expr = x ** 2 + 5 * x + exp(2, x)

    5. # 生成lambda函数
    6. f = to_lambda(expr, x)

    7. # 输出函数值
    8. print(f(1))  # 输出:8
    复制代码

        5.2 求导函数

    1. # 定义符号
    2. x = Symbol('x')

    3. # 定义表达式
    4. expr = sin(x) * cos(x)

    5. # 求导
    6. deriv = derivative(expr, x)

    7. # 输出导数
    8. print(deriv)  # 输出:cos(x)**2 - sin(x)**2
    复制代码

        5.3 使用Newton方法求解方程

    1. # 定义符号
    2. x = Symbol('x')

    3. # 定义方程 f(x) = x^2 - 2
    4. expr = x**2 - _Constant(2)

    5. # 使用牛顿法求解
    6. root = Newton(1.0, expr, x, 1e-6, 100)

    7. # 输出结果
    8. print(root)  # 输出:1.414213562373095
    复制代码


    六、常见问题与解决方案

        问题 1:如何定义新的数学单位?
            用户可以通过继承  Unit  类创建新的数学单位,并实现必要的方法如  derivative  和  to_lambda 。
        问题 2:为什么我的运算结果不符合预期?
            确保符号和常量的使用方法正确,并检查导数的计算规则是否适用。
        问题 3:如何处理无法收敛的方程?
            在使用  Newton  方法时,可以增加  max_time  参数或调整初始猜测值来提高收敛性。

    评分

    参与人数 3血液 +12 追随 +2 堕落 +1 收起 理由
    yota + 1
    福黎 + 10 + 1 + 1 很给力!
    zhuovboyan + 2

    查看全部评分

      收起(2)
    回复

    使用道具 举报

    百相千面-戏艾吉奥岛田半藏诺克提斯·路西斯·伽拉姆萨菲罗斯岛田源氏BIG BOSS康纳/ConnorDoc普隆普特·阿金塔姆

      2302594 发表于 2025-1-31 07:42:51 | 显示全部楼层 <
      回复

      使用道具 举报

      黑暗消融瑞雪兆丰年,生灵万物新模擬人生4十字军护盾GM論壇進階勛章神奇四叶草啊!菊花开了!

        芋头先森 发表于 2025-1-28 15:09:20 | 显示全部楼层 <
        回复

        使用道具 举报

        千杯不醉捡到了肥皂弗雷迪玩偶发条八音盒You Can Pet Blaidd

          Sam30 发表于 2025-1-27 16:52:59 | 显示全部楼层 <
          回复

          使用道具 举报

          法卡斯瑞雪兆丰年,生灵万物新森林羊男生化危机:复仇驯化黑龙幼崽街头霸王龙腾世纪:审判【新手友好】昆進

            cjamno 发表于 2025-1-25 11:59:22 | 显示全部楼层 <
            额,在这里发Python合适吗,而且这个太基础了吧,感觉用c会更顺眼点
              收起(3)
            回复

            使用道具 举报

            愤怒的巴哈姆特步行鮟鱇金钱马车【圣诞限定】心心念念小雪人吃饱金币的Doge鎏彩万幢

              yota 发表于 2025-1-25 07:57:05 | 显示全部楼层 <
              回复

              使用道具 举报

              命运的轮廓检定场『狄文卡德的残羽』『厢庭望远』万众瞩目『搓粉团珠』神奇宝贝图鉴神奇宝贝大师球雪王的心脏肉垫手套

                zhuovboyan 发表于 2025-1-23 18:58:44 | 显示全部楼层 <
                回复

                使用道具 举报

                鎏彩万幢Zootopia都市:天际线2叶卡捷琳娜大帝传奇实现梦想官复原职丹雀衔五穗,人间始丰登丹妮莉丝·坦格利安刀锋女王 - 归宿

                  威风妖怪麒麟 发表于 2025-1-23 01:05:37 | 显示全部楼层 <
                  自己重载运算符的时候,感觉还是很容易出现边界或者特殊值的问题的
                    收起(4)
                  回复

                  使用道具 举报

                  永远的克叔Forever Titanic光之少女の魔法书双向圣杯:焕然意志天灾骑士阿努比斯信徒弗雷迪玩偶猫咪点唱机自定义男从Homunculus

                    PURO_ 发表于 2025-1-22 20:28:28 | 显示全部楼层 <
                    回复

                    使用道具 举报

                    猫咪点唱机吸血魔蝠弗雷迪玩偶传奇虚空之海的鲸呆猫苏醒的格罗姆守卫: 坚守眼位金钱马车月影狼

                      SweetUncle 发表于 2025-1-22 20:09:17 | 显示全部楼层 <
                      别卷了别卷了,你这是要拿ACM金奖吗
                      回复

                      使用道具 举报

                      弗雷迪玩偶发条八音盒桂花米糕鎏彩万幢女巫之路虚空之海的鲸【新春限定】果体 隆『召唤好运的角笛』永远的克叔業火死鬥

                        娱乐法师火布偶 发表于 2025-1-22 19:24:21 | 显示全部楼层 <
                        本质上应该还是C++里面的重载,不过python可能写起来更简单
                        回复

                        使用道具 举报

                        『冰雕马拉橇』夜魔护符竹取物语苏格兰圆脸胖鸡[Pro Max]仇恋BIG BOSS不朽之恋卡利亚权杖虚空之海的鲸男巫之歌

                          phillipé 发表于 2025-1-22 19:07:14 | 显示全部楼层 <
                          回复

                          使用道具 举报

                          您需要登录后才可以回帖 登录 | 立即注册

                          本版积分规则

                          关闭

                          站长公告上一条 /1 下一条

                          文字版|手机版|小黑屋|GameMale

                          GMT+8, 2025-12-7 19:44 , Processed in 0.119918 second(s), 101 queries , Redis On.

                          Copyright © 2013-2025 GameMale

                          All Rights Reserved.

                          快速回复 返回列表