diff --git a/src/apply.cc b/src/apply.cc
index 9adf1158c6e83adee1cae204efe638c8de5cb199..01f222eba286b8e08db35c95752b2f25050167fe 100644
--- a/src/apply.cc
+++ b/src/apply.cc
@@ -33,18 +33,10 @@ SEXP gmpMatToListZ(SEXP X, SEXP line)
 	  bigvec oneLine ;
 	  for(unsigned int j = 0; j < ncol; ++j)
 	    {
-	      oneLine.value.push_back(matrix.value[i+j*nrow]);
-
-	      // modulus, if one by cell
-	      if(matrix.modulus.size() ==matrix.value.size() )
-		oneLine.modulus.push_back(matrix.modulus[i+j*nrow]);
+	      oneLine.push_back(matrix[i+j*nrow]);
 
 	    }
 
-	  // modulus, if one by line
-	  if(((matrix.modulus.size() == nrow ) || (matrix.modulus.size() == 1) ) && (matrix.modulus.size() !=matrix.value.size()) )
-	    oneLine.modulus.push_back(matrix.modulus[i % matrix.modulus.size() ]);
-
 
 	  SET_VECTOR_ELT(ans, i,bigintegerR::create_SEXP(oneLine));
 
@@ -60,19 +52,10 @@ SEXP gmpMatToListZ(SEXP X, SEXP line)
 	  bigvec oneLine ;
 	  for(unsigned int i = 0; i < nrow; ++i)
 	    {
-	      oneLine.value.push_back(matrix.value[i+j*nrow]);
-
-	      // modulus, if one by cell
-	      if(matrix.modulus.size() ==matrix.value.size() )
-		oneLine.modulus.push_back(matrix.modulus[i+j*nrow]);
+	      oneLine.push_back(matrix[i+j*nrow]);
 
 	    }
 
-	  // modulus, if one by line
-	  if( (matrix.modulus.size() == 1)  && (matrix.modulus.size() !=matrix.value.size()) )
-	    oneLine.modulus.push_back(matrix.modulus[0 ]);
-
-
 	  SET_VECTOR_ELT(ans, j,bigintegerR::create_SEXP(oneLine));
 
 	}
diff --git a/src/biginteger.cc b/src/biginteger.cc
index 0beb5885fea584f38cf8c6f7b7e74c3bff48e0c1..409fa50d9cadf3e8e2a94017abef38d303606b73 100644
--- a/src/biginteger.cc
+++ b/src/biginteger.cc
@@ -4,7 +4,7 @@
  *  \version 1
  *
  *  \date Created: 27/10/04
- *  \date Last modified: Time-stamp: <2023-01-16 18:48:41 (antoine)>
+ *  \date Last modified: Time-stamp: <2023-01-21 21:01:28 (antoine)>
  *
  *  \author Immanuel Scholz
  *
@@ -17,10 +17,13 @@
 #include "biginteger.h"
 
 using std::string;
+static int count=0;
+static int countALL=0;
 
 biginteger::biginteger() 
   : na(true) {
-
+  count++;
+  countALL++;
   mpz_init(value);}
 
 
@@ -29,6 +32,8 @@ biginteger::biginteger()
  * Construct a biginteger from a int value.
  */
 biginteger::biginteger(const int value_) : na(false) {
+  count++;
+  countALL++;
   if(value_ ==  NA_INTEGER)
     {mpz_init(value); na = true  ;}
   else
@@ -38,6 +43,8 @@ biginteger::biginteger(const int value_) : na(false) {
  * Construct a biginteger from a long value.
  */
 biginteger::biginteger(const long int value_) : na(false) {
+  count++;
+  countALL++;
   if(value_ ==  NA_INTEGER)
     {mpz_init(value); na = true  ;}
   else
@@ -47,6 +54,8 @@ biginteger::biginteger(const long int value_) : na(false) {
  * Construct a biginteger from a unsigned long value.
  */
 biginteger:: biginteger(const unsigned long int value_) : na(false) {
+  count++;
+  countALL++;
   if(value_ == (unsigned long int) NA_INTEGER)
     {mpz_init(value); na = true  ;}
   else
@@ -56,6 +65,8 @@ biginteger:: biginteger(const unsigned long int value_) : na(false) {
  * Construct a biginteger from a double value.
  */
 biginteger::biginteger(const double value_) : na(false) {
+  count++;
+  countALL++;
   if( R_FINITE(value_) )
     mpz_init_set_d(value, value_);
   else
@@ -67,6 +78,8 @@ biginteger::biginteger(const double value_) : na(false) {
  */
 biginteger::biginteger(const std::string& value_) : na(false)
 {
+  count++;
+  countALL++;
   /* mpz_init.. return -1 when error, 0: ok */
   if(mpz_init_set_str(value, value_.c_str(), 0))
     {
@@ -82,6 +95,8 @@ biginteger::biginteger(const std::string& value_) : na(false)
  */
 biginteger::biginteger(const biginteger& rhs) : na(rhs.na)
 {
+  count++;
+  countALL++;
   mpz_init_set(value, rhs.getValueTemp());
 }
 
@@ -89,10 +104,16 @@ biginteger::biginteger(const biginteger& rhs) : na(rhs.na)
   /**
    * Free the owned mpz_t structs
    */
-biginteger::~biginteger() {mpz_clear(value);}
+biginteger::~biginteger() {
+  count--;
+  //  printf("nb : %d %d \n",count,countALL);
+  mpz_clear(value);
+}
 
 biginteger::biginteger(const char* raw)
 {
+  count++;
+  countALL++;
   mpz_init(value);
   na = true;
   const int* r = (int*)(raw);
@@ -117,6 +138,8 @@ biginteger::biginteger(const char* raw)
 biginteger::biginteger(const mpz_t value_)
     : na(false)
 {
+  count++;
+  countALL++;
   mpz_init_set(value, value_);
 }
 
diff --git a/src/biginteger.h b/src/biginteger.h
index 3277ab97299986ea29165542b2721d7dda2d67dd..6c9fecd36876f8ad1a22f0b384e7dcfcb7349030 100644
--- a/src/biginteger.h
+++ b/src/biginteger.h
@@ -2,7 +2,7 @@
  *  \brief Description of class biginteger
  *
  *  \date Created: 2004
- *  \date Last modified: Time-stamp: <2023-01-16 19:17:13 (antoine)>
+ *  \date Last modified: Time-stamp: <2023-01-17 18:20:27 (antoine)>
  *
  *  \author Immanuel Scholz
  *
diff --git a/src/bigintegerR.cc b/src/bigintegerR.cc
index 106e7b7f27eef1626a17a8c37c83da29a309003c..666510850002e4356917db17d805843604d27670 100644
--- a/src/bigintegerR.cc
+++ b/src/bigintegerR.cc
@@ -31,7 +31,6 @@ using namespace std;
 
 static gmp_randstate_t seed_state;
 static int seed_init=0;
-
 namespace bigintegerR
 {
   // \brief create a vector of bigvecs, all without a modulus.
@@ -48,10 +47,10 @@ namespace bigintegerR
 	int pos = sizeof(int); // position in raw[]. Starting after header.
 	int sizevec = ((int*)raw)[0];
 	//std::cout << "nb element a lire " << sizevec << std::endl;
-	v.value.resize(sizevec);
+	v.resize(sizevec);
 	for (int i = 0; i < sizevec; ++i) {
-	  v.value[i] = biginteger(&raw[pos]);
-	  pos += v.value[i].raw_size(); // increment number of bytes read.
+	  v[i].setValue(make_shared<biginteger>(&raw[pos]));
+	  pos += v[i].getValue().raw_size(); // increment number of bytes read.
 	}
 	return v;
       }
@@ -60,30 +59,33 @@ namespace bigintegerR
 	double* d = REAL(param);
 	//bigvec v(d,d+LENGTH(param));
 	bigvec v;
-	v.value.resize(LENGTH(param));
+	v.resize(LENGTH(param));
 	for (int j = 0; j < LENGTH(param); ++j) {
 	    /// New:   numeric '+- Inf'  give  +- "Large" instead of NA
 	    double dj = d[j];
 	    if(R_FINITE(dj) || ISNAN(dj))
-		v.value[j] = dj;
+	      v[j].setValue(make_shared<biginteger>( dj ));
 	    else { // dj is +- Inf : use LARGE ( =   +- 2 ^ 80000 -- arbitrarily )
-		mpz_t LARGE;
-		mpz_init(LARGE);
-		// FIXME: Keep 'LARGE' a static const; initialized only once
+	      mpz_t LARGE;
+	      mpz_init(LARGE);
+	      // FIXME: Keep 'LARGE' a static const; initialized only once
+
+	      if(dj == R_PosInf){
 		mpz_ui_pow_ui (LARGE, (unsigned long int) 2, (unsigned long int) 8000);
-		if(dj == R_PosInf)
-		    v.value[j] = LARGE;
-		else if(dj == R_NegInf) {
-		    mpz_t neg_L;
-		    mpz_init(neg_L);
-		    mpz_neg(neg_L, LARGE);
-		    v.value[j] = neg_L;
-		    mpz_clear(neg_L);
-		}
-		else// should never happen
-		    v.value[j] = dj;
-
-		mpz_clear(LARGE);
+		v[j].setValue(make_shared<biginteger>(LARGE));
+	      }
+	      else if(dj == R_NegInf) {
+		mpz_t neg_L;
+		mpz_init(neg_L);
+		mpz_neg(neg_L, LARGE);
+		v[j].setValue( make_shared<biginteger>(neg_L));
+		mpz_clear(neg_L);
+	      }
+	      else// should never happen
+		v[j].setValue( make_shared<biginteger>(dj));
+	      
+	      mpz_clear(LARGE);
+
 	    }
 	}
 	return v;
@@ -94,22 +96,20 @@ namespace bigintegerR
 	int* i = INTEGER(param);
 	//bigvec v(i,i+LENGTH(param));
 	bigvec v;
-	v.value.resize(LENGTH(param));
+	v.resize(LENGTH(param));
 
 	for (int j = 0; j < LENGTH(param); ++j)
-	    v.value[j] = i[j];
+	  v[j].setValue( make_shared<biginteger>(i[j]));
 
 	return v;
       }
     case STRSXP:
       {
 	bigvec v;
-	v.value.resize(LENGTH(param));
+	v.resize(LENGTH(param));
 	for (int i = 0; i < LENGTH(param); ++i) {
-	  if (STRING_ELT(param,i) == NA_STRING)
-	    v.value[i]= biginteger();
-	  else
-	    v.value[i]=biginteger(std::string(CHAR(STRING_ELT(param,i))));
+	  if (STRING_ELT(param,i) != NA_STRING)
+	    v[i].setValue(make_shared<biginteger>(std::string(CHAR(STRING_ELT(param,i)))));
 	}
 	return v;
       }
@@ -141,7 +141,11 @@ namespace bigintegerR
     if (TYPEOF(modAttr) != NILSXP)
       {
 	//std::cout << "import value" << std::endl;
-	v.modulus = bigintegerR::create_vector(modAttr).value;
+	bigvec vMod = bigintegerR::create_vector(modAttr);
+	for (int i = 0 ; i < v.size(); i++){
+	  v[i].setModulus(vMod[i % vMod.size()].getValuePtr());
+	}
+	v.setType(vMod.size() == 1 ? TYPE_MODULUS::MODULUS_GLOBAL :  TYPE_MODULUS::MODULUS_BY_CELL);
       }
     return v;
 
@@ -155,7 +159,6 @@ namespace bigintegerR
 	double* d = REAL(param);
 	// copy vector manually to avoid stupid conversion warning in STL-code :-/
 	vector<int> v;
-	v.reserve(LENGTH(param));
 	for (int i = 0; i < LENGTH(param); ++i)
 	  v.push_back(static_cast<int>(d[i]));
 	return v;
@@ -174,26 +177,35 @@ namespace bigintegerR
   }
 
 
-  SEXP create_SEXP(const std::vector<biginteger>& v)
+  SEXP create_SEXP(const bigvec & v , bigmod_accessor_fn fct, int size)
   {
     unsigned int i;
-    int size = sizeof(int); // starting with vector-size-header
-    for (i = 0; i < v.size(); ++i)
-      size += v[i].raw_size(); // adding each bigint's needed size
-    SEXP ans = PROTECT(Rf_allocVector(RAWSXP, size));
+    int sizeRaw = sizeof(int); // starting with vector-size-header
+    for (i = 0; i < size; ++i)
+      sizeRaw += fct(v[i]).raw_size(); // adding each bigint's needed size
+    SEXP ans = PROTECT(Rf_allocVector(RAWSXP, sizeRaw));
     // Rprintf("    o create_SEXP(vect<biginteger>): size=%d, v.size()=%d\n", size, v.size());
     char* r = (char*)(RAW(ans));
-    ((int*)(r))[0] = v.size(); // first int is vector-size-header
+    ((int*)(r))[0] = size; // first int is vector-size-header
     int pos = sizeof(int); // current position in r[] (starting after vector-size-header)
-    for (i = 0; i < v.size(); ++i)
-      pos += v[i].as_raw(&r[pos]);
+    for (i = 0; i < size; ++i)
+      pos += fct(v[i]).as_raw(&r[pos]);
     UNPROTECT(1);
     return(ans);
   }
 
-  SEXP create_SEXP(const bigvec& v) {
 
-    SEXP ans = PROTECT(create_SEXP(v.value));
+ const biginteger & bigModToValue(const bigmod& v){
+    return v.getValue();
+  }
+
+ const biginteger & bigModToModulus(const bigmod& v){
+    return v.getModulus();
+  }
+
+  SEXP create_SEXP(const bigvec& v) {
+    int size = v.size();
+    SEXP ans = PROTECT(create_SEXP(v, bigModToValue, size));
     // set the class attribute to "bigz"
     Rf_setAttrib(ans, R_ClassSymbol, Rf_mkString("bigz"));
 
@@ -208,8 +220,9 @@ namespace bigintegerR
       UNPROTECT(2);
     }
     // set the mod attribute
-    if(v.modulus.size() > 0) {
-      SEXP mod = PROTECT(create_SEXP(v.modulus)); // and set *its* class
+    if(v.getType() !=  TYPE_MODULUS::NO_MODULUS && v.size() > 0 ) {
+      int sizeM = v.getType() ==  TYPE_MODULUS::MODULUS_GLOBAL ? 1 : size;
+      SEXP mod = PROTECT(create_SEXP(v, bigModToModulus, sizeM )); // and set *its* class
       Rf_setAttrib(mod, R_ClassSymbol, Rf_mkString("bigz"));
       Rf_setAttrib(ans, Rf_mkString("mod"), mod);
       UNPROTECT(1);
@@ -228,12 +241,21 @@ namespace bigintegerR
   {
     bigvec va = bigintegerR::create_bignum(a);
     bigvec vb = bigintegerR::create_bignum(b), result;
-    int size = (va.value.empty() || vb.value.empty()) ? 0 : max(va.value.size(), vb.value.size());
-    result.value.reserve(size);
-    for (int i = 0; i < size; ++i)
+    int size = (va.size() ==0 || vb.size()==0 ) ? 0 : max(va.size(), vb.size());
+
+ 
+    int nrow = matrixz::checkDims(va.nrow,vb.nrow);
+    if(result.nrow == -2){
+      va.clear();
+      vb.clear();
+      error(_("Matrix dimensions do not match"));
+    }
+    
+   for (int i = 0; i < size; ++i)
 	result.push_back(f(va[i%va.size()], vb[i%vb.size()]));
 
-    result.nrow = matrixz::checkDims(va.nrow,vb.nrow);
+    result.nrow = nrow;
+
     // Rprintf(" o bigI_b_op(.); size=%d -> nrow=%d\n", size, result.nrow);
     return bigintegerR::create_SEXP(result);
   }
@@ -243,22 +265,28 @@ namespace bigintegerR
   {
     bigvec va = bigintegerR::create_bignum(a);
     bigvec vb = bigintegerR::create_bignum(b), result;
-    int size = (va.value.empty() || vb.value.empty()) ? 0 : max(va.value.size(), vb.value.size());
+
+    int nrow = matrixz::checkDims(va.nrow,vb.nrow) ;
+    if(nrow == -2){
+      va.clear();
+      vb.clear();
+      error(_("Matrix dimensions do not match"));
+    }
+    
+    int size = (va.size()==0 || vb.size() == 0) ? 0 : max(va.size(), vb.size());
     //	int sizemod = max(va.modulus.size(), vb.modulus.size());
     SEXP ans = PROTECT(Rf_allocVector(LGLSXP, size));
     int *r = LOGICAL(ans);
     /* TODO: this kind of situation 5 == (5 %% 17)*/
     for (int i = 0; i < size; ++i) {
-      biginteger am = va.value[i % va.value.size()];
-      biginteger bm = vb.value[i % vb.value.size()];
+      biginteger & am = va[i % va.size()].getValue();
+      biginteger & bm = vb[i % vb.size()].getValue();
       if (am.isNA() || bm.isNA())
 	r[i] = NA_LOGICAL;
       else
 	r[i] = f(am, bm) ? 1 : 0;
     }
 
-    int nrow = matrixz::checkDims(va.nrow,vb.nrow) ;
-
     // Add dimension parameter when available
     if(nrow >= 0)
       {
@@ -306,32 +334,43 @@ SEXP biginteger_div (SEXP a, SEXP b) { // called from  "/.bigz" == div.bigz
     bigvec A = bigintegerR::create_bignum(a),
 	B = bigintegerR::create_bignum(b);
     // Note: a or b may be simple numbers (e.g. '1') => work with (A,B)
-    int len_m_a = A.modulus.size(),
-	len_m_b = B.modulus.size();
-    if(len_m_a == 0 && len_m_b == 0) // deal with important case quickly:
+    TYPE_MODULUS type_a = A.getType();
+    TYPE_MODULUS type_b = B.getType();
+
+    if(type_a == TYPE_MODULUS::NO_MODULUS && type_b == TYPE_MODULUS::NO_MODULUS) // deal with important case quickly:
+      {
 	return bigrational_div(a, b);
-    else if(len_m_a == 0) { // and  len_m_b > 0:
+      }
+    else if(type_a == TYPE_MODULUS::NO_MODULUS) { // and  len_m_b > 0:
 	// should work directly using b's "mod" --> compute  a * b^(-1)
     }
-    else if(len_m_b == 0) { // and  len_m_a > 0:
-	// should use a's "mod" for b: div_via_inv() need's  b's modulus
-	B.modulus = A.modulus;
-	return bigintegerR::biginteger_binary_operation(a,
-							bigintegerR::create_SEXP(B),
-							div_via_inv);
+    else if(type_b == TYPE_MODULUS::NO_MODULUS) { // and  len_m_a > 0:
+      // should use a's "mod" for b: div_via_inv() need's  b's modulus
+      if(type_a == TYPE_MODULUS::MODULUS_GLOBAL){
+	B.setGlobalModulus(A.getGlobalModulus());
+      } else{
+	for (unsigned int i = 0 ; i < B.size(); i++){
+	  B[i].setModulus(A[i % A.size()].getModulusPtr());
+	}
+      }
+      return bigintegerR::biginteger_binary_operation(a,
+						      bigintegerR::create_SEXP(B),
+						      div_via_inv);
     }
     else { // len_m_a > 0 and  len_m_b > 0:
 	bool same_mod = true;// are the two mods the "same" (after recycling)?
+	int len_m_a = A.getModulusSize();
+	int len_m_b = B.getModulusSize();
 	int m = (len_m_a < len_m_b) ? len_m_b : len_m_a; // = max(l..a, l..b)
-	for(int i = 0; i < m; i++)
-	    if(A.modulus[i % len_m_a] != B.modulus[i % len_m_b])  {
-		same_mod = false; break;
-	    }
+	for(unsigned int i = 0; i < m; i++)
+	  if(A[i % len_m_a].getModulus() != B[i % len_m_b].getModulus())  {
+	    same_mod = false; break;
+	  }
 	if(same_mod) {
-	    // compute   a * b^(-1) ... should work w/o more
+	  // compute   a * b^(-1) ... should work w/o more
 	} else {
-	    // use *rational* a/b  (not considering 'mod' anymore):
-	    return bigrational_div(a, b);
+	  // use *rational* a/b  (not considering 'mod' anymore):
+	  return bigrational_div(a, b);
 	}
     }
     return bigintegerR::biginteger_binary_operation(a,b, div_via_inv);
@@ -340,11 +379,11 @@ SEXP biginteger_div (SEXP a, SEXP b) { // called from  "/.bigz" == div.bigz
 SEXP biginteger_pow (SEXP a, SEXP b) {
   bigvec v = bigintegerR::create_bignum(a),
     exp = bigintegerR::create_bignum(b);
-  if(v.modulus.size() == 0) { /* has no modulus: now, if any b < 0, the
+  if(v.getType() == TYPE_MODULUS::NO_MODULUS) { /* has no modulus: now, if any b < 0, the
 				 result must be (non-integer) bigrational */
     bool use_rat = FALSE;
-    for (unsigned int i = 0; i < exp.value.size(); ++i) {
-      if(mpz_sgn(exp.value[i].getValueTemp()) < 0) {
+    for (unsigned int i = 0; i < exp.size(); ++i) {
+      if(mpz_sgn(exp[i].getValue().getValueTemp()) < 0) {
 	use_rat = TRUE;
 	break;
       }
@@ -384,9 +423,11 @@ SEXP biginteger_as_character(SEXP a, SEXP b)
   bigvec v = bigintegerR::create_bignum(a);
   SEXP ans;
   int base =  Rf_asInteger(b);
-  if (base < 2 || base > 36)
+  if (base < 2 || base > 36){
+    v.clear();
     error(_("select a base between 2 and 36"));
-
+  }
+  
   PROTECT(ans = Rf_allocVector(STRSXP, v.size()));
   for (unsigned int i = 0; i < v.size(); ++i)
     SET_STRING_ELT(ans, i, Rf_mkChar(v.str(i,base).c_str()));
@@ -395,7 +436,7 @@ SEXP biginteger_as_character(SEXP a, SEXP b)
     {
       SEXP dim = PROTECT(Rf_allocVector(INTSXP, 2));
       INTEGER(dim)[0] = v.nrow;
-      INTEGER(dim)[1] = v.value.size() / v.nrow;
+      INTEGER(dim)[1] = v.size() / v.nrow;
       Rf_setAttrib(ans, Rf_mkString("dim"), dim);
       UNPROTECT(1);
     }
@@ -410,7 +451,7 @@ SEXP biginteger_as_numeric(SEXP a)
   SEXP ans = PROTECT(Rf_allocVector(REALSXP,v.size()));
   double *r = REAL(ans);
   for (unsigned int i = 0; i < v.size(); ++i)
-    r[i] = v.value[i].isNA() ? NA_REAL : v.value[i].as_double();
+    r[i] = v[i].isNA() ? NA_REAL : v[i].getValue().as_double();
   UNPROTECT(1);
   return ans;
 }
@@ -421,14 +462,14 @@ SEXP biginteger_as_integer(SEXP a)
   SEXP ans = PROTECT(Rf_allocVector(INTSXP,v.size()));
   int *r = INTEGER(ans);
   for (unsigned int i = 0; i < v.size(); ++i) {
-    if(v.value[i].isNA()) {
+    if(v[i].isNA()) {
       r[i] = NA_INTEGER;
     }
-    else if(!mpz_fits_slong_p(v.value[i].getValueTemp())) {
+    else if(!mpz_fits_slong_p(v[i].getValue().getValueTemp())) {
       Rf_warning("NAs introduced by coercion from big integer");
       r[i] = NA_INTEGER;
     } else {
-      r[i] = mpz_get_si(v.value[i].getValueTemp());
+      r[i] = mpz_get_si(v[i].getValue().getValueTemp());
     }
   }
   UNPROTECT(1);
@@ -476,6 +517,8 @@ SEXP biginteger_set_at(SEXP src, SEXP idx, SEXP value)
   }
 
   if(vvalue.size() == 0) {
+    vvalue.clear();
+    result.clear();
     error(_("replacement has length zero"));
   }
  
@@ -560,8 +603,9 @@ SEXP biginteger_c(SEXP args)
   bigvec result;
   for(int i=0; i < LENGTH(args); i++) {
     bigvec v = bigintegerR::create_bignum(VECTOR_ELT(args,i));
-    for(unsigned int j=0; j < v.size(); j++)
+    for(unsigned int j=0; j < v.size(); j++){
       result.push_back(v[j]);
+    }
     v.clear();
   }
   return bigintegerR::create_SEXP(result);
@@ -574,7 +618,7 @@ SEXP biginteger_rep(SEXP x, SEXP times)
     result;
   int rep =  Rf_asInteger(times);
 
-  result.value.reserve(v.size()*rep);
+
   for(int i = 0 ; i < rep ; i++)
     for(unsigned int j = 0 ; j < v.size() ; j++)
       result.push_back(v[j]);
@@ -605,7 +649,7 @@ SEXP biginteger_nextprime(SEXP a)
 {
   bigvec v = bigintegerR::create_bignum(a),
     result;
-  result.value.reserve(v.size());
+
 
   mpz_t val;
   mpz_init(val);
@@ -613,7 +657,7 @@ SEXP biginteger_nextprime(SEXP a)
 
   for (unsigned int i = 0; i < v.size(); ++i) {
     mpz_nextprime(val,v[i].getValue().getValueTemp());
-    result.push_back(DefaultBigMod(val));
+    result.push_back(bigmod(val));
   }
   return bigintegerR::create_SEXP(result);
 }
@@ -622,7 +666,7 @@ SEXP biginteger_abs(SEXP a)
 {
   bigvec v = bigintegerR::create_bignum(a),
     result;
-  result.value.reserve(v.size());
+
 
   mpz_t val;
   mpz_init(val);
@@ -631,14 +675,9 @@ SEXP biginteger_abs(SEXP a)
   for (unsigned int i = 0; i < v.size(); ++i)
     {
       mpz_abs(val,v[i].getValue().getValueTemp());
-      result.push_back(DefaultBigMod(val));
-
-      // TODO: understand why following lines don't work.
-      //result.push_back(bigmod());
-      //result[i].value.setValue(val);
+      result.push_back(bigmod(make_shared<biginteger>(val),v[i].getModulusPtr()));
     }
 
-  result.modulus = v.modulus;
   return bigintegerR::create_SEXP(result);
 }
 
@@ -657,7 +696,6 @@ SEXP biginteger_gcdex(SEXP a, SEXP b)
   if(va.size() != vb.size())
     return bigintegerR::create_SEXP(bigvec());
 
-  result.value.reserve(3*va.size());
 
   mpz_t g;
   mpz_t s;
@@ -668,17 +706,15 @@ SEXP biginteger_gcdex(SEXP a, SEXP b)
   mpz_t_sentry val_g(g);
   mpz_t_sentry val_s(s);
   mpz_t_sentry val_t(t);
+  shared_ptr<biginteger> mod = make_shared<biginteger>(); // NA
 
   for(unsigned int i=0; i < va.size(); i++)
     {
       mpz_gcdext (g,s,t,va[i].getValue().getValueTemp(),vb[i].getValue().getValueTemp());
-      result.value.push_back(biginteger(g)); // Hem... not very elegant !
-      result.value.push_back(biginteger(s));
-      result.value.push_back(biginteger(t));
-      /*      result[i*3].value.setValue(g);
-      result[i*3+1].value.setValue(s);
-      result[i*3+2].value.setValue(t);*/
-
+      result.push_back(bigmod(make_shared<biginteger>(g))); 
+      result.push_back(bigmod(make_shared<biginteger>(s)));
+      result.push_back(bigmod(make_shared<biginteger>(t)));
+      
     }
   return bigintegerR::create_SEXP(result);
 }
@@ -710,7 +746,6 @@ SEXP biginteger_rand_u (SEXP nb, SEXP length, SEXP newseed, SEXP ok)
   size =  Rf_asInteger(nb);
   UNPROTECT(3);
 
-  result.value.reserve(size);
 
   /* Random seed initialisation */
 
@@ -734,7 +769,7 @@ SEXP biginteger_rand_u (SEXP nb, SEXP length, SEXP newseed, SEXP ok)
     {
       /*  Random number generation  */
       mpz_urandomb(bz,seed_state,len);
-      result.push_back(DefaultBigMod(bz));
+      result.push_back(bigmod(bz));
     }
   return bigintegerR::create_SEXP(result);
 }
@@ -764,11 +799,11 @@ SEXP bigI_factorial(SEXP n)
 {
   bigvec result;
   int *nn = INTEGER(AS_INTEGER(n)), size = Rf_length(n);
-  result.value.resize(size);
+  result.resize(size);
   for (int i = 0; i < size; ++i) {
-    result.value[i].NA(false);
+    result[i].getValue().NA(false);
     if(nn[i] != NA_INTEGER && nn[i] >= 0) {
-      mpz_fac_ui(result.value[i].getValue(), (unsigned long int)nn[i]);
+      mpz_fac_ui(result[i].getValue().getValue(), (unsigned long int)nn[i]);
     }
   }
   return bigintegerR::create_SEXP(result);
@@ -782,20 +817,23 @@ SEXP bigI_choose(SEXP n, SEXP k)
 {
   bigvec result, n_ = bigintegerR::create_bignum(n);
   int *kk = INTEGER(AS_INTEGER(k)), n_k = Rf_length(k);
-  int size = (n_.value.empty() || n_k == 0) ? 0 :
+  int size = (n_.size() == 0 || n_k == 0) ? 0 :
     // else:  max(n_.value.size(), n_k)
-    (((int)n_.value.size() <= n_k) ? n_k : n_.value.size());
+    (((int)n_.size() <= n_k) ? n_k : n_.size());
 
-  result.value.resize(size);
+  result.resize(size);
+  // if(n_.getType() ==  MODULUS_GLOBAL){
+  //   result.setGlobalModulus(n_.getGlobalModulus());
+  //}
   for (int i = 0; i < size; ++i) {
-    result.value[i].NA(false);
+    result[i].getValue().NA(false);
     int ik_i = kk[i % n_k];
     // check if k in range:
     if(ik_i != NA_INTEGER && ik_i >= 0) {
       unsigned long int k_i = (unsigned long int)ik_i;
       /* void mpz_bin_ui (mpz_t ROP, mpz_t N, unsigned long int K) */
-      mpz_bin_ui(result.value[i].getValue(),
-		 n_.value[i % n_.value.size()].getValueTemp(), k_i);
+      mpz_bin_ui(result[i].getMpValue(),
+		 n_[i % n_.size()].getValueTemp(), k_i);
     }
   }
   return bigintegerR::create_SEXP(result);
@@ -818,7 +856,7 @@ SEXP bigI_fibnum(SEXP n)
       mpz_t_sentry val_s(val);
 
       mpz_fib_ui(val,num);
-      result.push_back(DefaultBigMod(val));
+      result.push_back(bigmod(val));
       //      result[0].value.setValue(val);
     }
   // else
@@ -840,7 +878,7 @@ SEXP bigI_fibnum2(SEXP n)
       unsigned long int num = nn;
       if(nn < 0 || nn == NA_INTEGER)
 	  error(_("argument must be non-negative"));
-      result.value.reserve(1);
+
       mpz_t val;
       mpz_init(val);
       mpz_t_sentry val_s(val);
@@ -849,8 +887,8 @@ SEXP bigI_fibnum2(SEXP n)
       mpz_t_sentry val_s2(val2);
 
       mpz_fib2_ui(val,val2, num);
-      result.push_back(DefaultBigMod(val2));
-      result.push_back(DefaultBigMod(val));
+      result.push_back(bigmod(val2));
+      result.push_back(bigmod(val));
     }
   else
     error(_("argument must not be an empty list"));
@@ -877,7 +915,7 @@ SEXP bigI_lucnum(SEXP n)
       mpz_t_sentry val_s(val);
 
       mpz_lucnum_ui(val,num);
-      result.push_back(DefaultBigMod(val));
+      result.push_back(bigmod(val));
     }
   // else
   //   error(_("argument must not be an empty list"));
@@ -906,8 +944,8 @@ SEXP bigI_lucnum2(SEXP n)
     mpz_t_sentry val_s2(val2);
 
     mpz_lucnum2_ui(val,val2,num);
-    result.push_back(DefaultBigMod(val2));
-    result.push_back(DefaultBigMod(val));
+    result.push_back(bigmod(val2));
+    result.push_back(bigmod(val));
   }
   else
     error(_("argument must not be an empty list"));
@@ -932,31 +970,16 @@ SEXP biginteger_max(SEXP a, SEXP narm)
 
   for(unsigned int i = 1 ; i < va.size(); ++i)
     {
-      if(va.value[i].isNA() && !na_remove)
+      if(va[i].isNA() && !na_remove)
 	return(bigintegerR::create_SEXP(result));
       else
-	if(!(va.value[i] <  va.value[maximum] ))
+	if(va[i].getValue() > va[maximum].getValue() )
 	  maximum = i; // if va.value[maximum = 0] is NA => false for the "<" => maximum changed = good
     }
 
-  result.push_back(va.value[maximum]);
+  result.push_back(va[maximum]);
 
-
-  // now the modulus !
-  if(va.modulus.size() == 1)
-    result.modulus.push_back(va.modulus[0]);
-
-  if(va.modulus.size()>1)
-    {
-      biginteger modulus ;
-      modulus.setValue(va.modulus[0].getValueTemp());
-      for(unsigned int i = 1 ; i < va.modulus.size() ; ++i)
-	{
-	  if(modulus != va.modulus[i]) // if one is different: no modulus
-	    return(bigintegerR::create_SEXP(result));
-	}
-      result.modulus.push_back(modulus);
-    }
+  if(va.getType() == TYPE_MODULUS::MODULUS_BY_CELL) result[0].getModulus().NA(TRUE);
 
   return(bigintegerR::create_SEXP(result));
 }
@@ -976,30 +999,17 @@ SEXP biginteger_min(SEXP a, SEXP narm)
 
   for(unsigned int i = 1 ; i < va.size(); ++i)
     {
-      if(va.value[i].isNA() && !na_remove)
+      if(va[i].isNA() && !na_remove)
 	return bigintegerR::create_SEXP(result);
       else
-	if(!(va.value[i] >  va.value[minimum] ))
+	if(va[i].getValue() <  va[minimum].getValue() )
 	  minimum = i;
     }
 
-  result.push_back(va.value[minimum]);
+  result.push_back(va[minimum]);
 
   // now the modulus !
-  if(va.modulus.size() == 1)
-    result.modulus.push_back(va.modulus[0]);
-
-  if(va.modulus.size()>1)
-    {
-      biginteger modulus ;
-      modulus.setValue(va.modulus[0].getValueTemp());
-      for(unsigned int i = 1 ; i < va.modulus.size() ; ++i)
-	{
-	  if(modulus != va.modulus[i]) // if one is different: no modulus
-	    return bigintegerR::create_SEXP(result);
-	}
-      result.modulus.push_back(modulus);
-    }
+  if(va.getType() == TYPE_MODULUS::MODULUS_BY_CELL) result[0].getModulus().NA(TRUE);
 
   return bigintegerR::create_SEXP(result);
 }
@@ -1009,48 +1019,31 @@ SEXP biginteger_cumsum(SEXP a)
 {
   bigvec result, va = bigintegerR::create_bignum(a);
 
-  result.value.resize(va.value.size());
+  result.resize(va.size());
 
   mpz_t val;
   mpz_init(val);
   mpz_t_sentry val_s(val);
 
-  bool hasmodulus = true;
-
-  // first the modulus !
-  if(va.modulus.size() > 1) {
-      biginteger modulus ;
-      modulus.setValue(va.modulus[0].getValueTemp());
-
-      for(unsigned int i = 1 ; i < va.modulus.size() ; ++i) {
-	    if(modulus != va.modulus[i]) { // if one is different: no modulus
-		hasmodulus = false;
-		break;
-	    }
-      }
-      if(hasmodulus)
-	result.modulus.push_back(modulus);
-  }
-  else if(va.modulus.size() == 1) {
-      result.modulus.push_back(va.modulus[0]);
-      hasmodulus = true;
-  }
-  else hasmodulus = false;
+  bool hasmodulus = va.getType() == TYPE_MODULUS::MODULUS_GLOBAL;
 
+ 
   for(unsigned int i = 0 ; i < va.size(); ++i)
     {
       {
-	if(va.value[i].isNA() )
+	if(va[i].isNA() )
 	  {
 	    break; // all last values are NA.
 	  }
 
-	mpz_add(val,val,va.value[i].getValueTemp());
-
-	if(hasmodulus)
-	  mpz_mod(val,val,va.modulus[0].getValueTemp() );
+	mpz_add(val,val,va[i].getValue().getValueTemp());
 
-	result.value[i].setValue(val);
+	if(hasmodulus){
+	  mpz_mod(val,val,va.getGlobalModulus()->getValueTemp() );
+	  result[i].setModulus(va.getGlobalModulus());
+	}
+	result[i].getValue().setValue(val);
+	
       }
     }
 
@@ -1063,55 +1056,33 @@ SEXP biginteger_sum(SEXP a)
 {
   bigvec result, va = bigintegerR::create_bignum(a);
 
-  result.value.resize(1);
+  result.resize(1);
 
   mpz_t val;
   mpz_init(val);
   mpz_t_sentry val_s(val);
 
-  bool hasmodulus = true;
-
-  // first the modulus !
-  if(va.modulus.size() > 1) {
-      biginteger modulus ;
-      modulus.setValue(va.modulus[0].getValueTemp());
-
-      for(unsigned int i = 1 ; i < va.modulus.size() ; ++i) {
-	    if(modulus != va.modulus[i]) { // if one is different: no modulus
-		hasmodulus = false;
-		break;
-	    }
-      }
-      if(hasmodulus)
-	result.modulus.push_back(modulus);
-  }
-  else if(va.modulus.size() == 1) {
-      result.modulus.push_back(va.modulus[0]);
-      hasmodulus = true;
-  }
-  else
-      hasmodulus = false;
-
-
+  bool hasmodulus = va.getType() == TYPE_MODULUS::MODULUS_GLOBAL;
 
 
 
   for(unsigned int i = 0 ; i < va.size(); ++i)
     {
       {
-	if(va.value[i].isNA() )
+	if(va[i].isNA() )
 	  {
 	    break; // all last values are NA.
 	  }
 
-	mpz_add(val,val,va.value[i].getValueTemp());
+	mpz_add(val,val,va[i].getValueTemp());
 
 	if(hasmodulus)
-	  mpz_mod(val,val,va.modulus[0].getValueTemp() );
+	  mpz_mod(val,val,va.getGlobalModulus()->getValueTemp() );
       }
     }
 
-  result.value[0].setValue(val);
+  result[0].setValue(val);
+  if(hasmodulus) result[0].setModulus(va.getGlobalModulus());
 
   return(bigintegerR::create_SEXP(result));
 }
@@ -1122,54 +1093,31 @@ SEXP biginteger_prod(SEXP a)
   bigvec result;
   bigvec va = bigintegerR::create_bignum(a);
 
-  result.value.resize(1);
+  result.resize(1);
 
   mpz_t val;
   mpz_init(val);
   mpz_set_ui(val,1);
   mpz_t_sentry val_s(val);
 
-  bool hasmodulus = true;
-
-  // first the modulus !
-  if(va.modulus.size()>1)
-    {
-      biginteger modulus ;
-      modulus.setValue(va.modulus[0].getValueTemp());
-
-      for(unsigned int i = 1 ; i < va.modulus.size() ; ++i) {
-	if(modulus != va.modulus[i]) { // if one is different: no modulus
-	  hasmodulus = false;
-	  break;
-	}
-      }
-      if(hasmodulus)
-	result.modulus.push_back(modulus);
-
-    }
-  else
-    hasmodulus = false;
-
-  if(va.modulus.size() == 1)
-    {
-      result.modulus.push_back(va.modulus[0]);
-      hasmodulus = true;
-    }
+  bool hasmodulus = va.getType() == TYPE_MODULUS::MODULUS_GLOBAL;
 
+  
   for(unsigned int i = 0 ; i < va.size(); ++i)
     {
-      if(va.value[i].isNA() )
+      if(va[i].isNA() )
 	{
 	  return (bigintegerR::create_SEXP(result));
 	}
 
-      mpz_mul(val,val,va.value[i].getValueTemp());
+      mpz_mul(val,val,va[i].getValue().getValueTemp());
 
       if(hasmodulus)
-	mpz_mod(val,val,va.modulus[0].getValueTemp() );
+	mpz_mod(val,val,va.getGlobalModulus()->getValueTemp() );
     }
 
-  result.value[0].setValue(val);
+  result[0].setValue(val);
+  if(hasmodulus) result[0].setModulus(va.getGlobalModulus());
 
   return(bigintegerR::create_SEXP(result));
 }
@@ -1183,18 +1131,18 @@ SEXP biginteger_powm(SEXP x, SEXP y, SEXP n)
   bigvec vy = bigintegerR::create_bignum(y);
   bigvec vn = bigintegerR::create_bignum(n);
 
-  result.value.resize(vx.value.size());
-
-  for (unsigned int i = 0 ; i < vx.value.size(); i++)
+  result.resize(vx.size());
+  result.setGlobalModulus(vn[0].getValuePtr());
+  for (unsigned int i = 0 ; i < vx.size(); i++)
   {
 
-    result.value[i].NA(false);
+    result[i].getValue().NA(false);
     // check if n != 0
-    if(mpz_sgn(vn.value[i % vn.value.size()].getValueTemp()) != 0)
-      mpz_powm(result.value[i].getValue(),
-	       vx.value[i].getValueTemp(),
-	       vy.value[i % vy.value.size()].getValueTemp(),
-	       vn.value[i % vn.value.size()].getValueTemp());
+    if(mpz_sgn(vn[i % vn.size()].getValueTemp()) != 0)
+      mpz_powm(result[i].getMpValue(),
+	       vx[i].getValue().getValueTemp(),
+	       vy[i % vy.size()].getValueTemp(),
+	       vn[i % vn.size()].getValueTemp());
 
   }
 
@@ -1220,7 +1168,7 @@ SEXP bigI_frexp(SEXP x)
   const char *nms[] = {"d", "exp", ""};
   SEXP ans, d_R, exp_R;
   bigvec vx = bigintegerR::create_bignum(x);
-  int n = vx.value.size();
+  int n = vx.size();
 
   PROTECT(ans = Rf_mkNamed(VECSXP, nms)); // =~= R  list(d = . , exp= .)
   d_R   = Rf_allocVector(REALSXP, n); SET_VECTOR_ELT(ans, 0, d_R);
@@ -1229,11 +1177,14 @@ SEXP bigI_frexp(SEXP x)
   int  *exp_ = INTEGER(exp_R);
   for (int i = 0 ; i < n; i++) {
     signed long int ex;
-    d_[i] = mpz_get_d_2exp(&ex, vx.value[i].getValueTemp());
-    if(abs(ex) < INT_MAX)
+    d_[i] = mpz_get_d_2exp(&ex, vx[i].getValueTemp());
+    if(abs(ex) < INT_MAX){
       exp_[i] = (int) ex;
-    else
+    }
+    else{
+      vx.clear();
       error(_("exponent too large to fit into an integer"));
+    }
   }
   UNPROTECT(1);
   return ans;
@@ -1248,7 +1199,7 @@ SEXP biginteger_log2(SEXP x)
 
   for (unsigned int i = 0; i < v.size(); ++i) {
     signed long int ex;
-    double di = mpz_get_d_2exp(&ex, v.value[i].getValueTemp());
+    double di = mpz_get_d_2exp(&ex, v[i].getValueTemp());
     // xi = di * 2 ^ ex  ==> log2(xi) = log2(di) + ex :
     r[i] = log(di) / M_LN2 + (double)ex;
   }
@@ -1264,7 +1215,7 @@ SEXP biginteger_log(SEXP x)
 
   for (unsigned int i = 0; i < v.size(); ++i) {
     signed long int ex;
-    double di = mpz_get_d_2exp(&ex, v.value[i].getValueTemp());
+    double di = mpz_get_d_2exp(&ex, v[i].getValueTemp());
     // xi = di * 2 ^ ex  ==> log(xi) = log(di) + ex*log(2) :
     r[i] = log(di) + M_LN2*(double)ex;
   }
diff --git a/src/bigintegerR.h b/src/bigintegerR.h
index f5a8b073b34f2768df7b4edc742e0b7f84f9330d..35c2f495919a3af3cf71741c476c07008bb63f83 100644
--- a/src/bigintegerR.h
+++ b/src/bigintegerR.h
@@ -4,7 +4,7 @@
  *  \version 1
  *
  *  \date Created: 2006
- *  \date Last modified: Time-stamp: <2023-01-16 19:11:24 (antoine)>
+ *  \date Last modified: Time-stamp: <2023-01-19 19:43:37 (antoine)>
  *
  *
  *  \note Licence: GPL (>= 2)
@@ -18,7 +18,7 @@
 #ifndef T_BIGMOD_BINARY_OPERATION
 #define T_BIGMOD_BINARY_OPERATION 1
 /// A pointer to a binary operator for bigintegers
-typedef DefaultBigMod (*biginteger_binary_fn)(const bigmod&, const bigmod&);
+typedef bigmod (*biginteger_binary_fn)(const bigmod&, const bigmod&);
 #endif
 
 #ifndef T_BIGMOD_BINARY_OPERATION_LOGICAL
@@ -26,6 +26,7 @@ typedef DefaultBigMod (*biginteger_binary_fn)(const bigmod&, const bigmod&);
 typedef bool (*biginteger_logical_binary_fn)(const biginteger&, const biginteger&);
 #endif
 
+typedef const biginteger & (*bigmod_accessor_fn)(const bigmod&);
 
 struct lockSexp {
   lockSexp(const SEXP & value) {
@@ -61,7 +62,7 @@ namespace bigintegerR{
   /**
    * \brief export vector of biginteger to R value
    */
-  SEXP create_SEXP(const std::vector<biginteger>& v);
+  SEXP create_SEXP(const bigvec& v,bigmod_accessor_fn fct, int size);
 
   /**
    * \brief export bigvec to R value
diff --git a/src/bigmod.cc b/src/bigmod.cc
index 99ae1dc606ec5193e42a0dffbdbd04ed8c4ed683..69a8aba39ef1abf5f06ef192cdf0168f04d5389e 100644
--- a/src/bigmod.cc
+++ b/src/bigmod.cc
@@ -12,21 +12,21 @@
 // for GetOption etc:
 #include <R.h>
 #include <Rinternals.h>
-
+using namespace std;
 
 // string representation of (.) wrt base 'b' :
 std::string bigmod::str(int b) const
 {
-  if (value.isNA())
+  if (value->isNA())
     return "NA";
 
   std::string s; // sstream seems to collide with libgmp :-(
-  if (!modulus.isNA())
+  if (!modulus->isNA())
     s = "(";
-  s += value.str(b);
-  if (!modulus.isNA()) {
+  s += value->str(b);
+  if (!modulus->isNA()) {
     s += " %% ";
-    s += modulus.str(b);
+    s += modulus->str(b);
     s += ")";
   }
   return s;
@@ -36,15 +36,15 @@ bigmod & bigmod::operator= (const bigmod& rhs)
 {
   if(this != &rhs)
     {
-      modulus.setValue( rhs.getModulus() );
-      value.setValue(rhs.value );
+      modulus = make_shared<biginteger>(rhs.getModulus());
+      value = make_shared<biginteger>(rhs.getValue() );
     }
   return(*this);
 }
 
 bigmod bigmod::inv () const
 {
-  if(value.isNA() || modulus.isNA()) {
+  if(value->isNA() || modulus->isNA()) {
     return bigmod();
   }
     
@@ -59,7 +59,7 @@ bigmod bigmod::inv () const
     return bigmod(); // return NA; was
   }
 
-  return bigmod(val, modulus);
+  return bigmod(std::make_shared<biginteger>(val), std::make_shared<biginteger>(modulus->getValueTemp()));
 }
 
 
@@ -72,23 +72,25 @@ bool operator!=(const bigmod& rhs, const bigmod& lhs)
 
 bool operator==(const bigmod& rhs, const bigmod& lhs)
 {
+  
   if(rhs.getValue() != lhs.getValue())
     return(false);
+  // if(rhs.getModulusPtr().get() == lhs.getModulusPtr().get()) return true; // same pointer
   return(!(rhs.getModulus() != lhs.getModulus()));
 }
 
 
-DefaultBigMod operator+(const bigmod& lhs, const bigmod& rhs)
+bigmod operator+(const bigmod& lhs, const bigmod& rhs)
 {
   return create_bigmod(lhs, rhs, mpz_add);
 }
 
-DefaultBigMod operator-(const bigmod& lhs, const bigmod& rhs)
+bigmod operator-(const bigmod& lhs, const bigmod& rhs)
 {
   return create_bigmod(lhs, rhs, mpz_sub);
 }
 
-DefaultBigMod operator*(const bigmod& lhs, const bigmod& rhs)
+bigmod operator*(const bigmod& lhs, const bigmod& rhs)
 {
   return create_bigmod(lhs, rhs, mpz_mul);
 }
@@ -98,9 +100,9 @@ DefaultBigMod operator*(const bigmod& lhs, const bigmod& rhs)
  *   ~~~~~~~~~~~~~~
  * itself called from  "/.bigz" = div.bigz()
  */
-DefaultBigMod div_via_inv(const bigmod& a, const bigmod& b) {
+bigmod div_via_inv(const bigmod& a, const bigmod& b) {
     // compute  a/b  as  a * b^(-1)
-    return operator*(a, pow(b, DefaultBigMod(-1)));
+    return operator*(a, pow(b, bigmod(-1)));
 }
 
 
@@ -125,17 +127,17 @@ void integer_div(mpz_t result,const mpz_t a, const mpz_t b) {
 /* called via biginteger_binary_operation(.) from R's
  * .Call(biginteger_divq, a, b) , itself called from '%/%.bigz' = divq.bigz()
  */
-DefaultBigMod operator/(const bigmod& lhs, const bigmod& rhs) {
+bigmod operator/(const bigmod& lhs, const bigmod& rhs) {
   return create_bigmod(lhs, rhs, integer_div, false);
 }
 
-DefaultBigMod operator%(const bigmod& lhs, const bigmod& rhs)
+bigmod operator%(const bigmod& lhs, const bigmod& rhs)
 {
   if (lhs.getValue().isNA() || rhs.getValue().isNA())
-    return DefaultBigMod();
+    return bigmod();
   if (mpz_sgn(rhs.getValue().getValueTemp()) == 0) {
     warning(_("biginteger division by zero: returning NA"));
-    return DefaultBigMod();
+    return bigmod();
   }
   biginteger mod;
   if (!lhs.getModulus().isNA() || !rhs.getModulus().isNA())
@@ -145,13 +147,13 @@ DefaultBigMod operator%(const bigmod& lhs, const bigmod& rhs)
   mpz_init(val);
   mpz_t_sentry val_s(val);
   mpz_mod(val, lhs.getValue().getValueTemp(), rhs.getValue().getValueTemp());
-  return DefaultBigMod(val, mod);
+  return bigmod(val, mod);
 }
 
 
 // Either 'base' has a modulus, or it has not *and* exp >= 0 :
 
-DefaultBigMod pow(const bigmod& base, const bigmod& exp)
+bigmod pow(const bigmod& base, const bigmod& exp)
 {
   biginteger mod = get_modulus(base, exp);
 #ifdef DEBUG_bigmod
@@ -165,9 +167,9 @@ DefaultBigMod pow(const bigmod& base, const bigmod& exp)
   if(mod.isNA() &&
      ((!base.getValue().isNA() && !mpz_cmp_si(base.getValue().getValueTemp(), 1)) ||
       (! exp.getValue().isNA() && !mpz_cmp_si( exp.getValue().getValueTemp(), 0))))
-    return DefaultBigMod(biginteger(1));
+    return bigmod(biginteger(1));
   if (base.getValue().isNA() || exp.getValue().isNA())
-    return DefaultBigMod();
+    return bigmod();
   int sgn_exp = mpz_sgn(exp.getValue().getValueTemp());
   bool neg_exp = (sgn_exp < 0); // b ^ -|e| =  1 / b^|e|
   mpz_t val; mpz_init(val); mpz_t_sentry val_s(val);
@@ -177,7 +179,9 @@ DefaultBigMod pow(const bigmod& base, const bigmod& exp)
 	  mod.str(10).c_str());
 #endif
   if (mod.isNA()) { // <==> (both have no mod || both have mod. but differing)
-    if(neg_exp) error(_("** internal error (negative powers for Z/nZ), please report!"));
+    if(neg_exp){
+      error(_("** internal error (negative powers for Z/nZ), please report!"));
+    }
     if (!mpz_fits_ulong_p(exp.getValue().getValueTemp()))
       error(_("exponent e too large for pow(z,e) = z^e"));// FIXME? return( "Inf" )
     // else :
@@ -190,7 +194,7 @@ DefaultBigMod pow(const bigmod& base, const bigmod& exp)
 	SEXP wOpt = Rf_GetOption1(Rf_install("gmp:warnNoInv"));
 	if(wOpt != R_NilValue && Rf_asInteger(wOpt))
 	  warning(_("pow(x, -|n|) returning NA as x has no inverse wrt modulus"));
-	return(DefaultBigMod()); // return NA; was
+	return(bigmod()); // return NA; was
       } // else: val = x^(-1) already: ==> result =  val ^ |exp| =  val ^ (-exp) :
       // nExp := - exp
       mpz_t nExp; mpz_init(nExp); mpz_neg(nExp, exp.getValue().getValueTemp());
@@ -199,18 +203,18 @@ DefaultBigMod pow(const bigmod& base, const bigmod& exp)
       mpz_powm(val, base.getValue().getValueTemp(), exp.getValue().getValueTemp(), mod.getValueTemp());
     }
   }
-  return DefaultBigMod(val, mod);
+  return bigmod(val, mod);
 }
 
-DefaultBigMod inv(const bigmod& x, const bigmod& m)
+bigmod inv(const bigmod& x, const bigmod& m)
 {
   if (x.getValue().isNA() || m.getValue().isNA())
-    return DefaultBigMod();
+    return bigmod();
   SEXP wOpt = Rf_GetOption1(Rf_install("gmp:warnNoInv"));
   bool warnI = (wOpt != R_NilValue && Rf_asInteger(wOpt));
   if (mpz_sgn(m.getValue().getValueTemp()) == 0) {
     if(warnI) warning(_("inv(0) returning NA"));
-    return DefaultBigMod();
+    return bigmod();
   }
   biginteger mod = get_modulus(x, m);
   mpz_t val;
@@ -218,30 +222,30 @@ DefaultBigMod inv(const bigmod& x, const bigmod& m)
   mpz_t_sentry val_s(val);
   if (mpz_invert(val, x.getValue().getValueTemp(), m.getValue().getValueTemp()) == 0) {
     if(warnI) warning(_("inv(x,m) returning NA as x has no inverse modulo m"));
-    return(DefaultBigMod()); // return NA; was
+    return(bigmod()); // return NA; was
   }
-  return DefaultBigMod(val, mod);
+  return bigmod(val, mod);
 }
 
 // R  as.bigz() :
-DefaultBigMod set_modulus(const bigmod& x, const bigmod& m)
+bigmod set_modulus(const bigmod& x, const bigmod& m)
 {
   if (!m.getValue().isNA() && mpz_sgn(m.getValue().getValueTemp()) == 0)
     error(_("modulus 0 is invalid"));
   //    if (!m.getValue().isNA() && mpz_cmp(x.getValue().getValueTemp(),m.getValue().getValueTemp())>=0) {
   if (!m.getValue().isNA() ) {
-    DefaultBigMod t(x%m);
-    return DefaultBigMod(t.getValue(), m.getValue());
+    bigmod t(x%m);
+    return bigmod(t.getValue(), m.getValue());
   } else
-    return DefaultBigMod(x.getValue(), m.getValue());
+    return bigmod(x.getValue(), m.getValue());
 }
 
-DefaultBigMod gcd(const bigmod& lhs, const bigmod& rhs)
+bigmod gcd(const bigmod& lhs, const bigmod& rhs)
 {
   return create_bigmod(lhs, rhs, mpz_gcd);
 }
 
-DefaultBigMod lcm(const bigmod& lhs, const bigmod& rhs)
+bigmod lcm(const bigmod& lhs, const bigmod& rhs)
 {
   return create_bigmod(lhs, rhs, mpz_lcm);
 }
@@ -271,13 +275,13 @@ biginteger get_modulus(const bigmod& b1, const bigmod& b2)
 
 
 // Create a bigmod from a binary combination of two other bigmods
-DefaultBigMod create_bigmod(const bigmod& lhs, const bigmod& rhs, gmp_binary f,
+bigmod create_bigmod(const bigmod& lhs, const bigmod& rhs, gmp_binary f,
 		     bool zeroRhsAllowed) {
   if (lhs.getValue().isNA() || rhs.getValue().isNA())
-    return DefaultBigMod();
+    return bigmod();
   if (!zeroRhsAllowed && mpz_sgn(rhs.getValue().getValueTemp()) == 0) {
     warning(_("returning NA  for (modulus) 0 in RHS"));
-    return DefaultBigMod();
+    return bigmod();
   }
   biginteger mod = get_modulus(lhs, rhs);
   mpz_t val;
@@ -313,5 +317,5 @@ DefaultBigMod create_bigmod(const bigmod& lhs, const bigmod& rhs, gmp_binary f,
     }
 #endif
   }
-  return DefaultBigMod(val, mod);
+  return bigmod(val, mod);
 }
diff --git a/src/bigmod.h b/src/bigmod.h
index efbd2645048a4be8bed94f8f27b220d2145cdedb..3df7808917b51a80348840b8274478a6a66a5ce1 100644
--- a/src/bigmod.h
+++ b/src/bigmod.h
@@ -2,7 +2,7 @@
  *  \brief Description of class bigmod
  *
  *  \date Created: 22/05/06
- *  \date Last modified: Time-stamp: <2019-03-10 10:30:30 (antoine)>
+ *  \date Last modified: Time-stamp: <2023-01-21 11:41:06 (antoine)>
  *
  *  \author Immanuel Scholz
  *
@@ -13,6 +13,7 @@
 #ifndef BIGMOD_HEADER_
 #define BIGMOD_HEADER_ 1
 
+#include <memory>
 #include "biginteger.h"
 
 typedef void (*gmp_binary)(mpz_t, const mpz_t, const mpz_t);
@@ -36,32 +37,25 @@ extern "C" {
  */
 class bigmod {
  private:
-  /** optional source */
-  biginteger * value_ptr;
-  biginteger * modulus_ptr;
- 
- protected:
-  /** \brief  Value of our bigmod -- only references*/
-  biginteger & value;
+  /** \brief  Value of our bigmod */
+  std::shared_ptr<biginteger> value;
   /** \brief  modulus of our bigmod representation: value %% modulus */
-  biginteger & modulus;
+  std::shared_ptr<biginteger> modulus;
  
  public:
 
-  /** keep both references value / modulus
+  /** keep both pointers value / modulus
    */
-  bigmod(biginteger& value_,
-	 biginteger& modulus_)  :
-    value_ptr(NULL),
-    modulus_ptr(NULL),
-    value(value_),modulus(modulus_) {};
+  bigmod(biginteger * value_,
+	 biginteger * modulus_)  :
+    value(value_),
+    modulus(modulus_) {};
 
  /** keep references value / modulus is new object.
    */
- bigmod(biginteger& value_)  :
-   value_ptr(NULL),
-   modulus_ptr(new biginteger()),
-   value(value_),modulus(*modulus_ptr) {};
+ bigmod(biginteger* value_)  :
+   value(value_),
+   modulus(std::make_shared<biginteger>()) {};
 
 
   /**
@@ -69,33 +63,48 @@ class bigmod {
    */
  bigmod(const biginteger& value_,
 	 const biginteger& modulus_)  :
-   value_ptr(new biginteger(value_)),
-   modulus_ptr(new biginteger(modulus_)),
-   value(*value_ptr),modulus(*modulus_ptr) {};
+   value(std::make_shared<biginteger>(value_)),
+   modulus(std::make_shared<biginteger>(modulus_)) {};
+
 
  bigmod(const biginteger& value_)  :
-   value_ptr(new biginteger(value_)),
-   modulus_ptr(new biginteger()),
-   value(*value_ptr),modulus(*modulus_ptr) {};
+   value(std::make_shared<biginteger>(value_)),
+   modulus(std::make_shared<biginteger>()) {};
 
 
  bigmod()  :
-   value_ptr(new biginteger()),
-   modulus_ptr(new biginteger()),
-   value(*value_ptr),modulus(*modulus_ptr) {};
-
+   value(std::make_shared<biginteger>()),
+   modulus(std::make_shared<biginteger>()) {};
+
+ bigmod(std::shared_ptr<biginteger> value_, std::shared_ptr<biginteger> modulus_ )  :
+    value(),
+    modulus()
+  {
+    value = value_;
+    modulus = modulus_;
+  };
+ 
+  bigmod(std::shared_ptr<biginteger> value_ )  :
+    value(),
+    modulus(std::make_shared<biginteger>())
+  {
+    value = value_;
+  };
+ 
  
   /** \brief copy operator  */
-  bigmod(const bigmod & rhs) : 
-    value_ptr(new biginteger(rhs.getValue())),
-    modulus_ptr(new biginteger(rhs.getModulus())),
-   value(*value_ptr),modulus(*modulus_ptr) {
+   bigmod(const bigmod & rhs) : 
+    value(),
+    modulus()
+  {
+    value = rhs.value;
+    modulus = rhs.modulus;
   };
+ 
 
 
   virtual ~bigmod(){
-    if(value_ptr != NULL) delete value_ptr;
-    if(modulus_ptr != NULL) delete modulus_ptr;
+  
   };
 
   /**
@@ -116,86 +125,78 @@ class bigmod {
   bigmod  inv () const;
 
  
-  biginteger & getValue() {
-    return value;
+  inline biginteger & getValue() {
+    return *value;
+  }
+  
+  inline mpz_t & getMpValue()
+  {
+    return value->getValue();
+  }
+  
+  inline const mpz_t& getValueTemp() const
+  {
+    return value->getValueTemp();
   }
 
   biginteger & getModulus() {
-    return modulus;
+    return *modulus;
   }
 
-  const biginteger & getValue() const{
+
+  inline bool isNA(){
+    return value->isNA();
+  }
+  
+  std::shared_ptr<biginteger> & getValuePtr()  {
     return value;
   }
-
-  const biginteger & getModulus() const {
+  
+  const std::shared_ptr<biginteger> & getModulusPtr() const {
     return modulus;
   }
 
-};
+  inline void setValue(const std::shared_ptr<biginteger>  & v){
+    value = v;
+  }
+  
+  inline void setValue(const bigmod  & v){
+    value = std::make_shared<biginteger>(v.getValue());
+    modulus = std::make_shared<biginteger>(v.getModulus());
+  }
 
+  inline void setValue(const mpz_t  & v){
+    value->setValue(v);
+  }
 
-class DefaultBigMod : public bigmod {
- private:
-  /** \brief  Value of our bigmod */
-  biginteger valueLocal;
-  /** \brief  modulus of our bigmod representation: value %% modulus */
-  biginteger modulusLocal;
- 
- public:
-/** \brief creator
-   */
-  DefaultBigMod(const biginteger& value_ = biginteger(),
-	 const biginteger& modulus_ = biginteger()) :
-  bigmod(valueLocal,modulusLocal),
-    valueLocal(value_),modulusLocal(modulus_) {
-    value = valueLocal;
-    modulus = modulusLocal;
-}
+  inline void setValue(int v){
+    value->setValue(v);
+  }
 
-  /** \brief copy operator  */
- DefaultBigMod(const bigmod & rhs) :
-    bigmod(valueLocal,modulusLocal),
-     valueLocal(rhs.getValue()),modulusLocal(rhs.getModulus()) {
-    value = valueLocal;
-    modulus = modulusLocal;
-}
+  inline void setValue(double v){
+    value->setValue(v);
+  }
 
- /** \brief copy operator  */
- DefaultBigMod(const DefaultBigMod & rhs) :
-    bigmod(valueLocal,modulusLocal),
-     valueLocal(rhs.getValue()),modulusLocal(rhs.getModulus()) {
-    value = valueLocal;
-    modulus = modulusLocal;
-}
-  ~DefaultBigMod(){};
- 
+  inline void setValue(){
+    value->setValue();
+    modulus->setValue();
+  }
+
+  inline void setModulus(const std::shared_ptr<biginteger> & v){
+    modulus = v;
+  }
   
+  const biginteger & getValue() const{
+    return *value;
+  }
+
+  const biginteger & getModulus() const {
+    return *modulus;
+  }
 
 };
 
 
-/**
- * a bigmod that has only integer.
- */
-class BigModInt : public bigmod {
- private:
-   /** \brief  modulus of our bigmod representation */
-  biginteger modulusLocal;
- 
- public:
-/** \brief creator
-   */
-  BigModInt(biginteger& value_) :
-  bigmod(value_,modulusLocal),
-    modulusLocal() {
-    modulus = modulusLocal;
-}
-
-  ~BigModInt(){};
- 
- 
-};
 
 
 
@@ -217,33 +218,33 @@ bool operator== (const bigmod& rhs, const bigmod& lhs);
  * a modulus set. If none modulus for either bigmod is set, the result will not
  * have a modulus as well.
  */
-DefaultBigMod operator+(const bigmod& rhs, const bigmod& lhs);
+bigmod operator+(const bigmod& rhs, const bigmod& lhs);
 
 /**
  * \brief Subtract two bigmods.
  *
  * For modulus description, see operator+(bigmod, bigmod)
  */
-DefaultBigMod operator-(const bigmod& rhs, const bigmod& lhs);
+bigmod operator-(const bigmod& rhs, const bigmod& lhs);
 
 /**
  * \brief Multiply two bigmods.
  *
  * For modulus description, see operator+(bigmod, bigmod)
  */
-DefaultBigMod operator*(const bigmod& rhs, const bigmod& lhs);
+bigmod operator*(const bigmod& rhs, const bigmod& lhs);
 
 /**
  * \brief Divide two bigmods   a / b  :=  a * b^(-1)
  */
-DefaultBigMod div_via_inv(const bigmod& a, const bigmod& b);
+bigmod div_via_inv(const bigmod& a, const bigmod& b);
 
 /**
  * \brief Divide two bigmods.
  *
  * For modulus description, see operator+(bigmod, bigmod)
  */
-DefaultBigMod operator/(const bigmod& rhs, const bigmod& lhs);
+bigmod operator/(const bigmod& rhs, const bigmod& lhs);
 
 /**
  * \brief Calculate the modulus (remainder) of two bigmods.
@@ -253,7 +254,7 @@ DefaultBigMod operator/(const bigmod& rhs, const bigmod& lhs);
  * was before, except if rhs and lhs has both no modulus set,
  * in which case the resulting modulus will be unset too.
  */
-DefaultBigMod operator%(const bigmod& rhs, const bigmod& lhs);
+bigmod operator%(const bigmod& rhs, const bigmod& lhs);
 
 /**
  * \brief Return the power of "exp" to the base of "base" (return = base^exp).
@@ -265,14 +266,14 @@ DefaultBigMod operator%(const bigmod& rhs, const bigmod& lhs);
  *
  * For other modulus description, see operator+(bigmod, bigmod)
  */
-DefaultBigMod pow(const bigmod& base, const bigmod& exp);
+bigmod pow(const bigmod& base, const bigmod& exp);
 
 /**
  * \brief Return the modulo inverse to x mod m. (return = x^-1 % m)
  *
  * For modulus description, see operator+(bigmod, bigmod)
  */
-DefaultBigMod inv(const bigmod& x, const bigmod& m);
+bigmod inv(const bigmod& x, const bigmod& m);
 
 /**
  * \brief Return a bigmod with value (x % m) and the intern modulus set to m.
@@ -280,7 +281,7 @@ DefaultBigMod inv(const bigmod& x, const bigmod& m);
  *
  * Do not confuse this with operator%(bigmod, bigmod).
  */
-DefaultBigMod set_modulus(const bigmod& x, const bigmod& m);
+bigmod set_modulus(const bigmod& x, const bigmod& m);
 
 
 biginteger get_modulus(const bigmod& b1, const bigmod& b2);
@@ -289,20 +290,20 @@ biginteger get_modulus(const bigmod& b1, const bigmod& b2);
  *
  * For modulus description, see operator+(bigmod, bigmod)
  */
-DefaultBigMod gcd(const bigmod& rhs, const bigmod& lhs);
+bigmod gcd(const bigmod& rhs, const bigmod& lhs);
 
 /**
  * \brief  Return the least common multiply of both parameter.
  *
  * For modulus description, see operator+(bigmod, bigmod)
  */
-DefaultBigMod lcm(const bigmod& rhs, const bigmod& lhs);
+bigmod lcm(const bigmod& rhs, const bigmod& lhs);
 
 /**
  * \brief function used to make any binary operation between
  * two bigmod that return a bigmod (addition substraction... )
  */
-DefaultBigMod create_bigmod(const bigmod& lhs, const bigmod& rhs, gmp_binary f,
+bigmod create_bigmod(const bigmod& lhs, const bigmod& rhs, gmp_binary f,
 		     bool zeroRhsAllowed = true) ;
 
 #endif
diff --git a/src/bigrational.h b/src/bigrational.h
index 2264f006e7e9ef1614f55288df4608f540bb0c66..0575afc964b0e8487a35ca1d8f5db48963dc28ef 100644
--- a/src/bigrational.h
+++ b/src/bigrational.h
@@ -2,7 +2,7 @@
  *  \brief Description of class bigrational
  *
  *  \date Created: 22/05/06
- *  \date Last modified: Time-stamp: <2009-10-27 17:28:06 antoine>
+ *  \date Last modified: Time-stamp: <2023-01-21 13:13:10 (antoine)>
  *
  *  \author Antoine Lucas (adapted from biginteger class made by
  *                         Immanuel Scholz)
@@ -134,6 +134,17 @@ class bigrational
 		Rf_error("Not a valid number");    */
     }
 
+  /**
+   *  Copy constructor (mpz_t aren't standard-copyable)
+   */
+  bigrational(const biginteger & rhs) :
+    value(),
+    na(rhs.isNA())
+    {
+      mpq_init(value);
+      mpq_set_z(value, rhs.getValueTemp());
+    }
+
   /**
    *  Copy constructor (mpz_t aren't standard-copyable)
    */
diff --git a/src/bigrationalR.cc b/src/bigrationalR.cc
index d776403cd5a0b364dc1f5ca0a151a599e6f08269..0f36ef0ce9ea5d06d1ee33c480a79f7bb7d7f6a7 100644
--- a/src/bigrationalR.cc
+++ b/src/bigrationalR.cc
@@ -127,7 +127,7 @@ namespace bigrationalR
     if (TYPEOF(denAttr) != NILSXP)
       {
 	bigvec_q attrib = bigrationalR::create_vector(denAttr);
-	if (!attrib.value.empty()) // sanity check
+	if (!attrib.size() == 0) // sanity check
 	  for (unsigned int i = 0; i < v.size(); ++i)
 	    {
 	      if( attrib[i%attrib.size()].sgn() != 0)
@@ -212,14 +212,23 @@ namespace bigrationalR
   {
     bigvec_q va = bigrationalR::create_bignum(a);
     bigvec_q vb = bigrationalR::create_bignum(b), result;
+
+    int nrow = matrixz::checkDims(va.nrow,vb.nrow) ;
+    if(nrow == -2){
+      va.clear();
+      vb.clear();
+      error(_("Matrix dimensions do not match"));
+    }
+    
     // MM: I think, 0 length vector operations should work too!
     // if (va.value.empty() || vb.value.empty())
     //   error(_("argument must not be an empty list"));
-    int size = (va.value.empty() || vb.value.empty()) ? 0 : max(va.size(), vb.size());
+    int size = (va.size() ==0 || vb.size() == 0) ? 0 : max(va.size(), vb.size());
     result.value.reserve(size);
     for (int i = 0; i < size; ++i)
       result.push_back(f(va.value[i%va.size()], vb.value[i%vb.size()]));
-    result.nrow = matrixz::checkDims(va.nrow,vb.nrow) ;
+    result.nrow = nrow;
+
     return bigrationalR::create_SEXP(result);
   }
 
@@ -227,12 +236,20 @@ namespace bigrationalR
   {
     bigvec_q va = bigrationalR::create_bignum(a), result;
     bigvec vb = bigintegerR::create_bignum(b);
-    int size = (va.value.empty() || vb.value.empty()) ? 0 : max(va.size(), vb.size());
-    result.value.reserve(size);
-    for (int i = 0; i < size; ++i)
-      result.push_back(f(va.value[i%va.size()], vb.value[i%vb.size()]));
-    result.nrow = matrixz::checkDims(va.nrow,vb.nrow) ;
-    return bigrationalR::create_SEXP(result);
+    int size = (va.size()==0 || vb.size()==0) ? 0 : max(va.size(), vb.size());
+
+    int nrow =  matrixz::checkDims(va.nrow,vb.nrow) ;
+    if(nrow == -2){
+      va.clear();
+      vb.clear();
+      error(_("Matrix dimensions do not match"));
+    }
+    
+   for (int i = 0; i < size; ++i)
+      result.push_back(f(va.value[i%va.size()], vb[i%vb.size()].getValue()));
+   result.nrow = nrow;
+
+   return bigrationalR::create_SEXP(result);
   }
 
   SEXP bigrational_logical_binary_operation(SEXP a, SEXP b, bigrational_logical_binary_fn f)
@@ -240,9 +257,17 @@ namespace bigrationalR
     bigvec_q va = bigrationalR::create_bignum(a);
     bigvec_q vb = bigrationalR::create_bignum(b), result;
     // MM: I think, 0 length vector operations should work too!
-    // if (va.value.empty() || vb.value.empty())
+    // if (va.size() == 0 || vb.size() == 0)
     //   error(_("argument must not be an empty list"));
-    int size = (va.value.empty() || vb.value.empty()) ? 0 : max(va.size(), vb.size());
+
+    int nrow = matrixz::checkDims(va.nrow,vb.nrow) ;
+    if(nrow == -2){
+      va.clear();
+      vb.clear();
+      error(_("Matrix dimensions do not match"));
+    }
+
+    int size = (va.size() == 0 || vb.size() == 0) ? 0 : max(va.size(), vb.size());
     SEXP ans = PROTECT(Rf_allocVector(LGLSXP, size));
     for (int i = 0; i < size; ++i) {
       bigrational am = va.value[i % va.size()];
@@ -253,8 +278,6 @@ namespace bigrationalR
 	LOGICAL(ans)[i] = f(va[i%va.size()], vb[i%vb.size()]) ? 1 : 0;
     }
 
-    int nrow = matrixz::checkDims(va.nrow,vb.nrow) ;
-
     // Add dimension parameter when available
     if(nrow >= 0)
       {
@@ -484,11 +507,11 @@ SEXP bigrational_den(SEXP a)
   mpz_init(z_tmp);
   bigvec_q v =bigrationalR::create_bignum(a);
   bigvec result;
-  result.value.resize(v.size());
+  result.resize(v.size());
 
   for (unsigned int i = 0; i < v.size(); ++i) {
-    mpq_get_den(z_tmp,v.value[i].getValueTemp());
-    result.value[i].setValue(z_tmp);
+    mpq_get_den(z_tmp,v[i].getValueTemp());
+    result[i].setValue(z_tmp);
   }
   mpz_clear(z_tmp);
   return bigintegerR::create_SEXP(result);
@@ -503,9 +526,9 @@ SEXP bigrational_num(SEXP a)
   result.resize(v.size());
 
   for (unsigned int i = 0; i < v.size(); ++i) {
-    if(!v.value[i].isNA()) {
-      mpq_get_num(z_tmp,v.value[i].getValueTemp());
-      result.value[i].setValue(z_tmp);
+    if(!v[i].isNA()) {
+      mpq_get_num(z_tmp,v[i].getValueTemp());
+      result[i].setValue(z_tmp);
     } // else: uninitialized, i.e., NA
   }
   mpz_clear(z_tmp);
@@ -543,7 +566,7 @@ SEXP bigrational_setlength(SEXP vec, SEXP value)
     error(_("invalid second argument"));
   }
   bigvec_q v =bigrationalR::create_bignum(vec);
-  v.value.resize(len);
+  v.resize(len);
   return bigrationalR::create_SEXP(v);
 }
 
@@ -553,7 +576,7 @@ SEXP bigrational_is_na(SEXP a)
   SEXP ans = PROTECT(Rf_allocVector(LGLSXP, v.size()));
   int *a_ = LOGICAL(ans);
   for (unsigned int i = 0; i < v.size(); ++i)
-    a_[i] = v.value[i].isNA();
+    a_[i] = v[i].isNA();
   UNPROTECT(1);
   return ans;
 }
@@ -568,7 +591,7 @@ SEXP bigrational_is_int(SEXP a)
   mpz_init(z_tmp);
 
   for (unsigned int i = 0; i < v.size(); ++i) {
-    mpq_get_den(z_tmp,v.value[i].getValueTemp());
+    mpq_get_den(z_tmp,v[i].getValueTemp());
     a_[i] = mpz_cmp_ui (z_tmp, 1) == 0; // <==> numerator == 1
   }
   mpz_clear(z_tmp);
@@ -584,7 +607,7 @@ SEXP bigrational_c(SEXP args)
   for(int i = 0; i < Rf_length(args); i++) {
       bigvec_q v = bigrationalR::create_bignum(VECTOR_ELT(args,i));
       for(unsigned int j=0; j < v.size(); j++)
-	result.push_back(v.value[j]);
+	result.push_back(v[j]);
       v.value.clear();
     }
 
@@ -600,7 +623,7 @@ SEXP bigrational_rep(SEXP x, SEXP times)
   result.value.reserve(v.size()*rep);
   for(i = 0 ; i< rep ; i++)
     for(j = 0 ; j < v.size() ; j++)
-      result.push_back(v.value[j]);
+      result.push_back(v[j]);
 
   return bigrationalR::create_SEXP(result);
 }
@@ -619,14 +642,14 @@ SEXP bigrational_max(SEXP a, SEXP narm)
 
   for(unsigned int i = 1 ; i < va.size(); ++i)
     {
-      if(va.value[i].isNA() && ! na_remove)
+      if(va[i].isNA() && ! na_remove)
 	return(bigrationalR::create_SEXP(result));
       else
-	if(!(va.value[i] <  va.value[maximum] ))
+	if(!(va[i] <  va[maximum] ))
 	  maximum = i; // if va.value[maximum = 0] is NA => false for the "<" => maximum changed = good
     }
 
-  result.push_back(va.value[maximum]);
+  result.push_back(va[maximum]);
 
   return bigrationalR::create_SEXP(result);
 }
@@ -645,14 +668,14 @@ SEXP bigrational_min(SEXP a, SEXP narm)
 
   for(unsigned int i = 1 ; i < va.size(); ++i)
     {
-      if(va.value[i].isNA() && !na_remove)
+      if(va[i].isNA() && !na_remove)
 	return(bigrationalR::create_SEXP(result));
       else
-	if(!(va.value[i] >  va.value[minimum] ))
+	if(!(va[i] >  va[minimum] ))
 	  minimum = i; // if va.value[maximum = 0] is NA => false for the "<" => maximum changed = good
     }
 
-  result.push_back(va.value[minimum]);
+  result.push_back(va[minimum]);
 
   return bigrationalR::create_SEXP(result);
 }
@@ -661,19 +684,19 @@ SEXP bigrational_min(SEXP a, SEXP narm)
 SEXP bigrational_cumsum(SEXP a)
 {
   bigvec_q result, va = bigrationalR::create_bignum(a);
-  result.value.resize(va.value.size());
+  result.resize(va.size());
 
   mpq_t val;
   mpq_init(val);
   mpq_t_sentry val_s(val);
 
   for(unsigned int i = 0 ; i < va.size(); ++i) {
-      if(va.value[i].isNA() ) {
+      if(va[i].isNA() ) {
 	  break; // all last values are NA.
       }
-      mpq_add(val,val,va.value[i].getValueTemp());
+      mpq_add(val,val,va[i].getValueTemp());
 
-      result.value[i].setValue(val);
+      result[i].setValue(val);
   }
   return(bigrationalR::create_SEXP(result));
 }
@@ -683,19 +706,19 @@ SEXP bigrational_cumsum(SEXP a)
 SEXP bigrational_sum(SEXP a)
 {
   bigvec_q result, va = bigrationalR::create_bignum(a);
-  result.value.resize(1);
+  result.resize(1);
 
   mpq_t val;
   mpq_init(val);
   mpq_t_sentry val_s(val);
 
   for(unsigned int i = 0 ; i < va.size(); ++i) {
-    if(va.value[i].isNA()) {
+    if(va[i].isNA()) {
       break; // all last values are NA.
     }
-    mpq_add(val,val,va.value[i].getValueTemp());
+    mpq_add(val,val,va[i].getValueTemp());
   }
-  result.value[0].setValue(val);
+  result[0].setValue(val);
   return(bigrationalR::create_SEXP(result));
 }
 
@@ -705,7 +728,7 @@ SEXP bigrational_sum(SEXP a)
 SEXP bigrational_prod(SEXP a)
 {
   bigvec_q result, va = bigrationalR::create_bignum(a);
-  result.value.resize(1);
+  result.resize(1);
 
   mpq_t val;
   mpq_init(val);
@@ -713,12 +736,12 @@ SEXP bigrational_prod(SEXP a)
   mpq_t_sentry val_s(val);
 
   for(unsigned int i = 0 ; i < va.size(); ++i) {
-    if(va.value[i].isNA() ) {
+    if(va[i].isNA() ) {
       return (bigrationalR::create_SEXP(result));
     }
-    mpq_mul(val,val,va.value[i].getValueTemp());
+    mpq_mul(val,val,va[i].getValueTemp());
   }
-  result.value[0].setValue(val);
+  result[0].setValue(val);
   return(bigrationalR::create_SEXP(result));
 }
 
@@ -728,33 +751,33 @@ SEXP bigrational_R_pow(SEXP x, SEXP y)
 {
   bigvec_q result, vx = bigrationalR::create_bignum(x);
   bigvec vy = bigintegerR::create_bignum(y);
-  int size = (vx.value.empty() || vy.value.empty()) ? 0 : max(vx.size(), vy.size());
+  int size = (vx.size() ==0 || vy.size() == 0) ? 0 : max(vx.size(), vy.size());
 
   mpq_t val; mpq_init(val); mpq_t_sentry val_s(val);
   mpz_t num, den; mpz_init(num); mpz_init(den);
   mpz_t_sentry val_n(num); mpz_t_sentry val_d(den);
 
-  result.value.resize(size);
+  result.resize(size);
 
   for (int i = 0 ; i < size; i++) {
-    int i_x = i % vx.value.size(),
-        i_y = i % vy.value.size();
+    int i_x = i % vx.size(),
+        i_y = i % vy.size();
 
     //fails: val.NA(false);
-    if(vx.value[i_x].isNA() ||
-       vy.value[i_y].isNA())
+    if(vx[i_x].isNA() ||
+       vy[i_y].isNA())
 	break;
     // else -- res[i] :=  x[i] ^ y[i]  =  (num ^ y_i) / (den ^ y_i) ----
 
-    if(mpz_sgn(vy.value[i_y].getValueTemp()) < 0)
+    if(mpz_sgn(vy[i_y].getValueTemp()) < 0)
 	error(_("Negative powers not yet implemented [i = %d]"), i_y +1);
-    if (!mpz_fits_ulong_p(vy.value[i_y].getValueTemp()))
+    if (!mpz_fits_ulong_p(vy[i_y].getValueTemp()))
 	error(_("exponent too large for pow  [i = %d]"), i_y +1);
-    int y_i = mpz_get_ui(vy.value[i_y].getValueTemp());
-    // *num = mpq_numref(vx.value[i].getValueTemp());
-    // *den = mpq_denref(vx.value[i].getValueTemp());
-    mpq_get_num(num, vx.value[i_x].getValueTemp());
-    mpq_get_den(den, vx.value[i_x].getValueTemp());
+    int y_i = mpz_get_ui(vy[i_y].getValueTemp());
+    // *num = mpq_numref(vx[i].getValueTemp());
+    // *den = mpq_denref(vx[i].getValueTemp());
+    mpq_get_num(num, vx[i_x].getValueTemp());
+    mpq_get_den(den, vx[i_x].getValueTemp());
     mpz_pow_ui(num, num, y_i); // num := num ^ y_i
     mpz_pow_ui(den, den, y_i); // den := den ^ y_i
 
@@ -764,7 +787,7 @@ SEXP bigrational_R_pow(SEXP x, SEXP y)
     /* Simplify numerator and denominator */
     mpq_canonicalize(val);
 
-    result.value[i].setValue(val);
+    result[i].setValue(val);
   }
 
   return bigrationalR::create_SEXP(result);
diff --git a/src/bigvec.cc b/src/bigvec.cc
index 46930e1f85f738c7c8a20b4efc2c6bc11f9ee7fa..2a4b8544369b5be7c4e51fc38bdda4647240b474 100644
--- a/src/bigvec.cc
+++ b/src/bigvec.cc
@@ -1,69 +1,57 @@
 
 #include "bigvec.h"
 
+static int count = 0;
+static int countAll = 0;
+
 
 /** \brief constructor
  *
  */
 bigvec::bigvec(unsigned int size) :
   math::Matrix<bigmod>(),
-  value(),
-  modulus(),
-  valuesMod(),
-  nrow(-1)
-{
-
+  values(),
+  type(NO_MODULUS),
+  nrow(-1),
+  modulus()
+{
+  count++;
+  countAll++;
+ 
   for (int i=0 ; i < size; i++){
-    value.push_back(biginteger());
+    values.push_back(bigmod());
   }
 }
 
 
 bigvec::bigvec(const bigvec & vecteur) :
   math::Matrix<bigmod>(),
-  value(),
-  modulus(),
-  valuesMod(),
-  nrow(vecteur.nrow)
-{
-  //  *this = vecteur;
-  std::vector<biginteger>::const_iterator it;
-
-  for(it = vecteur.modulus.begin();it !=  vecteur.modulus.end(); ++it)
+  values(),
+  type(vecteur.type),
+  nrow(vecteur.nrow),
+  modulus(vecteur.modulus)
+{
+  count++;
+  countAll++;
+   //  *this = vecteur;
+  values.reserve(vecteur.size());
+  for(std::vector<bigmod>::const_iterator it= vecteur.values.begin(); it !=  vecteur.values.end(); ++it)
     {
-      modulus.push_back(*it);
-    }
-
-  for(it= vecteur.value.begin(); it !=  vecteur.value.end(); ++it)
-    {
-      value.push_back(*it);
+      values.push_back(*it);
     }
 }
 
 bigvec::~bigvec(){
-  clearValuesMod();
+  count--;
+  //  printf("bv %d %d \n",count, countAll);
+    
+    
 }
 
 //
 std::string bigvec::str(int i,int b) const
 {
-    if (value[i].isNA())
-      return ("NA");
-
-    std::string s; // sstream seems to collide with libgmp :-(
-    bool onemodulus = modulus.size()>0;
-    if(onemodulus)
-      onemodulus = !modulus[i%modulus.size()].isNA() ;
-    if (onemodulus)
-	s = "(";
-    s += value[i].str(b);
-    if (onemodulus) {
-	s += " %% ";
-	s += modulus[i%modulus.size()].str(b);
-	s += ")";
-    }
-
-    return s;
+   return values[i].str(b);
 }
 
 bigmod & bigvec::get(unsigned int row, unsigned int col) {
@@ -73,116 +61,47 @@ bigmod & bigvec::get(unsigned int row, unsigned int col) {
 
  bigmod & bigvec::operator[] (unsigned int i)
 {
-  checkValuesMod();
-  return *valuesMod[i];
+  return values[i];
 }
 
 
 const bigmod & bigvec::operator[] (unsigned int i) const
 {
-  bigvec * nonConst = const_cast<bigvec*>(this);
-  nonConst->checkValuesMod();
-  return *valuesMod[i];
+  return values[i];
 }
 
 void bigvec::set(unsigned int row, unsigned int col, const  bigmod & val) {
   set( row + col*nRows(),val);
 }
 
-void bigvec::checkValuesMod() {
-  if (valuesMod.size() != value.size()){
-    // reconstruct bigmod that are references to values and modulus:
-    clearValuesMod();
-    if(modulus.size()>0) {
-      for (unsigned int i = 0 ; i < value.size(); i++)
-	valuesMod.push_back(new bigmod(value[i], modulus[i%modulus.size()]));
-    } else {
-      for (unsigned int i= 0 ; i < value.size(); i++)
-	valuesMod.push_back(new BigModInt(value[i]));
-    }
-
-  }
-}
-
-void bigvec::clearValuesMod(){
-  for (unsigned int i = 0 ; i < valuesMod.size(); i++){
-    delete valuesMod[i];
-  }
-  valuesMod.clear();
-}
 
 void bigvec::set(unsigned int i,const bigmod & val)
 {
-  value[i] = val.getValue();
+  values[i] = val;
 
-  if(!val.getModulus().isNA())
-    {
-      if(modulus.size()> i)
-	{
-	  modulus[i] = val.getModulus() ;
-	  return;
-	}
-
-      unsigned int nrow_mod = nrow;
-      if(nrow<1)
-	nrow_mod = 1;
-      if( (modulus.size() ==  (unsigned int)nrow_mod ) || (modulus.size() == 1) )
-	{
-	  // check "row-mod" or "global" modulus
-	  if(!(val.getModulus() != modulus[i % modulus.size()])) {
-	    return;
-	  }
-	}
-
-      // we add "previous"
-      nrow_mod = modulus.size();
-      for(unsigned int j = nrow_mod; j< i;++j)
-	modulus.push_back(modulus[j % nrow_mod]);
-      modulus.push_back(val.getModulus());
-      clearValuesMod();
+
+  if(type == NO_MODULUS){
+    if(val.getModulus().isNA()) return;
+    if(i == 0 && values.size() == 1) {
+      type = MODULUS_GLOBAL;
+      modulus = val.getModulusPtr();
+    } else {
+      type = MODULUS_BY_CELL;
     }
+  }
+  if(type == MODULUS_GLOBAL){
+    if(values.size() == 1){
+      modulus = val.getModulusPtr();
+    } else 	if(val.getModulus() != *modulus ){
+      type = MODULUS_BY_CELL;
+    }
+  }
 }
 
 void bigvec::push_back(const bigmod & number)
 {
-  unsigned int nrow_mod = (nrow < 0) ? 1 : nrow;
-  clearValuesMod();
-
-  value.push_back(number.getValue());
-
-  if((!number.getModulus().isNA()) || (modulus.size()>0) )
-    {
-      // pathologic case: value.size >0 ; modulus.size =0
-      // we assume previous mod where NA
-      if((modulus.size() ==0) && (value.size()>0))
-	{
-	  modulus.resize(value.size()-1);
-	  modulus.push_back( number.getModulus());
-	  return;
-	}
-
-      // standard cas
-      if((modulus.size() != 1 ) && (modulus.size() != nrow_mod))
-	{
-	  modulus.push_back(number.getModulus());
-	  return;
-	}
-
-      // pathologic case:
-      //  value modulus [nrow=4]
-      //  2     2  push_back: ok
-      //  2     2  push_back: nothing
-      //  2     1  push_back: shoud add previous modulus then 1
-      // note nrow_mod is either 1 ither nrow (when nrow >1)
-      nrow_mod = modulus.size();
-      if(modulus[(value.size() -1)% nrow_mod ] != number.getModulus())
-	{
-	  // we add "previous"
-	  for(unsigned int i = nrow_mod; i< value.size()-1;i++)
-	    modulus.push_back(modulus[i % nrow_mod]);
-	  modulus.push_back(number.getModulus());
-	  }
-    }
+  values.push_back(bigmod());
+  set(values.size()-1, number);
 }
 
 /**
@@ -190,8 +109,7 @@ void bigvec::push_back(const bigmod & number)
  */
 void bigvec::push_back(int value_p)
 {
-  clearValuesMod();
-  value.push_back(biginteger(value_p));
+  push_back(biginteger(value_p));
 }
 
 /**
@@ -199,8 +117,7 @@ void bigvec::push_back(int value_p)
  */
 void bigvec::push_back(biginteger & value_p)
 {
-  clearValuesMod();
-  value.push_back(value_p);
+  push_back(bigmod(value_p));
 }
 
 /**
@@ -208,15 +125,14 @@ void bigvec::push_back(biginteger & value_p)
  */
 void bigvec::push_back(const __mpz_struct * value_p)
 {
-  clearValuesMod();
-  value.push_back(biginteger(value_p));
+  push_back(biginteger(value_p));
 }
 
 
 // return size of value
 unsigned int bigvec::size() const
 {
-  return(value.size());
+  return(values.size());
 }
 
 
@@ -228,20 +144,16 @@ unsigned int  bigvec::nRows() const {
 // hummm. to avoid !
 void bigvec::resize(unsigned int i)
 {
-  clearValuesMod();
 
-
-  value.resize(i);
-  if(i < modulus.size())
-      modulus.resize(i);
+  values.resize(i);
 }
 
 // clear all
 void bigvec::clear()
 {
-  clearValuesMod();
-  value.clear();
-  modulus.clear();
+  values.clear();
+  type=NO_MODULUS;
+  modulus=nullptr;
   nrow = -1;
 }
 
@@ -251,22 +163,16 @@ bigvec & bigvec::operator= (const bigvec & rhs)
 {
   if(this != &rhs)
     {
-      clearValuesMod();
-      value.resize(0);
-      modulus.resize(0);
-      std::vector<biginteger>::const_iterator it;
-      
-      for(it = rhs.modulus.begin();it !=  rhs.modulus.end(); ++it)
-	{
-	  modulus.push_back(*it);
-	}
+      values.resize(0);
+      modulus = rhs.modulus;
+      type=rhs.type;
       
-      for(it= rhs.value.begin(); it !=  rhs.value.end(); ++it)
-	{
-	  value.push_back(*it);
-	}
+      for (unsigned int i = 0 ;  i < rhs.size(); i++){
+	values.push_back(rhs[i]);
+      }
       
       nrow = rhs.nrow;
+      
     }
   return(*this);
 }
@@ -276,24 +182,21 @@ bigvec & bigvec::operator= (const bigvec & rhs)
 // Comparison operator
 bool operator!=(const bigvec & rhs, const bigvec& lhs)
 {
-  std::vector<biginteger>::const_iterator it = rhs.value.begin();
-  std::vector<biginteger>::const_iterator jt = lhs.value.begin();
 
-  if( (rhs.value.size() != lhs.value.size()) || \
+
+  if( (rhs.size() != lhs.size()) || \
       (rhs.nrow != lhs.nrow )  )
     return(false);
 
+
+  
   // check value
-  while(it != rhs.value.end())
+  for (unsigned int i = 0 ; i < rhs.size(); i++)
     {
-      if(*it != *jt)
+      if(rhs[i] != lhs[i])
 	return(false);
-      it++; jt++;
     }
-  for(unsigned int i=0; i < std::max( rhs.modulus.size() ,lhs.modulus.size() ); ++i)
-    if(rhs.modulus[i % rhs.modulus.size()] != \
-       lhs.modulus[i % lhs.modulus.size()] )
-      return(false);
+
   return(true);
 }
 
@@ -305,14 +208,34 @@ void bigvec::print()
   if(nrow > 0) {
     for(int i=0; i < nrow; ++i)
       {
-	for(unsigned int j=0; j < (value.size() / nrow); ++j)
-	  Rprintf("%s\t", value[i+j* nrow].str(10).c_str() );
+	for(unsigned int j=0; j < (values.size() / nrow); ++j)
+	  Rprintf("%s\t", values[i+j* nrow].str(10).c_str() );
 	Rprintf("\n");
       }
   }
   else {
-    for(unsigned int i=0; i < value.size(); ++i)
-      Rprintf("%s\t", value[i].str(10).c_str() );
+    for(unsigned int i=0; i < values.size(); ++i)
+      Rprintf("%s\t", values[i].str(10).c_str() );
     Rprintf("\n");
   }
 }
+
+
+void bigvec::setGlobalModulus(std::shared_ptr<biginteger> & val){
+  modulus = val;
+  type = MODULUS_GLOBAL;
+  for (int i = 0 ; i < values.size(); i++){
+    values[i].setModulus(val);
+  }
+}
+
+
+std::shared_ptr<biginteger> bigvec::getGlobalModulus(bigvec & first,  bigvec & second){
+  std::shared_ptr<biginteger> empty(nullptr);
+  if(first.getType() == MODULUS_GLOBAL && second.getType() ==  NO_MODULUS) return first.getGlobalModulus();
+  if(first.getType() == NO_MODULUS && second.getType() ==  MODULUS_GLOBAL) return second.getGlobalModulus();
+  if(first.getType() == MODULUS_GLOBAL && second.getType() ==  MODULUS_GLOBAL) {
+    return (*first.getGlobalModulus()) == (*second.getGlobalModulus()) ? first.getGlobalModulus() : empty;
+  }
+  return empty;
+}
diff --git a/src/bigvec.h b/src/bigvec.h
index b0f16e7b0a3f598a83f575b8ad72d87c478e2212..8aab56a77db50fad2d9a21d56421e476108db827 100644
--- a/src/bigvec.h
+++ b/src/bigvec.h
@@ -4,7 +4,7 @@
  *  \version 1
  *
  *  \date Created: 2005
- *  \date Last modified: Time-stamp: <2023-01-16 19:09:32 (antoine)>
+ *  \date Last modified: Time-stamp: <2023-01-21 11:22:09 (antoine)>
  *
  *
  *  \note Licence: GPL (>= 2)
@@ -19,6 +19,12 @@
 #include "bigmod.h"
 #include "templateMatrix.h"
 
+enum TYPE_MODULUS{
+		  NO_MODULUS,
+		  MODULUS_GLOBAL,
+		  MODULUS_BY_CELL
+};
+
 /** \brief class bigvec
  *
  * It a class composed of 2 vectors, (value & modulus) that
@@ -26,15 +32,14 @@
  * parameter (for matrix support)
  */
 class bigvec : public math::Matrix<bigmod> {
- public:
-  /** \brief value */
-  std::vector<biginteger> value;
-  /** \brief modulus */
-  std::vector<biginteger> modulus;
   
+protected:
   /** array with all bigmod, that are references to values in vector. */
-  std::vector<bigmod *> valuesMod;
+  std::vector<bigmod > values;
+  TYPE_MODULUS type;
+  std::shared_ptr<biginteger> modulus;
   
+public:
   /** \brief optional parameter used with matrix -- set to -1 for non-matrix */
   int nrow ;
 
@@ -89,6 +94,10 @@ class bigvec : public math::Matrix<bigmod> {
    */
   void push_back(int value_p);
 
+  inline void erase(unsigned int index){
+    values.erase(values.begin() + index);
+  }
+
   /**
    * Insert Big Integer value
    */
@@ -128,8 +137,33 @@ class bigvec : public math::Matrix<bigmod> {
    */
   void print();
 
+  inline unsigned int getModulusSize(){
+    if(type == NO_MODULUS) return 0;
+    if(type == MODULUS_GLOBAL) return 1;
+    return size();
+  }
 
+  void setGlobalModulus(std::shared_ptr<biginteger> & modulus);
 
+  inline std::shared_ptr<biginteger> & getGlobalModulus(){
+    return modulus;
+  }
+  
+  const  TYPE_MODULUS getType() const {
+    return type;
+  }
+
+  inline void setType(TYPE_MODULUS val){
+    type = val;
+    if(val == MODULUS_GLOBAL && size() > 0){
+      modulus = (*this)[0].getModulusPtr();
+    }
+  }
+
+
+  /** return a global modulus if possible, null if not */
+  static std::shared_ptr<biginteger> getGlobalModulus(bigvec & first,  bigvec & second);
+  
  private:
   void checkValuesMod() ;
   void clearValuesMod() ;
diff --git a/src/bigvec_q.cc b/src/bigvec_q.cc
index 51c4480db00f41e18472da84fb0b5e32dd9e5769..551b639620c24815c71cba2ff75d731a11a7a5b0 100644
--- a/src/bigvec_q.cc
+++ b/src/bigvec_q.cc
@@ -11,12 +11,12 @@ bigvec_q::bigvec_q(const bigvec_q & rhs):
 
 
 bigvec_q::bigvec_q(const bigvec & rhs):
-  value(rhs.value.size()),
+  value(rhs.size()),
   nrow(rhs.nrow)
 {
   for(unsigned int i=0; i< rhs.size(); ++i)
     {
-      value[i].setValue(rhs.value[i]);
+      value[i].setValue(rhs[i].getValue());
     }
 }
 
diff --git a/src/bigvec_q.h b/src/bigvec_q.h
index d33df00210b8326dd37c101cbcbb3eb613c3f8ed..2feacb77ceb20185e662a6efe199eb952911fb3f 100644
--- a/src/bigvec_q.h
+++ b/src/bigvec_q.h
@@ -4,7 +4,7 @@
  *  \version 1
  *
  *  \date Created: 2005
- *  \date Last modified: Time-stamp: <2006-06-16 20:19:01 antoine>
+ *  \date Last modified: Time-stamp: <2023-01-20 19:13:13 (antoine)>
  *
  *
  *  \note Licence: GPL (>= 2)
@@ -90,6 +90,9 @@ class bigvec_q  : public math::Matrix<bigrational> {
    */
   void set(unsigned int i,const mpq_t & val);
 
+  inline void erase(unsigned int index){
+    value.erase(value.begin() + index);
+  }
 
   /**
    * \brief add a value
diff --git a/src/extract_matrix.cc b/src/extract_matrix.cc
index 5524dc1c73f356ee7db4a5a1748931524af131df..d2dc3cf72e874a6a4944cf1f139edbfd41bbf397 100644
--- a/src/extract_matrix.cc
+++ b/src/extract_matrix.cc
@@ -13,12 +13,13 @@ SEXP matrix_get_at_q(SEXP A,SEXP INDI, SEXP INDJ)
 // for something like x = A[indi, indj], but also simply  A[ind]
 SEXP matrix_get_at_z(SEXP A,SEXP INDI, SEXP INDJ)
 {
+  //  printf("ici\n");
   bigvec mat = bigintegerR::create_bignum(A);
   bigvec mat2 = extract_gmp_R::get_at( mat,INDI,INDJ);
-
+  /*
   // now modulus !
   // cell based modulus
-  if(mat.modulus.size() == mat.value.size())
+  if(mat.getType() == TYPE_MODULUS:: MODULUS_BY_CELL)
     {
       for(unsigned int i = 0; i< mat.size(); ++i)
 	mat.value[i] = mat.modulus[i];
@@ -49,8 +50,7 @@ SEXP matrix_get_at_z(SEXP A,SEXP INDI, SEXP INDJ)
     {
       mat2.modulus.resize(1);
       mat2.modulus[0] = mat.modulus[0];
-    }
-
+      }*/
   return(bigintegerR::create_SEXP(mat2) );
 }
 
diff --git a/src/extract_matrix.h b/src/extract_matrix.h
index daf5763be1a0d453a8f878fcdf7edada9569f255..792a14bf31429f345b0c565c2e572fef34d6068a 100644
--- a/src/extract_matrix.h
+++ b/src/extract_matrix.h
@@ -75,19 +75,23 @@ namespace extract_gmp_R
     if(A.nrow < 0)
       A.nrow = A.size();
     else // check that size is a multiple of row
-	if((A.size() / A.nrow) != static_cast<float>(A.size()) / static_cast<float>(A.nrow))
-	    Rf_error("malformed matrix");
-
+      {
+	if((A.size() / A.nrow) != static_cast<float>(A.size()) / static_cast<float>(A.nrow)){
+	  A.clear();
+	  Rf_error("malformed matrix");
+	}
+      }
+    
     retour.resize(A.size() / A.nrow);
     for(i = 0; i < retour.size();  ++i)
       {
 	retour[i] = new T();
-	retour[i]->value.resize(A.nrow);
+	retour[i]->resize(A.nrow);
       }
     // go !
-    for(i= 0 ; i < A.value.size(); ++i)
+    for(i= 0 ; i < A.size(); ++i)
       // retour[col       ]  [row        ]
-      (retour[i / A.nrow ])->value[ i % A.nrow].setValue(A.value[i]);
+      (*retour[i / A.nrow ])[ i % A.nrow].setValue(A[i]);
 
     //return(retour);
 
@@ -116,14 +120,15 @@ namespace extract_gmp_R
    */
   template <class T> T get_at (T & A, SEXP& INDI, SEXP& INDJ)
   {
-
+    //DEBUG
+    //return A;
     // result = A[indi,indj]
     int oldnrow = A.nrow;
     std::vector<int> indJ;
 
     typename std::vector<T*> matricetmp ;
     typename std::vector<T*> matricetmp2;
-
+    
     toVecVec(A,matricetmp);
     typename std::vector<T*> copyAdress(matricetmp);
 
@@ -189,9 +194,11 @@ namespace extract_gmp_R
 	      it = std::unique(indJ.begin(),indJ.end());
 	      //indJ.erase(it,indJ.end());
 
-	      if ( indJ.back() > 0)
+	      if ( indJ.back() > 0){
+		clearVec<T>(copyAdress);
+		A.clear();
 		Rf_error("only 0's may mix with negative subscripts");
-
+	      }
 
 
 	      it=indJ.begin();
@@ -225,13 +232,18 @@ namespace extract_gmp_R
 	      // for all [new] rows
 	      for( it=indJ.begin(); it != indJ.end(); it++)
 		{
-		  if (*it < 0)
+		  if (*it < 0){
+		    clearVec<T>(copyAdress);
+		    A.clear();		    
 		    Rf_error("only 0's may mix with negative subscripts");
+		  }
 		  if( static_cast<unsigned int>(*it-1) < matrice->size() ) {
 		      //printf("on sort %s",(*matrice)[(*it)-1][0].str(10).c_str());
 		      matricework->push_back( (*matrice)[*it-1] );
 		  } else {
-		      Rf_error("column subscript out of bounds");
+		    clearVec<T>(copyAdress);
+		    A.clear();
+		    Rf_error("column subscript out of bounds");
 		  }
 		}
 
@@ -265,7 +277,7 @@ namespace extract_gmp_R
 		{
 		  // for all columns j delete row i
 		  for (j = 0; j < matrice->size(); ++j)
-		    (*matrice)[j]->value.erase(i+(*matrice)[j]->value.begin());
+		    (*matrice)[j]->erase(i);
 
 		  //++newnrow;
 		  --i; // i: new indice in modified matrix
@@ -295,9 +307,11 @@ namespace extract_gmp_R
 	      std::unique(indI.begin(),indI.end());
 	      //indI.erase(it,indI.end());
 
-	      if ( indI.back() > 0)
+	      if ( indI.back() > 0){
+		clearVec<T>(copyAdress);
+		A.clear();	
 		Rf_error("only 0's may mix with negative subscripts");
-
+	      }
 
 
 	      //newnrow = A.nrow;
@@ -313,7 +327,7 @@ namespace extract_gmp_R
 			// for all columns j remove row i
 			for (j = 0; j < matrice->size(); ++j)
 			  {
-			    (*matrice)[j]->value.erase(i+(*matrice)[j]->value.begin());
+			    (*matrice)[j]->erase(i);
 			  }
 			//--newnrow;
 			--i; // i: new indice in modified matrix
@@ -337,6 +351,8 @@ namespace extract_gmp_R
 			/* it = indI.erase(it); */
 			/* --it; */
 		      } else { // matrix case:
+			clearVec<T>(copyAdress);
+			A.clear();
 			Rf_error("subscript out of bounds");
 		      }
 		    }
@@ -365,18 +381,21 @@ namespace extract_gmp_R
 	      // for all [new] rows
 	      for( i=0; i < indI.size(); ++i)
 		{
-		  if (indI[i] < 0)
+		  if (indI[i] < 0){
+		    clearVec<T>(copyAdress);
+		    A.clear();
 		    Rf_error("only 0's may mix with negative subscripts");
+		  }
 		  if( static_cast<unsigned int>(indI[i]-1) < (*matrice)[0]->size() )
 		    {
 		      // for all columns
 		      for (j = 0; j < matricework->size(); ++j)
 			//newmat[i,j] = oldmat[ind[i],j]
-			( (*matricework)[j])->value[i] = ((*matrice)[j])->value[indI[i]-1];
+			( *(*matricework)[j])[i] = (*(*matrice)[j])[indI[i]-1];
 		    }
 		  else
 		    for (j = 0; j < matricework->size(); ++j)
-		      ( (*matricework)[j])->value[i].setValue();
+		      ( *(*matricework)[j])[i].setValue();
 		}
 
 	      matrice = matricework; // change addresses
@@ -393,7 +412,7 @@ namespace extract_gmp_R
     retour.resize(matrice->size() * newnrow);
     for(i=0; i< newnrow ; ++i)
       for(j=0; j <  matrice->size() ; ++j)
-	retour.value[i + j* newnrow ]  =  ((*matrice)[j])->value[i] ;
+	retour[i + j* newnrow ]  =  (*(*matrice)[j])[i] ;
 
     retour.nrow = (oldnrow < 0) ? -1 : newnrow;
 
@@ -413,9 +432,12 @@ namespace extract_gmp_R
       src.nrow = src.size();
 
     // check that size is a multiple of row
-    if((src.size() / src.nrow) != static_cast<float>(src.size()) / static_cast<float>(src.nrow))
+    if((src.size() / src.nrow) != static_cast<float>(src.size()) / static_cast<float>(src.nrow)){
+      src.clear();
+      T & vval = const_cast<T&>(value);
+      vval.clear();
       Rf_error("malformed matrix");
-
+    }
     unsigned int ncol = src.size() / src.nrow; // number of col
     std::vector<int> vidx =  indice_get_at ( src.nrow, IDX);
     std::vector<int> vjdx =  indice_get_at ( ncol, JDX);
@@ -428,7 +450,12 @@ namespace extract_gmp_R
 	for(unsigned int i = 0 ; i < vidx.size(); ++i)
 	  {
 	    unsigned int index = vidx[i] + vjdx[j] * src.nrow;
-	    if(index >= src.size()) Rf_error("indice out of bounds");
+	    if(index >= src.size()) {
+	      src.clear();
+	      T & vval = const_cast<T&>(value);
+	      vval.clear();
+	      Rf_error("indice out of bounds");
+	    }
 
 	    src.set(index, value[k % value.size()] );
 	    ++k;
diff --git a/src/factor.cc b/src/factor.cc
index cfb6d2b2a684717ac23169be0964b6862288dc21..a4487133eebd0d34a0a1f326ad573db0dfd1cc40 100644
--- a/src/factor.cc
+++ b/src/factor.cc
@@ -4,7 +4,7 @@
  *  \version 1
  *
  *  \date Created: 04/12/04
- *  \date Last modified: Time-stamp: <2013-06-08 22:47:18 antoine>
+ *  \date Last modified: Time-stamp: <2023-01-21 16:28:55 (antoine)>
  *
  *  \author Antoine Lucas (help from Immanuel Scholz) (R adaptation)
  *          Original C code from libgmp.
@@ -33,12 +33,14 @@ SEXP factorR (SEXP n)
     mpz_set(val,v[0].getValue().getValueTemp());
 
     int sgn = mpz_sgn(val);
-    if(sgn == 0)
+    if(sgn == 0){
+      v.clear();
       error(_("Cannot factorize 0"));
+    }
     if(sgn<0)
       {
 	mpz_abs(val,val);
-	result.value.push_back(biginteger(-1));
+	result.push_back(bigmod(biginteger(-1)));
       }
     //
     // function from gmplib, in demo/factorize.c
diff --git a/src/factorize.cc b/src/factorize.cc
index de6445b351b375d4bbc28c0f63cff8bc831098a9..bff20c14e8e16f096971ccc66897f5060d02ed00 100644
--- a/src/factorize.cc
+++ b/src/factorize.cc
@@ -180,7 +180,7 @@ mp_prime_p (mpz_t n)
 	}
     }
 
-
+  factors.clear();
   error( "Lucas prime test failure.  This should not happen\n");
  ret1:
   if (flag_prove_primality)  
diff --git a/src/matrix.cc b/src/matrix.cc
index 4a8e1c3b40710fc5534217172b69b73b2596f033..3b9f349ebd30a79d7744e1337919d4d93cd9d425 100644
--- a/src/matrix.cc
+++ b/src/matrix.cc
@@ -5,7 +5,7 @@
  *  \version 1
  *
  *  \date Created: 19/02/06
- *  \date Last modified: Time-stamp: <2023-01-16 18:58:59 (antoine)>
+ *  \date Last modified: Time-stamp: <2023-01-21 21:18:14 (antoine)>
  *
  *  \author A. Lucas
  *
@@ -47,29 +47,34 @@ SEXP as_matrixz (SEXP x, SEXP nrR, SEXP ncR, SEXP byrowR, SEXP mod)
 
   // get "bigz" vector, this makes all conversion int to bigz etc...
   bigvec mat = bigintegerR::create_bignum(x);
-  int lendat = mat.value.size();
+  int lendat = mat.size();
   // int sizemod = mat.modulus.size();
   // when modulus specified
   bigvec modulus = bigintegerR::create_bignum(mod);
-  if(modulus.value.size()>0) // should be allways the case
-    if(!modulus.value[0].isNA()) {
-      mat.modulus.resize(modulus.size());
-      for (unsigned int i = 0; i < modulus.size(); i++)
-	mat.modulus[i] = modulus.value[i];
-      // sizemod = modulus.size();
-    }
 
   // A copy from R project to get correct dimension
   // all warnings...
   //
-  if (nr == NA_INTEGER) // This is < 0
+  if (nr == NA_INTEGER){ // This is < 0
+    mat.clear();
+    modulus.clear();
     error(_("matrix: invalid 'nrow' value (too large or NA)"));
-  if (nr < 0)
+  }
+  if (nr < 0){
+    mat.clear();
+    modulus.clear();
     error(_("matrix: invalid 'nrow' value (< 0)"));
-  if (nc < 0)
+  }
+  if (nc < 0){
+    mat.clear();
+    modulus.clear();
     error(_("matrix: invalid 'ncol' value (< 0)"));
-  if (nc == NA_INTEGER)
+  }
+  if (nc == NA_INTEGER){
+    mat.clear();
+    modulus.clear();
     error(_("matrix: invalid 'ncol' value (too large or NA)"));
+  }
 
   if(lendat > 0 ) {
     if (lendat > 1 && (nr * nc) % lendat != 0) {
@@ -96,11 +101,29 @@ SEXP as_matrixz (SEXP x, SEXP nrR, SEXP ncR, SEXP byrowR, SEXP mod)
   // when we extend "x"
   if(nc*nr > lendat)
     {
-      mat.value.resize(nr*nc);
+      mat.resize(nr*nc);
       for(int i = lendat; i < nr*nc; i++)
-	mat.value[i] = mat.value[i % lendat];
+	mat[i] = mat[i % lendat];
     }
   mat.nrow = nr;
+
+
+  
+  if(modulus.size()>0) // should be allways the case
+    if(modulus[0].isNA()) {
+      // nothing but mat could have already a modulus
+    } else {
+      for (unsigned int i = 0; i < mat.size(); i++){
+	mat[i].setModulus(modulus[i % modulus.size()].getValuePtr());
+      }
+      if(modulus.size() == 1){
+	mat.setGlobalModulus(modulus[0].getValuePtr());
+      }
+      mat.setType( modulus.size() == 1 ? TYPE_MODULUS::MODULUS_GLOBAL : TYPE_MODULUS::MODULUS_BY_CELL);
+      // sizemod = modulus.size();
+    }
+
+  
   if(byrow)
     {
       bigvec mat2 = matrixz::bigint_transpose (mat);
@@ -128,6 +151,7 @@ SEXP bigint_transposeR(SEXP x)
   } else if (TYPEOF(dimAttr) == INTSXP) {
     nr = INTEGER(dimAttr)[0];
   } else { nr = -1;// -Wall
+    mat.clear();
     error(_("argument must be a matrix of class \"bigz\""));
   }
   UNPROTECT(2);
@@ -150,7 +174,7 @@ SEXP matrix_crossp_z (SEXP a, SEXP trans)
   bool useMod = FALSE,
     tr = (bool)Rf_asLogical(trans);
   bigvec mat_a = bigintegerR::create_bignum(a);
-  int sizemod = mat_a.modulus.size(),
+  int sizemod = mat_a.getModulusSize(),
     a_nrow = mat_a.nrow,
     a_len = mat_a.size();
 
@@ -175,13 +199,11 @@ SEXP matrix_crossp_z (SEXP a, SEXP trans)
   mpz_init(tt);
   mpz_t common_modulus; mpz_init(common_modulus);
 
-  if(sizemod <= 1) { // maybe 'useMod' i.e., can use common modulus:
-    if(sizemod == 1) {
-      mpz_set(common_modulus, mat_a.modulus[0].getValueTemp());
-      if(!mat_a.modulus[0].isNA())
-	useMod = TRUE;
-    }
+  if(sizemod == 1) {
+    mpz_set(common_modulus, mat_a.getGlobalModulus()->getValueTemp());
+    useMod = TRUE;
   }
+ 
 
   // here the computation:
   for(int i=0; i < m; i++)
@@ -202,16 +224,16 @@ SEXP matrix_crossp_z (SEXP a, SEXP trans)
 
       if(tr) {//------------- tcrossprod ---------------------------
 
-#define A_I_K  mat_a.value [ i + k *a_nrow]
-#define B_K_J  mat_a.value [ j + k *a_nrow]
+#define A_I_K  mat_a [ i + k *a_nrow]
+#define B_K_J  mat_a [ j + k *a_nrow]
 	K_LOOP
 #undef A_I_K
 #undef B_K_J
 
        } else {//------------- crossprod ---------------------------
 
-#define A_I_K  mat_a.value [ k + i *a_nrow]
-#define B_K_J  mat_a.value [ k + j *a_nrow]
+#define A_I_K  mat_a [ k + i *a_nrow]
+#define B_K_J  mat_a [ k + j *a_nrow]
 	K_LOOP
 #undef A_I_K
 #undef B_K_J
@@ -219,17 +241,18 @@ SEXP matrix_crossp_z (SEXP a, SEXP trans)
        }
 
       if(isna) {
-	res.value[i + j*m].setValue(0);
-	res.value[i + j*m].NA(true);
+	res[i + j*m].setValue(0);
+	res[i + j*m].getValue().NA(true);
       }
       else
-	res.value[i + j*m].setValue(R_ij);
+	res[i + j*m].setValue(R_ij);
 
     } // for(i ..)  for(j ..)
 
-  if(useMod)
-    res.modulus.push_back(biginteger(common_modulus));
-
+  if(useMod) {
+    std::shared_ptr<biginteger> ptr = std::make_shared<biginteger>(common_modulus);
+    res.setGlobalModulus(ptr);
+  }
   mpz_clear(R_ij);
   mpz_clear(tt);
   mpz_clear(common_modulus);
@@ -248,6 +271,7 @@ SEXP matrix_crossp_z (SEXP a, SEXP trans)
  */
 SEXP matrix_mul_z (SEXP a, SEXP b, SEXP op)
 {
+
   if(!strcmp(class_P(b), "bigq")) { // b  "bigq",  --> use q arithm:
       return(matrix_mul_q(a, b, op));
   }
@@ -258,8 +282,9 @@ SEXP matrix_mul_z (SEXP a, SEXP b, SEXP op)
   bigvec mat_a = bigintegerR::create_bignum(a),
          mat_b = bigintegerR::create_bignum(b);
 
-  int sizemod_a = mat_a.modulus.size(),
-      sizemod_b = mat_b.modulus.size();
+  
+  int sizemod_a = mat_a.getModulusSize(),
+      sizemod_b = mat_b.getModulusSize();
 
   int
     a_nrow = mat_a.nrow, a_len = mat_a.size(),
@@ -340,9 +365,11 @@ SEXP matrix_mul_z (SEXP a, SEXP b, SEXP op)
   if(((o_ == 0) && (a_ncol != b_nrow)) ||
      ((o_ == 1) && (a_nrow != b_nrow)) || // crossprod()
      ((o_ == 2) && (a_ncol != b_ncol))    // tcrossprod()
-     )
+     ){
+    mat_a.clear();
+    mat_b.clear();
     error(_("Matrix dimensions do not match"));
-
+  }
   // Result R is R[1..n, 1..m] -- and R_{ij} = sum_{k=1} ^ p  A.. B..
   int n,m, p;
   if(o_ == 0) {
@@ -352,6 +379,8 @@ SEXP matrix_mul_z (SEXP a, SEXP b, SEXP op)
   }else if (o_ == 2) {
     n= a_nrow; m= b_nrow; p= a_ncol;// = b_ncol
   }else {
+    mat_a.clear();
+    mat_b.clear();
     error(_("invalid 'op' code in matrix_mul_z()"));
     n = m = p = -1;// -Wall
   }
@@ -366,22 +395,10 @@ SEXP matrix_mul_z (SEXP a, SEXP b, SEXP op)
   /* modulus when modulus are "global" (i.e. of size 1) and
    * either are the same, or only one of a or b is specified
    */
-  if( !(sizemod_a > 1 || sizemod_b > 1)) {
-    if((sizemod_a == 1) && (sizemod_b == 1)) {
-      mpz_set(common_modulus, mat_a.modulus[0].getValueTemp());
-      if(mpz_cmp(common_modulus, mat_b.modulus[0].getValueTemp()) == 0
-	 && !mat_a.modulus[0].isNA())
-	useMod = TRUE;
-    }
-    else { // at least one of the sizemod_*  is > 1 :
-      if ((sizemod_a == 1) && !mat_a.modulus[0].isNA()) {
-	mpz_set(common_modulus, mat_a[0].getModulus().getValueTemp());
-	useMod = TRUE;
-      } else if ((sizemod_b == 1) && !mat_b.modulus[0].isNA()) {
-	mpz_set(common_modulus, mat_b[0].getModulus().getValueTemp());
-	useMod = TRUE;
-      }
-    }
+  std::shared_ptr<biginteger> globalMod = bigvec::getGlobalModulus(mat_a,mat_b);
+  useMod = globalMod.get() != nullptr;
+  if(useMod){
+    mpz_init_set(common_modulus,globalMod->getValueTemp());
   }
   // bigmod tmp;
 
@@ -389,12 +406,12 @@ SEXP matrix_mul_z (SEXP a, SEXP b, SEXP op)
   for(int i=0; i < n; i++)
     for(int j=0; j < m; j++)
       {
-#define	R_IJ res.value[ i + j*n]
+#define	R_IJ res[ i + j*n]
 #define K_LOOP								\
 	for(int k=0; k < p; k++)					\
 	    {								\
 	      if(A_I_K.isNA() || B_K_J.isNA()) {			\
-		R_IJ.setValue(0); R_IJ.NA(true);			\
+		R_IJ.setValue(0); R_IJ.getValue().NA(true);		\
 		break;							\
 	      }								\
 	      /* Z = A_I_K * B_K_J */					\
@@ -410,33 +427,34 @@ SEXP matrix_mul_z (SEXP a, SEXP b, SEXP op)
 
 	if(o_ == 0) { //------------- %*% ---------------------------
 
-#define A_I_K  mat_a.value [ i + k *a_nrow]
-#define B_K_J  mat_b.value [ k + j *b_nrow]
+#define A_I_K  mat_a [ i + k *a_nrow]
+#define B_K_J  mat_b [ k + j *b_nrow]
 	  K_LOOP
 #undef A_I_K
 #undef B_K_J
 
 	} else if(o_ == 1){//------------- crossprod ---------------------------
 
-#define A_I_K  mat_a.value [ k + i *a_nrow]
-#define B_K_J  mat_b.value [ k + j *b_nrow]
+#define A_I_K  mat_a [ k + i *a_nrow]
+#define B_K_J  mat_b [ k + j *b_nrow]
 	  K_LOOP
 #undef A_I_K
 #undef B_K_J
 
 	} else {//(o_ == 2) ------------- tcrossprod ---------------------------
 
-#define A_I_K  mat_a.value [ i + k *a_nrow]
-#define B_K_J  mat_b.value [ j + k *b_nrow]
+#define A_I_K  mat_a [ i + k *a_nrow]
+#define B_K_J  mat_b [ j + k *b_nrow]
 	  K_LOOP
 #undef A_I_K
 #undef B_K_J
 
 	}
       }
-  if(useMod)
-    res.modulus.push_back(biginteger(common_modulus));
-
+  if(useMod){
+    std::shared_ptr<biginteger> ptr = std::make_shared<biginteger>(common_modulus);
+    res.setGlobalModulus(ptr);
+  }
   mpz_clear(tt);
   mpz_clear(common_modulus);
 
@@ -542,6 +560,10 @@ namespace matrixz
     bigvec matbis (mat.size());
     matbis.nrow = mat.nCols();
 
+    if(mat.getType() == MODULUS_GLOBAL){
+      matbis.setGlobalModulus(mat.getGlobalModulus());
+    }
+    
     /* we compute transpose */
     for(unsigned int i =0; i<mat.nRows(); i++)
       for(unsigned int j =0; j<mat.nCols(); j++)
@@ -550,12 +572,12 @@ namespace matrixz
     return matbis;
   }
 
-  /* return dimension in dima */
+  /* return dimension in dima return -2 if dimension does not match */
   int checkDims(int dima, int dimb)
   {
     if(dima > 0 && dimb > 0) {
-      if (dimb != dima)
-	error(_("Matrix dimensions do not match"));
+      if (dimb != dima) return -2;
+      //error(_("Matrix dimensions do not match"));
     }
     else { /* either a or b is a matrix */
 	if(dima == -1)
diff --git a/src/matrixq.cc b/src/matrixq.cc
index 8563cc95d4a76fc763282254a942753093bf6519..ef8d6e7f827ad0e809d62e0bf050f25e86da9511 100644
--- a/src/matrixq.cc
+++ b/src/matrixq.cc
@@ -5,7 +5,7 @@
  *  \version 1
  *
  *  \date Created: 19/02/06
- *  \date Last modified: Time-stamp: <2022-12-09 15:55:39 (antoine)>
+ *  \date Last modified: Time-stamp: <2023-01-21 16:26:18 (antoine)>
  *
  *  \author A. Lucas
  *
@@ -52,15 +52,27 @@ SEXP as_matrixq (SEXP x, SEXP nrR, SEXP ncR, SEXP byrowR, SEXP den)
   /* A copy from R project to get correct dimension
    * all warnings...
    */
-  if (nr == NA_INTEGER) /* This is < 0 */
+  if (nr == NA_INTEGER){ /* This is < 0 */
+    mat.clear();
+    denominator.clear();
     error(_("matrix: invalid 'nrow' value (too large or NA)"));
-  if (nr < 0)
+  }
+  if (nr < 0){
+    mat.clear();
+    denominator.clear();
     error(_("matrix: invalid 'nrow' value (< 0)"));
-  if (nc < 0)
+  }
+  if (nc < 0){
+    mat.clear();
+    denominator.clear();
     error(_("matrix: invalid 'ncol' value (< 0)"));
-  if (nc == NA_INTEGER)
+  }
+  if (nc == NA_INTEGER){
+    mat.clear();
+    denominator.clear();
     error(_("matrix: invalid 'ncol' value (too large or NA)"));
-
+  }
+  
   if(lendat > 0 ) {
     if (lendat > 1 && (nr * nc) % lendat != 0) {
       if (((lendat > nr) && (lendat / nr) * nr != lendat) ||
@@ -115,6 +127,7 @@ SEXP bigq_transposeR(SEXP x)
   } else if (TYPEOF(dimAttr) == INTSXP) {
     nr = INTEGER(dimAttr)[0];
   } else {
+    mat.clear();
     error(_("argument must be a matrix of class \"bigq\""));
     nr = -1;// -Wall
   }
@@ -306,9 +319,11 @@ SEXP matrix_mul_q (SEXP a, SEXP b, SEXP op)
   if(((o_ == 0) && (a_ncol != b_nrow)) ||
      ((o_ == 1) && (a_nrow != b_nrow)) || // crossprod()
      ((o_ == 2) && (a_ncol != b_ncol))    // tcrossprod()
-     )
+     ){
+    mat_a.clear();
+    mat_b.clear();
     error(_("Matrix dimensions do not match"));
-
+  }
   // Result R is R[1..n, 1..m] -- and R_{ij} = sum_{k=1} ^ p  A.. B..
   int n,m, p;
   if(o_ == 0) {
@@ -318,6 +333,8 @@ SEXP matrix_mul_q (SEXP a, SEXP b, SEXP op)
   }else if (o_ == 2) {
     n= a_nrow; m= b_nrow; p= a_ncol;// = b_ncol
   }else {
+    mat_a.clear();
+    mat_b.clear();
     error(_("invalid 'op' code in matrix_mul_z()"));
     n = m = p = -1;// -Wall
   }
diff --git a/src/solve.cc b/src/solve.cc
index 7f46c70e3c84edd8afb311f154a9008512397d36..b4d87b734e8fca1e06664285ed8151ed8d46040c 100644
--- a/src/solve.cc
+++ b/src/solve.cc
@@ -4,7 +4,7 @@
  *  \version 1
  *
  *  \date Created: 25/05/06
- *  \date Last modified: Time-stamp: <2006-05-25 23:05:20 antoine>
+ *  \date Last modified: Time-stamp: <2023-01-21 13:18:55 (antoine)>
  *
  *  \author A. Lucas
  *
@@ -28,15 +28,17 @@ SEXP inverse_q(SEXP A)
 
 SEXP solve_gmp_R::inverse_q(bigvec_q a)
 {
-  if(a.nrow * a.nrow != (int) a.size())
+  if(a.nrow * a.nrow != (int) a.size()){
+    a.clear();
     error(_("Argument 1 must be a square matrix"));
+  }
   bigvec_q b (a.size());
   b.nrow = a.nrow;
 
   // initialize b to identity
   for(int i=0; i<b.nrow ; ++i)
     for(int j=0; j<b.nrow ; ++j)
-	b.value[i+j*b.nrow].setValue((i == j) ? 1 : 0);
+	b[i+j*b.nrow].setValue((i == j) ? 1 : 0);
 
   solve_gmp_R::solve(a,b);
 
@@ -47,18 +49,22 @@ SEXP solve_gmp_R::inverse_q(bigvec_q a)
 SEXP inverse_z (SEXP A)
 {
   bigvec a = bigintegerR::create_bignum(A);
-  if(a.modulus.size() == 1 &&  !a.modulus[0].isNA()) {
+
+  if(a.nrow * a.nrow != (int) a.size()){
+    a.clear();
+    error(_("Argument 1 must be a square matrix"));
+  }
+
+  if(a.getType() == TYPE_MODULUS::MODULUS_GLOBAL) {
     bigvec b (a.size() );
     b.nrow = a.nrow;
-    if(a.nrow * a.nrow != (int) a.size())
-      error(_("Argument 1 must be a square matrix"));
-
-    b.modulus.push_back(a.modulus[0]);
+  
     // initialize b to identity
     for(int i=0; i<b.nrow ; ++i)
       for(int j=0; j<b.nrow ; ++j)
-	b.value[i+j*b.nrow].setValue((i == j) ? 1 : 0);
+	b[i+j*b.nrow].setValue((i == j) ? 1 : 0);
 
+    b.setGlobalModulus(a.getGlobalModulus());
     solve_gmp_R::solve(a,b);
 
     return(bigintegerR::create_SEXP(b));
@@ -75,37 +81,41 @@ SEXP solve_z(SEXP A,SEXP B)
   bool common_modulus=true;
   bigvec a = bigintegerR::create_bignum(A);
   bigvec b = bigintegerR::create_bignum(B);
-  if(a.modulus.size() == 1 )
-    if(!a.modulus[0].isNA())
+
+  // case: b a vector
+  if(b.nrow<1)
+    b.nrow = b.size();
+  
+  if(a.nrow * a.nrow != (int) a.size()){
+    a.clear();
+    b.clear();
+    error(_("Argument 1 must be a square matrix"));
+  }
+	
+  if(a.nrow != b.nrow){
+    a.clear();
+    b.clear();
+    error(_("Dimensions do not match"));
+  }
+  
+  if(a.getType() == TYPE_MODULUS::MODULUS_GLOBAL && b.getType() != TYPE_MODULUS::MODULUS_BY_CELL ) {
+
+    if(b.getType() == TYPE_MODULUS::NO_MODULUS){
+      b.setGlobalModulus(a.getGlobalModulus());
+    }
+    
+    if(*a.getGlobalModulus() == *b.getGlobalModulus())
       {
-	if(b.modulus.size()>1)
-	  common_modulus = false; // -> solve with rational
-	if(b.modulus.size() == 1)
-	  {
-	    if(b.modulus[0] == a.modulus[0])
-	      common_modulus = false; // -> solve with rational
-	  }
-	else
-	  b.modulus.push_back(a.modulus[0]);
 	// solve in Z/nZ
-	if(common_modulus)
-	  {
-	    // case: b a vector
-	    if(b.nrow<1)
-	      b.nrow = b.size();
-
-	    if(a.nrow * a.nrow != (int) a.size())
-	      error(_("Argument 1 must be a square matrix"));
-
-	    if(a.nrow != b.nrow)
-	      error(_("Dimensions do not match"));
-
-	    solve_gmp_R::solve(a,b);
-
-	    return(bigintegerR::create_SEXP(b));
-	  }
+	
+	
+	solve_gmp_R::solve(a,b);
+	
+	return(bigintegerR::create_SEXP(b));
+	
       }
-
+  }
+  // Solve as rational numbers.
   bigvec_q aq (a);
   bigvec_q bq (b);
   return(solve_gmp_R::solve_q(aq,bq));
@@ -124,16 +134,21 @@ SEXP solve_q(SEXP A,SEXP B)
 // solve AX = B
 SEXP solve_gmp_R::solve_q(bigvec_q a, bigvec_q b)
 {
-  if(a.nrow * a.nrow != (int) a.size())
+  if(a.nrow * a.nrow != (int) a.size()){
+    a.clear();
+    b.clear();
     error(_("Argument 1 must be a square matrix"));
-
+  }
   // case: b a vector
   if(b.nrow<0)
     b.nrow = b.size();
 
-  if(a.nrow != b.nrow)
+  if(a.nrow != b.nrow){
+    a.clear();
+    b.clear();
     error(_("Dimensions do not match"));
-
+  }
+  
   solve_gmp_R::solve(a,b);
 
   return(bigrationalR::create_SEXP(b));
diff --git a/src/solve.h b/src/solve.h
index 200f0e658cf66ff0c13c7dd5bbc4dfb1ba597039..0d42b6c6ecf0d6354eb8cab60360952bb09e74e2 100644
--- a/src/solve.h
+++ b/src/solve.h
@@ -58,9 +58,12 @@ namespace solve_gmp_R
       // A [ i ,j] = A[ i + j * A.nrow]
       for(unsigned int k = 0 ; k < A.nRows(); ++k)
 	{
-	  if(A.get(k, k).sgn() == 0 )
+	  if(A.get(k, k).sgn() == 0 ){
+	    A.clear();
+	    B.clear();
 	    Rf_error("System is singular");
-
+	  }
+	  
 	  // l_k <- (1/akk) l_k
 	  T tmpValeur =A.get(k , k).inv() ;
 	  A.mulLine(k,tmpValeur);
diff --git a/src/templateMatrix.h b/src/templateMatrix.h
index c7fceed371cc681032501cb27e610384145e24c8..89a952ccf000358c2b303f787f304b8882fc9d1b 100644
--- a/src/templateMatrix.h
+++ b/src/templateMatrix.h
@@ -16,6 +16,8 @@ namespace math{
 
     virtual const T & operator[](unsigned int i) const=0;
     virtual  T & operator[](unsigned int i) =0;
+
+    virtual ~Vector(){};
   };
 
   template< class T>
@@ -44,6 +46,7 @@ namespace math{
     /** return true if matrix is supposed to be a vector and not a matrix n x 1 */
     virtual bool isVector() const = 0;
 
+    virtual void clear() = 0;
     /**
      * \brief assign a value at indice i
      */