1 / 44

Håkan Kjellerst rand (hakank@gmail) Independent Researcher, Malmö hakank/

What I (still) like about Constraint Programming. Håkan Kjellerst rand (hakank@gmail.com) Independent Researcher, Malmö http://www.hakank.org/ My Constraint Programming Blog: http://www.hakank.org/constraint_programming_blog/ This talk at SweConsNet 20130527:

nelia
Download Presentation

Håkan Kjellerst rand (hakank@gmail) Independent Researcher, Malmö hakank/

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. What I (still) like about Constraint Programming Håkan Kjellerstrand (hakank@gmail.com) Independent Researcher, Malmö http://www.hakank.org/ My Constraint Programming Blog: http://www.hakank.org/constraint_programming_blog/ This talk at SweConsNet 20130527: http://www.hakank.org/constraint_programming/sweconsnet_talk_20130527.ppt

  2. Some more about me * Not a theory guy, much more a modeling guy I like to solve a good puzzle – with CP. * I don't do CP professionally which might explain some things... * Co-organizer of the CP 2013 Workshop (in Uppsala, September) “CP Solvers: Modeling, Applications, Integration, and Standardization” http://cp2013.a4cp.org/workshops/cpsolvers Organizers: Jacob Feldman, Helmut Simonis, and me Constraint Solvers Catalog http://openjvm.jvmhost.net/CPSolvers/

  3. Tested ~24 CP Systems - Choco (21 models) - Comet (168 models) - ECLiPSe CLP (177 models) - Gecode (165 models) - Gecode/R (29 models) - JaCoP (18 models) - JaCoP/Scala (39 models) - MiniZinc (1031 models) - SICStus Prolog (152 models) - Essence'/Tailor (26 models) - Essence'/Savile Row (56 models) - Zinc (39 models) - Google or-tools/Python (202 models) - Google or-tools/Java (36 models) - Google or-tools/C# (129 models) - OscaR (Scala in OR) (146 models) - Java JSR-331 (42 models) - Numberjack (52 models) - AIMMS+CP (39 models) - B-Prolog (207 models) - Choco3 (90 models) - AMPL (100 "pure" CP models) - ILOG CP Optimizer OPL (as we speak, > 100 models) - Answer Set Programming ("related paradigm" 87 encodings) In total > 3200 models. Note: Not all of these are pure CP models, some are plain IP models.

  4. Common Constraint Programming Problems http://hakank.org/common_cp_models/ * I always start testing a CP system with a number of standard "learning" problems to get a feel for different constructs in the CP system. * Also, I always report bugs and whine about things I don't like (or is inconvenient/weird/etc) to the developers. * Forthcoming (perhaps) - Picat, http://picat-lang.org/ (available 20130531) - JaCoP v 4.0 - Gecode-python, https://launchpad.net/gecode-python (Python inteface to Gecode) - Copris, http://bach.istc.kobe-u.ac.jp/copris/ (Scala) - Clojure core.logic, https://github.com/clojure/core.logic - or-tools/C++ (no syntactic sugar at all...) - new MiniZinc solvers Other suggestions?

  5. So, what do I (still) like about Constraint Programming? In short: The modeling part, the ease of modeling many types of problems. Some CP features: - element - reification - generating 1/N/all solution(s) - global constraints - reversibility/bidirection - nonlinear constraints - symmetry breaking - declarative (high level) - nifty language features (wish list) Many of these features was what caught my interest (blew my mind) in 2008 after checking out mathematical programming some year earlier. Hence the “still”.

  6. Element constraint The “signum” of Constraint Programming. * Good example (IMHO): x[y] = z; % MiniZinc, similar Essence' cp.add(x(y) == z, Strong); // OscaR (Scala) * OK: rel(*this, z == element(x, y); // Gecode * Not so good: solver.addConstraint( solver.makeEquality(z, solver.makeElement(x, y).var())); // or-tools/Java Yes, I punish certain host languages (e.g. Java) that don't have operator overloading. AMPL: can simulate element with “exists”. Here 1..n is the domain of y. s.t. c1: exists{j in 1..n} j = y and x[j] = z;

  7. Reification * alldifferent_except_0 Implementing a decomposition of this constraint is often a good proxy of the "syntactical sugarness" of a CP system. It's one of the first things I test. * good example: MiniZinc, Zinc, Comet, Essence' % MiniZinc version forall(i, j in 1..length(x) where i < j) ( (x[i] != 0 /\ x[j] != 0) -> x[i] != x[j] ) * good example: Gecode for(int i = 0; i < x.size(); i++) { for(int j = i+1; j < x.size(); j++) { rel(space, (x[i] != 0 && x[j] != 0) >> (x[i] != x[j]), Icl); } }

  8. Reification Choco3 (beta) // only half-reification (might be easier in fortcoming versions) BoolVar[] b = VariableFactory.boolArray("b_"+i+"_"+j, 3, solver); solver.post(IntConstraintFactory.implies(b[0], (IntConstraintFactory.arithm(v[i], "!=", c)))); solver.post(IntConstraintFactory.implies(VariableFactory.not(b[0]), (IntConstraintFactory.arithm(v[i], "=", c)))); solver.post(IntConstraintFactory.implies(b[1], (IntConstraintFactory.arithm(v[j], "!=", c)))); solver.post(IntConstraintFactory.implies(VariableFactory.not(b[1]), (IntConstraintFactory.arithm(v[j], "=", c)))); solver.post(IntConstraintFactory.implies(b[2], (IntConstraintFactory.arithm(v[i], "!=", v[j])))); solver.post(IntConstraintFactory.implies(VariableFactory.not(b[2]), (IntConstraintFactory.arithm(v[i], "=", v[j])))); ALogicTree t = Node.implies(Node.and(Literal.pos(b[0]), Literal.pos(b[1])), Literal.pos(b[2]) ); solver.post(IntConstraintFactory.clauses(t, solver));

  9. Generating 1/N/all solution(s) * Debugging Example: 8-queens should have 92 solutions, otherwise the model is wrong. Or - much rarer - the solver is wrong. Later: This assumes that no symmetry breaking is used. (Thanks Mats Carlsson.) I use this very much. In the current AMPL+Gecode implementation this is not implemented which was quite strenuous.. * Ensure unicity of a solution, e.g. a Sudoku problem (set the numbet of solution to 2 and expect just 1) * Certain combinatorial problems is about counting the number of solutions. * Generating problem instances This is - kind of - the reverse of solving a problem, by letting all decision variable be free. E.g. "Drive Ya Nuts". * Special case Search for optimal value and then generate all solutions with that value. No CP system has this as built-in. Hint, hint :-)

  10. Global constraints Global Constraint Catalog (364 listed global constraints) http://www.emn.fr/z-info/sdemasse/gccat/index.html Advantages * Special tailored propagators This is the usual sale pitch for global constraints. * For me: the modeling part High level concepts as "patterns" in modeling * Some personal favorites all_different all_different_except_0 element ( x[y] = z) global_cardinality_count decrease/increase (sortedness) regular (finite state machine) cumulative (for scheduling like problems) circuit (Hamiltonian circuit) table (allowed assignments) inverse (useful in some puzzles :) http://hakank.org/minizinc/#global (~170 decompositions in MiniZinc, more or less general)

  11. Reversibility (bi-direction) Simple example: convert a number ("num") to/from its digits ("x"). // MiniZinc (general predicate, base 10) predicate toNum(array[int] of var int: a, var int: n) = let { int: len = length(a) } in n = sum(i in 1..len) ( pow(10,len-i) * a[len-i+1] ); var 0..999: num; array[1..3] of var 0..9: x; constraint toNum(x, num) /\ num % 2 = 1 /\ % constraint on num: is an odd number x[2] > 5; % constraint of digits: second digits > 5 - more general: channelling/dual model

  12. Nonlinear constraints * Compared to (traditional) IP modeling, there is much less need to reformulate/linearize nonlinear constraints. * There is no need to remember which IP solver it is that handle that nonlinear constraints (quadratic etc). * No big M's! Though we want as small domains as possible.

  13. Symmetry breaking Pruning the search tree. Global constraints: - increasing/decreasing - lex family - precedence Some system supports dynamic symmetry breaking, e.g. Chris Mears' Lightweight Dynamic Symmetry Breaking (LDSB) http://www.cmears.id.au/symmetry/ Supported by: - ECLiPSe CLP - Gecode ECLiPSe CLP also has support for - Symmetry Breaking During Search (SBDS) - GAP-based Symmetry Breaking via Dominance Detection (SBDD)

  14. Declarative, high level Note: I'm not sure how to define "declarative", but I know it when I see it. :-) http://en.wikipedia.org/wiki/Declarative_programming The introduction: “In computer science, declarative programming is a programming paradigm that expresses the logic of a computation without describing its control flow. Many languages applying this style attempt to minimize or eliminate side effects by describing what the program should accomplish, rather than describing how to go about accomplishing it (the how is left up to the language's implementation). This is in contrast with imperative programming, in which algorithms are implemented in terms of explicit steps.“ Sometimes it's hard claiming declarativness of CP modeling when the code is full of for(all) loops. Though, I still insist that it's declarative... High level: The higher, the better (IMHO), at least for prototyping.

  15. What I (still) don't like about CP - Can be hard to debug "Everything happens at once" is brilliant, but can also be hard to debug. I tend to rely on “printf-debugging“and removing all constraints and then put them back one after another (or testing after adding each single constraint). - For more complex problems: must use search heuristics (or remodel) Getting the heuristics right is (still) “an art, not a science”. There are some Black Box solvers/heuristics, but - IMHO - they need to be tweaked as well. Examples: - Gecode (v 4.0): AFC variants, Activity-Based - Choco 3: Activity-Based, Impact-Based - or-tools: Impact-Based - ILOG CP Optimizer: recommends to use no labeling at all first Question: Is black box solvers a realistic/interesting/feasible goal for CP research?

  16. Nifty language features I Some of these features are not unique to CP, but are very handy. Many are just syntactic sugar. - “syntactic sugar is everything” (hakank) If you want to make me happy, implement as many of these as possible. :-) Some may be possible only for new dedicated CP languages or DSL. - element as x[y] = z where x, y, and z (or at least y) are decision variables - general matrix element Gecode and Choco2 has some support for this

  17. Nifty language features II • - “exists” • Supported by MiniZinc and AMPL+CP. • Useful when the range in a forall loop is dynamic; • or instead of declaring a temporary decision variable (might give • worse propagation). • Small example (MiniZinc): • % z is a decision variable used elsewhere • exists(i in 1..n) ( • z = i /\ • forall(j in i+1..n) ( x[j] = 0) • ) • - array/set comprehension • % MiniZinc • forall(i in 1..n) ( • alldifferent([x[i,j] | j in 1..n where cost[i,j] > 0]) • )

  18. Nifty language features III - “external loops” Which all host languages have (except some Prolog's). This is one of the feature I miss most in MiniZinc, i.e. the possibilty to do simple for loops, e.g. to create temporary variables, counting etc. - if-then-else on decision variables as well as non-decision variables Example: AIMMS and (sometimes) AMPL. In most other CP system one have to use reifications or dedicated methods like: ifThenElse(condition,thenclause, elseclause) or % MiniZinc (condition → then clause) /\ (not(condition) → else clause) Choco3 - current beta version - only support half-reification which is a nuisance. (See earlier slide.)

  19. Nifty language features IV - predicates (functions) Is – surprisingly - not supported in some of the high level systems such as AMPL, OPL and Essence'. - set variables Sometimes extremely useful. (I definitely respect the complexity of this.) - Systematically testing all variable and value heuristics It would be nice to have a simple way of systematically testing all variable + value heuristics on a model, e.g. with a simple flag. I haven't seen this in any system yet, and in some it's quite easy to implement.

  20. Thank you! - Questions? - Comments? Hakan Kjellerstrand (hakank@gmail.com) http://www.hakank.org/

  21. CP bloggers There are few CP bloggers (tweeters etc) compared to the OR bloggers. - Jean-Charles Regin/Pierre Schaus: "CP is fun" http://cp-is-fun.blogspot.com/ - Jacob Feldman: "CP Standardization Blog" http://cpstandard.wordpress.com/ - Helmut Simonis: "CP Applications Blog" http://hsimonis.wordpress.com/ - Hakan Kjellerstrand: My Constraint Programming Blog http://www.hakank.org/constraint_programming_blog/ Some OR people that sometimes blog about CP. (See next slide.)

  22. OR people that sometimes blog about CP Here are some great OR-bloggers that sometimes mention CP: - Mike Trick: "Michael Trick’s Operations Research Blog" http://mat.gsia.cmu.edu/blog/ - Jean-Francois Puget: "IT Best Kept Secret Is Optimization" https://www.ibm.com/developerworks/community/blogs/jfp/?lang=en - Erwin Kalvelagen: "Yet Another Math Programming Consultant" http://yetanothermathprogrammingconsultant.blogspot.com/ - Paul Rubin: “OR in an OB World” http://orinanobworld.blogspot.com

  23. all_different_except_0: decomposition in different CP systems Implementation of all_different_except_0 in different CP systems: - proxy for “ease of modelling” - overloading of operators (if possible) - logical operators - reification Note: It's not the only way to encode this constraint.

  24. all_different_except_0: decomposition G12 MiniZinc forall(i, j in 1..length(x) where i < j) ( (x[i] > 0 /\ x[j] > 0) -> x[i] != x[j] )‏ Comet int n = x.getSize(); forall(i in 1..n, j in i+1..n) { m.post(x[i] > 0 && x[j] > 0 => x[i] != x[j]); }

  25. all_different_except_0: decomposition Choco2 for(int i = 0; i < v.length; i++) { for(int j = i+1; j < v.length; j++) { m.addConstraint(ifThenElse( and( gt(v[i], 0), gt(v[j], 0)‏ ), neq(v[i], v[j]), TRUE)‏ ); } }

  26. all_different_except_0: decomposition JaCoP for(int i = 0; i < v.length; i++) { for(int j = i+1; j < v.length; j++) { m.impose(new IfThen( new And( new XneqC(v[i], 0), new XneqC(v[j], 0)‏ ), new XneqY(v[i], v[j])‏ )‏ ); } }

  27. all_different_except_0: decomposition JaCoP/Scala for(i <- 0 until y.length; j <- 0 until i) { val b = new BoolVar("b") b <=> AND((y(i) #\= 0), (y(j) #\= 0)); b -> (y(i) #\= y(j)) }

  28. all_different_except_0: decomposition Gecode for(int i = 0; i < x.size(); i++) { for(int j = i+1; j < x.size(); j++) { rel(space, (x[i] != 0 && x[j] != 0) >> (x[i] != x[j]), icl); } }

  29. all_different_except_0: decomposition Gecode/R n = x.length b1_is_an bool_var_matrix(n,n)‏ b2_is_an bool_var_matrix(n,n)‏ b3_is_an bool_var_matrix(n,n)‏ n.times{|i| n.times{|j| if i != j then x[i].must_not.equal(0, :reify => b1[i,j])‏ x[i].must_not.equal(0, :reify => b2[i,j])‏ x[i].must_not.equal(x[j], :reify => b3[i,j])‏ (b1[i,j] & b2[i,j]).must.imply(b3[i,j])‏ else b1[i,j].must.true b2[i,j].must.true b3[i,j].must.true end } }

  30. all_different_except_0: decomposition ECLiPSe CLP alldifferent_except_0(Xs) :- dim(Xs, [Len]), labeling(Xs), ( for(I, 1, Len) * for(J, 1, Len), param(Xs) do ( I \= J, Xs[I] #\= 0, Xs[J] #\= 0 )‏ -> Xs[I] #\= Xs[J] ; true ).

  31. all_different_except_0: decomposition SICStus Prolog alldifferent_except_0(Xs) :- ( foreach(X,Xs) do indomain(X)), ( foreach(XI,Xs), count(I,1,_), param(Xs) do ( foreach(XJ,Xs), count(J,1,_), param(I,XI) do I < J, XI #\=0, XJ #\=0 -> XI #\= XJ ; true ) ).

  32. all_different_except_0: decomposition Essence' forall i,j : int(1..n) . ( (i != j) => (((x[i] != 0) /\ (x[j] != 0)) => (x[i] != x[j]))‏ ),

  33. all_different_except_0: decomposition G12 Zinc forall(i,j in index_set(x) where i != j) ( (x[i] > 0 /\ x[j] > 0) -> x[i] != x[j] )

  34. all_different_except_0: decomposition or-tools/Python n = len(a) for i in range(n): for j in range(i): s.Add((a[i] != 0) * (a[j] != 0) <= (a[i] != a[j]))

  35. all_different_except_0: decomposition or-tools/Java int n = a.length; for(int i = 0; i < n; i++) { for(int j = 0; j < i; j++) { IntVar bi = s.makeIsDifferentCstVar(a[i], 0); IntVar bj = s.makeIsDifferentCstVar(a[j], 0); IntVar bij = s.makeIsDifferentCstVar(a[i], a[j]); solver.addConstraint( s.makeLessOrEqual( s.makeProd(bi, bj).var(), bij)); } }

  36. all_different_except_0: decomposition or-tools/C# int n = a.Length; for(int i = 0; i < n; i++) { for(int j = 0; j < i; j++) { s.Add((a[i] != 0) * (a[j] != 0) <= (a[i] != a[j])); } }

  37. all_different_except_0: decomposition AIMMS+CP CONSTRAINT: identifier : CAllDifferentExcept0 index domain : (i,j) | i < j definition : if (x(i) <> 0 and x(j) <> 0) then x(i) <> x(j) endif;

  38. all_different_except_0: decomposition AMPL+CP s.t. alldifferent_except0{i in dom,j in dom: i < j}: (x[i] > 0 && x[j] > 0) ==> (x[i] != x[j]);

  39. all_different_except_0: decomposition B-Prolog alldifferent_except_0(Xs) :- Len @= Xs^length, foreach(I in 1..Len, J in 1..Len, (I #\=J #/\ Xs[I] #\= 0 #/\ Xs[J] #\= 0) #=> (Xs[I] #\= Xs[J])).

  40. all_different_except_0: decomposition Choco 3 (beta version) BoolVar[] b = VariableFactory.boolArray("b_"+i+"_"+j, 3, solver); solver.post(IntConstraintFactory.implies(b[0], (IntConstraintFactory.arithm(v[i], "!=", c)))); solver.post(IntConstraintFactory.implies(VariableFactory.not(b[0]), (IntConstraintFactory.arithm(v[i], "=", c)))); solver.post(IntConstraintFactory.implies(b[1], (IntConstraintFactory.arithm(v[j], "!=", c)))); solver.post(IntConstraintFactory.implies(VariableFactory.not(b[1]), (IntConstraintFactory.arithm(v[j], "=", c)))); solver.post(IntConstraintFactory.implies(b[2], (IntConstraintFactory.arithm(v[i], "!=", v[j])))); solver.post(IntConstraintFactory.implies(VariableFactory.not(b[2]), (IntConstraintFactory.arithm(v[i], "=", v[j])))); ALogicTree t = Node.implies(Node.and(Literal.pos(b[0]), Literal.pos(b[1])), Literal.pos(b[2]) ); solver.post(IntConstraintFactory.clauses(t, solver));

  41. all_different_except_0: decomposition Numberjack return [ ( ((a != 0) & (b != 0)) <= (a != b ) ) for a, b in pair_of(x)]

  42. all_different_except_0: decomposition OscaR (Scala) for(i <- 0 until y.length; j <- 0 until i) { cp.add( ((y(i) !== 0) && (y(j) !== 0)) ==> (y(i) !== y(j)) ) }

  43. all_different_except_0: decomposition JSR-331 for(int i = 0; i < v.length; i++) { for(int j = i+1; j < v.length; j++) { Constraint c1 = p.linear(v[i],"!=", 0); Constraint c2 = p.linear(v[j],"!=", 0); Constraint c3 = p.linear(v[i],"!=", v[j]); p.postIfThen(c1.and(c2), c3); } }

  44. all_different_except_0: decomposition Answer Set Programming (“related paradigm”) #const n = 6. #const m = 9. values(0..m). ix(1..n). % unique indices of x, 1..n 1 { x(I, Val) : values(Val) } 1 :- ix(I). % alldifferent except 0: % If Val > 0 then there must be 0..1 % occurrences of Val in x. { x(I, Val) : ix(I) } 1 :- values(Val), Val > 0.

More Related