# How to use inference in Prolog?

**URL:** <https://swi-prolog.discourse.group/t/how-to-use-inference-in-prolog/2191>\
**Category:** Help!\
**Created:** [April 18, 2020, 11:28pm UTC](https://swi-prolog.discourse.group/t/how-to-use-inference-in-prolog/2191 "2020-04-18T23:28:47Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![nick](https://avatars.discourse-cdn.com/v4/letter/n/f9ae1b/32.png) [@nick](https://swi-prolog.discourse.group/u/nick)\
**Post date:** [April 18, 2020, 11:28pm UTC](https://swi-prolog.discourse.group/t/how-to-use-inference-in-prolog/2191/1 "2020-04-18T23:28:47Z")

</div>

Hi,  
Newbie here.  
Trying to do the following.

```prolog
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.

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [April 18, 2020, 11:40pm UTC](https://swi-prolog.discourse.group/t/how-to-use-inference-in-prolog/2191/2 "2020-04-18T23:40:55Z")

</div>

> [@nick](#):
>
> How to express it in 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](https://en.wikipedia.org/wiki/Rubber_duck_debugging).

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

---

<div class="post-metadata">

**Author:** ![nick](https://avatars.discourse-cdn.com/v4/letter/n/f9ae1b/32.png) [@nick](https://swi-prolog.discourse.group/u/nick)\
**Post date:** [April 18, 2020, 11:44pm UTC](https://swi-prolog.discourse.group/t/how-to-use-inference-in-prolog/2191/3 "2020-04-18T23:44:55Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [April 18, 2020, 11:50pm UTC](https://swi-prolog.discourse.group/t/how-to-use-inference-in-prolog/2191/4 "2020-04-18T23:50:27Z")

</div>

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](https://www.swi-prolog.org/pldoc/man?section=allsolutions) since the data is stored in facts.

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

```prolog
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.

```prolog
:- 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.

```prolog
?- 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. 🙂

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.

```prolog
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.

```prolog
:- 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.

```prolog
?- 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.

```

---

<div class="post-metadata">

**Author:** ![nick](https://avatars.discourse-cdn.com/v4/letter/n/f9ae1b/32.png) [@nick](https://swi-prolog.discourse.group/u/nick)\
**Post date:** [April 19, 2020, 12:07am UTC](https://swi-prolog.discourse.group/t/how-to-use-inference-in-prolog/2191/5 "2020-04-19T00:07:52Z")

</div>

Thanks, I will dig into your reply. 🙂

---

<div class="post-metadata">

**Author:** ![nick](https://avatars.discourse-cdn.com/v4/letter/n/f9ae1b/32.png) [@nick](https://swi-prolog.discourse.group/u/nick)\
**Post date:** [April 19, 2020, 12:19am UTC](https://swi-prolog.discourse.group/t/how-to-use-inference-in-prolog/2191/6 "2020-04-19T00:19:48Z")

</div>

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:

```prolog
session_users(chat1,[person1, person3]).

```

even if I did not explicitly specify the association.

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [April 19, 2020, 12:34am UTC](https://swi-prolog.discourse.group/t/how-to-use-inference-in-prolog/2191/7 "2020-04-19T00:34:36Z")

</div>

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

```prolog
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.

---

<div class="post-metadata">

**Author:** ![nick](https://avatars.discourse-cdn.com/v4/letter/n/f9ae1b/32.png) [@nick](https://swi-prolog.discourse.group/u/nick)\
**Post date:** [April 19, 2020, 12:38am UTC](https://swi-prolog.discourse.group/t/how-to-use-inference-in-prolog/2191/8 "2020-04-19T00:38:16Z")

</div>

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?

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [April 19, 2020, 1:04am UTC](https://swi-prolog.discourse.group/t/how-to-use-inference-in-prolog/2191/9 "2020-04-19T01:04:20Z")

</div>

> [@nick](#):
>
> 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](https://www.swi-prolog.org/pldoc/man?predicate=-%3E/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

```prolog
a(a).

```

Rules (just one).

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

```

Example run

```prolog
?- 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

```prolog
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

---

<div class="post-metadata">

**Author:** ![nick](https://avatars.discourse-cdn.com/v4/letter/n/f9ae1b/32.png) [@nick](https://swi-prolog.discourse.group/u/nick)\
**Post date:** [April 19, 2020, 1:50am UTC](https://swi-prolog.discourse.group/t/how-to-use-inference-in-prolog/2191/10 "2020-04-19T01:50:19Z")

</div>

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

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

```

Then query

```prolog
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.

---

<div class="post-metadata">

**Author:** ![grossdan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/grossdan/32/23_2.png) [@grossdan](https://swi-prolog.discourse.group/u/grossdan)\
**Post date:** [April 19, 2020, 4:21am UTC](https://swi-prolog.discourse.group/t/how-to-use-inference-in-prolog/2191/11 "2020-04-19T04:21:02Z")

</div>

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](https://www.swi-prolog.org/pldoc/man?section=tabling-non-termination)
