Рождение условного поведения 2

В предыдущей статье, я познакомил вас с первым организмом получившим так называемое “условное поведение” в результате нескольких случайных мутаций. Как оказалось, этим дело не закончилось 🙂 Данный поведенческий шаблон оказался очень удобен для последующих изменений. Что это значит? Это значит, что на его основе можно делать новые виды условного поведения. Немного позже, я нашел другой организм, который содержал тот же код (смотри предыдущую статью), но с некоторыми модификациями. Смотрите:

code-escape

модификация условного поведения

В строке 2, организм проверяет кто находится над ним. Функция Creature.idUp() возвращает идентификатор организма, находящегося над текущим. Если над нами ничего нет, то возвращается 0. Окей, переменная var_33 теперь равно нулю или идентификатору недруга. Далее, в строке 9 мы проверяем, что в переменной var_33. Если там 0, то и var_2 будет 0. Но если там идентификатор организма, то var_2 будет равна 127. И от этого значения зависит то, зайдем ли мы в цикл в строке 14 и будем ли мы “убегать” в противоположную сторону или нет 🙂 Если описать это простыми словами то получается вот что: “если над тобой кто-то есть – убегай вниз”. Не знаю как Вы, но я в восторге от этого 😀

P.S. список всех 80 лучших организмов вы можете найти здесь.

И еще раз, с новым годом!

Рождение условного поведения

Сегодня отличный день знаете ли 🙂 Отличный он, потому что в одной из популяций (6 дней работы алгоритма) родился организм с экстраординарными способностями. Такой себе мальчик-индиго 🙂 Анализируя код двадцатки лучших, я заметил, что у одного из них аномально много вызовов редких функций energyLeft(), energyDown() и idLeft().

Это странно, так как такие штуки редко поддерживаются отбором. Когда я начал разбираться, то наткнулся на интересную конструкцию:

code-2

Обратите внимание на строки от 70 до 84. Что Вы там видите? Это то самое условное поведение, которого я так долго ждал! Итак, в двух словах, о том, что здесь происходит. Сначала наш организм проверяет есть ли что-то под ним с помощью функции Creature.energyDown() (строка 63). Она возвращает количество энергии (это может быть как обычная энергия, так и другой организм). И если это число не ноль (ноль – означает пусто), то организм входит в цикл, где он 7 раз откусывает от жертвы 127 энергетических единиц. Если же под ним ничего нет, то в цикл мы не заходим и выполнение кода продолжается. Эта хитрость дает ему возможность нападать на своих жертв предварительно поняв, что они рядом. Если быть совсем точным, то нужно отметить, что количество энергии под ним должно быть больше 127. Но это не играет большой роли, так как в строке 84 все равно происходит откусывание снизу…

Стоит так же отметить, что появлению такого условного поведения предшествовал ряд событий. А именно:

  • Приоритет на добавление мутаций. В строке 90, Вы можете заметить массив чисел: 98, 38, 30,... – это коэффициенты которые влияют на частоту появления определенных мутаций. Первое число (98) определяет, как часто новый код будет добавляться в код нашего организма. Само число больше, чем все остальные. А это значит, что добавления будут более часты, нежели, например модификация (38) или удаление (30) кода.
  • Высокий процент мутаций при делении. В той же 90-й строке Вы можете заметить число 47.4821. Это процент мутаций при делении организма (при получении потомства). По сути – это означает, что при делении будет внесено столько мутаций сколько строк кода содержит организм поделенное на 2. То есть, если организм состоит из 88 строк, то будет внесено 44 мутации. И большинство из них будут вставками нового кода (мы это выяснили из предыдущего пункта).
  • Высокий коэффициент мусора. В данной популяции коэффициент мусора составляет 0.2. Это означает, что организм может хранить 80% мусорного кода без потери энергии. Это одно из новшеств, которое было добавлено в версии 1.1-rc1. Что дает мусор? Как ни странно, мы не до конца понимаем зачем в наших ДНК хранится столько мусора (по разным оценкам от 80% до 40%). Некоторые эксперименты на мышах, показывают, что он используется ими для реакции на экстремальное изменение окружающей среды. В нем, могут хранится нужные случайные мутации… По всей видимости в нашем (в цифровом организме) случае все произошло именно так.

Именно по этим важным причинам, данный организм случайно получил в подарок эту последовательность операций 🙂 Для желающих изучить все детали, привожу полный листинг нашего альфа-самца:

code

Еще один примечательный факт, касающийся этих важных мутаций – они были поддержаны отбором. Просмотрев список из 80 лучших организмов, я нашел их в коде у многих из них. В общем, буду держать вас в курсе 😉

Всех с Новым Годом! 🙂

Пост 6. Видео материалы.

Добрый вечер друзья. Давненько я не находил времени для очередного поста. Был занят: программировал и играл в хоккей 🙂 Сегодня я хочу поделиться с Вами видео материалами, которых у меня накопилось, за последний год с лишним, некоторое множество. Они полезны тем, кто хочет изучить тему эволюционного программирования и генетического алгоритма немного глубже. Ссылки расставлены сверху-вниз по тому, как по моему мнению нужно знакомиться с материалом. Единственная разница между этим постом и постом 1 – этот более полный. Итак:

Bio evolution – сборник ссылок на лекции Александра Маркова по эволюционной биологии. Они важны, так как эволюционная биология и генетика лягли в основу при разработке принципов эволюционного программирования.
http://macroevolution.livejournal.com/206803.html
GA – видео, объясняющие суть генетического алгоритма.

AI – видео по искусственному интеллекту связанному с ГА и ЭП от Криса Адами.

Avida – от части, конкурирующая программа, которая разрабатывается Чарлзом Офрия из Мичиганского университета. Так же, эмулирует виртуальный мир цифровых организмов (программ), которые используют ассемблеро-подобный язык для жизни и функционирования в памяти. Помимо видео материалов, советую послушать интервью, где Чарлз объясняет многие детали своего проекта.

Polyworld – интерактивная OpenGL программа (несколько устаревшая) по разведению цифровых организмов. Похожая на Avida, но имеет 2D виртуальный мир, используя который можно вживую посмотреть, чем именно занимаются организмы, как они охотятся, развиваются, едят и т.д. Использует нейронные сети вместе с генетическим алгоритмом.

Всем хорошего вечера 🙂

Пост 5. О чем говорят цифры…

Всем привет!

Окей, этот выпуск будет немного неформатный, по той причине что у меня появились первые данные 🙂 В прошлый раз, мы говорили о языке julia и о том, как писать простые программы с его использованием. Сегодня – поговорим о реальных результатах и уже в следующий раз, продолжим с julia. Что я имею ввиду, когда говорю о данных? “Данные” – это различные характеристики (возраст популяции, размер кода организмов, количество мутаций, количество циклов в коде и т.д.) тестируемой популяции, которые изменяются со временем. Таким образом, их можно визуализировать в виде графиков.

Если в двух словах говорить о том, как были получены эти данные и связанные с ними графики, то дело происходило так: сначала создавалась “пустая” (без кода) популяция из 250 особей. У каждого организма такой популяции было 7000 юнитов энергии. Далее они размножались и мутировали, а отбор делал свое грязное дело (убивал организмы (10 штук), количество энергии которых было минимальным). Каждые 5 секунд система делала срез данных куда входили следующие поля:

fields

Давайте, я поясню детальней что означают эти поля. Сверху-вниз:

  • Вероятностные коэффициенты. Определяют, как часто в коде появятся мутации добавления, изменения и удаления кода (первые 3 числа). Последние 3 числа определяют: количество мутаций при клонировании, период дополнительных мутаций и количество доп. мутаций после этого периода. Все эти параметры так же могут мутировать у каждого организма по отдельности
  • Количество функций в коде организма
  • Количество вызовов этих функций
  • Фактическое количество мутаций применяемое после клонирования
  • Период, после которого применяются дополнительные мутации
  • Количество дополнительных мутаций применяющихся после периода доп. мутаций
  • Количество энергии организма
  • Количество операторов for в коде организма
  • Количество операторов if в коде организма
  • Количество вызовов функции getEnergy() (аналог примитивного зрения)
  • Количество обращений к внутренней памяти организма
  • Количество вызовов функции eatXXX() (еда)
  • Количество вызовов функции stepXXX() (движение)
  • Количество строк кода организма
  • Количество организмов в текущей популяции
  • Текущий IPS (Iterations Per Second)
  • Количество энергии в “мире” доступной для поедания
  • Возраст популяции

Каждый из этих параметров меняется со временем и таким образом формируется большой JSON файл со всеми срезами, и на его основе рисуются графики. Вот такие:

2016-08-16 (500000) code-lines-charts
увеличить

Начнем с того, что по горизонтали у нас “возраст популяции”. Что это значит? Это значит, что в самом левом углу (где ноль) популяция начала существование, а в самом правом (где значение 500000) – она находится сейчас. Сами числа определяют количество умерших организмов с момента рождения популяции и до выбранного момента. В некотором смысле – этот параметр означает “текущее поколение” и он напрямую связан со временем. Чем больше число, тем дольше существует популяция…

Видите этот синий график сверху? Это количество строк кода у самых лучших организмов популяции. Вообще, все эти графики строятся на основе “лучших из лучших” организмов. Такой себе показ “альфа самцов” 🙂 (в этом месте должны проснуться феминистки). Для нас важно то, что всреднем, синий график растет. Это означает, что организмы увеличивают размер своего кода, при этом затраты энергии тоже увеличиваются. Важно помнить, что увеличение количества строк кода – задача вполне тривиальная. А вот увеличение кол-ва строк одновременно с увеличивающейся потерей энергии – нет. Все это означает, что удлинение кода происходит с одновременным увеличением его эффективности. В нашем случае – это способность “находить” больше энергии для пропитания, чем твои предки. Таким образом отбор работает в сторону тех организмов, которые мутируют в направлении более эффективного кода. Затраты увеличиваются, потому что каждая дополнительная строка кода приравнивается к одному юниту энергии. То есть, чем больше код организма, тем больше энергии он тратит с течением времени. Даже в том случае, если он ничего не делеат (просто итост на месте) – энергия все равно тратится. Это обстоятельство – один из факторов, который заставляет систему стремиться к увеличению потребления энергии. Давайте взглянем на код одного из лучших организмов (приблизительное поколение: 500000):

final-cut

Что мы здесь видим? Во-первых, сверху (строки 2-66) распологаются объявления функций и переменных. Далее, можно заметить вызов функции func_232() целых 5 раз. Видимо для жизни организма она играет центральную роль (у всех его “родственников” она тоже присутсвует). Заглянув внутрь нее, мы видим, что это по-сути микс движения и пожирания всего, что вокруг. Менее важной является функция func_296(). Она вызывается только раз (строка 130) и служит для дополнительного передвижения организма. Далее – интересней. Обратите внимание на строку 166. Там происходит вызов функции func_254(), но сама функция не определена в коде. Что это означает? Это означает, что текущий лучший организм содержит логическую ошибку (одна из предыдущих мутаций удалила эту функцию), которая ведет к исключению в строке 166. То есть, далее, код не выполнится. Строки 167-174, никогда не будут выполнены. По сути – это баласт, за который забирается дополнительная энергия. Разумеется, со временем отбор конечно же вычистит его, но на момент сбора данных это не мешало нашему подопытному кролику быть лучшим в популяции себеподобных. В остальном, там нет ничего интересного. Весть код – это смесь отностельно оптимального движения и поедания всего, что находится вокруг организма.

Идем дальше. Желтый и красный графики – определяют количество вызовов функций “двигайся” и “ешь”. Впринципе, эти показатели должны расти прапорционально с ростом размера кода (хотя здесь есть нюансы – рост может замедлиться при оптимизации кода). Как видно по этим графикам “есть”, по сути, означает – “двигаться”. Как минимум на этом этапе жизни популяции. И это логично, ведь движение напрямую влияет на то, сколько энергетических блоков будет найдено.

Окей, что еще? Чуть ниже, можно увидеть зеленый график – это количество функций. О них мы уже говорили выше. Это обычные функции (оператор function), которые программисты используют для абстрагирования. Я не учил организмы, как их использовать. Они сами “поняли”, что функции – это более оптимальный выбор нежели просто линейный код. Давайте я объясню. Обратите внимание на фиолетовый график – он тоже растет. Хоть и не так быстро, но все же растет. Оба, они показывают, как часто организм использует функции для изменения своего поведения. Количество вызовов функции всегда больше количества самих функций. Это логично. Ведь, если Вам нужно сделать 50 шагов. Вы можете вызвать 50 раз функцию stepXXX() или написать функцию с 10 вызовами stepXXX() внутри и вызвать её 5 раз. Такой код будет занимать 15 строк. Видите разницу? 50 против 15. Второй вариант короче, а значит, тратит меньше энергии. А, значит, более экономный и выживет с большей вероятностью. Именно так и просходит – оптимальные программы имеют больший шанс на выживание, а значит и на то, что именно их потомство “продолжит их дело”.

Еще один график, который я бы хотел обсудить – это потребление энергии. Он означает: сколько лучшие организмы потребляют энергии за свою жизнь. Если этот показатель растет – это означает, что они умудряются находить энергетические точки все лучше и лучше. Давайте взглянем на него:

2016-08-16 (500000) energy-charts

увеличить

Обратите внимание – первые 50000 особей активно увеличивали потребление энергии. После наступил медленный рост с перепадами, вплоть до самого конца (до 500000 поколения). Среднее увеличение показывает отдельная линия в центре графика (полином, построенный по данным энергии). Она передает сглаженное совокупное трендовое значение всего графика. Именно на её основе, мы делаем вывод о росте этого параметра.

Чтобы не мучать Вас дальше, я опущу остальные параметры. Последнее, на что бы хотел обратить ваше внимение это видео! Видео того, как в одной из популяций появилось примитивная групповая охота на случайно разбросанную энергию. Смотрим здесь.

Давайте подведем итог:

  • рассматриваемое поколение (приблизительно 500000) “научилось” писать относительно оптимальный код используя функции
  • общий график потребления энергии растет
  • общий график размера кода тоже растет
  • количество таких операторов как: for, if, getEnergy,… растет медленно
  • основная логика организмов (как минимум на текущий момент) – это “есть” и “двигаться”. Именно на эти параметры направлен отбор
  • эволюция сложного поведения процесс очень медленный и неверояно затратный (относительно CPU time). Результаты полученные в этой статье собирались 6 дней постоянной работы при 12% загрузки CPU

Всем спасибо, я спать 🙂

Пост 4. Многозадачная Юля.

Привествую друзья!

Сегодня мы поговорим о языке, на котором реализован практически весь функционал проекта jevo. А именно, о Julia.

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

Я более чем уверен, что Вы не слышали о Julia. Не слышали, так как этот язык достаточно молод. Он появился в 2012 усилиями трех друзей из MIT. Вот, что пишет о нем wikipedia: “Julia — высокоуровневый высокопроизводительный свободный язык программирования с динамической типизацией, созданный для математических вычислений. Эффективен также и для написания программ общего назначения. Синтаксис языка схож с синтаксисом других математических языков (например, MATLAB и Octave), однако имеет некоторые существенные отличия. Julia написана на Си, C++ и Scheme. В стандартный комплект входит JIT-компилятор на основе LLVM, благодаря чему, по утверждению авторов языка, приложения, полностью написанные на языке, практически не уступают в производительности приложениям, написанным на статически компилируемых языках вроде Си или C++. Большая часть стандартной библиотеки языка написана на нём же. Также язык имеет встроенную поддержку большого числа команд для распределенных вычислений.”. Неплохо, правда? 🙂 Для первого знакомства, рекомендую Вам посмотреть 4 вводных урока вот здесь.

Отвечая на вопрос: “почему ты выбрал именно его?”, я скажу: “на первый взгляд, он содержал все, что нужно для этой задачи”. А именно (сверху наиболее важные):

  • производительность близкая к языку С. Одна из основных проблем таких систем в том, что они очень сильно “нагружают” процессор. По этому, не терять скорость на этом этапе для нас очень критично.
  • “зеленые” потоки. Изначально, я планировал использовать что-то(какую-то технологию), что давало бы возможность запускать очень много независимых процессов. При чем проблемы синхронизации должны отсутствовать. Оригинальные системные потоки не подходят для этого, так как они слишком медленные. При переключении между ними, процессор тратит очень много тактов да и синхронизация данных задача непростая. По-этому выбор пал на виртуальные или “зеленые” потоки.
  • возможность динамически модифицировать свой код. По сути – это метапрограммирование или возможность дописывать, удалять или модифицировать свой же код без перезапуска программы. Именно так должны поступать организмы в случае мутаций. По сути, им нужно перекомпилировать свой исходный код в машинный и запустить его в режиме реального времени. В jevo этим занимается специальный модуль – Mutator. Видео урок о метапрограммировании Вы можете найти здесь.
  • поддержка работы с сетью. Наша задача требует распределенных вычислений для ускорения работы системы в целом. Удаленный терминал, визуализатор, менеджеры и другие компоненты jevo используют сеть для “общения” с сервером(менеджером). Детальнее о работе с сетью Вы можете узнать из этого обучающего видео.
  • кроссплатформенный. Согласитесь, сегодня без этого никак 🙂
  • лицензия MIT. Моя душа склоняется к открытым системам 🙂
  • динамическая типизация. Это просто упрощает жизнь разработчикам.
  • встроенная система управления пакетами. Этот пункт очень важен, так как он в значительной мере помогает разработчикам решать рутинные и прикладные задачи. jevo использует множество пакетов. Например: Cairo для работы с canvas, GR – для OpenGL графики, FactCheck для тестов и т.д.
  • активное сообщество.

Если быть до конца чесным, то стоит упомянуть о том, что первая версия этой системы была написана на JavaScript 😛 Это была достаточная фриковая и нереальная идея по той причине, что системы реального времени на JS писать попросту нельзя 🙂 Был даже разработан простой ассемблер для генерации кода организмов… Но, так как этот язык имеет серъезные архитектурные ограничения (например, невозможность писать приложения реального времени с бесконечным главным циклом), увы, ничего не получилось. В любом случае исходный код есть на github, и вы можете с ним познакомиться. Продолжая, стоит так же упомянуть о минусах Julia:

  • Язык молод и содержит ошибки. Лично я запостил 4 критические ощибки в github репозиторий авторов (вот пример одной из них).
  • Среднее кол-во библиотек. Не смотря на активное развитие инфраструктуры языка, есть задачи, которые прийдется решать вручную или использовать библиотеки на C и Python.
  • Нет полноценной поддержки отладки. Есть лишь альтернативный дебаггер. Он он появится в v0.5.

В остальном – это современный, быстрый и многообещающий язык программирования для научных вычислений и исследований. Окей, так как же выглядит код на Julia? Я расчитываю, что Вы, уважаемый читатель уже имеете некоторые навыки в программировании и мы не будем останавливаться на простых вещах. Давайте рассмотрим простой пример:

helloWorlds.jl

Код вполне читабельный и не нуждается в дополнительном объяснении. Обратите внимание, на то, что аргумент msg не типизирован. Julia мягко относится к отсутствию типов. По умолчанию, таким переменным присваивается тип Any. Разница в коде с фиксированными типами и коде без фиксации в скорости его выполнния. Хотя, в данном примере – это не будет заметно. Хорошо, двигаемся дальше. Основной базовой еденицей программ на Julia является модуль. Он инкапсулирует в себе функции и, иногда данные. Такие данные называют глобальными в пределах модуля (хотя, авторы языка не рекомендуют использовать их из за уменьшения прозводительности). Так же, модуль – это своеобразное пространство имен в вашей программе, которое собирает внутри себя функции связанные логически. Модули могут использовать другие модули внутри себя. Но давайте обо всем по порядку. Создадим простой модуль:

helloWorldModule.jl

В коде выше, мы добавили несколько новых элементов. Комментарий сверху (формируется с помощью символа решетки (#)) и модуль – создается с помощью ключевого слова module. Пока все просто. Давайте сохраним этот код в отдельный файл с именем Hello.jl. Использование нашего модуля дело не сложное – все, что нам нужно, это подключить его в коде и вызвать функцию showMessage с помощью оператора “.” точка, вот так:

appHello.jl

Давайте сохраним этот код в файле AppHello.jl в той же папке, где мы сохранили Hello.jl. Супер! У нас есть два файла и мы можем их запустить. Для этого на Вашем компьютере должна быть установлена Julia. Скачать простой инсталлятор можно здесь. Нужно будет поскролить чуть ниже и выберать свою версию OS для скачивания. Скачали? Прекрасно d:) Давайте запустим все это:

cmdLineRun

Упс 🙂 Julia не может найти модуль Hello. Все по-тому, что она ищет его не там, где нужно. А нужно чтобы она искала его в текущей папке. Дело в том, что по умолчанию все модули должны находиться в специальной папке. На моем компьютере это c:\Users\<user-name>\.julia\v0.4\. Чтобы решить эту проблему, нам нужно указать список папок, где могут находиться модули и где Julia будет их искать. Давайте немного исправим наш код:

helloWorldModuleFixed

И запустим все снова:

cmdLineRunFixed

Вуаля. Все работает. Продолжим 🙂 Давайте рассмотрим что-то посложнее, а именно виртуальные или зеленые потоки. Идея зеленых потоков состоит в том, что  Вы можете создать множество (на много больше, чем системных) виртуальных потоков и управлять ими своими руками. То есть, Вы выступаете в роли процессора, который переключается мижду такими потоками в тот момент, когда это нужно. Пока все понятно? Если нет, то прочтите статью на википедии и погуглите немного 🙂 Важно понимать, что все эти “зеленые” друзья выполняются внутри одного – системного. Плюсы такого подхода в том, что на переключение между ними уходит минимум времени (значительно меньше, чем на системных братьев). И это дает значительное приимущество в скорости выполнения. Итак, рассмотрим пример:

task

С точки зрения Julia, поток – это функция, в которую можно входить и выходить в нескольких местах. Эта концепция хорошо описывается термином coroutine. thread – является такой функцией. Точки входа\выхода – это функции produce. Каждый раз, когда функция produce вызывается, управление передается “главному” коду, который породил этот поток. В свою очередь вход внутрь потока осуществляется в помощью вызова consume. Но давайте будем последовательными: в 7 строке создается объект Task (зеленый поток или задача) на основе функции thread. Переменная task будет содержать ссылку на поток. Строки 8,9,10 передают управление внутрь потока с помощью метода consume. То, что передается параметром в produce выдается “наружу” потока и выводится с помощью println. Если бы между вызовами функций produce находился какой-то код, то он выполнялся бы до тех пор, пока следующий вызов produce не передал бы управления родительскому коду. Еще, нужно понимать, что в каждый момент времени выполняется только что-то одно. То есть, нет реальной параллельности, что можно наблюдать в современных многопоточных процессорах Intel  или AMD. Это отличие очень важное. Так как оно избавляет нас от всех проблем синхронизации данных. Давайте запустим этот код:

cmdLineRunTask

Этот принцип (псевдопараллелизма) лежит в основе того, как выполняются цифровые организмы в программе jevo. Каждый организм – это поток, выполнение которого прерывается много раз для того, чтобы переключиться внутрь потока другого организма и так далее. Именно это создает видимость многопоточности и параллельного выполнения кода организмов популяции.

Пойду ка я спать… До новых встреч 😉

 

 

 

Пост 3. Детали проекта.

Окей!

Пора нам копнуть немного глубже и разобраться, что именно представляет из себя данный проект и “кто” сидит под капотом. Еще раз напомню, что мы говорим о программе – эмуляторе, которая “повторяет”(эмулирует) биологическую систему организмов (в нашем случае компьютерных программ). Их задача (как и в природе) приспособиться к окружающей среде максимально сильно. Более приспособленные – выживут(чуть с большей вероятностью) и дадут чуть больше потомства, чем менее приспособленные. Тем самым, происходит итеративное улучшение всей популяции со временем. Стоит так же упомянуть о том, что во всех перечисленных процессах нет полного детерминизма, чего стоило бы ожидать от программы. Есть лишь вероятности и вероятностные функции, которые конфигурируются оператором…

Перед тем, как перейти к технической части, напомню о том, что базовыми принципами нашей системы (и биологической тоже) являются:

  • отбор организмов по каким-то критериям (умертвление менее приспособленных)
  • возможность давать потомство (пока реализовано только клонирование)
  • мутации (изменения\удаления\добавления кода организмов)

Зная это, давайте опишем нашу систему более детально. Для начала, определимся с терминалогией:

  • оператор – человек, взаимодействующий с системой и имеющий возможность менять её параметры как до, так и во время работы
  • мир – 2D пространство заданного размера в памяти, где “живут” все организмы
  • визуализатор – отдельная программа, которая показывает мир организмов в окошке
  • терминал – окно с консолью, через которое можно конфигурировать менеджер или получать из него данные удаленно по сети
  • инстанс или менеджер – одна запущенная копия jevo. Она контроллирует мир и все организмы в нем. “Общается” с другими менеджерами и поддерживает удаленное конфигурирование с помощью терминала. Так же, может выводить киртинку мира на удаленный визуализатор. По факту – это TCP сервер.
  • организм – компьютерная программа на языке Julia. Из дополнительных параметров содержит энергию, координаты в 2D мире, код, его размер, уникальный id и т.д.
  • код организма – текст программы на языке Julia уникальный для каждого организма и определяющий что именно данный организм “умеет”. В некотором смысле код – это аналог нашего ДНК. В этом случае менеджер “выполняет” этот ДНК.
  • мутация – изменение\добавление\удаление одной атомарной конструкции в программе организма на языке Julia.
  • энергия – индивидуальное число для каждого организма описывающее его “успешность”
  • смерть организма – удаление его кода и всех ассоциированных с ним данных из системы.

Итак, у нас есть какое-то количество программ(организмов) на языке Julia. Их код хранится в двух представлениях – AST (Abstract Syntax Tree) и скомпилированный машинный код. Первый используется для мутаций, второй(бинарная копия первого) – работает постоянно, пока организм жив. При первом запуске системы код организмов одинаков и пуст. И поверьте мне, умрет немало поколений, до тех пор пока не появится первый “общий предок“. Еще, есть мир (прямоугольная область X на Y – кусок памяти), где живут все программы. Он состоит из пикселей. На данный момент есть три типа пикселей: организм, энергия и пустота. В будущем планируется добавить на много больше типов. Цель организмов найти и съесть, как можно больше энергии чтобы выжить и дать потомство. Это и является их критерием успешности. То есть энергия === успешность. Так же, есть текущий менеджер, который всем этим управляет(выполняет код организмов, следит за миром, убивает и создает потомство для организмов, ждет удаленных соединений от TCP клиентов и т.д.). Когда энергия какого-то организма доходит до нуля – он умирает. Система удаляет его отовсюду (из мира и памяти). С другой стороны, если у одного из организмов больше всего энергии, то шансы на производство потомства наибольшие. Обратите внимание на слово “шансы”. То есть, вероятен процесс, когда менее энергичный организм сможет обзавестись потомством обойдя более энергичного. Такой себе миллионер из трущоб 🙂 С другой стороны, в долгой перспективе более успешные все таки выиграют эту гонку. Вообще, по моим наблюдениям, со временем вся популяция заполняется родственниками таких успешных особей… Количество энергии организма зависит от нескольких факторов: кол-ва найденной и съеденой энергии и от размера кода. Чем больше код, тем больше энергии тратится на его поддержание. По этому, всегда есть компромисс между размером кода и его качеством.

Теперь, когда мы в общем представляем о том, как работает система, давайте взглянем на то, как выглядит мир организмов:

2016-04-262
кликабельный скриншот программы jevo

На рисунке выше, Вы можете видеть 4 окошка с разными данными. Давайте опишем каждое из них:

  • Визуализатор. В верхнем – левом углу Вы можете видеть большое поле зеленых точек – это энергия. Она генерируется менеджером исходя из настроек, которые задает оператор. Эти точки неподвижны и просто “лежат”. Синие точки – это организмы. Черные – пустота. На момент создания скриншота, организмы уже достигли такого уровня развития, что могли двигаться и “есть”. Это можно заметить по “проеденным” черным каналам(сверху справа в основном). Не вникая в детали, можно догадаться, что популяция “научилась” двигаться по горизонтали и при этом есть все, что попадет её по дороге. Маленькое окошко по центру, снизу – это терминал, который запустил визуализатор. Он так же работает по TCP протоколу и получает данные с сервера(менеджера).
  • Терминал. В правой части рисунка Вы можете заметить окошко терминала – это TCP клиент, который дал запрос на сервер (левое нижнее окошко) для получения данных о пяти лучших(наиболее успешных) организмах. Об этом свидетельствует последняя выполненная команда. Там хорошо видно их код. Предыдущие команды – получение количества организмов популяции – 277, 281, 295, 304, 367. Существует целый набор команд, который поддерживается на данный момент.
  • Сервер(или менеджер). В левом, нижнем углу находится окно сервера. Вы можете видеть часть лога, который он выводит. В часности, видно, что сервер создал несколько популяций(“Creating organisms”), а так же записал два бекапа.

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

В следующем посте мы поговорим о языке Julia, а пока – до встречи 🙂

Пост 2. Детальное описание.

Итак друзья. Пожалуй, мне нужно более детально объяснить, что именно тут происходит. Вообще, для этого, я планирую снять видео, где все будет разложено “по полочкам”. Но пока его нет – будет текст.

Как я уже сказал, данное направление – эволюционное программирование – это набор подходов и алгоритмов, с помощью которых мы можем повторять эволюцию природы на домашних компьютерах. В пределе, такая система может создать ИИ. В науке нет четкого определения относительно искусственного интеллекта, так как это довольно сложный и неоднозначный вопрос. К примеру, есть тест Тьюринга, целью которого является определить обладает ли им машина. По одной из версий ИИ и наш человеческий интеллект – это нечто схожее. Поправьте меня, если я не прав 🙂 Единственный пример интеллекта, который нам известен и который мы таковым считаем, есть у людей. Хотя учитывая факт, что наше сознание порождается мозгом, а он в свою очередь нераздельно связан с конфигурацией нашего тела (его формой, положением глаз, ростом, и т.д.) – мы скорей специфический подвид ИИ… Давайте предположим, что интеллектом обладают большинство сложных живых существ на нашей планете. Тогда, можно говорить о неком его уровне (развития). И мы находимся на верхушке этой шкалы. Исходя из этих рассуждений можно сформировать догадку о постепенном формировании и усложнении ИИ со временем. Именно этим и занимается программа jevo.

Перейдем к сути. В основе всех моих вычислений лежит генетический алгоритм, который описывает эволюцию живых организмов нашей планеты. Эта идея была перенесена на математический язык из биологии несколькими учеными прошлого века. Например, господами Фогелем и Коза. Абстрактно, она состоит в том, что для получения какого-то сложного решения мы можем:

  1. создать набор случайных простых решений
  2. модифицировать и\или скомбинировать эти решения
  3. отобрать лучшие и отсеять худшие
  4. проверить достигнут ли результат. если нет, то идти на шаг 2

Таким образом – это итеративный (и, возможно, бесконечный) процесс, дающий каждый раз лучшее решение. Чтобы понять о чем идет речь, давайте рассмотрим пример. Чем хорош пример с презервативами, так это тем, что Вы точно его запомните : – )

В моем случае, используется нечто похожее. Роль решений выполняют компьютерные программы. Это в прямом смысле полноценные тексты на julia, которые живут независимо в двумерном пространстве, где помимо них, есть только энергия (точки, которые можно “есть”) и другие программы. Другими словами, организмы – это компьютерные программы, которые дописываются и переписываются с помощью мутаций (изменений, добавлений и удалений) своего кода постоянно. Те программы, которые преуспеют в нахождении “пищи” (в нашем случае энергитических точек на экране), будут более успешны и “родят” больше потомков, похожих на них самих. Тем самым, “дети” унаследуют их поведение. С течением времени, все программы меняются (при рождении происходят небольшие мутации, а так же время от времени – случайно). Это приводит к все большей адаптации к среде, где они живут. В теории, при изменении среды и её усложнении, организмы так же будут усложнятся, что в результате приводит нас к простейшим формам ИИ.

Всем спасибо, на сегодня это все. Спокойной ночи 🙂

Введение

Доброе время суток!

На этой странице я буду делиться с Вами информацией, касающейся эволюционного программирования. Целью данного блога является исследование данного направления и создание сообщества вокруг проекта jevo. jevo – это упрощенный эмулятор так называемых цифровых организмов (аналог живых организмов в природе), суть которого в создании различных форм искусственного интеллекта. Это открытый проект и участие в нем так же открыто для всех. Присоединяйтесь! 🙂 Кто заинтересовался – пишите мне в личку… В следующих постах я раскажу обо всем более детально. Для людей, не в теме, вот список материалов, которые помогут разобраться в вопросе: