blob: fd45edaa18755bddc341ac2df5c612593562e300 [file] [log] [blame]
/*
* 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;
}