初学者向けCHRの使い方まとめ
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
|
ログイン
]
開始行:
#norelated
*本ページ作成の目的 [#ld707f1e]
上田研究室言語班ではLMNtal言語を主に研究対象としているが...
宣言型プログラミング言語Constraint Handling Rules(CHR)も...
しかし2018/08/07現在、CHRにはほとんど日本語の資料が存在し...
故に英語での読解を苦手とする学生には学ぶためのハードルが...
そこでここに日本語で表記法を示し、日本語話者である初学者...
*目次 [#r7bf5d07]
#contents
*CHRとは [#tbb9c0ec]
CHRことConstraint Handling Rulesとは、論理プログラミング...
*CHRの特徴 [#e25f7c56]
CHRは理論と実践、論理的な書き方と処理可能なコードのギャッ...
CHR自体も言語としての機能を備えているのだが、実際にはProl...
*CHRの起動手続き [#hfacf408]
CHRの実行時にはホスト言語においてCHRを使う宣言などのため...
Prologの場合、前書きは例えば以下に記述するような三行でな...
:- module(weather, [rain/0]).
:- use_module(library(chr)).
:- chr_constraint rain/0, wet/0, umbrella/0.
これはrain,wet,umbrellaという、引数が0個の制約3つを導入す...
一行目はPrologのモジュール宣言で、CHRプログラムをweather...
このように書いた場合、モジュールは指定した制約 rain/0 し...
c/nというfunctorの宣言はc(t_1,t_2...,t_n)という制約の名前...
二行目は実際のCHRプログラムが読み込まれる前にCHRライブラ...
三行目は実際に使用される前に制約を宣言している場所である...
最低でも名前と、引数の数だけは与えられなくてはならないが...
*CHRの記法 [#nd267f5a]
まずCHRのコードを分解すると、制約とルールで書かれている。
制約は名前と引数という二つの要素を持ち、C言語でいう関数呼...
name(arg1,arg2,...)
これは実行時の入力に書くことも、コードに書いておくことも...
ルールには
単純化規則
伝播規則
単純化伝播規則
の三種類があるが、いずれもネーム、ヘッド、ガード、ボディ...
単純化規則
name @ head <=> guard | body.
伝播規則
name @ head ==> guard | body.
単純化伝播規則
name @ head1 \ head2 <=> guard | body.
このうち、 name @ と guard | は省略が可能である。
それぞれの規則の動作についてはCHRの動作の項に記述する。
なお変数をルール中で記述したい場合は、大文字で始まる名前...
名前のない変数を記述したい場合は、アンダーバー( _ ) を名...
*CHRの動作 [#w9fb12a3]
CHRが扱う制約は原子論理式(それを構成する部分論理式がない...
前述のルールの動作は以下の通りである。
単純化規則
guard部に記述した条件が満たされているとき、head部に対応...
基本的な問題では、等価でより単純な制約に書き換える時に使...
伝播規則
guard部に記述した条件が満たされており、head部に対応する...
このルールは同じ制約群をhead部としては一度しか発火しない。
基本的な問題では制約としては冗長であっても、より単純な制...
単純化伝播規則
guard部に記述した条件が満たされており、head部に対応する...
他の二つの規則の組み合わせである。
用意されたルールが一つも発火しない状態になると(親言語であ...
以下、CHRの例題を挙げてその動作を解説する。
**例題1 基本的な問題[#u84c4bc4]
制約
A leq B, B leq C, C leq A
ルール
reflexivity @ X leq X <=> true.
antisymmetry @ X leq Y, Y leq X <=> X = Y.
transitivity @ X leq Y, Y leq Z ==> X leq Z.
idempotence @ X leq Y \ X leq Y <=> true.
この問題において、制約leq/2は引数1が引数2以下であることを...
この問題の出力は以下のようになる。
出力
A = B,
A = C.
何故このような結果になったのか、順を追って説明する。
まず、ルールtransitivityが
A leq B, B leq C
をhead部として発火し、制約群は以下のように変化する。
A leq B, B leq C, C leq A, A leq C.
ここでルールantisymmetryが
A leq C, C leq A
をhead部として発火し、制約群が以下のように変化する。
A leq B, B leq C, A = C.
このとき、C = A によって制約 B leq C は B leq A と等価に...
A leq B, B leq A, A = C.
従ってここでルールantisymmetryが
A leq B, B leq C (= A leq B, B leq A)
をhead部として発火し、制約群が以下のように変化する。
A = B, A = C.
これ以上発火するルールがないためここで処理は終了し、残っ...
**例題2 ナップサック問題 [#oe963284]
CHRは前述の通り様々な言語の拡張機能として提供されているわ...
以下はナップサック問題と呼ばれる問題を解くためのSWI-Prolo...
:- use_module(library(chr)).
:- chr_option(optimize,off).
:- chr_constraint knapsack/1, labelk/0, wlimit/1, ptotal...
% make domains for variables
item(V,W) <=> in(item(V,W,count(0)),[0,1]).
% generate auxiliary constraints etc.
knapsack(WL) <=> retractall(memlistitems(X)), retractall...
asserta(memtotalv(0)), wlimit(WL), ptotalw(0), ptotal...
% if an item can't be added to the set, constrain its do...
wlimit(WL), ptotalw(TW) \ in(item(V,W, count(0)),[0,1]) ...
% if an item is labeled to be added to the set, update t...
wlimit(WL) \ in(item(V,W,count(0)),[1]), ptotalw(TW) <=>...
ptotalw(TW2), in(item(V,W,count(1)),[1]).
% labeling
labelk \ in(item(V,W,count(0)), [0,1]) <=> member(P,[0,1...
% calculating total value of the solution
in(item(V,W,count(1)),[1]), ptotalv(TV) <=> TV2 is TV+V,...
% listing items included in the solution
in(item(V,W,count(2)),D), listitems(L) <=> in(item(V,W,c...
% if the current solution has a value greater than the p...
% (and the corresponding set), print intermediate result...
labelmem \ listitems(L), ptotalv(TV) <=>
memtotalv(TV1), TV > TV1, memlistitems(L1) |
retract(memtotalv(TV1)), asserta(memtotalv(TV)), ...
print('best set '), print(L), nl,
print('with value '), print(TV), nl, nl,
fail.
% ...otherwise just backtrack
labelmem \ ptotalv(TV) <=> memtotalv(TV1), TV =< TV1 | f...
ナップサック問題とは価値と重さを持ついくつかの物品から、...
ここで、このプログラムの以下の部分に注目してほしい。
% labeling
labelk \ in(item(V,W,count(0)), [0,1]) <=> member(P,[0,1...
この中に出てくる P という変数について説明する。
SWI-Prologの動作の話になるのだが、SWI-Prologはこのように...
今回はmember/2という関数(SWI-Prologでは述語と呼ぶ)が親言...
よって、in/2制約の第二引数のリストにはひとまず0が代入され...
しかし実行を続けると、このプログラムは必ずfail/0が返るよ...
CHRにバックトラックの機能はなく、以上のように親言語から提...
具体的には以下のような動作をすることになる。
入力例
item(1,1), item(1,2), item(2,4), item(3,4), item(4,3), k...
まず、一番上と、上から二番目のルールによって入力された制...
in(item(1,1,count(0)),[0,1]),
in(item(1,2,count(0)),[0,1]),
in(item(2,4,count(0)),[0,1]),
in(item(3,4,count(0)),[0,1]),
in(item(4,3,count(0)),[0,1]),
retractall(memlistitems(X)), retractall(memtotalv(X)), a...
asserta(memtotalv(0)), wlimit(10), ptotalw(0), ptotal...
memlistitemsやmemtotalvの引数Xは前述の通り変数で、解が見...
三番目のルールは今のところ、ptotalvの引数と重さを足してwl...
in(item(1,1,count(0)),[0]),
in(item(1,2,count(0)),[0]),
in(item(2,4,count(0)),[0]),
in(item(3,4,count(0)),[0]),
in(item(4,3,count(0)),[0]),
retractall(memlistitems(X)), retractall(memtotalv(X)), a...
asserta(memtotalv(0)), wlimit(10), ptotalw(0), ptotal...
六番目のルールは第二引数が[1]のin/2制約に対応しており、七...
八番目のルールはTV1にasserta(memtotalv(0))となっていたの...
結局、九番目のルールにマッチングして、failが返る。
制約には順番がないため、連続して選ばれたmember/2の解はど...
in(item(1,1,count(0)),[1]),
in(item(1,2,count(0)),[0,1]),
in(item(2,4,count(0)),[0,1]),
in(item(3,4,count(0)),[0,1]),
in(item(4,3,count(0)),[0,1]),
retractall(memlistitems(X)), retractall(memtotalv(X)), a...
asserta(memtotalv(0)), wlimit(10), ptotalw(0), ptotal...
三番目のルールは今回も発火しないため、解の候補は以下のよ...
in(item(1,1,count(0)),[1]),
in(item(1,2,count(0)),[0]),
in(item(2,4,count(0)),[0]),
in(item(3,4,count(0)),[0]),
in(item(4,3,count(0)),[0]),
retractall(memlistitems(X)), retractall(memtotalv(X)), a...
asserta(memtotalv(0)), wlimit(10), ptotalw(0), ptotal...
今度は四番目のルールが発火し、重さ1のアイテムがナップサッ...
in(item(1,1,count(1)),[1]),
in(item(1,2,count(0)),[0]),
in(item(2,4,count(0)),[0]),
in(item(3,4,count(0)),[0]),
in(item(4,3,count(0)),[0]),
retractall(memlistitems(X)), retractall(memtotalv(X)), a...
asserta(memtotalv(0)), wlimit(10), ptotalw(1), ptotal...
続けて六番目のルールが発火し、ナップサック内の価値が1にな...
in(item(1,1,count(2)),[1]),
in(item(1,2,count(0)),[0]),
in(item(2,4,count(0)),[0]),
in(item(3,4,count(0)),[0]),
in(item(4,3,count(0)),[0]),
retractall(memlistitems(X)), retractall(memtotalv(X)), a...
asserta(memtotalv(0)), wlimit(10), ptotalw(1), ptotal...
もう入れることになっているアイテムがないので、この解を保...
七番目のルールが発火し、listitems内のリストの頭にitemが挿...
in(item(1,1,count(3)),[1]),
in(item(1,2,count(0)),[0]),
in(item(2,4,count(0)),[0]),
in(item(3,4,count(0)),[0]),
in(item(4,3,count(0)),[0]),
retractall(memlistitems(X)), retractall(memtotalv(X)), a...
asserta(memtotalv(0)), wlimit(10), ptotalw(1), ptotal...
memtotalvの引数をptotalvの引数が上回っているので、八番目...
結果、memtotalvの引数はptotalvの引数に上書きされ、asserta...
そしてこれも親言語の機能であるprintによって今回ナップサッ...
これを繰り返して最高総価値は更新され続け、そのたびに物品...
in(item(1,1,count(0)),[0]),
in(item(1,2,count(0)),[1]),
in(item(2,4,count(0)),[0]),
in(item(3,4,count(0)),[0]),
in(item(4,3,count(0)),[0]).
は総価値がすでに出た1を上回らないのでリストの更新は起きず、
in(item(1,1,count(0)),[1]),
in(item(1,2,count(0)),[1]),
in(item(2,4,count(0)),[0]),
in(item(3,4,count(0)),[0]),
in(item(4,3,count(0)),[0]).
では最高総価値が2に更新されて組み合わせと総価値が出力され...
その次は
in(item(1,1,count(0)),[1]),
in(item(1,2,count(0)),[0]),
in(item(2,4,count(0)),[1]),
in(item(3,4,count(0)),[0]),
in(item(4,3,count(0)),[0]).
で最高総価値が3に更新される、という動きを辿っていくが、me...
in(item(1,1,count(0)),[1]),
in(item(1,2,count(0)),[1]),
in(item(2,4,count(0)),[1]),
in(item(3,4,count(0)),[0,1]),
in(item(4,3,count(0)),[0,1]).
のように、次の解を1にするとナップサックの最大容量を超える...
最終的にすべての組み合わせを調べ終え、そのどれもfail/0が...
**例題3 ユークリッドの互除法 [#c0d008a6]
応用として、制約と全く関係ない問題も場合によっては解くこ...
2つの自然数の最大公約数を求める問題は以下のように記述され...
制約
gcd(A), gcd(B).
※処理系にかけるときはA,Bを任意の自然数にすること
ルール
cleanup @ gcd(0) <=> true.
gcd(N) \ gcd(M) <=> 0<N, N=<M | L is M mod N, gcd(L).
*Constraint Solver [#nd409582]
CHRの主な利用法として、Constraint Solverの作成が上げられ...
これは与えられた制約群を満たす解が存在するかを確かめるア...
⇒ [[./Constraint_Solver]]
*用語解説 [#z60811ef]
終了行:
#norelated
*本ページ作成の目的 [#ld707f1e]
上田研究室言語班ではLMNtal言語を主に研究対象としているが...
宣言型プログラミング言語Constraint Handling Rules(CHR)も...
しかし2018/08/07現在、CHRにはほとんど日本語の資料が存在し...
故に英語での読解を苦手とする学生には学ぶためのハードルが...
そこでここに日本語で表記法を示し、日本語話者である初学者...
*目次 [#r7bf5d07]
#contents
*CHRとは [#tbb9c0ec]
CHRことConstraint Handling Rulesとは、論理プログラミング...
*CHRの特徴 [#e25f7c56]
CHRは理論と実践、論理的な書き方と処理可能なコードのギャッ...
CHR自体も言語としての機能を備えているのだが、実際にはProl...
*CHRの起動手続き [#hfacf408]
CHRの実行時にはホスト言語においてCHRを使う宣言などのため...
Prologの場合、前書きは例えば以下に記述するような三行でな...
:- module(weather, [rain/0]).
:- use_module(library(chr)).
:- chr_constraint rain/0, wet/0, umbrella/0.
これはrain,wet,umbrellaという、引数が0個の制約3つを導入す...
一行目はPrologのモジュール宣言で、CHRプログラムをweather...
このように書いた場合、モジュールは指定した制約 rain/0 し...
c/nというfunctorの宣言はc(t_1,t_2...,t_n)という制約の名前...
二行目は実際のCHRプログラムが読み込まれる前にCHRライブラ...
三行目は実際に使用される前に制約を宣言している場所である...
最低でも名前と、引数の数だけは与えられなくてはならないが...
*CHRの記法 [#nd267f5a]
まずCHRのコードを分解すると、制約とルールで書かれている。
制約は名前と引数という二つの要素を持ち、C言語でいう関数呼...
name(arg1,arg2,...)
これは実行時の入力に書くことも、コードに書いておくことも...
ルールには
単純化規則
伝播規則
単純化伝播規則
の三種類があるが、いずれもネーム、ヘッド、ガード、ボディ...
単純化規則
name @ head <=> guard | body.
伝播規則
name @ head ==> guard | body.
単純化伝播規則
name @ head1 \ head2 <=> guard | body.
このうち、 name @ と guard | は省略が可能である。
それぞれの規則の動作についてはCHRの動作の項に記述する。
なお変数をルール中で記述したい場合は、大文字で始まる名前...
名前のない変数を記述したい場合は、アンダーバー( _ ) を名...
*CHRの動作 [#w9fb12a3]
CHRが扱う制約は原子論理式(それを構成する部分論理式がない...
前述のルールの動作は以下の通りである。
単純化規則
guard部に記述した条件が満たされているとき、head部に対応...
基本的な問題では、等価でより単純な制約に書き換える時に使...
伝播規則
guard部に記述した条件が満たされており、head部に対応する...
このルールは同じ制約群をhead部としては一度しか発火しない。
基本的な問題では制約としては冗長であっても、より単純な制...
単純化伝播規則
guard部に記述した条件が満たされており、head部に対応する...
他の二つの規則の組み合わせである。
用意されたルールが一つも発火しない状態になると(親言語であ...
以下、CHRの例題を挙げてその動作を解説する。
**例題1 基本的な問題[#u84c4bc4]
制約
A leq B, B leq C, C leq A
ルール
reflexivity @ X leq X <=> true.
antisymmetry @ X leq Y, Y leq X <=> X = Y.
transitivity @ X leq Y, Y leq Z ==> X leq Z.
idempotence @ X leq Y \ X leq Y <=> true.
この問題において、制約leq/2は引数1が引数2以下であることを...
この問題の出力は以下のようになる。
出力
A = B,
A = C.
何故このような結果になったのか、順を追って説明する。
まず、ルールtransitivityが
A leq B, B leq C
をhead部として発火し、制約群は以下のように変化する。
A leq B, B leq C, C leq A, A leq C.
ここでルールantisymmetryが
A leq C, C leq A
をhead部として発火し、制約群が以下のように変化する。
A leq B, B leq C, A = C.
このとき、C = A によって制約 B leq C は B leq A と等価に...
A leq B, B leq A, A = C.
従ってここでルールantisymmetryが
A leq B, B leq C (= A leq B, B leq A)
をhead部として発火し、制約群が以下のように変化する。
A = B, A = C.
これ以上発火するルールがないためここで処理は終了し、残っ...
**例題2 ナップサック問題 [#oe963284]
CHRは前述の通り様々な言語の拡張機能として提供されているわ...
以下はナップサック問題と呼ばれる問題を解くためのSWI-Prolo...
:- use_module(library(chr)).
:- chr_option(optimize,off).
:- chr_constraint knapsack/1, labelk/0, wlimit/1, ptotal...
% make domains for variables
item(V,W) <=> in(item(V,W,count(0)),[0,1]).
% generate auxiliary constraints etc.
knapsack(WL) <=> retractall(memlistitems(X)), retractall...
asserta(memtotalv(0)), wlimit(WL), ptotalw(0), ptotal...
% if an item can't be added to the set, constrain its do...
wlimit(WL), ptotalw(TW) \ in(item(V,W, count(0)),[0,1]) ...
% if an item is labeled to be added to the set, update t...
wlimit(WL) \ in(item(V,W,count(0)),[1]), ptotalw(TW) <=>...
ptotalw(TW2), in(item(V,W,count(1)),[1]).
% labeling
labelk \ in(item(V,W,count(0)), [0,1]) <=> member(P,[0,1...
% calculating total value of the solution
in(item(V,W,count(1)),[1]), ptotalv(TV) <=> TV2 is TV+V,...
% listing items included in the solution
in(item(V,W,count(2)),D), listitems(L) <=> in(item(V,W,c...
% if the current solution has a value greater than the p...
% (and the corresponding set), print intermediate result...
labelmem \ listitems(L), ptotalv(TV) <=>
memtotalv(TV1), TV > TV1, memlistitems(L1) |
retract(memtotalv(TV1)), asserta(memtotalv(TV)), ...
print('best set '), print(L), nl,
print('with value '), print(TV), nl, nl,
fail.
% ...otherwise just backtrack
labelmem \ ptotalv(TV) <=> memtotalv(TV1), TV =< TV1 | f...
ナップサック問題とは価値と重さを持ついくつかの物品から、...
ここで、このプログラムの以下の部分に注目してほしい。
% labeling
labelk \ in(item(V,W,count(0)), [0,1]) <=> member(P,[0,1...
この中に出てくる P という変数について説明する。
SWI-Prologの動作の話になるのだが、SWI-Prologはこのように...
今回はmember/2という関数(SWI-Prologでは述語と呼ぶ)が親言...
よって、in/2制約の第二引数のリストにはひとまず0が代入され...
しかし実行を続けると、このプログラムは必ずfail/0が返るよ...
CHRにバックトラックの機能はなく、以上のように親言語から提...
具体的には以下のような動作をすることになる。
入力例
item(1,1), item(1,2), item(2,4), item(3,4), item(4,3), k...
まず、一番上と、上から二番目のルールによって入力された制...
in(item(1,1,count(0)),[0,1]),
in(item(1,2,count(0)),[0,1]),
in(item(2,4,count(0)),[0,1]),
in(item(3,4,count(0)),[0,1]),
in(item(4,3,count(0)),[0,1]),
retractall(memlistitems(X)), retractall(memtotalv(X)), a...
asserta(memtotalv(0)), wlimit(10), ptotalw(0), ptotal...
memlistitemsやmemtotalvの引数Xは前述の通り変数で、解が見...
三番目のルールは今のところ、ptotalvの引数と重さを足してwl...
in(item(1,1,count(0)),[0]),
in(item(1,2,count(0)),[0]),
in(item(2,4,count(0)),[0]),
in(item(3,4,count(0)),[0]),
in(item(4,3,count(0)),[0]),
retractall(memlistitems(X)), retractall(memtotalv(X)), a...
asserta(memtotalv(0)), wlimit(10), ptotalw(0), ptotal...
六番目のルールは第二引数が[1]のin/2制約に対応しており、七...
八番目のルールはTV1にasserta(memtotalv(0))となっていたの...
結局、九番目のルールにマッチングして、failが返る。
制約には順番がないため、連続して選ばれたmember/2の解はど...
in(item(1,1,count(0)),[1]),
in(item(1,2,count(0)),[0,1]),
in(item(2,4,count(0)),[0,1]),
in(item(3,4,count(0)),[0,1]),
in(item(4,3,count(0)),[0,1]),
retractall(memlistitems(X)), retractall(memtotalv(X)), a...
asserta(memtotalv(0)), wlimit(10), ptotalw(0), ptotal...
三番目のルールは今回も発火しないため、解の候補は以下のよ...
in(item(1,1,count(0)),[1]),
in(item(1,2,count(0)),[0]),
in(item(2,4,count(0)),[0]),
in(item(3,4,count(0)),[0]),
in(item(4,3,count(0)),[0]),
retractall(memlistitems(X)), retractall(memtotalv(X)), a...
asserta(memtotalv(0)), wlimit(10), ptotalw(0), ptotal...
今度は四番目のルールが発火し、重さ1のアイテムがナップサッ...
in(item(1,1,count(1)),[1]),
in(item(1,2,count(0)),[0]),
in(item(2,4,count(0)),[0]),
in(item(3,4,count(0)),[0]),
in(item(4,3,count(0)),[0]),
retractall(memlistitems(X)), retractall(memtotalv(X)), a...
asserta(memtotalv(0)), wlimit(10), ptotalw(1), ptotal...
続けて六番目のルールが発火し、ナップサック内の価値が1にな...
in(item(1,1,count(2)),[1]),
in(item(1,2,count(0)),[0]),
in(item(2,4,count(0)),[0]),
in(item(3,4,count(0)),[0]),
in(item(4,3,count(0)),[0]),
retractall(memlistitems(X)), retractall(memtotalv(X)), a...
asserta(memtotalv(0)), wlimit(10), ptotalw(1), ptotal...
もう入れることになっているアイテムがないので、この解を保...
七番目のルールが発火し、listitems内のリストの頭にitemが挿...
in(item(1,1,count(3)),[1]),
in(item(1,2,count(0)),[0]),
in(item(2,4,count(0)),[0]),
in(item(3,4,count(0)),[0]),
in(item(4,3,count(0)),[0]),
retractall(memlistitems(X)), retractall(memtotalv(X)), a...
asserta(memtotalv(0)), wlimit(10), ptotalw(1), ptotal...
memtotalvの引数をptotalvの引数が上回っているので、八番目...
結果、memtotalvの引数はptotalvの引数に上書きされ、asserta...
そしてこれも親言語の機能であるprintによって今回ナップサッ...
これを繰り返して最高総価値は更新され続け、そのたびに物品...
in(item(1,1,count(0)),[0]),
in(item(1,2,count(0)),[1]),
in(item(2,4,count(0)),[0]),
in(item(3,4,count(0)),[0]),
in(item(4,3,count(0)),[0]).
は総価値がすでに出た1を上回らないのでリストの更新は起きず、
in(item(1,1,count(0)),[1]),
in(item(1,2,count(0)),[1]),
in(item(2,4,count(0)),[0]),
in(item(3,4,count(0)),[0]),
in(item(4,3,count(0)),[0]).
では最高総価値が2に更新されて組み合わせと総価値が出力され...
その次は
in(item(1,1,count(0)),[1]),
in(item(1,2,count(0)),[0]),
in(item(2,4,count(0)),[1]),
in(item(3,4,count(0)),[0]),
in(item(4,3,count(0)),[0]).
で最高総価値が3に更新される、という動きを辿っていくが、me...
in(item(1,1,count(0)),[1]),
in(item(1,2,count(0)),[1]),
in(item(2,4,count(0)),[1]),
in(item(3,4,count(0)),[0,1]),
in(item(4,3,count(0)),[0,1]).
のように、次の解を1にするとナップサックの最大容量を超える...
最終的にすべての組み合わせを調べ終え、そのどれもfail/0が...
**例題3 ユークリッドの互除法 [#c0d008a6]
応用として、制約と全く関係ない問題も場合によっては解くこ...
2つの自然数の最大公約数を求める問題は以下のように記述され...
制約
gcd(A), gcd(B).
※処理系にかけるときはA,Bを任意の自然数にすること
ルール
cleanup @ gcd(0) <=> true.
gcd(N) \ gcd(M) <=> 0<N, N=<M | L is M mod N, gcd(L).
*Constraint Solver [#nd409582]
CHRの主な利用法として、Constraint Solverの作成が上げられ...
これは与えられた制約群を満たす解が存在するかを確かめるア...
⇒ [[./Constraint_Solver]]
*用語解説 [#z60811ef]
ページ名: