# What's with subset/2?

**URL:** <https://swi-prolog.discourse.group/t/whats-with-subset-2/4454>\
**Category:** Help!\
**Created:** [September 16, 2021, 6:17pm UTC](https://swi-prolog.discourse.group/t/whats-with-subset-2/4454 "2021-09-16T18:17:13Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Drakken](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/drakken/32/3732_2.png) [@Drakken](https://swi-prolog.discourse.group/u/Drakken)\
**Post date:** [September 16, 2021, 6:17pm UTC](https://swi-prolog.discourse.group/t/whats-with-subset-2/4454/1 "2021-09-16T18:17:13Z")

</div>

I’m using: SWI-Prolog version SWISH

I want the code to: find bindings for subsets

But what I’m getting is: only one set of bindings, and it’s not even a set

My code looks like this:

```prolog
?- subset([A,B],[1,2,3]).
A = B, B = 1

```

No buttons in the results window to try more bindings.  
I would expect [1,2], [1,3], etc.

```prolog
?- trace,subset([A,B],[1,2,3]).
Call:lists:subset([_4884, _4888], [1, 2, 3])
 Exit:lists:subset([1, 1], [1, 2, 3])
A = B, B = 1

```

---

<div class="post-metadata">

**Author:** ![dmchurch](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/dmchurch/32/3427_2.png) [@dmchurch](https://swi-prolog.discourse.group/u/dmchurch)\
**Post date:** [September 16, 2021, 7:04pm UTC](https://swi-prolog.discourse.group/t/whats-with-subset-2/4454/2 "2021-09-16T19:04:20Z")

</div>

So, the reason you’re not getting the results you’re hoping for is that, by the docs, subset/2 (and its cousin, ord\_subset/2) only operates in the `(+, +)` mode, i.e. with both parameters as inputs. Generation shouldn’t be too tough, though:

```prolog
any_subset([], []).
any_subset([H|T], Subset) :-
    any_subset(T, Subset)
    ;
    Subset = [H|Sub1],
    any_subset(T, Sub1).

```

(I swapped the order of the parameters, but only because of a SWI-Prolog-specific optimization. That’s also why this predicate has two clauses, not three.)

---

<div class="post-metadata">

**Author:** ![Drakken](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/drakken/32/3732_2.png) [@Drakken](https://swi-prolog.discourse.group/u/Drakken)\
**Post date:** [September 16, 2021, 7:33pm UTC](https://swi-prolog.discourse.group/t/whats-with-subset-2/4454/3 "2021-09-16T19:33:32Z")

</div>

I was wondering what those doohickies were. Thank you. 😃

How about this:

```prolog
is_subset([],_).
is_subset([H|T],Set) :-
  member(H,Set),
  delete(Set,H,Remainder),
  is_subset(T,Remainder).

```

Or with select(H,Set,Remainder) instead of delete(Set,H,Remainder).

---

<div class="post-metadata">

**Author:** ![dmchurch](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/dmchurch/32/3427_2.png) [@dmchurch](https://swi-prolog.discourse.group/u/dmchurch)\
**Post date:** [September 16, 2021, 8:53pm UTC](https://swi-prolog.discourse.group/t/whats-with-subset-2/4454/4 "2021-09-16T20:53:51Z")

</div>

That’s a decent way to do it if you’re looking for all _permutations_, rather than _combinations_, yes! You’re correct that select/3 is a better predicate to use than delete/3 (I actually had to look up delete/3 in the docs, because it’s not a commonly-used predicate), but I’ll take it one step further: you can replace _both_ the calls to member/2 and delete/2 with a single call to `select(H, Set, Remainder)`. Notice that the docs for select/3 specifies the mode as `(?, ?, ?)` - that’s the ideal for a Prolog predicate, actually, as it specifies that _any_ of the arguments can be used as input or output.

Incidentally, that’s also the reason why most predicate documentation is phrased with the almost Jeopardy-esque “Is true when…” preface rather than using imperative language like “Removes Elem from List1”, even when that requires jumping through some grammatical hoops. In Prolog, you ideally aren’t specifying the _process_ so much as the _solution_. (Of course, realistically that’s not always the case, but the ideal still holds.)

I’ll offer you another solution, though - not because I think it’s _better_ so much as it’s just fun:

```prolog
is_subset(Subset, Set) :-
    permutation(Set, Perm),
    prefix(Subset, Perm).

```

---

<div class="post-metadata">

**Author:** ![Boris](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/boris/32/7486_2.png) [@Boris](https://swi-prolog.discourse.group/u/Boris)\
**Post date:** [September 17, 2021, 7:24am UTC](https://swi-prolog.discourse.group/t/whats-with-subset-2/4454/5 "2021-09-17T07:24:01Z")

</div>

I think that this has been already discussed [here](https://swi-prolog.discourse.group/t/why-doesnt-ord-subset-generate-subsets/3682/9) in the context of ord\_subset/2. As long as you represent the set as list, the same considerations apply. For any list without repetitions the set of subsequences of the list is the same as the set of subsets. The gist of it (excerpt from the linked post):

```prolog
list_subseq_1([], _).
list_subseq_1([X|Xs], L) :-
    append(_, [X|Rest], L),
    list_subseq_1(Xs, Rest).

```

So, for a subsequence you can use append/3, instead of member/2 and select/3 or delete/3 and so on.

For your example, I get:

```prolog
?- list_subseq([1,2,3], [A,B]).
A = 1, B = 2 ;
A = 1, B = 3 ;
A = 2, B = 3 ;
false.

```

---

<div class="post-metadata">

**Author:** ![Drakken](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/drakken/32/3732_2.png) [@Drakken](https://swi-prolog.discourse.group/u/Drakken)\
**Post date:** [September 17, 2021, 5:22pm UTC](https://swi-prolog.discourse.group/t/whats-with-subset-2/4454/6 "2021-09-17T17:22:55Z")

</div>

That’s awesome. It’s amazing how sneaky you can be with Prolog. 😁 😁 😁
