1 /**
2  * userphrase.c
3  *
4  * Copyright (c) 1999, 2000, 2001
5  *	Lu-chuan Kung and Kang-pen Chen.
6  *	All rights reserved.
7  *
8  * Copyright (c) 2004
9  *	libchewing Core Team. See ChangeLog for details.
10  *
11  * See the file "COPYING" for information on usage and redistribution
12  * of this file.
13  */
14 
15 #include <stdlib.h>
16 #include <time.h>
17 #include <string.h>
18 
19 #include "global.h"
20 #include "hash.h"
21 #include "dict.h"
22 #include "private.h"
23 
24 extern int chewing_lifetime;
25 static HASH_ITEM *pItemLast;
26 
DeltaFreq(int recentTime)27 int DeltaFreq( int recentTime )
28 {
29 	int diff;
30 
31 	diff = ( chewing_lifetime - recentTime );
32 
33 	if ( diff < 1000 )
34 		return ( 1500 - diff ); /* 1500 ~ 500 */
35 	if ( diff < 2000 )
36 		return ( 500 );       /* 500 ~ 500 */
37 	if ( diff < 3000 )
38 		return ( 2500 - diff ); /* 500 ~ -500 */
39 	return ( -500 );    /* -500 forever */
40 }
41 
42 /* load the orginal frequency from the static dict */
LoadOriginalFreq(const uint16 phoneSeq[],const char wordSeq[],int len)43 int LoadOriginalFreq( const uint16 phoneSeq[], const char wordSeq[], int len )
44 {
45 	int pho_id;
46 	int retval;
47 	Phrase *phrase = ALC( Phrase, 1 );
48 
49 	pho_id = TreeFindPhrase( 0, len - 1, phoneSeq );
50 	if ( pho_id != -1 ) {
51 		GetPhraseFirst( phrase, pho_id );
52 		do {
53 			/* find the same phrase */
54 			if ( ! memcmp(
55 				phrase->phrase,
56 				wordSeq,
57 				len * 2 * sizeof( char ) ) ) {
58 				retval = phrase->freq;
59 				free( phrase );
60 				return retval;
61 			}
62 		} while ( GetPhraseNext( phrase ) );
63 	}
64 
65 	return FREQ_INIT_VALUE;
66 }
67 
68 /* find the maximum frequency of the same phrase */
LoadMaxFreq(const uint16 phoneSeq[],int len)69 int LoadMaxFreq( const uint16 phoneSeq[], int len )
70 {
71 	int pho_id;
72 	Phrase *phrase = ALC( Phrase, 1 );
73 	int maxFreq = FREQ_INIT_VALUE;
74 	UserPhraseData *uphrase;
75 
76 	pho_id = TreeFindPhrase( 0, len - 1, phoneSeq );
77 	if ( pho_id != -1 ) {
78 		GetPhraseFirst( phrase, pho_id );
79 		do {
80 			if ( phrase->freq > maxFreq )
81 				maxFreq = phrase->freq;
82 		} while( GetPhraseNext( phrase ) );
83 	}
84 	free( phrase );
85 
86 	uphrase = UserGetPhraseFirst( phoneSeq );
87 	while ( uphrase ) {
88 		if ( uphrase->userfreq > maxFreq )
89 			maxFreq = uphrase->userfreq;
90 		uphrase = UserGetPhraseNext( phoneSeq );
91 	}
92 
93 	return maxFreq;
94 }
95 
96 /* compute the new updated freqency */
UpdateFreq(int freq,int maxfreq,int origfreq,int deltatime)97 int UpdateFreq( int freq, int maxfreq, int origfreq, int deltatime )
98 {
99 	int delta;
100 
101 	/* Short interval */
102 	if ( deltatime < 4000 ) {
103 		delta = ( freq >= maxfreq ) ?
104 			min(
105 				( maxfreq - origfreq ) / 5 + 1,
106 				SHORT_INCREASE_FREQ ) :
107 			max(
108 				( maxfreq - origfreq ) / 5 + 1,
109 				SHORT_INCREASE_FREQ );
110 		return min( freq + delta, MAX_ALLOW_FREQ );
111 	}
112 	/* Medium interval */
113 	else if ( deltatime < 50000 ) {
114 		delta = ( freq >= maxfreq ) ?
115 			min(
116 				( maxfreq - origfreq ) / 10 + 1,
117 				MEDIUM_INCREASE_FREQ ) :
118 			max(
119 				( maxfreq - origfreq ) / 10 + 1,
120 				MEDIUM_INCREASE_FREQ );
121 		return min( freq + delta, MAX_ALLOW_FREQ );
122 	}
123 	/* long interval */
124 	else {
125 		delta = max( ( freq - origfreq ) / 5, LONG_DECREASE_FREQ );
126 		return max( freq - delta, origfreq );
127 	}
128 }
129 
UserUpdatePhrase(const uint16 phoneSeq[],const char wordSeq[])130 int UserUpdatePhrase( const uint16 phoneSeq[], const char wordSeq[] )
131 {
132 	HASH_ITEM *pItem;
133 	UserPhraseData data;
134 	int len;
135 
136 	len = strlen( wordSeq ) / 2;
137 	pItem = HashFindEntry( phoneSeq, wordSeq );
138 	if ( ! pItem ) {
139 		if ( ! AlcUserPhraseSeq( &data, len ) ) {
140 			return USER_UPDATE_FAIL;
141 		}
142 
143 		memcpy( data.phoneSeq, phoneSeq, len * sizeof( phoneSeq[ 0 ] ) );
144 		data.phoneSeq[ len ] = 0;
145 		strcpy( data.wordSeq, wordSeq );
146 
147 		/* load initial freq */
148 		data.origfreq = LoadOriginalFreq( phoneSeq, wordSeq, len );
149 		data.maxfreq = LoadMaxFreq( phoneSeq, len );
150 
151 		data.userfreq = data.origfreq;
152 		data.recentTime = chewing_lifetime;
153 		pItem = HashInsert( &data );
154 		HashModify( pItem );
155 		return USER_UPDATE_INSERT;
156 	}
157 	else {
158 		pItem->data.maxfreq = LoadMaxFreq( phoneSeq, len );
159 		pItem->data.userfreq = UpdateFreq(
160 			pItem->data.userfreq,
161 			pItem->data.maxfreq,
162 			pItem->data.origfreq,
163 			chewing_lifetime - pItem->data.recentTime );
164 		pItem->data.recentTime = chewing_lifetime;
165 		HashModify( pItem );
166 		return USER_UPDATE_MODIFY;
167 	}
168 }
169 
UserGetPhraseFirst(const uint16 phoneSeq[])170 UserPhraseData *UserGetPhraseFirst( const uint16 phoneSeq[] )
171 {
172 	pItemLast = HashFindPhonePhrase( phoneSeq, NULL );
173 	if ( ! pItemLast )
174 		return NULL;
175 	return &( pItemLast->data );
176 }
177 
UserGetPhraseNext(const uint16 phoneSeq[])178 UserPhraseData *UserGetPhraseNext( const uint16 phoneSeq[] )
179 {
180 	pItemLast = HashFindPhonePhrase( phoneSeq, pItemLast );
181 	if ( ! pItemLast )
182 		return NULL;
183 	return &( pItemLast->data );
184 }
185 
186