diff --git a/docs/Doxyfile b/docs/Doxyfile index a1fde048..25a3ac69 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -1,4 +1,4 @@ -# Doxyfile 1.8.13 +# Doxyfile 1.9.2 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -162,7 +162,7 @@ FULL_PATH_NAMES = YES # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. -STRIP_FROM_PATH = +STRIP_FROM_PATH = ../ # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which diff --git a/include/kiwi/Form.h b/include/kiwi/Form.h index cd6f2973..e1a6480e 100644 --- a/include/kiwi/Form.h +++ b/include/kiwi/Form.h @@ -1,3 +1,13 @@ +/** + * @file Form.h + * @author bab2min (bab2min@gmail.com) + * @brief 형태 및 형태소에 관한 정보를 담는 구조체들이 선언된 헤더 + * @version 0.10.0 + * @date 2021-09-10 + * + * + */ + #pragma once #include @@ -7,15 +17,54 @@ namespace kiwi { struct Morpheme; + /** + * @brief 형태소에 관한 모든 정보를 담는 구조체의 템플릿 + * + * @note `baked = false`는 변경가능한 상태로 인덱스와 관련된 값이나 std::vector 등의 길이를 변경할 수 있음. + * 이 상태는 `kiwi::MorphemeRaw`라는 타입의 부모클래스로 쓰이며, `kiwi::KiwiBuilder`에서 사용한다. + * `baked = true`는 변경 불가능한 상태로 인덱스는 모두 포인터로, std::vector는 FixedVector로 변경되어 수정이 불가능한 대신 + * 각 값에 효율적으로 빠르게 접근 가능하다. 이 상태는 `kiwi::Morpheme`이라는 타입의 부모클래스로 쓰이며, + * `kiwi::Kiwi` 내 실제 형태소 분석 단계에 쓰인다. + * @tparam baked + */ template struct MorphemeT { - typename std::conditional::type kform = 0; - POSTag tag = POSTag::unknown; - CondVowel vowel = CondVowel::none; - CondPolarity polar = CondPolarity::none; + typename std::conditional::type kform = 0; /**< 형태에 대한 포인터 */ + POSTag tag = POSTag::unknown; /**< 품사 태그 */ + CondVowel vowel = CondVowel::none; /**< 선행형태소의 자/모음 조건 */ + CondPolarity polar = CondPolarity::none; /**< 선행형태소의 모음조화 조건 */ + + /** + * @brief 형태소가 두 부분으로 분할된 경우 결합 번호를 표기하기 위해 사용된다. + * + * @note `덥/VA`, `춥/VA` 등의 형태소는 `어/EC`와 만나면 `더워`, `추워`와 같이 형태가 변화한다. + * 이 경우를 각각 처리하기 보다는 `더/V + ㅂ/V`, `추/V + ㅂ/V`과 같이 분해하면 + * `ㅂ/V` + `어/EC`가 `워`로 변한다는 규칙만으로 처리가 가능해진다. (이 규칙은 `chunks`를 이용해 형태소 정보에 담길 수 있음) + * 그러나 모든 ㅂ으로 끝나는 형태소가 위와 같은 규칙에 결합되면 안된다. + * 예를 들어 `굽/VA`의 경우 `어/EC`와 만나도 `굽어`라고 형태가 유지되기 때문. + * 따라서 `ㅂ/V`이 결합할 수 있는 조건을 명시해서 이 조건과 맞는 경우에만 `더/V + ㅂ/V` -> `덥/VA`과 같이 복원해야 한다. + * `combineSocket`이 0이면 이런 결합 조건이 없는 일반 형태소임을 뜻하며, 0이 아닌 경우 결합 조건을 가지고 분해된 형태소임을 뜻한다. + * `더/V`와 `워/UNK`(`ㅂ/V + 어/EC`)는 예를 들어 3과 같이 동일한 combineSocket을 할당해 둘이 서로 결합이 가능한 형태소임을 식별한다. + */ uint8_t combineSocket = 0; + + /** + * @brief 여러 형태소가 결합되어 형태가 변경된 경우에 원 형태소 목록을 표기하기 위해 사용된다. + * + * @note `되/VV + 어/EC`의 결합은 `돼`라는 형태로 축약될 수 있다. + * 분석과정에서 `돼`를 만난 경우 역으로 `되/VV + 어/EC`로 분석할 수 있도록 `돼/UNK`를 더미 형태소로 등록하고 + * chunks에는 `되/VV`와 `어/EC`에 대한 포인터를 넣어둔다. + */ typename std::conditional, std::vector>::type chunks; + + /** + * @brief 분할된 형태소의 원형 형태소를 가리키는 오프셋 + * + * @note `덥/VA`이 `더/V` + `ㅂ/V`으로 분할된 경우 `더/V`는 `덥/VA`에 대한 오프셋을 combined에 저장해둔다. + * `kiwi::Morpheme::getCombined()`를 통해 원형 형태소의 포인터를 구할 수 있음 + * @sa combineSocket + */ int32_t combined = 0; float userScore = 0; @@ -39,21 +88,39 @@ namespace kiwi void serializerWrite(std::ostream& ostr) const; }; + /** + * @brief 최적화된 형태소 정보를 담는 구조체. 값을 변경하면 안된다. + * + */ struct Morpheme : public MorphemeT { using MorphemeT::MorphemeT; + /** 형태소의 형태를 반환한다. */ const KString& getForm() const { return *kform; } + + /** 분할된 형태소의 경우 원형 형태소를 반환한다. 그 외에는 자기 자신을 반환한다. */ const Morpheme* getCombined() const { return this + combined; } }; + /** + * @brief 형태에 관한 모든 정보를 담는 구조체의 템플릿 + * + * @note `baked = false`는 변경가능한 상태로 인덱스와 관련된 값이나 std::vector 등의 길이를 변경할 수 있음. + * 이 상태는 `kiwi::FormRaw`라는 타입의 부모클래스로 쓰이며, `kiwi::KiwiBuilder`에서 사용한다. + * `baked = true`는 변경 불가능한 상태로 인덱스는 모두 포인터로, std::vector는 FixedVector로 변경되어 수정이 불가능한 대신 + * 각 값에 효율적으로 빠르게 접근 가능하다. 이 상태는 `kiwi::Form`이라는 타입의 부모클래스로 쓰이며, + * `kiwi::Kiwi` 내 실제 형태소 분석 단계에 쓰인다. + * @tparam baked + */ template struct FormT { - KString form; - CondVowel vowel = CondVowel::none; - CondPolarity polar = CondPolarity::none; + KString form; /**< 형태 */ + CondVowel vowel = CondVowel::none; /**< 선행형태소의 자/모음 조건 */ + CondPolarity polar = CondPolarity::none; /**< 선행형태소의 모음조화 조건 */ typename std::conditional, Vector>::type candidate; + /**< 이 형태에 해당하는 형태소들의 목록 */ FormT(const kchar_t* _form = nullptr) { @@ -91,6 +158,22 @@ namespace kiwi using FormT::FormT; }; + /** + * @brief 변경가능한 형태 정보를 bake하여 최적화한다. + * + * @param o 변경 가능한 형태 정보 + * @param morphBase 형태소 배열의 시작 위치 + * @return 최적화된 형태 정보 + */ Form bake(const FormRaw& o, const Morpheme* morphBase); + + /** + * @brief 변경 가능한 형태소 정보를 bake하여 최적화한다. + * + * @param o 변경 가능한 형태소 정보 + * @param morphBase 형태소 배열의 시작 위치 + * @param formBase 형태 배열의 시작 위치 + * @return 최적화된 형태소 정보 + */ Morpheme bake(const MorphemeRaw& o, const Morpheme* morphBase, const Form* formBase); } diff --git a/include/kiwi/Types.h b/include/kiwi/Types.h index 6a529488..57aa06cb 100644 --- a/include/kiwi/Types.h +++ b/include/kiwi/Types.h @@ -5,7 +5,6 @@ * @version 0.10.0 * @date 2021-08-31 * - * @copyright Copyright (c) 2021 * */ @@ -86,21 +85,48 @@ namespace kiwi using KcVector = Vector; using KcScores = Vector>; #else + /** + * @brief std::vector의 내부용 타입. mimalloc 옵션에 따라 mi_stl_allocator로부터 메모리를 할당받는다. + * + * @note Vector는 std::vector와 동일한 역할을 수행하지만, + * mimalloc 사용시 Vector가 좀 더 빠른 속도로 메모리를 할당 받을 수 있음. + * Vector와 std::vector는 섞어 쓸 수 없다. + * Kiwi 내부에서만 사용할 것이라면 Vector를, 외부로 반환해야할 값이라면 std::vector를 사용할 것. + */ template using Vector = std::vector<_Ty>; + /** + * @brief std::unordered_map의 내부용 타입. mimalloc 옵션에 따라 mi_stl_allocator로부터 메모리를 할당받는다. + * + * @note UnorderMap은 std::unordered_map과 동일한 역할을 수행하지만, + * mimalloc 사용시 UnorderMap이 좀 더 빠른 속도로 메모리를 할당 받을 수 있음. + * @sa Vector + */ template using UnorderedMap = std::unordered_map<_K, _V>; + /** + * @brief std::u16string의 내부용 타입. mimalloc 옵션에 따라 mi_stl_allocator로부터 메모리를 할당받는다. + * + * @note KString은 std::u16string과 동일한 역할을 수행하지만, + * mimalloc 사용시 KString이 좀 더 빠른 속도로 메모리를 할당 받을 수 있음. + * @sa Vector + */ using KString = std::basic_string; using KStringStream = std::basic_stringstream; using KcVector = Vector; using KcScores = Vector>; #endif + /** + * @brief 형태소 품사 태그와 관련된 열거형 + * + * @note 나머지 품사 태그에 대한 정보는 README.md 를 참조할 것. + */ enum class POSTag : uint8_t { - unknown, + unknown, /**< 미설정 */ nng, nnp, nnb, vv, va, mag, @@ -115,29 +141,37 @@ namespace kiwi w_url, w_email, w_mention, w_hashtag, jks, jkc, jkg, jko, jkb, jkv, jkq, jx, jc, ep, ef, ec, etn, etm, - v, - max, + v, /**< 분할된 동사/형용사를 나타내는데 사용됨 */ + max, /**< POSTag의 총 개수를 나타내는 용도 */ }; constexpr size_t defaultTagSize = (size_t)POSTag::jks; + /** + * @brief 선행 형태소의 종성 여부 조건과 관련된 열거형 + * + */ enum class CondVowel : uint8_t { - none, - any, - vowel, - vocalic, - vocalic_h, - non_vowel, - non_vocalic, - non_vocalic_h, + none, /**< 조건이 설정되지 않음 */ + any, /**< 자음, 모음 여부와 상관 없이 등장 가능 */ + vowel, /**< 선행 형태소가 받침이 없는 경우만 등장 가능*/ + vocalic, /**< 선행 형태소가 받침이 없거나 ㄹ받침인 경우만 등장 가능*/ + vocalic_h, /**< 선행 형태소가 받침이 없거나 ㄹ, ㅎ 받침인 경우만 등장 가능 */ + non_vowel, /**< `vowel`의 부정 */ + non_vocalic, /**< `vocalic`의 부정 */ + non_vocalic_h, /**< `vocalic_h`의 부정 */ }; + /** + * @brief 선행 형태소의 양/음성 조건(모음 조화)과 관련된 열거형 + * + */ enum class CondPolarity : char { - none, - positive, - negative + none, /**< 조건이 설정되지 않음 */ + positive, /**< 선행 형태소가 양성(ㅏ,ㅑ,ㅗ)인 경우만 등장 가능 */ + negative, /**< 선행 형태소가 음성(그 외)인 경우만 등장 가능 */ }; /** @@ -156,13 +190,17 @@ namespace kiwi struct Morpheme; + /** + * @brief 분석 완료된 각 형태소들의 정보를 담는 구조체 + * + */ struct TokenInfo { - std::u16string str; - uint32_t position = 0; - uint16_t length = 0; - POSTag tag = POSTag::unknown; - const Morpheme* morph = nullptr; + std::u16string str; /**< 형태 */ + uint32_t position = 0; /**< 시작 위치(UTF16 문자 기준) */ + uint16_t length = 0; /**< 길이(UTF16 문자 기준) */ + POSTag tag = POSTag::unknown; /**< 품사 태그 */ + const Morpheme* morph = nullptr; /**< 기타 형태소 정보에 대한 포인터 (OOV인 경우 nullptr) */ TokenInfo() = default; @@ -209,6 +247,10 @@ namespace kiwi } }; + /** + * @brief 분석 완료된 형태소의 목록(`std::vector`)과 점수(`float`)의 pair 타입 + * + */ using TokenResult = std::pair, float>; using U16Reader = std::function;