How to use inference in Prolog?

Hi,
Newbie here.
Trying to do the following.

belongs(person1,chat1).
alsoBelongs( P ) :- 
   belongs(P,chat1) -> belongs(P,chat2).                                 
alsoBelongs(person1).

I assume ?- belongs(person1, chat2).
will return true, since the rule alsoBelongs is true for person1 and I logically can derive belongs(P,chat2) is true.

However, Prolog returns false.

Am I missing something? How to express it in Prolog? I see some articles on first order logic but they do not say how to map it into Prolog.

Can you be more specific about what it means. I know some people will be able to make sense of what you said, but it doesn’t make sense for me. In other words use some Rubber Duck debugging.

Also Prolog returning false for belongs(person1, chat2). is what I would expected since since chat2 can not unify with chat1.

I am creating the following world.

  • Any person who belongs to chat 1 also belongs to chat 2.
  • Person 1 belongs to chat 1.

I want to ask the question. Does the person 1 belong to chat 2? And I assume to receive a positive answer.

In my mind a chat can take place between more than one person, so I changed the result to a list which can hold zero or more items to represent the people in the chat. Also the code makes use of findall/3 from Finding all Solutions to a Goal since the data is stored in facts.

Hopefully this gives you a better idea of what to do.

session(chat1,person1).
session(chat1,person2).
session(chat2,person2).
session(chat3,person1).
session(chat3,person3).
session(chat3,person4).

session_users(Session,Users) :-
    findall(Person,session(Session,Person),Users).

Here are some test cases.

:- begin_tests(session).

session_case(1,chat1,[person1, person2]).
session_case(2,chat3,[person1, person3, person4]).
session_case(3,chat4,[]).
session_case(4,chat2,[person2]).

test(session_users,[forall(session_case(_,Session,Users))]) :-
    session_users(Session,Users).

:- end_tests(session).

A demonstration of building the code which also runs the test cases.

?- make.
% c:/users/groot/documents/projects/prolog/swi-discourse_040 compiled 0.05 sec, 8 clauses
% PL-Unit: session .... done
% All 4 tests passed
true.

Enjoy. :slightly_smiling_face:

I am sure you will have some questions so do ask, but don’t expect that I will be the only responding.


EDIT

Expanded with a second predicate to show the sessions a user is in and the added test cases.

session(chat1,person1).
session(chat1,person2).
session(chat2,person2).
session(chat3,person1).
session(chat3,person3).
session(chat3,person4).

session_users(Session,Users) :-
    findall(Person,session(Session,Person),Users).

user_sessions(User,Sessions) :-
    findall(Session,session(Session,User),Sessions).

Test cases.

:- begin_tests(session).

session_user_case(1,chat1,[person1, person2]).
session_user_case(2,chat3,[person1, person3, person4]).
session_user_case(3,chat4,[]).
session_user_case(4,chat2,[person2]).

test(session_users,[forall(session_user_case(_,Session,Users))]) :-
    session_users(Session,Users).

user_sessions_case(1,person1,[chat1, chat3]).
user_sessions_case(2,person2,[chat1, chat2]).
user_sessions_case(3,person3,[chat3]).
user_sessions_case(4,person4,[chat3]).
user_sessions_case(5,person5,[]).

test(user_sessions,[forall(user_sessions_case(_,User,Sessions))]) :-
    user_sessions(User,Sessions).

:- end_tests(session).

Example run.

?- make.
% c:/users/groot/documents/projects/prolog/swi-discourse_040 compiled 0.00 sec, 0 clauses
% PL-Unit: session ......... done
% All 9 tests passed
true.

Thanks, I will dig into your reply. :slight_smile:

Thanks for the example. There, let’s say I know for sure there is a certain rule.

if person is in chat1, the person is also in chat3.

So, when I query, I want Prolog to understand that in the following query, the users are connected because of that rule:

session_users(chat1,[person1, person3]).

even if I did not explicitly specify the association.

I am sure what you are thinking is clear in your mind, but when you say rule and use a fact, e.g.

session_users(chat1,[person1, person3]).

which is a fact because it does not have :-, I can’t figure out what you are implying on need.

Logically, let’s say we have the following facts:

  • For any x: A(X) -> B(X)
  • A(a) = true

It is possible to derive B(a) = true. Is there a way to ask Prolog to derive it?

Others here are better at the deriving this sort of logic but I will give it a shot.

First I take it your -> means that if A(X) is true then B(X) should be added. So I will take that to mean a fact has to be added to the database using assert. Also in Prolog -> (->/2) works as an if and is typically used with ; to work like an if then else statement.

Here is a working example based on that thinking.

Fact

a(a).

Rules (just one).

imply(X) :-
    a(X),
    assert(b(X)).

Example run

?- consult("C:/Users/groot/Documents/Projects/Prolog/swi-discourse_040.pl").
true.

?- listing(b).
ERROR: procedure `b' does not exist (DWIM could not correct goal)
   Call: (15) prolog_listing:close_sources ? abort
% Execution Aborted
?- imply(b).
false.

?- imply(a).
true.

?- listing(b).
:- dynamic b/1.

b(a).

true.

First in Prolog an uppercase is by default a variable so your A becomes a. Then the state starts with the fact a(a) and the rule

imply(X) :-
    a(X),
    assert(b(X)).

Next using listing(b) is run to show that there are not facts or rules starting with b, which is evident by the ERROR.

Running imply(b) the rule is executed with the value b, but because there is no fact a(b) it fails.
Running imply(a) the rule is executed with the value a and because there is a fact a(a) that statement succeeds and the next statement in the rule adds the fact b(a) to the database.

listing(b). is then used to show that the database now has the fact b(a)..

HTH

Thanks a lot! Now it makes sense. I modified the original example that works.

belongs(person1,chat1).
alsoBelongs(P) :- 
   belongs(P,chat1), assert(belongs(P,chat2)).                                 
:- dynamic belongs/2.
?- alsoBelongs(person1).

Then query

belongs(person1, chat2)

returns true.

My mistakes:

  1. -> is not the same as imply, I needed to implement it via , (and) and assert like in your example.
  2. the goal must be set via ?- before anything is derived.
1 Like

I am wondering if what you are seeking is a transitivity property of a relationship.

Here is an example, from the tabling section in the manual:

https://www.swi-prolog.org/pldoc/man?section=tabling-non-termination