数学家函数编程¶
本教程讨论了一些函数编程技术,这些技术可能会引起数学家或使用Python进行科学计算的人的兴趣。我们从过程式和面向对象编程的简要概述开始,然后讨论函数式编程技术。在此过程中,我们简要回顾Python对函数式编程的内置支持,包括 filter , lambda , map 和 reduce . 本教程最后提供了一些有关使用Python进行函数式编程的详细信息的参考资料。
编程风格¶
Python支持多种编程风格。您可以通过编写一个作为指令列表的程序样式来编程。假设您要对整数实现加法和乘法。这样做的程序程序如下:
sage: def add_ZZ(a, b):
....: return a + b
...
sage: def mult_ZZ(a, b):
....: return a * b
...
sage: add_ZZ(2, 3)
5
sage: mult_ZZ(2, 3)
6
Python模块 operator 将几个常用的算术和比较运算符定义为命名函数。加法在内置函数中定义 operator.add
乘法的定义见 operator.mul
. 上面的例子可以按如下方式进行:
sage: from operator import add
sage: from operator import mul
sage: add(2, 3)
5
sage: mul(2, 3)
6
另一种常见的编程风格称为面向对象编程。把一个对象看作是同时封装数据和功能的代码。您可以将整数加法和乘法封装为以下面向对象的实现:
sage: class MyInteger:
....: def __init__(self):
....: self.cardinality = "infinite"
....: def add(self, a, b):
....: return a + b
....: def mult(self, a, b):
....: return a * b
...
sage: myZZ = MyInteger()
sage: myZZ.cardinality
'infinite'
sage: myZZ.add(2, 3)
5
sage: myZZ.mult(2, 3)
6
基于map的函数式程序设计¶
函数式编程是另一种编程风格,其中程序被分解成各种函数。Python内置函数 map
, reduce
和 filter
允许您使用函数式编程。请注意,在Python3中(与Python2相比),这些函数具有不同的行为,并且 reduce
已删除:如果要使用 reduce
在python3中,必须从 functools
.
功能:
map(func, seq1, seq2, ...)
接受一个函数 func
以及一个或多个序列,并应用 func
这些序列的元素。特别是,你会得到这样一个清单:
[func(seq1[0], seq2[0], ...), func(seq1[1], seq2[1], ...), ...]
在许多情况下,使用 map
允许您以简洁的方式表达程序的逻辑,而无需使用列表理解。例如,假设您有两个整数列表,并希望按元素方式将它们相加。实现这一点的清单理解如下:
sage: A = [1, 2, 3, 4]
sage: B = [2, 3, 5, 7]
sage: [A[i] + B[i] for i in range(len(A))]
[3, 5, 8, 11]
或者,可以使用Python内置的加法函数 operator.add
与 map
为了达到同样的效果:
sage: from operator import add
sage: A = [1, 2, 3, 4]
sage: B = [2, 3, 5, 7]
sage: list(map(add, A, B))
[3, 5, 8, 11]
优点 map
就是不需要像在上面的列表理解中那样显式地定义for循环。
使用lambda定义小函数¶
有时您需要编写一个简短的、一行程序函数。您可以重新编写上述加法函数,如下所示:
sage: def add_ZZ(a, b): return a + b
...
或者你可以用 lambda
声明以更清晰的方式做同样的事情。上面的加法和乘法函数可以用 lambda
如下:
sage: add_ZZ = lambda a, b: a + b
sage: mult_ZZ = lambda a, b: a * b
sage: add_ZZ(2, 3)
5
sage: mult_ZZ(2, 3)
6
一旦你结合在一起,事情就变得更有趣了 map
与 lambda
声明。作为练习,您可以尝试编写一个简单的函数来实现 Chinese Remainder Theorem . 你可以把列表理解和 map
和 lambda
如下所示。这里,参数 A
是整数和 M
是一个模块列表。:
sage: def crt(A, M):
....: Mprod = prod(M)
....: Mdiv = list(map(lambda x: Integer(Mprod / x), M))
....: X = list(map(inverse_mod, Mdiv, M))
....: x = sum([A[i]*X[i]*Mdiv[i] for i in range(len(A))])
....: return mod(x, Mprod).lift()
...
sage: A = [2, 3, 1]
sage: M = [3, 4, 5]
sage: x = crt(A, M); x
11
sage: mod(x, 3)
2
sage: mod(x, 4)
3
sage: mod(x, 5)
1
在环上产生随机矩阵,例如 ZZ ,可以从定义矩阵空间开始,然后获得该矩阵空间的随机元素:
sage: MS = MatrixSpace(ZZ, nrows=5, ncols=3)
sage: MS.random_element() # random
<BLANKLINE>
[ 6 1 0]
[-1 5 0]
[-1 0 0]
[-5 0 1]
[ 1 -1 -3]
或者你可以用这个函数 random_matrix
::
sage: random_matrix(ZZ, nrows=5, ncols=3) # random
<BLANKLINE>
[ 2 -50 0]
[ -1 0 -6]
[ -4 -1 -1]
[ 1 1 3]
[ 2 -1 -1]
下一个示例使用 map
要构造随机整数矩阵的列表:
sage: rows = [randint(1, 10) for i in range(10)]
sage: cols = [randint(1, 10) for i in range(10)]
sage: rings = [ZZ]*10
sage: M = list(map(random_matrix, rings, rows, cols))
sage: M[0] # random
<BLANKLINE>
[ -1 -3 -1 -37 1 -1 -4 5]
[ 2 1 1 5 2 1 -2 1]
[ -1 0 -4 0 -2 1 -2 1]
如果您希望对矩阵的条目有比 random_matrix
功能允许,你可以使用 lambda
与 map
如下:
sage: rand_row = lambda n: [randint(1, 10) for i in range(n)]
sage: rand_mat = lambda nrows, ncols: [rand_row(ncols) for i in range(nrows)]
sage: matrix(rand_mat(5, 3)) # random
<BLANKLINE>
[ 2 9 10]
[ 8 8 9]
[ 6 7 6]
[ 9 2 10]
[ 2 6 2]
sage: rows = [randint(1, 10) for i in range(10)]
sage: cols = [randint(1, 10) for i in range(10)]
sage: M = list(map(rand_mat, rows, cols))
sage: M = list(map(matrix, M))
sage: M[0] # random
<BLANKLINE>
[ 9 1 5 2 10 10 1]
[ 3 4 3 7 4 3 7]
[ 4 8 7 6 4 2 10]
[ 1 6 3 3 6 2 1]
[ 5 5 2 6 4 3 4]
[ 6 6 2 9 4 5 1]
[10 2 5 5 7 10 4]
[ 2 7 3 5 10 8 1]
[ 1 5 1 7 8 8 6]
将序列还原为值¶
函数 reduce
接受一个包含两个参数的函数,并将其应用于给定序列,以将该序列缩减为单个值。功能 sum 是一个 reduce
功能。下面的示例代码使用 reduce
以及内置功能 operator.add
将给定列表中的所有整数相加。然后使用 sum
为了完成同样的任务:
sage: from functools import reduce # py3
sage: from operator import add
sage: L = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
sage: reduce(add, L)
55
sage: sum(L)
55
在下面的示例代码中,我们将向量视为实数的列表。这个 dot product 然后使用函数实现 operator.add
和 operator.mul
,以及内置的Python函数 reduce
和 map
. 然后我们展示如何 sum
和 map
可以组合起来产生同样的结果。:
sage: from functools import reduce # py3
sage: from operator import add
sage: from operator import mul
sage: U = [1, 2, 3]
sage: V = [2, 3, 5]
sage: reduce(add, map(mul, U, V))
23
sage: sum(map(mul, U, V))
23
或者你可以使用Sage对dot产品的内置支持:
sage: u = vector([1, 2, 3])
sage: v = vector([2, 3, 5])
sage: u.dot_product(v)
23
这是一个不使用 sum
如前所述。以下版本使用 operator.add
并定义 mul3
乘以三个数而不是两个数。:
sage: from functools import reduce # py3
sage: def crt(A, M):
....: from operator import add
....: Mprod = prod(M)
....: Mdiv = list(map(lambda x: Integer(Mprod / x), M))
....: X = map(inverse_mod, Mdiv, M)
....: mul3 = lambda a, b, c: a * b * c
....: x = reduce(add, map(mul3, A, X, Mdiv))
....: return mod(x, Mprod).lift()
...
sage: A = [2, 3, 1]
sage: M = [3, 4, 5]
sage: x = crt(A, M); x
11
用过滤器过滤¶
Python内置函数 filter
接受一个参数和一个序列的函数。然后它返回给定序列中所有这些项的列表,这样新列表中的任何项都会导致给定函数返回 True
. 从某种意义上说,您过滤掉了满足给定函数中定义的某些条件的所有项。例如,您可以使用 filter
过滤掉1到50之间的所有素数。:
sage: list(filter(is_prime, [1..50]))
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
对于给定的正整数 n, the Euler phi function 计算整数的数目 a 用 1 leq a leq n ,这样 gcd(a, n) = 1 . 你可以使用列表理解来获得所有这些 a 什么时候 n = 20 ::
sage: [k for k in range(1, 21) if gcd(k, 20) == 1]
[1, 3, 7, 9, 11, 13, 17, 19]
功能方法是使用 lambda
定义一个函数来确定给定的整数是否是20的相对素数。那你就可以利用 filter
而不是列表理解来获得所有需要的 a s.::
sage: is_coprime = lambda k: gcd(k, 20) == 1
sage: list(filter(is_coprime, range(1, 21)))
[1, 3, 7, 9, 11, 13, 17, 19]
函数 primroots
下面定义的返回给定正素数整数模的所有原根 p . 它使用 filter
获取 1 和 p - 1 ,包括在内,列表中的每个整数相对于乘法组的顺序都是相对素数 (ZZ/pZZ)^{{ast}} . ::
sage: def primroots(p):
....: g = primitive_root(p)
....: znorder = p - 1
....: is_coprime = lambda x: gcd(x, znorder) == 1
....: good_odd_integers = filter(is_coprime, [1..p-1, step=2])
....: all_primroots = [power_mod(g, k, p) for k in good_odd_integers]
....: all_primroots.sort()
....: return all_primroots
...
sage: primroots(3)
[2]
sage: primroots(5)
[2, 3]
sage: primroots(7)
[3, 5]
sage: primroots(11)
[2, 6, 7, 8]
sage: primroots(13)
[2, 6, 7, 11]
sage: primroots(17)
[3, 5, 6, 7, 10, 11, 12, 14]
sage: primroots(23)
[5, 7, 10, 11, 14, 15, 17, 19, 20, 21]
sage: primroots(29)
[2, 3, 8, 10, 11, 14, 15, 18, 19, 21, 26, 27]
sage: primroots(31)
[3, 11, 12, 13, 17, 21, 22, 24]
更多资源¶
这是一个关于使用Python进行函数式编程的简短教程。Python标准文档有一个内置函数的列表,其中许多函数在函数编程中很有用。例如,您可能需要阅读 all , any , max , min 和 zip . Python模块 operator 有许多内置的算术和比较运算符,每个运算符都被实现为一个函数,其名称反映了其预期用途。对于算术和比较操作,建议您参考 operator
模块来确定是否有满足您需求的内置函数。模块 itertools 有许多内置函数,以有效地处理项目序列。
Python中函数式编程的另一个有用资源是 Functional Programming HOWTO 作者:A.M.Kuchling。史蒂芬·洛特的书 Building Skills in Python 有一章 Functional Programming using Collections . 另见本章 Functional Programming 从马克·皮尔格林的书中 Dive Into Python .
你也可以考虑尝试 Haskell 用来表达数学概念。关于Haskell表达数学算法的例子,请参阅J.Gibbons的文章 Unbounded Spigot Algorithms for the Digits of Pi 在美国数学月刊上。