3
36
38
39
40:- module(generic_search, [search/6]). 41
42:- use_module(library(tor_clpfd)). 43
44:- use_module(library(apply)). 45:- use_module(library(lists)). 46:- use_module(library(random)). 47
48
54
66
70
71get_bounds(X, Min, Max) :-
72 fd_inf(X, Min),
73 fd_sup(X, Max).
74
75get_compact_domain_as_list(Var,List) :-
76 fd_dom(Var,Domain),
77 domain_to_list(Domain,List,[]).
78
79get_compact_domain_rep(Var,Rep) :-
80 get_compact_domain_as_list(Var,Rep).
81
82domain_to_list(D1\/D2,List,Tail) :-
83 domain_to_list(D1,List,Middle),
84 domain_to_list(D2,Middle,Tail).
85domain_to_list(Lo..Hi,[Lo..Hi|Tail],Tail).
86
90
91search(Vars,Arg,Select,Choice,Method,Option):-
92 Module = user,
93 Vars = List,
94 integer(Arg),
95 callable(Select),
96 callable(Choice),
97 is_search_method(Method),
98 is_list(Option),
99 !,
100 in_out(Choice,In,Out),
101 option_heuristics(Option,search1(List,Arg,Select,Choice,Method,In,Out,Module),Goal),
102 search(Goal).
103search(Vars,Arg,Select,Choice,Method,Option):-
104 Module = generic_search,
105 throw(error(5, search(Vars,Arg,Select,Choice,Method,Option), Module)).
106
107:- meta_predicate option_heuristics(?,0,0). 108
109option_heuristics([],Goal,Goal).
110option_heuristics([backtrack(N) | Option], Goal, backtrack_count(N, NGoal)) :-
111 option_heuristics(Option,Goal,NGoal).
112option_heuristics([nodes(Limit) | Option],Goal,nbs(Limit,NGoal)) :-
113 option_heuristics(Option,Goal,NGoal).
114
116search1(L,Arg,Select,Choice,Heuristic,In,Out,Module) :-
117 heuristic_goal(Heuristic,labeling(L,Arg,Select,Choice,In,Out,Module),Goal),
118 call(Goal).
119
120:- meta_predicate heuristic_goal(+,0,0). 121
122heuristic_goal(complete,Goal,Goal).
123heuristic_goal(bbs(Steps),Goal,bbs(Steps,Goal)).
124heuristic_goal(lds(Disc),Goal,dibs(Disc,Goal)).
125heuristic_goal(credit(Credit,Steps),Goal,credit(Credit,StepsPartialGoal,Goal)) :-
126 heuristic_partial_goal(Steps,StepsPartialGoal).
127heuristic_goal(dbs(Level,Steps),Goal,dbs(Level,StepsPartialGoal,Goal)) :-
128 heuristic_partial_goal(Steps,StepsPartialGoal).
129
130heuristic_partial_goal(bbs(M),bbs(M)).
131heuristic_partial_goal(lds(M),dibs(M)).
132
133is_search_method(complete) :- !.
134is_search_method(bbs(N)) :- integer(N), !.
135is_search_method(credit(N,M)) :- integer(N), integer(M), !.
136is_search_method(credit(N,bbs(M))) :- integer(N), integer(M), !.
137is_search_method(credit(N,lds(M))) :- integer(N), integer(M), !.
138is_search_method(lds(N)) :- integer(N), !.
139is_search_method(dbs(N,M)) :- integer(N), integer(M), !.
140is_search_method(dbs(N,bbs(M))) :- integer(N), integer(M), !.
141is_search_method(dbs(N,lds(M))) :- integer(N), integer(M), !.
147
148
158labeling(L,Arg,Select,Choice,In,Out,Module):-
159 labeling1(L,Arg,Select,Choice,In,Out,Module).
160
161
163labeling1([],_,_,_,In,In,_Module).
164labeling1([H|T],Arg,Select,Choice,In,Out,Module):-
165 delete(X,[H|T],R,Arg,Select,Module),
166 choose(X,Arg,Choice,In,In1,Module),
167 labeling1(R,Arg,Select,Choice,In1,Out,Module).
168
174
182choose(X,N,indomain,_In, _Out, _Module):-
183 !,
184 access(X,N,Var),
185 indomain(Var).
186choose(X,N,Type,_In, _Out, _Module):-
187 translate_indomain_atom(Type, IndomainType),
188 !,
189 access(X,N,Var),
190 indomain(Var,IndomainType).
191
202
203
209
211translate_indomain_atom(indomain, enum).
212translate_indomain_atom(indomain_min, min).
213translate_indomain_atom(indomain_max, max).
214translate_indomain_atom(outdomain_min, reverse_min). 215translate_indomain_atom(outdomain_max, reverse_max). 216translate_indomain_atom(indomain_reverse_min, reverse_min).
217translate_indomain_atom(indomain_reverse_max, reverse_max).
218translate_indomain_atom(indomain_middle, middle).
219translate_indomain_atom(indomain_median, median).
220translate_indomain_atom(indomain_split, split).
221translate_indomain_atom(indomain_reverse_split, reverse_split).
222translate_indomain_atom(indomain_interval, interval).
223translate_indomain_atom(indomain_random, random).
224
227access(X,0,X) :- !.
228access(X,N,Var):-
229 N > 0,
230 arg(N,X,Var).
231
235in_out(T,In,Out):-
236 functor(T,_,2),
237 !,
238 arg(1,T,In),
239 arg(2,T,Out).
240in_out(_T,-,-).
241
255
261
264
272delete(H,List,T,_Arg,input_order,_Module):-
273 !, List = [H|T].
274delete(X,List,R,Arg,Select,Module):-
275 List = [H|T],
276 find_criteria(H,Arg,Select,Crit,Module),
277 ( var(Crit) ->
278 X=H, R=T 279 ;
280 find_best_and_rest(T,List,Crit,X,R,Arg,Select,Module)
281 ).
282
283
292find_best_and_rest([], BestSoFar, _OldCrit, BestVar, Rest, _Arg, _Select, _Module) :- !,
293 BestSoFar = [BestVar|Rest].
294find_best_and_rest(List, BestSoFar, CritOld, BestVar, Rest, Arg, Select, Module) :-
295 List = [Var|Vars],
296 find_criteria(Var, Arg, Select, CritNew, Module),
297 ( CritNew @>= CritOld -> 298 find_best_and_rest(Vars, BestSoFar, CritOld, BestVar, Rest, Arg, Select, Module)
299 ; nonvar(CritNew) -> 300 301 copy_until_elem(BestSoFar, Var, Rest, Rest0),
302 find_best_and_rest(Vars, List, CritNew, BestVar, Rest0, Arg, Select, Module)
303 ;
304 305 BestVar = Var,
306 307 copy_until_elem(BestSoFar, Var, Rest, Vars)
308 ).
309
310
317find_criteria(Term,0,Select,Crit,Module):-
318 !,
319 find_value(Term,Select,Crit,Module).
320find_criteria(Term,Arg,Select,Crit,Module):-
321 arg(Arg,Term,X),
322 find_value(X,Select,Crit,Module).
323
333find_value(X,first_fail,Size,_Module):-
334 !,
335 ( nonvar(X) ->
336 true 337 ;
338 fd_size(X,Size0),
339 ( integer(Size0) -> Size=Size0 ; Size=inf ) 340 ).
341find_value(X,anti_first_fail,Number,_Module):-
342 !,
343 fd_size(X,Size), 344 Number is -Size. 345find_value(X,smallest,Min,_Module):-
346 !,
347 fd_inf(X,Min).
348find_value(X,largest,Number,_Module):-
349 !,
350 fd_sup(X,Max),
351 Number is -Max.
352find_value(X,occurence,Number,Module):- 353 !,
354 find_value(X,occurrence,Number,Module).
375find_value(X,most_constrained,Crit,Module):-
376 !,
377 ( nonvar(X) ->
378 true 379 ;
380 Crit = crit(Size,Number),
381 find_value(X,first_fail,Size,Module),
382 find_value(X,occurrence,Number,Module)
383 ).
388
389
392copy_until_elem([X|Xs], K, Ys, Ys0) :-
393 ( X==K ->
394 Ys = Ys0
395 ;
396 Ys = [X|Ys1],
397 copy_until_elem(Xs, K, Ys1, Ys0)
398 ).
399
400
406
407:-export(indomain/2). 408
413indomain(X,Type):- indomain1(X,Type).
414
416indomain1(X,enum):-
417 indomain(X).
418indomain1(X,min):-
419 fd_inf(X,Min),
420 indomain_min(X,Min).
421indomain1(X,max):-
422 fd_sup(X,Max),
423 indomain_max(X,Max).
424indomain1(X,reverse_min):-
425 fd_inf(X,Min),
426 outdomain_min(X,Min).
427indomain1(X,reverse_max):-
428 fd_sup(X,Max),
429 outdomain_max(X,Max).
430indomain1(X,middle):-
431 select_initial_value_middle(X,Value),
432 indomain1(X,Value).
433indomain1(X,median):-
434 select_initial_value_median(X,Value),
435 indomain1(X,Value).
436indomain1(X,split):-
437 indomain_split(X).
438indomain1(X,reverse_split):-
439 indomain_reverse_split(X).
440indomain1(X,interval):-
441 indomain_interval(X).
442indomain1(X,random):-
443 indomain_random(X).
444indomain1(X,Value):-
445 integer(Value),
446 get_bounds(X,Min,Max),
447 ( Value =< Min ->
448 449 indomain_min(X,Min)
450 ; Value >= Max ->
451 452 indomain_max(X,Max)
453 ;
454 455 456 Range is 2*max(Max-Value,Value-Min)+1,
457 indomain_from(X,Value,1,Range)
458 ).
459
460 461select_initial_value_middle(X,Value) :-
462 get_bounds(X,Min,Max),
463 Value is (Min+Max)//2. 464
465 466select_initial_value_median(X,Value) :-
467 fd_size(X,Size),
468 Index is 1+Size//2,
469 get_compact_domain_rep(X, L),
470 nth_value(L,Index,Value).
471
472% indomain_from(?X:dvar, ++Value:integer, ++Inc:integer, ++Range:integer)
473% the choice consists in either taking the proposed value or in excluding it
474% and choosing another one
475% the next value is always the old value plus the increment
476% the next increment is one bigger than the previous, but of opposite sign
477% 1, -2, 3, -4, 5, -6, 7 ...
478% if the increment becomes too large, you can stop
479%:-mode indomain_from(?,++,++,++).
480indomain_from(X,Value,Inc,Range):-
481 ( X #= Value
482 tor
483 X #\= Value,
484 Value1 is Value+Inc,
485 Inc1 is -sign(Inc)*(abs(Inc)+1),
486 Range >= abs(Inc1),
487 indomain_from(X,Value1,Inc1,Range)
488 ).
489
490% indomain_min(?X:dvar, ++Value:integer)
491% the choice consists in either taking the proposed value or in excluding it
492% and choosing another one
493%:-mode indomain_min(?,++).
494indomain_min(X,Min) :-
495 ( X #= Min
496 tor
497 X #> Min,
498 fd_inf(X,New),
499 indomain_min(X,New)
500 ).
501
502%:-mode outdomain_min(?,++).
503outdomain_min(X,Min) :-
504 ( X #> Min,
505 fd_inf(X,New),
506 outdomain_min(X,New)
507 tor
508 X #= Min
509 ).
510
511
512
513% indomain_max(?X:dvar, ++Value:integer)
514% the choice consists in either taking the proposed value or in excluding it
515% and choosing another one
516%:-mode indomain_max(?,++).
517indomain_max(X,Max) :-
518 ( X #= Max
519 tor
520 X #< Max,
521 fd_sup(X,New),
522 indomain_max(X,New)
523 ).
524
525%:-mode outdomain_max(?,++).
526outdomain_max(X,Max):-
527 ( X #< Max,
528 fd_sup(X,New),
529 outdomain_max(X,New)
530 tor
531 X #= Max
532 ).
533
536indomain_split(X):-
537 integer(X),
538 !.
539indomain_split(X):-
540 get_bounds(X,Min,Max),
541 Middle is (Min+Max) div 2,
542 (
543 X #=< Middle
544 tor
545 X #> Middle
546 ),
547 indomain_split(X).
548
550indomain_reverse_split(X):-
551 integer(X),
552 !.
553indomain_reverse_split(X):-
554 get_bounds(X,Min,Max),
555 Middle is (Min+Max) div 2,
556 (
557 X #> Middle
558 tor
559 X #=< Middle
560 ),
561 indomain_reverse_split(X).
562
566indomain_interval(X):-
567 get_compact_domain_as_list(X,L),
568 fix_interval(X,L).
569
570%:-mode fix_interval(?,++).
571fix_interval(X,[A|_R]):-
572 ( integer(A) ->
573 ( X #= A
574 tor
575 X #\= A,
576 fix_interval(X,R)
577 )
578 ; A = [_A..B|R] ->
579 ( X #=< B,
580 indomain(X,split) % there are many alternatives here
581 tor
582 X #> B,
583 fix_interval(X,R)
584 )
585 ).
586
590indomain_random(X):-
591 fd_size(X,Size),
592 random(V),
593 Index is 1+ (V mod Size),
594 get_compact_domain_rep(X,L),
595 nth_value(L,Index,Try),
596 indomain_random(X,Try).
597
598%:-mode indomain_random(?,++).
599indomain_random(X,Try) :-
600 ( X #= Try
601 tor
602 X #\= Try,
603 indomain_random(X)
604 ).
605
606
612
613:-export(nth_value/3). 614
615nth_value(V, 1, V) :-
616 integer(V).
617nth_value(I, N, V) :-
618 I = _.._,
619 nth_value1(I, [], N, V).
620nth_value([I | R], N, V) :-
621 nth_value1(I, R, N, V).
622
623nth_value1(A..B, R, N, V) :-
624 A1 is A + N - 1,
625 N1 is A1 - B,
626 ( N1 > 0 ->
627 nth_value(R, N1, V)
628 ;
629 A1 >= A,
630 V = A1
631 ).
632nth_value1(A, R, N, V) :-
633 atomic(A),
634 nth_value2(A, R, N, V).
635
636nth_value2(A, _R, 1, V) :-
637 !,
638 V = A.
639nth_value2(_A, R, N, V) :-
640 N1 is N - 1,
641 nth_value(R, N1, V)