计算机起源于数学,那么随着近几年计算机人工智能技术的不断更新进化,我们不禁要问,计算机能不能也帮我们“进化”下古老的数学呢?实际上,数学恰恰是一个极好的测试人工智能实力的试验场。如果我们把数学的各个定理看成一个独立的节点,你会发现节点和节点间存在着数不清的链接,进而组成了一个庞大而复杂的网络。事实上,这个网络太过于复杂以至于现在的数学家已经很难精通这个网络中的每一个节点了。但是,处理复杂的网络恰恰是计算机的强项,所以剩下的问题就是如何将现有的人类通过智慧创造的数学理论转换成一个可以计算的数据,然后交给计算机去处理,去发现新定理。

事实上,我们发现在这个数学的网络里,定理之间是有”远近“的,有些定理间挨得非常“近”,有些定理间离的非常“远”。你发现挨得近的定理之间可以很容易相互证明,或者你发现他们其实是相似或者根本就是同构的。这种定理距离上面的远近到底是因为“冥冥之中自有天意”还是只是“历史的偶然”,我们不得而知。纵观历史,你会发现很多时候之前看似无关的两个数学子领域,在随着人类对数学知识的不断探索后,最终奇迹般连接在了一起。比如怀尔斯用椭圆曲线及模形式证明的数论领域著名的猜想——费马大定理。又比如前两年望月新一通过构建宇宙際Teichmüller理論来证明的ABC猜想(虽然至今没人看得懂…)。因此有人想,如果我们能够量化这种定理之间的远近关系,然后把这个网络输入到深度学习网络中,我们没准就能够创造出最初级的”人工数学家“了。当然要想成功,我们还需要攻克的难关就是如何用一种简单或者自然的方法来表达最终的结果,并让机器在自己创造的结果上继续学习。

事实上,之前大量的人工智能项目都遇到了这个问题。例如麻省理工学院在开发”MACSYMA”这个基于LISP的计算机代数运算软件时,其中要解决的一个重要问题就是,怎么确定当前状态下的运算是朝向正确(简化)的方向在计算。那个年代的人工智能大多依赖于树结构的搜索,而数学运算每一步都会产生大量的分支,一一探索将会浪费极大的时间。为了改善速度,他们又提出了一个分级的结构,利用启发式算法结合已知的数学知识对整体运算做剪枝优化。事实上这个方法和现在的阿尔法狗利用蒙特卡洛树搜索树的方法有着异曲同工之妙。

另外一个不得不提的人工项目是由斯坦福大学的道格拉斯教授开发的一个可以自我”发明“数学定理的程序。一开始他先定义一组符号集合和一组”有趣“的符号之间的关系,然后把这两组数据分别输入到计算机。之后他的程序就不再做任何干预,而是让计算机去自己发现这里面的关系。最后他发现计算机可以通过这两组数据重新发明如何计数,如何做加法,如何做乘法,如何标识出来素数,甚至可以重新“发现”哥德巴赫猜想。 这些当然都是我们人类在上千年前就已经知道的知识,但是能取得这种结果也让人感到欣喜。可是令他不解的是,在这之后计算机就不能够继续创造有用的知识了,这个系统不能继续用它推导出来的理论继续产生新的理论。所以这些计算机推导出的有限的数学知识也没准是因为输入的数据中已经包含了这些定理。而他创造的这个人工智能本身却没法创造新的知识。

回到现在,深度学习能够让我们更有效的利用已有的硬件资源。但是,依照现有的计算机体系框架,即使我们成功的将数学理论全部输入进入神经网络,最好的结果估计就是能够通过分析现有的人类数学知识,将一些遗漏的定理之间的“链接”补全。现有的人工智能还没有能力像天才数学家那样去开创新的数学领域,也不能参透数学的奥秘。

URL: http://groundwavesimulation.com/Torterra/ 最近正在忙毕业设计和毕业论文。之前怕不能如期毕业,所以我不得不给之前做的地波雷达的项目做个“壳”。现在看来美国教授也很吃这一套,弄个B/S的壳后,我终于能够顺利毕业了:) 该项目可以理解为是尝试用ns-2来仿真地波雷达。整个仿真系统是搭建在Linux下。先通过Grwave计算Path Loss然后再带到ns-2中做仿真。 整个项目后续计划是加入Dynamic Spectrum access,并用gh_noise计算噪声。--》但愿老板能够给点钱:) 有钱才有动力。 现有的前端GUI部分是一个星期赶工的结果,用的技术也是2年前的老技术了。没啥创新... 希望下次能够有机会尝试下令人激动人心的新技术,比如Tornado,Redis :)

Greed is never good. - Linus Torvalds

下一版本的操作系统已经制作好,但是我在后续的开发上面遇到了困难(移植bash和gcc),我正在抓紧时间解决问题。等我先把需要学习的东西看懂并把手头的问题解决了,再继续发布教程。 另外,最近买了一个das的青轴机械键盘,非常不错:)

我们需要做的第一件事是在自己的电脑上搭建一个操作系统的开发环境。然后写个能显示"Hello World"的操作系统。

下面是我们需要准备的东西: 1、一个你操作熟练的编辑器,比如Vim 2、编辑C语言代码的gcc和binutils 3、用于自动化编译和链接的GNU Make 4、一个用于运行我们的操作系统的虚拟机,推荐使用Bochs。

安装上面的软件非常容易。在我的archlinux系统上面只需要一行命令

yaourt -S vim gcc binutils make bochs

就瞬间全部搞定了。 Ubuntu和Fedora系统安装这些工具应该也非常容易,如果有问题,大家自己用百度Google下就行了。 都安装好后,我们就要分析下下面需要做的事情了。我们已经有了Bochs作为虚拟机,而这个虚拟机可以通过模拟插入软盘或硬盘然后引导启动。我们可以把Bochs看作是一台电脑——事实上我们真的可以用一台电脑来代替它,只是在一开始的阶段,使用Bochs更方便于开发调试。 有了“电脑“后我们需要开发的第一个东西就是启动引导程序(Boot Loader),也就是让电脑在通电后通过引导程序运行我们的操作系统。但是这个Boot Loader的开发非常复杂,需要用到大量汇编知识。在这里我要介绍下UIUC的SigOps uBoot System。 这个uBoot系统是我们初学者的一个神器,它可以让你跳过令人头疼的Boot Loader的开发,而直接进入到下一阶段。它的用法很简单,使用一个bootmaker程序编译elf或者是其它文件然后创建一个SBBB (SigOps Bitchin' Boot Block 哈哈)的启动映像。然后我们就可以利用我们的Bochs来运行这个SBBB的启动映像了——这实在是太强大的一个工具了! 下面我来叙述下过程。 首先下载下面的文件

http://os-quake.googlecode.com/files/kernel_0_0_f.tar.gz

解压后我们看到里面有8个文件。其中main.c是我们写的"hello world"的主程序,bloader.h是对应的头文件,Makefile是对应的make文件,helloworld.ini是配置文件。bochsrc是我们所用的虚拟机bochs的配置文件,bootmaker我之前介绍过了。kernel.elf和helloworld.img是我们编译时才会生成的文件,我刚刚打包的时候一并打包进去了,你可以删掉然后让它重新生成。 再进行下一步之前,我们先熟悉下这些文件。首先看下main.c

#include "bloader.h"
int main();

/*Global Variables BAD BAD:) */
unsigned int oldEBP;
struct boot_dir *viewableDirectory;
int totalMem;
char * passedParams;
/*end global vars */

void _start(int memSize, char *parms, struct boot_dir *loadedfiles)
{
	asm("mov %%ebp, %0":"=m"(oldEBP));
	viewableDirectory = loadedfiles; /*make file mem locations global*/
	totalMem = memSize; /*make mem of system global*/
	passedParams = parms; /*make paramaters passed to system global*/
	main();

	asm("hlt");		/* this halts the machine, solving the problem of triple-faults on 
							some machines, but also making it impossible to return to DOS */
}

int main()
{
	char *vidmem = (char *) 0xb8000;
	
	/* "Hello " */
	vidmem[0] = 'H';
	vidmem[1] = 0x7;
	vidmem[2] = 'H';
	vidmem[3] = 0x7;
	vidmem[4] = 'e';
	vidmem[5] = 0x7;
	vidmem[6] = 'l';
	vidmem[7] = 0x7;
	vidmem[8] = 'l';
	vidmem[9] = 0x7;
	vidmem[10] = 'o';
	vidmem[11] = 0x7;

	/* "World " */
	vidmem[12] = 'W';
	vidmem[13] = 0x7;
	vidmem[14] = 'o';
	vidmem[15] = 0x7;
	vidmem[16] = 'r';
	vidmem[17] = 0x7;
	vidmem[18] = 'l';
	vidmem[19] = 0x7;
	vidmem[20] = 'd';
	vidmem[21] = 0x7;
	vidmem[22] = ' ';
	vidmem[23] = 0x7;

	/* "OS" */
	vidmem[24] = 'O';
	vidmem[25] = 0x7;
	vidmem[26] = 'S';
	vidmem[27] = 0x7;

	return 0;
}

main.c只有60多行,仔细看下。void start()应该就是我们的C程序和SigOps提供的bootloader之间的桥接函数,也就是我们使用bootmaker为我们的程序添加bootloader外壳时,它会让我们的程序从start()开始运行。事实上,实现这一点并不难。 我们可以通过类似下面的代码来实现一个类似的内核的main函数,并实现汇编和C之间的链接。 kernel_asm.asm

[bits 32] ; hey, we're in PMode

[global start]
[extern _kernel_main] ; always add a "_" in front of a C function to call it

start:
  call _kernel_main
  jmp $ ; halt

kernel_c.c

kernel_main()
{
     k_init();
     k_sayhello();
     ...
};

void _start()函数一开始做了一些初始化的工作,然后就直接跳转到main()函数。char vidmem = (char )0xb8000是CGA显示卡显示内存的地址(确切来说是 0XB800-0XBC00),一般的IBM PC在这一部分使用了统一编址的方式。因此若要让一个彩色字符显示在屏幕上,我们可以直接使用内存操作指令往这个内存区域执行写操作即可。0x7是一个控制字符,它用来设置字体的颜色为黑底白字。你可以查阅相关资料把它替换为其它颜色。(相关资料见 《Linux 内核完全剖析--基于0.12内核》 赵炯编著 机械工业出版社 2009.1 第24页 2.4.6 “显示控制”一节) Makefile没什么稀奇的,调用gcc把main.c编译为main.o 然后调用bootmaker读取helloworld.ini中的配置文件,bootloader生成一个包含bootloader的kernel.elf,然后利用ld命令把main.o和kernel.elf链接到一起生成helloworld.img。

好了,在了解了我们的程序之后,我们需要做的就是启动bochs虚拟机加载helloworld.img这个映像文件,然后启动。 下面是我们动手操作下,先输入命令make,生成helloworld.img映像文件,然后再用bochs加载它。

$ make $ bochs -f bochsrc

之后我们根据提示一路回车就可以看到我们的"Hello world"了! 就在屏幕的左上方,仔细找下 :)

如果运行起来有问题的话,请检查下虚拟机的配置文件里面的内容是否正确。确保里面romimage和varomimage的目录确实在对应的目录下。

好了,我们的"hello world"已经完成了。下面我们需要做的是要为它添加一些基础的功能,比如初学者最喜欢的printf()。

本系列文章旨在一步步指导读者完成一个操作系统的编写。不同于于渊大牛的《Orange's 一个操作系统的实现》,本系列文章将直接用C语言开始编写自己的内核,略过较为艰涩的汇编内容。因为作者我也是第一次尝试编写内核,所以文章中的错误应该不少,希望大家能够及时留言指正。

本系列文章使用的UIUC的SIGOPS代码。先向UIUC的大牛们致敬!

- 前言: 能够自己动手写一个操作系统是很多编程爱好者的梦想。不过,我们不得不承认,编写操作系统还是要比编写日常的程序要困难一些。因为这次你所编写的是操作系统,而这个系统要能够运行别人编写的日常程序。一个操作系统的创建,是一个白手起家的过程,你除了硬件和对应的手册,其他什么都没有。在我们操作系统开发的初期,我们会面临缺乏各种常用库,调试器和各种常用代码的窘境。好在现在我们有了互联网,网上丰富的资料把一切都变得简单了。

所需知识和设备: C or C++的语法知识 对计算机体系结构的了解,了解汇编语言。因为我们使用了SigOPS,而它已经提供了一个i386的结构,所以读者不需要一上来就陷入到汇编和计算机体系结构的细节当中去。我们会在后面根据需要逐步介绍。 一台装了Linux的机器:我只喜欢使用Linux。 坚持坚持坚持坚持坚持坚持坚持坚持

最终目标: 我希望在系列教程的最后,我们能够完成一个非常NX的操作系统。虽然在写下这段文字的我还没有达到这一目标,但是我会不断努力的。 我所说的NX的操作系统至少要具备: 能运行多个程序 能够有进程调度程序 有系统调用 有硬件中断....等等

好了 坑已经挖好了。下面开始动工!