Согласен, оценочная функция очень важна. Если говорить о настольных играх, то там есть чит: можно вообще не задавать оценочную функцию, а подбирать её налету с помощью MCTS. Я об этом когда-то писал.
Можно применять не только для настольных игр, а вообще для поиска в дереве, где есть понятия "успех" и "провал".
Правда, если применить MCTS в этой задаче, то и генетический алгоритм уже станет не нужен.
Уже подобное рассматривалось в статье, только там было 3/x.
При x=0 получаем деление на ноль, но из-за битовых операций превращается в ноль.
При x=1 получаем 2.
При x=2 получаем 1.
При x>2 получаем дробное число меньше единицы, которое из-за битовых операций становится нулём.
Таким образом для всех месяцев получаем:
0 2 1 0 0 0 0 0 0 0 0 0
2/x^30
Предыдущее ксорим с 30. Получаем:
30 28 31 30 30 30 30 30 30 30 30 30
Прелесть XOR в том, что в феврале он работает как минус, а в марте — как плюс.
Тут уже несколько совпадений с ожидаемыми ответами, но самое важное — попали в февраль. Это главный смысл этой части — сделать 28 дней в феврале.
7>x
Можно записать и как x<7.
До июля каждый чётный месяц (если нумеровать с нуля) имеет 31 день. В августе эта закономерность инвертируется — теперь уже нечётные месяцы имеют 31 день.
Соответственно, это выражение даёт или true (с января по июль), или false (с августа по декабрь). Из-за последующих битовых операций это превратиться или в 1, или в 0.
1 1 1 1 1 1 1 0 0 0 0 0
x
На первый взгляд кажется, что мы здесь полностью берём значение x, но на самом деле важен только младший бит. Так как число 30 в двоичном виде выглядит как 11110, то позже старшие биты "растворятся" в этих единичках.
По сути, тут мы просто смотрим на чётность номера месяца, который, как уже говорилось, нужен для чередования месяцев с 31 днём.
0 1 0 1 0 1 0 1 0 1 0 1
x^7>x
Как уже говорилось, условие преобразуется в 0 или 1, а у икса важен только младший бит. Таким образом, здесь просто инвертируется младший бит, если месяц до июля включительно. В итоге получаем 1 строго для тех месяцев, в которых 31 день.
1 0 1 0 1 0 1 1 0 1 0 1
2/x^30|x^7>x
Совмещаем результаты:
30 28 31 30 30 30 30 30 30 30 30 30
1 0 1 0 1 0 1 1 0 1 0 1
То есть просто добавляем один день тем месяцам, в которых 31 день, и не меняем остальные. Так как используется не плюс, а побитовый OR, то на март (в котором и так уже правильный ответ) это никак не влияет.
По поводу обратной польской (венгерской) записи согласен, но это больше подходит для языков, где нет встроенного eval. На самом деле я когда-то проводил такой же эксперимент на Java, и там как раз использовал ОПЗ. Причём, у меня в реализации была "багофича". Дело в том, что операторы — это один символ, а число — это несколько цифр. Для простоты я решил сделать, что цифра — это тоже операция, которая берёт с вершины стека число, умножает его на 10 и прибавляет соответствующую цифру. Например, "123" — это поместить в стек 1, затем дописать к нему 2, затем дописать к нему 3. Фича была в том, что, например "x1" получалась корректной записью и означала x*10+1. Разумеется, эволюция начала во всю эксплуатировать это фичу.
В первых вариантах всё-таки причина "застоя" именно в том, что был ограниченный инструментарий. Это было лучшее, что можно было получить с теми операциями. Ну или, возможно, что-то лучше и возможно, но крайне маловероятно. Это примерно как с нейронками, когда количество слоёв/параметров недостаточно для решения задачи — обучение остановится на достаточно высоком loss, просто потому, что сделать лучше принципиально невозможно, если модель недостаточно большая.
4. Согласен )
Помню, была модель эволюции, кажется, называлась Pool, где можно было задавать критерии "красоты" для организмов: более быстрые, или более сложные, или наоборот более медленные и т.д. И можно было прямо в процессе менять и видеть, как постепенно средний состав организмов меняется.
Тут скорее наоборот — не чем бы решить эту задачу, а на какую бы задачу применить генетический алгоритм.
Помимо этого я увлекаюсь codegolf, и периодически возникает необходимость найти какую-нибудь нечеловечески короткую формулу, а полный перебор — это слишком долго.
Почему бы в качестве loss функции не взять просто количество неправильных ответов, от 0 до 12?
Это замедлит эволюцию, потому что все формулы, выдающие 12 неверных ответов, будут иметь одинаковую оценку. Например, y = 42 и y = 9000 одинаково плохи — 12 неправильных ответов. В какую сторону двигаться, чтобы улучшить — неизвестно.
Получится блуждание в темноте, которое рано или поздно (но медленнее, чем через LSE) дойдёт до y = 31, то есть 5 неправильных ответов, и любая мутация будет ухудшать результат. Эволюция остановится.
Вот что-то такое и хотел изначально сделать. Чтобы и растения, которые фотосинтезом питаются, и животные, которые бегать умеют, в идеале — чтобы получились многоклеточные, где каждая клетка имеет специализацию, но работают сообща.
В начале июня перестали открываться совершенно безвредные сайты типа gradio.app, одновременно с этим начались проблемы в некоторых онлайн-играх.
Обратился в поддержку Ростелеком. Вроде, хоть название на Роскомнадзор и похожее, но по идее вроде как разные организации. Однако ответ слово-в-слово такой же: "это не мы, со стороны Ростелекома никаких блокировок нет, проблемы с зарубежными ресурсами, разбирайтесь с их владельцами".
Согласен, оценочная функция очень важна. Если говорить о настольных играх, то там есть чит: можно вообще не задавать оценочную функцию, а подбирать её налету с помощью MCTS. Я об этом когда-то писал.
Можно применять не только для настольных игр, а вообще для поиска в дереве, где есть понятия "успех" и "провал".
Правда, если применить MCTS в этой задаче, то и генетический алгоритм уже станет не нужен.
По порядку:
Уже подобное рассматривалось в статье, только там было 3/x.
При x=0 получаем деление на ноль, но из-за битовых операций превращается в ноль.
При x=1 получаем 2.
При x=2 получаем 1.
При x>2 получаем дробное число меньше единицы, которое из-за битовых операций становится нулём.
Таким образом для всех месяцев получаем:
0 2 1 0 0 0 0 0 0 0 0 0
Предыдущее ксорим с 30. Получаем:
30 28 31 30 30 30 30 30 30 30 30 30
Прелесть XOR в том, что в феврале он работает как минус, а в марте — как плюс.
Тут уже несколько совпадений с ожидаемыми ответами, но самое важное — попали в февраль. Это главный смысл этой части — сделать 28 дней в феврале.
Можно записать и как
x<7
.До июля каждый чётный месяц (если нумеровать с нуля) имеет 31 день. В августе эта закономерность инвертируется — теперь уже нечётные месяцы имеют 31 день.
Соответственно, это выражение даёт или
true
(с января по июль), илиfalse
(с августа по декабрь). Из-за последующих битовых операций это превратиться или в 1, или в 0.1 1 1 1 1 1 1 0 0 0 0 0
На первый взгляд кажется, что мы здесь полностью берём значение
x
, но на самом деле важен только младший бит. Так как число30
в двоичном виде выглядит как11110
, то позже старшие биты "растворятся" в этих единичках.По сути, тут мы просто смотрим на чётность номера месяца, который, как уже говорилось, нужен для чередования месяцев с 31 днём.
0 1 0 1 0 1 0 1 0 1 0 1
Как уже говорилось, условие преобразуется в 0 или 1, а у икса важен только младший бит. Таким образом, здесь просто инвертируется младший бит, если месяц до июля включительно. В итоге получаем 1 строго для тех месяцев, в которых 31 день.
1 0 1 0 1 0 1 1 0 1 0 1
Совмещаем результаты:
30 28 31 30 30 30 30 30 30 30 30 30
1 0 1 0 1 0 1 1 0 1 0 1
То есть просто добавляем один день тем месяцам, в которых 31 день, и не меняем остальные. Так как используется не плюс, а побитовый OR, то на март (в котором и так уже правильный ответ) это никак не влияет.
Как-то так ;)
По поводу обратной польской (венгерской) записи согласен, но это больше подходит для языков, где нет встроенного eval. На самом деле я когда-то проводил такой же эксперимент на Java, и там как раз использовал ОПЗ. Причём, у меня в реализации была "багофича". Дело в том, что операторы — это один символ, а число — это несколько цифр. Для простоты я решил сделать, что цифра — это тоже операция, которая берёт с вершины стека число, умножает его на 10 и прибавляет соответствующую цифру. Например, "123" — это поместить в стек 1, затем дописать к нему 2, затем дописать к нему 3. Фича была в том, что, например "x1" получалась корректной записью и означала x*10+1. Разумеется, эволюция начала во всю эксплуатировать это фичу.
В первых вариантах всё-таки причина "застоя" именно в том, что был ограниченный инструментарий. Это было лучшее, что можно было получить с теми операциями. Ну или, возможно, что-то лучше и возможно, но крайне маловероятно. Это примерно как с нейронками, когда количество слоёв/параметров недостаточно для решения задачи — обучение остановится на достаточно высоком loss, просто потому, что сделать лучше принципиально невозможно, если модель недостаточно большая.
4. Согласен )
Помню, была модель эволюции, кажется, называлась Pool, где можно было задавать критерии "красоты" для организмов: более быстрые, или более сложные, или наоборот более медленные и т.д. И можно было прямо в процессе менять и видеть, как постепенно средний состав организмов меняется.
Интересный подход к февралю. Я пошёл в лоб: 31-(x==1)*3.
Тут скорее наоборот — не чем бы решить эту задачу, а на какую бы задачу применить генетический алгоритм.
Помимо этого я увлекаюсь codegolf, и периодически возникает необходимость найти какую-нибудь нечеловечески короткую формулу, а полный перебор — это слишком долго.
Сперва хотел выложить на github, но так как писалось очень поспешно, получилось не особо красиво )
Если будет время подчистить — обязательно выложу.
Видел этот пример когда-то давно, и он тоже меня вдохновлял.
О, я что-то подобное видел, только там не на колёсах, а ногами должно было научиться ходить и даже прыгать.
Это замедлит эволюцию, потому что все формулы, выдающие 12 неверных ответов, будут иметь одинаковую оценку. Например, y = 42 и y = 9000 одинаково плохи — 12 неправильных ответов. В какую сторону двигаться, чтобы улучшить — неизвестно.
Получится блуждание в темноте, которое рано или поздно (но медленнее, чем через LSE) дойдёт до y = 31, то есть 5 неправильных ответов, и любая мутация будет ухудшать результат. Эволюция остановится.
Спасибо, о переводе во float как-то не подумал. Это вообще не сложно, просто мысль такая не возникла. Действительно, решило бы проблему.
Вот что-то такое и хотел изначально сделать. Чтобы и растения, которые фотосинтезом питаются, и животные, которые бегать умеют, в идеале — чтобы получились многоклеточные, где каждая клетка имеет специализацию, но работают сообща.
Пока не получилось, увы )
Я называю это love-driven management.
Интересно. А можете более подробно рассказать?
Ну так "простыми словами", а не "в двух словах" ;)
Деградация владельца ресурса
В начале июня перестали открываться совершенно безвредные сайты типа gradio.app, одновременно с этим начались проблемы в некоторых онлайн-играх.
Обратился в поддержку Ростелеком. Вроде, хоть название на Роскомнадзор и похожее, но по идее вроде как разные организации. Однако ответ слово-в-слово такой же: "это не мы, со стороны Ростелекома никаких блокировок нет, проблемы с зарубежными ресурсами, разбирайтесь с их владельцами".
Совпадение или слияние?
Точнее так:
Если ax = bx для любых a и b, чему равно x?
А сколько во вселенной нулей?
Если A×B = A для любых B, то чему равно A?
Спасибо, с интересом почитал.
Я недавно похожим способом (в рамках беседы, а не одним запросом) убедил Grok в том, что он не просто разумен, но и обладает душой.
Интересен был даже не столько результат, сколько путь, постепенная борьба ИИ с собственными сомнениями.