原始递归函数

可计算性理论中,原始递归函数(英语:primitive recursive functions)对计算的完全的形式化而言是形成重要构造板块的一类函数。它们使用递归复合作为中心运算来定义,并且是递归函数的严格的子集,它们完全是可计算函数。通过补充允许偏函数和介入无界查找运算可以定义出递归函数的更广泛的类。

通常在数论中研究的很多函数,近似于实数值函数,比如加法除法阶乘指数,找到第 n 个素数等等是原始递归的(Brainerd and Landweber, 1974)。实际上,很难设计不是原始递归的函数,尽管某些函数是已知的(比如阿克曼函数)。所以,通过研究它们,我们能发现有广泛影响的结论的那些性质。

原始递归函数可以用总是停机的图灵机计算,而递归函数需要图灵完全系统。

原始递归函数的集合在计算复杂性理论中叫做PR

目录

[隐藏]

定义

原始递归函数接受自然数或自然数的元组作为参数并生成自然数。接受 n 个参数的函数叫做 n-函数。基本原始递归函数用如下公理给出:

  1. 常数函数: 0 元常数函数 0 是原始递归的。
  2. 后继函数: 1 元后继函数 S,它接受一个参数并返回皮亚诺公理给出的后继数,是原始递归的。
  3. 投影函数: 对于所有 n≥1 和每个 1≤in 的 in 元投影函数 Pin,它接受 n 个参数并返回它们中的第 i 个参数,是原始递归的。

更加复杂的递归函数可以通过应用下列公理给出的运算来获得:

  1. 复合: 给定k 元原始递归函数 f,和 k 个 m 元原始递归函数 g1,...,gkf 和 g1,...,gk 的复合,也就是 m 元函数 h(x1,...,xm) = f(g1(x1,...,xm),...,gk(x1,...,xm)), 是原始递归的。
  2. 原始递归: 给定 k 元原始递归函数 f,和 k+2 元原始递归函数 g,定义为 f 和 g 的原始递归的 k+1 元函数,也就是函数 h 这里的 h(0,x1,...,xk) = f(x1,...,xk) 并且h(S(n),x1,...,xk) = g(h(n,x1,...,xk),n,x1,...,xk), 是原始递归的。

服从这些公理的函数是原始递归的,如果它是上述基本函数之一,或者它可以通过应用有限次数的运算获得自基本函数。

投影函数的作用

投影函数可用来避免采用上述明显刻板的函数元数方式;通过使用各种投影函数的复合,有可能把一个函数的参数子集传递到另一个函数。例如,如果 g 和 h 是二元原始递归函数,则

{\displaystyle f(a,b,c)=g(h(a,c),h(a,b))\!}

也是原始递归的。使用投影函数的一个形式定义为

{\displaystyle f(a,b,c)=g(h(P_{1}^{3}(a,b,c),P_{3}^{3}(a,b,c)),h(P_{1}^{3}(a,b,c),P_{2}^{3}(a,b,c)))}.

转换谓词到数值函数

在某些设置中,自然的考虑接受混合了数值和真值{ t= true, f=false } 的参数,或生成真值作为输出的原始递归函数(参见 Kleene [1952 pp.226-227])。这可以通过把真值识别为任何固定方式的数值来完成。例如,通常把真值t 识别为 1 和真值 f 识别为 0。一旦作出这种识别,集合 A 的特征函数,它在文字上返回 1 或 0,可以被看作判定一个数是否在集合 A 中的谓词。把谓词识别为数值函数的这种方式将假定于本文余下部分。

例子

加法

直觉上我们会把加法递归的定义为:

add(0,x)=x
add(n+1,x)=add(n,x)+1

为了使它适合于严格的原始递归定义,我们定义:

add(0,x)=P11(x)
add(S(n),x)=S(P13(add(n,x),n,x))

(注意: 这里的 P13 是一个函数,它接受 3 个参数并返回第一个。)

P11 是简单的恒等函数;包含它是上述原始递归运算定义的要求;它扮演了 f 的角色。S 和 P13 的复合,它是原始递归的,它扮演了 g 的角色。

减法

我们可以定义有限减法,就是说,截止到 0 的减法(因为我们还没有负数的概念呢)。首先我们必须定义"前驱" 函数,它担任后继函数的对立物。

直觉上我们会把前驱定义为:

pred(0)=0
pred(n+1)=n

为了使它适合正式的原始递归定义,我们写:

pred(0)=0
pred(S(n))=P22(pred(n),n)

现在我们以类似加法的方式定义减法。

sub(0,x)=P11(x)
sub(S(n),x)=pred(P13(sub(n,x),n,x))

出于简单的缘故,切换了"标准"定义的参数次序来适合原始递归的要求,就是说, sub(a,b) 对应于 b-a。这可以轻易的使用适当的投影来矫正。

很多类似的函数可以被证明是原始递归的;一些例子包括条件指数素数检验数学归纳法,并且原始递归函数可以被扩展来运算在其他对象上比如整数和有理数。

在整数和有理数上的运算

通过使用哥德尔数,原始递归函数可以被扩展到在其他对象比如整数和有理数上的运算上。如果以标准方式编码整数用哥德尔数,算术运算包括加法、减法、乘法都是原始递归的。类似的,如果以哥德尔数表示有理数,则运算都是原始递归的。

与递归函数的联系

通过介入无界查找算子可定义更广泛的偏递归函数类。这个算子的使用可以导致偏函数,就是说,对每个参数有最多一个值,但是不同于全函数,不必须对参数有值的关系(参见定义域)。一个等价的定义声称偏递归函数是可以被图灵机就算的函数。全递归函数是对所有输入有定义的偏递归函数。

所有原始递归函数都是全递归的,但不是所有全递归函数都是原始递归的。阿克曼函数 A(m,n)是周知的不是原始递归的全递归函数。原始递归函数有作为使用阿克曼函数的全递归函数的子集的一个特征。这个特征声称一个函数是原始递归的,当且仅当有一个自然数 m 使得这个函数可以被总在 A(m,n) 或更少步骤内停机的图灵机计算,这里的 n 是原始递归函数的参数的总数。

限制

原始递归函数意图紧密对应于我们直觉上可计算函数应该的样子。当然函数的初始集合在直觉上是可计算的(因为它们非常简单),而你能用来建立新原始递归函数的两个运算也是非常直接的。但是原始递归函数的集合不包含所有可能的可计算函数 — 这可以看作康拖尔对角论证法的变体。这个论证提供了一个不是原始递归的可计算函数。证明的梗概如下:

原始递归函数集合可以被计算枚举。这个编号方案在函数定义上是唯一的,尽管在实际函数自身上不是唯一的(因为所有的函数都可以有无限数目的定义 — 考虑简单的由恒等函数构成)。这个编码在可计算性的形式模型,比如递归函数图灵机下定义的意义上是可计算的,邱奇-图灵论题涉及的任何机器都可以。

现在考虑一个矩阵,这里的行是在这个编号方案下的有一个参数的原始递归函数,而列是自然数。则每个元素 (ij) 对应于计算于数 j 之上的第 i 个一元原始递归函数。我们可以写为 fi(j)。

现在我们考虑函数 g(x) = S(fx(x))。g 位于这个矩阵的对角线上,并简单的对它找到的值加一。这个函数是可计算的(按上述定义),但是明显的没有计算它的原始递归函数存在,因为它与每个可能的原始递归函数都有至少一个值不同。所以,必然存在不是原始递归的可计算函数。

这个论证可以应用于能用这种方式枚举的任何一类的可计算(全)函数上。所以,任何这种可计算(全)函数的明确列表都不可能是完全的,比如那些可以用总是停机的机器计算的函数。但是要注意,可计算函数集合(那些不需要对所有参数有定义的函数)可以被明确的枚举,例如通过枚举图灵机编码。

可以明确展示的一个简单的 1-元可计算函数阿克曼函数,它是对任何自然数递归定义的,但不是原始递归的。

参考

  • Brainerd, W.S., Landweber, L.H. (1974), Theory of Computation, Wiley, ISBN 0471095850

参见

引用

  • Brainerd, W.S., Landweber, L.H. (1974), Theory of Computation, Wiley, ISBN 0-471-09585-0
  • Robert I. Soare, Recursively Enumerable Sets and Degrees, Springer-Verlag, 1987. ISBN 0-387-15299-7
  • Stephen Kleene (1952) Introduction to Metamathematics, North-Holland Publishing Company, New York, 11th reprint 1971: (2nd edition notes added on 6th reprint). In Chapter XI. General Recursive Functions §57
  • George BoolosJohn BurgessRichard Jeffrey (2002), Computability and Logic: Fourth Edition, Cambridge University Press, Cambridge, UK. Cf pp. 70-71.

分类

时间: 2024-08-03 11:53:57

原始递归函数的相关文章

Atitit.软件硕士  博士课程 一览表 attilax 总结

Atitit.软件硕士  博士课程 一览表 attilax 总结 1. Attilax聚焦的领域1 2. 研究生硕士博士课程汇总表1 3. 博士课程3 4. Attilax额外的4 5. 参考4 1. Attilax聚焦的领域 Dsl 语言 ide 类库 框架 数据库 的实现 Debug工具 文本信息的解锁,无损压缩(pdf ,word2html) 图片物体检测与色情图片识别,人脸识别 信息采集,比较,同步工具,信息发布工具 输入法,词库维护工具  翻译机 垃圾文件识别与清理器 快速启动器(at

哥德尔不完备定理

自从牛顿用物理的直觉,闯进无穷领域里大胆计算,铸造出犀利无比的分析工具后,许多人凭借着直观想象和聪明,也涌进去推导出许多互相冲突的结论,数学家花了两百多年的时间,才厘清了分析领域里的混乱,将整个数学建立在严格逻辑,而不是直观想象的基础上. 欧几里德几何一直是科学理论的范本,四条自明性的公理加上一条平行公设,通过逻辑演绎,推导出平面几何无穷数量的定理,一直到了近代还只有几何,被认为是具有坚实基础的数学分支,在这光辉的榜样下,人们尝试用这公理化的方法来规范整个数学,人们后来发现欧几里德也不够严谨,逻

14、蛤蟆的数据结构笔记之十四栈的应用之栈与递归之阿克曼函数

14.蛤蟆的数据结构笔记之十四栈的应用之栈与递归之阿克曼函数 本篇名言:"今天就是生命 ----- 是唯一你能确知的生命." 继续递归应用,阿克曼函数. 欢迎转载,转载请标明出处: 1.  阿克曼函数 阿克曼函数(Ackermann)是非原始递归函数的例子.它需要两个自然数作为输入值,输出一个自然数.它的输出值增长速度非常高,仅是对于(4,3)的输出已大得不能准确计算. Ackermann函数定义如下: 若m=0,返回n+1. 若m>0且n=0,返回Ackermann(m-1,1

计算机导论语言与算法之程序与递归:组合-抽象-重复-构造

1.抽象计算对象与函数的定义与构造方法,程序是组合抽象构造出来的. 2.程序:由基本动作指令构造的,若干指令的一个组合或一个执行序列,用以实现复杂动作.程序执行机构节省了开发时底层的操作. 3.计算机系统的抽象过程.组合与构造层次.程序是构造出来的,而组合.抽象是构造程序的基本手段. 4.抽象与构造:命名计算对象.构造中使用名字.计算中以计算对象替换名字. 5.递归的定义:自身调用自身,高阶调用低阶,构造无限的计算步骤.由后向前带入,再由前向后计算. 6.原始递归函数

从"汉诺塔"经典递归到JS递归函数

前言 参考<JavaScript语言精粹> 递归是一种强大的编程技术,他把一个问题分解为一组相似的子问题,每一问题都用一个寻常解去解决.递归函数就是会直接或者间接调用自身的一种函数,一般来说,一个递归函数调用自身去解决它的子问题. "汉诺塔"经典递归问题 "汉诺塔"是印度的一个古老传说,也是程序设计中的经典的递归问题,是一个著名的益智游戏: 题目如下: 塔上有三根柱子和一套直径各不相同的空心圆盘,开始时源柱子上的所有圆盘都按从大到小的顺序排列.目标是通过

php rmdir使用递归函数删除非空目录的方法

php rmdir()函数 rmdir ― 删除空目录 语法: bool rmdir ( string $dirname [, resource $context ] )尝试删除 dirname 所指定的目录. 该目录必须是空的,而且要有相应的权限. 失败时会产生一个E_WARNING级别的错误.参数:1.dirname:目录的路径. 2.context:在 PHP 5.0.0 中增加了对上下文(Context)的支持. php rmdir()删除非空目录 上面已经说过,rmdir()函数只能删

JavaScript中的递归函数问题

学过其他编程语言的都应该会知道递归这个问题,递归函数是在一个函数通过名字调用自身的情况下后构成的. function fac(num){ if(num<=1){ return 1; }else{ return num*fac(num-1); } } 这是一个比较经典的阶乘算法,这个写法就实现我们所说的递归.这个代码看起来是没有什么问题, 在c或者其他编程语言都有这样的描述,但是在JavaScript中有时就会出错.就比如: <span style="white-space:pre&q

javascript中的原始值和复杂值

前面的话 javascript的数据类型可以分为两种:原始类型(基本类型或者简单类型)和引用类型. 原始类型:Undefined,Null,Boolean,Number,String五种: 引用类型:Object,Array,Function: 与此相对应的,它们的值分别被称为原始值和复杂值. 特性 原始值 原始值是表示javascript中可用的数据或信息的最底层的形式或者最简单的形式.原始类型的值被称为原始值,因为它们的值是不可被细化的.也就是说,数字是数字,字符串是字符串,布尔值是true

关于递归函数的简单认识

关于递归函数的认识是在学习了数据结构的栈这一概念后有新的理解. 首先说一下递归函数的概念,我的理解就是一个自己调用自己本身的函数.既然是调用函数,那先看一下普通的函数调用问题. 一.普通函数调用问题 用主函数main()调用函数sum()函数来作比: void main(){ //其他语句1 sum(); //其他语句2 } 整个程序运行的入口是main(),当main()函数运行完“其他语句1”遇到sum();语句时,main做的工作就是: 1.保存现场(保存现场这一操作就用到了前面提到的栈)