100 likes | 303 Views
Dave Reed. constraint-based problem solving constraint-based problems Generate&Test approach generate candidate solution, then test constraints Test&Generate approach apply constraints first, then fill in blanks in candidate timing code: time , doReps. Constraint-based problems.
E N D
Dave Reed • constraint-based problem solving • constraint-based problems • Generate&Test approach generate candidate solution, then test constraints • Test&Generate approach apply constraints first, then fill in blanks in candidate timing code: time, doReps
Constraint-based problems • some problems are not perfectly suited to search space representation • not really interested in a sequence of transitions from one state to another • instead, know the basic form of a solution, plus constraints on that solution Consider 4 people: Bob, Karen, Dan, Sue Constraints: Bob is older than Karen. Dan is the youngest. Sue is not the oldest. Problem: Given these constraints, find the relative ages of the 4 people. • In fact, this problem is under-constrained: • Solution 1 (by increasing ages): Dan, Sue, Karen, Bob • Solution 2 (by increasing ages): Dan Karen, Sue, Bob • constraint-based problems can still be reduced to search using a Generate&Test approach • generate a candidate solution (based on the known solution form) • test the candidate solution to see if it meets the constraints • if not, BACKTRACK to try a new candidate solution
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% ages1.pro Dave Reed 2/24/02 %%% %%% Test and Generate solution to ages problem: %%% Bob is older than Karen. %%% Dan is the youngest. %%% Sue is not the oldest. %%% This program represents the solution as a list, ordered by age. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% solve(X) :- candidate(X), constraints(X). candidate(Candidate) :- permutation(Candidate,[bob,karen,dan,sue]). constraints(Candidate) :- Candidate = [P1,P2,P3,P4], comes_before(karen,bob,Candidate), P1 = dan, member(sue,[P1,P2,P3]). %%%%%%%%%% Utilities %%%%%%%%%% comes_before(X,Y,[X|T]) :- member(Y,T). comes_before(X,Y,[_|T]) :- comes_before(X,Y,T). permutation([],[]). permutation([H|T],Perm) :- permutation(T,P), select(H, Perm, P). Age problem: Generate&Test • will represent a solution as a list of people, ordered by age • solve predicate: • generates a candidate solution (i.e., permutation of the names) • tests to see if that candidate solution meets the problem constraints ?- solve(X). X = [dan, karen, sue, bob] ; X = [dan, sue, karen, bob] ; HANGS!
Generate&Test vs. Test&Generate • if the solution space is large, Generate&Test can be infeasible worst case: would have to generate every potential solution & test for ages problem: • 4! = 24 possible arrangements of the people exhausting solution space is doable • if there were 8 people, 8! = 40,320 possible arrangements • if there were 10 people, 10! = 3,628,800 possible arrangements • instead, use a Test&Generate approach • first apply constraints to a solution template • then generate permutations to fill in the remaining blanks for ages problem: the constraint that Dan is the youngest eliminates 18 possibilities the constraint that Sue in not the oldest eliminates another 2 possibilities . . .
Age problem: Test&Generate %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% ages2.pro Dave Reed 2/24/02 %%% %%% Test and Generate solution to ages problem: %%% Bob is older than Karen. %%% Dan is the youngest. %%% Sue is not the oldest. %%% This program represents the solution as a list, ordered by age. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% solve(X) :- constraints(X), candidate(X). candidate(Candidate) :- permutation(Candidate,[bob,karen,dan,sue]). constraints(Candidate) :- Candidate = [P1,P2,P3,P4], comes_before(karen,bob,Candidate), P1 = dan, member(sue,[P1,P2,P3]). %%%%%%%%%% Utilities %%%%%%%%%% comes_before(X,Y,[X|T]) :- member(Y,T). comes_before(X,Y,[_|T]) :- comes_before(X,Y,T). permutation([],[]). permutation([H|T],Perm) :- permutation(T,P), select(H, Perm, P). • again, represent solution as a list of people, ordered by age • solve predicate: • apply constraints to an abstract solution (i.e., a list of variables) • fill in the remaining blanks using the candidate predicate ?- solve(X). X = [dan, karen, sue, bob] ; X = [dan, sue, karen, bob] ; No EXHAUSTS THE SEARCH
time predicate to quantify how much better Test&Generate is, can make use of the built-in time predicate time(Goal): solves Goal and reports the # of inferences and cpu time required note: time does not allow backtracking to see alternate answers ?- consult(ages1). % ages1 compiled 0.06 sec, 0 bytes Yes ?- time(solve(X)). % 239 inferences in 0.00 seconds (Infinite Lips) X = [dan, karen, sue, bob] Yes ?- consult(ages2). % ages2 compiled 0.06 sec, 0 bytes Yes ?- time(solve(X)). % 44 inferences in 0.00 seconds (Infinite Lips) X = [dan, karen, sue, bob] Yes
Better timings %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% doreps.pro Dave Reed 2/24/02 %%% %%% A predicate for repeatedly solving a goal. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% doReps(Goal, 1) :- Goal. doReps(Goal, Reps) :- not(not(Goal)), NewReps is Reps-1, doReps(Goal, NewReps). • since time rounds to nearest 100th of a second, quick goals appear as 0 • can define our own predicate for repeating a goal some # of repetitions • note use of double negation to discard bindings -- makes sure each call to Goal uses the initial variables • by doing 1000 reps each, see that Test&Generate is 4-5 times faster ?- consult(ages1). % ages1 compiled 0.06 sec, 0 bytes Yes ?- time(doReps(solve(X), 1000)). % 242,997 inferences in 0.27 seconds (899989 Lips) X = [dan, karen, sue, bob] Yes ?- consult(ages2). % ages2 compiled 0.06 sec, 0 bytes Yes ?- time(doReps(solve(X), 1000)). % 47,997 inferences in 0.06 seconds (799950 Lips) X = [dan, karen, sue, bob] Yes
Another example • Consider a more complex example: Three friends came in 1st, 2nd and 3rd in a programming contest. Each has a different name (Michael, Simon, Richard), nationality (American, Australian, Israeli), and favorite sport (basketball, tennis, cricket). The following is known: • Michael likes basketball, and did better than the American. • Simon, the Israeli, did better than the tennis player. • The cricket player came in first. Solution space: 6 ways to assign names to the 3 places 6 ways to assign nationalities to the 3 places 6 ways to assign sports to the 3 places 6*6*6 = 216 possible arrangements
Competition problem: Test&Generate %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% compete.pro Dave Reed 2/24/02 %%% %%% Test and Generate solution to the competition problem. %%% %%% This program represents the solution as a list, ordered by finish. %%% Each element of the list is of the form "Name::Nationality::Sport". %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% :- op(100,xfy,'::'). solve(X) :- constraints(X), candidate(X). candidate([P1::N1::S1, P2::N2::S2, P3::N3::S3]) :- permutation([P1,P2,P3],[michael,richard,simon]), permutation([N1,N2,N3],[american,australian,israeli]), permutation([S1,S2,S3],[basketball,cricket,tennis]). constraints(Candidate) :- Candidate = [X1,X2,X3], member(michael::_::basketball,Candidate), comes_before(michael::_::_,_::american::_,Candidate), member(simon::israeli::_,Candidate), comes_before(simon::_::_,_::_::tennis,Candidate), X1 = _::_::cricket. %%%%%%%%%% Utilities %%%%%%%%%% permutation([],[]). permutation([H|T],Perm) :- permutation(T,P), select(H, Perm, P). represent solution as a list of competitors, ordered by finish (1st place at HEAD) use '::' operator to combine info about each competitor
Timing the Test&Generate solution ?- solve(X). X = [simon::israeli::cricket, michael::australian::basketball, richard::american::tennis] ; No ?- time(solve(X)). % 97 inferences in 0.00 seconds (Infinite Lips) X = [simon::israeli::cricket, michael::australian::basketball, richard::american::tennis] Yes ?- time(doReps(solve(X), 1000)). % 100,997 inferences in 0.11 seconds (918155 Lips) X = [simon::israeli::cricket, michael::australian::basketball, richard::american::tennis] Yes code finds the unique solution Generate&Test would require 1,191 inferences Generate&Test would take 1.54 seconds for 1000 repetitions