0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

KuinAdvent Calendar 2018

Day 19

CSセミナー005 正規言語の和集合演算・スター演算

Posted at

今回は、正規言語の演算のうち、和集合演算スター演算について説明します。

今回のソースコード

和集合演算

正規言語の和集合演算を数式で記述すると次のようになります。
A ∪ B = { x | x ∈ A または x ∈ B }
例えば、「みかん」という文字列を認識する言語と「りんご」という文字列を認識する言語を和集合演算すると、「みかん」と「りんご」の両方を認識する言語になります。

ソースコードを次に示します。

automaton.kn(抜粋)
; 2つのオートマトンの和集合演算を行うクラス
class Union(@Automaton)
	+var automatonA: @Automaton
	+var automatonB: @Automaton
	
	+*func isAccepted(): bool
		ret me.automatonA.isAccepted() | me.automatonB.isAccepted()
	end func
	
	+*func put(c: char)
		do me.automatonA.put(c)
		do me.automatonB.put(c)
	end func
	
	+*func clone(): @Automaton
		var res: @Union :: #@Union
		do res.automatonA :: me.automatonA.clone()
		do res.automatonB :: me.automatonB.clone()
		ret res
	end func
end class

+func makeUnion(a: @Automaton, b: @Automaton): @Automaton
	var res: @Union :: #@Union
	do res.automatonA :: a.clone()
	do res.automatonB :: b.clone()
	ret res
end func

テストコードを次に示します。

test_union1.kn
; test_union1.kn

func runAutomaton(automaton: \automaton@Automaton, str: []char): bool
	var a: \automaton@Automaton :: automaton.clone()
	for i(0, ^str - 1)
		do a.put(str[i])
	end for
	ret a.isAccepted()
end func

var automaton: \automaton@Automaton

func check(str: []char)
	var res: []char ::
	|@runAutomaton(@automaton, str) ?("受理", "拒否")
	do cui@print("入力=\"\{str}\", 結果=\{res}\n")
end func

; 文字列をオートマトンに変換する関数
func toAutomaton(str: []char): \automaton@Automaton
	var res: \automaton@Automaton
	do res :: \automaton@makeOneChar(str[0])
	for i(1, ^str - 1)
		do res :: \automaton@makeConcatenation(
		|res, \automaton@makeOneChar(str[i]))
	end for
	ret res
end func

func main()
	alias a: \automaton@Automaton
	do cui@print("test kuina or chan\n")
	do @automaton :: \automaton@makeUnion(
	|@toAutomaton("くいな"), @toAutomaton("ちゃん"))
	do @check("")
	do @check("くいな")
	do @check("ちゃん")
	do @check("くいなちゃん")
	do @check("く")
	do @check("ち")
	do cui@print("test kuinachan or rokusai\n")
	do @automaton :: \automaton@makeUnion(
	|@toAutomaton("くいなちゃん"), @toAutomaton("6さい"))
	do @check("")
	do @check("くいな")
	do @check("ちゃん")
	do @check("くいなちゃん")
	do @check("6さい")
	do @check("くいなちゃん6さい")
end func

実行結果を次に示します。
001.png

スター演算

スター演算はある言語の繰り返しを認識する言語を生成する演算です。数式で示すと以下のようになります。
A* = { x1 x2 ... xk | k ≥ 0 で、各々の xi について xi ∈ A }
例えば、「くいなちゃん」という文字列を認識する言語にスター演算を適用すると、空文字列「」、「くいなちゃん」、「くいなちゃんくいなちゃん」などを認識する言語が生成されます。

次にソースコードを示します。

automaton.kn(抜粋)
; オートマトンのスター演算を行うクラス
class Star(@Automaton)
	+var automaton: @Automaton {テンプレート}
	+var listA: list<@Automaton> {実働}
	
	*func ctor()
		do me.listA :: #list<@Automaton>
	end func
	
	+*func isAccepted(): bool
		if(^me.listA = 0)
			ret true
		end if
		do me.listA.head()
		while(!me.listA.term())
			if(me.listA.get().isAccepted())
				ret true
			end if
			do me.listA.next()
		end while
		ret false
	end func
	
	+*func put(c: char)
		if(^me.listA = 0)
			do me.listA.add(me.automaton.clone())
		else
			do me.listA.head()
			while loop(!me.listA.term())
				if(me.listA.get().isAccepted())
					do me.listA.add(me.automaton.clone())
					break loop
				end if
				do me.listA.next()
			end while
		end if
		do me.listA.head()
		while(!me.listA.term())
			do me.listA.get().put(c)
			do me.listA.next()
		end while
	end func
	
	+*func clone(): @Automaton
		var res: @Star :: #@Star
		do res.automaton :: me.automaton
		ret res
	end func
end class

+func makeStar(a: @Automaton): @Automaton
	var res: @Star :: #@Star
	do res.automaton :: a
	ret res
end func

スター演算の実装の仕方は連結演算のそれに似ています。空文字列の扱いは少しトリッキーになっています。

次にテストコードを示します。

test_star1.kn
; test_star1.kn

func runAutomaton(automaton: \automaton@Automaton, str: []char): bool
	var a: \automaton@Automaton :: automaton.clone()
	for i(0, ^str - 1)
		do a.put(str[i])
	end for
	ret a.isAccepted()
end func

var automaton: \automaton@Automaton

func check(str: []char)
	var res: []char ::
	|@runAutomaton(@automaton, str) ?("受理", "拒否")
	do cui@print("入力=\"\{str}\", 結果=\{res}\n")
end func

; 文字列をオートマトンに変換する関数
func toAutomaton(str: []char): \automaton@Automaton
	var res: \automaton@Automaton
	do res :: \automaton@makeOneChar(str[0])
	for i(1, ^str - 1)
		do res :: \automaton@makeConcatenation(
		|res, \automaton@makeOneChar(str[i]))
	end for
	ret res
end func

func main()
	alias a: \automaton@Automaton
	do cui@print("test kuina*\n")
	do @automaton :: \automaton@makeStar(@toAutomaton("くいな"))
	do @check("")
	do @check("くいな")
	do @check("くいなくいな")
	do @check("くいなくいなくいな")
	do @check("くいなくいなくいなちゃん")
	do cui@print("test (kuina or rokusai)*\n")
	do @automaton :: \automaton@makeStar(
	|\automaton@makeUnion(@toAutomaton("くいな"), @toAutomaton("6さい")))
	do @check("")
	do @check("くいな")
	do @check("ちゃん")
	do @check("6さい")
	do @check("くいなちゃん6さい")
	do @check("くいな6さい")
	do @check("くいな6さい6さいくいな")
end func

次に実行結果を示します。
002.png

まとめ

有限オートマトンと、それに関する3つの演算(連結演算・和集合演算・スター演算)を示しました。有限オートマトンに対してこれらの演算を適用しても有限オートマトンが得られることが分かっています。示したソースコードでは定義を満たす最も簡潔な実装を行っているので実行効率は悪いものとなっています。

正規言語は有限オートマトンで認識可能な言語のことです。プログラミング言語で用いられている正規表現は正規言語のアイディアがもとになっていますが、より実用的なインターフェースが用意されており、アルゴリズムの工夫により高速に動作するようになっています。次回は、Kuinの正規表現ライブラリについて学んでみましょう。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?