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]; }
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