[작업노트] 휴대폰 문자입력기 평가 시스템 #2
- Posted at 2008/04/05 21:49
- Filed under 밥벌이의즐거움
Solver Generator
문제 분석
휴대폰 키 입력 시스템은 외부 입력에 반응하는 스택머신으로 모델링 가능하다.
삼성 천지인 시스템을 살펴보자. 다음은 천지인에서 입력 1에 대응하는 상태전이를 나열한 것이다.
종성ㄹ::나머지,1 -> 종성ㄹㄱ::나머지
종성ㄹㄱ::나머지,1 -> 초성ㅋ::종성ㄹ::나머지
초성ㄲ:종성ㄹ::나머지,1 -> 종성ㄹㄱ::나머지
초성ㄱ::나머지, 1 -> 초성ㄲ::나머지
초성ㄲ::나머지, 1 -> 초성ㅋ::나머지
초성ㅋ::나머지, 1 -> 초성ㄱ::나머지
중성_::나머지, 1 -> 종성ㄱ::중성_::나머지
종성ㄱ::나머지, 1-> 종성ㅋ::나머지
종성ㅋ::나머지, 1 -> 종성ㄲ::나머지
종성ㄲ::나머지, 1 -> 종성ㄱ::나머지
특정 문자열을 휴대폰으로 입력하기 위해 필요한 키 입력 순서를 찾는 문제는 결국 어떤 순서로 상태전이가 일어나야 하는지 찾는 문제와 동일하다.
Prolog가 Mercury같은 언어 익숙하다면 이 대목에서 "Inference Rule Backward Chaining" 가 떠오를지 모른다. 또한 문맥민감언어를 파싱하는 문제와 거의 흡사하다. (사실 문맥민감 언어와 내리누름 오토마타는 동등하다) 그러나 Yaccd으로 파서를 짜고 Prolog로 직접 휴대폰입력기의 작동을 기술하자면 인생이 고달퍼진다. (휴대폰 자판 종류가 바뀔 때 마다 전체 프로그램을 새로 작성해야 한다) 상태전기 규칙만 기술하면 그에 상응하는 Prolog나 Yacc(혹은 제3의 언어) 코드를 생성해주는 무언가가 필요하다. 그런 변환기가 있다면 삶이 조금더 행복해질 것 같다.
Prolog가 Mercury같은 언어 익숙하다면 이 대목에서 "Inference Rule Backward Chaining" 가 떠오를지 모른다. 또한 문맥민감언어를 파싱하는 문제와 거의 흡사하다. (사실 문맥민감 언어와 내리누름 오토마타는 동등하다) 그러나 Yaccd으로 파서를 짜고 Prolog로 직접 휴대폰입력기의 작동을 기술하자면 인생이 고달퍼진다. (휴대폰 자판 종류가 바뀔 때 마다 전체 프로그램을 새로 작성해야 한다) 상태전기 규칙만 기술하면 그에 상응하는 Prolog나 Yacc(혹은 제3의 언어) 코드를 생성해주는 무언가가 필요하다. 그런 변환기가 있다면 삶이 조금더 행복해질 것 같다.
트랜지션 기술 언어
우선 상태전이 규칙을 기술하는 간단한 언어를 고안했다. 예를 들어 초성ㄹ::나머지,1 -> 중성ㄹㄱ::나머지 의 규칙은
1<리턴키>
0 ㄹ<리턴키>
1 ㄹㄱ<리턴키>
이렇게 인코딩 한다. 이런 구조의 텍스트파일은 쉽게 처리할 수 있다. Solver Generator를 만들기 전에 미리 6개의 휴대폰 시스템의 상태전이 규칙을 기술해 보았다. 규칙만으로도 분량이 2000줄 정도 되었다. Yacc이나 Prolog (혹은 제 3의 언어)를 써서 직접 작성했을 생각을 하니 확실히 삶이 행복하게 느껴졌다.
Solver Generator작업
이렇게 간단하게 인코딩된 파일을 읽어들여 Solver 코드를 뱉어내는 Solver Generator 를 자바로 작성하였다. 자바를 선택한 이유는 언어수준에서 유니코드를 지원하고 문자열 처리가 용이하기 때문이다.
우선은 삼성 휴대폰의 상태전이 규칙을 작성한뒤 그것을 토대로 Ocaml 로된 Solver를 직접 만들었다. Solver를 최대한 튜닝한 다음 이 코드를 바탕으로 Generator를 작성하기 시작했다.
Solver는 BFS를 써서 가능한 모든 상태전이를 시도해보며 해답을 찾아간다. 최적화를 위해서 적합도 평가함수을 만들었다. 적합도 값은 "목표 스트링과 현재 만든 스트링의 공통 접두사의 길이"로 정의한다. 적합도가 작아지거나, 세번의 상태전이 이후에도 적합도가 증가하지 않으면 그 경로는 버린다. 적합도가 증가하는 경로가 단 하나 존재하는 경우, 나머지 경로를 모든 버린다. 이렇게 하면 스트링의 길이가 길어도 경우의 수가 폭발하지 않고 솔루션을 찾아나갈 수 있다. GLR parsing algorithm과 비슷하다.
DFS를 쓸 수 있으면 Solver의 구조가 더 단순해 질 것 같은데 생각하기 귀찮아서 포기했다.
Solver Generator의 출력 언어 선택
DFS를 쓸 수 있으면 Solver의 구조가 더 단순해 질 것 같은데 생각하기 귀찮아서 포기했다.
Solver Generator의 출력 언어 선택
Solver Generator에는 세가지 대안이 있었다.
첫 번째는 Solver Generator가 Parser Code 를 Generate하는 것이다. 그러나 Parser Generator를 위한 문법을 만들어 내는 알고리즘을 고안하기가 수작업으로 Solver 전체를 코딩하기 보다 어려워 보였다. 게다가 Parser Generator가 만들어 주는 Parser는 DFS 기반이라 Solver와는 어울리지 않는다.
두 번째로 엄청난 Library 를 제공하는 C++가 있다. 포인터와 라이브러리의 기능이 빠방하지만 내가 익숙하지 않다. 게다가 모든 로직을 언어의 도움 없이 직접 짜야 해서 머리가 고달퍼진다.
마지막은 패턴매칭을 제공하는 Ocaml이다. 라이브러리도 빈약하고 글로벌이나 포인터를 명시적으로 사용할 수 없어 큰 프로그램을 짜기에는 답답하다. 그러나 "현재 스택에 적용 가능한 상태전이" 를 찾는 문제를 Ocaml에서 지원하는 "리스트에 대한 패턴매칭" 으로 표현하면 컴파일러가 알아서 처리해어 귀찮은 작업을 덜 수 있다.
문자입력시스템에 따라 달라지는 부분은 "가능한 상태전이"를 찾아주는 함수 뿐이므로, Ocaml을 선택하게 되었다.
작업 당시에는 Prolog나 Mercury에 대한 지식이 없었다. 주어진 규칙을 사용하여 목표를 만드는 적용순서를 찾는 문제는 Prolog가 아주 잘 처리하는 "Inference" 유형의 문제로 인코딩할 수 있을 것 같다. Ocaml이라 C정도로 Prolog를 쓸 수 있었더라면 Prolog를 택했을지도 모른다.
-to be continue첫 번째는 Solver Generator가 Parser Code 를 Generate하는 것이다. 그러나 Parser Generator를 위한 문법을 만들어 내는 알고리즘을 고안하기가 수작업으로 Solver 전체를 코딩하기 보다 어려워 보였다. 게다가 Parser Generator가 만들어 주는 Parser는 DFS 기반이라 Solver와는 어울리지 않는다.
두 번째로 엄청난 Library 를 제공하는 C++가 있다. 포인터와 라이브러리의 기능이 빠방하지만 내가 익숙하지 않다. 게다가 모든 로직을 언어의 도움 없이 직접 짜야 해서 머리가 고달퍼진다.
마지막은 패턴매칭을 제공하는 Ocaml이다. 라이브러리도 빈약하고 글로벌이나 포인터를 명시적으로 사용할 수 없어 큰 프로그램을 짜기에는 답답하다. 그러나 "현재 스택에 적용 가능한 상태전이" 를 찾는 문제를 Ocaml에서 지원하는 "리스트에 대한 패턴매칭" 으로 표현하면 컴파일러가 알아서 처리해어 귀찮은 작업을 덜 수 있다.
문자입력시스템에 따라 달라지는 부분은 "가능한 상태전이"를 찾아주는 함수 뿐이므로, Ocaml을 선택하게 되었다.
작업 당시에는 Prolog나 Mercury에 대한 지식이 없었다. 주어진 규칙을 사용하여 목표를 만드는 적용순서를 찾는 문제는 Prolog가 아주 잘 처리하는 "Inference" 유형의 문제로 인코딩할 수 있을 것 같다. Ocaml이라 C정도로 Prolog를 쓸 수 있었더라면 Prolog를 택했을지도 모른다.
Posted by 발당
- Response
- No Trackback , No Comment
Trackback URL : http://jbdmk1.upnl.org/tt/trackback/379

