I am having some issues with a part of my revision for my prolog exam.
I need to create a recursive statement that will be called simplify/2. An example use would be
simplify(s(p(s(0))),Z)
which would result in Z being s(0). S stands for successor and P predecessor.
So:
s(0) is 1,
s(s(0)) is 2 and p(0) is -1 etc.
and
p(s(p(p(0)))) would be p(p(0)).
The code I initially had was
check(s(0),s(0)).
check(s(X),s(0)) :- check(X,s(s(0))).
check(p(X),s(0)) :- check(X,0).
But this clearly doesn't work as the second part needs to be kept as a variable that is added on to itself during the recursive call. I'll have another look at it in around 30 minutes because my head is fried at the moment.
My attempt:
simplify(X, Z) :-
simplify(X, 0, Z).
simplify(0, Z, Z).
simplify(s(X), 0, Z) :- simplify(X, s(0), Z).
simplify(p(X), 0, Z) :- simplify(X, p(0), Z).
simplify(p(X), s(Y), Z) :- simplify(X, Y, Z).
simplify(s(X), p(Y), Z) :- simplify(X, Y, Z).
simplify(s(X), s(Y), Z) :- simplify(X, s(s(Y)), Z).
simplify(p(X), p(Y), Z) :- simplify(X, p(p(Y)), Z).
Update - shorter version:
simplify(X, Z) :-
simplify(X, 0, Z).
simplify(0, Z, Z).
simplify(p(X), s(Y), Z) :- simplify(X, Y, Z).
simplify(s(X), p(Y), Z) :- simplify(X, Y, Z).
simplify(s(X), Y, Z) :- Y \= p(_), simplify(X, s(Y), Z).
simplify(p(X), Y, Z) :- Y \= s(_), simplify(X, p(Y), Z).
Some tests:
?- simplify(s(p(s(0))), Z).
Z = s(0)
?- simplify(p(s(p(p(0)))), Z).
Z = p(p(0))
?- simplify(p(p(s(s(0)))), Z).
Z = 0
z(0).
z(s(X)) :-
z(X).
z(p(X)) :-
z(X).
z_canonized(Z, C) :-
z_canonized(Z, 0, C).
z_canonized(0, C,C).
z_canonized(s(N), C0,C) :-
z_succ(C0,C1),
z_canonized(N, C1,C).
z_canonized(p(N), C0,C) :-
z_pred(C0,C1),
z_canonized(N, C1,C).
z_succ(0,s(0)).
z_succ(s(X),s(s(X))). % was: z_succ(X,s(X)) :- ( X = 0 ; X = s(_) ).
z_succ(p(X),X).
z_pred(0,p(0)).
z_pred(p(X),p(p(X))).
z_pred(s(X),X).
Yet another answer, coded for fun of it. It first simplifies an expression into an integer and then converts the result into p(...) for negative integers, s(...) for positive integers (excluding zero), and 0 for 0. The standard sign/1 arithmetic function is used to take advantage of first-argument indexing.
simplify(Expression, Result) :-
simplify(Expression, 0, Result0),
Sign is sign(Result0),
convert(Sign, Result0, Result).
simplify(0, Result, Result).
simplify(s(X), Result0, Result) :-
Result1 is Result0 + 1,
simplify(X, Result1, Result).
simplify(p(X), Result0, Result) :-
Result1 is Result0 - 1,
simplify(X, Result1, Result).
convert(-1, N, p(Result)) :-
N2 is N + 1,
Sign is sign(N2),
convert(Sign, N2, Result).
convert(0, _, 0).
convert(1, N, s(Result)) :-
N2 is N - 1,
Sign is sign(N2),
convert(Sign, N2, Result).
OK, another "fun" solution. This one works in ECliPSe and uses non-standard append_strings, which is a strings' analog of lists' append:
simplify(X, Z) :-
term_string(X, Xstr),
( append_strings(Middle, End, Xstr),
(
append_strings(Begin, "s(p(", Middle)
;
append_strings(Begin, "p(s(", Middle)
) ->
append_strings(NewEnd, "))", End),
append_strings(Begin, NewEnd, Zstr),
term_string(Ztemp, Zstr),
simplify(Ztemp, Z)
;
Z = X
).
This is my answer:
simplify(X, Z) :- simplify(X, 0, 0, Z).
simplify(0, 0, X, X).
simplify(0, X, 0, X) :- X \= 0.
simplify(0, p(X), s(Y), Z) :- simplify(0, X, Y, Z).
simplify(p(X), P, S, Z) :- simplify(X, p(P), S, Z).
simplify(s(X), P, S, Z) :- simplify(X, P, s(S), Z).
I'm dividing input structure into two chains of ps and ss and then I am removing one by one from both chains. When one of them ends, the other one becomes the result of operation. I think it is quite efficient.
I was inspired by Paulo's submission to do a variant of the "Count the p's and s's" approach:
simplify(Exp, Simp) :-
exp_count(Exp, Count),
exp_count(Simp, Count).
exp_count(Exp, C) :-
exp_count(Exp, 0, C).
exp_count(s(X), A, C) :-
( nonvar(C)
-> A < C
; true
),
A1 is A + 1,
exp_count(X, A1, C).
exp_count(p(X), A, C) :-
( nonvar(C)
-> A > C
; true
),
A1 is A - 1,
exp_count(X, A1, C).
exp_count(0, C, C).
Related
I need to write the predicate Frequest(InList, OutList) to find the list
OutList of all elements that occur most frequently in the given InList.
Here is my code, help me write more professional and understandable for everyone please.
`counter([], _, 0).
counter([X|T], X, C) :- counter(T, X, C1), C is C1 + 1.
counter([X|T], Y, C) :- X == Y, counter(T, Y, C).
max_count([], , 0).
max_count([E|L], L1, C):-
counter(L1, E, C1),
maxcount(L, L1, C2),
C is max(C1, C2), !.
max_count_el([], , _, []) :- !.
max_count_el([X|L], L1, M, LR) :-
ffff(L, L1, M, LR2),
( counter(L1, X, C),
C == M,
+ member(X, LR2),
append(LR2, [X], LR);
LR = LR2
).
frequentest(L1, L2):-
max_count(L1, L1, R),
max_count_el(L1, L1, R, L2), !.`
I am trying to implement exponentiation with the code below, but a simple query like 2^1 (ex(s(s(0)), s(0), Z).) hangs forever.
nat(0).
nat(s(X)) :- nat(X).
su(0, X, X) :- nat(X).
su(s(X), Y, s(Z)) :- su(X, Y, Z).
mu(0, _, 0).
mu(s(X), Y, Z) :- su(Y, A, Z), mu(X, Y, A).
ex(_, 0, s(0)).
ex(X, s(Y), Z) :- mu(X, A, Z), ex(X, Y, A).
As far as I can see, it is not efficient, because the mu/3 is called with two free variables. Indeed:
ex(X, s(Y), Z) :- mu(X, A, Z), ex(X, Y, A).
Both A and Z are unknown at that moment (I have put them in boldface).
Now your mu/2 is not capable of handling this properly. If we query mu/3 with mu(s(0), A, Z), we get:
?- mu(s(0), A, Z).
A = Z, Z = 0 ;
ERROR: Out of global stack
So it got stuck in infinite recursion as well.
This is due to the fact that it will tak the second clause of mu/3, and:
mu(s(X), Y, Z) :- su(Y, A, Z), mu(X, Y, A).
So su/3 is called with three unknown variables. The effect of this is that su/3 can keep proposing values "until the end of times":
?- su(A, B, C).
A = B, B = C, C = 0 ;
A = 0,
B = C, C = s(0) ;
A = 0,
B = C, C = s(s(0)) ;
A = 0,
...
even if the recursive mu(X, Y, A) rejects all these proposals, su/3 will never stop proposing new solutions.
Therefore it might be better to keep that in mind when we design the predicates for mu/3, and ex/3.
We can for example use an accumulator here that accumulates the values, and returns the end product. The advantage of this, is that we work with real values when we make the su/3 call, like:
mu(A, B, C) :-
mu(A, B, 0, C).
mu(0, _, 0, S, S).
mu(s(X), Y, I, Z) :-
su(Y, I, J),
mu(X, Y, J, Z).
Now if we enter mu/3 with only the first parameter fixed, we see:
?- mu(s(0), X, Y).
X = Y, Y = 0 ;
X = Y, Y = s(0) ;
X = Y, Y = s(s(0)) ;
X = Y, Y = s(s(s(0))) ;
...
?- mu(s(s(0)), X, Y).
X = Y, Y = 0 ;
X = s(0),
Y = s(s(0)) ;
X = s(s(0)),
Y = s(s(s(s(0)))) ;
X = s(s(s(0))),
Y = s(s(s(s(s(s(0)))))) ;
...
...
So that means that we now at least do not get stuck in a loop for mu/3 with only the first parameter fixed.
We can use the same strategy to define an ex/3 predicate:
ex(X, Y, Z) :-
ex(X, Y, s(0), Z).
ex(X, 0, Z, Z).
ex(X, s(Y), I, Z) :-
mu(X, I, J),
ex(X, Y, J, Z).
We then manage to calculate exponents like 21 and 22:
?- ex(s(s(0)), s(0), Z).
Z = s(s(0)) ;
false.
?- ex(s(s(0)), s(s(0)), Z).
Z = s(s(s(s(0)))) ;
false.
Note that the above has still some flaws, for example calculating for which powers the value is 4 will still loop:
?- ex(X, Y, s(s(s(s(0))))).
ERROR: Out of global stack
By rewriting the predicates, we can avoid that as well. But I leave that as an exercise.
predicate change_pos(E1, E2,Lin,Lout).
The Lin has any number of elements, and I need to change all occurences of E1 to E2, and vice-versa. And return in Lout.
I was thinking to do something like this:
change(X, Y, [], []).
change(X, Y, [X|L], [Y,L1]):- change(X,Y,L,L1).
change(X, Y, [Z|L], [Z,L1]:- X \== Z, change(X,Y,L,L1).
But this way is not swiping two number of the list
I'm supposing, since this is homework, it's an exercise to learn list processing and recursion. But in Prolog, a common tool for processing each term in turn in a list is maplist:
% Rule for changing one element
change_element(X, Y, X, Y).
change_element(X, Y, Y, X).
change_element(X, Y, Z, Z) :- dif(X, Z), dif(Y, Z).
% Rule for changing a list
change(X, Y, L1, L2) :-
maplist(change_element(X, Y), L1, L2).
Which yields:
?- change(a, b, [a,b,c,b,a], L).
L = [b, a, c, a, b] ? ;
no
?-
For a determinate solution, you can use if_/3:
change1(X, Y, A, B) :-
if_(=(Y, A), B = X, A = B).
change2(X, Y, A, B) :-
if_(=(X, A), B = Y, change1(X, Y, A, B)).
change(X, Y, L1, L2) :- maplist(change2(X, Y), L1, L2).
Which yields:
?- change(a, b, [a,b,c,b,a], L).
L = [b, a, c, a, b].
?-
You're almost there. Your base case (the empty lists) and your second rule (swap X for Y) are basically fine (apart from the details pointed out in the comments). However, you are missing a rule for vice-versa (swap Y for X). And in your last rule you likely want to make sure that Z differs not only from X but also from Y, otherwise Z would be subject to rule two or three.
change(X, Y, [], []).
change(X, Y, [X|L], [Y|L1]) :-
change(X,Y,L,L1).
change(X, Y, [Y|L], [X|L1]) :- % <- vice versa case
change(X,Y,L,L1).
change(X, Y, [Z|L], [Z|L1]) :-
dif(X,Z), % <- neither X=Z
dif(Y,Z), % <- nor vice versa
change(X,Y,L,L1).
Here are some example queries. What does [1,2,3,4] look like after swapping 1 with 2 and vice versa?
?- change(1,2,[1,2,3,4],L).
L = [2,1,3,4] ? ;
no
What did [2,1,3,4] look like before swapping 1 with 2 and vice versa?
?- change(1,2,L,[2,1,3,4]).
L = [1,2,3,4] ? ;
no
Which elements have been swapped in [1,2,3,4] if the resulting list is [2,1,3,4] ?
?- change(X,Y,[1,2,3,4],[2,1,3,4]).
X = 1,
Y = 2 ? ;
X = 2,
Y = 1 ? ;
no
The title kind of says it all. I'm looking to compute the GCD of two polynomials. Is there any way this can be done in Prolog? If so, what's a good starting point? Specifically, I'm having trouble with how to implement polynomial division using Prolog.
Edit to include example input and output:
Example input:
?- GCD(x^2 + 7x + 6, x2 − 5x − 6, X).
Example output:
X = x + 1.
Solution
On the off chance that someone else needs to do this, here's my final solution:
tail([_|Tail], Tail).
head([Head | _], Head).
norm(Old, N, New) :-
length(Tail, N),
append(New, Tail, Old).
norm(Old, N, []) :-
length(Old, L),
N > L.
mult_GCD(List, GCD) :- length(List, L),
L > 2, tail(List, Tail),
mult_GCD(Tail, GCD).
mult_GCD([H | T], GCD) :-
length(T, L),
L == 1, head(T, N),
gcd(H, N, GCD).
lead(List, List) :-
length(List, L),
L == 1.
lead([0 | Tail], Out) :-
!, lead(Tail, Out).
lead([Head | Tail], [Head | Tail]) :- Head =\= 0.
poly_deg([], 0).
poly_deg(F, D) :-
lead(F, O),
length(O, N),
D is N - 1.
poly_red([0], [0]).
poly_red(Poly, Out) :-
mult_GCD(Poly, GCD),
scal_div(Poly, GCD, Out).
poly_sub(Poly,[],Poly) :- Poly = [_|_].
poly_sub([],Poly,Poly).
poly_sub([P1_head|P1_rest], [P2_head|P2_rest], [PSub_head|PSub_rest]) :-
PSub_head is P1_head-P2_head,
poly_sub(P1_rest, P2_rest, PSub_rest).
scal_prod([],_Sc,[]).
scal_prod([Poly_head|Poly_rest], Sc, [Prod_head|Prod_rest]) :-
Prod_head is Poly_head*Sc,
scal_prod(Poly_rest, Sc, Prod_rest).
scal_div([],_,[]).
scal_div([Poly_head|Poly_rest], Sc, [Prod_head|Prod_rest]) :-
Prod_head is Poly_head / Sc,
scal_div(Poly_rest, Sc, Prod_rest).
poly_div(Num, Den, OutBuild, Out) :-
poly_deg(Num, X),
poly_deg(Den, Y),
X < Y,
Out = OutBuild.
poly_div(INum, IDen, OutBuild, Out) :-
lead(INum, [NumHead | NumTail]), lead(IDen, [DenHead | DenTail]),
Q is NumHead / DenHead,
append(OutBuild, [Q], Out1),
append([DenHead], DenTail, DenNorm), append([NumHead], NumTail, Num),
scal_prod(DenNorm, Q, DenXQ),
poly_sub(Num, DenXQ, N),
poly_div(N, IDen, Out1, Out).
poly_mod(Num, Den, Out) :-
poly_deg(Num, X), poly_deg(Den, Y),
X < Y,
lead(Num, Out1),
poly_red(Out1, Out2),
lead(Out2, Out).
poly_mod(INum, IDen, Out) :-
lead(INum, [NumHead | NumTail]), lead(IDen, [DenHead | DenTail]),
Q is NumHead / DenHead,
append([DenHead], DenTail, DenNorm), append([NumHead], NumTail, Num),
scal_prod(DenNorm, Q, DenXQ),
poly_sub(Num, DenXQ, N),
poly_mod(N, IDen, Out).
poly_gcd(X, Y, X):- poly_deg(Y, O), O == 0, !.
poly_gcd(Y, X, X):- poly_deg(Y, O), O == 0, !.
poly_gcd(X, Y, D):- poly_deg(X, Xd), poly_deg(Y, Yd), Xd > Yd, !, poly_mod(X, Y, Z), poly_gcd(Y, Z, D).
poly_gcd(X, Y, D):- poly_mod(Y, X, Z), poly_gcd(X, Z, D).
gcd(X, Y, Z) :-
X < 0, X > Y, !,
X1 is X - Y,
gcd(-X, Y, Z).
gcd(X, Y, Z) :-
Y < 0, Y >= X, !,
Y1 is Y - X,
gcd(X, -Y, Z).
gcd(X, 0, X).
gcd(0, Y, Y).
gcd(X, Y, Z) :-
X > Y, Y > 0,
X1 is X - Y,
gcd(Y, X1, Z).
gcd(X, Y, Z) :-
X =< Y, X > 0,
Y1 is Y - X,
gcd(X, Y1, Z).
gcd(X, Y, Z) :-
X > Y, Y < 0,
X1 is X + Y,
gcd(Y, X1, Z).
gcd(X, Y, Z) :-
X =< Y, X < 0,
Y1 is Y + X,
gcd(X, Y1, Z).
This answer is meant as a push in the right direction.
First, forget for a moment that you need to parse an expression like x^2 + 7x + 6; this isn't even a proper term in Prolog yet. If you tried to write it on the top level, you will get an error:
?- Expr = x^2 + 7x + 6.
ERROR: Syntax error: Operator expected
ERROR: Expr = x^2 +
ERROR: ** here **
ERROR: 7x + 6 .
Prolog doesn't know how to deal with the 7x you have there. Parsing the expression is a question of its own, and maybe it is easier if you assumed you have already parsed it and gotten a representation that looks for example like this:
[6, 7, 1]
Similarly, x^2 − 5x − 6 becomes:
[-6, -5, 1]
and to represent 0 you would use the empty list:
[]
Now, take a look at the algorithm at the Wikipedia page. It uses deg for the degree and lc for the leading coefficient. With the list representation above, you can define those as:
The degree is one less then the length of the list holding the coefficients.
poly_deg(F, D) :-
length(F, N),
D is N - 1.
The leading coefficient is the last element of the list.
poly_lc(F, C) :-
last(F, C).
You also need to be able to do simple arithmetic with polynomials. Using the definitions on the Wikipedia page, we see that for example adding [] and [1] should give you [1], multiplying [-2, 2] with [1, -3, 1] should give you [-2, 8, -8, 2]. A precursory search gave me this question here on Stackoverflow. Using the predicates defined there:
?- poly_prod([-2,2], [1, -3, 1], P).
P = [-2.0, 8.0, -8.0, 2] .
?- poly_sum([], [1], S).
S = [1].
From here on, it should be possible for you to try and implement polynomial division as outlined in the Wiki article I linked above. If you get into more trouble, you should edit your question or ask a new one.
So far, my program can add two numbers together.
s(0) represents 1, s(s(0)) represents 2 and so on
p(0) represents -1, p(p(0)) is -2 etc.
I want to be able to call a program such that
add2(s(s(0)), p(0), Z).
returns
Z = s(0).
My code is as follows:
numeral(0).
numeral(s(X)) :- numeral(X).
add(0,X,X).
add(s(X),Y,s(Z)) :- add(X,Y,Z).
numeral(X+Y) :- numeral(X), numeral(Y).
add2(X,Y,Z):-add(X,Y,Z).
add2(X+Y, Z,A) :-add(X,Y,R),add2(R,Z,A).
add2(Z,X+Y,A) :-add(X,Y,R),add2(Z,R,A).
numeral(p(X)) :- numeral(X).
add2(p(X),Y,p(Z)) :- add2(X,Y,Z).
p(s(X)) =:= 0.
s(p(X)) =:= 0.
My logic was that if p(s(0)) was in the list, it would just equate it to 0.. I was wrong, however. Does anybody know where to go with this?
Each numeral could be represented only in one of these 3 ways:
0 - null;
s(X) - next, where X is numeral;
p(X) - previous, where X is numeral;
add2/3 should take 2 numerals and return sum of them. It could be defined manually for each possible arguments:
add2(0, 0, 0).
add2(0, s(X), Y) :- Y = s(X).
add2(0, p(X), Y) :- Y = p(X).
add2(s(X), 0, Y) :- Y = s(X).
add2(s(X), s(Y), Z) :- add2(X, Y, s(s(Z))).
add2(s(X), p(Y), Z) :- add2(X, Y, Z).
add2(p(X), 0, Y) :- Y = p(X).
add2(p(X), s(Y), Z) :- add2(X, Y, Z).
add2(p(X), p(Y), Z) :- add2(X, Y, p(p(Z))).
Works well:
?- add2(s(s(0)), p(0), Z).
Z = s(0) .
It is notable that many cases of add2/3 rule is actually overlapped and could be eliminated:
add2(0, X, X).
add2(X, 0, X).
add2(s(X), s(Y), Z) :- add2(X, Y, s(s(Z))).
add2(s(X), p(Y), Z) :- add2(X, Y, Z).
add2(p(X), s(Y), Z) :- add2(X, Y, Z).
add2(p(X), p(Y), Z) :- add2(X, Y, p(p(Z))).