Exemplo n.º 1
0
string SeqOp::digital2Motif(const int index, const int len)
{
	string motif(len, '0');
	int quot = index;
	int order = 0;
	while(quot!=0) {
		motif[order] += (quot%4);
		quot /= 4;
		order++;
	}
	return SeqOp::Digital2Letter(motif);
}
Exemplo n.º 2
0
//  Return a sorted occurrence list 
//  First the occurences are sorted according to the motif m (canonic form)
//  Then the occurences are sorted according to the motif m' or mp 
//  obtained by removing one node from m.
//  Then a last sort is done according to the location U (of mp)
//  mode
//    a - if "NodeToClass" and "NbrOfClasses" are provided the p-value
//        is computed
//    b - if  "StoreOcc" is motif occurence positions are stored
//    c - "motif_filter" if true only this motif is considered
//    d - "del_class" if true provided an deletion class is applied after the 
//        "motif filter" 
SEXP sort_m_mp_u( SparseAdjacency &G, int G_N, int k, 
		  vector<int*> *occurrences, 
		  double *Pi, int *NodeToClass, int NbrOfClasses, 
		  int *MotifFilter, int DelClassFilter, 
		  double PValue,
		  int &n_prot, bool StoreOcc) {


  int directed; 
  if(G.getSymmetry()) 
    directed=0 ; 
  else 
    directed=1;

  // Active Filters
  bool useMotifFilter=false, useDelClassFilter=false;
  if( MotifFilter ) {
    useMotifFilter = true;
    if( DelClassFilter >= 0 )
      useDelClassFilter=true;
  }
    

  // If LambdaU must be computed
  bool ComputePValue = false;
  int  *Alpha = new int[NbrOfClasses];

  // Init Alpha
  if ( (NodeToClass != 0) && (Pi != 0) && (NbrOfClasses != 0) ) {
    ComputePValue = true;
    for( int *it=Alpha, *it_end=&Alpha[NbrOfClasses]; it != it_end; it++) {
      *it=0;
    }
    for( int *it = NodeToClass, *it_end = &NodeToClass[G_N]; 
	 it != it_end; it++) {
      Alpha[*it]++;
    }
  } else {
    NbrOfClasses = 0; 
  }

  // Instanciate PseudoMixnet
  PseudoMixnet pmixnet(G_N, NbrOfClasses, Alpha, Pi, directed);

  SEXP  S_M_List;

  int64_t TotalCount        = occurrences -> size();
  vector<int*>::const_iterator it = occurrences -> begin();
  int *ptr = *it;

  // Print occurences
  // cerr << "TotalCount " << TotalCount << endl;

  // for ( int64_t count=0; count < TotalCount; count++, it++) {
  //   printList( "Occurrence : ", *it, *it + k, " ", true);
  // }

  int *mat;
  int *gamma = new int[k];

  // Store 2 references : on canonic form and on an occurence
  canonic_list_t *canonic_list = new canonic_list_t[TotalCount];

  // To Store canonic form
  int *canonic = new int[TotalCount * k*k];

  // To sort canonic form (used by canonic_order function)
  sort_canonic_nbr_elmnt = k*k;

  // tmp array to perform permutation
  int *tempo = new int[k];

  //
  // Compute canonic form and reoder occurrence indexes
  //
  for ( int64_t count=0; count < TotalCount; count++, it++) {

    // Extract motif 
    // The matrix must be transposed (true) for nauty
    mat = G.getMatrix( *it, k, false );

    // Get canonic form
    // ToDo : Perf call getCanonic once
    int *cur_canonic = &canonic[k*k * count];
    getCanonic( mat , k, directed, cur_canonic, gamma );

    delete [] mat;

    canonic_list[count].canonic    = cur_canonic;
    canonic_list[count].occurrence = *it;

    //
    // Print canonic form
    // printList( "Occurences, canonic ", *it, *it+k, " ", false); 
    // cout << ", " ;

    //
    // Permute nodes
    //
    int *node=*it;
    for( int i=0; i < k; i++){
      tempo[i] = node[gamma[i]];
    } 
    // Permute node in the occurence list
    for( int i=0; i < k; i++){
      node[i] = tempo[i];
    } 
    
    // Print cannonic
    // printList("", cur_canonic, cur_canonic + k*k, "", true);
    
    // Print gamma
    // printList( "  gamma : ", gamma, gamma + k);

  }

  //
  //  Sort occurrences according to the canonical form of m
  //

  qsort( canonic_list, TotalCount,  sizeof(canonic_list_t), canonic_order);

  //
  //  Print occurrences after the canonic sort and reordering
  //
# if( MSG > 0)
  cout << " Occurrences after the canonic sort and reordering" << endl;
  cout << " -------------------------------------------------" << endl;
  it = occurrences -> begin( );
  for ( int64_t count=0; count < TotalCount; count++, it++) {

    // Print node list
    ptr = canonic_list[count].occurrence;
    printList( "  ",  ptr, ptr + k, false);
    cout << ", ";

    // Print cannonic
    ptr = canonic_list[count].canonic;
    printList("", ptr, ptr + k*k, "", true);
  }
  cout << endl; 
# endif
  //
  //  Get refences where start and end a motif( canonic form)
  //

  //
  //  Build list of reference (pointer of type : canonic_list_t*)
  //  pointing to the same canonical form of m.
  //  Stored in the MotifEnd, MotifStart (STL) list
  //

  vector<canonic_list_t*> MotifEnd, MotifStart;
  int nbr_motif=0;
  it = occurrences -> begin( );
  canonic_list_t *prev_canonic = &canonic_list[0];
  MotifStart.push_back( &canonic_list[ 0 ] );
  for ( int64_t count=0; count < TotalCount; count++, it++) {

    //  If the current canonc form is equal to the previous one
    if( canonic_order( &canonic_list[count], prev_canonic ) ) {

      // New canonic form
      prev_canonic = &canonic_list[count];
      
      MotifEnd.push_back( &canonic_list[count] );
      MotifStart.push_back( prev_canonic  );
      nbr_motif = 0;
    } else{
      nbr_motif++;
    }
  }
  MotifEnd.push_back( &canonic_list[ TotalCount ] );


  //
  //  For each motif m, the occurence list of m is sorted 
  //  by ignoring one node (belonging to the same TC - the 
  //  remove index is stored in "remove" field) 
  // 

  vector<canonic_list_t*>::const_iterator ite     =  MotifEnd.begin();
  // unused vector<canonic_list_t*>::const_iterator ite_end =  MotifEnd.end();
  FindMotif TopoClassesBuider(TCMode, 0);
  int *ij_index = new int[ 2*k*k+2];
  int *Color  = new int[k];
  int *perm   = new int[k];
  int *perm_1 = new int[k];

  // Init
  for( int i=0; i < k; i++) {
      Color[i] = 0;
  }

  // Configure the occurence sort
  sort_occurences_nbr_elmnt = k;
 

  SEXP S_M_CanonicList; 

  if ( useMotifFilter ) {
    PROTECT( S_M_CanonicList = allocVector( VECSXP, 1 )); n_prot++;
    PROTECT( S_M_List        = allocVector( VECSXP, 1 )); n_prot++;
  } else {
    PROTECT( S_M_CanonicList=
	     allocVector( VECSXP,  MotifStart.size() )); n_prot++;
    PROTECT( S_M_List=
	     allocVector(VECSXP,  MotifStart.size() )); n_prot++;
  }

  // Counter of the sorted motif m to manage the SEXP 
  int m_index = 0;
  // Counter of the deletion class  mp to mana the corresponding SEXP
  int mp_index = 0;

  for( vector<canonic_list_t*>::const_iterator its =  MotifStart.begin(), 
	 its_end=  MotifStart.end();
       its != its_end; its++, ite++ ) {

    //
    // Occurences having the same motif
    //

    //
    //   Motif filter
    //
    if( ! useMotifFilter 
	|| isEqualCanonic( (*its) -> canonic, MotifFilter, k) ) {

      // Print cannonic
#     if( MSG > 0)
      ptr = (*its) -> canonic; 
      printList("Motif m=", ptr, ptr + k*k, "", false);
      cout << ", " << endl;
#     endif      

      //
      // Get a SparseAdjacency on the current motif m
      //
      ptr = (*its) -> canonic; 
      int pos = 0;
      for( int i=0 ; i < k*k; i++, ptr++){
	if(*ptr) {
	  // row index
	  ij_index[pos+1]   = i % k;
	  // col index
	  ij_index[pos] = i / k;
	  pos += 2;
	}
      } 
      // End list
      ij_index[pos]   = NOT_INDEX;
      ij_index[pos+1] = NOT_INDEX;
      
      // Buid the SparseAdjacency 
      SparseAdjacency motif( ij_index, k, (directed==0) );
      // Get good property to compute TC, 
      // "perm" give the permutation done
      motif.optimizeConnexity( perm ); 
      
      // get Topological Classes (TC)
      vector< int > *CT = TopoClassesBuider.getEquivalentNodes( motif, Color );
    
      size_t nbr_motif_m = *ite - *its;
      
      // 
      // motif.print(" motif" );
      // cout << "Occurences number of motif m " << nbr_motif_m  << endl; 
      
      // Compute inverse permutation perm_1
      for( int i=0; i < k; i++) {
	perm_1[perm[i]] = i; 
      }
      
      // Count the number of m' (mp)
      int n_mp=0;
      for( int i=0; i < k; i++) {
	if( CT[i].size() != 0) {
	  n_mp++;
	}
      }
    
      // unused SEXP S_Fuse_MP_List;
      SEXP S_MP_List;
      if ( useDelClassFilter ) {
	PROTECT( S_MP_List=allocVector(VECSXP, 1  )); n_prot++;
      } else {
	PROTECT( S_MP_List=allocVector(VECSXP, n_mp  )); n_prot++;
      }

      //
      //  For each Topological Class of m
      //
      
      mp_index = 0;
      for( int i=0; i < k; i++) {
	
	// Deletion class Filter
	if( ! useDelClassFilter ||  
	    isInDelClass( DelClassFilter, CT[i], perm_1 ) ) { 
	  // Computed for class of deletion
	  double max_t = -1;
	  
	  // Print  Topological Class
#         if( MSG > 0)
	  cout << "  Couple (m, m'),  DelClass " << i << " : ";
	  for ( vector<int>::iterator it_ct = CT[i].begin(),
	        it_ct_end = CT[i].end();
	      it_ct != it_ct_end; it_ct++) {
	   cout << *it_ct << ", ";
	  }
	  cout << endl;
#         endif	  
	
	  // Build [m,_mp] occurences list
	  m_mp_list_t *m_mp_list   = new m_mp_list_t[ CT[i].size() * nbr_motif_m ];
	  m_mp_list_t *it_m_mp_end = &m_mp_list[ CT[i].size() * nbr_motif_m ];
	  canonic_list_t *it_m = *its;
	  for( m_mp_list_t *it_m_mp = m_mp_list; 
	       it_m_mp != it_m_mp_end; it_m++) {
	    
	    // Scan all possible node in the same TC
	    // and specify the node index to remove in the occ. 
	    // list
	    for ( vector<int>::iterator it_ct = CT[i].begin(),
		    it_ct_end = CT[i].end();
		  it_ct != it_ct_end; it_ct++) {
	      it_m_mp -> occurrence = (it_m) -> occurrence;
	      it_m_mp -> remove     = perm_1[*it_ct];
	      it_m_mp++; 
	    }
	  }
	  
	  // sort occurences with one column removing (same CT)
	  // Sort according to U
	  qsort( m_mp_list , CT[i].size() * nbr_motif_m, 
		 sizeof(m_mp_list_t), occurrences_order);
	  
	  // Print after the sort
	  m_mp_list_t *prev = m_mp_list;
	  int remove;
	
	  // Store temporary the extension
	  // stack pb 
	  // int ExtStack[ it_m_mp_end - m_mp_list];
	  // SEXP S_Exts[it_m_mp_end - m_mp_list];
	  // SEXP S_U[it_m_mp_end - m_mp_list];

	  int *ExtStack = new  int[ it_m_mp_end - m_mp_list ];
	  SEXP *S_Exts  = new SEXP[ it_m_mp_end - m_mp_list ];
	  SEXP *S_U     = new SEXP[ it_m_mp_end - m_mp_list ];

	  // Fuse the 4 lists
	  SEXP S_U_Fuse_List=0;      
	  size_t ExtStackSize = 0;
	  size_t U_index = 0;
	  SEXP S_Del_List;

	  // Store LambdaU and DeltaU
	  double LambdaU[2];
	  LambdaU[0] = 0.0;  LambdaU[1] = 0.0;
	  double DeltaU, gU;
	  
	  int *occ_tmp = new int[ k-1 ];

	  // New extension
#         if( MSG > 0)
	  cout << "    Position U" << endl;
#         endif
	  // Test empty list
	  if( m_mp_list != it_m_mp_end ) {
	    
	    for( m_mp_list_t *it_m_mp = m_mp_list; 
		 it_m_mp != it_m_mp_end; it_m_mp++, it_m++ ) {
	      ptr    = it_m_mp -> occurrence;
	      remove = it_m_mp -> remove;
	      
	      // New position
	      if( occurrences_order( it_m_mp, prev ) ) {
#               if( MSG > 0)
		cout << "    Position U" << endl;
#               endif 
		
		// To store occurences
		int *it_occ;
		
		//
		// Store previous U (position)
		//
		
		// Allocate and store previous extension 
		if( StoreOcc ) {
		  
		  // Store deletion class
		  /* Inv
		  int* ct_ptr = AllocateIntSEXP( CT[i].size(), 
						 S_Del_List, n_prot);
		  
		  for ( vector<int>::iterator it_ct = CT[i].begin(),
			  it_ct_end = CT[i].end();
			it_ct != it_ct_end; it_ct++, ct_ptr++ ) {
		    *ct_ptr = perm_1[ *it_ct ];
		  }
		  */
		  
		  AllocateAndStoreInSEXP( ExtStack, ExtStackSize, 
					  S_Exts[U_index], 
					  n_prot );
		  
		  // Allocate and store previous 'remove index' 
		  // AllocateAndStoreInSEXP( RemStack, ExtStackSize, 
		  // S_Remove[U_index], 
		  //			    n_prot );
		  
		  it_occ = AllocateAndStoreOccurInSEXP( prev->occurrence, k, 
							prev -> remove, 
							S_U[U_index], 
							n_prot );
		  
		} else if (ComputePValue)  {

		  // Compute LambdaU
		  
		  // Allocate and store previous occurence U
		  // Need to be stored even if StoreOcc == false
		  it_occ = AllocateAndStoreOccurInArray( prev->occurrence, k, 
							 prev -> remove, 
							 occ_tmp );
	       

		  
		  // The removed node must be permuted according to the 
		  // OptimizeGeometry permutation
		  LambdaU[ 0 ] = pmixnet.computeLambdaU( 
							G, 
							it_occ, 
							k-1,
							// First Ext
							ExtStack[0], 
							NodeToClass );
		  
		  DeltaU = (ExtStackSize -  LambdaU[ 0 ]) /  LambdaU[ 0 ];
		  
		  LambdaU[ 1 ] = DeltaU;
		  gU = computegU( LambdaU[ 0 ], DeltaU );
		  max_t = MAX( max_t, gU );

#                 if( MSG > 0)
		  cout << "    Lambda U, Delta U, gU : " 
		       << LambdaU[ 0 ] << " "
		       << DeltaU << " " 
		       << gU << " " 
		       << endl;
#                 endif
		}
		U_index++;
		ExtStackSize = 0;
		
		prev =  it_m_mp;
	      }

	      // Print occurrence
#             if( MSG > 0)
	      ptr    = it_m_mp -> occurrence;
	      cout << "      ";
	      for( int i_i=0 ; i_i < k; i_i++, ptr++){
		if( i_i != remove )
		  cout << *ptr << ", ";
	      } 
	      ptr    = it_m_mp -> occurrence;
	      cout << "[" << ptr[remove] << "]";
	      cout << endl;
#             endif
	      // Store extension and remove index
	      ExtStack[ExtStackSize ] = ptr[remove];
	      // RemStack[ExtStackSize ] = remove;
	      ExtStackSize++;
	      
	    }
	    
	    //
	    // Store last U (position)
	    //
	    
	    // To store Occurences
	    int *it_occ;
	    bool store_list=true;
	    
	    if ( StoreOcc ) {
	      
	      // Store deletion class
	      int* ct_ptr = AllocateIntSEXP( CT[i].size(), 
					   S_Del_List, n_prot);
	      
	      for ( vector<int>::iterator it_ct = CT[i].begin(),
		      it_ct_end = CT[i].end();
		    it_ct != it_ct_end; it_ct++, ct_ptr++ ) {
		*ct_ptr = perm_1[ *it_ct ];
	      }
	  
	      // Allocate and store previous extension
	      AllocateAndStoreInSEXP( ExtStack, ExtStackSize, S_Exts[U_index], 
				      n_prot );
	      
	      // AllocateAndStoreInSEXP( RemStack, ExtStackSize, 
	      // S_Remove[U_index], n_prot );
	      
	      it_occ = AllocateAndStoreOccurInSEXP( prev->occurrence, k, 
						    prev -> remove, 
						    S_U[U_index], 
						    n_prot );
	    } else if (ComputePValue)  {
	      
	      // Allocate and store previous occurence U
	      // Need to be stored even if StoreOcc == false
	      it_occ = AllocateAndStoreOccurInArray( prev->occurrence, k, 
						     prev -> remove, 
						     occ_tmp );


	      // Compute LambdaU
	      
	      LambdaU[ 0 ] = pmixnet.computeLambdaU( 
						    G, 
						    it_occ, 
						    k-1,
						    // First Ext
						    ExtStack[0], 
						    NodeToClass );
	      DeltaU = (ExtStackSize -  LambdaU[ 0 ]) /  LambdaU[ 0 ];
		  
	      LambdaU[ 1 ] = DeltaU;
	      gU = computegU( LambdaU[ 0 ], DeltaU );
	      max_t = MAX( max_t, gU );
#             if( MSG > 0)
	      cout << "    Lambda U, Delta U, gU : " 
		   << LambdaU[ 0 ] << ", "
		   << DeltaU << ", " 
		   << gU << ", " 
		   << endl;
#             endif
	    }
	    
	    // Number of occurences (m, m', U)
	    size_t  NbrOfOccur = U_index + 1;
	
	    // Store arrays in (NbrOfOccur) lists  
	    // unused SEXP S_RemList;
	    SEXP S_UList, S_ExtList;
	  
	    if (StoreOcc) {
	      PROTECT( S_UList  =allocVector(VECSXP, NbrOfOccur  )); n_prot++;
	      PROTECT( S_ExtList=allocVector(VECSXP, NbrOfOccur  )); n_prot++;
	      // PROTECT( S_RemList=allocVector(VECSXP, NbrOfOccur)); n_prot++;

	      for( size_t i_u = 0; i_u < NbrOfOccur; i_u++) { 
		SET_VECTOR_ELT( S_ExtList, i_u, S_Exts  [ i_u ] );
		SET_VECTOR_ELT( S_UList,   i_u, S_U     [ i_u ] );
		// SET_VECTOR_ELT( S_RemList, i_u, S_Remove[ i_u ] );
	      } 

	      // Store in the main fields
	      PROTECT( S_U_Fuse_List = allocVector(VECSXP, 3) ); n_prot++;
	      SET_VECTOR_ELT( S_U_Fuse_List, 0, S_Del_List);
	      SET_VECTOR_ELT( S_U_Fuse_List, 1, S_UList   );
	      SET_VECTOR_ELT( S_U_Fuse_List, 2, S_ExtList );

	    } else if ( ComputePValue) {

	      // Compute E( mp ) - mp submotif
	      // and p-value
	      
	      //
	      //   Get a SparseAdjacency on the current mp motif 
	      //
	      
	      if ( CT[i].begin() != CT[i].end() ) {
		
		// No empty list
		int *ij_mp_index = new int[ 2*(k-1)*(k-1)+2];
		ptr = (*its) -> canonic; 
		int rem = perm_1[ *( CT[i].begin() )];
		int pos = 0;
		for( int u=0 ; u < k*k; u++, ptr++){
		  if(*ptr) {
		    // row index - discard the removed node
		    int ii = u % k;
		    // col index - discard the removed node
		    int jj =  u / k;
		    if ( (ii != rem) && (jj != rem) ) {
		      ij_mp_index[pos+1]   = ii - ( ii > rem );
		      ij_mp_index[pos] = jj - ( jj > rem );
		      pos += 2;
		    }
		  }
		}
		// End list
		ij_mp_index[pos]   = NOT_INDEX;
		ij_mp_index[pos+1] = NOT_INDEX;
		
		SparseAdjacency mp( ij_mp_index, k-1, (directed==0) );
		// mp.print("mp :");
		
		// Not optimal : FindNotif can't be used because works 
		// on a connex network 
		NonRedondantPermutation NRPMotif( mp );
		
		SEXP S_PValue;
		SEXP S_Filter;
		
		double esp_mp;
		double proba = 0.0;
		esp_mp = pmixnet.computeMean( mp, NRPMotif );
		proba = exp( - max_t) * esp_mp;
		
#               if( MSG > 0)
		cout << "  max_t, esp_mp, proba : " << max_t << " "
		     << esp_mp << " " 
		     << proba << endl;
#               endif
		if ( proba <= PValue) {
		  // Store PValue
		  double *p_value = AllocateDoubleSEXP(1, S_PValue, n_prot);
		  *p_value = proba;

		  // allocate filter
		  int *p_filter = AllocateIntSEXP(4, S_Filter, n_prot);
		  for( int *p_=p_filter, *p_end=p_filter+4; p_ != p_end; p_++) {
		    *p_ = 1;
		  } 
		
		  // Store deletion class
		  int* ct_ptr = AllocateIntSEXP( CT[i].size(), 
						 S_Del_List, n_prot);
		  for ( vector<int>::iterator it_ct = CT[i].begin(),
			  it_ct_end = CT[i].end();
			it_ct != it_ct_end; it_ct++, ct_ptr++ ) {
		    *ct_ptr = perm_1[ *it_ct ];
		  }
	  
		  
		  PROTECT( S_U_Fuse_List = allocVector(VECSXP, 3) ); n_prot++;
		  SET_VECTOR_ELT( S_U_Fuse_List, 0, S_Del_List);
		  SET_VECTOR_ELT( S_U_Fuse_List, 1, S_Filter);
		  SET_VECTOR_ELT( S_U_Fuse_List, 2, S_PValue);
		} else {
		  // empty list
		  store_list = false;
		}
		delete [] ij_mp_index;
	      } else {
		// empty list
		store_list = false;
	      }
	      
	    }
	    
	    // Add an item to MP_List
	    if(store_list) { 
	      SET_VECTOR_ELT( S_MP_List, mp_index, S_U_Fuse_List);
	      mp_index++;
	    }
	    
	    
	  } // End new extension :  if( m_mp_list != it_m_mp_end )

	  delete [] m_mp_list;
	  delete [] ExtStack; 
	  delete [] S_Exts; 
	  delete [] S_U;
	  delete [] occ_tmp;

	} // DelClassFilter

      } // For each topologic class (m')
      
      if ( mp_index != 0 ) {
	if( useMotifFilter )
	  SET_VECTOR_ELT( S_M_List, 0, S_MP_List);
	else
	  SET_VECTOR_ELT( S_M_List, m_index, S_MP_List);

	// Store Canonic or Adjacency matrix
	
	SEXP S_Canonic;
	
	// Transpose canonic
	int *transp = new int[k*k];
	int *can =  (*its) -> canonic ;
	for ( int i=0; i < k; i++){
	  for ( int j=0; j < k; j++){
	    //	transp[ i + k * j] = can[  j + k * i];
	    transp[ i + k * j] = can[  i + k * j];
	  }
	}
	AllocateAndStoreInSEXP( transp, k*k, S_Canonic, n_prot );
	delete [] transp;

	// Add to canonic list
	if (useMotifFilter) {
	  SET_VECTOR_ELT( S_M_CanonicList, 0, S_Canonic );
	} else {
	  SET_VECTOR_ELT( S_M_CanonicList, m_index, S_Canonic );
	}
      }
      delete [] CT;

    } // Motif Filter
    if ( mp_index != 0) {
      m_index++;
    }
  } // Motif loop

  delete [] canonic;
  delete [] canonic_list;
  SEXP S_Result = R_NilValue;
  // Fuse the two fields
  if ( m_index !=0 ) {
    PROTECT( S_Result = allocVector(VECSXP, 2  )); n_prot++;
    SET_VECTOR_ELT( S_Result, 0, S_M_CanonicList );
    SET_VECTOR_ELT( S_Result, 1, S_M_List );
  } 
    
  // To avoid warnings
  LOGMSG(100, std::cout, "NULL message ", "" );

  delete [] Alpha;
  delete [] gamma;
  delete [] tempo;
  delete [] ij_index;
  delete [] Color;
  delete [] perm;
  delete [] perm_1;
  
  return S_Result;
}