GrabDuck

Вот он, мутирующий алгоритм. Или чего не может «Lisp»

:

Полагаю, вам будет интересно взглянуть на настоящий мутирующий алгоритм, который только то и умеет делать, что мутировать. Всего пара функций написанных на проклятом языке «Автор».
В этой статье я:
  • — приведу алгоритм,
  • — расскажу, как его интерпретирует «Автор»,
  • — покажу, во что он превращается,
  • — немного расскажу про автоматическое самообучение и ИИ,
  • — посмеюсь над собой.

Для начала хочу сказать, что единственным фундаментальным отличием языка «Автор» от других языков является возможность программ наглядно редактировать собственный алгоритм. Не текст программы, а именно алгоритм. Смотри тут. На мой взгляд, именно эта возможность является необходимой и достаточной для существования самообучающихся программ ну и, конечно же, не побоюсь этого слова, искусственного интеллекта. Да, да именно ИИ. Как мне говорил преподаватель информатики: «Зайди на кафедру программного обеспечения, крикни «искусственный интеллект» и все будут в замешательстве». А я мов – люди, давайте я сделаю ИИ, просто объясните мне, дураку, как это сделать. Если уже я что-то пойму, я непременно смогу научить этому машину. Что считать интеллектом? Что считать самообучением? Как сощитать интеллект или пользу? Философский вопрос. Дайте мне одну экспоненту информации…

Итак, вот «самый простой» пример программы, которая пытается учиться, да так, чтобы не сломать себя:

// killme.txt
var generator(n){
	if(n<2)return PROGRAM({1,5,18,3,7,"x","y"}[#]);
	a=(int)(n/{1.4,2}[#]);
	if(#?1:0)a=n-a;
	b=n-a;
	operators={"+","-","*","|","&"};
	command=PROGRAM("#"+operators[#]+"#");
	command.setSub({0},generator(a));
	command.setSub({1},generator(b));
	return command;
}

void main(functionName){
	if(!isset(functionName)){
		main(getThisFunctionName());
		main("generator");
		return;
		}
	f=getFunction(functionName);
	ids=f.getIDs()+{f.Root()};
	pos=ids[#];
	next=f.Next(pos);
	isElse=0;
	if(typeof(next)=="vector")isElse=rand()%next.size();
	pos=f.insertDown(pos,isElse);
	f.setCommand(pos,generator(5));
	pos=f.insertDown(pos);
	f.setIF(pos,"#?1:0");
}

Конечно, вы скажете, что еще проще будет пример программы, которая уже всё умеет. Но не будем всё возводить в абсолют.

Первая функция производит мусор, вторая пичкает им себя и первую. Мера развития алгоритма изначально определена.

Вот во что превратится алгоритм уже после пятого своего запуска:

// killme.code
var generator(var n){
	if(n<2)return PROGRAM({1,5,18,3,7,"x","y"}[# ]);else {
		5-1&(7|1-18);
		if(# ?1:0);
		}
	a=((int)(n/{1.4,2}[# ]));
	if(# ?1:0)a=n-a;
	b=n-a;
	7*x|x-(x-18);
	if(# ?1:0);
	operators={"+","-","*","|","&"};
	(5&3)-3-(1|18);
	(3|7)|18&3&y;
	7+18|7-(y&x);
	if(# ?1:0);
	if(# ?1:0);
	if(# ?1:0);
	command=PROGRAM("#"+operators[# ]+"#");
	command.setSub({0},generator(a));
	command.setSub({1},generator(b));
	return command;
}

void main(var functionName){
	if(!isset(functionName)){
		main(getThisFunctionName());
		(5|5)-(7&x*x);
		if(# ?1:0);
		main("generator");
		return;
		}else {
		7*5+7*(18&7);
		if(# ?1:0);
		}
	f=getFunction(functionName);
	ids=f.getIDs()+{f.Root()};
	pos=ids[# ];
	next=f.Next(pos);
	isElse=0;
	if(typeof(next)=="vector")isElse=rand()%next.size();
	pos=f.insertDown(pos,isElse);
	x-(x&3)+(18|5);
	if(# ?1:0){
		(3|7)+(x&1+3);
		if(# ?1:0);else {
			(y|7-1)&(18|x);
			if(# ?1:0);
			}
		}
	f.setCommand(pos,generator(5));
	pos=f.insertDown(pos);
	f.setIF(pos,"#?1:0");
}
// killme.code	:-|

Конечно, можно сделать ещё более мутирующий алгоритм с заменой имен переменных и изменением порядка следования некоторых команд, но он изначально будит, всего лишь, больше и сложней.

Порой мне кажется, что я сам своими статьями, произвожу мусор, но так можно сказать и про всю нашу банковскую систему.

А ведь «преображение» можно сделать и в другую сторону. Настроить программу на самосовершенствование. Пусть программа минимизирует себя по размерам, сложности и/или времени исполнения. Вот это уже будет что-то похоже на ИИ в плане «робота программиста».

Сейчас хочу остановиться на вопросе «Что считать самообучением?».
Здесь, с одной стороны, всё просто – не было алгоритма, и вот он появился. Не было данных, и вот они появились. Но с другой стороны, если их изначально не было, то, как же они смогут появиться. Значит должно быть что-то, откуда эти данные можно извлечь, что-то, откуда алгоритм можно понять?

Вот вам задача на смекалку. Скажите, что хотел написать автор следующего кода?

// smekni.txt
void main(){
	m={4,6,1,78,43,59,8,12};
	while(1){
		ok=1;
		for(i=1;i<m.size();++i)if(m[i-1]>m[i])ok=0;
		if(ok)break;
		a=rand()%m.size();
		b=rand()%m.size();
		X=m[a];
		m[a]=m[b];
		m[b]=X;
		}
	trace(m.export());
	getstring();
}

Ну не знаю я, как сортировать массив. Лисп всю жизнь изучал. Пойми меня. Пойми.

Я думаю, вы все меня когда-нибудь поймёте.

У меня к вам просьба. Присылайте мне задачи, в которых можно увидеть меру обучения, подобно «Хенойская башня» или «Палки». Наверняка у игры «Палки» существует и оригинальное название, просто я его не знаю.

Игра заключается в следующем. Дано миллион палок, два игрока, каждый игрок может за свой ход забрать одну, две или три палки, игроки ходят по очереди, кто забрал последнюю палку – проиграл. Первым хожу, конечно же, я:). Здесь дело не в проигрыше или выигрыше, а в том, что эти задачи можно представить как алгоритм, из которого нужно получить правило, умение. Вот в чём соль.

Вот, что значит, посмотреть в детстве на зад терминатора).

Продолжение следует?