[Python, Программирование, Искусственный интеллект] Constraint Programming или как решить задачу коммивояжёра, просто описав её (перевод)
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Пожалуй, наиболее популярной парадигмой программирования является императивное программирование. Но это не единственный вид программирования, широко известны функциональное и логическое программирование. Constraint Programming (Программирование в ограничениях/Ограниченное программирование) не так популярно. Но это очень мощный инструмент для решения комбинаторных задач. Вместо реализации алгоритма, который решает задачу, с последующей тратой кучи времени на его отладку, рефакторинг и оптимизацию, программирование с ограничениями позволяет вам просто описать модель в специальном синтаксисе, а особая программа (решатель - solver) найдет решение за вас (или скажет, если их нет). Впечатляет, не правда ли? Мне кажется, каждый программист должен знать о такой возможности. Minizinc Вероятно, наиболее часто используемым инструментом программирования ограничений (по крайней мере, в образовательных целях) является minizinc. Он предоставляет IDE для объявления моделей и несколько встроенных решателей для поиска ответа. Вы можете скачать программу с официального сайта.Простая модель в MinizincРассмотрим пример решения модели, начнем с криптоарифметической задачи. В данном типе задач все буквы следует заменить цифрами с двумя условиями:
- равенство должно выполняться
- одна и та же цифра не должна соответствовать разным буквам и наоборот.
Например, решим следующее уравнение:
S E N D
+ M O R E
= M O N E Y
Структура моделиВ minizinc каждая модель представляет собой набор переменных, параметров и ограничений. Переменные - это неизвестные значения, которые должен найти решатель, параметры - это некоторые константы, которые известны во время выполнения модели, вы можете изменять параметры от запуска к запуску, и, очевидно, это повлияет на результат.Например, количество городов и расстояния между ними являются параметрами для задачи коммивояжёра, путь будет зависеть от них. Но программист может создать одну модель для задачи, а затем просто выполнить ее для разных параметров без изменения исходного кода модели.Ограничения - это ограничения :), которым должны удовлетворять значения переменных. Объявление моделиПриступим к собственно программированию. Здесь у нас есть 8 переменных (S, E, N, D, M, O, R, Y), они являются цифрами, поэтому они могут принимать значения от 0 до 9 (S и M от 1 до 9, потому что число не может начаться с нуля).В синтаксисе minizinc это объявляется следующим образом:
var 1..9: S;
var 0..9: E;
var 0..9: N;
var 0..9: D;
var 1..9: M;
var 0..9: O;
var 0..9: R;
var 0..9: Y;
Далее следует указать равенство, в minizinc оно задается самым обычным образом:
constraint 1000 * S + 100 * E + 10 * N + D
+ 1000 * M + 100 * O + 10 * R + E
== 10000 * M + 1000 * O + 100 * N + 10 * E + Y;
Мы также должны указать, что каждая переменная имеет свои собственные значения и не должно быть переменных с одинаковым значением. Minizinc имеет специальное ограничение alldifferent, но оно не определено в стандартной библиотеке, необходимо подключить его специальной директивой include "alldifferent.mzn";.И последнее, что необходимо сделать, это объявить, каким образом решать модель, есть 3 варианта: удовлетворить (satisfy), минимизировать (minimize) и максимизировать (maximize) какое-то значение, я думаю, их названия говорят сами за себя :).Результирующий исходный код выглядит следующим образом:
import zython as zn
class MoneyModel(zn.Model):
def __init__(self):
self.S = zn.var(range(1, 10))
self.E = zn.var(range(0, 10))
self.N = zn.var(range(0, 10))
self.D = zn.var(range(0, 10))
self.M = zn.var(range(1, 10))
self.O = zn.var(range(0, 10))
self.R = zn.var(range(0, 10))
self.Y = zn.var(range(0, 10))
self.constraints = [(self.S * 1000 + self.E * 100 + self.N * 10 + self.D +
self.M * 1000 + self.O * 100 + self.R * 10 + self.E ==
self.M * 10000 + self.O * 1000 + self.N * 100 + self.E * 10 + self.Y),
zn.alldifferent((self.S, self.E, self.N, self.D, self.M, self.O, self.R, self.Y))]
model = MoneyModel()
result = model.solve_satisfy()
print(" ", result["S"], result["E"], result["N"], result["D"])
print(" ", result["M"], result["O"], result["R"], result["E"])
print(result["M"], result["O"], result["N"], result["E"], result["Y"])
Minizinc может выполнить модель и найти решение:
9567
+ 1085
= 10652
По умолчанию minizinc прекращает выполнение задачи satisfy после первого решения, это поведение можно изменить в настройках, вы можете повторно запустить эту модель и попросить minizinc найти все решения, но он скажет, что есть только одно :). Заключение для первой частиMinizinc предоставляет мощный, общий и простой в использовании способ углубиться в constraint programming. Но он использует собственный синтаксис, который замедляет обучение и затрудняет интеграцию с другими языками программирования.
Интеграция с Pythonminizinc-python решает вторую проблему, предоставляя способ вызова моделей minizinc из python, библиотека будет запускать minizinc, сериализовать ваш ввод и разбирать вывод, но программист по-прежнему должен писать довольно много строк кода. Мы можем посмотреть на пример решения квадратного уравнения:SpoilerУ автора публикации сломался хабр и перестал выдавать список языков для подсветки синтаксиса в drop-down меню, если кто-то знает, как починить, буду очень признателен.
import minizinc
# Create a MiniZinc model
model = minizinc.Model()
model.add_string("""
var -100..100: x;
int: a; int: b; int: c;
constraint a*(x*x) + b*x = c;
solve satisfy;
""")
# Transform Model into a instance
gecode = minizinc.Solver.lookup("gecode")
inst = minizinc.Instance(gecode, model)
inst["a"] = 1
inst["b"] = 4
inst["c"] = 0
# Solve the instance
result = inst.solve(all_solutions=True)
for i in range(len(result)):
print("x = {}".format(result[i, "x"]))
Лично для меня проблематично запомнить и воссоздать такой пример, а модель minizinc (которая представляет собой всего 4 строки кода) представлена в виде string, поэтому IDE и python не могут подсветить синтаксис и предоставить любую помощь и статические проверки для вас.
ZythonПочему бы не скрыть поиск решателя, создание экземпляров параметров, а также не предоставить способ реализации моделей на чистом Python?Это то, что делает zython (miniZinc pYTHON). Это самый простой способ погрузиться в программирование с ограничениями*.Spoiler* из того, что я знаю* по крайней мере, если вы разработчик на Python. :)Чтобы начать работу с zython, у вас должны быть установлены python 3.6+ и minizinc в путь по умолчанию или доступен в $PATH. После этого можно скачать сам пакет и проверить установку
pip install zython
python
>>> import zython as zn
Если все было установлено правильно, вы не должны увидеть исключений и ошибок. После этого можно начинать изучить constraint programming с zython.Send More MoneyСначала разберём уже известную модель — задачу "Send More Money"
import zython as zn
class MoneyModel(zn.Model):
def __init__(self):
self.S = zn.var(range(1, 10))
self.E = zn.var(range(0, 10))
self.N = zn.var(range(0, 10))
self.D = zn.var(range(0, 10))
self.M = zn.var(range(1, 10))
self.O = zn.var(range(0, 10))
self.R = zn.var(range(0, 10))
self.Y = zn.var(range(0, 10))
self.constraints = [(self.S * 1000 + self.E * 100 + self.N * 10 + self.D +
self.M * 1000 + self.O * 100 + self.R * 10 + self.E ==
self.M * 10000 + self.O * 1000 + self.N * 100 + self.E * 10 + self.Y),
zn.alldifferent((self.S, self.E, self.N, self.D, self.M, self.O, self.R, self.Y))]
model = MoneyModel()
result = model.solve_satisfy()
print(" ", result["S"], result["E"], result["N"], result["D"])
print(" ", result["M"], result["O"], result["R"], result["E"])
print(result["M"], result["O"], result["N"], result["E"], result["Y"])
Она должен вернуть тот же результат, что и раньше.Однако кажется, всё еще довольно много кода. Но если мы посмотрим внимательнее, мы увидим, что это в основном объявление переменных и арифметическое уравнение, zython выполняет всю грязную работу, например, поиск решателя, создания экземпляра, его параметризацию, запуск модели и передачу решения в скрипт на python. Все, что вы делаете, это само программирование. Кроме того, zython предоставляет синтаксис Python для определения модели, что позволяет IDE выделять ваш код и проверять его на наличие ошибок перед запуском. Zython же дополнительно осуществляет проверки во время выполнения.Генерация судокуСоздадим поле для судоку. Для этого необходимо использовать zn.Array. Массив может быть как переменной, так и параметром. Так как на момент запуска значения в ячейках поля судоку неизвестны и должны быть найдены в данном случае создаётся массив переменных.
import zython as zn
class MyModel(zn.Model):
def __init__(self):
self.a = zn.Array(zn.var(range(1, 10)), shape=(9, 9))
self.constraints = \
[zn.forall(range(9),
lambda i: zn.alldifferent(self.a[i])),
zn.forall(range(9),
lambda i: zn.alldifferent(self.a[:, i])),
zn.forall(range(3),
lambda i: zn.forall(range(3),
lambda j: zn.alldifferent(self.a[i * 3: i * 3 + 3, j * 3: j * 3 + 3]))),
]
model = MyModel()
result = model.solve_satisfy()
print(result["a"])
Решение, выданное моделью будет зависить от версии minizinc, мне выдало следующее:
Задача коммивояжёраПоскольку я обещал, что мы рассмотрим задачу коммивояжёра, давайте перейдём к ней. Данную модуль можно описать следующим образом:
import zython as zn
class TSP(zn.Model):
def __init__(self, distances):
self.distances = zn.Array(distances)
self.path = zn.Array(zn.var(range(len(distances))),
shape=len(distances))
self.cost = (self._cost(distances))
self.constraints = [zn.circuit(self.path)]
def _cost(self, distances):
return (zn.sum(range(1, len(distances)),
lambda i: self.distances[self.path[i - 1],
self.path[i]]) +
self.distances[self.path[len(distances) - 1],
self.path[0]])
distances = [[0, 6, 4, 5, 8],
[6, 0, 4, 7, 6],
[4, 4, 0, 3, 4],
[5, 7, 3, 0, 5],
[8, 6, 4, 5, 0]]
model = TSP(distances)
result = model.solve_minimize(model.cost)
print(result)
Мы снова использовали массив в модели, но теперь это параметр, то есть его значения, определенны до выполнения модели.Заключение для второй частиConstraint programming - концепция, достойная изучения, она может сэкономить время при решении множества проблем: составить расписание, определить, каких юнитов следует нанять, чтобы обладать самой сильной армией при заданном ограничении ресурсов в вашей любимой стратегии или помочь определить самую сильная сборку в вашей любимой ролевой игре, какие цвета вы должны использовать, чтобы покрасить географические регионы на карте таким образом, чтобы все соседствующие области имели разные цвета, и даже определить оптимальные интервалы в движении общественного транспорта и, какие тортики должна печь ваша пекарня для максимизации прибыли.Zython предоставляет способ выразить модель constraint programming на чистом питоне и легко решить эту проблему. Вы можете увидеть больше примеров в документации.Конструктивная критика, выражение своего мнения в комментариях, баг репорты, feature request'ы и PR одобряются.Удачи в изучении программирования с ограничениями.
===========
Источник:
habr.com
===========
===========
Автор оригинала: Artyom Kaltovich
===========Похожие новости:
- [Программирование, Функциональное программирование] Используйте парсинг вместо контроля типов (перевод)
- [Научно-популярное, Искусственный интеллект] Искусственный интеллект для обывателя
- [Программирование, .NET, Amazon Web Services, C#, DevOps] Nuke: настраиваем сборку и публикацию .NET-проекта
- [Системное программирование, Программирование микроконтроллеров] Embox на плате EFM32ZG_STK3200
- [Python, Голосовые интерфейсы] Голосовой ассистент на Python (Виталий alfa 2.0)
- [Программирование, C++, Работа с 3D-графикой, Разработка игр, CGI (графика)] Vulkan. Руководство разработчика. Устройства и очереди (перевод)
- [Высокая производительность, Программирование, Apache, Big Data] Kafka Streams — непростая жизнь в production
- [Python] Поиск известных паттернов на Forex с Python
- [Машинное обучение, Искусственный интеллект, Natural Language Processing] Google обучила языковую модель ИИ на триллионе параметров
- [Python, Big Data, Разработка под e-commerce, Управление продуктом] Как мы в СберМаркете боремся с товарами-призраками
Теги для поиска: #_python, #_programmirovanie (Программирование), #_iskusstvennyj_intellekt (Искусственный интеллект), #_minizinc, #_python, #_constraint_programming, #_programmirovanie (программирование), #_python, #_programmirovanie (
Программирование
), #_iskusstvennyj_intellekt (
Искусственный интеллект
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 12:40
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Пожалуй, наиболее популярной парадигмой программирования является императивное программирование. Но это не единственный вид программирования, широко известны функциональное и логическое программирование. Constraint Programming (Программирование в ограничениях/Ограниченное программирование) не так популярно. Но это очень мощный инструмент для решения комбинаторных задач. Вместо реализации алгоритма, который решает задачу, с последующей тратой кучи времени на его отладку, рефакторинг и оптимизацию, программирование с ограничениями позволяет вам просто описать модель в специальном синтаксисе, а особая программа (решатель - solver) найдет решение за вас (или скажет, если их нет). Впечатляет, не правда ли? Мне кажется, каждый программист должен знать о такой возможности. Minizinc Вероятно, наиболее часто используемым инструментом программирования ограничений (по крайней мере, в образовательных целях) является minizinc. Он предоставляет IDE для объявления моделей и несколько встроенных решателей для поиска ответа. Вы можете скачать программу с официального сайта.Простая модель в MinizincРассмотрим пример решения модели, начнем с криптоарифметической задачи. В данном типе задач все буквы следует заменить цифрами с двумя условиями:
S E N D
+ M O R E = M O N E Y var 1..9: S;
var 0..9: E; var 0..9: N; var 0..9: D; var 1..9: M; var 0..9: O; var 0..9: R; var 0..9: Y; constraint 1000 * S + 100 * E + 10 * N + D
+ 1000 * M + 100 * O + 10 * R + E == 10000 * M + 1000 * O + 100 * N + 10 * E + Y; import zython as zn
class MoneyModel(zn.Model): def __init__(self): self.S = zn.var(range(1, 10)) self.E = zn.var(range(0, 10)) self.N = zn.var(range(0, 10)) self.D = zn.var(range(0, 10)) self.M = zn.var(range(1, 10)) self.O = zn.var(range(0, 10)) self.R = zn.var(range(0, 10)) self.Y = zn.var(range(0, 10)) self.constraints = [(self.S * 1000 + self.E * 100 + self.N * 10 + self.D + self.M * 1000 + self.O * 100 + self.R * 10 + self.E == self.M * 10000 + self.O * 1000 + self.N * 100 + self.E * 10 + self.Y), zn.alldifferent((self.S, self.E, self.N, self.D, self.M, self.O, self.R, self.Y))] model = MoneyModel() result = model.solve_satisfy() print(" ", result["S"], result["E"], result["N"], result["D"]) print(" ", result["M"], result["O"], result["R"], result["E"]) print(result["M"], result["O"], result["N"], result["E"], result["Y"]) 9567
+ 1085 = 10652 Интеграция с Pythonminizinc-python решает вторую проблему, предоставляя способ вызова моделей minizinc из python, библиотека будет запускать minizinc, сериализовать ваш ввод и разбирать вывод, но программист по-прежнему должен писать довольно много строк кода. Мы можем посмотреть на пример решения квадратного уравнения:SpoilerУ автора публикации сломался хабр и перестал выдавать список языков для подсветки синтаксиса в drop-down меню, если кто-то знает, как починить, буду очень признателен. import minizinc
# Create a MiniZinc model model = minizinc.Model() model.add_string(""" var -100..100: x; int: a; int: b; int: c; constraint a*(x*x) + b*x = c; solve satisfy; """) # Transform Model into a instance gecode = minizinc.Solver.lookup("gecode") inst = minizinc.Instance(gecode, model) inst["a"] = 1 inst["b"] = 4 inst["c"] = 0 # Solve the instance result = inst.solve(all_solutions=True) for i in range(len(result)): print("x = {}".format(result[i, "x"])) ZythonПочему бы не скрыть поиск решателя, создание экземпляров параметров, а также не предоставить способ реализации моделей на чистом Python?Это то, что делает zython (miniZinc pYTHON). Это самый простой способ погрузиться в программирование с ограничениями*.Spoiler* из того, что я знаю* по крайней мере, если вы разработчик на Python. :)Чтобы начать работу с zython, у вас должны быть установлены python 3.6+ и minizinc в путь по умолчанию или доступен в $PATH. После этого можно скачать сам пакет и проверить установку pip install zython
python >>> import zython as zn import zython as zn
class MoneyModel(zn.Model): def __init__(self): self.S = zn.var(range(1, 10)) self.E = zn.var(range(0, 10)) self.N = zn.var(range(0, 10)) self.D = zn.var(range(0, 10)) self.M = zn.var(range(1, 10)) self.O = zn.var(range(0, 10)) self.R = zn.var(range(0, 10)) self.Y = zn.var(range(0, 10)) self.constraints = [(self.S * 1000 + self.E * 100 + self.N * 10 + self.D + self.M * 1000 + self.O * 100 + self.R * 10 + self.E == self.M * 10000 + self.O * 1000 + self.N * 100 + self.E * 10 + self.Y), zn.alldifferent((self.S, self.E, self.N, self.D, self.M, self.O, self.R, self.Y))] model = MoneyModel() result = model.solve_satisfy() print(" ", result["S"], result["E"], result["N"], result["D"]) print(" ", result["M"], result["O"], result["R"], result["E"]) print(result["M"], result["O"], result["N"], result["E"], result["Y"]) import zython as zn
class MyModel(zn.Model): def __init__(self): self.a = zn.Array(zn.var(range(1, 10)), shape=(9, 9)) self.constraints = \ [zn.forall(range(9), lambda i: zn.alldifferent(self.a[i])), zn.forall(range(9), lambda i: zn.alldifferent(self.a[:, i])), zn.forall(range(3), lambda i: zn.forall(range(3), lambda j: zn.alldifferent(self.a[i * 3: i * 3 + 3, j * 3: j * 3 + 3]))), ] model = MyModel() result = model.solve_satisfy() print(result["a"]) Задача коммивояжёраПоскольку я обещал, что мы рассмотрим задачу коммивояжёра, давайте перейдём к ней. Данную модуль можно описать следующим образом: import zython as zn
class TSP(zn.Model): def __init__(self, distances): self.distances = zn.Array(distances) self.path = zn.Array(zn.var(range(len(distances))), shape=len(distances)) self.cost = (self._cost(distances)) self.constraints = [zn.circuit(self.path)] def _cost(self, distances): return (zn.sum(range(1, len(distances)), lambda i: self.distances[self.path[i - 1], self.path[i]]) + self.distances[self.path[len(distances) - 1], self.path[0]]) distances = [[0, 6, 4, 5, 8], [6, 0, 4, 7, 6], [4, 4, 0, 3, 4], [5, 7, 3, 0, 5], [8, 6, 4, 5, 0]] model = TSP(distances) result = model.solve_minimize(model.cost) print(result) =========== Источник: habr.com =========== =========== Автор оригинала: Artyom Kaltovich ===========Похожие новости:
Программирование ), #_iskusstvennyj_intellekt ( Искусственный интеллект ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 12:40
Часовой пояс: UTC + 5