Home | History | Annotate | Download | only in jni
      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 
     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     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   DecomposeSparseWeightVector(env, &key_array_model, &value_array_model, &M_weights);
    381 }
    382 
    383 jlong Java_android_bordeaux_learning_StochasticLinearRanker_initNativeClassifier(
    384   JNIEnv* /* env */,
    385   jobject /* thiz */) {
    386   StochasticLinearRanker<string>* classifier = new StochasticLinearRanker<string>();
    387   return ((jlong) classifier);
    388 }
    389 
    390 jboolean Java_android_bordeaux_learning_StochasticLinearRanker_deleteNativeClassifier(
    391   JNIEnv* /* env */,
    392   jobject /* thiz */,
    393   jlong paPtr) {
    394   StochasticLinearRanker<string>* classifier = (StochasticLinearRanker<string>*) paPtr;
    395   delete classifier;
    396   return JNI_TRUE;
    397 }
    398 
    399 jboolean Java_android_bordeaux_learning_StochasticLinearRanker_nativeUpdateClassifier(
    400   JNIEnv* env,
    401   jobject /* thiz */,
    402   jobjectArray key_array_positive,
    403   jfloatArray value_array_positive,
    404   jobjectArray key_array_negative,
    405   jfloatArray value_array_negative,
    406   jlong paPtr) {
    407   StochasticLinearRanker<string>* classifier = (StochasticLinearRanker<string>*) paPtr;
    408 
    409   if (classifier && key_array_positive && value_array_positive &&
    410       key_array_negative && value_array_negative) {
    411 
    412     const int keys_p_len = env->GetArrayLength(key_array_positive);
    413     jfloat* values_p = env->GetFloatArrayElements(value_array_positive, NULL);
    414     const int values_p_len = env->GetArrayLength(value_array_positive);
    415     jfloat* values_n = env->GetFloatArrayElements(value_array_negative, NULL);
    416     const int values_n_len = env->GetArrayLength(value_array_negative);
    417     const int keys_n_len = env->GetArrayLength(key_array_negative);
    418 
    419     if (values_p && key_array_positive && values_p_len == keys_p_len &&
    420       values_n && key_array_negative && values_n_len == keys_n_len) {
    421 
    422       SparseWeightVector<string> sample_pos;
    423       SparseWeightVector<string> sample_neg;
    424       CreateSparseWeightVector(env, key_array_positive, values_p, values_p_len, &sample_pos);
    425       CreateSparseWeightVector(env, key_array_negative, values_n, values_n_len, &sample_neg);
    426       classifier->UpdateClassifier(sample_pos, sample_neg);
    427       env->ReleaseFloatArrayElements(value_array_negative, values_n, JNI_ABORT);
    428       env->ReleaseFloatArrayElements(value_array_positive, values_p, JNI_ABORT);
    429 
    430       return JNI_TRUE;
    431     }
    432     env->ReleaseFloatArrayElements(value_array_negative, values_n, JNI_ABORT);
    433     env->ReleaseFloatArrayElements(value_array_positive, values_p, JNI_ABORT);
    434   }
    435   return JNI_FALSE;
    436 }
    437 
    438 jfloat Java_android_bordeaux_learning_StochasticLinearRanker_nativeScoreSample(
    439   JNIEnv* env,
    440   jobject /* thiz */,
    441   jobjectArray key_array,
    442   jfloatArray value_array,
    443   jlong paPtr) {
    444 
    445   StochasticLinearRanker<string>* classifier = (StochasticLinearRanker<string>*) paPtr;
    446 
    447   if (classifier && key_array && value_array) {
    448 
    449     jfloat* values = env->GetFloatArrayElements(value_array, NULL);
    450     const int values_len = env->GetArrayLength(value_array);
    451     const int keys_len = env->GetArrayLength(key_array);
    452 
    453     if (values && key_array && values_len == keys_len) {
    454       SparseWeightVector<string> sample;
    455       CreateSparseWeightVector(env, key_array, values, values_len, &sample);
    456       env->ReleaseFloatArrayElements(value_array, values, JNI_ABORT);
    457       return classifier->ScoreSample(sample);
    458     }
    459   }
    460   return -1;
    461 }
    462