| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "jni/jni_stochastic_linear_ranker.h" |
| #include "native/common_defs.h" |
| #include "native/sparse_weight_vector.h" |
| #include "native/stochastic_linear_ranker.h" |
| |
| #include <vector> |
| #include <string> |
| using std::string; |
| using std::vector; |
| using std::unordered_map; |
| using learning_stochastic_linear::StochasticLinearRanker; |
| using learning_stochastic_linear::SparseWeightVector; |
| |
| void CreateSparseWeightVector(JNIEnv* env, const jobjectArray keys, const float* values, |
| const int length, SparseWeightVector<string> * sample) { |
| |
| for (int i = 0; i < length; ++i) { |
| jboolean iscopy; |
| jstring s = (jstring) env->GetObjectArrayElement(keys, i); |
| const char *key = env->GetStringUTFChars(s, &iscopy); |
| sample->SetElement(key, static_cast<double>(values[i])); |
| env->ReleaseStringUTFChars(s,key); |
| } |
| } |
| |
| void ConvertParameter2Object(JNIEnv* env, jobjectArray *keys, jobjectArray *values, |
| const char * name , const char * paramValue, int index) { |
| |
| jstring jstrK = env->NewStringUTF(name); |
| jstring jstrV = env->NewStringUTF(paramValue); |
| env->SetObjectArrayElement(*keys, index, jstrK); |
| env->SetObjectArrayElement(*values, index, jstrV); |
| } |
| |
| void DecomposeSparseWeightVector(JNIEnv* env, jobjectArray *keys, jfloatArray *values, |
| SparseWeightVector<string> *sample) { |
| |
| SparseWeightVector<string>::Wmap w_ = sample->GetMap(); |
| int i=0; |
| for ( SparseWeightVector<string>::Witer_const iter = w_.begin(); |
| iter != w_.end(); ++iter) { |
| std::string key = iter->first; |
| float value = (float) iter->second; |
| jstring jstr = env->NewStringUTF(key.c_str()); |
| env->SetObjectArrayElement(*keys, i, jstr); |
| jfloat s[1]; |
| s[0] = value; |
| env->SetFloatArrayRegion(*values, i, 1, s); |
| i++; |
| } |
| } |
| |
| jboolean Java_android_bordeaux_learning_StochasticLinearRanker_nativeSetWeightClassifier( |
| JNIEnv* env, |
| jobject /* thiz */, |
| jobjectArray key_array_model, |
| jfloatArray value_array_model, |
| jfloat normalizer_model, |
| jlong paPtr) { |
| |
| StochasticLinearRanker<string>* classifier = (StochasticLinearRanker<string>*) paPtr; |
| if (classifier && key_array_model && value_array_model && normalizer_model) { |
| const int keys_m_len = env->GetArrayLength(key_array_model); |
| jfloat* values_m = env->GetFloatArrayElements(value_array_model, NULL); |
| const int values_m_len = env->GetArrayLength(value_array_model); |
| |
| if (values_m && key_array_model && values_m_len == keys_m_len) { |
| SparseWeightVector<string> model; |
| CreateSparseWeightVector(env, key_array_model, values_m, values_m_len, &model); |
| model.SetNormalizer(normalizer_model); |
| classifier->LoadWeights(model); |
| env->ReleaseFloatArrayElements(value_array_model, values_m, JNI_ABORT); |
| return JNI_TRUE; |
| } |
| } |
| return JNI_FALSE; |
| } |
| |
| jboolean Java_android_bordeaux_learning_StochasticLinearRanker_nativeSetParameterClassifier( |
| JNIEnv* env, |
| jobject /* thiz */, |
| jstring key, |
| jstring value, |
| jlong paPtr) { |
| |
| StochasticLinearRanker<string>* classifier = (StochasticLinearRanker<string>*) paPtr; |
| jboolean iscopy; |
| const char *cKey = env->GetStringUTFChars(key, &iscopy); |
| const char *cValue = env->GetStringUTFChars(value, &iscopy); |
| float v; |
| if (strcmp(cKey, ITR_NUM) == 0){ |
| sscanf(cValue, "%f", &v); |
| classifier->SetIterationNumber((uint64) v); |
| return JNI_TRUE; |
| } |
| else if (strcmp(cKey, NORM_CONSTRAINT) == 0){ |
| sscanf(cValue, "%f", &v); |
| classifier->SetNormConstraint((double) v); |
| return JNI_TRUE; |
| } |
| else if (strcmp(cKey, REG_TYPE) == 0){ |
| if (strcmp(cValue, REG_TYPE_L0 ) == 0) |
| classifier->SetRegularizationType(learning_stochastic_linear::L0); |
| else if (strcmp(cValue, REG_TYPE_L1 ) == 0) |
| classifier->SetRegularizationType(learning_stochastic_linear::L1); |
| else if (strcmp(cValue, REG_TYPE_L2 ) == 0) |
| classifier->SetRegularizationType(learning_stochastic_linear::L2); |
| else if (strcmp(cValue, REG_TYPE_L1L2 ) == 0) |
| classifier->SetRegularizationType(learning_stochastic_linear::L1L2); |
| else if (strcmp(cValue, REG_TYPE_L1LInf ) == 0) |
| classifier->SetRegularizationType(learning_stochastic_linear::L1LInf); |
| else { |
| ALOGE("Error: %s is not a Regularization Type", cValue); |
| return JNI_FALSE; |
| } |
| return JNI_TRUE; |
| } |
| else if (strcmp(cKey, LAMBDA) == 0){ |
| sscanf(cValue, "%f", &v); |
| classifier->SetLambda((double) v); |
| return JNI_TRUE; |
| } |
| else if (strcmp(cKey, UPDATE_TYPE) == 0){ |
| if (strcmp(cValue, UPDATE_TYPE_FULL_CS) == 0) |
| classifier->SetUpdateType(learning_stochastic_linear::FULL_CS); |
| else if (strcmp(cValue, UPDATE_TYPE_CLIP_CS) == 0) |
| classifier->SetUpdateType(learning_stochastic_linear::CLIP_CS); |
| else if (strcmp(cValue, UPDATE_TYPE_REG_CS ) == 0) |
| classifier->SetUpdateType(learning_stochastic_linear::REG_CS); |
| else if (strcmp(cValue, UPDATE_TYPE_SL) == 0) |
| classifier->SetUpdateType(learning_stochastic_linear::SL); |
| else if (strcmp(cValue, UPDATE_TYPE_ADAPTIVE_REG) == 0) |
| classifier->SetUpdateType(learning_stochastic_linear::ADAPTIVE_REG); |
| else { |
| ALOGE("Error: %s is not an Update Type", cValue); |
| return JNI_FALSE; |
| } |
| return JNI_TRUE; |
| } |
| else if (strcmp(cKey, ADAPT_MODE) == 0){ |
| if (strcmp(cValue, ADAPT_MODE_CONST ) == 0) |
| classifier->SetAdaptationMode(learning_stochastic_linear::CONST); |
| else if (strcmp(cValue, ADAPT_MODE_INV_LINEAR ) == 0) |
| classifier->SetAdaptationMode(learning_stochastic_linear::INV_LINEAR); |
| else if (strcmp(cValue, ADAPT_MODE_INV_QUADRATIC ) == 0) |
| classifier->SetAdaptationMode(learning_stochastic_linear::INV_QUADRATIC); |
| else if (strcmp(cValue, ADAPT_MODE_INV_SQRT ) == 0) |
| classifier->SetAdaptationMode(learning_stochastic_linear::INV_SQRT); |
| else { |
| ALOGE("Error: %s is not an Adaptation Mode", cValue); |
| return JNI_FALSE; |
| } |
| return JNI_TRUE; |
| } |
| else if (strcmp(cKey, KERNEL_TYPE) == 0){ |
| if (strcmp(cValue, KERNEL_TYPE_LINEAR ) == 0) |
| classifier->SetKernelType(learning_stochastic_linear::LINEAR); |
| else if (strcmp(cValue, KERNEL_TYPE_POLY ) == 0) |
| classifier->SetKernelType(learning_stochastic_linear::POLY); |
| else if (strcmp(cValue, KERNEL_TYPE_RBF ) == 0) |
| classifier->SetKernelType(learning_stochastic_linear::RBF); |
| else { |
| ALOGE("Error: %s is not a Kernel Type", cValue); |
| return JNI_FALSE; |
| } |
| return JNI_TRUE; |
| } |
| else if (strcmp(cKey, KERNEL_PARAM) == 0){ |
| sscanf(cValue, "%f", &v); |
| classifier->SetKernelParam((double) v); |
| return JNI_TRUE; |
| } |
| else if (strcmp(cKey, KERNEL_GAIN) == 0){ |
| sscanf(cValue, "%f", &v); |
| classifier->SetKernelGain((double) v); |
| return JNI_TRUE; |
| } |
| else if (strcmp(cKey, KERNEL_BIAS) == 0){ |
| sscanf(cValue, "%f", &v); |
| classifier->SetKernelBias((double) v); |
| return JNI_TRUE; |
| } |
| else if (strcmp(cKey, LOSS_TYPE) == 0){ |
| if (strcmp(cValue, LOSS_TYPE_PAIRWISE ) == 0) |
| classifier->SetRankLossType(learning_stochastic_linear::PAIRWISE); |
| else if (strcmp(cValue, LOSS_TYPE_RECIPROCAL_RANK ) == 0) |
| classifier->SetRankLossType(learning_stochastic_linear::RECIPROCAL_RANK); |
| else { |
| ALOGE("Error: %s is not a Kernel Type", cValue); |
| return JNI_FALSE; |
| } |
| return JNI_TRUE; |
| } |
| else if (strcmp(cKey, ACC_PROB) == 0){ |
| sscanf(cValue, "%f", &v); |
| classifier->SetAcceptanceProbability((double) v); |
| return JNI_TRUE; |
| } |
| else if (strcmp(cKey, MIN_BATCH_SIZE) == 0){ |
| sscanf(cValue, "%f", &v); |
| classifier->SetMiniBatchSize((uint64) v); |
| return JNI_TRUE; |
| } |
| else if (strcmp(cKey, GRAD_L0_NORM) == 0){ |
| sscanf(cValue, "%f", &v); |
| classifier->SetGradientL0Norm((int32) v); |
| return JNI_TRUE; |
| } |
| ALOGE("Error: %s is not a ranker parameter", cKey); |
| return JNI_FALSE; |
| } |
| |
| jint Java_android_bordeaux_learning_StochasticLinearRanker_nativeGetLengthClassifier( |
| JNIEnv* /* env */, |
| jobject /* thiz */, |
| jlong paPtr) { |
| |
| StochasticLinearRanker<string>* classifier = (StochasticLinearRanker<string>*) paPtr; |
| SparseWeightVector<string> M_weights; |
| classifier->SaveWeights(&M_weights); |
| |
| SparseWeightVector<string>::Wmap w_map = M_weights.GetMap(); |
| int len = w_map.size(); |
| return len; |
| } |
| |
| std::string ConvertFloat2String(float v){ |
| std::stringstream converter; |
| converter << v; |
| return converter.str(); |
| } |
| |
| void Java_android_bordeaux_learning_StochasticLinearRanker_nativeGetParameterClassifier( |
| JNIEnv* env, |
| jobject /* thiz */, |
| jobjectArray key_array_param, |
| jobjectArray value_array_param, |
| jlong paPtr){ |
| |
| std::string s; |
| StochasticLinearRanker<string>* classifier = (StochasticLinearRanker<string>*) paPtr; |
| s = ConvertFloat2String((float) classifier->GetIterationNumber()); |
| ConvertParameter2Object(env, &key_array_param, &value_array_param, ITR_NUM, s.c_str(), 0 ); |
| |
| s = ConvertFloat2String((float) classifier->GetNormContraint()); |
| ConvertParameter2Object(env, &key_array_param, &value_array_param, NORM_CONSTRAINT, s.c_str(), 1 ); |
| |
| float value = (float) classifier->GetRegularizationType(); |
| switch ((int) value) { |
| case learning_stochastic_linear::L0 : |
| s = REG_TYPE_L0; |
| break; |
| case learning_stochastic_linear::L1 : |
| s = REG_TYPE_L1; |
| break; |
| case learning_stochastic_linear::L2 : |
| s = REG_TYPE_L2; |
| break; |
| case learning_stochastic_linear::L1L2 : |
| s = REG_TYPE_L1L2; |
| break; |
| case learning_stochastic_linear::L1LInf : |
| s = REG_TYPE_L1LInf; |
| break; |
| } |
| ConvertParameter2Object(env, &key_array_param, &value_array_param, REG_TYPE, s.c_str(), 2 ); |
| |
| s = ConvertFloat2String((float) classifier->GetLambda()); |
| ConvertParameter2Object(env, &key_array_param, &value_array_param, LAMBDA, s.c_str(), 3 ); |
| |
| value = (float) classifier->GetUpdateType(); |
| switch ((int) value) { |
| case learning_stochastic_linear::FULL_CS : |
| s = UPDATE_TYPE_FULL_CS; |
| break; |
| case learning_stochastic_linear::CLIP_CS : |
| s = UPDATE_TYPE_CLIP_CS; |
| break; |
| case learning_stochastic_linear::REG_CS : |
| s = UPDATE_TYPE_REG_CS; |
| break; |
| case learning_stochastic_linear::SL : |
| s = UPDATE_TYPE_SL; |
| break; |
| case learning_stochastic_linear::ADAPTIVE_REG : |
| s = UPDATE_TYPE_ADAPTIVE_REG; |
| break; |
| } |
| ConvertParameter2Object(env, &key_array_param, &value_array_param, UPDATE_TYPE, s.c_str(), 4 ); |
| |
| value = (float) classifier->GetAdaptationMode(); |
| switch ((int) value) { |
| case learning_stochastic_linear::CONST : |
| s = ADAPT_MODE_CONST; |
| break; |
| case learning_stochastic_linear::INV_LINEAR : |
| s = ADAPT_MODE_INV_LINEAR; |
| break; |
| case learning_stochastic_linear::INV_QUADRATIC : |
| s = ADAPT_MODE_INV_QUADRATIC; |
| break; |
| case learning_stochastic_linear::INV_SQRT : |
| s = ADAPT_MODE_INV_SQRT; |
| break; |
| } |
| ConvertParameter2Object(env, &key_array_param, &value_array_param, ADAPT_MODE, s.c_str(), 5 ); |
| |
| value = (float) classifier->GetKernelType(); |
| switch ((int) value) { |
| case learning_stochastic_linear::LINEAR : |
| s = KERNEL_TYPE_LINEAR; |
| break; |
| case learning_stochastic_linear::POLY : |
| s = KERNEL_TYPE_POLY; |
| break; |
| case learning_stochastic_linear::RBF : |
| s = KERNEL_TYPE_RBF; |
| break; |
| } |
| ConvertParameter2Object(env, &key_array_param, &value_array_param, KERNEL_TYPE, s.c_str(), 6 ); |
| |
| s = ConvertFloat2String((float) classifier->GetKernelParam()); |
| ConvertParameter2Object(env, &key_array_param, &value_array_param, KERNEL_PARAM, s.c_str(), 7 ); |
| |
| s = ConvertFloat2String((float) classifier->GetKernelGain()); |
| ConvertParameter2Object(env, &key_array_param, &value_array_param, KERNEL_GAIN, s.c_str(), 8 ); |
| |
| s = ConvertFloat2String((float)classifier->GetKernelBias()); |
| ConvertParameter2Object(env, &key_array_param, &value_array_param, KERNEL_BIAS, s.c_str(), 9 ); |
| |
| value = (float) classifier->GetRankLossType(); |
| switch ((int) value) { |
| case learning_stochastic_linear::PAIRWISE : |
| s = LOSS_TYPE_PAIRWISE; |
| break; |
| case learning_stochastic_linear::RECIPROCAL_RANK : |
| s = LOSS_TYPE_RECIPROCAL_RANK; |
| break; |
| } |
| ConvertParameter2Object(env, &key_array_param, &value_array_param, LOSS_TYPE, s.c_str(), 10 ); |
| |
| s = ConvertFloat2String((float) classifier->GetAcceptanceProbability()); |
| ConvertParameter2Object(env, &key_array_param, &value_array_param, ACC_PROB, s.c_str(), 11 ); |
| |
| s = ConvertFloat2String((float) classifier->GetMiniBatchSize()); |
| ConvertParameter2Object(env, &key_array_param, &value_array_param, MIN_BATCH_SIZE, s.c_str(), 12 ); |
| |
| s = ConvertFloat2String((float) classifier->GetGradientL0Norm()); |
| ConvertParameter2Object(env, &key_array_param, &value_array_param, GRAD_L0_NORM, s.c_str(), 13 ); |
| } |
| |
| void Java_android_bordeaux_learning_StochasticLinearRanker_nativeGetWeightClassifier( |
| JNIEnv* env, |
| jobject /* thiz */, |
| jobjectArray key_array_model, |
| jfloatArray value_array_model, |
| jfloat normalizer, |
| jlong paPtr) { |
| |
| StochasticLinearRanker<string>* classifier = (StochasticLinearRanker<string>*) paPtr; |
| SparseWeightVector<string> M_weights; |
| classifier->SaveWeights(&M_weights); |
| SparseWeightVector<string>::Wmap w_map = M_weights.GetMap(); |
| int array_len = w_map.size(); |
| |
| normalizer = M_weights.GetNormalizer(); |
| DecomposeSparseWeightVector(env, &key_array_model, &value_array_model, &M_weights); |
| } |
| |
| jlong Java_android_bordeaux_learning_StochasticLinearRanker_initNativeClassifier( |
| JNIEnv* /* env */, |
| jobject /* thiz */) { |
| StochasticLinearRanker<string>* classifier = new StochasticLinearRanker<string>(); |
| return ((jlong) classifier); |
| } |
| |
| jboolean Java_android_bordeaux_learning_StochasticLinearRanker_deleteNativeClassifier( |
| JNIEnv* /* env */, |
| jobject /* thiz */, |
| jlong paPtr) { |
| StochasticLinearRanker<string>* classifier = (StochasticLinearRanker<string>*) paPtr; |
| delete classifier; |
| return JNI_TRUE; |
| } |
| |
| jboolean Java_android_bordeaux_learning_StochasticLinearRanker_nativeUpdateClassifier( |
| JNIEnv* env, |
| jobject /* thiz */, |
| jobjectArray key_array_positive, |
| jfloatArray value_array_positive, |
| jobjectArray key_array_negative, |
| jfloatArray value_array_negative, |
| jlong paPtr) { |
| StochasticLinearRanker<string>* classifier = (StochasticLinearRanker<string>*) paPtr; |
| |
| if (classifier && key_array_positive && value_array_positive && |
| key_array_negative && value_array_negative) { |
| |
| const int keys_p_len = env->GetArrayLength(key_array_positive); |
| jfloat* values_p = env->GetFloatArrayElements(value_array_positive, NULL); |
| const int values_p_len = env->GetArrayLength(value_array_positive); |
| jfloat* values_n = env->GetFloatArrayElements(value_array_negative, NULL); |
| const int values_n_len = env->GetArrayLength(value_array_negative); |
| const int keys_n_len = env->GetArrayLength(key_array_negative); |
| |
| if (values_p && key_array_positive && values_p_len == keys_p_len && |
| values_n && key_array_negative && values_n_len == keys_n_len) { |
| |
| SparseWeightVector<string> sample_pos; |
| SparseWeightVector<string> sample_neg; |
| CreateSparseWeightVector(env, key_array_positive, values_p, values_p_len, &sample_pos); |
| CreateSparseWeightVector(env, key_array_negative, values_n, values_n_len, &sample_neg); |
| classifier->UpdateClassifier(sample_pos, sample_neg); |
| env->ReleaseFloatArrayElements(value_array_negative, values_n, JNI_ABORT); |
| env->ReleaseFloatArrayElements(value_array_positive, values_p, JNI_ABORT); |
| |
| return JNI_TRUE; |
| } |
| env->ReleaseFloatArrayElements(value_array_negative, values_n, JNI_ABORT); |
| env->ReleaseFloatArrayElements(value_array_positive, values_p, JNI_ABORT); |
| } |
| return JNI_FALSE; |
| } |
| |
| jfloat Java_android_bordeaux_learning_StochasticLinearRanker_nativeScoreSample( |
| JNIEnv* env, |
| jobject /* thiz */, |
| jobjectArray key_array, |
| jfloatArray value_array, |
| jlong paPtr) { |
| |
| StochasticLinearRanker<string>* classifier = (StochasticLinearRanker<string>*) paPtr; |
| |
| if (classifier && key_array && value_array) { |
| |
| jfloat* values = env->GetFloatArrayElements(value_array, NULL); |
| const int values_len = env->GetArrayLength(value_array); |
| const int keys_len = env->GetArrayLength(key_array); |
| |
| if (values && key_array && values_len == keys_len) { |
| SparseWeightVector<string> sample; |
| CreateSparseWeightVector(env, key_array, values, values_len, &sample); |
| env->ReleaseFloatArrayElements(value_array, values, JNI_ABORT); |
| return classifier->ScoreSample(sample); |
| } |
| } |
| return -1; |
| } |