Advertisement
JosepRivaille

LI - Gangsters

Jun 23rd, 2017
127
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Prolog 11.36 KB | None | 0 0
  1.  
  2. %% The mafia has a lot gangsters for doing different tasks.
  3. %% These tasks are planned every 3 days (72h), according to a forecast
  4. %% of the tasks to be done every hour.
  5. %% No gangster can do two different tasks during the same hour or on two consecutive hours.
  6. %% Some gangsters are not available on certain hours.
  7. %% We want to plan all tasks (which gangster does what task when) and
  8. %% we want to find the minimal K such that no gangster works more than
  9. %% K consecutive hours.
  10.  
  11.  
  12. %% EXAMPLE OUTPUT:
  13. %%
  14. %%                       10        20        30        40        50        60        70  
  15. %%               123456789012345678901234567890123456789012345678901234567890123456789012
  16. %%
  17. %% gangster g01: ------------------------------p-------p-----p----p----p--------------p--
  18. %% gangster g02: ------p--p-p--------------p--ppp-----pp---pp-----p----p---p----p--------
  19. %% gangster g03: -p----p--p-p-p--p-------p-----pp-pp-p-pp-pppp--pp--p-pp-pppp--p-------p-
  20. %% gangster g04: -pp---p--p--pp----pp-p-pp-p-p-pppppp-cc-p--c----pppppp-p-c-p--ppp--p-p--
  21. %% gangster g05: pppppppppppppp--p-pp-p-ppppp-c--cc-p-cc-c-c-p--ppppppp-c-c-pppppppppppp-
  22. %% gangster g06: pp-c--c-c-cc-pp-p-pppppppppp-c--ccc-ccc-c-c-ppppp-cc-p-c-c-pppppp-cc-ppp
  23. %% gangster g07: -c-c-cc-c-cccc--ppp-c-pp-c-cccccccc-ccccccccc--c--ccccccccc-c--cc-cccc-p
  24. %% gangster g08: ccccccccc-cccc-p-c-cccc--c-ccccccccc-k-ccccccc-cccccccc-k-p-c-ccc-ccccc-
  25. %% gangster g09: k--k-c-k-cc-k--cccc-k-ccccc-k-c-k-c-kk-k-c-k-cccc-kk-cc-kk--cccccccccccc
  26. %% gangster g10: k--k-c-k--k-k-cc-kkkk-k--k-kkk-kk-k-kk-k-c-kkkk--kkk-kkkkk-c-kkkk--k--k-
  27. %% gangster g11: k-kkk--k--kkkk-k-kkkk-k-kk-kkkkkkkk-kk-kkk-kkkkkkkkk-kkkkk--kkkkkk-k--kk
  28. %% gangster g12: kkkkkkkkkkkkkkkkkk-kkkkkkkkkkkkkkkkkk-kkkkkkkkkkkkkkkkkk-kkkkkkkkkkkkkkk
  29.  
  30. %%%%%%%%%%%%%%%%%%%%% INPUT:
  31.  
  32. % example: 4 gangsters are needed for killing on hour 1, one gangster on hour 2, two gangsters on hour 3, etc.
  33. gangstersNeeded(killing, [4,1,2,4,2,1,1,4,1,1,3,2,4,2,1,2,1,3,2,3,4,1,3,1,2,3,1,3,4,3,2,3,4,2,3,1,4,4,1,4,2,2,1,4,3,3,3,2,2,3,4,4,1,3,3,3,4,4,1,1,2,3,3,3,3,2,1,3,1,1,3,2] ).
  34. gangstersNeeded(countingMoney, [1,2,1,3,1,4,3,1,3,1,4,3,2,2,1,2,1,2,1,1,2,1,2,1,1,3,1,2,2,4,3,2,4,4,4,1,2,4,4,2,4,4,4,3,2,2,1,3,2,1,3,3,2,3,3,3,1,4,1,1,3,1,2,3,3,1,4,4,3,3,2,1] ).
  35. gangstersNeeded(politics, [2,4,2,1,1,1,4,1,1,4,1,3,2,4,1,1,4,1,4,3,1,3,2,4,4,2,4,2,1,1,4,3,1,2,2,2,1,1,3,1,1,1,2,2,4,1,1,3,4,4,2,3,2,4,3,1,1,1,3,4,2,2,4,4,3,1,1,2,1,4,3,2] ).
  36.  
  37. % Gangsters definitions
  38. gangsters([g01,g02,g03,g04,g05,g06,g07,g08,g09,g10,g11,g12]).
  39.  
  40. % Restrictions among gangsters
  41. notAvailable(g01,[6,13,14,16,21,35,37,41,59]).
  42. notAvailable(g02,[14,34,40,45,48,52,58,65,70,72]).
  43. notAvailable(g03,[8,11,13,27,30,38,50,51,70]).
  44. notAvailable(g04,[4,12,16,17,26,30,42,45,48,55,71]).
  45.  
  46. %%%%%%%%%%%%%%%%%%%%% END INPUT. %%%%%%%%%%%%%%%%%%%%%
  47.  
  48. :-dynamic(varNumber/3).
  49. symbolicOutput(0). % set to 1 to see symbolic output only; 0 otherwise.
  50.  
  51. %%%%%% Some helpful definitions to make the code cleaner:
  52.  
  53. task(T):-        gangstersNeeded(T,_).
  54. needed(T,H,N):-  gangstersNeeded(T,L), nth1(H,L,N).
  55. gangster(G):-    gangsters(L), member(G,L).
  56. hour(H):-        between(1,72,H).
  57. blocked(G,H):-   notAvailable(G,L), member(H,L).
  58. available(G,H):- hour(H), gangster(G), \+blocked(G,H).
  59.  
  60. % We use (at least) the following types of symbolic propositional variables:
  61. %   1. does-G-T-H means:  "gangster G does task T at hour H"     (MANDATORY)
  62. %   2. works-G-H means: "gangster G works hour H"
  63.  
  64. writeClauses(K):-  
  65.     initClauseGeneration,
  66.     eachHourEachGangsterAtMostOneTask,
  67.     eachHourEachTaskEnoughGangsters,
  68.     twoConsecutiveHoursEachGangsterAtMostOneTask,
  69.     eachGangsterWorksMaxKConsecutiveHours(K),
  70.     relateVariables,
  71.     true, !.
  72.  
  73. subList(L, S) :- append(_, L1, L), append(S, _, L1).
  74. subList([], []).
  75.  
  76. first([F|_], F).
  77.  
  78. maxConsecutiveHours(M, K) :-
  79.     between(0, 71, KP),
  80.     K is 72 - KP,
  81.     gangster(G),
  82.     findall(H, member(works-G-H, M), Lits),
  83.     sort(Lits, L),
  84.     subList(L, SL),
  85.     length(SL, K),
  86.     first(SL, HS),
  87.     last(SL, HE),
  88.     HE is HS + K - 1.
  89.  
  90. relateVariables :-
  91.     available(G, H),
  92.     task(T),
  93.     writeClause([\+does-G-T-H, works-G-H]),
  94.     fail.
  95. relateVariables.
  96.  
  97. eachHourEachGangsterAtMostOneTask :-
  98.     available(G, H), % Each combination Gangster G and Hour H.
  99.     findall(does-G-T-H, task(T), Lits), % Each Task T for each Gangster G at Hour H.
  100.     atMost(1, Lits), % At most one Task for Gangster and Hour.
  101.     fail.
  102. eachHourEachGangsterAtMostOneTask.
  103.  
  104. eachHourEachTaskEnoughGangsters :-
  105.     task(T),
  106.     hour(H),
  107.     needed(T, H, N),
  108.     findall(does-G-T-H, available(G, H), Lits),
  109.     atLeast(N, Lits),
  110.     fail.
  111. eachHourEachTaskEnoughGangsters.
  112.  
  113. twoConsecutiveHoursEachGangsterAtMostOneTask :-
  114.     available(G, H1), % Each combination Gangster and hour H1
  115.     H2 is H1 + 1, hour(H2), % Consecutive hour
  116.     available(G, H2), % Gangster available at hour H2
  117.     task(T1), task(T2), T1 \= T2, % Different tasks
  118.     writeClause([\+does-G-T1-H1, \+does-G-T2-H2]),
  119.     fail.
  120. twoConsecutiveHoursEachGangsterAtMostOneTask.
  121.  
  122. eachGangsterWorksMaxKConsecutiveHours(K) :-
  123.     available(G, H),
  124.     HP is H + K, hour(HP),
  125.     createNegativeClause(G, H, HP, C),
  126.     writeClause(C),
  127.     fail.
  128. eachGangsterWorksMaxKConsecutiveHours(_).
  129.    
  130. createNegativeClause(G, K, K, [\+works-G-K]).
  131. createNegativeClause(G, H, K, [\+works-G-H|C]) :-
  132.     HP is H + 1, HP =< K,
  133.     createNegativeClause(G, HP, K, C).
  134.  
  135. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% DISPLAYSOL:
  136.  
  137. displaySol(M):- nl,nl,
  138.     write('                      10        20        30        40        50        60        70  '), nl,
  139.     write('              123456789012345678901234567890123456789012345678901234567890123456789012'), nl,
  140.     gangster(G), nl, write('gangster '), write(G), write(': '), hour(H), writeIfBusy(G,H,M), fail.
  141. displaySol(_):- nl,nl,!.
  142.  
  143. writeIfBusy(G,H,M):- member(does-G-killing-H,M),       write('k'),!.
  144. writeIfBusy(G,H,M):- member(does-G-countingMoney-H,M), write('c'),!.
  145. writeIfBusy(G,H,M):- member(does-G-politics-H,M),      write('p'),!.
  146. writeIfBusy(_,_,_):- write('-'),!.
  147.  
  148. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% MAIN:
  149.  
  150. main:-  symbolicOutput(1), !, writeClauses(30), halt.   % print the clauses in symbolic form and halt
  151. main:-
  152.     write('Looking for initial plan allowing arbitrary consecutive hours (72h).'), nl,
  153.     tell(clauses), writeClauses(72), told,     % generate the (numeric) SAT clauses and call the solver
  154.     tell(header),  writeHeader,  told,
  155.     numVars(N), numClauses(C),
  156.     write('Generated '), write(C), write(' clauses over '), write(N), write(' variables. '),nl,
  157.     shell('cat header clauses > infile.cnf',_),
  158.     write('Launching picosat...'), nl,
  159.     shell('picosat -v -o model infile.cnf', Result),  % if sat: Result=10; if unsat: Result=20.
  160.     treatResult(Result,[]),!.
  161.  
  162. treatResult(20,[]       ):- write('No solution exists.'), nl, halt.
  163. treatResult(20,BestModel):- nl,nl,write('Optimal solution: '),nl, displaySol(BestModel), halt.
  164. treatResult(10,_):- %   shell('cat model',_),  
  165.     see(model), symbolicModel(M), seen,  
  166.     maxConsecutiveHours(M,K),
  167.     write('planning found with at most '), write(K), write(' consecutive hours '),nl,nl,
  168.     displaySol(M),
  169.     K1 is K-1,
  170.     tell(clauses), writeClauses(K1), told,
  171.     tell(header),  writeHeader,  told,
  172.     numVars(N),numClauses(C),
  173.     write('Generated '), write(C), write(' clauses over '), write(N), write(' variables. '),nl,
  174.     shell('cat header clauses > infile.cnf',_),
  175.     write('Launching picosat...'), nl,
  176.     shell('picosat -v -o model infile.cnf', Result),  % if sat: Result=10; if unsat: Result=20.
  177.     treatResult(Result,M),!.
  178.    
  179.  
  180. initClauseGeneration:-  %initialize all info about variables and clauses:
  181.     retractall(numClauses(   _)),
  182.     retractall(numVars(      _)),
  183.     retractall(varNumber(_,_,_)),
  184.     assert(numClauses( 0 )),
  185.     assert(numVars(    0 )),     !.
  186.  
  187.  
  188. writeClause([]):- symbolicOutput(1),!, nl.
  189. writeClause([]):- countClause, write(0), nl.
  190. writeClause([Lit|C]):- w(Lit), writeClause(C),!.
  191. w( Lit ):- symbolicOutput(1), write(Lit), write(' '),!.
  192. w(\+Var):- var2num(Var,N), write(-), write(N), write(' '),!.
  193. w(  Var):- var2num(Var,N),           write(N), write(' '),!.
  194.  
  195.  
  196. % given the symbolic variable V, find its variable number N in the SAT solver:
  197. var2num(V,N):- hash_term(V,Key), existsOrCreate(V,Key,N),!.
  198. existsOrCreate(V,Key,N):- varNumber(Key,V,N),!.                            % V already existed with num N
  199. existsOrCreate(V,Key,N):- newVarNumber(N), assert(varNumber(Key,V,N)), !.  % otherwise, introduce new N for V
  200.  
  201. writeHeader:- numVars(N),numClauses(C), write('p cnf '),write(N), write(' '),write(C),nl.
  202.  
  203. countClause:-     retract( numClauses(N0) ), N is N0+1, assert( numClauses(N) ),!.
  204. newVarNumber(N):- retract( numVars(   N0) ), N is N0+1, assert(    numVars(N) ),!.
  205.  
  206. % Getting the symbolic model M from the output file:
  207. symbolicModel(M):- get_code(Char), readWord(Char,W), symbolicModel(M1), addIfPositiveInt(W,M1,M),!.
  208. symbolicModel([]).
  209. addIfPositiveInt(W,L,[Var|L]):- W = [C|_], between(48,57,C), number_codes(N,W), N>0, varNumber(_,Var,N),!.
  210. addIfPositiveInt(_,L,L).
  211. readWord( 99,W):- repeat, get_code(Ch), member(Ch,[-1,10]), !, get_code(Ch1), readWord(Ch1,W),!. % skip line starting w/ c
  212. readWord(115,W):- repeat, get_code(Ch), member(Ch,[-1,10]), !, get_code(Ch1), readWord(Ch1,W),!. % skip line starting w/ s
  213. readWord(-1,_):-!, fail. %end of file
  214. readWord(C,[]):- member(C,[10,32]), !. % newline or white space marks end of word
  215. readWord(Char,[Char|W]):- get_code(Char1), readWord(Char1,W), !.
  216. %========================================================================================
  217.  
  218. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  219. % Everything below is given as a standard library, reusable for solving
  220. %    with SAT many different problems.
  221. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  222.  
  223. %%%%%% Cardinality constraints on arbitrary sets of literals Lits:
  224. % For example the following generates the clauses expressing that
  225. %     exactly K literals of the list Lits are true:
  226. exactly(K,Lits):- atLeast(K,Lits), atMost(K,Lits),!.
  227.  
  228. atMost(K,Lits):-   % l1+...+ln <= k:  in all subsets of size k+1, at least one is false:
  229.     negateAll(Lits,NLits),
  230.     K1 is K+1,    subsetOfSize(K1,NLits,Clause), writeClause(Clause),fail.
  231. atMost(_,_).
  232.  
  233. atLeast(K,Lits):-  % l1+...+ln >= k: in all subsets of size n-k+1, at least one is true:
  234.     length(Lits,N),
  235.     K1 is N-K+1,  subsetOfSize(K1, Lits,Clause), writeClause(Clause),fail.
  236. atLeast(_,_).
  237.  
  238. negateAll( [], [] ).
  239. negateAll( [Lit|Lits], [NLit|NLits] ):- negate(Lit,NLit), negateAll( Lits, NLits ),!.
  240.  
  241. negate(\+Lit, Lit):- !.
  242. negate(Lit, \+Lit):- !.
  243.  
  244. subsetOfSize(0,_,[]):-!.
  245. subsetOfSize(N,[X|L],[X|S]):- N1 is N-1, length(L,Leng), Leng>=N1, subsetOfSize(N1,L,S).
  246. subsetOfSize(N,[_|L],   S ):-            length(L,Leng), Leng>=N,  subsetOfSize( N,L,S).
  247.  
  248. % Express that Var is equivalent to the disjunction of Lits:
  249. expressOr( Var, Lits ):- member(Lit,Lits), negate(Lit,NLit), writeClause([ NLit, Var ]), fail.
  250. expressOr( Var, Lits ):- negate(Var,NVar), writeClause([ NVar | Lits ]),!.
  251.  
  252. % Express that Var is equivalent to the conjunction of Lits:
  253. expressAnd( Var, Lits ):- negate(Var,NVar), member(Lit,Lits),  writeClause([ NVar, Lit ]), fail.
  254. expressAnd( Var, Lits ):- negateAll(Lits,NLits), writeClause([ Var | NLits ]),!.
  255.  
  256. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  257.  
  258. % JosepRivaille
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement