/**
 * 
 * APDPlat - Application Product Development Platform
 * Copyright (c) 2013, 杨尚川, yang-shangchuan@qq.com
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */

package org.apdplat.word.corpus;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apdplat.word.segmentation.Word;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 三元语法模型
 * @author 杨尚川
 */
public class Trigram {
    private static final Logger LOGGER = LoggerFactory.getLogger(Trigram.class);
    private static final Map<String, Float> TRIGRAM = new HashMap<>();
    /**
     * 计算分词结果的三元模型分值
     * @param words 分词结果
     * @return 三元模型分值
     */
    public static float trigram(List<Word> words){
        if(words.size() > 2){
            float score=0;
            for(int i=0; i<words.size()-2; i++){
                score += Trigram.getScore(words.get(i).getText(), words.get(i+1).getText(), words.get(i+2).getText());
            }
            return score;
        }
        return 0;
    }
    /**
     * 获取三个词前后紧挨着同时出现在语料库中的分值
     * @param first 第一个词
     * @param second 第二个词
     * @param third 第三个词
     * @return 同时出现的分值
     */
    public static float getScore(String first, String second, String third) {
        Float value = TRIGRAM.get(first+":"+second+":"+third);
        if(value == null){
            value = 0f;
        }
        if(value > 0){
            LOGGER.debug("三元模型 "+first+":"+second+" 获得分值："+value);
        }
        return value;
    }
    static{
        try{
            LOGGER.info("开始加载trigram文件");
            long start = System.currentTimeMillis();
            String trigramPath = System.getProperty("trigram.path");
            InputStream in = null;
            if(trigramPath == null){
                in = Trigram.class.getClassLoader().getResourceAsStream("trigram.txt");
                LOGGER.info("从类路径trigram.txt加载默认三元语法模型");
            }else{
                trigramPath = trigramPath.trim();
                if(trigramPath.startsWith("classpath:")){
                    in = Trigram.class.getClassLoader().getResourceAsStream(trigramPath.replace("classpath:", ""));
                }else{
                    in = new FileInputStream(trigramPath);
                }                    
            }
            try(BufferedReader reader = new BufferedReader(new InputStreamReader(in,"utf-8"));){
                String line;
                while( (line = reader.readLine()) != null ){
                    //去除首尾空白字符
                    line = line.trim();
                    //忽略空行
                    if(!"".equals(line)){
                        String[] attr = line.split(" -> ");
                        TRIGRAM.put(attr[0], Float.parseFloat(attr[1]));
                    }
                }
            }
            long cost = System.currentTimeMillis() - start;
            LOGGER.info("成功加载trigram文件，耗时："+cost+" 毫秒");
        }catch (IOException ex) {
            System.err.println("trigram文件装载失败:"+ex.getMessage());
            throw new RuntimeException(ex);
        }
    }
}
@@ -975,60 +975,12 @@
 til.
-HashMap;%0Aimport java.util.List;%0Aimport java.util.Map
+List
 ;%0Aim
@@ -1244,50 +1244,41 @@
 nal 
-Map%3CString, Float%3E TRIGRAM = new HashMap%3C%3E
+GramTrie GRAM_TRIE = new GramTrie
 ();%0A
@@ -1942,17 +1942,17 @@
         
-F
+f
 loat val
@@ -1956,23 +1956,25 @@
 value = 
-TRI
 GRAM
+_TRIE
 .get(fir
@@ -2016,23 +2016,19 @@
 f(value 
-== null
+%3E 0
 )%7B%0A     
@@ -2046,44 +2046,32 @@
 e = 
-0f;%0A        %7D%0A        if(value %3E 0)%7B
+(float)Math.sqrt(value);
 %0A   
@@ -2118,16 +2118,26 @@
 second+%22
+:%22+third+%22
  %E8%8E%B7%E5%BE%97%E5%88%86%E5%80%BC%EF%BC%9A%22+
@@ -3381,15 +3381,17 @@
     
-TRI
 GRAM
+_TRIE
 .put
@@ -3404,23 +3404,23 @@
 0%5D, 
-Float
+Integer
 .parse
-Floa
+In
 t(at

重构三元模型使用新的前缀树实现，对三元模型频率进行开方