# Creating pairs of variables from a clause

**URL:** <https://swi-prolog.discourse.group/t/creating-pairs-of-variables-from-a-clause/6085>\
**Category:** Help!\
**Created:** [January 11, 2023, 3:50pm UTC](https://swi-prolog.discourse.group/t/creating-pairs-of-variables-from-a-clause/6085 "2023-01-11T15:50:39Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![JCR](https://avatars.discourse-cdn.com/v4/letter/j/258eb7/32.png) [@JCR](https://swi-prolog.discourse.group/u/JCR)\
**Post date:** [January 11, 2023, 3:50pm UTC](https://swi-prolog.discourse.group/t/creating-pairs-of-variables-from-a-clause/6085/1 "2023-01-11T15:50:39Z")

</div>

Hi!

I am trying to create pairs of variables from a list of literals that contain unbound variables (`ClauseLiterals` below): I want to create pairs that combine all the variables in each literal with all the variables in the other literals. See the program at the bottom of this post.

Running `test1` yields the behavior I was expecting:

```prolog
?- test1.
[h(_15806,_15808),p(_15818,_15820),q(_15830,_15832,_15834)]
_15806,_15818
_15806,_15820
_15808,_15818
_15808,_15820
_15806,_15830
_15806,_15832
_15806,_15834
_15808,_15830
_15808,_15832
_15808,_15834
_15818,_15830
_15818,_15832
_15818,_15834
_15820,_15830
_15820,_15832
_15820,_15834
false.

```

But running `test2`, which I want to use in my real program, yields this:

```prolog
?- test2.
[h(_17660,_17662),p(_17672,_17674),q(_17684,_17686,_17688)]
_28,_32
_28,_34
_30,_32
_30,_34
_28,_36
_28,_38
_28,_40
_30,_36
_30,_38
_30,_40
_32,_36
_32,_38
_32,_40
_34,_36
_34,_38
_34,_40
true.

```

Why are new variables seemingly introduced? I.e. `_34`, `_40`, and so on?

Thanks in advance!

Cheers/JCR

```prolog
test1:- 
    ClauseLiterals = [h(A, B), p(C, D), q(E, F, G)],
    writeln(ClauseLiterals),
    variablePairForClause(ClauseLiterals, Pair),
    writeln(Pair),
    fail.

test2:-
    ClauseLiterals = [h(A, B), p(C, D), q(E, F, G)],
    writeln(ClauseLiterals),
    bagof(Pair, variablePairForClause(ClauseLiterals, Pair), Pairs),
    maplist(writeln, Pairs).

variablePairForClause(ClauseLiterals, Pair):-
    length(ClauseLiterals, NLiterals),
    between(1, NLiterals, Index1),
    StartIndex2 is Index1 + 1,
    between(StartIndex2, NLiterals, Index2),
    nth1(Index1, ClauseLiterals, Literal1),
    nth1(Index2, ClauseLiterals, Literal2),
    term_variables(Literal1, Literal1Vars),
    term_variables(Literal2, Literal2Vars),
    member(P1, Literal1Vars),
    member(P2, Literal2Vars),
    Pair = (P1, P2).

```

---

<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:** [January 11, 2023, 4:05pm UTC](https://swi-prolog.discourse.group/t/creating-pairs-of-variables-from-a-clause/6085/2 "2023-01-11T16:05:08Z")

</div>

> [@JCR](#):
>
> Why are new variables seemingly introduced?

Quick guess without testing.

You did not use the existential (caret) `^` operator with bagof/3. Off the top of my head I have never tried something like you seek and don’t know how/if it can be done.

---

<div class="post-metadata">

**Author:** ![JCR](https://avatars.discourse-cdn.com/v4/letter/j/258eb7/32.png) [@JCR](https://swi-prolog.discourse.group/u/JCR)\
**Post date:** [January 11, 2023, 4:52pm UTC](https://swi-prolog.discourse.group/t/creating-pairs-of-variables-from-a-clause/6085/3 "2023-01-11T16:52:47Z")

</div>

Thanks @EricGT. I tried the caret but that did not seem to work…  
Cheers/JCR

---

<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:** [January 11, 2023, 5:00pm UTC](https://swi-prolog.discourse.group/t/creating-pairs-of-variables-from-a-clause/6085/4 "2023-01-11T17:00:52Z")

</div>

> [@JCR](#):
>
> that did not seem to work…

Sorry, 🙁 I did not mean that you should try using the existential operator `^` as your result is all variables and the existential operator excludes variables (if that is the right wording) and thus why I noted `I have never tried something like you seek and don’t know how/if it can be done.`

I have not looked at what you are trying to do in detail to offer anything new at the moment.

---

<div class="post-metadata">

**Author:** ![CapelliC](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/capellic/32/17_2.png) [@CapelliC](https://swi-prolog.discourse.group/u/CapelliC)\
**Post date:** [January 11, 2023, 5:49pm UTC](https://swi-prolog.discourse.group/t/creating-pairs-of-variables-from-a-clause/6085/5 "2023-01-11T17:49:54Z")

</div>

I cannot observe the behaviour you reported:

```prolog
?- test2.
[h(_11830,_11832),p(_11842,_11844),q(_11854,_11856,_11858)]
_11830,_11842
_11830,_11844
_11832,_11842
_11832,_11844
_11830,_11854
_11830,_11856
_11830,_11858
_11832,_11854
_11832,_11856
_11832,_11858
_11842,_11854
_11842,_11856
_11842,_11858
_11844,_11854
_11844,_11856
_11844,_11858
true.

```

so, I think it could derive from garbage collection.

---

<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:** [January 11, 2023, 5:56pm UTC](https://swi-prolog.discourse.group/t/creating-pairs-of-variables-from-a-clause/6085/6 "2023-01-11T17:56:15Z")

</div>

> [@CapelliC](#):
>
> I cannot observe the behaviour you reported:

To second what CapelliC noted, I too get a correct result.

```prolog
?- test2.
[h(_15956,_15958),p(_15968,_15970),q(_15980,_15982,_15984)]
_15956,_15968
_15956,_15970
_15958,_15968
_15958,_15970
_15956,_15980
_15956,_15982
_15956,_15984
_15958,_15980
_15958,_15982
_15958,_15984
_15968,_15980
_15968,_15982
_15968,_15984
_15970,_15980
_15970,_15982
_15970,_15984
true.

```

---

<div class="post-metadata">

**Author:** ![JCR](https://avatars.discourse-cdn.com/v4/letter/j/258eb7/32.png) [@JCR](https://swi-prolog.discourse.group/u/JCR)\
**Post date:** [January 11, 2023, 6:00pm UTC](https://swi-prolog.discourse.group/t/creating-pairs-of-variables-from-a-clause/6085/7 "2023-01-11T18:00:26Z")

</div>

Aha, that’s interesting. Just to be sure I ran my queries again. Still get the same results as I got before. I’ll try to see what happens when integrate the predicate in my real program 🙃

---

<div class="post-metadata">

**Author:** ![CapelliC](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/capellic/32/17_2.png) [@CapelliC](https://swi-prolog.discourse.group/u/CapelliC)\
**Post date:** [January 11, 2023, 6:10pm UTC](https://swi-prolog.discourse.group/t/creating-pairs-of-variables-from-a-clause/6085/8 "2023-01-11T18:10:06Z")

</div>

In the past, [I used to think](https://stackoverflow.com/a/38181628/874024) that bagof/3 **not** copies terms from the template into output, and also used such feature solving a CLP(FD) puzzle, but then I got corrected by (iirc) [@false](https://stackoverflow.com/users/772868/false), and Jan as well, so I’m not sure anymore…

---

<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:** [January 11, 2023, 6:16pm UTC](https://swi-prolog.discourse.group/t/creating-pairs-of-variables-from-a-clause/6085/9 "2023-01-11T18:16:12Z")

</div>

Here is a slight variation that uses numbervars/1.

```prolog
test2a:-
    ClauseLiterals = [h(A, B), p(C, D), q(E, F, G)],
    bagof(Pair, variablePairForClause(ClauseLiterals, Pair), Pairs),
    numbervars(ClauseLiterals),
    writeln(ClauseLiterals),
    maplist(writeln, Pairs).

```

```prolog
?- test2a.
[h(A,B),p(C,D),q(E,F,G)]
A,C
A,D
B,C
B,D
A,E
A,F
A,G
B,E
B,F
B,G
C,E
C,F
C,G
D,E
D,F
D,G
true.

```

AFAIK the printing of the variables has to come after numbervars/1 and the use of numbervars/1 has to come after using the variables thus the change in order of some of the statements.

@JCR thanks for this puzzle. I did not know that bagof/3 has a valid use case with all variables and without the existential operator (`^/2`) and thanks to @CapelliC for showing a correct result.

---

<div class="post-metadata">

**Author:** ![JCR](https://avatars.discourse-cdn.com/v4/letter/j/258eb7/32.png) [@JCR](https://swi-prolog.discourse.group/u/JCR)\
**Post date:** [January 11, 2023, 6:21pm UTC](https://swi-prolog.discourse.group/t/creating-pairs-of-variables-from-a-clause/6085/10 "2023-01-11T18:21:30Z")

</div>

Cool! That seems promising 🙂

---

<div class="post-metadata">

**Author:** ![CapelliC](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/capellic/32/17_2.png) [@CapelliC](https://swi-prolog.discourse.group/u/CapelliC)\
**Post date:** [January 11, 2023, 6:21pm UTC](https://swi-prolog.discourse.group/t/creating-pairs-of-variables-from-a-clause/6085/11 "2023-01-11T18:21:32Z")

</div>

> [@EricGT](#):
>
> `numbervars(ClauseLiterals)`

so clever !

---

<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:** [January 11, 2023, 6:24pm UTC](https://swi-prolog.discourse.group/t/creating-pairs-of-variables-from-a-clause/6085/12 "2023-01-11T18:24:24Z")

</div>

> [@CapelliC](#):
>
> so clever !

I can not take any credit for it. Thanks go to those that created it and to Jan W. for using it in the SWI-Prolog code which I look at often for examples. I also had to re-read my [post](https://swi-prolog.discourse.group/search?q=numbervars%20%40EricGT) that used numbervars/N to figure it out.

---

<div class="post-metadata">

**Author:** ![JCR](https://avatars.discourse-cdn.com/v4/letter/j/258eb7/32.png) [@JCR](https://swi-prolog.discourse.group/u/JCR)\
**Post date:** [January 11, 2023, 6:46pm UTC](https://swi-prolog.discourse.group/t/creating-pairs-of-variables-from-a-clause/6085/13 "2023-01-11T18:46:17Z")

</div>

With your test2a @EricGT I get the same (correct) results as you.

---

<div class="post-metadata">

**Author:** ![CapelliC](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/capellic/32/17_2.png) [@CapelliC](https://swi-prolog.discourse.group/u/CapelliC)\
**Post date:** [January 11, 2023, 7:02pm UTC](https://swi-prolog.discourse.group/t/creating-pairs-of-variables-from-a-clause/6085/14 "2023-01-11T19:02:50Z")

</div>

So, seems like your initial problem does not highlight a _problem_ ? To clarify: differently ‘named’ variables in setof/3 output still **share** with those from `ClauseLiterals` ? A little experiment could be to assign to `A` before `maplist(writeln, Pairs)` and also move there `writeln(ClauseLiterals)`

---

<div class="post-metadata">

**Author:** ![JCR](https://avatars.discourse-cdn.com/v4/letter/j/258eb7/32.png) [@JCR](https://swi-prolog.discourse.group/u/JCR)\
**Post date:** [January 11, 2023, 9:56pm UTC](https://swi-prolog.discourse.group/t/creating-pairs-of-variables-from-a-clause/6085/15 "2023-01-11T21:56:12Z")

</div>

> [@CapelliC](#):
>
> So, seems like your initial problem does not highlight a _problem_ ? To clarify: differently ‘named’ variables in [setof/3](https://www.swi-prolog.org/pldoc/doc_for?object=setof/3) output still **share** with those from `ClauseLiterals` ?

To me it is really confusing why the results in the output from test1 and test2 differ and that the variables e.g. `_17660` do not correspond to the variables e.g. `_28`.

I tried as you suggested to play around by putting writeln/1 in different places as shown in `test2` and `test2b` in PROGRAM below (I did not understand what you meant by “A little experiment could be to assign to `A` before `maplist(writeln, Pairs)`”; what is A?). Now I am even more confused: The output changes depending on _in which order_ I query `?-test2` and `?-test2b` 🙃. See OUTPUT1 and OUTPUT2. What is happening?

PROGRAM:

```prolog
test2:-
    ClauseLiterals = [h(A, B), p(C, D), q(E, F, G)],
    writeln(ClauseLiterals),
    bagof(Pair, variablePairForClause(ClauseLiterals, Pair), Pairs),
    maplist(writeln, Pairs).

test2b:-
    ClauseLiterals = [h(A, B), p(C, D), q(E, F, G)],
    bagof(Pair, variablePairForClause(ClauseLiterals, Pair), Pairs),
    writeln(ClauseLiterals),
    maplist(writeln, Pairs).

variablePairForClause(ClauseLiterals, Pair):-
    length(ClauseLiterals, NLiterals),
    between(1, NLiterals, Index1),
    StartIndex2 is Index1 + 1,
    between(StartIndex2, NLiterals, Index2),
    nth1(Index1, ClauseLiterals, Literal1),
    nth1(Index2, ClauseLiterals, Literal2),
    term_variables(Literal1, Literal1Vars),
    term_variables(Literal2, Literal2Vars),
    member(P1, Literal1Vars),
    member(P2, Literal2Vars),
    Pair = (P1, P2).

```

OUTPUT 1:

```prolog
?- test2.
[h(_17376,_17378),p(_17388,_17390),q(_17400,_17402,_17404)]
_28,_32
_28,_34
_30,_32
_30,_34
_28,_36
_28,_38
_28,_40
_30,_36
_30,_38
_30,_40
_32,_36
_32,_38
_32,_40
_34,_36
_34,_38
_34,_40
true.

?- test2b.
[h(_2858,_2860),p(_2870,_2872),q(_2882,_2884,_2886)]
_2858,_2870
_2858,_2872
_2860,_2870
_2860,_2872
_2858,_2882
_2858,_2884
_2858,_2886
_2860,_2882
_2860,_2884
_2860,_2886
_2870,_2882
_2870,_2884
_2870,_2886
_2872,_2882
_2872,_2884
_2872,_2886
true.

```

…here I quit swipl and restarted it…

OUTPUT2:

```prolog
?- test2b.
[h(_17378,_17380),p(_17390,_17392),q(_17402,_17404,_17406)]
_28,_32
_28,_34
_30,_32
_30,_34
_28,_36
_28,_38
_28,_40
_30,_36
_30,_38
_30,_40
_32,_36
_32,_38
_32,_40
_34,_36
_34,_38
_34,_40
true.

?- test2.
[h(_2856,_2858),p(_2868,_2870),q(_2880,_2882,_2884)]
_2856,_2868
_2856,_2870
_2858,_2868
_2858,_2870
_2856,_2880
_2856,_2882
_2856,_2884
_2858,_2880
_2858,_2882
_2858,_2884
_2868,_2880
_2868,_2882
_2868,_2884
_2870,_2880
_2870,_2882
_2870,_2884
true.

```

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [January 12, 2023, 9:03am UTC](https://swi-prolog.discourse.group/t/creating-pairs-of-variables-from-a-clause/6085/16 "2023-01-12T09:03:31Z")

</div>

I’m afraid I have no time to read all the details, but one should be aware that calling write/1 twice on the same variable may not print the same value. This is because the print output are stack offsets and GC changes these. There is not a good way around that. For this type of exploration you may consider

```
 ?- set_prolog_flag(gc, false).

```

to disable garbage collection. Be careful, you easily run out of memory.

As is, variables appearing in a term that is printed as a whole are consistent, **unless** portray hooks are used. Printing a term reliably is pretty hard. The toplevel uses copy\_term/3 to move the constraints out, if the term is cyclic it factorizes the cycles. Next it uses numbervars/4 with the `singletons(true)` argument and finally prints using portray and numbervars options.

---

<div class="post-metadata">

**Author:** ![JCR](https://avatars.discourse-cdn.com/v4/letter/j/258eb7/32.png) [@JCR](https://swi-prolog.discourse.group/u/JCR)\
**Post date:** [January 12, 2023, 7:40pm UTC](https://swi-prolog.discourse.group/t/creating-pairs-of-variables-from-a-clause/6085/17 "2023-01-12T19:40:14Z")

</div>

Thanks @jan; this info helps!
