Constraint-Programmierung oder wie man das Problem des Handlungsreisenden löst, indem man es einfach beschreibt

Das vielleicht beliebteste Programmierparadigma ist die imperative Programmierung. Dies ist jedoch nicht die einzige Art der Programmierung. Funktionale und logische Programmierung sind weithin bekannt. Constraint Programming ist nicht so beliebt. Aber es ist ein sehr leistungsfähiges Werkzeug zur Lösung kombinatorischer Probleme. Anstatt einen Algorithmus zu implementieren, der ein Problem löst, und dann viel Zeit mit dem Debuggen, Refactoring und Optimieren zu verbringen, können Sie mit der Constraint-Programmierung das Modell einfach in einer speziellen Syntax beschreiben, und ein spezielles Programm (Solver) findet die Lösung für Sie (oder ermittelt, ob Sie sind nicht da). Beeindruckend, nicht wahr? Es scheint mir, dass jeder Programmierer sich dieser Möglichkeit bewusst sein sollte.





Minizinc

Das wahrscheinlich am häufigsten verwendete Tool zur Programmierung von Einschränkungen (zumindest für Bildungszwecke) ist Minizinc . Es bietet eine IDE zum Deklarieren von Modellen und mehrere integrierte Löser zum Finden einer Antwort. Sie können das Programm von der offiziellen Website herunterladen .





Einfaches Modell in Minizinc

Betrachten wir ein Beispiel für die Lösung des Modells und beginnen wir mit einem kryptoarithmetischen Problem. Bei dieser Art von Problem sollten alle Buchstaben durch Zahlen mit zwei Bedingungen ersetzt werden:





  • Gleichheit muss gelten





  • Die gleiche Nummer darf nicht unterschiedlichen Buchstaben entsprechen und umgekehrt.





Lösen wir zum Beispiel die folgende Gleichung:





    S E N D
+   M O R E
= M O N E Y
      
      



Modellstruktur

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) - , , :).





:





include "alldifferent.mzn";

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;

constraint alldifferent([S,E,N,D,M,O,R,Y]);

solve satisfy;

output ["   ",show(S),show(E),show(N),show(D),"\n",
        "+  ",show(M),show(O),show(R),show(E),"\n",
        "= ",show(M),show(O),show(N),show(E),show(Y),"\n"];

      
      



Minizinc :





   9567
+  1085
= 10652
      
      



minizinc satisfy , , minizinc , , :).





Minizinc , constraint programming. , .





Python

minizinc-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 bietet eine Möglichkeit, das Constraint-Programmiermodell in reinem Python auszudrücken und dieses Problem einfach zu lösen. Weitere Beispiele finden Sie in der Dokumentation .





Konstruktive Kritik, Meinungsäußerung in Kommentaren, Fehlerberichten, Feature-Anfragen und PR wird genehmigt.





Viel Glück beim Erlernen der eingeschränkten Programmierung.








All Articles