Related
The following is the classic "textbook" vanilla meta-interpreter for prolog.
% simplest meta-interpreter
solve(true) :- !.
solve((A,B)):- !, solve(A), solve(B).
solve(A) :- clause(A,B), solve(B).
The following is simple program which establishes facts two relations which are "positive" and one relation which makes use of negation by failure \+.
% fruit
fruit(apple).
fruit(orange).
fruit(banana).
% colour
yellow(banana).
% Mary likes all fruit
likes(mary, X) :- fruit(X).
% James likes all fruit, as long as it is yellow
likes(james, X) :- fruit(X), yellow(X).
% Sally likes all fruit, except yellow fruit
likes(sally, X) :- fruit(X), \+ (yellow(X)).
The meta-interpeter can handle goals related to the first two relations ?-solve(likes(mary,X)) and ?- solve(likes(james,X)_.
However it fails with a goal related to the third relation ?- solve(likes(sally,X). The swi-prolog reports a stack limit being reached before the program crashes.
Question 1: What is causing the meta-interpreter to fail? Can it be easily adjusted to cope with the \+ negation? Is this related to the sometimes discussed issue of built-ins not being executed by the vanilla meta-interpreter?
Question 2: Where can I read about the need for those cuts in the vanilla meta-interpreter?
Tracing suggests the goal is being grown endlessly:
clause(\+call(call(call(call(yellow(apple))))),_5488)
Exit:clause(\+call(call(call(call(yellow(apple))))),\+call(call(call(call(call(yellow(apple)))))))
Call:solve(\+call(call(call(call(call(yellow(apple)))))))
Call:clause(\+call(call(call(call(call(yellow(apple)))))),_5508)
Exit:clause(\+call(call(call(call(call(yellow(apple)))))),\+call(call(call(call(call(call(yellow(apple))))))))
Call:solve(\+call(call(call(call(call(call(yellow(apple))))))))
Change solve(A) into:
solve(Goal) :-
writeln(Goal),
sleep(1),
clause(Goal, Body),
solve(Body).
... and we see:
?- solve_mi(likes(sally,X)).
likes(sally,_8636)
fruit(_8636)
\+yellow(apple)
\+call(yellow(apple))
\+call(call(yellow(apple)))
\+call(call(call(yellow(apple))))
...
clause/2 determines the body of \+yellow(apple) to be \+call(yellow(apple)), which is not a simplification.
Can use instead:
solve_mi(true) :-
!.
solve_mi((Goal1, Goal2)):-
!,
solve_mi(Goal1),
solve_mi(Goal2).
solve_mi(\+ Goal) :-
!,
\+ solve_mi(Goal).
solve_mi(Goal) :-
clause(Goal, Body),
solve_mi(Body).
Result in swi-prolog:
?- solve_mi(likes(sally,X)).
X = apple ;
X = orange ;
false.
I'm using solve_mi because solve conflicts with e.g. clpBNR, and I'm not using variable names A and B because they convey no meaning.
For understanding the cuts, I'd recommend gtrace, to see the unwanted unification with other goals that would otherwise take place.
Im trying to write a code where if I run english(X). in Prolog I get a list of numbers 1-100 in linguistic form (one, two,....,twenty five,...,one hundred).
Is there a way to do this with a lexicon? I want to write a predicate for a pattern with how the "-teen" works. a predicate for the "-ty" and also a predicate for (twenty one, twenty two)? and when I say english(X). I should get a list of all the numbers. (one; two; three;....fifty one; .... one hundred. )
digit(0).
digit(1) :-
write(one).
digit(2) :-
write(two).
digit(3) :-
write(three).
digit(4) :-
write(four).
digit(5) :-
write(five).
digit(6) :-
write(six).
digit(7) :-
write(seven).
digit(8) :-
write(eight).
digit(9) :-
write(nine).
I have this so for and I am trying to write a predicate but having a hard time.
The links provided by Guy Coder give an excellent general case version.
Here is a solution that respects your starter code, although you should think about how you can make it neater and more general (including by consulting the links!)
english(X) :-
X<10, !,
digit(X).
english(X) :-
X<20, !,
teen(X).
english(X) :-
X<100, !,
Units is X mod 10,
Tens is X - Units,
tens(Tens),
digit(Units).
english(100) :-
write('one hundred').
teen(10) :-
write('ten'). % etc 10 to 19
tens(20) :-
write('twenty'). % etc 20 to 90
digit(0). % etc. 1 to 9 (as original digits)
I wonder, is it possible to do planning in Prolog using the knowledge base modified by retract and assert during the runtime?
My idea is as follows: assume that I need to replace a flat tire of a car. I can either put something on the ground or move something from the ground to some free place.
So I came up with such a code:
at(flat, axle).
at(spare, trunk).
free(Where) :- at(_, Where), !, fail.
remove(What) :- at(What, _), retract(at(What, _)), assert(at(What, ground)).
put_on(What, Where) :- at(What, _), free(Where), retract(at(What, _)), assert(at(What, Where)).
(I am a rookie in Prolog so maybe that it is even wrong, if so, please advise me how to correct it.)
The idea is: I have a flat tire on the axle and a spare one in the trunk. I can remove a thing X if X is somewhere and to remove it, I remove the fact specifying where it is and add a fact that it is on the ground. Similarly, I can put a thing X to location Y if X is somewhere and Y is free and to do so, I remove X from where it is and add the fact that X is at Y.
And now I am stuck: I have no idea how to use this code now, since at(spare, axle) just says nope, even with tracing.
So the question: can such an approach be used and if so, how?
I hope it makes sense.
Using the example code from "Artificial Intelligence - Structures and Strategies for Complex Problem Solving" by George F Luger (WorldCat)
adts
%%%
%%% This is one of the example programs from the textbook:
%%%
%%% Artificial Intelligence:
%%% Structures and strategies for complex problem solving
%%%
%%% by George F. Luger and William A. Stubblefield
%%%
%%% Corrections by Christopher E. Davis (chris2d#cs.unm.edu)
%%%
%%% These programs are copyrighted by Benjamin/Cummings Publishers.
%%%
%%% We offer them for use, free of charge, for educational purposes only.
%%%
%%% Disclaimer: These programs are provided with no warranty whatsoever as to
%%% their correctness, reliability, or any other property. We have written
%%% them for specific educational purposes, and have made no effort
%%% to produce commercial quality computer programs. Please do not expect
%%% more of them then we have intended.
%%%
%%% This code has been tested with SWI-Prolog (Multi-threaded, Version 5.2.13)
%%% and appears to function as intended.
%%%%%%%%%%%%%%%%%%%% stack operations %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% These predicates give a simple, list based implementation of stacks
% empty stack generates/tests an empty stack
member(X,[X|_]).
member(X,[_|T]):-member(X,T).
empty_stack([]).
% member_stack tests if an element is a member of a stack
member_stack(E, S) :- member(E, S).
% stack performs the push, pop and peek operations
% to push an element onto the stack
% ?- stack(a, [b,c,d], S).
% S = [a,b,c,d]
% To pop an element from the stack
% ?- stack(Top, Rest, [a,b,c]).
% Top = a, Rest = [b,c]
% To peek at the top element on the stack
% ?- stack(Top, _, [a,b,c]).
% Top = a
stack(E, S, [E|S]).
%%%%%%%%%%%%%%%%%%%% queue operations %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% These predicates give a simple, list based implementation of
% FIFO queues
% empty queue generates/tests an empty queue
empty_queue([]).
% member_queue tests if an element is a member of a queue
member_queue(E, S) :- member(E, S).
% add_to_queue adds a new element to the back of the queue
add_to_queue(E, [], [E]).
add_to_queue(E, [H|T], [H|Tnew]) :- add_to_queue(E, T, Tnew).
% remove_from_queue removes the next element from the queue
% Note that it can also be used to examine that element
% without removing it
remove_from_queue(E, [E|T], T).
append_queue(First, Second, Concatenation) :-
append(First, Second, Concatenation).
%%%%%%%%%%%%%%%%%%%% set operations %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% These predicates give a simple,
% list based implementation of sets
% empty_set tests/generates an empty set.
empty_set([]).
member_set(E, S) :- member(E, S).
% add_to_set adds a new member to a set, allowing each element
% to appear only once
add_to_set(X, S, S) :- member(X, S), !.
add_to_set(X, S, [X|S]).
remove_from_set(_, [], []).
remove_from_set(E, [E|T], T) :- !.
remove_from_set(E, [H|T], [H|T_new]) :-
remove_from_set(E, T, T_new), !.
union([], S, S).
union([H|T], S, S_new) :-
union(T, S, S2),
add_to_set(H, S2, S_new).
intersection([], _, []).
intersection([H|T], S, [H|S_new]) :-
member_set(H, S),
intersection(T, S, S_new),!.
intersection([_|T], S, S_new) :-
intersection(T, S, S_new),!.
set_diff([], _, []).
set_diff([H|T], S, T_new) :-
member_set(H, S),
set_diff(T, S, T_new),!.
set_diff([H|T], S, [H|T_new]) :-
set_diff(T, S, T_new), !.
subset([], _).
subset([H|T], S) :-
member_set(H, S),
subset(T, S).
equal_set(S1, S2) :-
subset(S1, S2), subset(S2, S1).
%%%%%%%%%%%%%%%%%%%%%%% priority queue operations %%%%%%%%%%%%%%%%%%%
% These predicates provide a simple list based implementation
% of a priority queue.
% They assume a definition of precedes for the objects being handled
empty_sort_queue([]).
member_sort_queue(E, S) :- member(E, S).
insert_sort_queue(State, [], [State]).
insert_sort_queue(State, [H | T], [State, H | T]) :-
precedes(State, H).
insert_sort_queue(State, [H|T], [H | T_new]) :-
insert_sort_queue(State, T, T_new).
remove_sort_queue(First, [First|Rest], Rest).
planner
%%%%%%%%% Simple Prolog Planner %%%%%%%%
%%%
%%% This is one of the example programs from the textbook:
%%%
%%% Artificial Intelligence:
%%% Structures and strategies for complex problem solving
%%%
%%% by George F. Luger and William A. Stubblefield
%%%
%%% Corrections by Christopher E. Davis (chris2d#cs.unm.edu)
%%%
%%% These programs are copyrighted by Benjamin/Cummings Publishers.
%%%
%%% We offer them for use, free of charge, for educational purposes only.
%%%
%%% Disclaimer: These programs are provided with no warranty whatsoever as to
%%% their correctness, reliability, or any other property. We have written
%%% them for specific educational purposes, and have made no effort
%%% to produce commercial quality computer programs. Please do not expect
%%% more of them then we have intended.
%%%
%%% This code has been tested with SWI-Prolog (Multi-threaded, Version 5.2.13)
%%% and appears to function as intended.
:- [adts].
plan(State, Goal, _, Moves) :- equal_set(State, Goal),
write('moves are'), nl,
reverse_print_stack(Moves).
plan(State, Goal, Been_list, Moves) :-
move(Name, Preconditions, Actions),
conditions_met(Preconditions, State),
change_state(State, Actions, Child_state),
not(member_state(Child_state, Been_list)),
stack(Child_state, Been_list, New_been_list),
stack(Name, Moves, New_moves),
plan(Child_state, Goal, New_been_list, New_moves),!.
change_state(S, [], S).
change_state(S, [add(P)|T], S_new) :- change_state(S, T, S2),
add_to_set(P, S2, S_new), !.
change_state(S, [del(P)|T], S_new) :- change_state(S, T, S2),
remove_from_set(P, S2, S_new), !.
conditions_met(P, S) :- subset(P, S).
member_state(S, [H|_]) :- equal_set(S, H).
member_state(S, [_|T]) :- member_state(S, T).
reverse_print_stack(S) :- empty_stack(S).
reverse_print_stack(S) :- stack(E, Rest, S),
reverse_print_stack(Rest),
write(E), nl.
/* sample moves */
move(pickup(X), [handempty, clear(X), on(X, Y)],
[del(handempty), del(clear(X)), del(on(X, Y)),
add(clear(Y)), add(holding(X))]).
move(pickup(X), [handempty, clear(X), ontable(X)],
[del(handempty), del(clear(X)), del(ontable(X)),
add(holding(X))]).
move(putdown(X), [holding(X)],
[del(holding(X)), add(ontable(X)), add(clear(X)),
add(handempty)]).
move(stack(X, Y), [holding(X), clear(Y)],
[del(holding(X)), del(clear(Y)), add(handempty), add(on(X, Y)),
add(clear(X))]).
go(S, G) :- plan(S, G, [S], []).
test :- go([handempty, ontable(b), ontable(c), on(a, b), clear(c), clear(a)],
[handempty, ontable(c), on(a,b), on(b, c), clear(a)]).
Most of the code stays the same, the only changes needed to solve your question are the predicates move/3 and the query test. Either comment out or remove the predicates move/3 and test/0 from the above code before adding predicates to solve your question.
Below is all of the new predicates needed, move/3 and test/0. The first move/3 is shown and the remainder need to be revealed (click Reveal spoiler) so that you can see them if needed but you should try to do them yourself.
move(take_from_trunk(X), [hand(empty), trunk(X)],
[del(hand(empty)), del(trunk(X)),
add(hand(X)), add(trunk(empty))]).
The state keeps track of four locations, hand, ground, axle, and trunk, and three values, flat, spare, and empty for the locations. The predicate move/3 also makes uses of variables so that they are not fixed in what they can do.
The move/3 predicate has 3 parameters.
Name: What appears in the answer, e.g. take_from_trunk(spare).
Preconditions: The conditions that have to be present in state for the move to be applied.
Actions: The changes made to state if the move is applied. These take the place of your assert and retract. The changes are very simple, you remove some of the properties of state, e.g. del(hand(empty)) and add some, e.g. add(hand(X)). For your given problem, this solution is simple in that for each change, for every del there is a matching add.
The query:
test :- go([hand(empty), trunk(spare), axle(flat), ground(empty)],
[hand(empty), trunk(flat), axle(spare), ground(empty)]).
Example run:
?- test.
moves are
take_from_trunk(spare)
place_on_ground(spare)
take_off_axle(flat)
place_in_trunk(flat)
pickup_from_ground(spare)
place_on_axle(spare)
true.
Other move/3 predicates needed. Try to do this on your own.
move(take_off_axle(X), [hand(empty), axle(X)],
[del(hand(empty)), del(axle(X)),
add(hand(X)), add(axle(empty))]).
move(place_on_ground(X), [hand(X), ground(empty)],
[del(hand(X)), del(ground(empty)),
add(hand(empty)), add(ground(X))]).
move(pickup_from_ground(X), [hand(empty), ground(X)],
[del(hand(empty)), del(ground(X)),
add(hand(X)), add(ground(empty))]).
move(place_on_axle(X), [hand(X), axle(empty)],
[del(hand(X)), del(axle(empty)),
add(hand(empty)), add(axle(X))]).
move(place_in_trunk(X), [hand(X), trunk(empty)],
[del(hand(X)), del(trunk(empty)),
add(hand(empty)), add(trunk(X))]).
In writing these predicates some of move/3 were not working as I expected so I created simple test queries for each to check them.
Using the test also helped me to change what was in state and how it was represented, e.g, instead of handempty and holding(X) it was changed to hand(empty) and hand(X) which was easier to understand, follow, and check for consistency of the code, but most likely made the code more inefficient.
test_01 :- go([hand(empty), trunk(spare), axle(flat), ground(empty)],
[hand(spare), trunk(empty), axle(flat), ground(empty)]).
test_02 :- go([hand(empty), trunk(spare), axle(flat), ground(empty)],
[hand(flat), trunk(spare), axle(empty), ground(empty)]).
test_03 :- go([hand(flat), trunk(spare), axle(empty), ground(empty)],
[hand(empty), trunk(spare), axle(empty), ground(flat)]).
test_04 :- go([hand(empty), trunk(spare), axle(empty), ground(flat)],
[hand(flat), trunk(spare), axle(empty), ground(empty)]).
test_05 :- go([hand(spare), trunk(empty), axle(empty), ground(flat)],
[hand(empty), trunk(empty), axle(spare), ground(flat)]).
test_06 :- go([hand(flat), trunk(empty), axle(spare), ground(empty)],
[hand(empty), trunk(flat), axle(spare), ground(empty)]).
Some of these test work as expected using just one move, while others return many moves. I did not modify the move/3 here so that only one move/3 is considered, but they can be modified if you so choose. Think guard statements or constraints.
The other reason the test results are listed here is to show that some of the moves are not picked in the way you would think, or intended and don't work exactly as you would expect, but yet the query to the posted question works as expected. So if you write test cases and they return something like this, don't assume your move/3 is invalid, or has bugs, they may not. When you get all of the move/3 and the final query working as expected, then go back and try to understand why these multiple moves are happening, and then modify them if you desire.
?- test_01.
moves are
take_from_trunk(spare)
true.
?- test_02.
moves are
take_from_trunk(spare)
place_on_ground(spare)
take_off_axle(flat)
place_in_trunk(flat)
pickup_from_ground(spare)
place_on_axle(spare)
take_from_trunk(flat)
place_on_ground(flat)
take_off_axle(spare)
place_in_trunk(spare)
pickup_from_ground(flat)
true.
?- test_03.
moves are
place_on_ground(flat)
true.
?- test_04.
moves are
take_from_trunk(spare)
place_on_axle(spare)
pickup_from_ground(flat)
place_in_trunk(flat)
take_off_axle(spare)
place_on_ground(spare)
take_from_trunk(flat)
place_on_axle(flat)
pickup_from_ground(spare)
place_in_trunk(spare)
take_off_axle(flat)
true.
?- test_05.
moves are
place_on_axle(spare)
true.
?- test_06.
moves are
place_on_ground(flat)
take_off_axle(spare)
place_in_trunk(spare)
pickup_from_ground(flat)
place_on_axle(flat)
take_from_trunk(spare)
place_on_ground(spare)
take_off_axle(flat)
place_in_trunk(flat)
pickup_from_ground(spare)
place_on_axle(spare)
true.
I am doing Prolog Programming for my research and I got some problems..
First, all of my codes are below.
%% Lines are without period(.)
diagnosis :-
readln(Line1),
readln(Line2),
readln(Line3),
readln(Line4),
readln(Line5),
readln(Line6),
readln(Line7),
readln(Line8),
readln(Line9),
readln(Line10),
write(Line1),nl,
write(Line2),nl,
write(Line3),nl,
write(Line4),nl,
write(Line5),nl,
write(Line6),nl,
write(Line7),nl,
write(Line8),nl,
write(Line9),nl,
write(Line10),nl.
%% (get_symptom(Line1,[man]) -> write('man!!!!!!!!!')),
%% (get_symptom(Line2,[woman]) -> write('woman!!!!!!!!!')).
%% if A then B else C, (A->B; C)
%% grammar
s --> np, vp.
np --> det, n.
vp --> v, np.
det --> [a].
n --> [man].
v --> [has].
n --> [woman].
n --> [fever].
n --> [runny_nose].
get_symptom(Line,N) :- s(Line,[]), member(N,Line).
member(X, [X|T]).
member(X,[H|T]) :-
member(X,T).
%% FindSymptom(Line, [Symptom]) : - s(Line,[]), np(_, _, object,[a,
%% Symptom]), n(singular, [Symptom], []).
start :-
write('What is the patient''s name? '),
readln(Patient), %% Here, this can be used for input of all symtoms
diagnosis,
hypothesis(Patient,cold,S1),
append([cold/S1/red],[],N1), write(S1),
write('until...'),
hypothesis(Patient,severe_cold,S2), write(S2),
append([severe_cold/S2/red],N1,BarList),
write('until...'),
%% write(Patient,"probably has ",Disease,"."),nl.
hypothesis(Patient,Disease,100),
write(Patient),
write(' probably has '),
write(Disease),
write('.'),
test_barchart(BarList).
start :-
write('Sorry, I don''t seem to be able to'),nl,
write('diagnose the disease.'),nl.
symptom(Patient,fever) :-
get_symptom(Line1, [fever]);
get_symptom(Line2, [fever]);
get_symptom(Line3, [fever]);
get_symptom(Line4, [fever]);
get_symptom(Line5, [fever]);
get_symptom(Line6, [fever]);
get_symptom(Line7, [fever]);
get_symptom(Line8, [fever]);
get_symptom(Line9, [fever]);
get_symptom(Line10, [fever]).
symptom(Patient,runny_nose) :-
get_symptom(Line1, [runny_nose]);
get_symptom(Line2, [runny_nose]);
get_symptom(Line3, [runny_nose]);
get_symptom(Line4, [runny_nose]);
get_symptom(Line5, [runny_nose]);
get_symptom(Line6, [runny_nose]);
get_symptom(Line7, [runny_nose]);
get_symptom(Line8, [runny_nose]);
get_symptom(Line9, [runny_nose]);
get_symptom(Line10, [runny_nose]).
hypothesis(Patient,cold,Score_Cold) :-
(symptom(Patient,fever), Score_Cold is 100),write('!!!');
Score_Cold is 0.
hypothesis(Patient,severe_cold,Score_Severe) :-
((symptom(Patient,fever), Score1 is 50);
Score1 is 0),
((symptom(Patient, runny_nose), Score2 is 50);
Score2 is 0),
Score_Severe is Score1 + Score2.
%% hypothesis(Disease) :-
%%(hypothesis1(Patient,cold,Score1),
%%Score1 =:= 100 -> Disease = cold);
%%(hypothesis2(Patient,severe_cold,Score2),
%%Score2 =:= 100 -> Disease = severe_cold).
%% make graph for the result
:- use_module(library(pce)).
:- use_module(library(plot/barchart)).
:- use_module(library(autowin)).
test_barchart(BarList):-
new(W, picture),
send(W, display, new(BC, bar_chart(vertical,0,100))),
forall(member(Name/Height/Color,
BarList),
( new(B, bar(Name, Height)),
send(B, colour(Color)),
send(BC, append, B)
)),
send(W, open).
%% [X/100/red, y/150/green, z/80/blue, v/50/yellow]
%% append List
append([], L, L).
append([H|T], L2, [H|L3]):-
append(T, L2, L3).
As you can see, I want to make a bar_graph from 10 input lines by extracting symptoms..
But when I executed this code, I got the result as below...
1 ?- start.
What is the patient's name? GJ
|: a man has a runny_nose
|: a
|: a
|: a
|: a
|: a
|: a
|: a
|: a
|: a
[a,man,has,a,runny_nose]
[a]
[a]
[a]
[a]
[a]
[a]
[a]
[a]
[a]
!!!100until...100until...!!![GJ] probably has cold.
true
I only typed one symptom (runny_nose). I want to get Score for "cold" is 0, Score for "severe_cold" is 50 and BarGraph result... But What Happened? I can't find..
*****Edited******
I found that the problem is related to local variables (Line1, .. ,Line10) But how can I deal with? If I can make all the variables; Line1, ... , Line10 as global variables then, I think the problem can be solved...
****Addition*****
I changed my 'start' predicate as follows...I didn't use 'diagnosis' and 'hypothesis' predicates/ But the problems is maybe.. 'get_symptoms' predicate. Is there any choice I can choose except that I don't use 'get_symptoms' and 'symptoms' predicates...? Then the code will become very coarse...
start :-
write('What is the patient''s name? '),
readln(Patient), %% Here, this can be used for input of all symtom
readln(Line1),
readln(Line2),
readln(Line3),
readln(Line4),
readln(Line5),
readln(Line6),
readln(Line7),
readln(Line8),
readln(Line9),
readln(Line10),
(symptom(Patient,fever,Line1,Line2,Line3,Line4,Line5,Line6,Line7,Line8,Line9,Line10) -> (Cold is 80, Severe_Cold is 50)),
(symptom(Patient,runny_nose,Line1,Line2,Line3,Line4,Line5,Line6,Line7,Line8,Line9,Line10) -> Severe_Cold is Severe_Cold + 50),
write(Severe_Cold), write(Cold),
append([cold/Cold/red],[],N1),
append([severe_cold/Severe_Cold/red],N1,BarList),
%% write(Patient,"probably has ",Disease,"."),nl.
write(Severe_Cold),
((Cold =:= 100 -> Disease = cold) ; (Severe_Cold =:= 100 -> Disease = severe_cold)),
write(Patient),
write(' probably has '),
write(Disease),
write('.'),
test_barchart(BarList).
When programming in Prolog, you need to do some research into the language to understand how it works. Many Prolog beginners make the mistake of learning a couple of snippets of Prolog logic and then apply what they know of other languages to attempt to create a valid Prolog programming. However, Prolog doesn't work like other common languages at all.
Regarding variables, there are no globals. Variables are always "local" to a predicate clause. A predicate clause is one of one or more clauses that describe a predicate. For example:
foo(X, Y) :- (some logic including X and Y).
foo(X, Y) :- (some other logic including X and Y).
foo(X, X) :- (some other logic including X).
These are three clauses describing the predicate foo/2. The value of X or Y instantiated in one clause isn't visible to the other clauses.
If you want to instantiate a variable in one predicate and use it in another, you have to pass it as a parameter:
foo([1,2,3,4], L),
bar(L, X).
Here, foo might instantiate L using some logic and based upon the instantiated value of [1,2,3,4] for the first argument. Then L (now instantiated) is passed as the first argument to the predicate bar.
If you need a value to be persistent as data, you could assert it as a fact as follows:
foo :-
(some logic that determines X),
assertz(my_fact(X)),
(more logic).
bar :-
my_fact(X), % Will instantiate X with what was asserted
(some logic using X).
This would work, but is not a desirable approach in Prolog to "fake" global variables. Asserting items into persistent data is designed for the purpose of maintaining a Prolog database of information.
So you can see that the logic you have involving Line1, Line2, ... will not work. One clue would be that you must have received many warnings about these variables being "singleton". You need to study Prolog a bit more, then recast your logic using that knowledge.
I'm trying to write a rule in my prolog program that determines if someone is the brother of someone else.
For example, if I type brother_of(chris, X) it will return christy because chris is the brother of christy. However, when I type this I get an existence exception. I've included facts to cover everything, but maybe it's a problem in my rule definition? The code is below.
/* Facts */
female(ella).
female(jodi).
female(sonya).
female(jane).
female(christy).
female(mary).
male(arnold).
male(chris).
male(louis).
male(mark).
father(arnold).
father(louis).
father(mark).
mother(ella).
mother(jodi).
mother(jane).
mother(mary).
father_of(arnold, chris). /* arnold is the father of chris */
father_of(arnold, christy).
father_of(louis, mark).
father_of(mark, arnold).
mother_of(mary, chris).
mother_of(mary, christy).
mother_of(jane, arnold).
mother_of(ella, sonya).
mother_of(jodi, ella).
mother_of(jodi, mark).
/* Rules */
brother_of(X, Y) :-
male(X),
((father_of(Z, X), father_of(Z, Y));
(mother_of(W, X), mother_of(W, Y))),
X =\= Y.
The operator =\= is used in arithmetic only (AFAIK), to see if two terms are different (non-unifiable) use the operator \=:
X \= Y.
Update: a brief introduction to the cut (!) goal: when the cut is used in a predicate, it means no more answers should be searched besides the already found ones (i.e. you are "cutting the remaining branches" in the search tree). Example:
first_child(X,Y) :-
father_of(X,Y), !.
?- first_child(arnold,Y).
Y = chris ;
no
After the cut is reached, all choice points before the cut are discarded (but new ones can be created after it). In you example, you know that if X and Y have the same father, it's irrelevant if they also have the same mother. So you can place the cut right after the "common father" part succeeds:
brother_of(X, Y) :-
male(X),
((father_of(Z, X), father_of(Z, Y), X \= Y, !); # If cut is reached, will not run the next line
(mother_of(W, X), mother_of(W, Y), X \= Y)).
Note however that using cut has many pitfalls (refer to "green cut" vs "red cut" in the linked Wikipedia article), but it's too much to describe here. (note how I repeated X \= Y - if I didn't do that the program would fail sometimes)
Lastly, I'd also like to point out that using ; is often discouraged when writing Prolog code (you can use when needed though). Instead, write it in two clauses:
brother_of(X, Y) :-
male(X),
father_of(Z, X),
father_of(Z, Y),
X \= Y,
!.
brother_of(X, Y) :-
male(X),
mother_of(W, X),
mother_of(W, Y),
X \= Y.
(this ; vs two clauses is a bit subjective, though, so I won't argue too much about it... just know that both ways are possible, and will produce the same result)