线性代数Python计算:自定义代数系统

本文介绍了如何使用Python定义一个多项式类myPoly,通过类定义和重载运算符函数,实现线性空间的加法和数乘。实例演示了多项式对象的创建、相等判断和表达式输出。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述
Python是一个面向对象的程序设计语言,可以用类的定义方式来自定义代数系统:定义类中对象(集合元素)所具有的属性以及对象间的运算。Python为顶层抽象类保留了对应各种运算符的虚方法,我们只需在类的定义中重载所需运算符函数即可。设 n ∈ n\in nℕ,数域 P P P上所有次数小于 n n n的一元多项式记为 P [ x ] n P[x]_n P[x]n(参见博文《Python的布尔代数》),不难证明 ( P [ x ] n , + , ⋅ ) (P[x]_n,+,\cdot) (P[x]n,+,)构成一个线性空间。我们来实现这个代数系统。
首先,定义多项式类myPoly:

import numpy as np                      #导入numpy
class myPoly:                           #多项式类
    def __init__(self, coef):           #初始化函数
        c=np.trim_zeros(coef,trim='b')  #删除高次零系数
        self.coef=np.array(c)           #设置多项式系数
        self.degree=(self.coef).size-1  #设置多项式次数
    def __eq__(self, other):            #相等运算符函数
        if self.degree!=other.degree:   #次数不等
            return False
        return (abs(self.coef-other.coef)<1e-10).all()
    def __str__(self):                  #生成表达式串供输出
        return exp(self.coef)        
        return s        

Python自定义类的语法格式为

class 类名:
    类定义体

类定义体内定义所属的各函数。上列程序中,第2~13行所定义的多项式类名为“myPoly”。类定义体中罗列了3个函数:第3~6行重载的初始化函数init、第7~10行重载的相等关系运算符函数eq和第11~13行定义的供输出表达式串的函数str。
Python类中的函数分成类函数和对象函数两种。类函数从属于类,其调用格式为\
类名.函数名(实际参数表) \text{类名.函数名(实际参数表)} 类名.函数名(实际参数表)
对象函数从属于类的对象,其调用格式为
对象.函数名(实际参数表) \text{对象.函数名(实际参数表)} 对象.函数名(实际参数表)
myPoly类中罗列的三个函数都是对象函数,其定义特征为函数的形式参数表均含表示对象的self。换句话说,类函数的形式参数表中不含参数self。
Pyhon的顶层抽象类中已经定义了部分虚函数,如几乎每个类都必需的初始化函数init,以及各种常用的运算符函数,重载这些函数时的特征是函数名的首、尾各有两个下划线,如上列程序中重载的__init__、__eq__和__str__函数,程序员要做的是按需实现这些函数。普通函数的定义中函数名前后无需如此修饰。
根据多项式的定义可知 f ( x ) = a 0 + a 1 x + ⋯ + a n x n f(x)=a_0+a_1x+\cdots+a_nx^n f(x)=a0+a1x++anxn由其次数 n n n n + 1 n+1 n+1个系数构成的序列 a 0 , a 1 , ⋯   , a n a_0,a_1,\cdots,a_n a0,a1,,an所确定,文字是取符号 x x x还是别的符号无关紧要。Python中表示序列的数据类型有list,还可以使用numpy包中的数组array类。无论是list还是array对象,它们的下标与我们所定义的多项式的系数序列下标一致,也是从 0 0 0开始的。numpy是快速处理数组的工具包,为使用其中的工具模块需事先导入numpy包,这就是程序的第1行的任务。
第3~{}6行重载的init函数中,除表示创建的多项式对象参数self之外还有一个表示多项式系数序列的数组参数coef,该参数既可以是Python的list型对象也可以是numpy的array类对象。第4行调用numpy的trim_zeros函数,消除参数coef的尾部可能包含的若干个0。注意传递给命名参数trim的值为’b’表示操作是针对序列coef的尾部的。第5行用参数coef的数据创建对象自身的array型属性coef。第6行用系数序列的长度-1初始化对象的次数属性degree。需要注意的是,当参数coef传递进来的是元素均为0的数组时,即系数均为0的零多项式时,第4行操作的结果c成为一个空(没有元素)的数组,第6行的操作使得多项式该对象的次数degree为-1。与我们在博文《Python的布尔代数》约定保持一致。
第7~10行重载的是表示两个多项式是否相等的关系运算符“==”的eq函数。该函数有两个参数:表示多项式对象自身的self和另一个多项式other。其返回值是一个布尔型数据:True或False,表示self和other是否相等。第8~9行的{\bf{if}}语句检验两个多项式的次数是否不等,若不等则返回False。第10行针对两个次数相同的多项式判断是否相等。我们知道self和other均具有numpy的array类属性对象coef,表达式self.coef-other.coef表示两个等长数组按对应元素相减得到数组,即 a 0 − b 0 , a 1 − b 1 , ⋯   , a n − b n a_0-b_0,a_1-b_1,\cdots,a_n-b_n a0b0,a1b1,,anbn。abs(self.coef-other.coef)则表示数组 ∣ a 0 − b 0 ∣ , ∣ a 1 − b 1 ∣ , ⋯   , ∣ a n − b n ∣ |a_0-b_0|,|a_1-b_1|,\cdots,|a_n-b_n| a0b0,a1b1,,anbn,而abs(self.coef-other.coef)<1e-10则表示数组
∣ a 0 − b 0 ∣ < 1 0 − 10 , ∣ a 1 − b 1 ∣ < 1 0 − 10 , ⋯   , ∣ a n − b n ∣ < 1 0 − 10 |a_0-b_0|<10^{-10},|a_1-b_1|<10^{-10},\cdots,|a_n-b_n|<10^{-10} a0b0<1010,a1b1<1010,,anbn<1010
其中的每一项都是布尔型数据:非True即False。(abs(self.coef-other.coef)<1e-10).all()则表示上述数组中的所有项是否都是True。这正是判断两个等长的浮点型数组是否安对应元素相等,若返回True,则意味着以 1 1 0 10 \frac{1}{10^{10}} 10101的精确度,断定两个等次多项式相等,否则认为两个多项式不等。
第11~13行重载的对象函数str的功能是利用对象自身的coef数组数据生成多项式的表达式串供输出时使用:调用print函数输出myPoly对象时自动在后台调用此函数。该函数只有一个表示多项式对象自身的参数self,函数体中简单调用我们在博文《Python的布尔代数》中定义的exp函数即可。用下列代码测试myPoly类。

import numpy as np                  #导入numpy
from fractions import Fraction as F #导入Fraction
p=myPoly(np.array([1,-2,1]))        #用numpy的array类对象创建多项式p
q=myPoly([F(0),F(-1,2),F(0),F(1,3)])#用Python的list对象创建多项式q
r=myPoly([0.0,-0.5,0.0,1/3])        #用list对象创建多项式r
print(p)                            #输出p的表达式
print(q)                            #输出q的表达式
print(r)                            #输出r的表达式
print(p==q)                         #检测p与q是否相等
print(p==q)                         #检测q与r是否相等

程序的第2行用整型数据构成的array类对象array([-1, -2, 1])作为系数序列创建myPoly类对象p。注意,形式上似乎在调用一个与myPoly类同名的函数,实际上是调用myPoly的init函数在创建多项式对象。第3行用list类对象[F(0),F(-1,2),F(0),F(1,3)]创建分数型系数的多项式q。第4行用list对象[0.0,-0.5,0.0,1/3]创建浮点型系数的多项式r。第6~8行分别输出各自的表达式串,检测重载的init函数和str函数。第9、10两行检测p与q是否相等,q与r是否相等,即检测重载的eq函数。运行程序,输出

1-2・x+1・x**2
-1/2・x+1/3・x**3
-0.5・x+0.3333333333333333・x**3
False
True

接下来,我们在myPoly类中重载多项式的线性运算:加法和数乘。

import numpy as np                                      #导入numpy
class myPoly:                                           #多项式类
    ……
    def __add__(self, other):                           #运算符“+”
        n=max(self.degree,other.degree)+1               #系数个数
        a=np.append(self.coef,[0]*(n-self.coef.size))   #补长
        b=np.append(other.coef,[0]*(n-other.coef.size)) #补长
        return myPoly(a+b)                              #创建并返回多项式和
    def __rmul__(self, k):                              #右乘数k
        c=self.coef*k                                   #各系数与k的积
        return myPoly(c)

程序第3行中的省略号表示第1个程序中已定义的对象函数。第4~9行按多项式加法定义重载运算符“+”的函数add。该函数的两个参数self表示多项式对象本身,other表示参加运算的另一个多项式对象。第5行调用系统函数max计算self及othen次数的最大者+1赋予n。第6、7两行调用numpy的append函数利用n将两个多项式的系数序列a和b调整为相同长度。注意,append函数是将传递给它的两个参数首尾相接。第8行用a与b按元素求和得到的序列创建myPoly对象返回。
我们已经看到重载的相等运算符“==”实际上是函数eq,它是自身对象self的函数。表达式p==q实际上是调用p的eq函数,p扮演了第一个参数self。q是传递给eq的other参数。此处重载的加法运算符“+”的参数意义也是如此。然而,数乘法就不能简单地重载乘法运算符“∗”函数mul。因为参加运算的一个是多项式(参数self),另一个是数k。换句话说,self参数表示的是多项式p,调用时就应写成p∗k,这不符合大多数人的习惯。因此,上列程序的第9~11行重载的是“右乘”运算符“∗”函数rmul,调用时多项式可写在运算符的右边:k∗p。该函数的第一个参数self表示多项式对象作为右运算数,第二个参数表示左运算数k。第10行用k按元素乘self的系数序列coef赋予c,第11行用c创建结果多项式并返回。
下列代码测试多项式的线性运算。

import numpy as np                  #导入numpy
from fractions import Fraction as F #导入Fraction
p=myPoly(np.array([1,-2,1]))        #用numpy的array类对象创建多项式p
q=myPoly([F(0),F(-1,2),F(0),F(1,3)])#用Python的list对象创建多项式q
k=1.5
print(p+q)
print(k*q)

运行程序,输出

1-5/2・x+1・x**2+1/3・x**3
-0.75・x+0.5・x**3

写博不易,敬请支持:
如果阅读本文于您有所获,敬请点赞、评论、收藏,谢谢大家的支持!
代码诚可贵,原理价更高。若为AI学,读正版书好

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值