プログラミングなどなど

プログラミングに関係しそうな内容を

Prolog:1〜9の2つの整数で和が10になる組み合わせを求める

gprologのマニュアルを見ていると「9 Finite domain solver and built-in predicates」という章がありました。「9.1 introduction」にも「constraint solver」という記述があるので、何らかの制約問題を解いてくれるのかと思い試して見ました。

簡単そうなサンプルとして、以下のような問題を考えてみました。

  • A,B が1〜9の範囲の整数をとる。
  • A+Bが10となる組み合わせを考える。
  • A>=Bとする。

gplorgの起動

$ gprolog
GNU Prolog 1.4.5 (64 bits)
Compiled Mar 17 2020, 23:55:22 with gcc
By Daniel Diaz
Copyright (C) 1999-2020 Daniel Diaz
| ?- 

1〜9の範囲のA,Bを用意

| ?- fd_domain([A,B],1,9).

A = _#0(1..9)
B = _#17(1..9)

yes

それぞれに値を代入してみる

| ?- fd_domain([A,B],1,9), fd_labeling([A,B]).

A = 1
B = 1 ? ;

A = 1
B = 2 ? ;

A = 1
B = 3 ? 

yes

組み合わせがどんどん出てきます。上記の例では止めていますが、A=9,B=9の組み合わせまで出てきます。

A+Bが10となる制約

| ?- fd_domain([A,B],1,9), A + B #= 10, fd_labeling([A,B]).

A = 1
B = 9 ? a

A = 2
B = 8

A = 3
B = 7

A = 4
B = 6

A = 5
B = 5

A = 6
B = 4

A = 7
B = 3

A = 8
B = 2

A = 9
B = 1

(1 ms) yes

A + B = 10 となる組み合わせが出てきますが、3+7=10, 7+3=10 のような組み合わせを省くため、大小関係の制約を追加します。

大小関係の制約 A >= Bの追加

| ?- fd_domain([A,B],1,9), A + B #= 10, A #>= B, fd_labeling([A,B]).

A = 5
B = 5 ? ;

A = 6
B = 4 ? ;

A = 7
B = 3 ? ;

A = 8
B = 2 ? ;

A = 9
B = 1

(1 ms) yes