atom_elements(h1,hydrogen,[c1]).
atom_elements(n1,nitrogen,[o1, o2, c2]).
atom_elements(o1,oxygen,[n1]).
atom_elements(o2,oxygen,[n1]).
atom_elements(n2,nitrogen,[o3, o4, c4]).
atom_elements(o3,oxygen,[n2]).
atom_elements(o4,oxygen,[n2]).
atom_elements(h5,hydrogen,[c5]).
atom_elements(n3,nitrogen,[o5, o6, c6]).
atom_elements(o5,oxygen,[n3]).
atom_elements(o6,oxygen,[n3]).
atom_elements(h7,hydrogen,[c7]).
atom_elements(h8,hydrogen,[c7]).
atom_elements(h9,hydrogen,[c7]).
atom_elements(c1,carbon,[c2,c6,h1]).
atom_elements(c2,carbon,[c1,c3,n1]).
atom_elements(c3,carbon,[c2,c7,c4]).
atom_elements(c4,carbon,[c3,c5,n2]).
atom_elements(c5,carbon,[c4,c6,h5]).
atom_elements(c6,carbon,[c1,c5,n3]).
atom_elements(c7,carbon,[c3,h7,h8,h9]).
Example query on the 2,4,6-Trinitrotoluene:
?- tnt(X).
X = [[c1, [c2, n1, o1, o2], c3, [c4, n2, o3, o4], c5,
[c6, n3, o5, o6]]] .
My first step is to find a cycle path and show as a List. But the result is shown as fault. It cannot save the path as a list.
atom_elements(h1,hydrogen,[c1]).
atom_elements(n1,nitrogen,[o1, o2, c2]).
atom_elements(o1,oxygen,[n1]).
atom_elements(o2,oxygen,[n1]).
atom_elements(n2,nitrogen,[o3, o4, c4]).
atom_elements(o3,oxygen,[n2]).
atom_elements(o4,oxygen,[n2]).
atom_elements(h5,hydrogen,[c5]).
atom_elements(n3,nitrogen,[o5, o6, c6]).
atom_elements(o5,oxygen,[n3]).
atom_elements(o6,oxygen,[n3]).
atom_elements(h7,hydrogen,[c7]).
atom_elements(h8,hydrogen,[c7]).
atom_elements(h9,hydrogen,[c7]).
atom_elements(c1,carbon,[c2,c6,h1]).
atom_elements(c2,carbon,[c1,c3,n1]).
atom_elements(c3,carbon,[c2,c7,c4]).
atom_elements(c4,carbon,[c3,c5,n2]).
atom_elements(c5,carbon,[c4,c6,h5]).
atom_elements(c6,carbon,[c1,c5,n3]).
atom_elements(c7,carbon,[c3,h7,h8,h9]).
removeprevious(X,Y):-
X=Y.
filterList(A,In,Out) :-
exclude(removeprevious(A),In,Out).
nextlist(P,C,O) :-
atom_elements(C,_,L),
filterList(P,L,O).
findTNT(Start,Output):-
atom_elements(Start,_,List),
findTNT(Start,Start,List,[],Output).
findTNT(_,_,[],_,[]).
findTNT(Start,_,[H|_],_,Output) :-
H = Start,
write('Find it'), %For debugging%
append([H],[],Output).
findTNT(Start,Privious,[H|T],Visited,Output) :-
write(H+'--'), %For debugging%
H \== Start,
\+ member(H,Visited),
nextlist(Privious,H,List),
append([H],Visited,V),
(
findTNT(Start,H,List,V,Output),
Output = [],
findTNT(Start,Privious,T,V,Output);
append([H],Output,O),
Output is O).
The result is :
The error message is not very good, but it indicates that the problem is with your use of is. Concretely, line 65 of your code reads:
Output is O
At the problematic point in the program, Output is [] and O is [c6], which is why this goal is printed as
[] is [c6]
So the problem is that you are using is on something that is not an arithmetic expression. is is only usable for evaluating arithmetic, for example:
X is 2 + 2
It is not usable for equality of terms. Use = for that. So this last line should maybe be something more like:
Output = O
Except that that will also not work, because you are trying to "assign" a new term to a variable that is already bound to a different term. And you're trying to do "recursive append", which is something that is pretty much always wrong in Prolog. Some recent questions about this: Prolog - Recursively append numbers to a list, Prolog - Recursive append to list returning false
Related
I am trying to write a predicate in Prolog that will use my predicate 'PAR', which tests whether a 4 digit number meets certain conditions, but return a list of all numbers which are PARs, i.e. all numbers which return true when passed into par.
pars(A, C)
:- A =< 9999,
par(A) -> append(C, A, C),
A1 is A+1,
pars(A1, C).
This is my current code, with A initially passed in as 1000 (the smallest 4 digit number), but it will only return false when the first number is tried, or timeout if the first number is a PAR.
I also want the predicate to take only one argument, e.g. pars(X) where X is then the list of PARs.
par(A)
:- number_chars(A, [W,X,Y,Z]),
unique([W,X,Y,Z]),
atom_number(W, W1),
atom_number(X, X1),
atom_number(Y, Y1),
atom_number(Z, Z1),
B1 is W1 * 10 + X1,
B2 is Y1 * 10 + Z1,
0 is mod(B1,B2).
Here is my par predicate for reference, I know this is also probably very inefficient.
Any help would be appreciated, thanks in advance.
The easy way is to use a "solution-collecting" metapredicate, i.e. findall/3, bagof/3 or setof/3:
findall(P,(between(1000,9999,P),par(P)),Bag).
In this case the subgoal is between(1000,9999,P),par(P):
Generate a number P between 1000 and 9999
Test is for "par-ity"
If there is success of the above, it will be in the list Bag when findall/3 succeeds.
If there is failure of the above, the Prolog processor backtracks to the start of the subgoal and tries again, generating and testing the next number.
This can also be written more extensively (i.e. not "inlined"):
subgoal(P) :- between(1000,9999,P),par(P).
findthem(Bag) :- findall(P,subgoal(P),Bag).
(Testing this fails because I dont't have the definition of unique/1 as used in par/1.)
I'm quite new in Prolog. I'm trying to find the nth term and sum of a Fibonacci Series.
/* Fibonacci */
predicates
fibonacci(integer, integer, integer)
clauses
fibonacci(1,1,1):-!.
fibonacci(2,1,2):-!.
fibonacci(N, Term, Sum):-
N1 = N - 1,
N2 = N - 2,
fibonacci(N1, Term1, Sum1),
fibonacci(N2, Term2, Sum2),
Term = Term1 + Term2,
Sum = Term + Sum.
However while compiling in Turbo Prolog I'm getting 420 PROLOG.ERR missing on
fibonacci(N2, Term2, Sum2),
Why is this happening? Any help is appreciated. Thanks in advance.
Is that really the entire error message? It does not say what is missing?
EDIT: According to comments below, Turbo Prolog's = does indeed
correspond to is/2, so the remarks below, which are correct for
Prolog, don't apply. According to comments on the original question,
the terrible error message might be a singleton warning for Sum2.
In any case: Assuming that Turbo Prolog's clauses part corresponds to standard Prolog, none of N1, N2, Term and Sum will be integers in your program. = means unification, not arithmetic evaluation. If you call fibonacci(3, Term, Sum), then inside the call N1 will be bound to the uninterpreted term 3 - 1, not to the integer 2. The same goes for your other uses of =.
For the arithmetic part, you will want to use is/2: N1 is N - 1, N2 is N - 2 etc. This will evaluate the right-hand side as an arithmetic expression and actually bind these variables to integers.
Without thinking about it too hard, it's not clear to me if this will result in a useful computation for Term.
i guessing turbo cant find some file with error descriptions. looks like tp incorrectly installed? correct this and you get more informative message.
look at
http://rosettacode.org/mw/index.php?title=Fibonacci_sequence&action=edit§ion=399
and modify it for not only finding Nth but Sum also.
you get something like:
----
% fibsum(i, n, fib(i-2), fib(i-1), fib(i), sum(i-1), sum(i))
fibsum(N, N, Fi2, Fi1, F, Si1, S) :-
F is Fi2 + Fi1,
S is Si1 + F.
fibsum(I, N, Fi2, Fi1, F, Si1, S) :-
In is I + 1,
Fn is Fi2 + Fi1,
Sn is Si1 + Fn, !,
fibsum(In, N, Fi1, Fn, F, Sn, S).
% fibs(i, fib(i), sum(i))
fibs(1, 1, 1).
fibs(2, 1, 2).
fibs(C, N, S) :-
C > 2,
fibsum(3, C, 1, 1, N, 2, S). % Generate from 3rd on
---
(barely tested on http://swish.swi-prolog.org/)
Turbo Prolog cannot find the error messages file PROLOG.ERR. That is normally installed in Turbo Prolog installation directory.
If the file is there, chek that the application path is correctly set under Setup->Directories->Turbo Directory
I am trying to find the number of occurrences of X in the List L
For eg :-
occurrences(a, [b, a, b, c, a, d, a], N ).
N =3
My code not working .Here is my code.
occ(K,L,N) :- N1=0, occ1(K,L,N1,N).
occ1(K,[],N1,N) :- N=N1.
occ1(K,L,N1,N) :-
L=[X|L1],
( K=X -> N1 is N1+1, occ1(K,L1,N1,N) ; occ1(K,L1,N1,N) ).
Can anybody tell me what's wrong in the code.
While the answer given by #Kay is spot-on as far as fixing the bug is concerned, it completely circumvents a much bigger issue: The code of occ1/4 is logically impure.
This may not appear very important to you right now,
but using impure code has several negative consequences:
Impure code cannot be read declaratively, only procedurally.
Debugging impure code is often tedious and pain-staking.
Impure predicates are less "relational" than their pure counterparts.
Logical impurity hampers code re-use.
Because it is non-monotone, impure code is prone to lead to logically unsound answers, particularly when working with non-ground terms.
To show that these problems persisted in your code after having been "fixed" as suggested #Kay, let us consider the "corrected" code and some queries. First, here's the corrected code:
occ(K,L,N) :- N1=0, occ1(K,L,N1,N).
occ1(_,[],N1,N) :- N=N1.
occ1(K,L,N1,N) :-
L=[X|L1],
( K=X -> N2 is N1+1, occ1(K,L1,N2,N) ; occ1(K,L1,N1,N) ).
Here's the query you gave in your question:
?- occ(a,[b,a,b,c,a,d,a],N).
N = 3 ;
false.
Okay! What if we write the query differently?
?- A=a,B=b,C=c,D=d, occ(a,[B,A,B,C,A,D,A],N).
A = a, B = b, C = c, D = d, N = 3 ;
false.
Okay! What if we reorder goals? Logical conjunction should be commutative...
?- occ(a,[B,A,B,C,A,D,A],N), A=a,B=b,C=c,D=d.
false.
Fail! It seemed that occ1/4 is fine, but now we get an answer that is logically unsound.
This can be avoided by using logically pure code:
Look at the pure and monotone code I gave in my answer to the related question "Prolog - count repititions in list (sic)".
The problem is
N1 is N1+1
Variables cannot be "overwritten" in Prolog. You need to just a new variable, e.g.
N2 is N1+1, occ1(K,L1,N2,N)
To your question "Can we replace a particular list element. If yes, what is the syntax?":
You can only build a new list:
replace(_, _, [], []).
replace(Old, New, [H0|T0], [H1|T1]) :-
(H0 = Old -> H1 = New; H1 = H0),
replace(Old, New, T0, T1).
I have the following task:
Write a method that will add two polynoms. I.e 0+2*x^3 and 0+1*x^3+2*x^4 will give 0+3*x^3+2*x^4.
I also wrote the following code:
add_poly(+A1*x^B1+P1,+A2*x^B2+P2,+A3*x^B3+P3):-
(
B1=B2,
B3 = B2,
A3 is A1+A2,
add_poly(P1,P2,P3)
;
B1<B2,
B3=B1,
A3=A1,
add_poly(P1,+A2*x^B2+P2,P3)
;
B1>B2,
B3=B2,
A3=A2,
add_poly(+A1*x^B1+P1,P2,P3)
).
add_poly(X+P1,Y+P2,Z+P3):-
Z is X+Y,
add_poly(P1,P2,P3).
My problem is that I don't know how to stop. I would like to stop when one the arguments is null and than to append the second argument to the third one. But how can I check that they are null?
Thanks.
Several remarks:
Try to avoid disjunctions (;)/2 in the beginning. They need special indentation to be readable. And they make reading a single rule more complex — think of all the extra (=)/2 goals you have to write and keep track of.
Then, I am not sure what you can assume about your polynomials. Can you assume they are written in canonical form?
And for your program: Consider the head of your first rule:
add_poly(+A1*x^B1+P1,+A2*x^B2+P2,+A3*x^B3+P3):-
I will generalize away some of the arguments:
add_poly(+A1*x^B1+P1,_,_):-
and some of the subterms:
add_poly(+_+_,_,_):-
This corresponds to:
add_poly(+(+(_),_),_,_) :-
Not sure you like this.
So this rule applies only to terms starting with a prefix + followed by an infix +. At least your sample data did not contain a prefix +.
Also, please remark that the +-operator is left associative. That means that 1+2+3+4 associates to the left:
?- write_canonical(1+2+3+4).
+(+(+(1,2),3),4)
So if you have a term 0+3*x^3+2*x^4 the first thing you "see" is _+2*x^4. The terms on the left are nested deeper.
For your actual question (how to stop) - you will have to test explicitly that the leftmost subterm is an integer, use integer/1 - or maybe a term (*)/2 (that depends on your assumptions).
I assume that polynomials you are speaking of are in 1 variable and with integer exponents.
Here a procedure working on normal polynomial form: a polynomial can be represented as a list (a sum) of factors, where the (integer) exponent is implicitly represented by the position.
:- [library(clpfd)].
add_poly(P1, P2, Sum) :-
normalize(P1, N1),
normalize(P2, N2),
append(N1, N2, Nt),
aggregate_all(max(L), (member(M, Nt), length(M, L)), LMax),
maplist(rpad(LMax), Nt, Nn),
clpfd:transpose(Nn, Tn),
maplist(sumlist, Tn, NSum),
denormalize(NSum, Sum).
rpad(LMax, List, ListN) :-
length(List, L),
D is LMax - L,
zeros(D, Z),
append(List, Z, ListN).
% the hardest part is of course normalization: here a draft
normalize(Ts + T, [N|Ns]) :-
normalize_fact(T, N),
normalize(Ts, Ns).
normalize(T, [N]) :-
normalize_fact(T, N).
% build a list with 0s left before position E
normalize_fact(T, Normal) :-
fact_exp(T, F, E),
zeros(E, Zeros),
nth0(E, Normal, F, Zeros).
zeros(E, Zeros) :-
length(Zeros, E),
maplist(copy_term(0), Zeros).
fact_exp(F * x ^ E, F, E).
fact_exp(x ^ E, 1, E).
fact_exp(F * x, F, 1).
fact_exp(F, F, 0).
% TBD...
denormalize(NSum, NSum).
test:
?- add_poly(0+2*x^3, 0+1*x^3+2*x^4, P).
P = [0, 0, 0, 3, 2]
the answer is still in normal form, denormalize/2 should be written...
I starting to study for my upcoming exam and I'm stuck on a trivial prolog practice question which is not a good sign lol.
It should be really easy, but for some reason I cant figure it out right now.
The task is to simply count the number of odd numbers in a list of Int in prolog.
I did it easily in haskell, but my prolog is terrible. Could someone show me an easy way to do this, and briefly explain what you did?
So far I have:
odd(X):- 1 is X mod 2.
countOdds([],0).
countOdds(X|Xs],Y):-
?????
Your definition of odd/1 is fine.
The fact for the empty list is also fine.
IN the recursive clause you need to distinguish between odd numbers and even numbers. If the number is odd, the counter should be increased:
countOdds([X|Xs],Y1) :- odd(X), countOdds(Xs,Y), Y1 is Y+1.
If the number is not odd (=even) the counter should not be increased.
countOdds([X|Xs],Y) :- \+ odd(X), countOdds(Xs,Y).
where \+ denotes negation as failure.
Alternatively, you can use ! in the first recursive clause and drop the condition in the second one:
countOdds([X|Xs],Y1) :- odd(X), !, countOdds(Xs,Y), Y1 is Y+1.
countOdds([X|Xs],Y) :- countOdds(Xs,Y).
In Prolog you use recursion to inspect elements of recursive data structs, as lists are.
Pattern matching allows selecting the right rule to apply.
The trivial way to do your task:
You have a list = [X|Xs], for each each element X, if is odd(X) return countOdds(Xs)+1 else return countOdds(Xs).
countOdds([], 0).
countOdds([X|Xs], C) :-
odd(X),
!, % this cut is required, as rightly evidenced by Alexander Serebrenik
countOdds(Xs, Cs),
C is Cs + 1.
countOdds([_|Xs], Cs) :-
countOdds(Xs, Cs).
Note the if, is handled with a different rule with same pattern: when Prolog find a non odd element, it backtracks to the last rule.
ISO Prolog has syntax sugar for If Then Else, with that you can write
countOdds([], 0).
countOdds([X|Xs], C) :-
countOdds(Xs, Cs),
( odd(X)
-> C is Cs + 1
; C is Cs
).
In the first version, the recursive call follows the test odd(X), to avoid an useless visit of list'tail that should be repeated on backtracking.
edit Without the cut, we get multiple execution path, and so possibly incorrect results under 'all solution' predicates (findall, setof, etc...)
This last version put in evidence that the procedure isn't tail recursive. To get a tail recursive procedure add an accumulator:
countOdds(L, C) :- countOdds(L, 0, C).
countOdds([], A, A).
countOdds([X|Xs], A, Cs) :-
( odd(X)
-> A1 is A + 1
; A1 is A
),
countOdds(Xs, A1, Cs).