📄 kernel.c
字号:
/**
* JNI Kernel Extension for SVMlight - http://www.aifb.uni-karlsruhe.de/WBS/sbl/software/jnikernel/
* v0.9 (c) 19.01.2007 Stephan Bloehdorn, Institute AIFB, University of Karlsruhe, Germany
* v1.0 (c) 25.05.2007 Stephan Bloehdorn, Institute AIFB, University of Karlsruhe, Germany
* v1.1 (c) 29.05.2007 Stephan Bloehdorn, Institute AIFB, University of Karlsruhe, Germany
* v1.2 (c) 04.07.2007 Stephan Bloehdorn, Institute AIFB, University of Karlsruhe, Germany
*/
extern "C" {
# include "svm_common.h"
# include "kernel.h"
}
#include <stdlib.h>
#include <stdio.h>
#include <jni.h>
#include <map>
#include <math.h>
#define __VERSION "v1.2"
#define __MAX_LINE 1024
#define __MANAGERCLASS "edu/unika/aifb/jnikernel/KernelManager"
#define __CLASS_PARAM "jnikernel.class"
#define __OPTION_PARAM "jvm.option"
#define __NORMALIZE_PARAM "jnikernel.normalize"
using namespace std;
bool initialized = false;
//jvm references
JNIEnv *env;
JavaVM *jvm;
//backend references
jclass backend;
jmethodID m_initialize;
jmethodID m_evaluate;
// cosine normalization options and cache
bool normalize = false;
//REMOVE map<void*, double> norms;
//functions
void initialize(char* param);
void printErrorAndExit(char* message);
void printFileErrorAndExit(char* param);
extern "C" double custom_kernel(KERNEL_PARM *kernel_parm, SVECTOR *a, SVECTOR *b){
if(!initialized) initialize(kernel_parm->custom);
//determine number of array elements...
int anum = 0;
int bnum = 0;
WORD *wordpointer;
wordpointer=a->words;
while (wordpointer->wnum){
anum++;
wordpointer++;
}
wordpointer=b->words;
while (wordpointer->wnum){
bnum++;
wordpointer++;
}
//create java arrays and copy values
jlongArray arg1indicesJ = env->NewLongArray(anum);
jfloatArray arg1valuesJ = env->NewFloatArray(anum);
jlongArray arg2indicesJ = env->NewLongArray(bnum);
jfloatArray arg2valuesJ = env->NewFloatArray(bnum);
if (arg1indicesJ==NULL||arg2indicesJ==NULL||arg1valuesJ==NULL||arg2valuesJ==NULL){
if (env->ExceptionCheck()){
printf("\n");
env->ExceptionDescribe();
}
printErrorAndExit("Error when creating JNI array(s).");
}
jlong * arg1indices = env->GetLongArrayElements(arg1indicesJ, 0);
jlong * arg2indices = env->GetLongArrayElements(arg2indicesJ, 0);
float * arg1values = env->GetFloatArrayElements(arg1valuesJ, 0);
float * arg2values = env->GetFloatArrayElements(arg2valuesJ, 0);
for (int i=0;i<anum;i++){
arg1indices[i]=a->words[i].wnum;
arg1values[i]=a->words[i].weight;
}
for (int i=0;i<bnum;i++){
arg2indices[i]=b->words[i].wnum;
arg2values[i]=b->words[i].weight;
}
//release the changes back to java arrays
env->ReleaseLongArrayElements(arg1indicesJ, arg1indices, 0);
env->ReleaseLongArrayElements(arg2indicesJ, arg2indices, 0);
env->ReleaseFloatArrayElements(arg1valuesJ, arg1values, 0);
env->ReleaseFloatArrayElements(arg2valuesJ, arg2values, 0);
//construct java strings out of userdefined fields
jstring arg1stringJ = env->NewStringUTF(a->userdefined);
jstring arg2stringJ = env->NewStringUTF(b->userdefined);
if (arg1stringJ==NULL||arg2stringJ==NULL){
if (env->ExceptionCheck()){
printf("\n");
env->ExceptionDescribe();
}
printErrorAndExit("Java exception when creating JNI string(s) (see stderr).");
}
//call backend kernel evaluation, check for java exceptions
double result = env->CallStaticDoubleMethod(backend,m_evaluate,arg1indicesJ,arg1valuesJ,arg1stringJ,arg2indicesJ,arg2valuesJ,arg2stringJ);
if (env->ExceptionCheck()) {
printf("\n");
env->ExceptionDescribe();
printErrorAndExit("Java exception when computing kernel (see stderr).");
}
if(result!=0&&normalize){
/*
* NOTE:
* Internally, we "abuse" the "twonorm_sq" field of the SVECTOR to allow
* for fast retrieval of the squared norms.
* To indicate that the value is not the original vector length but
* the squared kernel norm supplied by this kernel, we store inverted
* (i.e. negative) values.
*
* This is obviously a hack, but we do not want to meddle with the SVMlight
* code. It won't affect your application unless you use SVMlight as a library
* and apply different kernels to the same dataset loaded only once. So this does
* not seem critical ;-)
*/
double norm_sq_negativeA,norm_sq_negativeB;
if (a->twonorm_sq<0){
norm_sq_negativeA = a->twonorm_sq;
}
else{
norm_sq_negativeA=-1*env->CallStaticDoubleMethod(backend,m_evaluate,arg1indicesJ,arg1valuesJ,arg1stringJ,arg1indicesJ,arg1valuesJ,arg1stringJ);
a->twonorm_sq=norm_sq_negativeA;
}
if (b->twonorm_sq<0){
norm_sq_negativeB = b->twonorm_sq;
}
else{
norm_sq_negativeB=-1*env->CallStaticDoubleMethod(backend,m_evaluate,arg2indicesJ,arg2valuesJ,arg2stringJ,arg2indicesJ,arg2valuesJ,arg2stringJ);
b->twonorm_sq=norm_sq_negativeB;
}
//multiplication is ok, as *both* values will be negative.
result = result/sqrt(norm_sq_negativeA*norm_sq_negativeB);
}
//clean up
env->DeleteLocalRef(arg1indicesJ);
env->DeleteLocalRef(arg2indicesJ);
env->DeleteLocalRef(arg1valuesJ);
env->DeleteLocalRef(arg2valuesJ);
env->DeleteLocalRef(arg1stringJ);
env->DeleteLocalRef(arg2stringJ);
return result;
}
void printErrorAndExit(char* message){
fflush(stdout);
fflush(stderr);
printf("An error occured in custom kernel module: ");
printf("%s\n",message);
printf("exiting...\n");
exit(1);
}
void printFileErrorAndExit(char* file, char* message){
fflush(stdout);
fflush(stderr);
printf("Error reading from parameter file: %s\n",file);
printf("%s\n",message);
printf("exiting...\n");
exit(1);
}
void initialize(char* param){
fflush (stdout);
printf("Using custom kernel module: JNI kernel version "__VERSION".\n");
FILE * pFile;
char line [__MAX_LINE];
char classname [__MAX_LINE];
char option [__MAX_LINE];
//first pass: count... (needed for determining number of options)
pFile = fopen (param , "r");
if (pFile == NULL) printFileErrorAndExit(param,"Can not open file.");
int optioncount=0;
int classcount=0;
while (fgets (line , __MAX_LINE , pFile)){
if (sscanf (line, __CLASS_PARAM" %[^\n]", &classname)) classcount++;
if (sscanf (line, __OPTION_PARAM" %[^\n]", &option)>0) optioncount++;
}
fclose (pFile);
if (classcount != 1) printFileErrorAndExit(param,"Invalid number of classes.");
//second pass: read content
char** optionstrings = (char**) malloc(optioncount*sizeof(char *));
int optionindex = 0;
pFile = fopen (param , "r");
if (pFile == NULL) printFileErrorAndExit(param,"Can not open file.");
while (fgets (line , __MAX_LINE , pFile)){
sscanf (line, __CLASS_PARAM" %[^\n]", &classname);
if (sscanf (line, __OPTION_PARAM" %[^\n]", &option)>0){
optionstrings[optionindex]=(char*)malloc(__MAX_LINE*sizeof(char));
strcpy(optionstrings[optionindex],option);
optionindex++;
}
else if (strncmp (line,__NORMALIZE_PARAM,strlen(__NORMALIZE_PARAM))==0)
normalize=true;
}
fclose (pFile);
//prepare Java Virtual Machine, locate classes and methods
//class specification needs to follow corresponding KernelManager Java class...
if (verbosity>0) printf("Preparing Java backend... (increase verbosity to see more details)\n");
JavaVMOption * options = (JavaVMOption *) malloc(sizeof(JavaVMOption)*optioncount);
for (int i=0;i<optioncount;i++){
if (verbosity > 1) printf("JVM option: %s\n",optionstrings[i]);
options[i].optionString = optionstrings[i];
}
/*
JavaVMOption options[4];
options[0].optionString = "-Xmx512M";
options[1].optionString = "-Xms128M";
options[2].optionString = "-Djava.class.path=" USER_CLASSPATH;
options[3].optionString = "-Djava.library.path=.";
*/
JavaVMInitArgs vm_args;
vm_args.version = JNI_VERSION_1_2;
vm_args.options = options;
vm_args.nOptions = optioncount;
vm_args.ignoreUnrecognized = JNI_TRUE;
jint status;
status = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
if (status < 0) {
char message[__MAX_LINE];
sprintf (message, "Can't create Java VM (err %d)\n", status);
printErrorAndExit(message);
}
else if (verbosity>1)
printf("Java VM ok.\n");
backend = env->FindClass(__MANAGERCLASS);
if (backend == NULL)
printErrorAndExit("Can't locate KernelManager class.");
else if (verbosity>1)
printf("KernelManager class ok.\n");
m_initialize = env->GetStaticMethodID(backend, "initialize","(Ljava/lang/String;Ljava/lang/String;)V");
if (m_initialize == NULL)
printErrorAndExit("Can't locate initialization method.");
else if (verbosity>1)
printf("Init method ok.\n");
m_evaluate = env->GetStaticMethodID(backend, "evaluate","([J[FLjava/lang/String;[J[FLjava/lang/String;)D");
if (m_evaluate == NULL)
printErrorAndExit("Can't locate evaluation method.");
else if (verbosity>1)
printf("Evaluation method ok.\n");
jstring classnamearg = env->NewStringUTF(classname);
jstring paramarg = env->NewStringUTF(param);
if (verbosity > 0)
printf("Backend class: %s\n",classname);
//calls "public static void initialize(String kernelClassString, String paramFileString) ..."
fflush (stdout);
env->CallStaticBooleanMethod(backend,m_initialize,classnamearg,paramarg);
fflush (stdout);
if (env->ExceptionCheck()) {
printf("\n");
env->ExceptionDescribe();
printErrorAndExit("Java exception during initialization (see stderr).");
}
else if (verbosity>0) printf("Java backend ready.\n");
if (normalize) printf("Kernel normalization is on.\n");
initialized=true;
fflush (stdout);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -