Hello everyone.

I'm still working with sparse matrices in oct-file, but i've got some
problems: i'm doing some multithread and as the octave libraries
revealed to be not really thread safe (some unexpected crashed ofter
repeating executions) i did the dirty work by hand: i copied the 3
vectors of the matrix B (the input matrix) and copied the full matrix
A into a vector. Then did what i have to do and then gave back the 3
vectors for the matrix C, then create the sparsematrix out of the 3
vectors and return from the function. something in creating the c
sparse matrix out of the 3 vector is going wrong, and the
documentation about this seem to be poor. For example, why the 3
vector has to be the same lenght? the cidx is always really shorter
than the other 2. (i solved the problem filling with zeroes but i
don't know if it's the correct why). Another problem is that sometimes
when creating the matrix it says i'm referencing an item that's out of
the matrix bounds (even if the 3 vectors have correct indexes and
values inside i suppose). The last problems is that i get an error on
a free call, the log is long so i post an attachment with it. the call
is:

mkoctfile -v fl_spcompose.cc
A = sprand(10, 10, 0.5);
B = sprand(10, 10, 0.5);
tic; C=fl_spcompose(A,B); toc

Hope that someone can help me solving my problem (i'll attach the full
sourcecode too, the part i'm talking about is from 319 to 371)
#include <octave/oct.h>
#include <octave/parse.h>
#include <pthread.h>    

#define HELP " -- Loadable Function: C = fl_spcompose (A, B)\n -- Loadable Function: C = fl_spcompose (A, B, LOCK)\n -- Loadable Function: C = fl_spcompose (A, B, T)\n -- Loadable Function: C = fl_spcompose (A, B, T, S)\n -- Loadable Function: C = fl_spcompose (A, B, LOCK, T)\n\nReturns the T-Norm / S-Norm composition as basic inference mechanism of Fuzzy\nLogic. By default, it calculates the max-min composition.\n\nA and B must be matrices with conformant dimensions as in matrix product.\n\nWhen true, the boolean LOCK option forces to calculate the diagonal results\nonly and returns it as a column vector.\n\nThe arguments T and S allows you to specify a custom T-Norm and S-Norm function\nrespectively. They can be:\n - 'min': use the minimum function (default for T-Norm);\n - 'pro': use the product function;\n - 'max': use the maximum function (default for S-Norm);\n - 'sum': use the sum function;\n - function_handle: a user-defined function (at most 2 arguments).\n\nNote that only the predefined functions are calculated rapidly and in\nmultithread mode. Using a user-defined function as T-Norm and/or S-Norm\nwill result in a long time calculation. \n\n\n\n\n"

#define MIN_ARG 2
#define MAX_ARG 4

#define STR_MINNORM "min"
#define STR_PRONORM "pro"
#define STR_MAXNORM "max"
#define STR_SUMNORM "sum"

#define ERR_INVALIDFUNC "fl_spcompose: the specified T-Norm or S-Norm function is invalid!\nPlease read help for details"
#define ERR_ARG "fl_spcompose: invalid arguments number!\n"
#define ERR_MATRIXSIZE "fl_spcompose: incompatible matrices dimensions\n"
#define ERR_MATRIXTYPE "fl_spcompose: the first two argument must be matrices\n"
#define ERR_LOCKOPTION "fl_spcompose: the lock_option must be 0 or 1\n"




// Structure for thread arguments. Each thread will perform the computation between the start_index and end_index row.
struct threadArg
{
	int start_index;
	int end_index;
};


// Functions prototype declaration
double getElem(double vec[], int row, int col,int numCols);
int checkFunction(octave_function *func);
void *thread_function(void *arg);
int getCpuCore();
void compose();
int assignFunction(octave_value arg, int tnorm);


double (*calc_tnorm)(double,double);
double (*calc_snorm)(double,double);

double func_min(double first, double second);
double func_prod(double first, double second);
double func_max(double first, double second);
double func_sum(double first, double second);

double func_custom_tnorm(double first, double second);
double func_custom_snorm(double first, double second);


// T-Norm and S-Norm function pointers
octave_function *tnorm;
octave_function *snorm;


// Structure for the thread arguments
struct threadArg* thread_args = NULL;

// Input and output matrices
SparseMatrix a,b,c;

// Matrix component vectors
int *cidxB, *ridxB, *cidxC, *ridxC;
double *dataB, *dataC;
double *copyA;

// Matrices dimensions
////////////////////////////////////////////////////////
int rowsA,rowsB,colsA,colsB,nnzA,nnzB;

// Lock option. 1 = calculation executed only for the diagonal of the matrix
int lock_option = 0;

// The increment 
int col_index_increment;

// Number of threads that will be created
int num_threads;





/* Main function - Check the arguments and call the compose method */
DEFUN_DLD (fl_spcompose, args, nargout, HELP)
{
	int numargs = args.length();		// Arguments number
	int specified_lockoption = 0;		// 1 = the lock_option was specified in the arguments

	// Set the num_thread to the actual available CPU cores
	num_threads = getCpuCore();

	// Set the lock_option to default value (0)
	lock_option = 0;

	// Set the T-Norm and S-Norm function pointer to default value (Minimum and Maximum)
	calc_tnorm = func_min;
	calc_snorm = func_max;


	// Check if the argument number is correct
	if(numargs < MIN_ARG || numargs > MAX_ARG)
	{
		error(ERR_ARG);	
		return octave_value_list();	
	}


	// Check if the first two arguments are matrices	
	if(!args(0).is_matrix_type() || !args(1).is_matrix_type())
	{
		error(ERR_MATRIXTYPE);
		return octave_value_list();
	}



	// Analyze the third argument (can be the lock_option, a custom T-Norm or a default string for T-Norm)	
	if(numargs > 2)
	{
		// Check if the third argument is the lock_option.
		if(args(2).is_bool_scalar())			
		{
			// Get the lock_option value
			lock_option = args(2).int_value();		
			specified_lockoption = 1;
		}


		// Check if the third argument is a function
		else if(args(2).is_function_handle())		
		{
			// Check if the custom T-Norm function has at most two arguments			
			if(!checkFunction(args(2).function_value()))	
			{		
				error(ERR_INVALIDFUNC);
				return octave_value_list();
			}
			else
			{
				// Set the custom T-Norm and force single thread mode					
				tnorm = args(2).function_value();
				calc_tnorm = func_custom_tnorm;
				num_threads = 1;		
			}	
		}

		// Check if the third argument is a string and try to assign a default T-Norm
		else if(!((args(2).is_sq_string() || args(2).is_dq_string()) && assignFunction(args(2),1)))
		{	
			error(ERR_INVALIDFUNC);	
			return octave_value_list();
		}
	}




	// Analyze the fourth argument (can be a custom T-Norm, a default string for T-Norm or a custom S-Norm)	
	if(numargs > 3)
	{
		// Check if the fourth argument is a function
		if(args(3).is_function_handle())		
		{
			if(specified_lockoption)
			{
				// Check if the custom T-Norm function has at most two arguments			
				if(!checkFunction(args(3).function_value()))	
				{		
					error(ERR_INVALIDFUNC);
					return octave_value_list();
				}
				else
				{
					// Set the custom T-Norm and force single thread mode					
					tnorm = args(3).function_value();
					calc_tnorm = func_custom_tnorm;
					num_threads = 1;		
				}
			}
			else
			{
				// Check if the custom S-Norm function has at most two arguments			
				if(!checkFunction(args(3).function_value()))	
				{		
					error(ERR_INVALIDFUNC);
					return octave_value_list();
				}
				else
				{
					// Set the custom S-Norm and force single thread mode	
					snorm = args(3).function_value();
					calc_snorm = func_custom_snorm;
					num_threads = 1;
				}
			}
		}
		
		// Check if the fourth argument is a string (could be a default T-Norm)
		else if (args(3).is_sq_string() || args(3).is_dq_string())
		{						
			if(specified_lockoption)
			{
				if (!assignFunction(args(3),1))
				{
					error(ERR_INVALIDFUNC);	
					return octave_value_list();
				}
			}
			else
			{
				if (!assignFunction(args(3),0))
				{
					error(ERR_INVALIDFUNC);	
					return octave_value_list();
				}
			}
		}
		else
		{
			error(ERR_INVALIDFUNC);	
			return octave_value_list();
		}			
	}
		

	// Get the input matrices	
        a = args(0).sparse_matrix_value();
        b = args(1).sparse_matrix_value();

	// Get the dimensions of matrices	
	rowsA = a.dims()(0);
	colsA = a.dims()(1);
        nnzA = a.nnz();
	rowsB = b.dims()(0);
	colsB = b.dims()(1);
        nnzB = b.nnz();

	const SparseMatrix tmpA (a);
	copyA = new double[rowsA*colsA];
	for (int i=0; i<rowsA; i++)
		for(int j=0; j<colsA;j++)
			copyA[i*colsA+j] = tmpA(i,j);

	int* tmp;
	int lenght;

	tmp = b.cidx();
	lenght = sizeof(tmp)/sizeof(*tmp);

	cidxB = new int[colsB+1];
	octave_stdout << "colsB= " << colsB << "\n";
	for (int i = 0; i <= colsB+1; i++) {
		octave_stdout << "b.cidx(" << i << ")= " << b.cidx(i) << "\n";
		cidxB[i] = b.cidx(i);
	}

	tmp = b.ridx();
	lenght = sizeof(tmp)/sizeof(*tmp);

	ridxB = new int[nnzB];
	octave_stdout << "nnzB= " << nnzB << "\n";
	for (int i = 0; i < nnzB; i++) {
		octave_stdout << "b.ridx(" << i << ")= " << b.ridx(i) << "\n";
		ridxB[i] = b.ridx(i);
	}

	double* tmpData;

/*
	tmpData = a.data();
	lenght = sizeof(tmpData)/sizeof(*tmpData);
	dataA = new double[lenght];
	for (int i = 0; i < lenght; i++)
		dataA[i] = a.data(i);
*/

	tmpData = b.data();
	lenght = sizeof(tmpData)/sizeof(*tmpData);

	dataB = new double[nnzB];
	for (int i = 0; i < nnzB; i++)
		dataB[i] = b.data(i);

	// Check if the dimensions are compatible
	if(colsA != rowsB)	
	{
		error(ERR_MATRIXSIZE);
		return octave_value_list();
	}
		

	// If the lock_option is true, the function will return a column vector.
	// Sets proper matrix dimension and column index increment.
	if(lock_option)
	{
		// A column index increment = colsB let the two FOR cycle to calculate only the first element 
		col_index_increment = colsB;
		//c = SparseMatrix(1, rowsA, rowsA);
		cidxC = new int[1];
		ridxC = new int[rowsA];
		dataC = new double[rowsA];
	}
	else
	{
		col_index_increment = 1;
		//c = SparseMatrix(colsB, rowsA, colsB*rowsA);
		cidxC = new int[colsB];
		ridxC = new int[colsB*rowsA];
		dataC = new double[colsB*rowsA];
	}			
		

	// Start the matrix composition
	compose();

	printf("res\n");

	if(lock_option)
	{

		ColumnVector cv_dataC (rowsA);
		octave_stdout << "rowsA= " << rowsA << "\n";
		for (int i = 0; i < rowsA; i++) {
			octave_stdout << "dataC{" << i << "}= " << dataC[i] << "\n";
			cv_dataC(i) = dataC[i];
		}

		ColumnVector cv_ridxC (rowsA);
		for (int i = 0; i < rowsA; i++)
			cv_ridxC(i) = ridxC[i];

		ColumnVector cv_cidxC (rowsA+1);
		for (int i = 0; i < rowsA+1; i++)
			cv_cidxC(i) = cidxC[i];

		c = SparseMatrix(cv_dataC, cv_ridxC, cv_cidxC, 1, rowsA);
	}
	else
	{

		ColumnVector cv_cidxC (colsB+1);
		for (int i = 0; i < colsB+1; i++) {
			octave_stdout << "cidxC{" << i << "}= " << cidxC[i] << "\n";
			cv_cidxC(i) = cidxC[i];
		}
		for (int i = colsB+1; i < colsB+1; i++) {
			cv_cidxC(i) = 0;
		}

		ColumnVector cv_dataC (cidxC[colsB]);
		octave_stdout << "colsB*rowsA= " << cidxC[colsB] << "\n";
		for (int i = 0; i < cidxC[colsB]; i++) {
			octave_stdout << "dataC{" << i << "}= " << dataC[i] << "\n";
			cv_dataC(i) = dataC[i];
		}

		ColumnVector cv_ridxC (cidxC[colsB]);
		for (int i = 0; i < cidxC[colsB]; i++) {
			octave_stdout << "ridxC{" << i << "}= " << ridxC[i] << "\n";
			cv_ridxC(i) = ridxC[i];
		}

		c = SparseMatrix(cv_dataC, cv_ridxC, cv_cidxC, colsB, rowsA, false);
	}

	// Return the resulting matrix
	c.maybe_compress();
        return octave_value(c.transpose());
}










// Calculate the S-Norm/T-Norm composition
void compose()
{

	// Create the thread args array
	thread_args = new threadArg[num_threads];
		

	// Define an array of threads
	pthread_t th[num_threads];

	// Define the number interval of rows for each thread		
	int interval = rowsA / num_threads;	
			
	printf("thread");

	// Define the threads
	for (int i=0; i<num_threads; i++)
	{	
		// Set the proper row start_index and end_index in the thread argument
		thread_args[i].start_index = i*interval;
		thread_args[i].end_index = thread_args[i].start_index + interval;	

		if(i == num_threads - 1)		
			thread_args[i].end_index = rowsA;
			
		// Start the thread			
		pthread_create(&th[i],NULL,thread_function, (void *) &thread_args[i]);
	}

	void *ans1;	
	
	// Wait the results from each thread
	for(int i=0; i<num_threads; i++)
		pthread_join(th[i],&ans1);
}










/* Function executed by each thread */
void *thread_function(void *arg)
{
	// Get the structure from the thread arguments
	struct threadArg *thread_args;
	thread_args = (struct threadArg *) arg;

        // Create constat versions of the input matrices to prevent them to be filled by zeros on reading
	const SparseMatrix tmpA (a);
	const SparseMatrix tmpB (b);

	// Declare variables for the T-Norm and S-Norm values 
	double snorm_val;	
	double tnorm_val;	
	
	// Get the row start_index and end_index 
	int start_index = thread_args->start_index;
	int end_index = thread_args->end_index;

        // Initialize the number of nonzero elemnts in sparse matrix c
        int nel = 0;
        cidxC[0] = 0;

	printf("for\n");

	// Calculate the composition for the specified rows (between start_index and end_index)
        for (int i = start_index; i < end_index; i++)
        {
            for(int j = lock_option*i; j < colsB; j = j+col_index_increment)
            {
                snorm_val = 0;

		printf("nelforj\n");
		// From b.cidx(j) to b.cidx(j+1)-1 there are all the nonzero elements of the column j of b (tmpB actually)
                for (int k = cidxB[j]; k <= (cidxB[j+1]-1); k++)
                {
			printf("nelfork\n");
			octave_stdout << "k= " << k << " cidxB[j+1]= " << cidxB[j+1] << "\n";
			// b.ridx(k) is the row index of the actual nonzero element in b (tmpB actually)
			// so it is also the column index of the element in a (tmpA actually)
		        tnorm_val = calc_tnorm(getElem(copyA, i, ridxB[k], colsA), dataB[k]);
			snorm_val = calc_snorm(snorm_val, tnorm_val);
                }

                if (snorm_val != 0)
                {
			printf("aggiunto\n");
                    ridxC[nel] = j;
                    dataC[nel++] = snorm_val;
                }
            }
            cidxC[i+1] = nel;
        }

	return((void *)0);
}






	





/* Returns 1 if an octave_function FUNC has at most 2 arguments. */
int checkFunction(octave_function *func)
{
	octave_value_list testArgs;
	testArgs(0) = 1;
	testArgs(1) = 2;
	feval(func,testArgs);
	if(error_state)
		return 0;
	else
		return 1;
}



/* Assign a default function or T-Norm or S-Norm. 
If tnorm = 0 the function will be assigned as S-Norm, else the function will be assigned as T-Norm.
Returns 0 if it fails*/
int assignFunction(octave_value arg, int tnorm)
{
	int res = 1;	
	if(arg.string_value() == STR_PRONORM)
		if(tnorm)
			calc_tnorm = func_prod;
		else
			calc_snorm = func_prod;
	else if (arg.string_value() == STR_MAXNORM)
		if(tnorm)
			calc_tnorm = func_max;
		else
			calc_snorm = func_max;
	else if (arg.string_value() == STR_SUMNORM)
		if(tnorm)
			calc_tnorm = func_sum;
		else
			calc_snorm = func_sum;
	else if(!(arg.string_value() == STR_MINNORM))
		res = 0;
	return res;
}

	








/* Calculate the minimum between the two values */
double func_min(double first, double second)
{	
	if(first < second)
		return first;
	else
		return second;
}



/* Calculate the product between the two values */
double func_prod(double first, double second)
{	
	return first*second;
}



/* Calculate the Maximum between the two values */
double func_max(double first, double second)
{	
	if(first > second)
		return first;
	else
		return second;
}



/* Calculate the sum between the two values */
double func_sum(double first, double second)
{	
	return first+second;
}



/* Calculate a custom T-Norm between the two values */
double func_custom_tnorm(double first, double second)
{	
	octave_value_list fargs;			
	fargs(0) = octave_value(first);
	fargs(1) = octave_value(second);
	return feval(tnorm,fargs)(0).double_value();
}



/* Calculate a custom S-Norm between the two values */
double func_custom_snorm(double first, double second)
{	
	octave_value_list fargs;			
	fargs(0) = octave_value(first);
	fargs(1) = octave_value(second);
	return feval(snorm,fargs)(0).double_value();
}










/* Get the current cpu cores number */
int getCpuCore()
{
	#ifdef WIN32	
		SYSTEM_INFO sysinfo;
		GetSystemInfo( &sysinfo );
		return sysinfo.dwNumberOfProcessors;
	#else
		return sysconf( _SC_NPROCESSORS_ONLN);
	#endif
}


/* Get the (i,j)-th element from the vector vec. The column number of the original matrix (numCols) is required */
double getElem(double vec[], int row, int col,int numCols)
{
	return vec[row*numCols+col];
}

Attachment: log
Description: Binary data

------------------------------------------------------------------------------
Learn how Oracle Real Application Clusters (RAC) One Node allows customers
to consolidate database storage, standardize their database environment, and, 
should the need arise, upgrade to a full multi-node Oracle RAC database 
without downtime or disruption
http://p.sf.net/sfu/oracle-sfdevnl
_______________________________________________
Octave-dev mailing list
Octave-dev@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/octave-dev

Reply via email to