0% found this document useful (0 votes)
127 views7 pages

01 - DFS Water Jug Problem Prolog

The document describes the implementation of a depth-first search (DFS) algorithm for solving the water jug problem using LISP/PROLOG. It includes the bb_planner.pl program, which defines the search strategy, and the Waterjug.pl program, which sets up the specific problem with jugs of different capacities and the goal of measuring out 4 liters of water. The document outlines the necessary predicates and transitions for the problem, allowing for flexible goal states and loop checking.

Uploaded by

237r5a7307
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
127 views7 pages

01 - DFS Water Jug Problem Prolog

The document describes the implementation of a depth-first search (DFS) algorithm for solving the water jug problem using LISP/PROLOG. It includes the bb_planner.pl program, which defines the search strategy, and the Waterjug.pl program, which sets up the specific problem with jugs of different capacities and the goal of measuring out 4 liters of water. The document outlines the necessary predicates and transitions for the problem, allowing for flexible goal states and loop checking.

Uploaded by

237r5a7307
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 7

Experiment - 1

1. Implementation of DFS for water jug problem using LISP/PROLOG

Bb_planner.pl Program:

%% bb_planner.pl
%% 1) goal_state now called with the solution search.
%% (Previously goal was determined prior to search, which is
%% less flexible. Now it can search for several potential goals
%% within a single goal.
%% 2) equivalent_states is now only used by the loop checker, not
%% when testing for goals, so goal_state predicate needs to be
%% true for all acceptable goals.
%% Change: eliminated some retundant backtracking in the 'solution'
% predicate.

%% This code implements a breadth-first search strategy for


%% transition-based search/planning problems.
%% It has an option to automatically eliminate loops and redundant
%% diversions by discarding any path whose end state is the same as
%% that of some shorter path.

%% To use the algorithm on a particular problem, you need to define


%% a number of problem-specific predicates that give the intitial
%% and goal states and describe the possible transitions between
%% states. This is explained in detail at the end of this file.

:- use_module( library(lists) ).

find_solution :-
initial_state( Initial ),
write( '== Starting Search ==' ), nl,
solution( [[Initial]], StateList ),
length( StateList, Len ),
Transitions is Len -1,
format( '~n** FOUND SOLUTION of length ~p **', [Transitions] ), nl,
showlist( StateList ), !.

%find_solution :-
% write( '!! FAILED: No plan reaches a goal !!' ), nl, fail.

%% Base case for finding solution.


%% Find a statelist whose last state is the goal or
solution( StateLists, StateList ) :-
member( StateList, StateLists ),
last( StateList, Last ),
goal_state(Last),
report_progress( StateLists, final ).

%% Recursive rule that looks for a solution by extending


%% each of the generated state lists to add a further state.
solution( StateLists, StateList ) :-
report_progress( StateLists, ongoing ),
extend( StateLists, Extensions ), !,
solution( Extensions, StateList ), !.

solution( _, _ ) :- !,
write( '!! Cannot extend statelist !!' ), nl,
write( '!! FAILED: No plan reaches a goal !!' ), nl,
fail, !.

%% Extend each statelist in a set of possible state lists.


%% If loopcheck(on) will not extend to any state previously reached
%% in any of the state lists, to avoid loops.
extend( StateLists, ExtendedStateLists ) :-
setof( ExtendedStateList,
StateList^Last^Next^( member( StateList, StateLists ),
last( StateList, Last ),
transition( Last, Next ),
legal_state( Next ),
no_loop_or_loopcheck_off( Next, StateLists ),
append( StateList, [Next], ExtendedStateList )
),
ExtendedStateLists
).

poss_empty_setof( X, G, S ) :- setof( X, G, S), !.


poss_empty_setof(_,_, []).
no_loop_or_loopcheck_off( _, _) :- loopcheck(off), !.
no_loop_or_loopcheck_off( Next, StateLists ) :-
\+( already_reached( Next, StateLists ) ).

%% Check whether State (or some equivalent state) has already been
%% reached in any state list in StateLists.
already_reached( State, StateLists ) :-
member( StateList, StateLists ),
member( State1, StateList ),
equivalent_states( State, State1 ).

%% Print out list, each element on a separate line.


showlist([]).
showlist([H | T]) :- write( H ), nl, showlist( T ).

%% Report progress after each cycle of the planner:


report_progress( StateLists, Status ) :-
length( StateLists, NS ),
StateLists = [L|_], length( L, N ),
Nminus1 is N - 1,
write( 'Found '), write( NS ),
write( ' states reachable in path length ' ), write(Nminus1), nl,
( Status = ongoing ->
(write( 'Computing extensions of length : ' ), write(N), nl)
; true
).

%% To run this you need to define the following predicates:

% initial_state( SomeState ).
% goal_state( AnotherState ).

% Specify possible transitions from any state S1


% transition( S1, S2 ) :- conditions.
% : : % specify as many as needed
% transition( S1, S2 ) :- conditions.

% You can add a further condition on what states are valid:


% legal_state( S ) :- conditions.
% If no special conditions are needed just use:
% legal_state( _ ). % Allow any state

% You can tell the planner that some state representations are equivalent.
% equivalent_states( S1, S2 ) :- conditions.
% If all distinct state expressions represent different states, just use:
% equivalent_states( S, S ).
% The equivalent_states predicate is only used when checking if a generated
% state is equivalent to an already reached state, when loopcheck is on.

% You must tell the planner whether to check for and discard repeated states.
% Specify one of:
% loopcheck(off).
% loopcheck(on).
% Eliminating loops can greatly prune the search space.
% But looking for loops can use a lot of processing time, and may not be
% worth doing (especailly if loops cannot occur!).

% To run each time file is loaded, add the following command to the
% the end of your program file.
% :- find_solution.

% This special SWISH comment adds the find_solution query to the examples
% menu under the console window. So you can use that instead when running
% in SWISH. (But you first need to define the initial state, goal state,
% transition relation etc., as explained above
/** <examples>
?- find_solution.
*/

Waterjug.pl Program:

:- include(bb_planner).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% bb_planner Example: A Measuring Jugs Problem
%% Changes: 1) Defined goal muliple possible goal_state options, which now
%% works because of update to bb_planner
%% 2) Simplified and added explanation to the pour/4 predicate.

%%% There are three jugs (a,b,c), whose capacity is respectively:


%%% 3 litres, 5 litres and 8 litres.
%%% Initially jugs a and b are empty and jug c is full of water.

%%%% Goal: Find a sequence of pouring actions by which you can measure out
%%% 4 litres of water into one of the jugs without spilling any.

%%% State representation will be as follows:


%%% A state is a list: [ how_reached, Jugstate1, Jugstate2, Jugstate3 ]
%%% Where each JugstateN is a lst of the form: [jugname, capcity, content]
initial_state( [initial, [a,3,0], [b,5,0], [c,8,8]]).

%% Define goal state to accept any state where one of the


%% jugs contains 4 litres of water:
goal_state( [_, [a,_,4], [b,_,_], [c,_,_]]).
goal_state( [_, [a,_,_], [b,_,4], [c,_,_]]).
goal_state( [_, [a,_,_], [b,_,_], [c,_,4]]).

% Is it possible to get to this state?


%goal_state( [_, [a,_,_], [b,_,3], [c,_,3]]).
% Or this one?
%goal_state( [_, [a,_,_], [b,_,_], [c,_,6]]).

% What if I want to share out the water equally between two people?

%%% The state transitions are "pour" operations, where the contents of
%%% one jug is poured into another jug up to the limit of the capacity
%%% of the recipient jug.
%%% There are six possible pour actions from one jug to another:
transition( [_, A1,B1,C], [pour_a_to_b, A2,B2,C] ) :- pour(A1,B1,A2,B2).
transition( [_, A1,B,C1], [pour_a_to_c, A2,B,C2] ) :- pour(A1,C1,A2,C2).
transition( [_, A1,B1,C], [pour_b_to_a, A2,B2,C] ) :- pour(B1,A1,B2,A2).
transition( [_, A,B1,C1], [pour_b_to_c, A,B2,C2] ) :- pour(B1,C1,B2,C2).
transition( [_, A1,B,C1], [pour_c_to_a, A2,B,C2] ) :- pour(C1,A1,C2,A2).
transition( [_, A,B1,C1], [pour_c_to_b, A,B2,C2] ) :- pour(C1,B1,C2,B2).

%%% The pour operation is defined as follows:


% Case where there is room to pour full contents of Jug1 to Jug2
% so Jug 1 ends up empty and its contents are added to Jug2.
pour( [Jug1, Capacity1, Initial1], [Jug2, Capacity2, Initial2], % initial jug states
[Jug1 ,Capacity1, 0], [Jug2, Capacity2, Final2] % final jug states
):-
Initial1 =< (Capacity2 - Initial2),
Final2 is Initial1 + Initial2.

% Case where only some of Jug1 contents fit into Jug2


% Jug2 ends up full and some water will be left in Jug1.
pour( [Jug1, Capacity1, Initial1], [Jug2, Capacity2, Initial2], % initial jug states
[Jug1 ,Capacity1, Final1], [Jug2, Capacity2, Capacity2] % final jug states
):-
Initial1 > (Capacity2 - Initial2),
Final1 is Initial1 - (Capacity2 - Initial2).

%% Define the other helper predicates that specify how bb_planner will operate:
legal_state( _ ). % All states that can be reached are legal
equivalent_states( X, X ). % Only identical states are equivalent.
loopcheck(on). % Don't allow search to go into a loop.

%% Call this goal to find a solution.


%:- find_solution.

% This special comment adds the find_solution query to the examples menu
% under the console window.
/** <examples>
?- find_solution.
*/

Output:

You might also like