近期在学习计算理论,C#还是入门,利用它来实现计算理论的Post-Turing程序的运行,作为练习。
有关概念:
[Post-Turing程序]
数据:一条带,两端无穷,数据只有1和空(B表示);
指令集只有六条:
(1)RIGHT (指令代码为1)
(2)LEFT (2)
(3)WRITE 1 (3)
(4)WRITE B (4)
(5)TO Ai IF 1 (指令代码2i+4)
(6)TO Ai IF B (指令代码2i+3)
数的表示:比如3在带上表示为 1111B
[Godel数(歌德尔数)]
歌德尔数[a1,a2,...,an]表示 (P1^a1)*(P2^a2)*...*(Pn^an),其中P1,P2,...,Pn为素数列(2,3,5,7...);
[Cantor(康托)配对函数]
<X,Y> =( (X+Y)*(X+Y+1))/2 + Y
[程序说明]
给出一个歌德尔数,比如[7,20,44,13,2,9],数字表示指令代码。或者输入一个长整数,进行质因子分解得到一个歌德尔数。然后进行有效性判断:
1、歌德尔数中不能有0;
2、用Cantor配对函数对歌德尔数进行反向计算求到X,Y(如7=<2,1>),说得到的X和Y集合中,Y>0,而且X中不能有不为0且相同的数;否则歌德尔数不是能够转换为P-T程序的有效序列。
分解得到的X表示标号代码,Y无标号指令代码,比如:
7 - <2,1> 表示程序语句:A2 RIGHT
20 - <0,5> 表示程序语句:TO A1 IF B
44 - <0,8> 表示程序语句:TO A2 IF 1
13 - <1,3> A1 WRITE 1
2 - <0,1> RIGHT
9 - <0,3> WRITE 1
根据歌德尔数得到P-T程序后,输入变量X,运行P-T程序对X进行计算。
[结论]
任意给定一个P-T程序,则一定对应一个唯一的歌德尔数;反之,任意给定一个整数得到的歌德尔数不一定有P-T程序与之对应。
另外,在P4 3G的机器上,如果整数超过8位,分解的时间太长,所以直接输入歌德尔序列更加有效。
[程序]
/*
* Project : Post-Turing
* Author : Sonky Jiang
* Description : 任意输入一个正整数,得到Godel数,并模拟Post-Turing程序运行
* Date : November,2005
*/
using System;
using System.Text;
using System.Collections;
namespace Computation
{
class PostTuring
{
public static void Main(String[] args)
{
PostTuringMachine ptm = new PostTuringMachine();
PostTuring gn = new PostTuring();
LabelReadChoose:
try
{
while (true)
{
Console.WriteLine("<Menu>");
Console.WriteLine("1 : Use default GodelList [7,20,44,13,2,9]"); //选择功能运行
Console.WriteLine("2 : Enter a long number to gain Godel Number");
Console.WriteLine("3 : Enter a Godel Number");
Console.WriteLine("Q : Exit System");
Console.Write("[Main Menu]Enter 1, 2, 3 or Q:");
string functionChar = Console.ReadLine();
if (functionChar.ToUpper().Equals("Q")) break;
int chooseInt = Convert.ToInt16(functionChar); //读入功能选择
switch (chooseInt)
{
case 1:
ArrayList defaultGodelArrayList = new ArrayList(); //用来测试程序的默认Godel数
defaultGodelArrayList.Add(7);
defaultGodelArrayList.Add(20);
defaultGodelArrayList.Add(44);
defaultGodelArrayList.Add(13);
defaultGodelArrayList.Add(2);
defaultGodelArrayList.Add(9);
ptm.PrintPostTuringMachine(defaultGodelArrayList);
break;
case 2: //如果选择2,则用户输入一个长整数,并分解质因子,得到一个歌德尔数。
Console.Write("[Menu 2]Enter a long number(such as 147456/629856) to gain GodelNumber:");
LabelReadTheLong:
string s = Console.ReadLine();
try
{
long theLong = Convert.ToInt64(s);
if (!ptm.PrintPostTuringMachine(gn.OuputGodelNumber(theLong))) //如果输入的Godel数不能转化为有效的P-T程序,则重新输入,否则调用PostTuringMachine函数,运行post-turing机
{
Console.Write("[Menu 2]Enter a new long number to gain Godel Number:");
goto LabelReadTheLong;
}
}
catch
{
Console.Write("Enter error,enter a new long number to gain GodelNumber:");
goto LabelReadTheLong;
}
break;
case 3: //自行输入Godel数
Console.Write("[Menu 3]Enter a Godel Number:");
LabelReadGodelList:
string enterGodelString = Console.ReadLine();
try
{
if (!ptm.PrintPostTuringMachine(gn.GetEnterGodel(enterGodelString))) //如果输入的Godel数不能转化为有效的P-T程序,则重新输入
{
Console.Write("[Menu 3]Enter a new Godel Number:");
goto LabelReadGodelList;
}
}
catch
{
Console.WriteLine("Enter error,enter Godel Number again:");
goto LabelReadGodelList;
}
break;
default:
Console.Write("Error,just enter 1, 2 or 3:");
goto LabelReadChoose;
}
}
}
catch
{
Console.Write("Enter wrong,please enter 1, 2, 3 or Q:");
goto LabelReadChoose;
}
}
public ArrayList GetEnterGodel(string enterGodelString) //得到输入的字符串,分割获得各个数字
{
ArrayList GodelListArrayList = new ArrayList();
enterGodelString = enterGodelString.Trim();
string[] split = enterGodelString.Split(new Char[] { ' ', ',' });//Split函数分割String中以空格或者‘,’为标志的字符串
foreach (string s in split)
{
if (s.Trim() != "")
{
int i = Convert.ToInt32(s);
GodelListArrayList.Add(i);
}
}
return GodelListArrayList;
}
public ArrayList OuputGodelNumber(long theLong)
{
Prime p = new Prime();
ArrayList L = p.MakeoutPrimes(theLong); //分解出长整数thelong以内的素数集,并存入ArrayList中
ArrayList godelList = new ArrayList();
long godelNumberTemp = theLong;
if (L.Count != 0)
{
int i = 0;
int index = 0;
while (i < L.Count) //计算godelNumberTemp在各个素数位上的指数,直到最后一个素数计算完毕
{
if (godelNumberTemp % Convert.ToInt64(L[i].ToString()) == 0)
{
index++; //如果正整数godelNumberTemp能够被L.get(i)中的素数整除,则该素数位的指数index加1;
godelNumberTemp = godelNumberTemp / Convert.ToInt64(L[i].ToString());
continue; //算出godelNumberTemp/该素数的值,返回到循环体前部,继续计算这个值是否还可以被该素数整除
}
else //如果不能整除,该素数位计算结束,输出它的指数index值。index赋值为0,计算下一个素数
{
godelList.Add(index);
index = 0;
i++;
if (godelNumberTemp == 1) break; //如果godelNumberTemp已经=1,结束计算
}
}
Console.Write("The Primes Number is ");
PrintValues(L, 0, i);
Console.Write("The Godel Number of {0} is ", theLong);
PrintValues(godelList);
}
return godelList;
}
public void PrintValues(ArrayList myList) //打印ArrayList中的所有object
{
Console.Write("[");
for (int i = 0; i < myList.Count; i++)
{
if (i == myList.Count - 1)
Console.Write(myList[i].ToString());
else
Console.Write(myList[i].ToString());
}
Console.WriteLine("]");
}
public void PrintValues(ArrayList myList, int index, int count) //打印ArrayList中的从index开始的count个object
{
Console.Write("[");
for (int i = index; i < (count + index); i++)
{
if (i == (count + index-1))
Console.Write(myList[i].ToString());
else
Console.Write(myList[i].ToString());
}
Console.WriteLine("]");
}
}
class Prime
{
public bool IsPrime(long n) //判断输入的数是否是素数
{
bool isPrime = true;
if (n == 1) isPrime = false;
for (long i = 2; i <= Math.Sqrt(n); i++)
{
if (n % i == 0)
{
isPrime = false;
break;
}
}
return isPrime;
}
public ArrayList MakeoutPrimes(long n) //输出N以内的所有素数,以ArrayList形式输出
{
ArrayList pa = new ArrayList();
for (long i = 1; i <= n; i++)
{
if (IsPrime(i)) pa.Add(i);
}
return pa;
}
}
public class Cantor //康托配对函数
{
public long CantorNumber(int x, int y) //算出配对函数<x,y>的值
{
return ((x + y) * (x + y + 1)) / 2 + y;
}
public void ReCantorNumber(long c, out int x, out int y) //算出一个数所对应的配对函数,不一定能够得到结果,如果没有得到有效的配对函数,则输出(0,0)
{
bool IsCantorNumber = false;
x = 0;
y = 0;
for (int x1 = 0; ; x1++) //穷举算出配对函数,如果找不到,退出的条件是<x1,1>的配对函数值大于c
{
if (CantorNumber(x1, 1) > c)
{
x = 0;
y = 0;
break;
}
for (int y1 = 1; ; y1++)
{
if (CantorNumber(x1, y1) > c) break;
if (CantorNumber(x1, y1) == c)
{
x = x1;
y = y1;
IsCantorNumber = true;
}
}
if (IsCantorNumber) break;
}
}
}
public class PostTuringMachine //Post-Turing机器
{
public string PrintCode(int tab, int notab) //打印程序代码,tab是标号代码,notab是无标号指令代码
{
string codeString;
if (tab != 0)
{
codeString = "A" + tab.ToString() + " ";
}
else codeString = " ";
switch (notab)
{
case 1:
codeString += " RIGHT ";
break;
case 2:
codeString += " LEFT ";
break;
case 3:
codeString += " WRITE 1 ";
break;
case 4:
codeString += " WRITE B ";
break;
default: //如果notab大于5
if (notab % 2 == 0) //如果notab的值是偶数,则根据(2i+4)算出标号i的值
{
notab = (notab - 4) / 2;
codeString += " TO A" + notab.ToString() + " IF 1 ";
}
else 如果notab的值是奇数,则根据(2i+3)算出标号i的值
{
notab = (notab - 3) / 2;
codeString += " TO A" + notab.ToString() + " IF B ";
}
break;
}
return codeString;
}
public bool PrintPostTuringMachine(ArrayList godelArrayList) //打印出整个P-T程序
{
Cantor ct = new Cantor();
int x;
int y;
ArrayList tempArrayList = new ArrayList();
bool IsValidGodelList = true;
//下面的语句判断输入的GodelList是否有效,即可以转化为一个P-T程序
for (int i = 0; i < godelArrayList.Count; i++)
{
if (Convert.ToInt32(godelArrayList[i].ToString()) == 0)
{
IsValidGodelList = false;
break;
}
ct.ReCantorNumber(Convert.ToInt64(godelArrayList[i].ToString()), out x, out y);
if (y == 0) //如果配对函数中的Y=0,则不是有效的godellist
{
IsValidGodelList = false;
break;
}
for (int j = 0; j < tempArrayList.Count; j++)
{
if ((x != 0) && (x == ((CantorCode)tempArrayList[j]).labelCodeInt)) //如果有不为0且相等的X,则不是有效的godelist
{
IsValidGodelList = false;
break;
}
}
CantorCode c1 = new CantorCode();
c1.labelCodeInt = x;
c1.operateCodeInt = y;
tempArrayList.Add(c1);
}
if (IsValidGodelList) //如果是有效的可转化为P-T程序的Godel,则运行
{
Console.WriteLine();
Console.WriteLine("The P-T Program is:");
Console.WriteLine("---------------------------------------");
ArrayList programArrayList = new ArrayList();
for (int i = 0; i < godelArrayList.Count; i++) //将指令代码和标号代码存入programArrayList中
{
ct.ReCantorNumber(Convert.ToInt64(godelArrayList[i].ToString()), out x, out y); //得到一个数的配对函数〈x,y〉中的x,y值
CantorCode cc = new CantorCode();
cc.labelCodeInt = x;
cc.operateCodeInt = y;
programArrayList.Add(cc);
Console.WriteLine("{0,3} -- <{1,2},{2,2}> -- " + PrintCode(x, y), Convert.ToInt64(godelArrayList[i].ToString()), x, y);
}
Console.WriteLine("---------------------------------------");
Console.Write("/nPlease enter the value of X to run the program:");
LabelReadX:
try
{
int X = Convert.ToInt32(Console.ReadLine()); //读入X的值
RunPostTuringMachin(programArrayList, X); //运行P-T程序
}
catch
{
Console.Write("Enter wrong,please enter a int number:");
goto LabelReadX;
}
}
else Console.WriteLine("Error : The GodelList can't change to a valid P-T program!!");
return IsValidGodelList;
}
public StringBuilder PrintTuringStrap(StringBuilder sb,int index) //格式turing带的表示格式,如:[1]1 1 1 1 B
{
StringBuilder tempStringBuilder = new StringBuilder();
for (int i = 0; i < sb.Length; i++)
{
if (i == index)
{
tempStringBuilder.Append('[');
tempStringBuilder.Append(sb[i].ToString());
tempStringBuilder.Append(']');
}
else
{
tempStringBuilder.Append(sb[i].ToString());
if (i != (sb.Length - 1)) tempStringBuilder.Append(' ');
}
}
return tempStringBuilder;
}
public void RunPostTuringMachin(ArrayList programArrayList, int x) //根据输入的指令集和x的值进行模拟运行
{
StringBuilder turingStringBuilder = new StringBuilder(); //turing带
for (int i = 0; i <= x; i++) //将x转化为turing带
{
turingStringBuilder.Append('1');
}
turingStringBuilder.Append('B');
Console.WriteLine("The initial TuringStrap is " + PrintTuringStrap(turingStringBuilder,0) + ",Running.../n");
Console.WriteLine("--------------------------------------------");
for (int i = 0; i < programArrayList.Count; i++)
{
CantorCode c2 = (CantorCode)programArrayList[i];
}
int turingIndexInt = 0;
int programIndexInt = 0;
int runIndex = 1;
while (!(programIndexInt > programArrayList.Count-1)) //如果指令序号大于指令集的总数,程序结束
{
CantorCode cc = (CantorCode)programArrayList[programIndexInt];
switch (cc.operateCodeInt)
{
case 1: //指令代码是1,Turing带进行右移操作:RIGHT
turingIndexInt++; //turing带右移
if (turingIndexInt >= turingStringBuilder.Length)
turingStringBuilder.Append(' ');
programIndexInt++; //读取下一条指令
Console.Write(runIndex.ToString("D2") + " -> RIGHT ");
Console.WriteLine(PrintTuringStrap(turingStringBuilder, turingIndexInt));
runIndex++; //运行指令数加1;
break;
case 2: //指令代码是2,则Turing带进行左移操作
turingIndexInt--; //turing带左移
if (turingIndexInt < 0 )
{
turingStringBuilder.Insert(0, ' ');
turingIndexInt = 0;
}
programIndexInt++; //读取下一条指令
Console.Write(runIndex.ToString("D2") + " -> Left ");
Console.WriteLine(PrintTuringStrap(turingStringBuilder, turingIndexInt));
runIndex++;
break;
case 3: //指令代码是3,则进行“写1”操作
if (turingIndexInt > (turingStringBuilder.Length - 1)) //如果指针超过turingStringBuilder的长度,则需要执行Append(在后面插入值)
{
turingStringBuilder.Append('1');
}
else
{
if (turingIndexInt < 0) //如果指针小于0,则需要执行Insert(在制定位置插入值)
{
turingStringBuilder.Insert(0, '1');
turingIndexInt = 0;
}
else turingStringBuilder[turingIndexInt] = '1';
}
programIndexInt++;
Console.Write(runIndex.ToString("D2") + " -> Write 1 ");
Console.WriteLine(PrintTuringStrap(turingStringBuilder, turingIndexInt));
runIndex++;
break;
case 4: //指令代码是3,则进行“写B”操作
if (turingIndexInt > (turingStringBuilder.Length - 1))
turingStringBuilder.Append('B');
else
{
if (turingIndexInt < 0)
{
turingStringBuilder.Insert(0, 'B');
turingIndexInt = 0;
}
else turingStringBuilder[turingIndexInt] = 'B';
}
programIndexInt++;
Console.Write(runIndex.ToString("D2") + " -> Write B ");
Console.WriteLine(PrintTuringStrap(turingStringBuilder, turingIndexInt));
runIndex++;
break;
default:
if ((turingStringBuilder[turingIndexInt]=='1') && (cc.operateCodeInt % 2 ==0)) //如果当前读到的数是1,且读到的指令代码是偶数
{
int labelCode = (cc.operateCodeInt - 4) / 2; //获取跳转的标号代码
programIndexInt = SearchLabelCode(programArrayList, labelCode); //找到标号代码所在程序指令的序号
Console.Write(runIndex.ToString("D2") + " -> To A{0} IF 1 ", labelCode);
Console.WriteLine(PrintTuringStrap(turingStringBuilder, turingIndexInt));
runIndex++;
}
else
if ((turingStringBuilder[turingIndexInt] == 'B') && (cc.operateCodeInt % 2 != 0)) //如果当前读到的数是B,且读到的指令代码是奇数
{
int labelCode = (cc.operateCodeInt - 3) / 2;
programIndexInt = SearchLabelCode(programArrayList, labelCode);
Console.Write(runIndex.ToString("D2") + " -> To A{0} IF B ", labelCode);
Console.WriteLine(PrintTuringStrap(turingStringBuilder, turingIndexInt));
runIndex++;
}
else programIndexInt++;
break;
}
}
Console.WriteLine("--------------------------------------------");
Console.WriteLine("/nThe result is " + PrintTuringStrap(turingStringBuilder,-1)+"({0})/n",ValueOfTuringStrap(turingStringBuilder));
}
public int ValueOfTuringStrap(StringBuilder turingStrapStringBuilder) //得到Turing带上的值
{
int sum = 0;
for (int i = 0; i < turingStrapStringBuilder.Length; i++)
{
if (turingStrapStringBuilder[i] == '1')
sum++;
}
return --sum;
}
public int SearchLabelCode(ArrayList al, int lcIndex) //在指令集中搜索标号代码为lcIndex相对应的指令序号
{
CantorCode c = new CantorCode();
int index = 0;
for (int i = 0; i < al.Count; i++)
{
c = (CantorCode)al[i];
if (c.labelCodeInt == lcIndex)
{
index = i;
break;
}
}
return index;
}
}
public class CantorCode
{
public int labelCodeInt; //存储标号代码
public int operateCodeInt; //存储无标号指令代码
}
}