맨위로가기

CYK 알고리즘

"오늘의AI위키"는 AI 기술로 일관성 있고 체계적인 최신 지식을 제공하는 혁신 플랫폼입니다.
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.

1. 개요

CYK 알고리즘은 주어진 문자열이 문맥 자유 문법에 속하는지 결정하는 데 사용되는 알고리즘으로, 촘스키 정규 형식(CNF)으로 변환된 문맥 자유 문법을 필요로 한다. 동적 계획법을 사용하여 문자열의 모든 부분 문자열에 대해 해당 부분 문자열이 문법의 각 비단말 기호로부터 생성될 수 있는지 여부를 저장하는 테이블을 채워나가는 상향식 구문 분석 알고리즘이다. CYK 알고리즘은 구문 분석 트리 생성, 가중 및 확률 문맥 자유 문법 파싱으로 확장될 수 있으며, 밸리언트의 알고리즘과 같은 개선된 알고리즘도 존재한다.

더 읽어볼만한 페이지

  • 파싱 알고리즘 - 하향식 구문 분석
    하향식 구문 분석은 컴파일러나 인터프리터가 소스 코드를 변환할 때 입력 전체가 문법의 최상위 규칙에 일치한다고 가정하고 좌단 기호부터 매칭하며, LL 파서는 생성 규칙을 적용하여 구문 분석을 수행하고 좌측 재귀는 변환 또는 그래프 구조 스택으로 처리한다.
  • 파싱 알고리즘 - 재귀 하향 파서
    재귀 하향 파서는 백트래킹 없이 LL(k) 문법 클래스에서 선형 시간에 동작하며 각 비종단 기호에 대한 프로시저를 가지는 예측 파서이다.
CYK 알고리즘
개요
CYK 알고리즘 파싱 예시
CYK 알고리즘
종류파싱
자료 구조문자열
시간 복잡도O(n³ · |G|), 여기서 n은 문자열의 길이, |G|는 CNF 문법의 크기
상세 정보
개발자존 코크
다니엘 얀거
타다오 카사미
발표 연도1967년 (코크)
1967년 (얀거)
1965년 (카사미)
분야전산 언어학
적용 대상문맥 자유 문법
특징
장점구현 용이
문법 오류 검출에 효과적
단점촘스키 정규형으로의 문법 변환 필요
시간 복잡도가 높음
관련 정보
관련 알고리즘Earley 알고리즘

2. 표준 형식

CYK 알고리즘은 촘스키 정규 형식(CNF)으로 표현된 문맥 자유 문법을 필요로 한다.[3] 촘스키 정규 형식은 생성 규칙이 다음의 형태만을 가지는 문법이다.


  • A \rightarrow BC
  • A \rightarrow \alpha
  • S \to \varepsilon (단, S는 시작 기호)


여기서 A, B, C는 비단말 기호, α는 단말 기호, S는 시작 기호, ε는 빈 문자열이다. 빈 문자열을 생성하지 않는 모든 문맥 자유 문법은 촘스키 정규 형식으로 변환될 수 있다.[3]

3. 알고리즘

CYK 알고리즘은 주어진 문자열의 모든 부분 문자열에 대해, 해당 부분 문자열이 문법의 각 비단말 기호로부터 생성될 수 있는지 여부를 저장하는 테이블을 작성한다. 이 테이블은 동적 계획법을 사용하여 채워진다.

CYK 알고리즘은 상향식 알고리즘이며, 문맥 자유 언어의 멤버십 문제가 결정 가능함을 구성적으로 증명할 수 있다는 점에서 이론적으로도 중요하다.

간단히 말하면, CYK 알고리즘은 입력 문자열의 모든 가능한 부분 문자열을 고려하여 각 부분 문자열이 특정 비단말 기호에서 생성될 수 있는지 여부를 테이블에 저장한다. 구체적인 알고리즘의 동작 방식은 다음과 같다.


  • 입력: ''n''개의 문자 ''a''1 ... ''a''''n''으로 구성된 문자열.
  • 문법: ''r''개의 비단말 기호 ''R''1 ... ''R''''r'' (시작 기호 ''R''s 포함).
  • P\[n,n,r]: 불리언 배열. 모든 요소를 false로 초기화.
  • i = 1부터 n까지:
  • 각 생성 규칙 Rj → ai에 대해, P\[i,1,j] = true로 설정.
  • i = 2부터 n까지 (범위의 길이):
  • j = 1부터 n-i+1까지 (범위의 시작 위치):
  • k = 1부터 i-1까지 (범위의 구분):
  • 각 생성 규칙 RA → RB RC에 대해:
  • 만약 P\[j,k,B]와 P\[j+k,i-k,C]가 모두 true이면, P\[j,i,A] = true로 설정.
  • P\[1,n,x] 중 하나라도 true이면 (x는 Rs의 모든 인덱스 s에 대해 반복), 입력 문자열은 해당 언어에 속한다. 그렇지 않으면 속하지 않는다.

3. 1. 의사 코드

다음은 CYK 알고리즘의 의사 코드이다.

'''Let''' 입력 문자열이 ''n''개의 문자 ''a''1 ... ''a''''n''으로 구성된다고 하자.

'''Let''' 문법이 ''r''개의 비단말 기호 ''R''1 ... ''R''''r''로 구성된다고 하자.

이 문법은 시작 기호의 집합 Rs를 포함한다.

'''Let''' P[n,n,r]을 불리언 배열로 한다. P의 모든 원소를 false로 초기화한다.

'''For each''' i = 1 to n

'''For each''' 단위 생성 규칙 Rj → ai에 대해, P[i,1,j] = true로 설정한다.

'''For each''' i = 2 to n -- 범위의 길이

'''For each''' j = 1 to n-i+1 -- 범위의 시작

'''For each''' k = 1 to i-1 -- 범위의 분할

'''For each''' 생성 규칙 RA → RB RC에 대해

'''If''' P[j,k,B] and P[j+k,i-k,C] '''then''' P[j,i,A] = true로 설정한다.

'''If''' P[1,n,x] 중 하나라도 true이면 (x는 Rs의 모든 인덱스 s에 대해 반복),

'''Then''' 입력 문자열은 해당 언어에 속한다.

'''Else''' 입력 문자열은 해당 언어에 속하지 않는다.

3. 2. 확률적 CYK

모든 생성 규칙의 확률이 주어졌을 때, 가장 확률이 높은 구문 분석 트리를 찾는 방법은 다음과 같다.[1]

'''입력'''은 ''n''개의 문자 ''a''1 ... ''a''''n''으로 구성된 문자열 ''I''라고 가정한다.

'''문법'''은 시작 기호 ''R''1을 포함하여 ''r''개의 비단말 기호 ''R''1 ... ''R''''r''을 포함한다고 가정한다.

'''실수''' 배열 ''P''[''n'',''n'',''r'']을 정의한다. 모든 ''P''의 요소를 0으로 초기화한다.

'''역추적''' 삼중항 배열 ''back''[''n'',''n'',''r'']을 정의한다.
''s'' = 1 부터 ''n''까지

단위 생성 규칙 ''R''''v'' →''a''''s''에 대해

''P''[''1'',''s'',''v''] = Pr(''R''''v'' →''a''''s'')로 설정한다.
''l'' = 2 부터 ''n''까지 ''-- 범위의 길이''

''s'' = 1 부터 ''n''-''l''+1까지 ''-- 범위의 시작''

''p'' = 1 부터 ''l''-1까지 ''-- 범위의 분할''

생성 규칙 ''R''''a'' → ''R''''b'' ''R''''c''에 대해

prob_splitting = Pr(''R''''a'' →''R''''b'' ''R''''c'') * ''P''[''p'',''s'',''b''] * ''P''[''l''-''p'',''s''+''p'',''c'']

만약 prob_splitting > ''P''[''l'',''s'',''a''] 이라면

''P''[''l'',''s'',''a''] = prob_splitting으로 설정한다.

''back''[''l'',''s'',''a''] = 로 설정한다.
만약 ''P''[n,''1'',''1''] > 0 이라면

''back''을 통해 파싱 트리를 역추적하여 찾습니다.

파싱 트리를 반환한다.
그렇지 않으면 "언어의 구성원이 아님"을 반환한다.

3. 3. 설명

CYK 알고리즘은 입력 문자열의 모든 가능한 부분 문자열을 고려하여, 각 부분 문자열이 특정 비단말 기호에서 생성될 수 있는지 여부를 테이블에 저장하는 방식으로 동작한다. 이 과정은 다음과 같이 진행된다.

1. 길이 1의 모든 부분 문자열에 대해, 해당 부분 문자열을 생성할 수 있는 비단말 기호를 찾아서 테이블에 표시한다.

2. 길이 2의 모든 부분 문자열에 대해, 해당 부분 문자열을 두 부분으로 나누는 모든 경우를 고려한다. 각 경우에 대해, 두 부분을 생성할 수 있는 비단말 기호의 쌍이 존재하는지 확인하고, 이 쌍을 이용하여 전체 부분 문자열을 생성할 수 있는 비단말 기호가 있는지 확인하여 테이블에 표시한다.

3. 위의 과정을 길이 3, 4, ..., n (입력 문자열의 길이)에 대해 반복한다.

4. 최종적으로, 시작 기호가 전체 입력 문자열을 생성할 수 있는지 여부를 테이블에서 확인하여, 입력 문자열이 해당 문법에 속하는지 판별한다.

이 알고리즘은 상향식 구문 분석 방식을 사용하며, 모든 가능한 부분 문자열을 체계적으로 검사함으로써 주어진 문자열이 문법에 의해 생성될 수 있는지 여부를 효율적으로 판별할 수 있다. 또한, 이 알고리즘은 문맥 자유 언어의 멤버십 문제가 결정 가능하다는 것을 보여주는 중요한 이론적 의미를 갖는다.

다음은 CYK 알고리즘의 동작 예시를 보여주는 테이블이다.

CYK 테이블
S
VP
S
VPPP
SNPNP
NPV, VPDet.NPDetN
sheeatsafishwithafork


4. 예시

다음은 주어진 문법이다.

:\begin{align}

\ce{S} & \ \ce{-> NP\ VP}\\

\ce{VP} & \ \ce{-> VP\ PP}\\

\ce{VP} & \ \ce{-> V\ NP}\\

\ce{VP} & \ \ce{-> eats}\\

\ce{PP} & \ \ce{-> P\ NP}\\

\ce{NP} & \ \ce{-> Det\ N}\\

\ce{NP} & \ \ce{-> she}\\

\ce{V} & \ \ce{-> eats}\\

\ce{P} & \ \ce{-> with}\\

\ce{N} & \ \ce{-> fish}\\

\ce{N} & \ \ce{-> fork}\\

\ce{Det} & \ \ce{-> a}

\end{align}

이제 "she eats a fish with a fork" 문장을 CYK 알고리즘으로 분석한다. 아래 표에서 P[i,j,k]는 i번째 행(아래에서부터 1로 시작), j번째 열(왼쪽에서부터 1로 시작)을 의미한다.

CYK 알고리즘을 사용한 문장 분석


CYK 표
S
VP
S
VPPP
SNPNP
NPV, VPDet.NPDetN
sheeatsafishwithafork



위 표에서 시작 기호 S가 P[7,1]에 있으므로, 이 문장은 주어진 문법으로 생성될 수 있다.

간단히 설명하면, CYK 알고리즘은 단어 배열에서 가능한 모든 조합을 고려한다. 먼저 길이 1의 배열을 검토하고, 그다음 길이 2의 배열을 검토하는 식으로 진행한다. 길이 2 이상의 배열은 두 부분으로 나누어, P → Q R 생성 규칙으로 Q와 R이 각각 배열의 전반부와 후반부에 일치하는지 확인한다. 일치하면 P를 해당 배열 전체와 일치하는 것으로 기록한다. 이 과정이 끝나면, 입력 문자열 전체가 시작 기호에서 생성되는지 알 수 있다.

5. 확장

CYK 알고리즘은 주어진 문장이 특정 문맥 자유 문법에 속하는지 판별하는 것 외에도, 다양한 방식으로 확장될 수 있다.


  • 구문 분석 트리 생성: CYK 알고리즘은 단순한 인식기를 넘어, 구문 분석 트리를 생성하는 파서로 확장될 수 있다. 배열 P의 각 요소에 부울 값 대신 파스 트리의 노드를 저장하고, 이 노드들을 연결하여 트리 구조를 만들 수 있다. 모호한 문장의 경우, 모든 가능한 파스 트리를 보존하기 위해 추가적인 테이블 B를 사용하여 파싱 과정에서 해당 노드를 얻는 모든 방법을 저장할 수 있다. 이렇게 생성된 공유 포레스트는 모호한 문법으로 읽을 수 있다.

  • 가중 문맥 자유 문법 파싱: CYK 알고리즘은 가중 문맥 자유 문법이나 확률 문맥 자유 문법을 처리하도록 확장될 수 있다. 이 경우, 테이블 P에 가중치나 확률을 저장하여 P[i, j, A]가 i부터 j까지의 부분 문자열이 A로부터 생성될 수 있는 최소 가중치(최대 확률)를 나타내도록 한다. 더 나아가, 모든 가능한 구문 분석을 가중치(확률) 순으로 열거할 수도 있다.[1]

  • 비 촘스키 정규 형식 문법 파싱: CYK 알고리즘은 촘스키 정규 형식으로 변환하지 않고도 임의의 문맥 자유 문법을 처리하도록 일반화될 수 있다. Lange와 Leiß는 알고리즘의 효율성, 명확성, 단순성을 유지하면서 CYK 알고리즘을 일반화하는 방법을 제안했다.

  • 수치 안정성: 확률적 CYK 알고리즘을 긴 문자열에 적용할 때 발생할 수 있는 수치적 불안정성 문제는 로그 확률을 사용하여 해결할 수 있다. 확률 값 대신 로그 확률을 사용하면 곱셈이 덧셈으로 바뀌어 계산이 안정적으로 이루어진다.[1]

5. 1. 구문 분석 트리 생성

위 알고리즘은 문장이 해당 언어에 속하는지 여부만 판별하는 인식기이다. 배열의 요소로 부울 값 1 대신 파스 트리 노드를 저장함으로써, 구문 분석 트리를 구성하는 파서로 확장할 수 있다. 노드는 이를 생성하는 데 사용된 배열 요소에 연결되어 트리 구조를 구축한다. 하나의 파스 트리만 생성하려는 경우 각 배열 요소에 그러한 노드 하나만 있으면 된다. 그러나 모호한 문장의 모든 파스 트리를 보존하려면 파싱 과정에서 해당 노드를 얻을 수 있는 모든 방법을 배열 요소에 목록으로 저장해야 한다. 이는 때때로 ''backpointers''라고 불리는 두 번째 테이블 B[n,n,r]을 사용하여 수행된다.

최종 결과는 가능한 파스 트리의 공유 포레스트이며, 여기서 공통 트리 부분은 다양한 파싱 간에 팩터링된다. 이 공유 포레스트는 파싱된 문장만 생성하는 모호한 문법으로 편리하게 읽을 수 있다.

가중 문맥 자유 문법이나 확률 문맥 자유 문법을 사용하여 문자열의 구문 분석을 하도록 확장하는 것도 가능하다. 이 경우, 가중치나 확률은 테이블 P에 부울 대신 저장된다. 즉, P[i,j,A]는 i부터 길이 j의 시퀀스가 A로부터 생성되는 최소 가중치 (또는 최대 확률)를 저장한다. 또한, 알고리즘을 확장하면 모든 가중치(확률)의 구문 트리를 열거할 수 있다.[1]

5. 2. 비 촘스키 정규 형식 문법 파싱

CYK algorithm|CYK 알고리즘영어은 촘스키 정규 형식으로 변환하지 않고도 임의의 문맥 자유 문법을 처리할 수 있도록 일반화될 수 있다. 하지만 이 경우 문법 크기의 팽창을 초래할 수 있다. Lange와 Leiß는 "알고리즘의 효율성, 제시의 명확성 또는 증명의 단순성을 손상시키지 않으면서" CYK 알고리즘의 약간의 일반화를 제안했다. 문법의 크기는 생성 규칙의 크기의 합이며, 규칙의 크기는 1과 해당 규칙 우변의 길이의 합이다. 원래 문법의 크기를 g로 표기하면, 사용된 변환 알고리즘에 따라 최악의 경우 크기 증가가 g^2에서 2^{2 g} 범위에 이를 수 있다.

5. 3. 가중 문맥 자유 문법 파싱

CYK 알고리즘은 가중 문맥 자유 문법(weighted CFG) 또는 확률 문맥 자유 문법(probabilistic CFG)을 사용하여 문자열을 구문 분석하도록 확장할 수 있다. 이 경우, 테이블 P에 부울 값 대신 가중치(확률)를 저장한다. P[i, j, A]는 i부터 j까지의 부분 문자열을 A로부터 파생할 수 있는 최소 가중치(최대 확률)를 나타낸다. 알고리즘을 더 확장하면 가장 낮은 가중치(가장 높은 확률)부터 가장 높은 가중치(가장 낮은 확률) 순으로 모든 구문 분석을 열거할 수 있다.

5. 3. 1. 수치 안정성

확률적 CYK 알고리즘을 긴 문자열에 적용하면, 여러 확률을 곱하는 과정에서 분할 확률이 매우 작아질 수 있다. 이는 수치적 불안정성 문제로 이어질 수 있는데, 확률 값 대신 로그 확률(log-probabilities)을 사용하여 해결할 수 있다. 즉, 확률의 곱셈을 로그 확률의 덧셈으로 바꾸어 계산하는 것이다.[1]

6. Valiant의 알고리즘

밸리언트는 CYK 알고리즘의 확장을 제시했다. 그의 알고리즘은 CYK 알고리즘과 동일한 파싱 테이블을 계산하지만, 효율적인 곱셈을 위한 알고리즘인 0-1 엔트리를 가진 행렬을 사용하여 이 계산을 수행할 수 있음을 보였다.[4]

이러한 행렬의 곱셈에 Coppersmith–Winograd 알고리즘을 사용하면 점근적 최악의 경우 실행 시간은 O(n^{2.38} \cdot |G|)가 된다. 그러나 빅 오 표기법에 의해 숨겨진 상수항이 너무 커서 Coppersmith–Winograd 알고리즘은 현재 컴퓨터에서 처리하기에는 너무 큰 행렬에만 가치가 있다. 효율적인 행렬 곱셈에 대한 의존성을 완전히 피할 수는 없다. 리는 O(n^{3-\varepsilon} \cdot |G|) 시간에 작동하는 문맥 자유 문법에 대한 모든 파서가 O(n^{3 - \varepsilon/3}) 시간에 0-1 엔트리를 가진 (n \times n) 행렬의 곱을 계산하는 알고리즘으로 효과적으로 변환될 수 있음을 증명했으며, 이는 Abboud et al.에 의해 상수 크기 문법에 적용되도록 확장되었다.[4]

참조

[1] 서적 Parsing techniques : a practical guide Springer 2008
[2] 간행물 "Syntax in universal translation" Her Majesty’s Stationery Office, London 1962
[3] 서적 Introduction to the theory of computation https://www.worldcat[...] Thomson Course Technology 2006
[4] 논문 If the Current Clique Algorithms are Optimal, so is Valiant's Parser 2015-11-05



본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.

문의하기 : help@durumis.com