Beim Constraint Programming geht es primär darum ein Problem durch die Modellierung von Constraints zu definieren. Im Gegensatz zu herkömmlichen Algorithmen wird dabei nicht der Lösungsweg vorgegeben, sondern das Problem selbst beschrieben und über Constraints eingegrenzt.
Für den Einsatz von Constraint Programming eignen sich vor allem Probleme, die sich einfach durch Regeln und Gesätze ausdrücken lassen. So spielt Constraint Programming zum Beispiel in folgenden Bereichen eine Rolle:
Um ein Problem mit dem Ansatz des Constraint Programming lösen zu können, muss es als Constraint Satisfaction Problem - CSP modelliert werden.
Ein Constraint Satisfaction Problem kann als Tripel definiert werden, bestehend aus:
Jedes Constraint ist definiert als ein Paar , wobei:
Eine Belegung ist ein Tupel , mit . Eine Belegung weist also einer Variablen ein Wert aus der jeweiligen Domäne zu.
Um eine Lösung für ein Constraint Satisfaction Problem zu finden, suchen wir nach einer vollständigen Belegung, eine Menge an Belegungen, bei der jeder freien Variable ein Wert zugeteilt wird. Damit eine solche vollständige Belegung nun eine passende Lösung unseres Problems darstellt müssen alle Constraints eingehalten werden. Für alle Belegungen muss also gelten: wenn die Variable der Zuteilung ein Element eines Scopes eines Constraints ist, so muss die zugeteilte Wert ein Element der Relation sein.
Für die Suche einer Lösung kommen Constraint Librarys zum Einsatz. Diese besitzen zur Lösungsfindung Constraint Solver - hoch optimierte Algorithmen, die sehr effizient den Suchbaum zu durchsuchen.
Die einfachste Suche stellt dabei ein einfacher Backtracking-Alogorithmus dar, welcher systematisch alle möglichen Belegungen ausprobiert und bei Verletzung eines Constraints zu einem vorherigen Zustand zurückspringt. Dieser Ansatz kann jedoch ineffizient sein, weshalb moderne Solver zahlreiche Optimierungen wie Heuristiken, Constraint Propagation und Konfliktanalyse einsetzen, um den Suchraum drastisch zu verkleinern. Im Folgenden wollen wir uns einige einfache Optimierungen genauer anschauen.
Eine einfache Optimierung zum Backtracking-Algorithmus ist das Forward Checking. Dabei wird nach jeder Zuweisung einer Varibale alle Werte der Domänen der übrigen Varibalen entfernt, die im Konflikt mit der aktuellen Zuweisung stehen. Damit ist es möglich die Domänen und damit auch den Suchbaum schon frühzeitig im Verlauf deutlich einzuschränken und damit deutlich an Effizienz zu gewinnen.
Die Abbildung veranschaulicht Forward Checking am Beispiel des 6-queens Problems. Durch das Setzen einer Dame können wir nach jedem Zug schon Felder streichen, die im Konflikt mit der gerade gesetzten Dame stehen. Als Folge lässt sich der Suchbaum deutlich reduzieren.
Der MAC Algorithmus folgt einem ähnlichen Prinzip wie der Forward Checking Algorithmus. Jedoch geht er noch einen Schritt weiter indem nach jeder Zuweisung alle Werte der Domänen entfernt werden, die:
Damit lässt sich der Suchbaum noch einmal frühzeitg deutlich reduzieren.
Apt, Krzysztof. Principles of constraint programming. Cambridge university press, 2003. book ↩︎
Rossi, Francesca, Peter Van Beek, and Toby Walsh, eds. Handbook of constraint programming. Elsevier, 2006. pdf ↩︎
Brailsford, Sally C., Chris N. Potts, and Barbara M. Smith. "Constraint satisfaction problems: Algorithms and applications." European journal of operational research 119.3 (1999): 557-581. pdf ↩︎ ↩︎ ↩︎