Prolog - multiplying by addition - prolog

I need simple fuction in SWI-prolog which multiplying by addition. Something like m(X,Y,Z) where for example X=5, Z=3 <==> 5*3. Y is result: Y=5, Y=10, Y=15 [stop]. I was thinking about something like that:
m(X,Y,Z):- Z>0, /*when Z reaches 0 you stop */ I=X+X, W=Z-1, m(I,Y,W).
But it always return "false" and dunno why.

Let's start by thinking about what the predicate should describe: it's a relation between three numbers, where the third is the product of the first two. Since you want to describe multiplication by reducing the second argument to zero while adding up the first accordingly many times we are talking about natural numbers. So a nicely descriptive name would be nat_nat_prod/3. Next consider the possible cases:
The second argument can be zero. Then the product has to be zero as well since X*0=0. So this is the base case.
Otherwise the second argument is greater than zero. Then you want to decrement it by one and calculate the product of the first argument and this new number. Since the predicate can use itself to describe that, this is a recursive goal. Subsequently you add the first argument to the intermediary product described by the recursion.
This can be written in Prolog like so:
nat_nat_prod(_X,0,0). % case 1)
nat_nat_prod(X,Y1,P1) :- % case 2)
Y1 > 0,
Y0 is Y1-1,
nat_nat_prod(X,Y0,P0),
P1 is P0+X.
Now let's try some queries:
?- nat_nat_prod(5,3,P).
P = 15 ;
false.
?- nat_nat_prod(5,4,P).
P = 20 ;
false.
?- nat_nat_prod(5,0,P).
P = 0 ;
false.
?- nat_nat_prod(1,0,P).
P = 0 ;
false.
?- nat_nat_prod(1,1,P).
P = 1 ;
false.
However, when playing around with the predicate, you'll notice that the first two arguments have to be instantiated otherwise you'll get an error:
?- nat_nat_prod(1,Y,3).
ERROR: >/2: Arguments are not sufficiently instantiated
?- nat_nat_prod(X,1,3).
ERROR: is/2: Arguments are not sufficiently instantiated
This happens due to the use of >/2 and is/2. You could get around this problem by using CLP(FD) but I think that's beside the point. This way of defining multiplication is obviously very inefficient compared to using the standard arithmetic function */2, e.g.:
?- time(nat_nat_prod(2,1000000,P)).
% 3,000,000 inferences, 33.695 CPU in 33.708 seconds (100% CPU, 89035 Lips)
P = 2000000 ;
% 3 inferences, 0.031 CPU in 0.031 seconds (100% CPU, 97 Lips)
false.
?- time(P is 2*1000000).
% 1 inferences, 0.000 CPU in 0.000 seconds (86% CPU, 82325 Lips)
P = 2000000.
As already hinted by #false in the comments it is more common to introduce people to successor arithmetics first and then to define addition/multiplication of two numbers in s(X) notation this way. Since you can't use the standard arithmetic functions with s(X) numbers, you also don't run into the associated instantiation errors.

Related

What is a simple worst case for occurs check in Prolog?

Many papers do note that an equational unification problem such as below, might run in exponential time, when occurs_check=true. There is no stipulation that this is a top-level query or a clause body, its just the equational unification problem:
X1 = f(X0, X0),
X2 = f(X1, X1),
..
Xn-1 = f(Xn-2, Xn-2),
Xn = f(Xn-1, Xn-1).
If true this could be a worst case for occurs check, since normal variable sharing unification is linear. Does every Prolog system
necessarely feature this equational unification problem as a worst case?
If the Prolog system does not have an occurs_check=true flag, one could try unify_with_occurs_check/2 in place of (=)/2.
Here is a comparison. I tested the equational unification problem inside a clause body. Link to source code of the test and the benchmark results is at the end of this answer:
test :-
B = f(A, A),
C = f(B, B),
D = f(C, C),
X = f(D, D).
Etc..
Jekejeke Prolog 1.4.6 and SWI-Prolog 8.3.17 is still linear. Jekejeke Prolog uses a static analysis, doesn't work always. SWI-Prolog does it dynamically, I guess side effect of dealing with cyclic terms. But GNU Prolog 1.4.5 is exponential. I was using n=4, 6, 8 and 10:
Open Source:
Linear or Exponential?
https://gist.github.com/jburse/2d5fd1d3dd8436acceca52fdfc537581#file-size-pl
Not yet completely verified hypothesis. There is some confirmation
that we can look at the VM code. There is the danger that I am still
looking, looking, looking, … and I don’t see anything.
Here is a suspicion of mine for SWI-Prolog. Concerning this
equational unification problem, now inside a clause body:
X1 = f(X0, X0),
X2 = f(X1, X1),
..
Xn-1 = f(Xn-2, Xn-2),
Xn = f(Xn-1, Xn-1).
Only one equation is optimized away when occurs_check=true? This would
explain the differing LIPS count and the differing performance:
/* (=)/2, occurs_check=false */
% % 2,000,000 inferences, 0.222 CPU in 0.226 seconds (98% CPU, 9007995 Lips)
/* unify_with_occurs_check/2 */
% % 12,000,000 inferences, 1.382 CPU in 1.411 seconds (98% CPU, 8680009 Lips)
/* (=)/2, occurs_check=true */
% 11,000,000 inferences, 1.264 CPU in 1.270 seconds (100% CPU, 8704963 Lips)
Oki, Doki.

Assert Intermediate Result in Prolog

This is the question.
Define a predicate sigma(N,S) such that S = 1+2+...+N. And remember every new intermediate result in the query. For example, after query sigma(3,S), it will store some thing like sigma(2,3),sigma(3,6) to database such that we needn't do duplicate and useless work later.
I tried the following method to solve it.
sigmares(1,1).
mysigma(N,A,Sum) :-
sigmares(N,SN),
Sum is SN+A,
!.
mysigma(N1,Acc,Sum) :-
N is N1-1,
A is Acc + N1,
mysigma(N,A,Sum),
assertz(sigmares(N1,Sum)). % <<<<<<<<<< This line doesn't work properly.
sigma(N,X) :-
mysigma(N,0,X).
There is some problem with assertz line. Since sum can be only initialized once which is the value of sum from 1 to N, sigma(2,6),sigma(3,6) for query sigma(3,S) will be inserted. Is there any other way to store new intermediate sigmares?
First, it's good coding style to always declare the dynamic predicates that your code uses using the standard dynamic/1 directive. Simply add at the beginning of the file:
:- dynamic(sigmares/2).
An interesting aspect of your definition of the mysigma/3 predicate is that it is a non tail-recursive with the consequence that it requires space linear on its inputs. But that allows it to cache all intermediate results as you intend. A fixed version of your code will be:
:- dynamic(sigma_cache/2).
sigma_cache(1, 1).
sigma(N, S) :-
sigma_cache(N, S),
!.
sigma(N, S) :-
N > 1,
M is N - 1,
sigma(M, SM),
S is SM + N,
assertz(sigma_cache(N, S)).
Sample call:
?- sigma(5, S).
S = 15.
?- listing(sigma_cache/2).
:- dynamic sigma_cache/2.
sigma_cache(1, 1).
sigma_cache(2, 3).
sigma_cache(3, 6).
sigma_cache(4, 10).
sigma_cache(5, 15).
true.
This alternative answer provides a solution based on the tabling mechanism found in some Prolog systems, including B-Prolog, Ciao, SWI-Prolog, XSB, and YAP:
:- table(sigma/2).
sigma(1, 1).
sigma(N, S) :-
N > 1,
M is N - 1,
sigma(M, SM),
S is SM + N.
Let's test it with the help of SWI-Prolog handy time/1 library predicate that reports the time and number of inferences taken to prove a goal:
?- time(sigma(5, S)).
% 166 inferences, 0.000 CPU in 0.006 seconds (2% CPU, 1238806 Lips)
S = 15.
?- time(sigma(5, S)).
% 5 inferences, 0.000 CPU in 0.000 seconds (68% CPU, 208333 Lips)
S = 15.
Note that I used a non tail-recursive definition for the sigma/2 predicate on purpose so that all intermediate results are cached (as per the requirements in your question). For example:
?- time(sigma(4, S)).
% 5 inferences, 0.000 CPU in 0.000 seconds (70% CPU, 217391 Lips)
S = 10.
You can see that, after the first call, the result is cached by the tabling mechanism, resulting in a much lower number of inferences when we repeat the query.
?- time(sigma(6, S)).
% 32 inferences, 0.000 CPU in 0.000 seconds (86% CPU, 727273 Lips)
S = 21.
?- time(sigma(6, S)).
% 5 inferences, 0.000 CPU in 0.000 seconds (70% CPU, 217391 Lips)
S = 21.
Note again the number of inferences. The first query reuses the cached result for sigma(5, S) and caches the result for sigma(6, S), making the repeated query again faster as it just reuses the cached result.

STRIPS Planner loops indefinitely

I defined in Prolog a STRIPS Planner to solve logic problems. After a few tryouts with other simpler problems I set out to see if it could solve a more complex one. I gave him a STRIPS definition of the peg solitaire, the english version and considering we cant do diagonal moves and the last ball will end up in the center of the board and tried it, to which the program broke into a loop. Here's the problem: https://en.wikipedia.org/wiki/Peg_solitaire
Here's my solution:
%%%%%%%%%%%%%%%%%%%%%% PLAN %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
accao(nome : move(Xi,Yi,Xf,Yf),
condicoes : [empty(Xf,Yf),ball(Xi,Yi), ball(Xm,Ym)],
efeitos : [ball(Xf,Yf), -ball(Xm,Ym),-ball(Xi,Yi), empty(Xi,Yi), empty(Xm,Ym), -empty(Xf,Yf)],
restricoes : [abs(Xf-Xi)+abs(Yf-Yi)=:=2, abs(Xf-Xi)*abs(Yf-Yi)=:=0, Xi=<Xm, Xm=<Xf, Yi=<Ym, Ym=<Yf]).
inicial([empty(5,5), ball(1,4), ball(1,5), ball(1,6),
ball(2,4), ball(2,5), ball(2,6),
ball(3,4), ball(3,5), ball(3,6),
ball(4,1), ball(4,2), ball(4,3),ball(4,4), ball(4,5), ball(4,6),ball(4,7), ball(4,8), ball(4,9),
ball(5,1), ball(5,2), ball(5,3),ball(5,4), ball(5,6),ball(5,7), ball(5,8), ball(5,9),
ball(6,1), ball(6,2), ball(6,3),ball(6,4), ball(6,5), ball(6,6),ball(6,7), ball(6,8), ball(6,9),
ball(7,4), ball(7,5), ball(7,6),
ball(8,4), ball(8,5), ball(8,6),
ball(9,4), ball(9,5), ball(9,6)]).
objectivos([ball(5,5), empty(1,4), empty(1,5), empty(1,6),
empty(2,4), empty(2,5), empty(2,6),
empty(3,4), empty(3,5), empty(3,6),
empty(4,1), empty(4,2), empty(4,3),empty(4,4), empty(4,5), empty(4,6),empty(4,7), empty(4,8), empty(4,9),
empty(5,1), empty(5,2), empty(5,3),empty(5,4), empty(5,6),empty(5,7), empty(5,8), empty(5,9),
empty(6,1), empty(6,2), empty(6,3),empty(6,4), empty(6,5), empty(6,6),empty(6,7), empty(6,8), empty(6,9),
empty(7,4), empty(7,5), empty(7,6),
empty(8,4), empty(8,5), empty(8,6),
empty(9,4), empty(9,5), empty(9,6)]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%% PRINT FUNCTION %%%%%%%%%%%%%%%%%%%%%%%%%%%
printExec([]).
printExec([A,E|T]) :- write("Action performed: "),
write(A),nl,
write("Situation: "),
write(E),nl,
printExec(T).
writeExec([I|T]):- write("Initial Situation"),
write(I),nl,
printExec(T),
write("Goal: "),
objectivos(G),
write(G),
write(" satisfied."),nl.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%% AUXILIAR FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%
member(E,[E|_]).
member(E,[_|T]):-member(E,T).
sub([],_).
sub([H|T],L):- member(H,L),
sub(T,L).
remove(_,[],[]):-!.
remove(E1, [E2|T], T):- E1 == E2, !.
remove(E,[H|T1],[H|T2]):- remove(E,T1,T2).
add(E,[],[E]):-!.
add(E1,[E2|T],[E1,E2|T]):- E1 \== E2, !.
add(E,[H|T1],[H|T2]):-add(E,T1,T2).
effects([],S,S).
effects([-H|Fx],S,N) :-!,
remove(H,S,NS),
effects(Fx,NS,N).
effects([H|Fx],S,N) :- !,
add(H,S,NS),
effects(Fx,NS,N).
restriction([]).
restriction([R|T]) :- R,
restriction(T).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%% PLAN EXECUTE %%%%%%%%%%%%%%%%%%%%%%%%%%%
planExecute(P):-testPlan(P,E),writeExec(E),!.
satisfiedGoal(E):- objectivos(Fn),!,
sub(Fn,E).
testPlan(Plan,[I|Exec]) :- inicial(I),
testPlan(Plan,I,Exec,Fn),
satisfiedGoal(Fn).
testPlan([],Fn,[],Fn).
testPlan([H|T],S,[H,N|Exec],Fn) :- accao(nome:H, condicoes:C,efeitos:E, restricoes:R),
sub(C,S),
effects(E,S,N),
restriction(R),
testPlan(T,N,Exec,Fn).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%% FIND PLAN %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
plano(P) :- progressivePlan(P, 0).
progressivePlan(P, N) :- createPlan(P,_,0,N).
progressivePlan(P, N) :- \+ createPlan(P,_,0,N),
NewN is N + 1,
progressivePlan(P, NewN).
createPlan(Plan,[I|Exec],N,Max) :- inicial(I),
createPlan(Plan,I,Exec,Fn,N,Max),
satisfiedGoal(Fn).
createPlan([],Fn,[],Fn,Max,Max):- !.
createPlan([H|T],S,[H,N|Exec],Fn,Acc, Max) :- accao(nome:H, condicoes:C, efeitos:E, restricoes:R),
sub(C,S),
effects(E,S,N),
restriction(R),
NewAcc is Acc+1,
createPlan(T,N,Exec,Fn,NewAcc, Max).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%`
I've tried simplifying the goal by just doing one or two moves, which works for the one and when the two moves don't contradict each other, like moving a marble on through one that was already moved, entering the loop with two moves when they do, like with said objective:
objectivos([ball(4,5), empty(3,5), empty(5,5), empty(6,5)]).
I've tried tracing and debugging but I cant seem to find the issue, although I believe it to be located in the formulation of the problem as opposed to the Planner itself. Any Ideas?
There is at least one logical error in your code, and some simple performance tweaks are possible. This gives a partial solution to your problem.
First, for the logical error: The intended solution for the goal objectivos([ball(4,5), empty(3,5), empty(5,5), empty(6,5)]) seems to be the plan P = [move(3, 5, 5, 5), move(6, 5, 4, 5)]. But the second of these moves is not legal with your definition of restricoes: For this move you have Xi = 6, Xf = 4, and conditions requiring that 6 =< Xm and Xm <= 4, but this is impossible. The idea of these constraints is to ensure that ball(Xm,Ym) is between the other two balls in the move. Here is an alternative formulation that ensures this:
restricoes : [abs(Xf-Xi)+abs(Yf-Yi) =:= 2,
abs(Xf-Xi)*abs(Yf-Yi) =:= 0,
abs(Xf-Xm)+abs(Yf-Ym) =:= 1,
abs(Xi-Xm)+abs(Yi-Ym) =:= 1]
This also excludes a case that confused me before, when tracing the code: Previously it was legal to have ball(Xi,Yi) = ball(Xm,Ym).
Second, to improve performance, exchange the goals effects(E,S,N) and restriction(R) in the definition of createPlan/6. Previously you computed the effects of moves before checking their legality! Because most moves proposed by the planner are illegal, this wastes a lot of time.
Then, to make the whole thing nicer to use, you can change the definitions of plano/1 and createPlan/4 to:
plano(P) :-
length(P, PlanLength),
createPlan(P, _, 0, PlanLength).
createPlan(Plan,[I|Exec],N,Max) :- inicial(I),
N =< Max,
createPlan(Plan,I,Exec,Fn,N,Max),
satisfiedGoal(Fn).
This is simpler than the definition you had before, and it also behaves more nicely. We can pass in a complete plan to check whether it is legal, or just pass in a list of fixed length to ask what plans of that length exist:
?- P = [_,_], plano(P).
P = [move(3, 5, 5, 5), move(6, 5, 4, 5)] ;
false. % no more solutions
With your definition, this would go on looping and counting up the Max counter, searching for further solutions that cannot exist.
With this formulation we can switch to your big goal and try to search for a solution (this is partly specific to SWI-Prolog):
?- length(P, N), format('searching for solutions of length ~w~n', [N]), time(plano(P)).
searching for solutions of length 0
% 58 inferences, 0.000 CPU in 0.000 seconds (71% CPU, 2171959 Lips)
searching for solutions of length 1
% 9,709 inferences, 0.001 CPU in 0.001 seconds (100% CPU, 9123980 Lips)
searching for solutions of length 2
% 79,789 inferences, 0.009 CPU in 0.009 seconds (100% CPU, 8778416 Lips)
searching for solutions of length 3
% 477,230 inferences, 0.051 CPU in 0.051 seconds (100% CPU, 9409315 Lips)
searching for solutions of length 4
% 3,412,088 inferences, 0.361 CPU in 0.361 seconds (100% CPU, 9453315 Lips)
searching for solutions of length 5
% 30,967,699 inferences, 3.503 CPU in 3.503 seconds (100% CPU, 8840598 Lips)
searching for solutions of length 6
I had to interrupt the search at this point, it becomes too slow. More tweaks are certainly possible, and I might keep looking at this.

Prolog subtract value not working

I got this knowledge base:
bottle(b1).
bottle(b2).
bottle(b3).
bottle(b4).
full(bottle(b1),100).
full(bottle(b2),150).
full(bottle(b3),300).
full(bottle(b4),400).
consume(bottle(X),Milliliter) :-
full(bottle(X),Y),
Milliliter=<Y,
Y-10.
So I want to use the consume predicate, and I want to reduce the value assigned to full as much as the value which is getting consumed. Is it allowed to subtract from static values and how could I work around this problem to achieve only the value true if there hasn't been consumed the bottle yet.
If you want to "update" the KB when you call "consume", you will have to retract and assert the fact, for example...
% Use this to add the initial facts (if you don;t have a clause to do this, prolog complains about modifying static clauses...)
addfacts :-
asserta(full(bottle(b1),100)),
asserta(full(bottle(b2),150)),
asserta(full(bottle(b3),300)),
asserta(full(bottle(b4),400)).
consume(bottle(X), Millis) :-
% Retract the current state of the bottle
retract(full(bottle(X), V)),
% Calculate the new Millis after consumption
Y is V - Millis,
% Check it was possible (there should be 0 or more millis left after)
Y >= 0,
% Add the new fact
asserta(full(bottle(X), Y)).
Now in prolog, you can do...
1 ?- addfacts.
true.
2 ?- full(bottle(b1), X).
X = 100.
3 ?- consume(bottle(b1), 10).
true.
4 ?- full(bottle(b1), X).
X = 90 .

Prolog - get the factors for a given number doesn't stop?

I need to find the factors of a given number , e.g :
?- divisors2(40,R).
R = [40,20,10,8,5,4,2,1].
The code :
% get all the numbers between 1-X
range(I,I,[I]).
range(I,K,[I|L]) :- I < K, I1 is I + 1, range(I1,K,L).
% calc the modulo of each element with the given number :
% any x%y=0 would be considered as part of the answer
divisors1([],[],_).
divisors1([H|T],S,X):-divisors1(T,W,X),Z is X mod H,Z==0,S=[H|W].
divisors1([_|T],S,X):-divisors1(T,S,X).
divisors2(X,Result) :-range(1,X,Result1),divisors1(Result1,Result,X).
But when I run divisors2(40,RR). I get infinite loop and nothing is presented to the screen.
Why ?
Regards
You are asking why you get an infinite loop for the query divisors2(40,R). I almost wanted to explain this to you using a failure-slice. Alas ...
... the answer is: No, you don't get an infinite loop! And your program also finds an answer. It's
R = [1,2,4,5,8,10,20,40]
which looks reasonable to me. They are in ascending order, and you wanted a descending list, but apart from that, that is a perfect answer. No kidding. However, I suspect that you were not patient enough to get the answer. For 36 I needed:
?- time(divisors2(36,R)).
% 10,744,901,605 inferences, 2248.800 CPU in 2252.918 seconds (100% CPU, 4778061 Lips)
R = [1,2,3,4,6,9,12,18,36]
; ... .
Quite unusual ... for a list with at most 36 meager integers Prolog needed 10 744 901 605 inferences, that is less than 234. Does this ring a bell? In any case, there are problems with your program. In fact, there are two quite independent problems. How can we find them?
Maybe we are looking at the wrong side. Just go back to the query. Our first error was how we used Prolog's toplevel. We were very impressed to get an answer. But Prolog offered us further answers! In fact:
?- time(divisors2(36,R)).
% 10,744,901,605 inferences, 2248.800 CPU in 2252.918 seconds (100% CPU, 4778061 Lips)
R = [1,2,3,4,6,9,12,18,36]
; % 10 inferences, 0.000 CPU in 0.000 seconds (82% CPU, 455892 Lips) R = [1,2,3,4,6,9,12,18]
; % 917,508 inferences, 0.192 CPU in 0.192 seconds (100% CPU, 4789425 Lips)
R = [1,2,3,4,6,9,12,36]
; ... .
This gets too tedious. Maybe a tiny example suffices?
?- divisors2(6,R).
R = [1,2,3,6]
; R = [1,2,3]
; R = [1,2,6]
; R = [1,2]
; R = [1,3,6]
; R = [1,3]
; R = [1,6]
; R = [1]
; R = [2,3,6]
; R = [2,3]
; R = [2,6]
; R = [2]
; R = [3,6]
; R = [3]
; R = [6]
; R = []
; false.
More than enough! Maybe we stick to the minimal example [] and restate it:
?- divisors2(6,[]).
true
; false.
Clearly, that's not what we expected. We wanted this to fail. How to localize the problem? There is one general debugging strategy in Prolog:
If a goal is too general, specialize the program.
We can specialize the program by adding further goals such that above query still succeeds. I will add false and some (=)/2 goals. false is particularly interesting because it wipes out an entire clause:
?- divisors2(6,[]).
range(I,I,[I]) :- I = 6.
range(I,K,[I|L]) :- K = 6,
I < K,
I1 is I + 1,
range(I1,K,L).
divisors1([],[],X) :- K=6.
divisors1([H|T],S,X):- false,
divisors1(T,W,X),
Z is X mod H,
Z=0,
S=[H|W].
divisors1([_|T],S,X):- S = [], X = 6,
divisors1(T,S,X).
divisors2(X,Result) :- X = 6, Result = [].
range(1,X,Result1),
divisors1(Result1,Result,X).
Somewhere in the remaining part something is too general! In fact the recursive rule of divisors1/3 is too general. This new modified program of yours is called a slice that is a specialization of our original program.
Several ways to fix this, the most naive way is to add the corresponding condition like so:
divisors1([],[],_).
divisors1([H|T],S,X):-
divisors1(T,W,X),
0 =:= X mod H,
S=[H|W].
divisors1([H|T],S,X):-
divisors1(T,S,X),
0 =\= X mod H.
However, the performance of the program did not improve. To see this, I will again specialize this program:
divisors1([],[],_) :- false.
divisors1([H|T],S,X):-
divisors1(T,W,X), false,
0 =:= X mod H,
S=[H|W].
divisors1([H|T],S,X):-
divisors1(T,S,X), false,
0 =\= X mod H.
Thus: No matter what is there behind the false, this program will try at least 3 * 2^N inferences for a list of length N.
By putting the recursive goals last we can avoid this.
You have a bug here
divisors1([H|T],S,X):-
divisors1(T,W,X),
Z is X mod H,
Z==0,S=[H|W]. <=== here
If Z is Zero then S = [H|W] else S = W.
If you correct your range (use a cut for the end-of-recursion clause), you will get it sort of working. You do not immediately succeed upon finding all divisors though.
A solution using your general idea, but also built-ins between/3 and bagof/3 (to make typing a bit easier):
divisors(X, Divs) :- bagof(D, divs(X,D), Divs).
divs(X,D) :- between(1,X,D), 0 is X mod D.
Please note that this solution returns the divisors in increasing order.

Resources