• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *    http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "jni/jni_stochastic_linear_ranker.h"
18 #include "native/common_defs.h"
19 #include "native/sparse_weight_vector.h"
20 #include "native/stochastic_linear_ranker.h"
21 
22 #include <vector>
23 #include <string>
24 using std::string;
25 using std::vector;
26 using std::unordered_map;
27 using learning_stochastic_linear::StochasticLinearRanker;
28 using learning_stochastic_linear::SparseWeightVector;
29 
CreateSparseWeightVector(JNIEnv * env,const jobjectArray keys,const float * values,const int length,SparseWeightVector<string> * sample)30 void CreateSparseWeightVector(JNIEnv* env, const jobjectArray keys, const float* values,
31     const int length, SparseWeightVector<string> * sample) {
32 
33   for (int i = 0; i < length; ++i) {
34     jboolean iscopy;
35     jstring s = (jstring) env->GetObjectArrayElement(keys, i);
36     const char *key = env->GetStringUTFChars(s, &iscopy);
37     sample->SetElement(key, static_cast<double>(values[i]));
38     env->ReleaseStringUTFChars(s,key);
39   }
40 }
41 
ConvertParameter2Object(JNIEnv * env,jobjectArray * keys,jobjectArray * values,const char * name,const char * paramValue,int index)42 void ConvertParameter2Object(JNIEnv* env, jobjectArray *keys, jobjectArray *values,
43     const char * name , const char * paramValue, int index) {
44 
45     jstring jstrK = env->NewStringUTF(name);
46     jstring jstrV = env->NewStringUTF(paramValue);
47     env->SetObjectArrayElement(*keys, index, jstrK);
48     env->SetObjectArrayElement(*values, index, jstrV);
49 }
50 
DecomposeSparseWeightVector(JNIEnv * env,jobjectArray * keys,jfloatArray * values,SparseWeightVector<string> * sample)51 void DecomposeSparseWeightVector(JNIEnv* env, jobjectArray *keys, jfloatArray *values,
52     SparseWeightVector<string> *sample) {
53 
54   SparseWeightVector<string>::Wmap w_ = sample->GetMap();
55   int i=0;
56   for ( SparseWeightVector<string>::Witer_const iter = w_.begin();
57     iter != w_.end(); ++iter) {
58     std::string key = iter->first;
59     float value = (float) iter->second;
60     jstring jstr = env->NewStringUTF(key.c_str());
61     env->SetObjectArrayElement(*keys, i, jstr);
62     jfloat s[1];
63     s[0] = value;
64     env->SetFloatArrayRegion(*values, i, 1, s);
65     i++;
66   }
67 }
68 
Java_android_bordeaux_learning_StochasticLinearRanker_nativeSetWeightClassifier(JNIEnv * env,jobject,jobjectArray key_array_model,jfloatArray value_array_model,jfloat normalizer_model,jlong paPtr)69 jboolean Java_android_bordeaux_learning_StochasticLinearRanker_nativeSetWeightClassifier(
70     JNIEnv* env,
71     jobject /* thiz */,
72     jobjectArray key_array_model,
73     jfloatArray value_array_model,
74     jfloat normalizer_model,
75     jlong paPtr) {
76 
77   StochasticLinearRanker<string>* classifier = (StochasticLinearRanker<string>*) paPtr;
78   if (classifier && key_array_model && value_array_model && normalizer_model) {
79     const int keys_m_len = env->GetArrayLength(key_array_model);
80     jfloat* values_m = env->GetFloatArrayElements(value_array_model, NULL);
81     const int values_m_len = env->GetArrayLength(value_array_model);
82 
83     if (values_m && key_array_model && values_m_len == keys_m_len) {
84       SparseWeightVector<string> model;
85       CreateSparseWeightVector(env, key_array_model, values_m, values_m_len, &model);
86       model.SetNormalizer(normalizer_model);
87       classifier->LoadWeights(model);
88       env->ReleaseFloatArrayElements(value_array_model, values_m, JNI_ABORT);
89       return JNI_TRUE;
90     }
91   }
92   return JNI_FALSE;
93 }
94 
Java_android_bordeaux_learning_StochasticLinearRanker_nativeSetParameterClassifier(JNIEnv * env,jobject,jstring key,jstring value,jlong paPtr)95 jboolean Java_android_bordeaux_learning_StochasticLinearRanker_nativeSetParameterClassifier(
96     JNIEnv* env,
97     jobject /* thiz */,
98     jstring key,
99     jstring value,
100     jlong paPtr) {
101 
102   StochasticLinearRanker<string>* classifier = (StochasticLinearRanker<string>*) paPtr;
103   jboolean iscopy;
104   const char *cKey = env->GetStringUTFChars(key, &iscopy);
105   const char *cValue = env->GetStringUTFChars(value, &iscopy);
106   float v;
107   if (strcmp(cKey, ITR_NUM) == 0){
108     sscanf(cValue, "%f", &v);
109     classifier->SetIterationNumber((uint64) v);
110     return JNI_TRUE;
111   }
112   else if (strcmp(cKey, NORM_CONSTRAINT) == 0){
113     sscanf(cValue, "%f", &v);
114     classifier->SetNormConstraint((double) v);
115     return JNI_TRUE;
116   }
117   else if (strcmp(cKey, REG_TYPE) == 0){
118     if (strcmp(cValue, REG_TYPE_L0 ) == 0)
119       classifier->SetRegularizationType(learning_stochastic_linear::L0);
120     else if (strcmp(cValue, REG_TYPE_L1 ) == 0)
121       classifier->SetRegularizationType(learning_stochastic_linear::L1);
122     else if (strcmp(cValue, REG_TYPE_L2 ) == 0)
123       classifier->SetRegularizationType(learning_stochastic_linear::L2);
124     else if (strcmp(cValue, REG_TYPE_L1L2 ) == 0)
125       classifier->SetRegularizationType(learning_stochastic_linear::L1L2);
126     else if (strcmp(cValue, REG_TYPE_L1LInf ) == 0)
127       classifier->SetRegularizationType(learning_stochastic_linear::L1LInf);
128     else {
129       ALOGE("Error: %s is not a Regularization Type", cValue);
130       return JNI_FALSE;
131     }
132     return JNI_TRUE;
133   }
134   else if (strcmp(cKey, LAMBDA) == 0){
135     sscanf(cValue, "%f", &v);
136     classifier->SetLambda((double) v);
137     return JNI_TRUE;
138   }
139   else if (strcmp(cKey, UPDATE_TYPE) == 0){
140     if (strcmp(cValue, UPDATE_TYPE_FULL_CS) == 0)
141       classifier->SetUpdateType(learning_stochastic_linear::FULL_CS);
142     else if (strcmp(cValue, UPDATE_TYPE_CLIP_CS) == 0)
143       classifier->SetUpdateType(learning_stochastic_linear::CLIP_CS);
144     else if (strcmp(cValue, UPDATE_TYPE_REG_CS ) == 0)
145       classifier->SetUpdateType(learning_stochastic_linear::REG_CS);
146     else if (strcmp(cValue, UPDATE_TYPE_SL) == 0)
147       classifier->SetUpdateType(learning_stochastic_linear::SL);
148     else if (strcmp(cValue, UPDATE_TYPE_ADAPTIVE_REG) == 0)
149       classifier->SetUpdateType(learning_stochastic_linear::ADAPTIVE_REG);
150     else {
151       ALOGE("Error: %s is not an Update Type", cValue);
152       return JNI_FALSE;
153     }
154     return JNI_TRUE;
155   }
156   else if (strcmp(cKey, ADAPT_MODE) == 0){
157     if (strcmp(cValue, ADAPT_MODE_CONST ) == 0)
158       classifier->SetAdaptationMode(learning_stochastic_linear::CONST);
159     else if (strcmp(cValue, ADAPT_MODE_INV_LINEAR ) == 0)
160       classifier->SetAdaptationMode(learning_stochastic_linear::INV_LINEAR);
161     else if (strcmp(cValue, ADAPT_MODE_INV_QUADRATIC ) == 0)
162       classifier->SetAdaptationMode(learning_stochastic_linear::INV_QUADRATIC);
163     else if (strcmp(cValue, ADAPT_MODE_INV_SQRT ) == 0)
164       classifier->SetAdaptationMode(learning_stochastic_linear::INV_SQRT);
165     else {
166       ALOGE("Error: %s is not an Adaptation Mode", cValue);
167       return JNI_FALSE;
168     }
169     return JNI_TRUE;
170   }
171   else if (strcmp(cKey, KERNEL_TYPE) == 0){
172     if (strcmp(cValue, KERNEL_TYPE_LINEAR ) == 0)
173       classifier->SetKernelType(learning_stochastic_linear::LINEAR);
174     else if (strcmp(cValue, KERNEL_TYPE_POLY ) == 0)
175       classifier->SetKernelType(learning_stochastic_linear::POLY);
176     else if (strcmp(cValue, KERNEL_TYPE_RBF ) == 0)
177       classifier->SetKernelType(learning_stochastic_linear::RBF);
178     else {
179       ALOGE("Error: %s is not a Kernel Type", cValue);
180       return JNI_FALSE;
181     }
182     return JNI_TRUE;
183   }
184   else if (strcmp(cKey, KERNEL_PARAM) == 0){
185     sscanf(cValue, "%f", &v);
186     classifier->SetKernelParam((double) v);
187     return JNI_TRUE;
188   }
189   else if (strcmp(cKey, KERNEL_GAIN) == 0){
190     sscanf(cValue, "%f", &v);
191     classifier->SetKernelGain((double) v);
192     return JNI_TRUE;
193   }
194   else if (strcmp(cKey, KERNEL_BIAS) == 0){
195     sscanf(cValue, "%f", &v);
196     classifier->SetKernelBias((double) v);
197     return JNI_TRUE;
198   }
199   else if (strcmp(cKey, LOSS_TYPE) == 0){
200     if (strcmp(cValue, LOSS_TYPE_PAIRWISE ) == 0)
201       classifier->SetRankLossType(learning_stochastic_linear::PAIRWISE);
202     else if (strcmp(cValue, LOSS_TYPE_RECIPROCAL_RANK ) == 0)
203       classifier->SetRankLossType(learning_stochastic_linear::RECIPROCAL_RANK);
204     else {
205       ALOGE("Error: %s is not a Kernel Type", cValue);
206       return JNI_FALSE;
207     }
208     return JNI_TRUE;
209   }
210   else if (strcmp(cKey, ACC_PROB) == 0){
211     sscanf(cValue, "%f", &v);
212     classifier->SetAcceptanceProbability((double) v);
213     return JNI_TRUE;
214   }
215   else if (strcmp(cKey, MIN_BATCH_SIZE) == 0){
216     sscanf(cValue, "%f", &v);
217     classifier->SetMiniBatchSize((uint64) v);
218     return JNI_TRUE;
219   }
220   else if (strcmp(cKey, GRAD_L0_NORM) == 0){
221     sscanf(cValue, "%f", &v);
222     classifier->SetGradientL0Norm((int32) v);
223     return JNI_TRUE;
224   }
225   ALOGE("Error: %s is not a ranker parameter", cKey);
226   return JNI_FALSE;
227 }
228 
Java_android_bordeaux_learning_StochasticLinearRanker_nativeGetLengthClassifier(JNIEnv *,jobject,jlong paPtr)229 jint Java_android_bordeaux_learning_StochasticLinearRanker_nativeGetLengthClassifier(
230   JNIEnv* /* env */,
231   jobject /* thiz */,
232   jlong paPtr) {
233 
234   StochasticLinearRanker<string>* classifier = (StochasticLinearRanker<string>*) paPtr;
235   SparseWeightVector<string> M_weights;
236   classifier->SaveWeights(&M_weights);
237 
238   SparseWeightVector<string>::Wmap w_map = M_weights.GetMap();
239   int len = w_map.size();
240   return len;
241 }
242 
ConvertFloat2String(float v)243 std::string ConvertFloat2String(float v){
244     std::stringstream converter;
245     converter << v;
246     return converter.str();
247 }
248 
Java_android_bordeaux_learning_StochasticLinearRanker_nativeGetParameterClassifier(JNIEnv * env,jobject,jobjectArray key_array_param,jobjectArray value_array_param,jlong paPtr)249 void Java_android_bordeaux_learning_StochasticLinearRanker_nativeGetParameterClassifier(
250     JNIEnv* env,
251     jobject /* thiz */,
252     jobjectArray key_array_param,
253     jobjectArray value_array_param,
254     jlong paPtr){
255 
256   std::string s;
257   StochasticLinearRanker<string>* classifier = (StochasticLinearRanker<string>*) paPtr;
258   s = ConvertFloat2String((float) classifier->GetIterationNumber());
259   ConvertParameter2Object(env, &key_array_param, &value_array_param, ITR_NUM, s.c_str(), 0 );
260 
261   s = ConvertFloat2String((float) classifier->GetNormContraint());
262   ConvertParameter2Object(env, &key_array_param, &value_array_param, NORM_CONSTRAINT, s.c_str(), 1 );
263 
264   float value = (float) classifier->GetRegularizationType();
265   switch ((int) value) {
266     case learning_stochastic_linear::L0 :
267       s = REG_TYPE_L0;
268       break;
269     case learning_stochastic_linear::L1 :
270       s = REG_TYPE_L1;
271       break;
272     case learning_stochastic_linear::L2 :
273       s = REG_TYPE_L2;
274       break;
275     case learning_stochastic_linear::L1L2 :
276       s = REG_TYPE_L1L2;
277       break;
278     case learning_stochastic_linear::L1LInf :
279       s = REG_TYPE_L1LInf;
280       break;
281   }
282   ConvertParameter2Object(env, &key_array_param, &value_array_param, REG_TYPE, s.c_str(), 2 );
283 
284   s = ConvertFloat2String((float) classifier->GetLambda());
285   ConvertParameter2Object(env, &key_array_param, &value_array_param, LAMBDA, s.c_str(), 3 );
286 
287   value = (float) classifier->GetUpdateType();
288   switch ((int) value) {
289     case learning_stochastic_linear::FULL_CS :
290       s = UPDATE_TYPE_FULL_CS;
291       break;
292     case learning_stochastic_linear::CLIP_CS :
293       s = UPDATE_TYPE_CLIP_CS;
294       break;
295     case learning_stochastic_linear::REG_CS :
296       s = UPDATE_TYPE_REG_CS;
297       break;
298     case learning_stochastic_linear::SL :
299       s = UPDATE_TYPE_SL;
300       break;
301     case learning_stochastic_linear::ADAPTIVE_REG :
302       s = UPDATE_TYPE_ADAPTIVE_REG;
303       break;
304   }
305   ConvertParameter2Object(env, &key_array_param, &value_array_param, UPDATE_TYPE, s.c_str(), 4 );
306 
307   value = (float) classifier->GetAdaptationMode();
308   switch ((int) value) {
309     case learning_stochastic_linear::CONST :
310       s = ADAPT_MODE_CONST;
311       break;
312     case learning_stochastic_linear::INV_LINEAR :
313       s = ADAPT_MODE_INV_LINEAR;
314       break;
315     case learning_stochastic_linear::INV_QUADRATIC :
316       s = ADAPT_MODE_INV_QUADRATIC;
317       break;
318     case learning_stochastic_linear::INV_SQRT :
319       s = ADAPT_MODE_INV_SQRT;
320       break;
321   }
322   ConvertParameter2Object(env, &key_array_param, &value_array_param, ADAPT_MODE, s.c_str(), 5 );
323 
324   value = (float) classifier->GetKernelType();
325   switch ((int) value) {
326     case learning_stochastic_linear::LINEAR :
327       s = KERNEL_TYPE_LINEAR;
328       break;
329     case learning_stochastic_linear::POLY :
330       s = KERNEL_TYPE_POLY;
331       break;
332     case learning_stochastic_linear::RBF :
333       s = KERNEL_TYPE_RBF;
334       break;
335   }
336   ConvertParameter2Object(env, &key_array_param, &value_array_param, KERNEL_TYPE, s.c_str(), 6 );
337 
338   s = ConvertFloat2String((float) classifier->GetKernelParam());
339   ConvertParameter2Object(env, &key_array_param, &value_array_param, KERNEL_PARAM, s.c_str(), 7 );
340 
341   s = ConvertFloat2String((float) classifier->GetKernelGain());
342   ConvertParameter2Object(env, &key_array_param, &value_array_param, KERNEL_GAIN, s.c_str(), 8 );
343 
344   s = ConvertFloat2String((float)classifier->GetKernelBias());
345   ConvertParameter2Object(env, &key_array_param, &value_array_param, KERNEL_BIAS, s.c_str(), 9 );
346 
347   value = (float) classifier->GetRankLossType();
348   switch ((int) value) {
349     case learning_stochastic_linear::PAIRWISE :
350       s = LOSS_TYPE_PAIRWISE;
351       break;
352     case learning_stochastic_linear::RECIPROCAL_RANK :
353       s = LOSS_TYPE_RECIPROCAL_RANK;
354       break;
355   }
356   ConvertParameter2Object(env, &key_array_param, &value_array_param, LOSS_TYPE, s.c_str(), 10 );
357 
358   s = ConvertFloat2String((float) classifier->GetAcceptanceProbability());
359   ConvertParameter2Object(env, &key_array_param, &value_array_param, ACC_PROB, s.c_str(), 11 );
360 
361   s = ConvertFloat2String((float) classifier->GetMiniBatchSize());
362   ConvertParameter2Object(env, &key_array_param, &value_array_param, MIN_BATCH_SIZE, s.c_str(), 12 );
363 
364   s = ConvertFloat2String((float) classifier->GetGradientL0Norm());
365   ConvertParameter2Object(env, &key_array_param, &value_array_param, GRAD_L0_NORM, s.c_str(), 13 );
366 }
367 
Java_android_bordeaux_learning_StochasticLinearRanker_nativeGetWeightClassifier(JNIEnv * env,jobject,jobjectArray key_array_model,jfloatArray value_array_model,jfloat normalizer,jlong paPtr)368 void Java_android_bordeaux_learning_StochasticLinearRanker_nativeGetWeightClassifier(
369   JNIEnv* env,
370   jobject /* thiz */,
371   jobjectArray key_array_model,
372   jfloatArray value_array_model,
373   jfloat normalizer,
374   jlong paPtr) {
375 
376   StochasticLinearRanker<string>* classifier = (StochasticLinearRanker<string>*) paPtr;
377   SparseWeightVector<string> M_weights;
378   classifier->SaveWeights(&M_weights);
379   SparseWeightVector<string>::Wmap w_map = M_weights.GetMap();
380   int array_len = w_map.size();
381 
382   normalizer = M_weights.GetNormalizer();
383   DecomposeSparseWeightVector(env, &key_array_model, &value_array_model, &M_weights);
384 }
385 
Java_android_bordeaux_learning_StochasticLinearRanker_initNativeClassifier(JNIEnv *,jobject)386 jlong Java_android_bordeaux_learning_StochasticLinearRanker_initNativeClassifier(
387   JNIEnv* /* env */,
388   jobject /* thiz */) {
389   StochasticLinearRanker<string>* classifier = new StochasticLinearRanker<string>();
390   return ((jlong) classifier);
391 }
392 
Java_android_bordeaux_learning_StochasticLinearRanker_deleteNativeClassifier(JNIEnv *,jobject,jlong paPtr)393 jboolean Java_android_bordeaux_learning_StochasticLinearRanker_deleteNativeClassifier(
394   JNIEnv* /* env */,
395   jobject /* thiz */,
396   jlong paPtr) {
397   StochasticLinearRanker<string>* classifier = (StochasticLinearRanker<string>*) paPtr;
398   delete classifier;
399   return JNI_TRUE;
400 }
401 
Java_android_bordeaux_learning_StochasticLinearRanker_nativeUpdateClassifier(JNIEnv * env,jobject,jobjectArray key_array_positive,jfloatArray value_array_positive,jobjectArray key_array_negative,jfloatArray value_array_negative,jlong paPtr)402 jboolean Java_android_bordeaux_learning_StochasticLinearRanker_nativeUpdateClassifier(
403   JNIEnv* env,
404   jobject /* thiz */,
405   jobjectArray key_array_positive,
406   jfloatArray value_array_positive,
407   jobjectArray key_array_negative,
408   jfloatArray value_array_negative,
409   jlong paPtr) {
410   StochasticLinearRanker<string>* classifier = (StochasticLinearRanker<string>*) paPtr;
411 
412   if (classifier && key_array_positive && value_array_positive &&
413       key_array_negative && value_array_negative) {
414 
415     const int keys_p_len = env->GetArrayLength(key_array_positive);
416     jfloat* values_p = env->GetFloatArrayElements(value_array_positive, NULL);
417     const int values_p_len = env->GetArrayLength(value_array_positive);
418     jfloat* values_n = env->GetFloatArrayElements(value_array_negative, NULL);
419     const int values_n_len = env->GetArrayLength(value_array_negative);
420     const int keys_n_len = env->GetArrayLength(key_array_negative);
421 
422     if (values_p && key_array_positive && values_p_len == keys_p_len &&
423       values_n && key_array_negative && values_n_len == keys_n_len) {
424 
425       SparseWeightVector<string> sample_pos;
426       SparseWeightVector<string> sample_neg;
427       CreateSparseWeightVector(env, key_array_positive, values_p, values_p_len, &sample_pos);
428       CreateSparseWeightVector(env, key_array_negative, values_n, values_n_len, &sample_neg);
429       classifier->UpdateClassifier(sample_pos, sample_neg);
430       env->ReleaseFloatArrayElements(value_array_negative, values_n, JNI_ABORT);
431       env->ReleaseFloatArrayElements(value_array_positive, values_p, JNI_ABORT);
432 
433       return JNI_TRUE;
434     }
435     env->ReleaseFloatArrayElements(value_array_negative, values_n, JNI_ABORT);
436     env->ReleaseFloatArrayElements(value_array_positive, values_p, JNI_ABORT);
437   }
438   return JNI_FALSE;
439 }
440 
Java_android_bordeaux_learning_StochasticLinearRanker_nativeScoreSample(JNIEnv * env,jobject,jobjectArray key_array,jfloatArray value_array,jlong paPtr)441 jfloat Java_android_bordeaux_learning_StochasticLinearRanker_nativeScoreSample(
442   JNIEnv* env,
443   jobject /* thiz */,
444   jobjectArray key_array,
445   jfloatArray value_array,
446   jlong paPtr) {
447 
448   StochasticLinearRanker<string>* classifier = (StochasticLinearRanker<string>*) paPtr;
449 
450   if (classifier && key_array && value_array) {
451 
452     jfloat* values = env->GetFloatArrayElements(value_array, NULL);
453     const int values_len = env->GetArrayLength(value_array);
454     const int keys_len = env->GetArrayLength(key_array);
455 
456     if (values && key_array && values_len == keys_len) {
457       SparseWeightVector<string> sample;
458       CreateSparseWeightVector(env, key_array, values, values_len, &sample);
459       env->ReleaseFloatArrayElements(value_array, values, JNI_ABORT);
460       return classifier->ScoreSample(sample);
461     }
462   }
463   return -1;
464 }
465