⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 kernel.c

📁 JNI Kernel Extension for SVMlight
💻 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 + -