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::hash_map; 27 using learning_stochastic_linear::StochasticLinearRanker; 28 using learning_stochastic_linear::SparseWeightVector; 29 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 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 51 void DecomposeSparseWeightVector(JNIEnv* env, jobjectArray *keys, jfloatArray *values, 52 const int length, 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 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 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 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 243 std::string ConvertFloat2String(float v){ 244 std::stringstream converter; 245 converter << v; 246 return converter.str(); 247 } 248 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 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, array_len, &M_weights); 384 } 385 386 jlong Java_android_bordeaux_learning_StochasticLinearRanker_initNativeClassifier(JNIEnv* env, 387 jobject thiz) { 388 StochasticLinearRanker<string>* classifier = new StochasticLinearRanker<string>(); 389 return ((jlong) classifier); 390 } 391 392 jboolean Java_android_bordeaux_learning_StochasticLinearRanker_deleteNativeClassifier(JNIEnv* env, 393 jobject thiz, 394 jlong paPtr) { 395 StochasticLinearRanker<string>* classifier = (StochasticLinearRanker<string>*) paPtr; 396 delete classifier; 397 return JNI_TRUE; 398 } 399 400 jboolean Java_android_bordeaux_learning_StochasticLinearRanker_nativeUpdateClassifier( 401 JNIEnv* env, 402 jobject thiz, 403 jobjectArray key_array_positive, 404 jfloatArray value_array_positive, 405 jobjectArray key_array_negative, 406 jfloatArray value_array_negative, 407 jlong paPtr) { 408 StochasticLinearRanker<string>* classifier = (StochasticLinearRanker<string>*) paPtr; 409 410 if (classifier && key_array_positive && value_array_positive && 411 key_array_negative && value_array_negative) { 412 413 const int keys_p_len = env->GetArrayLength(key_array_positive); 414 jfloat* values_p = env->GetFloatArrayElements(value_array_positive, NULL); 415 const int values_p_len = env->GetArrayLength(value_array_positive); 416 jfloat* values_n = env->GetFloatArrayElements(value_array_negative, NULL); 417 const int values_n_len = env->GetArrayLength(value_array_negative); 418 const int keys_n_len = env->GetArrayLength(key_array_negative); 419 420 if (values_p && key_array_positive && values_p_len == keys_p_len && 421 values_n && key_array_negative && values_n_len == keys_n_len) { 422 423 SparseWeightVector<string> sample_pos; 424 SparseWeightVector<string> sample_neg; 425 CreateSparseWeightVector(env, key_array_positive, values_p, values_p_len, &sample_pos); 426 CreateSparseWeightVector(env, key_array_negative, values_n, values_n_len, &sample_neg); 427 classifier->UpdateClassifier(sample_pos, sample_neg); 428 env->ReleaseFloatArrayElements(value_array_negative, values_n, JNI_ABORT); 429 env->ReleaseFloatArrayElements(value_array_positive, values_p, JNI_ABORT); 430 431 return JNI_TRUE; 432 } 433 env->ReleaseFloatArrayElements(value_array_negative, values_n, JNI_ABORT); 434 env->ReleaseFloatArrayElements(value_array_positive, values_p, JNI_ABORT); 435 } 436 return JNI_FALSE; 437 } 438 439 jfloat Java_android_bordeaux_learning_StochasticLinearRanker_nativeScoreSample( 440 JNIEnv* env, 441 jobject thiz, 442 jobjectArray key_array, 443 jfloatArray value_array, 444 jlong paPtr) { 445 446 StochasticLinearRanker<string>* classifier = (StochasticLinearRanker<string>*) paPtr; 447 448 if (classifier && key_array && value_array) { 449 450 jfloat* values = env->GetFloatArrayElements(value_array, NULL); 451 const int values_len = env->GetArrayLength(value_array); 452 const int keys_len = env->GetArrayLength(key_array); 453 454 if (values && key_array && values_len == keys_len) { 455 SparseWeightVector<string> sample; 456 CreateSparseWeightVector(env, key_array, values, values_len, &sample); 457 env->ReleaseFloatArrayElements(value_array, values, JNI_ABORT); 458 return classifier->ScoreSample(sample); 459 } 460 } 461 return -1; 462 } 463