How I can add all the data in a knowledge base in Prolog? - prolog

I need help with this exercise of Prolog:
% items
items (cell).
items (labial).
items (control).
items (mirror).
% Weight of each item
weight (cell 2).
weight (labial, 3).
weight (control, 5).
weight (mirror, 10).
capacity (X, Y, Z, V) :-
weight (X C1), weight (Y, C2), weight (Z, C3), sum (C1, C2, C3, R), V> = R.
sum (X, Y, Z, K) :- K is X + Y + Z.
this program does is give me a combination of 3 items or less a given weight, eg capacity (X, Y, Z, 15).
result is, X: cell, Y: Lipstick, Z: mirror, X: control, Y: cell, Z: mirror. successively with all combinations where the sum of the 3 weight no higher input.
At the moment I am limited by the number of income variables manually, capacity (X, Y, Z, N. .......) I want that the combination with respect to number of items that are in the knowledge base, not manually enter the variables. How I can do that?
so would be ideal capacity (weight) and response.
the combination of items where the weight does not exceed
phone, lipstick, mirror.
control labial phone.
mirror, control, labilal .......
Sorry I do not speak English, I'm using google translator.

It looks like the structure that you are looking for is a list and you should look it up ([HD:TL] where TL is a list). The solution I provide below should show how to use lists to the desired effect although my solution allows duplicates and doesn't care about the order of the list. If this is for homework, you should be able to figure out how to fix that on your own once you know a little about lists.
Basically, the first predicate handles making long lists of items, HD is an item with weight X, and it looks for a predicate to define the tail (TL) list; the second handles the end of a list (TL is [] in the previous inductive step) and empty lists (because even empty lists need love too).
items(cell).
items(labial).
items(control).
items(mirror).
weight(cell,2).
weight(labial,3).
weight(control,5).
weight(mirror,10).
capacity(W, [HD|TL]) :- items(HD),weight(HD,X),W>0,capacity(W-X,TL).
capacity(W, []) :- W>=0.

Related

How to call a function in foreach with local variables as arguments?

I have a knapsack problem to solve in B-Prolog. I have to write something like:
knapsack(X, Indexes, Quantity, Weights, Values, Capacity)
X - array with number of ith item that is put in the bag
Indexes - [0, ..., NumOfItems-1]
Quantity - array with number of available ith items
Weights - array with weight of each item on ith position (only 1 item)
Value - array with value of each item (only 1 item)
Capacity - limit for bag capacity
The task must be solved using a predicate:
get([X|_], 0, X).
get([_|X], I, Y) :- I>0, I1 is I-1, get(X, I1, Y).
which returns the element on ith index, considering they can start at 0. Then Y has the value of that element.
Also, we must maximize the item values. I tried to make it work not only for fixed number of items.
Since I'm just a beginer for Prolog, I had an idea, but it doesn't wort of course.
knapsack(X, Indexes, Quantity, Weights, Values, Capacity) :-
/*
Find the last index of items,
Calculate NumOfItems as last index+1,
Make an array X with NumOfItems elements,
Define domen for each item (ith element in X) as 0..NumOfThatItem
(meaning I can take zero or more up to the max number of that element that is avaliable)
*/
last(Indexes, Elem),
NumOfItems is Elem+1,
length(X, NumOfItems),
foreach(I in 1..NumOfItems, get(Quantity, I, K), X[I]::0..K),
/*
Set up the constraint that sum of item weights must not be bigger than bag capacity
*/
sum([X[I]*T : I in 1..NumOfItems], get(Weights, I, T)) #=< Capacity,
/*
Maximize the values of items in the bag, and find all possible combinations for it
*/
labeling([maximize( sum([X[I]*V : I in 1..NumOfItems, get(Values, I, V)]))], X),
/*
This is the part of a task, to write out the Profit we made by taking those items,
and the overall weight that we have put in the bag.
*/
Profit is sum([X[I]*V : I in 1..NumOfItems, get(Values, I, V)]),
Weight is sum([X[I]*T : I in 1..NumOfItems, get(Weights, I, T)]),
nl,
write('Profit: '), write(Profit), nl,
write('Weight: '), write(Weight), nl
.
I am using B-Prolog Version 8.1, it can be downloaded on this link(<- click)
You can copy my code and place it in the BProlog folder on the location where you chose to install it.
When you open/start bp aplication:
cl('path_to_my_code.pro').
Exaple I have for this problem is the following:
knapsack(X, [0,1,2,3], [1,1,1,4], [50,10,5,1], [1000,2000,100,1], 63).
And that should give us:
Profit: 3003
Weight: 63
X = [1,1,0,3]
I get the following:
***illegal_local_variables(get([1,1,1,4], _f8, _fc))
I concluded that he doesn't recognize I as a number.
If you have any book or article or whatever related to this please share.
How should this be done? Please help...
Thank you for your time
At this point since you get the error you should test get/3 predicate to see if this working properly. The problem is in the part:
I>0, I1 is I-1, get(X, I1, Y).
Since you call get with I as a variable, I>0 yields instantiation error, instead you can write:
get([X|_], 0, X).
get([_|X], I, Y) :- get(X, I1, Y), I is I1+1, I>0.

Sliding tile puzzle with varying tile size using logic programming

So I am trying to solve this Booth arrangement problem given here. It is basically a sliding tile puzzle where one (booth)tile has to reach a target spot and in the end all other (booths)tiles should be in their original location. Each tile/booth has a dimension and following are the input fact and relation descriptions:
One fact of the form room(W,H), which specifies the width W and
height H of the room (3 ≤ W, H ≤ 20).
One fact booths(B), which
specifies the number of booths (1 ≤ B ≤ 20).
A relation that consists
of facts of the form dimension(B, W, H), which specifies the width W
and height H of booth B.
A relation consisting of facts of the form
position(B, W, H), specifying the initial position (W, H) of booth B.
One fact target(B, W, H), specifying the destination (W, H) of the
target booth B.
An additional fact horizon(H) gives an upper bound on
the number of moves to be performed.
The program is supposed to read input facts from a file but I am just trying to do the solving so I have just copy pasted one possible input for now, and I have written some basic clauses:
room(3, 3).
booths(3).
dimension(1, 2, 1).
dimension(2, 2, 1).
dimension(3, 1, 1).
position(1, 0, 1).
position(2, 1, 2).
position(3, 0, 0).
target(3, 0, 2).
horizon(10).
xlim(X) :- room(X,_).
ylim(X) :- room(_,X).
sum(X,Y,Z) :- Z is X+Y .
do(position(B,X,Y),movedown,position(B,X,Z)) :- Y > 0 , sum(Y,-1,Z) .
do(position(B,X,Y),moveup,position(B,X,Z)) :- ylim(L), Y < L , sum(Y,1,Z) .
do(position(B,X,Y),moveleft,position(B,Z,Y)) :- X > 0 , sum(X,-1,Z) .
do(position(B,X,Y),moveright,position(B,Z,Y)) :- xlim(L), X < L, sum(X,1,Z) .
noverlap(B1,B2) :-
position(B1,X1,Y1),
position(B2,X2,Y2),
ends(Xe1,Ye1,B1),
ends(Xe2,Ye2,B2),
( Xe1 < X2 ;
Xe2 < X1 ;
Ye1 < Y2 ;
Ye2 < Y1 ).
ends(Xe,Ye,B) :-
dimension(B,W,H),
position(B,X,Y),
Xe is X+W-1,
Ye is Y+H-1.
between(X,Y,Z) :-
X > Y ,
X < Z .
validMove(M,B) :- do(position(B,X,Y),M,position(B,Xn,Yn)) .
I am new to Prolog and I am stuck on how to go from here, I have the no_overlap rule so I can test if a move is valid or not but I am not sure how with the current clauses that I have. My current clauses for moves do/3 probably needs some modification. Any pointers?.
You need to express the task in terms of relations between states of the puzzle. Your current clauses determine the validity of a single move, and can also generate possible moves.
However, that is not sufficient: You need to express more than just a single move and its effect on a single tile. You need to encode, in some way, the state of the whole puzzle, and also encode how a single move changes the state of the whole task.
For a start, I recommend you think about a relation like:
world0_move_world(W0, M, W) :- ...
and express the relation between a given "world" W0, a possible move M, and the resulting world W. This relation should be so general as to generate, on backtracking, each move M that is possible in W0. Ideally, it should even work if W0 is a free variable, and for this you may find clpfd useful: Constraints allow you to express arithmetic relations in a much more general way than you are currently using.
Once you have such a relation, the whole task is to find a sequence Ms of moves such that any initial world W0 is transformed to a desired state W.
Assuming you have implemented world0_move_world/3 as a building block, you can easily lift this to lists of moves as follows (using dcg):
moves(W0) --> { desired_world(W0) }.
moves(W0) --> [M], { world0_move_world(W0, M, W) }, moves(W).
You can then use iterative deepening to find a shortest sequence of moves that solves the puzzle:
?- length(Ms, _), initial_world(W0), phrase(moves(W0), Ms).

Prolog project. Labyrinth. Checking if next move is possible

Noob at prolog.
I need to do a school project related to a labyrinth.
My question is:
In the project I need to make a function "possible moves".
It gets a labyrinth, a current position and previous moves
Lab is represented by (these are the walls positions):
[[[down,left,up],[left,down,up],[right,up],[up],[,up],[right,left,up]],
[[left,down],[down,up],[down,up],[],[down],[right,down]],
[[left,up],[down,up],[down,up],[down],[down,up],[right,down,up]],
[[right,left],[left,up],[up],[up],[up],[right,up]],
[[left,down],[right,down],[left,down],[down],[down],[right,down]]]
And Poss_moves like:
Poss_moves(Lab, current_poss, previous_moves, possible_moves)
which is called as follows.
?- ..., poss_moves(Lab1, (2,5),
[(beginning, 1, 6), (down, 2, 6), (left, 2, 5)], possible_moves).
Lab1 = ...,
Poss = [ (up, 1, 5), (left, 2, 4)].
Important:
--- You can only move up, down, left or right.
PS: Sorry for my bad english.
PS: Edited.
PS: Can I do in prolog:
distance((Line1, Column1), (Line2, Column2), Dist) :-
Dist is abs(Line1 - Line2) + abs(Column1 - Column2).
PS: The lab that matches the picture.
[[[right,left,up],[left,down,up],[down,up],[up],[right,up],[right,left,up]],
[[left,down],[down,up],[b,up],[],[down],[right,down]],
[[left,up],[down,up],[down,up],[down],[down,up],[right,down,up]],
[[right,left],[left,up],[up],[up],[up],[right,up]],
[[left,down],[right,down],[left,down],[down],[down],[right,down]]]
By the way, the lab can change.
Thanks
EDIT 2:
I made this changes:
% predicates
lookup(Lab,(X,Y),Walls)
calc(Direction,(X1,Y1),(X2,Y2)
map_calc((X,Y),L,R)
poss_moves(Lab, (X,Y), PreviousMoves, PossibleMoves)
% clauses
nth(1, [H|T], H).
nth(N,[_|T],R) :-
M is N-1,
nth(M,T,R).
lookup(Lab, (X, Y), Walls) :-
nth(N,Lab,R),
Y == R,
X == Walls.
calc(up,(X,Y1),(X,Y2)) :-
Y2 is Y1-1.
calc(down,(X,Y1),(X,Y2)) :-
Y2 is Y1+1.
calc(left,(X,Y1),(X,Y2)) :-
X2 is X1-1.
calc(right,(X,Y1),(X,Y2)) :-
X2 is X1+1.
map_calc(_,[],[]).
map_calc((X,Y),[H|T],[(H,X1,Y1)|S]) :-
calc(H,(X,Y),(X1,Y1)),
map_calc((X,Y),T,S).
% main predicates
poss_moves(Lab, (X,Y), PreviousMoves, PossibleMoves) :-
lookup(Lab, (X,Y), Walls),
map_calc((X,Y), Lab, PossibleMoves).
I'm almost 100% sure that the lookup is incorrect.
Thanks
The first thing you need to do is define a way of looking up a cell in the Labryinth datastructure. You need something like:
lookup(Lab,(X,Y),Walls)
which is true if Walls is the list of walls present at cell (X,Y) in Lab. To do this you'll need an 'nth' predicate which finds the nth element of the list.
nth(1,[H|T],H).
nth(N,[_|T],R) :- M is N-1, nth(M,T,R).
Normally one would use 0 to return the first element of a list but your maze co-ordinates start at (1,1) so I've made nth do the same.
Now you can build lookup(Lab,(X,Y),Walls) which is true if the Yth element of Lab is Row and the Xth element of Row is Walls.
Next you need a way of turning the list of Walls in to a list of possible moves. A move consists of a direction and the co-ordinates of the new position so first write some helpers to calculate the new co-ordinates:
calc(Direction,(X1,Y1),(X2,Y2)
should be true if (X2,Y2) is the co-ordinate you get to if you move in Direction from (X1,Y1). Here is an example clause of calc, the others are similar:
calc(up,(X,Y1),(X,Y2)) :- Y2 is Y1-1.
But we need to apply calc to every element of the list of Walls to get the list of moves (this is called 'map' in functional programming)
map_calc((X,Y),L,R)
should be true if R is the result of applying calc to every direction in L starting from co-ordinate (X,Y).
map_calc(_,[],[]).
map_calc((X,Y),[H|T],[(H,X1,Y1)|S]) :- calc(H,(X,Y),(X1,Y1)),
map_calc((X,Y),T,S).
Now you can write poss_moves:
poss_moves(Lab, (X,Y), PreviousMoves, PossibleMoves)
i.e. PossibleMoves is the list of moves you can make from (X,Y) given that lookup(Lab,(X,Y),Walls) is true, and that map_calc on Walls gives you PossibleMoves.

How to maximize the goal in prolog?

I am trying to solve the knapsack problem in prolog. Following is my implementation.
% 'ks' is compound term which has 4 argumets
% 1 - List of items to be chosen from.
% 2 - Maximum weight a knapsack can carry.
% 3 - Selected items which sum of weights is less than or equal to knapsack capacity.
% 4 - The gain after choosing the selected item.
% base conditions where input list contains only one items and
% it is either selected or excluded.
ks([item(W1, V1)], W, [item(W1, V1)], V1):- W1 =< W.
ks([item(W1, _)], W, [], 0):- W1 > W.
% An item from the input list is chosen in the knapsack.
% In that case, we recurse with smaller list with reduced weight constraint.
ks(ItemList, MaxWeight, SelectItems, Gain) :-
append(Prefix, [item(W1, V1)|Suffix], ItemList),
append(Prefix, Suffix, RemList),
NewWeight is MaxWeight - W1,
W1 =< MaxWeight,
append([item(W1, V1)], SelectItems1, SelectItems),
ks(RemList, NewWeight, SelectItems1, Gain1),
Gain is V1 + Gain1.
% An item from the input list is not chosen in the knapsack.
% In that case, we recurse with smaller list but with the same weight constraint.
ks(ItemList, MaxWeight, SelectItems, Gain) :-
append([P1|Prefix], [item(W1, V1)|Suffix], ItemList),
append([P1|Prefix], Suffix, RemList),
not(member(item(W1, V1), SelectItems)),
ks(RemList, MaxWeight, SelectItems, Gain).
The input to the program will be list of items as below. in term item(W, V) W is weight of the item while V is value of the item. Goal to maximize the value for the given weight constraint.
ks([item(2,3), item(3,4), item(4,5), item(5,8), item(9,10)], 20, List, Gain).
List = [item(2, 3), item(3, 4), item(4, 5), item(5, 8)],
Gain = 20 ;
While I am able to generate all the combinations of items with above program, I am not able to code to find out the maximum gain only.
Could any one please point me the right direction?
Thanks.
I think that to find reusable abstractions it's an important point of studying programming. If we have a subset_set/2 that yields on backtracking all subsets, ks/4 becomes really simple:
subset_set([], _).
subset_set([H|T], Set) :-
append(_, [H|Rest], Set),
subset_set(T, Rest).
ks(Set, Limit, Choice, Gain) :-
subset_set(Choice, Set),
aggregate((sum(W), sum(G)), member(item(W, G), Choice), (TotWeight, Gain)),
TotWeight =< Limit.
and then
ks_max(Items, Limit, Sel, WMax) :-
aggregate(max(W,I), ks(Items,Limit,I,W), max(WMax,Sel)).
despite its simplicity, subset_set/2 is not really easy to code, and library available alternatives (subset/2, ord_subset/2) don't enumerate, but only check for the relation.
There are at least two things you can do, depending on how you want to approach this.
You could simply collect all solutions and find the maximum. Something along the lines of:
?- Items = [item(2,3), item(3,4), item(4,5), item(5,8), item(9,10)],
findall(Gain-List, ks(Items, 20, List, Gain), Solutions),
sort(Solutions, Sorted),
reverse(Sorted, [MaxGain-MaxList|_]).
% ...
MaxGain = 26,
MaxList = [item(9, 10), item(5, 8), item(4, 5), item(2, 3)].
So you find all solutions, sort them by Gain, and take the last. This is just one way to do it: if you don't mind collecting all solutions, it is up to you how you want to pick out the solution you need from the list. You might also want to find all maximum solutions: see this question and answers for ideas how to do that.
The cleaner approach would be to use constraints. As the comment to your questions points out, it is not very clear what you are actually doing, but the way to go would be to use a library like CLP(FD). With it, you could simply tell labeling/2 to look for the maximum Gain first (once you have expressed your problem in terms of constraints).
greedy Approximation algorithm :
pw((P,W),Res) :- PW is P/W, Res=(PW,P,W).
pws(Ps_Ws,PWs) :- maplist(pw,Ps_Ws,PWs).
sort_desc(List,Desc_list) :-
sort(List,Slist),
reverse(Slist,Desc_list).
ransack_([],_,_,[]).
ransack_([(_,P,W)|PWs],Const,Sum,Res) :-
Sum1 is W+Sum,
Sum1 < Const ->
Res=[(P,W)|Res1],
ransack_(PWs,Const,Sum1,Res1)
;ransack_(PWs,Const,Sum,Res).
% ransack(+[(P,W)|..],+W,,Res)
ransack(L_PWs,W,Res) :-
pws(L_PWs,Aux),
sort_desc(Aux,PWs),
ransack_(PWs,W,0,Res).
Test
item(W, V)-->(V,W)
| ?- ransack([(3,2),(4,3),(5,4),(8,5),(10,9)],20,Res).
Res = [(8,5),(3,2),(4,3),(5,4)] ? ;
no

Longest increasing subset Prolog

I want to create in Prolog to find longest increasing subset of entered list. For example, you enter list of [3,1,2] and the output is [1,2],
?- subset([3,1,2], X).
X = [1,2]
I have code which shows all the subsets of this list:
subset([],[]).
subset([_|X],Y):-subset(X,Y).
subset([A|X],[A|Y]):-subset(X,Y).
Can anyone help me to find just the longest increasing subset?
Do you mean [1,3,5,6,7] to be the answer for [4,1,3,8,9,5,6,7]? IOW, do you really mean subsets, or just sublists, i.e. contiguous portions of the list?
If the latter is the case, you won't need subsets. The search is linear. If in a list [a,b,c,d,e,f] you find that d > e and the increasing sequence [a,b,c,d] stops, you don't need to restart the search from b now: the sequence will still break at d. You will just continue your search from e.
So, we'll just carry around some additional information during the search, viz. the current and the winning-so-far sub-sequences. And their lengths.
longest_incr([],0-[]).
longest_incr([A|B],RL-R):- % R is the result, of length RL
longest_aux(B,[],0, [A],1, RL-R).
longest_aux([], Win,N, Curr,K, RL-R):-
( K>N -> RL=K, reverse(Curr,R) ; RL=N, reverse(Win,R) ).
longest_aux([A|B],Win,N, Curr,K, RL-R):- Curr = [X|_], L is K,
( A>X -> longest_aux(B,Win, N, [A|Curr],L+1,RL-R) % keep adding
; L>N -> longest_aux(B,Curr,K, [A], 1, RL-R) % switch the winner
; longest_aux(B,Win, N, [A], 1, RL-R) % winner unbeaten
).
If OTOH you really need the longest subset ... there's a contradiction there. A set can have its elements rearranged, so the longest subset of a given list will be
longset_subset(L,R):- sort(L,S), R=S.
Perhaps you mean the longest order-preserving sub-sequence, i.e. it is allowed to be non-contiguous. Then you can gather all solutions to your subset with findall or similar predicate, and analyze these results:
longest_subseq(L,R):-
findall( S, subset(L,S), X),
maplist( longest_incr, X, Y),
keysort( Y, Z),
last( Z, _Len-R).
The above has a lot of redundancy in it. We can attempt to improve its efficiency by only allowing the increasing subsequences:
incr_subseq([],[]).
incr_subseq([_|X],Y):- incr_subseq(X,Y).
incr_subseq([A|X],[A|Y]):- incr_subseq(X,Y), ( Y=[] ; Y=[B|_], A<B).
Now all the sub-sequences found by the above predicate will be increasing, so we can just take their lengths:
lenlist(List,Len-List) :- length(List,Len).
longest_subseq(L,R):-
findall( S, incr_subseq(L,S), X),
maplist( lenlist, X, Y),
keysort( Y, Z),
last( Z, _Len-R).
Or, the linear searching longest_incr could be tweaked for a more efficient solution. Instead of maintaining just one winning sub-sequence, it would maintain all the relevant possibilities as it goes along the input list.
Just out of curiosity, would it be possible in prolog to realize something like this for finding longest increasing subsequence:
You find all subsets of list
Than you find, which of these subsets are increasing
And then you search for the longest
If it's possible, how could I do that in Prolog?

Resources