Picat a new logicbased multiparadigm programming language Hkan
Picat - a new logic-based multi-paradigm programming language. Håkan Kjellerstrand (hakank@gmail. com) Independent Researcher, Malmö http: //www. hakank. org/ My Constraint Programming Blog: http: //www. hakank. org/constraint_programming_blog/ My Picat page: http: //www. hakank. org/picat/ Talk at Swe. Cons. Net Workshop 2014 -06 -13 http: //web. it. kth. se/~cschulte/events/Swe. Cons. Net-2014/
Picat – a new programming language * http: //picat-lang. org/ * Neng-Fa Zhou, creator (together with Jonathan Fruhman)/main developer Picat timeline: * Around 2012 -12 -06: Public specification Announced by Neng-Fa Zhou and Jonathan Fruhman (comp. lang. prolog) * 2013 -06 -01: alpha release v 0. 1 * 2014 -02 -03: stable version: v 0. 1 * 2014 -04 -01: stable version: v 0. 2#1 * 2014 -05 -23: Current release: v 0. 3
Picat - multi-paradigm: P I C A T PICAT: - P: Pattern matching Much like Haskell's pattern matching (and some like Prolog's) - I: Imperative While loops, (re)assignments, list comprehensions - C: Constraints Most from B-Prolog - A: Action rules Most from B-Prolog. Will not mention this more. - T: Tabling From B-Prolog And: - Logic based - Planner - Functions This talk will focus on Constraints, but other features are mentioned as well.
Picat – some (un)published papers * Roman Barták, Neng-Fa Zhou: Using Tabled Logic Programming to Solve the Petrobras Planning Problem (Theory and Practice of Logic Programming, 2014), http: //arxiv. org/abs/1405. 2501 * Neng-Fa Zhou, Hakan Kjellerstrand: Solving Several Planning Problems with Picat (CCDC, 2014) * Håkan Kjellerstrand: My First Look At Picat as a Modeling Language for Constraint Solving and Planning (CCDC, 2014) http: //www. hakank. org/picat/a_first_look_at_picat. pdf * Neng-Fa Zhou, Roman Barták, Agostino Dovier, Hakan Kjellerstrand: Tabling for Planning (DSW 2013) * Neng-Fa Zhou: Combinatorial Search With Picat (ICLP, 2014), http: //arxiv. org/abs/1405. 2538
Picat – introduction (definition of member/2) * Prolog based (non-deterministic and reversible): member(X, [Y|_]) ? => X=Y. member(X, [_|L]) => member(X, L) * Imperative (not reversible): member(X, List) => Found = false, foreach(I in 1. . List. length, Found = false) if List[I] = X then Found : = true end % this stops the loop end, % check if found Found = true. (member/2 is a built-in)
Constraint programming: SEND + MORE = MONEY % Much like any CLP import cp. go => sendmore(Digits), println(Digits). sendmore(Digits) => Digits = [S, E, N, D, M, O, R, Y], Digits : : 0. . 9, all_different(Digits), S #> 0, M #> 0, 1000*S + 100*E + 10*N + D + 1000*M + 100*O + 10*R + E #= 10000*M + 1000*O + 100*N + 10*E + Y, solve(Digits).
Constraint programming – reification (alldifferent_except_0) % Ensure that all values in Xs which are != 0 are different. alldifferent_except_0(Xs) => foreach(I in 1. . Xs. length, J in 1. . I-1) (Xs[I] #!= 0 #/ Xs[J] #!= 0) #=> (Xs[I] #!= Xs[J]) end. go => N = 5, X = new_list(N), X : : 0. . N, alldifferent_except_0(X), solve(X), println(X). Notes: - reification as in traditional Prolog CLPFD. - array indexing: Xs[I] requires that index I is instantiated (i. e. no decision variables)
Constraint programming – list comprehension (N-queens) import cp. queens(N, Q) => Q=new_list(N), Q : : 1. . N, all_different(Q), % list comprehension all_different([$Q[I]-I : I in 1. . N]), all_different([$Q[I]+I : I in 1. . N]), solve([ff], Q). Note the '$': Q is a term which must be “escaped”. * Timing (for first solution): N=100: 0. 03 s, 22 backtracks N=499: 1. 1 s, 1 backtrack N=501: 0. 63 s, 1 backtrack N=1000: 2. 7 s, 2 backtracks N=1500: 8. 7 s 2889 backtracks
Constraint programming – Optimization (Coins problem) % Minimize the number of coins used to ensure all changes of 1. . 99 cent % Solution: Num. Coins=8, X=[1, 2, 1, 1] go => Variables = [1, 2, 5, 10, 25, 50], % the denominations N = length(Variables), Xs = new_list(N), Xs : : 0. . 99, Num. Coins #= sum(Xs), foreach(J in 1. . 99) Tmp = new_list(N), Tmp : : 0. . 99, scalar_product(Variables, Tmp, J), % ensure we don't use more coins than in X[I] foreach(I in 1. . N) Tmp[I] #=< Xs[I] end, solve($[min(Num. Coins)], Xs). scalar_product(A, X, Product) => product #= sum([A[I]*X[I] : I in 1. . A. length]).
Constraint programming – Sudoku go => problem(1, Board), time 2(sudoku 2(3, Board)) sudoku(N, Board) => N 2 = N*N, Vars = Board. vars(), Vars : : 1. . N 2, foreach(Row in Board) all_different(Row) end, foreach(Column in transpose(Board)) all_different(Column) end. foreach(I in 1. . N 2, J in 1. . N 2) all_different([Board[I+K, J+L] : K in 0. . N-1, L in 0. . N-1]) end, solve([ff, down], Vars). problem(1, Data) => Data = [[_, _, 2, _, _, 5, _, 7, 9], [1, _, 5, _, _, 3, _, _, _], % ….
Constraint programming – built-in global constraints Built-in global constraints (as of v 0. 3) all_different(List), all_distinct(List) assignment(List 1, List 2) (a. k. a. inverse/2) circuit(List) count(Value, List, Rel, N) cumulative(Starts, Durations, Resources, Limit) diffn(Rectangle. List) disjunctive_tasks(Tasks) element(I, List, V) global_cardinality(List, Pairs) neqs(Neg. List) X notin Domain serialized(Starts, Durations) subcircuit(List) table_in(List, Allowed) table_notin(List, Not. Allowed)
Constraint programming – built-ins boolean constraints Boolean constraints: • # Bool. Exp • Bool. Exp 1 #/ Bool. Exp 2 • Bool. Exp 1 #ˆ Bool. Exp 2 • Bool. Exp 1 #/ Bool. Exp 2 • Bool. Exp 1 #=> Bool. Exp 2 • Bool. Exp 1 #<=> Bool. Exp 2 : not : and : xor : implication : equivalence
Common interface to CP, SAT and MIP solvers * Picat also have a SAT solver (Lingeling, Mini. SAT) and a MIP solver (GLPK). * Same syntax (constraints and #= etc). Only need to change: import cp. to import sat. % or import mip. * sat and mip supports CP constraints, e. g. all_different/1, element/1, and circuit/1 * sat support backtracking * mip don't support non linear constraints (linearization of “*” for small domains) * only one of cp/sat/mip modules can be active
Functions Picat supports a kind of functional programming. % List 2 = take(List, N): take the first N values of list List take(_Xs, 0) = []. take([], _N) = []. take([X|Xs], N) = [X] ++ take(Xs, N-1). fib(0) = 1. fib(1) = 1. fib(N) = fib(N-1) + fib(N-2). - functions never fails - however: Picat don't support lambdas - pattern matching: like Haskell
Tabling – memoization and dynamic programming % memoization table fibt(0)=1. fibt(1)=1. fibt(N)=F, N>1 => F=fibt(N-1)+fibt(N-2). Picat> time(fibt(10000)=F) % 0. 33 seconds % minimal editing distance of two lists table(+, +, min) edit([], D) => D=0. edit([X|Xs], [X|Ys], D) => % copy edit(Xs, Ys, D). edit(Xs, [_Y|Ys], D) ? => % insert edit(Xs, Ys, D 1), D=D 1+1. edit([_X|Xs], Ys, D) => % delete edit(Xs, Ys, D 1), D=D 1+1.
Planner module The planner module is based on tabling. * Init. State Define the initialization state (the first From. State) * final(State) Define the goal state(s)/definition, checks if the goal state has been reached. * action(From. State, To. State, Move, Cost) Define the action predicates (the legal moves) * plan*: predicate with the appropriate arguments, e. g. - plan(Start, Limit, Plan. Cost) - plan(Start, Limit, Plan) - best_plan(Start, Limit, Plan. Cost) - best_plan(Start, Limit, Plan) - etc
Planning module – example M 12 import planner. go => Init = [8, 11, 6, 1, 10, 9, 4, 3, 12, 7, 2, 5], % minimum # steps: 27 best_plan_downward(Init, Plan), writeln(Plan). final(Goal) => Goal = 1. . 12. table % merge action (perfect shuffe) action([M 1, M 12, M 11, M 3, M 10, M 4, M 9, M 5, M 8, M 6, M 7], To, M, Cost) ? => Cost=1, M=m, To=[M 1, M 2, M 3, M 4, M 5, M 6, M 7, M 8, M 9, M 10, M 11, M 12]. % reverse action (reverse list) action([M 12, M 11, M 10, M 9, M 8, M 7, M 6, M 5, M 4, M 3, M 2, M 1], To, M, Cost) => Cost=1, M=r, To=[M 1, M 2, M 3, M 4, M 5, M 6, M 7, M 8, M 9, M 10, M 11, M 12]. % [m, m, m, r, m, r, m, m, m, r] % ~1 s
Picat – other features Some other features not mentioned: * Picat shell (as Prolog shell) * debugging: as Prolog (trace, debug) * most Prolog basic predicates (e. g. var/1, nonvar/1, insert/3, delete/2) * maps (hash tables), global maps * modules: basic, os, sys, math, util, ordset * IO: read_file_bytes/1, read_file_chars(), etc * can call B-Prolog (“bp. <predicate>”) * can read B-Prolog compiled files * interface to PRISM (probabilistic reasoning and learning) * Picartesius: Picat extension in Excel (Lorenz Schiffmann) http: //sourceforge. net/projects/picartesius/
Picat – my models / programs My Picat models: - http: //www. hakank. org/picat/ - Git. Hub: https: //github. com/hakank/tree/master/picat * CP (and some SAT): 279 models * MIP (IP/LP): 30 models * Project Euler: 52 programs (some CP solutions) * Rosetta Code: 69 programs * Planning: about 40 programs * Misc: about 65 programs In total about 530 models/programs.
Why I like Picat - Different paradigms in one system * CP (quite high level) * same encoding can be used for SAT and MIP * logic programming * imperative programming * functional programming (kind of) * planner module - Suites my mind set
Thank you! Questions? My Picat page: http: //www. hakank. org/picat/ Git. Hub: https: //github. com/hakank/tree/master/picat
- Slides: 21