From 7ae0edbd6c036b32fa8dc909e7a67f57346d0a65 Mon Sep 17 00:00:00 2001
From: Christian Beckmann <c.beckmann@donders.ru.nl>
Date: Mon, 8 Dec 2008 22:15:08 +0000
Subject: [PATCH]  SBCA modified

---
 Makefile    | 11 ++++--
 fsl_mvlm.cc | 99 +++++++++++++++++++++++++++++++++++++++++------------
 melica.cc   |  3 ++
 test.cc     | 61 +++++++++------------------------
 4 files changed, 105 insertions(+), 69 deletions(-)

diff --git a/Makefile b/Makefile
index 552f8ad..b8ea47c 100644
--- a/Makefile
+++ b/Makefile
@@ -12,12 +12,14 @@ USRLDFLAGS = -L${LIB_NEWMAT} -L${LIB_PROB} -L${LIB_GD} -L${LIB_GDC} -L${LIB_PNG}
 
 LIBS = -lutils -lnewimage -lmiscplot -lmiscpic -lmiscmaths -lfslio -lniftiio -lznz -lnewmat -lprob -lm  -lgdc -lgd -lpng -lz
 
-TEST_OBJS = test.o test2.o
+TEST_OBJS = test.o 
 
 GGMIX_OBJS = ggmix.o
 
 FSL_GLM_OBJS = melhlprfns.o fsl_glm.o
 
+FSL_SBCA_OBJS = melhlprfns.o fsl_sbca.o
+
 FSL_MVLM_OBJS = melhlprfns.o fsl_mvlm.o
 
 FSL_REGFILT_OBJS = melhlprfns.o fsl_regfilt.o
@@ -26,13 +28,13 @@ MELODIC_OBJS =  meloptions.o melhlprfns.o melgmix.o meldata.o melpca.o melica.o
 
 TESTXFILES = test
 
-XFILES = fsl_glm fsl_mvlm fsl_regfilt melodic
+XFILES = fsl_glm fsl_sbca fsl_mvlm fsl_regfilt melodic
 
 RUNTCLS = Melodic
 
 SCRIPTS = melodicreport
 
-all: ggmix fsl_regfilt fsl_glm fsl_mvlm melodic
+all: ggmix fsl_regfilt fsl_glm fsl_mvlm fsl_sbca melodic
 
 ggmix: ${GGMIX_OBJS}
 	${AR} -r libggmix.a ${GGMIX_OBJS} 
@@ -46,6 +48,9 @@ test: ${TEST_OBJS}
 fsl_glm: ${FSL_GLM_OBJS}
 	$(CXX) ${CXXFLAGS} ${LDFLAGS} -o $@ ${FSL_GLM_OBJS} ${LIBS}
 
+fsl_sbca: ${FSL_SBCA_OBJS}
+		$(CXX) ${CXXFLAGS} ${LDFLAGS} -o $@ ${FSL_SBCA_OBJS} ${LIBS}
+
 fsl_mvlm: ${FSL_MVLM_OBJS}
 		$(CXX) ${CXXFLAGS} ${LDFLAGS} -o $@ ${FSL_MVLM_OBJS} ${LIBS}
 
diff --git a/fsl_mvlm.cc b/fsl_mvlm.cc
index bbe57c7..cafe3e8 100644
--- a/fsl_mvlm.cc
+++ b/fsl_mvlm.cc
@@ -64,7 +64,7 @@ using namespace std;
 		string("basename for output files "),
 		true, requires_argument);
 	Option<string> approach(string("-a,--alg"), string("PCA"),
-		string("algorithm for decomposition: PCA (or SVD; default), PLS, orthoPLS, CVA, SVD-CVA, MLM"),
+		string("algorithm for decomposition: PCA (or SVD; default), PLS, orthoPLS, CVA, SVD-CVA, MLM, NMF"),
 		false, requires_argument);	
     Option<string> fndesign(string("-d,--design"), string(""),
 		string("file name of the GLM design matrix (time courses or spatial maps)"),
@@ -81,6 +81,12 @@ using namespace std;
 	Option<bool> perf_demean(string("--demean"),FALSE,
 		string("switch on de-meaning of design and data"),
 		false, no_argument);
+	Option<int> nmfdim(string("--nmf_dim"), 0,
+		string(" Number of underlying factors for NMF"),
+		false,requires_argument);
+	Option<int> nmfitt(string("--nmfitt"), 100,
+		string("number of NMF itterations (default 100)"),
+		false,requires_argument);
 	Option<int> help(string("-h,--help"), 0,
 		string("display this help text"),
 		false,no_argument);
@@ -202,10 +208,12 @@ int setup(){
 		design =  SP(design,ones(design.Nrows(),1)*pow(stdev(design,1),-1));
 	
 	SVD( design, svd_X_D, svd_X_U, svd_X_V );
-	if(data.Nrows()>=data.Ncols())
-		SVD ( data, svd_Y_D, svd_Y_U, svd_Y_V );
-	else{
-		SVD ( data.t(), svd_Y_D, svd_Y_V, svd_Y_U );
+	if(approach.value()!=string("NMF")){
+		if(data.Nrows()>=data.Ncols())
+			SVD ( data, svd_Y_D, svd_Y_U, svd_Y_V );
+		else{
+			SVD ( data.t(), svd_Y_D, svd_Y_V, svd_Y_U );
+		}
 	}		
 
 	if(fnout.value().length() == 0){
@@ -303,30 +311,75 @@ int do_work(int argc, char* argv[]) {
 	}
 
     if( approach.value()!=string("MLM") && approach.value()!=string("CVA") && approach.value()!=string("PLS") &&
-		approach.value()!=string("SVD-CVA") && approach.value()!=string("orthoPLS"))
+		approach.value()!=string("SVD-CVA") && approach.value()!=string("orthoPLS") && approach.value()!=string("NMF"))
 		message(" Using method : PCA" << endl;);
 	
 	//perform an SVD on data	
 	outMsize(" New Data ", data);
+	
+	if(approach.value()!=string("NMF")){	
+		if(data.Nrows()>=data.Ncols())
+			SVD ( data, svd_Y_D, svd_Y_U, svd_Y_V );
+		else{
+			SVD ( data.t(), svd_Y_D, svd_Y_V, svd_Y_U );
+			svd_Y_U = svd_Y_U.t();
+			svd_Y_V = svd_Y_V.t();		
+		}	
+
+		dbgmsg(" Finished SVD : ");
+		outMsize("svd_Y_U",svd_Y_U);
+		outMsize("svd_Y_V",svd_Y_V);
+		outMsize("svd_Y_D",svd_Y_D);
+	
+		svd_Y_V = sqrtm(svd_Y_D) * svd_Y_V;	
+		svd_Y_U = svd_Y_U * sqrtm(svd_Y_D);	
+
+		if(approach.value()==string("SVD-CVA"))
+			svd_Y_V = svd_Y_V *tmpdata;
+	}
+	else{ //NMF
+		float err, err_old;
+		Matrix Ratio, Diff;
+
+		if(nmfdim.value()==0)
+			nmfdim.set_T(data.Nrows());
 		
-	if(data.Nrows()>=data.Ncols())
-		SVD ( data, svd_Y_D, svd_Y_U, svd_Y_V );
-	else{
-		SVD ( data.t(), svd_Y_D, svd_Y_V, svd_Y_U );
-		svd_Y_U = svd_Y_U.t();
-		svd_Y_V = svd_Y_V.t();		
-	}	
+		message("Using "<< nmfdim.value() << " dimensions" << endl;); 	
+		svd_Y_U =  unifrnd(data.Nrows(), nmfdim.value());
+		svd_Y_V =  unifrnd(nmfdim.value(), data.Ncols());
+		// re-scale columns of svd_Y_U to unit amplitude
+		Ratio = pow(stdev(svd_Y_U),-1);
+		svd_Y_U = SP(svd_Y_U,ones(svd_Y_U.Nrows(),1)*Ratio);
+				
+		Diff = data - svd_Y_U * svd_Y_V;
+		err = Diff.SumAbsoluteValue()/(data.Ncols()*data.Nrows());
+			
+		for(int k=1; k< nmfitt.value(); k++)
+		{
+		//	Ratio = SP(data,pow(svd_Y_U * svd_Y_V,-1));
+		//	svd_Y_U  =  SP(svd_Y_U, Ratio * svd_Y_V.t());
+		//	svd_Y_U  =  SP(svd_Y_U, pow( ones(svd_Y_U.Nrows(),1) * sum(svd_Y_U,1),-1));
+		//	svd_Y_V  =  SP(svd_Y_V, svd_Y_U.t()* Ratio);
+		//	
+		// Lee & Seung multiplicatice updates
+		
+			Ratio = SP(svd_Y_U.t() * data, pow(svd_Y_U.t() * svd_Y_U * svd_Y_V ,-1));
+			svd_Y_V  = SP(svd_Y_V,Ratio);
 
-	dbgmsg(" Finished SVD : ");
-	outMsize("svd_Y_U",svd_Y_U);
-	outMsize("svd_Y_V",svd_Y_V);
-	outMsize("svd_Y_D",svd_Y_D);
-	
-	svd_Y_V = sqrtm(svd_Y_D) * svd_Y_V;	
-	svd_Y_U = svd_Y_U * sqrtm(svd_Y_D);	
+			Ratio = SP(data * svd_Y_V.t(),pow(svd_Y_U * (svd_Y_V * svd_Y_V.t()),-1));
+			svd_Y_U  = SP(svd_Y_U,Ratio);
 
-	if(approach.value()==string("SVD-CVA"))
-		svd_Y_V = svd_Y_V *tmpdata;
+			// re-scale columns of svd_Y_U to unit amplitude
+			Ratio = pow(stdev(svd_Y_U),-1);
+			svd_Y_U = SP(svd_Y_U,ones(svd_Y_U.Nrows(),1)*Ratio);
+			
+			Diff = data - svd_Y_U * svd_Y_V;
+			err_old = err;
+			err = Diff.SumSquare()/(data.Ncols()*data.Nrows());			
+			message(" Error " << err << endl;);
+		}	
+	}
+	
 	write_res();
 	
 	dbgmsg(" Leaving <do_work>");
@@ -350,6 +403,8 @@ int main(int argc,char *argv[]){
 			options.add(normdes);
 			options.add(perfvn);
 			options.add(perf_demean);
+			options.add(nmfdim);
+			options.add(nmfitt);
 			options.add(help);
 			options.add(verbose);
 			options.add(debug);
diff --git a/melica.cc b/melica.cc
index c80b17d..cf00974 100644
--- a/melica.cc
+++ b/melica.cc
@@ -39,6 +39,9 @@ namespace Melodic{
     redUMM = melodat.get_white()*
        unifrnd(melodat.get_white().Ncols(),dim); // got to start somewhere
     
+	if(opts.debug.value())
+		cerr << "redUMM init submatrix : " << endl << redUMM.SubMatrix(1,2,1,2) << endl;
+		
     if(opts.guessfname.value().size()>1){
       message("  Use columns in " << opts.guessfname.value() 
 	      << " as initial values for the mixing matrix " <<endl);
diff --git a/test.cc b/test.cc
index b51a5b4..549caf2 100644
--- a/test.cc
+++ b/test.cc
@@ -9,6 +9,7 @@
 #include "miscmaths/miscprob.h"
 #include "utils/options.h"
 #include <vector>
+#include <time.h>
 #include "newimage/newimageall.h"
 #include "melhlprfns.h"
 
@@ -20,11 +21,11 @@ using namespace std;
 // The two strings below specify the title and example usage that is
 // printed out as the help or usage message
 
-  string title=string("fsl_glm (Version 1.0)")+
-		string("\nCopyright(c) 2007, University of Oxford (Christian F. Beckmann)\n")+
-		string(" \n Simple GLM usign ordinary least-squares regression on\n")+
-		string(" time courses and/or 3D/4D volumes\n\n");
-  string examples="fsl_glm <input> -d <design> [options]";
+  string title=string("fsl_BLAH")+
+		string("\nCopyright(c) 2008, University of Oxford (Christian F. Beckmann)\n")+
+		string(" \n \n")+
+		string(" \n");
+  string examples="fsl_BLAH [options]";
 
 //Command line Options {
   Option<string> fnin(string("-i,--in"), string(""),
@@ -46,43 +47,7 @@ using namespace std;
 // Local functions
 
 int do_work(int argc, char* argv[]) {
-	Matrix design;
-	design=read_ascii_matrix(fnin.value());
-		Matrix joined;
-		Matrix weights;
-		
-		
-	cerr << " Design : "  << design.Nrows() << " x " << design.Ncols() << endl <<endl;
-	for(int i=1; i <10; i++){
-		weights = normrnd(10,design.Ncols());
-		
-	
-		joined=SP(design,ones(design.Nrows(),1)*weights.Row(1));
-		
-		for(int j=2;j<=weights.Nrows();j++){
-			Matrix tmp;
-			tmp=SP(design,ones(design.Nrows(),1)*weights.Row(j));
-			joined &= tmp;
-		}
-			
-		
-	}
-	
-	cerr << " joined : " << joined.Nrows() << " x " << joined.Ncols() << endl << endl;
-	
-	Matrix Cols,Rows;
-	
-	Melodic::krfact(joined,design.Nrows(),Cols,Rows);
-	
-	cerr << " Cols : " << Cols.Nrows() << " x " << Cols.Ncols() << endl << endl;
-	
-	cerr << " Rows : " << Rows.Nrows() << " x " << Rows.Ncols() << endl << endl;
-
-	cerr << weights << endl <<endl << Rows << endl;
 
-	cerr << remmean(SP(weights,pow(Rows,-1))) << endl;
-	
-	
 	return 0;
 }
 
@@ -94,8 +59,16 @@ int do_work(int argc, char* argv[]) {
 	  try{
 	    // must include all wanted options here (the order determines how
 	    //  the help message is printed)
-			options.add(fnin);
-		
+	
+		  double tmptime = time(NULL);
+		  srand((unsigned int) tmptime);
+
+		cerr << (unsigned int) tmptime << endl << endl;
+
+		cerr << unifrnd(2,2) << endl;
+		exit(1);
+	/*
+			options.add(fnin);		
 			options.add(help);
 		
 	    options.parse_command_line(argc, argv);
@@ -108,7 +81,7 @@ int do_work(int argc, char* argv[]) {
 	    }else{
 	  		// Call the local functions
 	  		return do_work(argc,argv);
-			}
+			}*/
 		}catch(X_OptionError& e) {
 			options.usage();
 	  	cerr << endl << e.what() << endl;
-- 
GitLab