Replace a list in prolog - prolog

I want to add a element to a list and replace it with my list.
So i wrote
initialstate(0,[],[[1,0],[2,3],[1,2],[1,3]]).
add(X,L2,[X|L2]).
I would like to make something like that...
?- initialstate(_,List,_),add(4,List,List)
and replace me the initialstate to this one
initial_state(0,[4],[[1,0],[2,3],[1,2],[1,3]]).
The maining question for me it's how to replace the list inside the indetifiers "initialstate".
I am new in prolog...Please help me... and sorry if it is something stupid.

once provided the appropriate declaration
:- dynamic initialstate/3.
you could update your DB in this way
?- retract(initialstate(A,B,C)), assertz(initialstate(A,[4|B],C)).

If you want to change a list you get a different list. So you need a different name for it.
Prolog is not an imperative language but more a descriptive one. This means: you do not say do this and this. You say this is like that and when this is the case this is true/false in files (knowledge). Then you start the interpreter, consult the knowledge and ask questions wether something is true.
Writing A = B means that A is always B.
?- initialstate(_,List,_),add(4,List,List)
means initialstate of a List is when 4 added to the list is the list itself.
This is not true. if 4 is added there should be a 4 where no 4 was before.
You can do this:
append4(List, ListWithFourInside) :- append(List, [4], ListWithFourInside).
Which reads like when I append 4 to a list I get a list with 4 inside.
It can be done shorter if you want the 4 in the beginning
add4(List, ListWithFourInside) :- [4 | List] = ListWithFourInside.
or even shorter:
add4(List, [4|List]).

Related

Edit Prolog program to output the result of a computation

I've found something about this in other questions, but mine is a bit different.
Given a string, I have to output another string with no adjacent duplicates.
E.g., given [a,a,b,b,c,d,a], my output will be [a,b,c,d,a].
Now, I've wrote the following recursive program to check if a certain given string has adjacent duplicates:
notequal(A,[]).
notequal(A,[X|S]) :- not(A=X).
noadj([]):-!.
noadj([A|S]) :- notequal(A,S), noadj(S).
How would I modify it in order to output what I described? I've tried multiple times but I'm new to prolog and I can't seem to get into its logic.
Of course, I'll need another variable, which would contain an element if notequal is true for that element.
So my idea is to iterate through the list and only add a certain term to the result if it passes the "notequal" test.
I'll edit this: I finally managed to do something like that by adding
noadjlist([X|S],[X|LS]) :- notequal(X,S), noadjlist(S,LS).
noadjlist([X|S],LS) :- noadjlist(S,LS).
noadjlist([],LS):-!.
However, my results are like:
?- noadjlist([1,2,2,3],LS).
LS = [1, 2, 3|_19316] .
why do I get that uninstantiated variable at the end?
noadjlist([],LS):-!.
should be
noadjlist([],[]):-!.

Turning a relation into a fact

I would like to ask a very basic question in prolog. I have a list of lists that looks like [[a_1,a],[a_2,c],[a_3,e,f]]. I would like to create a relation which gets that list and adds an infix to each one of those sublists. For example I would like to insert x as infix: x([[a_1,a]),x([a_2,c]),x([a_3,e,f]]). The goal is to make the relation to be a fact. I was trying to use findall but without any success.
Example:
turn([[a_1,a],[a_2,c],[a_3,e,f]]).
Output:
[x([a_1,a]),x([a_2,c]),x([a_3,e,f])].
How to implement it?
[x([a])] is not, in and of itself, a fact. It's just a different Prolog term form. A fact is a term that is asserted in the database, doesn't represent a predicate, and can be queried. Sounds like you don't want to convert to "facts", but you just want to convert to a different term form.
It would be easy in this case with maplist:
turn_item(X, x(X)).
turn(TermList, NewTermList) :-
maplist(turn_item, TermList, NewTermList).
Then:
| ?- turn([[a_1,a],[a_2,c],[a_3,e,f]], L).
L = [x([a_1,a]),x([a_2,c]),x([a_3,e,f])]
yes

How to print variable value from a question?

I´m making a one bit addition:
sumbit(CIN,A,B,CO,R):- ...
?- sumbit(0
,1
,1
,CO
,R)
,write(CIN),nl
,write(A),nl
,write("+"),nl
,write(B),nl
,write("--"),nl
,write(CO),write(R),nl.
What I want to do is to print the variable values of CIN,A,B,CO and R.
It should come out something like this:
0
1
+
1
--
10
Instead it comes out as this:
_40
_73
+
_149
--
10
Yes.
Also is there a way to not print the "Yes"?
I´m using strawberry prolog if it helps.
Thank you in advance
One way to achieve that without altering your predicate definition is to tweak the query, like so:
?- [CIN, A, B] = [0, 1, 1]
,sumbit(CIN
,A
,B
,CO
,R)
,write(CIN),nl
,write(A),nl
,write("+"),nl
,write(B),nl
,write("--"),nl
,write(CO),write(R),nl.
Now all variables are instantiated, either by the call itself, or prior to the call.
When a variable is not instantiated, there's no value to print, so its "name" is printed instead. But since non-used name has no meaning in itself, it can be freely renamed by the system to anything. In SWI Prolog:
1 ?- write(A).
_G1338
true.
The renaming is usually done, as part of the Prolog problem solving process, to ensure that any two separate invocations of the same predicate do not interfere with each other.
So where SWI Prolog uses names like _G1338, the Prolog implementation you're using evidently uses names with the numbers only, after the underscore, like _40.
I found an answer by putting the write() inside the sumbit(...) predicate:
sumbit(CIN,A,B,CO,R):-
xor_(A,B,R1)
,and(A,B,R2)
,xor_(R1,CIN,R)
,and(R1,CIN,R4)
,or(R2,R4,CO)
,write(CIN),nl
,write(A),nl
,write("+"),nl
,write(B),nl
,write("--"),nl
,write(R),nl.
There are still some unanswered questions though:
is there a way to not print the "Yes"?
what was the _number that came out before?

Graph implementation (does graph include all vertices?)

Trying to implement following predicate, which takes on input
list of lists - one list = one tested graph T (as edges)
graph G itself (as edges)
and tests whether T includes all of the vertices of G. If it does(true) should return it. Basically it's list filtering.
What I have so far is:
covb([],G).
covb([H|R],G) :-
isItCov(G,H), covb(R,G).
isItCov([],H).
isItCov([V-W|R],H) :-
vertex(V,H),
vertex(W,H),
isItCov(R,H).
vertex(V,[V-_|G]).
vertex(V,[_-V|G]).
vertex(V,[_|G]):- vertex(V,G).
For covb([[a-c,c-b,c-d]],[a-b,a-c,a-d,c-d,b-c]) works fine(true). For covb([[a-c]],[a-b,a-c,a-d,c-d,b-c]) works fine too (false). I got an issue while I call it with multiple lists like covb([[a-c,c-b,c-d],[a-c]],[a-b,a-c,a-d,c-d,b-c]). which should work only for the first one.
I actually got two questions -
Why does it work for one list only?
I want to return items of lists of lists which passed the condition and returned true (that's the filtering part). How should I do that?
First of all, your program has a number of singleton variable warnings. Do not ignore singleton variable warnings. They can hide real bugs. Also, since more experienced Prolog users here know that programs with singleton variable warnings are not even worth running, they will (a) just see the warnings and decide that they are no longer interested in trying to help you, or (b) fix the warnings on their side, but then by definition they will be working on a program that is no longer the program you posted!
Now for your questions.
Why does it work for one list only?
It's really not clear what you are asking here, or just above with "covb([[a-c,c-b,c-d],[a-c]],[a-b,a-c,a-d,c-d,b-c]). which should work only for the first one."
This query does fail:
?- covb([[a-c,c-b,c-d],[a-c]],[a-b,a-c,a-d,c-d,b-c]).
false.
This comes down to testing each of the two lists:
?- isItCov([a-b,a-c,a-d,c-d,b-c], [a-c,c-b,c-d]).
true .
?- isItCov([a-b,a-c,a-d,c-d,b-c], [a-c]).
false.
The first list does cover the graph, while the second doesn't. Overall, your definition of covb/2 is written to succeed if all lists cover the graph. This is not the case, so your covb/2 query fails.
Was this what you wanted to know?
I want to return items of lists of lists which passed the condition and returned true (that's the filtering part). How should I do that?
You could see if your Prolog's documentation has something for the word "filter". On SWI-Prolog you can do this:
?- apropos(filter).
true.
This will point you to the include/3 predicate, which seems to do what you want:
?- include(isItCov([a-b,a-c,a-d,c-d,b-c]), [[a-c,c-b,c-d],[a-c]], Covers).
Covers = [[a-c, c-b, c-d]].
If you want to write a filter predicate for your concrete application, it might look something like this:
graph_covers(_Graph, [], []).
graph_covers(Graph, [Nodes|NodesRest], Covers) :-
( isItCov(Graph, Nodes)
-> Covers = [Nodes|CoversRest]
; Covers = CoversRest ),
graph_covers(Graph, NodesRest, CoversRest).
This is similar to your predicate, it just adds an extra argument to collect those node lists for which isItCov/2 succeeded. If it did not succeed, it continues with a list not containing that current node list.
?- graph_covers([a-b,a-c,a-d,c-d,b-c], [[a-c,c-b,c-d],[a-c]], Covers).
Covers = [[a-c, c-b, c-d]] ;
false.

Summing an already outputted list

This is the knowledge base I am working with:
localLib('AHorowitz','Stormbreaker',2).
localLib('AHorowitz','Scorpia',4).
localLib('AHorowitz','Ark Angel',6).
The key for the knowledge base is as follows:
localLib(W,B,C) where
W=Writer
B=Book
C=Acknowledgements
I would like to write a rule that adds up all the acknowledgements of the writer.
This is the code I have written so far:
getAcknowledgement(W,X):- findall(C,localLib(W,_,C),X).
This rule helps me list all the acknowledgements in separate list e.g.
?- getAcknowledgement('AHorowitz',X).
X = [2, 4, 6]
I am now getting stuck on how to add these items. I know of the sum_list built in and though I know it is not correct the thing I want to achieve is this:
getAcknowledgement(W,X):- findall(C,localLib(W,_,C),X).
sum_list(X,[getAcknowledgement]).
/* I would like to sum the output that I receive from the first rule above.
The KB has been simplified in this example to 3 clauses however in reality
there are 1000.*/
How would I go about doing this, any help would be great?
It sounds like you want to find the count of acknowledgements by writer.
bagof/3 is your friend here. It
bagof(+Template, :Goal, -Bag)
Unify Bag with the alternatives of Template. If Goal has free variables besides the one
sharing with Template, bagof/3 will backtrack over the alternatives of these free
variables, unifying Bag with the corresponding alternatives of Template. The construct
+Var^Goal tells bagof/3 not to bind Var in Goal. bagof/3 fails if Goal has no
solutions.
findall/3 is
equivalent to bagof/3 with all free variables bound with the existential operator (^),
except that bagof/3 fails when Goal has no solutions.
So...this should get you the summed count of knowledgements for a given writer, or, if Writer is unbound, on backtracking, it will find the solutions for all writers, one at a time.
acknowledgements_by_writer( Writer , Acknowledgements ) :-
bagof( N , local_lib(Writer,_,N) , Ns ) ,
sum_list(Ns,Acknowledgments).
If you want the overall count of acknowledgements, something like this ought to do you
total_acknowledgements(T) :-
findall(N,local_lib(,,N),Ns),
sum_list(Ns,T).

Resources