Parcourir la source

Add Garside structure for Artin and Dual braid of type A + modifications of the core

Jean Fromentin il y a 8 ans
Parent
commit
70c11b1ca3

+ 196 - 14
array.hpp

@@ -33,7 +33,7 @@ using namespace std;
 //! Class for array
 template <class T>
 class Array{
- protected:
+public:
 
   //! Size of the array
   size_t s;
@@ -42,14 +42,12 @@ class Array{
   //! Construct an array from a c++ array a of size s and own it
   Array(T* a,size_t s);
 
-public:
-
   //! Contruct an array of size s
   //! \param s size of the array
   Array(size_t s=0);
   
   //! Construct an array from an initialization list
-   Array(const initializer_list<T>& list);
+  Array(const initializer_list<T>& list);
     
   //! The copy contructor
   Array(const Array<T>&);
@@ -73,19 +71,20 @@ public:
   //! \param array Array to copy
   Array& operator=(const Array& array);
 
-  
-  //! Assignement operator with move
+    //! Assignement operator with move
   //! \param array Array to move
   Array& operator=(Array&& array);
-
   
   //! Test is the array is empty
   //! \return true if empty flase otherwise 
   bool is_empty() const;
     
   //! Return the size of the array$
-    size_t size() const;
-    
+  size_t size() const;
+   
+  //! Display the array in a string
+  string to_string() const;
+  
   //! Return a pointer to the begin of the array
   const T* begin() const;
     
@@ -122,25 +121,58 @@ public:
   //! \param return a reference to the value at index i
   T& operator[](size_t i);
 
-  
-  //! Comparison function
+  //! Operator<
   bool operator<(const Array& array) const;
-   
-  //! Display function
-  template<class U> friend std::ostream& operator<<(std::ostream& os,const Array<U>&);
 
+  //! Append an array to the current one
+  Array append(const Array& array) const;
+    
 };
 
+//***********************
+//* Auxiliary functions *
+//***********************
+
+//! Comparison function for int16_t
+//! \param x a int16_t
+//! \param y a int16_t
+//! \return -1 is x<y, 0 if x==y and 1 is x>y
+int cmp(int16_t x,int16_t y);
+
+//! Comparison function for Array
+//! \param A an Array
+//! \param B an Array
+//! \return -1 is A<B, 0 if A==B and 1 is A>B
+template<class T> int cmp(const Array<T>& A,const Array<T>& B);
+
+//! Operator<< for Array
+template<class T> ostream& operator<<(std::ostream& os,const Array<T>&);
+
+//! to_string function for Array
+template<class T> string to_string(const Array<T>&);
+
 //*************************
 //* Function declarations *
 //*************************
 
+//----------------------
+// Array::Array(size_t)
+//----------------------
+
 template<class T> inline
 Array<T>::Array(size_t _s):s(_s),array(new T[_s]){}
 
+//-------------------------
+// Array::Array(T*,size_t)
+//-------------------------
+
 template<class T> inline
 Array<T>::Array(T* a,size_t _s):s(_s),array(a){}
 
+//----------------------------------------
+// Array::Array(const initializer_list<T>
+//----------------------------------------
+
 template<class T> 
 Array<T>::Array(const initializer_list<T> &list):s((int)list.size()),array(new T[s]){
   T* ptr=array;
@@ -150,17 +182,29 @@ Array<T>::Array(const initializer_list<T> &list):s((int)list.size()),array(new T
   }
 }
 
+//------------------------------
+// Array::Array(const Array<T>&
+//------------------------------
+
 template<class T> inline
 Array<T>::Array(const Array<T>& a):s(a.s),array(new T[s]){
   memcpy(array,a.array,s*sizeof(T));
 }
 
+//-------------------
+// Array::Array<T>&&
+//-------------------
+
 template<class T> inline
 Array<T>::Array(Array<T>&& a):s(a.s),array(a.array){
   a.s=0;
   a.array=nullptr;
 }
 
+//------------------------------
+// Array::Array(const list<T>&)
+//------------------------------
+
 template<class T> 
 Array<T>::Array(const list<T>& l):s((int)l.size()),array(new T[s]){
   T* ptr=array;
@@ -170,6 +214,10 @@ Array<T>::Array(const list<T>& l):s((int)l.size()),array(new T[s]){
   }
 }
 
+//-------------------------
+// Array::Array(stack<T>&)
+//-------------------------
+
 template<class T> 
 Array<T>::Array(stack<T>& stack):s(stack.size()),array(new T[s]){
   T* ptr=array;
@@ -180,6 +228,10 @@ Array<T>::Array(stack<T>& stack):s(stack.size()),array(new T[s]){
   }
 }
 
+//-----------------------------
+// Array::Array(const set<T>&)
+//-----------------------------
+
 template<class T> 
 Array<T>::Array(const set<T>& l):s(l.size()),array(new T[s]){
   T* ptr=array;
@@ -189,11 +241,19 @@ Array<T>::Array(const set<T>& l):s(l.size()),array(new T[s]){
   }
 }
 
+//-----------------
+// Array::~Array()
+//-----------------
+
 template<class T> inline
 Array<T>::~Array(){
   if(array!=nullptr) delete[] array;
 }
 
+//-----------------------------------
+// Array::operator=(const Array<T>&)
+//-----------------------------------
+
 template<class T> Array<T>&
 Array<T>::operator=(const Array<T>& a){
   if(this!=&a){
@@ -207,6 +267,10 @@ Array<T>::operator=(const Array<T>& a){
   return *this;
 }
 
+//------------------------------
+// Array::operator=(Array<T>&&)
+//------------------------------
+
 template<class T>  Array<T>&
 Array<T>::operator=(Array<T>&& a){
   if(this!=&a){
@@ -219,38 +283,81 @@ Array<T>::operator=(Array<T>&& a){
   return *this;
 }
 
+//-------------------
+// Array::is_empty()
+//-------------------
+
 template<class T> inline bool
 Array<T>::is_empty() const{
   return s==0;
 }
 
+//---------------
+// Array::size()
+//---------------
+
 template<class T> inline size_t
 Array<T>::size() const{
   return s;
 }
 
+//------------------
+// Array::to_string()
+//------------------
+
+template<class T> string
+Array<T>::to_string() const{
+  if(s==0) return "()";
+  string res="("+std::to_string(read(0));
+  for(size_t i=1;i<s;++i){
+    res+=',';
+    res+=std::to_string(read(i));
+  }
+  return res+")";
+}
+
+//----------------
+// Array::begin()
+//----------------
+
 template<class T> inline const T*
 Array<T>::begin() const{
   return array;
 }
 
+//--------------
+// Array::end()
+//--------------
+
 template<class T> inline const T*
 Array<T>::end() const{
   return array+s;
 }
 
+//-------------------------------
+// Array::write(size_t,const T&)
+//-------------------------------
+
 template<class T> inline void
 Array<T>::write(size_t i,const T& v){
   assert(i<s);
   array[i]=v;
 }
 
+//---------------------
+// Array::read(size_t)
+//---------------------
+
 template<class T> inline T&
 Array<T>::read(size_t i) const{
   assert(i<s);
   return array[i];
 }
 
+//-------------------
+// Array::at(size_t)
+//-------------------
+
 template<class T> inline const T&
 Array<T>::at(size_t i) const{
   assert(i<s);
@@ -263,6 +370,10 @@ Array<T>::at(size_t i){
   return array[i];
 }
 
+//---------------------------
+// Array::operator[](size_t)
+//---------------------------
+
 template<class T> inline const T&
 Array<T>::operator[](size_t i) const{
   assert(i<s);
@@ -275,6 +386,22 @@ Array<T>::operator[](size_t i){
   return array[i];
 }
 
+//-----------------------------
+// Array::append(const Array&)
+//-----------------------------
+
+template<class T> Array<T>
+Array<T>::append(const Array<T>& arr) const{
+  Array<T> res(s+arr.s);
+  memcpy(res.array,array,s*sizeof(T));
+  memcpy(&res.array[s],arr.array,arr.s*sizeof(T));
+  return res;
+}
+
+//--------------------------------
+// Array::operator<(const Array&)
+//--------------------------------
+
 template<class T> bool
 Array<T>::operator<(const Array<T>& arr) const{
   if(s==arr.s){
@@ -286,6 +413,53 @@ Array<T>::operator<(const Array<T>& arr) const{
   return s<arr.s;
 }
 
+
+//***********************
+//* Auxiliary functions *
+//***********************
+
+//--------------------------
+// cmp(int16_t x,int16_t y)
+//--------------------------
+
+inline int
+cmp(int16_t x,int16_t y){
+  if(x<y) return -1;
+  if(x==y) return 0;
+  return 1;
+}
+
+//------------------------------------
+// cmp(const Array& A,const Array& B)
+//------------------------------------
+
+
+template<class T> int
+cmp(const Array<T>& A,const Array<T>& B){
+  if(A.s==B.s){
+    for(size_t i=0;i<A.s;++i){
+      int c=cmp(A.read(i),B.read(i));
+      if(c!=0) return c;
+    }
+    return 0;
+  }
+  if(A.s<B.s) return -1;
+  return 1;
+}
+
+//----------------------------
+// to_string(const Array<T>&)
+//----------------------------
+
+template<class T> inline string
+to_string(const Array<T>& arr){
+  return arr.to_string();
+}
+
+//-------------------------------------------
+// operator<<(ostram&,const Array<uint8_t>&)
+//-------------------------------------------
+
 inline ostream& 
 operator<<(ostream& os,const Array<uint8_t>& a){
   os<<'[';
@@ -297,6 +471,10 @@ operator<<(ostream& os,const Array<uint8_t>& a){
   return os<<']'; 
 }
 
+//------------------------------------------
+// operator<<(ostram&,const Array<int8_t>&)
+//------------------------------------------
+
 inline ostream& 
 operator<<(ostream& os,const Array<int8_t>& a){
   os<<'[';
@@ -308,6 +486,10 @@ operator<<(ostream& os,const Array<int8_t>& a){
   return os<<']'; 
 }
 
+//------------------------------------------
+// operator<<(ostram&,const Array<int8_t>&)
+//------------------------------------------
+
 template<class T> ostream& 
 operator<<(ostream& os,const Array<T>& a){
   os<<'[';

+ 2 - 2
ext/base/Makefile

@@ -1,4 +1,4 @@
-CPP 	= g++ -g --std=c++11 -march=corei7 -Wno-return-local-addr -fPIC -rdynamic -fmax-errors=1 -I/usr/local/include
+CPP 	= g++ -g --std=c++11 -march=corei7 -Wno-return-local-addr -fPIC -rdynamic -fmax-errors=10 -I/usr/local/include
 LDFLAGS = #-L/usr/local/lib -lgmpxx -lgmp -lflint
 MOD 	= ../base.so
 
@@ -7,7 +7,7 @@ all: $(MOD)
 %.o:%.cpp %.hpp
 	$(CPP) -c $< -o $@
 
-$(MOD): init.cpp array.o kernel.o module.o string.o
+$(MOD): init.cpp array.o kernel.o module.o string.o integer.o
 	$(CPP) -shared  $(LDFLAGS) $^ -o $@
 
 clean:

+ 1 - 0
ext/base/check

@@ -0,0 +1 @@
+2==2

+ 13 - 1
ext/base/init.cpp

@@ -20,6 +20,9 @@
 #include "init.hpp"
 
 extern "C"{
+
+  bool True=true;
+  bool False=false;
   
   Gomu::Type types[]={
     TYPE_SENTINEL
@@ -41,12 +44,21 @@ extern "C"{
   
   //--- Contextual functions ---//
   Gomu::Module::Function contextual_functions[]={
+    {"Void","check",{"Module"},(void*)module_check},
     {"Void","delete",{"Symbol"},(void*)del},
     {"Void","execute",{"String"},(void*)execute},
     {"Generic","operator=",{"Symbol","Generic"},(void*)assignment},
-    {"Array","symbols",{"Type"},(void*)symbols},
+    {"Boolean","operator==",{"Generic","Generic"},(void*)equality},
+    {"Array","symbols",{"Type"},(void*)member_symbols},
     {"Type","type",{"Generic"},(void*)type},
     FUNC_SENTINEL
   };
+
+
+  Gomu::Module::Symbol symbols[]={
+    {"true","Boolean",(void*)&True},
+    {"false","Boolean",(void*)&False},
+    SYMB_SENTINEL
+  };
 }
 

+ 1 - 0
ext/base/init.hpp

@@ -21,4 +21,5 @@
 #include "array.hpp"
 #include "kernel.hpp"
 #include "module.hpp"
+#include "integer.hpp"
 #include "string.hpp"

+ 20 - 0
ext/base/integer.cpp

@@ -0,0 +1,20 @@
+/**
+ * This file is part of Gomu.
+ *
+ *  Copyright 2016 by Jean Fromentin <jean.fromentin@math.cnrs.fr>
+ *
+ * Gomu is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Gomu is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Gomu. If not, see <http://www.gnu.org/licenses/>. 
+ */
+
+#include "integer.hpp"

+ 23 - 0
ext/base/integer.hpp

@@ -0,0 +1,23 @@
+/**
+ * This file is part of Gomu.
+ *
+ *  Copyright 2016 by Jean Fromentin <jean.fromentin@math.cnrs.fr>
+ *
+ * Gomu is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Gomu is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Gomu. If not, see <http://www.gnu.org/licenses/>. 
+ */
+
+ #include "../../module.hpp"
+
+using namespace Gomu;
+

+ 37 - 8
ext/base/kernel.cpp

@@ -17,11 +17,9 @@
  * along with Gomu. If not, see <http://www.gnu.org/licenses/>. 
  */
 
+#include <fstream>
 #include "kernel.hpp"
 #include "../../interpreter.hpp"
-#include <fstream>
-
-
 
 //------------------------------------
 // assignment(Context&,Value&,Value&)
@@ -34,7 +32,7 @@ Value assignment(Context& context,Value& lhs,Value& rhs){
     if(((Value*)lhs.ptr)->ptr==rhse->ptr) return rhs;
     Symbol* symbol=(Symbol*)lhs.ptr;
     if(symbol->locked) ContextError("The symbol is locked");
-    ((Value*)lhs.ptr)->del();
+    ((Value*)lhs.ptr)->pdel();
   }
   if(rhs.type==type_symbol){
     copyValue((Value*)lhs.ptr,rhse);
@@ -53,7 +51,7 @@ Value assignment(Context& context,Value& lhs,Value& rhs){
 //----------------------
 
 Value del(Context&,Value& v){
-  ((Value*)v.ptr)->del();  
+  ((Value*)v.ptr)->pdel();  
   ((Value*)v.ptr)->type=type_void;
   return Value(type_void,nullptr);
 }
@@ -68,8 +66,22 @@ Value execute(Context& context,Value& file){
   fs.open(filename.c_str(),fstream::in);
   string cmd;
   size_t line=1;
-  while(getline(fs,cmd)){
-    context.interpreter->eval(cmd,context,false);
+  bool error=false;
+  Value* res;
+  while(not error and getline(fs,cmd)){
+    try{
+      res=context.interpreter->eval_basic(cmd,context);
+    }
+    catch(Error err){
+      error=true;
+      context.interpreter->purge_tree();
+      cout<<"Line "<<line<<" : ";
+      err.disp(cout,cmd);
+      cout<<endl;
+    }
+    if(not error){
+      res->pdel();
+    }
   }
   fs.close();
   return Value(type_void,nullptr);
@@ -80,7 +92,7 @@ Value execute(Context& context,Value& file){
 // symbols
 //---------
 
-Value symbols(Context& context,Value& v){
+Value member_symbols(Context& context,Value& v){
   Type* type=(Type*)v.ptr;
   string str=type->name+'.';
   deque<string> stack;
@@ -107,3 +119,20 @@ Value type(Context&,Value& v){
 }
 
 
+//-------------------------------
+// equal(Context&,Value&,Value&)
+//-------------------------------
+
+Value equality(Context&,Value& v1,Value& v2){
+  Value res;
+  res.type=type_boolean;
+  Value* a=v1.eval();
+  Value* b=v2.eval();
+  if(a->type!=b->type){
+    res.ptr=to_boolean(false);
+    return res;
+  }
+  Type* type=a->type;
+  res.ptr=to_boolean(type->comp(a->ptr,b->ptr)==0);
+  return res;
+}

+ 4 - 1
ext/base/kernel.hpp

@@ -33,7 +33,10 @@ Value del(Context&,Value&);
 Value type(Context&,Value&);
 
 //! Return an array of member functions of a type
-Value symbols(Context&,Value&);
+Value member_symbols(Context&,Value&);
 
 //! Execute commands strored in a file
 Value execute(Context&, Value&);
+
+//! Test equality between values
+Value equality(Context&, Value&, Value&);

+ 47 - 0
ext/base/module.cpp

@@ -17,9 +17,56 @@
  * along with Gomu. If not, see <http://www.gnu.org/licenses/>. 
  */
 
+#include <fstream>
 #include "module.hpp"
 #include "../../interpreter.hpp"
 
+using namespace Gomu;
+
+//-----------------------------
+// module_check(Context,Value)
+//-----------------------------
+
+Value module_check(Context& context,Value& value){
+  Module* module=(Module*)value.ptr;
+   string filename="ext/"+module->name+"/check";
+   ifstream fs;
+  fs.open(filename.c_str(),fstream::in);
+  if(!fs) RuntimeError("File "+filename+" does not exist");
+  string cmd;
+  Value* v;
+  bool error=false;
+  size_t line=1;
+  while(not error and getline(fs,cmd)){
+    if(not cmd.empty() and cmd[0]!='#'){
+      try{
+	v=context.interpreter->eval_basic(cmd,context);
+      }
+      catch(Error err){
+	error=true;
+	context.interpreter->purge_tree();
+	cout<<"[\033[34m"<<filename<<"\033[0m:\033[32m"<<line<<"\033[0m] ";
+	err.disp(cout,cmd);
+	cout<<endl;
+	return Value(type_void,nullptr);
+      }
+      if(not error){
+	if(v->type==type_boolean){
+	  bool flag=*(bool*)v->ptr;
+	  if(not flag){
+	    cout<<"\033[31mfailed\033[0m line "<<line<<"\033[0m"<<endl;
+	    return Value(type_void,nullptr);
+	  }
+	}
+	v->pdel();
+      }
+    }
+    ++line;
+  }
+  cout<<"\033[32mpassed\033[0m"<<endl;
+  return Value(type_void,nullptr);
+}
+
 //---------------------
 // module_types(void*)
 //---------------------

+ 3 - 0
ext/base/module.hpp

@@ -22,6 +22,9 @@
 
 using namespace Gomu;
 
+//! Run ckeck of a mofule
+Value module_check(Context&,Value&);
+
 //! Return types defined in a module
 void* module_types(void*);
 

+ 20 - 0
ext/garside/Makefile

@@ -0,0 +1,20 @@
+CPP 	= g++ -g --std=c++11 -march=corei7 -Wno-return-local-addr -fPIC -rdynamic -fmax-errors=10 -I/usr/local/include
+LDFLAGS = #-L/usr/local/lib -lgmpxx -lgmp -lflint
+MOD 	= ../garside.so
+APP	= garside
+
+all: $(MOD)
+
+%.o:%.cpp %.hpp
+	$(CPP) -c $< -o $@
+
+$(MOD): init.cpp stacked_list.o braids.o monoid.o 
+	$(CPP) -shared  $(LDFLAGS) $^ -o $@
+
+$(APP): main.cpp stacked_list.o braids.o monoid.o
+	$(CPP) $(LDFLAGS) $^ -o $@
+
+clean:
+	-$(RM) *~
+	-$(RM) *.o
+	-$(RM) $(MOD) 

+ 190 - 0
ext/garside/braids.cpp

@@ -0,0 +1,190 @@
+/**
+ * This file is part of Gomu.
+ *
+ *  Copyright 2016 by Jean Fromentin <jean.fromentin@math.cnrs.fr>
+ *
+ * Gomu is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Gomu is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Gomu. If not, see <http://www.gnu.org/licenses/>. 
+ */
+
+#include "braids.hpp"
+#include "init.hpp"
+
+//******************
+//* Global objects *
+//******************
+
+MonoidFamily ArtinA_mf("Artin A-type",ArtinA_disp,ArtinA_gnum);
+MonoidFamily dualA_mf("Dual A-type",DualA_disp,DualA_gnum);
+
+//***********************
+//* Auxiliary functions *
+//***********************
+
+//---------------
+// braids_init()
+//---------------
+
+void braids_init(){
+  ArtinA_mf.set_left_complement(&ArtinA_left_sc);
+  ArtinA_mf.set_right_complement(&ArtinA_right_sc);
+  ArtinA_mf.data=(void*)type_ArtinWordA;
+  dualA_mf.set_left_complement(&DualA_left_sc);
+  dualA_mf.set_right_complement(&DualA_right_sc);
+  dualA_mf.data=(void*)type_DualWordA;
+}
+
+//------------------------------------------------
+// ArtinA_left_sc(Generator,Generator,Generator*)
+//------------------------------------------------
+
+int ArtinA_left_sc(const Generator& x,const Generator& y,Generator* comp){
+  //Comp statisfy comp*x=...*y
+  if(x==y) return 0;
+  if(abs(x-y)==1){
+    comp[0]=x;
+    comp[1]=y;
+    return 2;
+  }
+  else{
+    comp[0]=y;
+    return 1;
+  }
+}
+
+//-------------------------------------------------
+// ArtinA_rigth_sc(Generator,Generator,Generator*)
+//-------------------------------------------------
+
+int ArtinA_right_sc(const Generator& x,const Generator& y,Generator* comp){
+  //Comp satisfy x*comp=y*...
+  if(x==y) return 0;
+  if(abs(x-y)==1){
+    comp[0]=y;
+    comp[1]=x;
+    return 2;
+  }
+  else{
+    comp[0]=y;
+    return 1;
+  }
+}
+
+//--------------------
+// DualA_gnum(size_t)
+//--------------------
+
+inline size_t
+DualA_gnum(size_t n){
+  size_t res=0;
+  for(size_t i=1;i<n;++i){
+    res+=i;
+  }
+  return res;
+}
+
+//-----------------------------------------------
+// DualA_left_sc(Generator,Generator,Generator*)
+//-----------------------------------------------
+
+int DualA_left_sc(const Generator& x,const Generator& y,Generator* comp){
+  //Case 1
+  if(x==y) return 0;
+  uint p=get_i(x);
+  uint q=get_j(x);
+  uint r=get_i(y);
+  uint s=get_j(y);
+  //Case 5 and 6
+  if(p==r){
+    comp[0]=(q<s)?y:generator(s,q);
+    return 1;
+  }
+  //Case 7 and 8
+  if(q==s){
+    comp[0]=(p<r)?y:generator(r,p);
+    return 1;
+  }
+  //Case 3
+  if(p==s){
+    comp[0]=y;
+    return 1;
+  }
+  //Case 5
+  if(q==r){
+    comp[0]=generator(p,s);
+    return 1;
+  }
+  //Case 9
+  if(p<r and r<q and q<s){
+    comp[0]=generator(r,q);
+    comp[1]=generator(p,s);
+    return 2;
+  }
+  //Case 10
+  if(r<p and p<s and s<q){
+    comp[0]=generator(s,q);
+    comp[1]=generator(r,p);
+    return 2;
+  }
+  //Case 2
+  comp[0]=y;
+  return 1;
+}
+
+//------------------------------------------------
+// DualA_right_sc(Generator,Generator,Generator*)
+//------------------------------------------------
+
+int DualA_right_sc(const Generator& x,const Generator& y,Generator* comp){
+  //Case 1
+  if(x==y) return 0;
+  uint p=get_i(x);
+  uint q=get_j(x);
+  uint r=get_i(y);
+  uint s=get_j(y);
+  //Case 5 and 6
+  if(p==r){
+    comp[0]=(q<s)?generator(q,s):y;
+    return 1;
+  }
+  //Case 7 and 8
+  if(q==s){
+    comp[0]=(p<r)?generator(p,r):y;
+    return 1;
+  }
+  //Case 3
+  if(p==s){
+    comp[0]=generator(r,q);
+    return 1;
+  }
+  //Case 5
+  if(q==r){
+    comp[0]=y;
+    return 1;
+  }
+  //Case 9
+  if(p<r and r<q and q<s){
+    comp[0]=generator(q,s);
+    comp[1]=generator(p,r);
+    return 2;
+  }
+  //Case 10
+  if(r<p and p<s and s<q){
+    comp[0]=generator(p,s);
+    comp[1]=generator(r,q);
+    return 2;
+  }
+  //Case 2
+  comp[0]=y;
+  return 1;
+}

+ 122 - 0
ext/garside/braids.hpp

@@ -0,0 +1,122 @@
+/**
+ * This file is part of Gomu.
+ *
+ *  Copyright 2016 by Jean Fromentin <jean.fromentin@math.cnrs.fr>
+ *
+ * Gomu is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Gomu is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Gomu. If not, see <http://www.gnu.org/licenses/>. 
+ */
+
+#ifndef BRAIDS_HPP
+#define BRAIDS_HPP
+#include "monoid.hpp"
+
+//******************
+//* Global objects *
+//******************
+
+extern MonoidFamily ArtinA_mf;
+extern MonoidFamily dualA_mf;
+
+//***********************************
+//* Auxiliary functions declaration *
+//***********************************
+
+//! Initilise all braids structure
+void braids_init();
+Generator generator(uint8_t i,uint8_t j);
+uint8_t get_i(const Generator& x);
+uint8_t get_j(const Generator& y);
+
+//-----------------
+// Artin of type A
+//-----------------
+
+//! Display function for generators of type A braids
+string ArtinA_disp(const Generator& x);
+
+//! Return the number of generators of type A braid of rank n
+size_t ArtinA_gnum(size_t n);
+
+//! Set left complement for Artin monoid of type A
+int ArtinA_left_sc(const Generator& x,const Generator &y,Generator* comp);
+
+//! Set right complement for Artin monoid of type A
+int ArtinA_right_sc(const Generator& x,const Generator &y,Generator* comp);
+
+//-----------------
+// Dual of type A
+//-----------------
+
+//! Display function for generators of type A dual braids
+string DualA_disp(const Generator& x);
+
+//! Return the number of generators of type A dual braids of rank n
+size_t DualA_gnum(size_t n);
+
+//! Set left complement for dual monoid of type A
+int DualA_left_sc(const Generator& x,const Generator &y,Generator* comp);
+
+//! Set right complement for dual monoid of type A
+int DualA_right_sc(const Generator& x,const Generator &y,Generator* comp);
+
+
+//**********************
+//* Inline definitions *
+//**********************
+
+//---------------------
+// Auxiliary functions
+//---------------------
+
+inline string
+ArtinA_disp(const Generator& x){
+  if(x==0) return "e";
+  if(x>0) return "a"+to_string(x);
+  return "A"+to_string(-x);
+}
+
+inline size_t
+ArtinA_gnum(size_t n){
+  return n-1;
+}
+
+inline string
+DualA_disp(const Generator& x){
+  if(x==0) return "e";
+  if(x>0) return "a"+to_string(get_i(x))+to_string(get_j(x));
+  return "A"+to_string(get_i(-x))+to_string(get_j(-x));
+}
+
+inline Generator
+generator(uint8_t i,uint8_t j){
+  Generator res=j;
+  res<<=8;
+  return res+i;
+}
+
+inline uint8_t
+get_i(const Generator& x){
+  uint8_t* t=(uint8_t*)&x;
+  return t[0];
+}
+
+inline uint8_t
+get_j(const Generator& x){
+  uint8_t* t=(uint8_t*)&x;
+  return t[1];
+}
+
+
+
+#endif

+ 136 - 0
ext/garside/check

@@ -0,0 +1,136 @@
+#******************
+#* Dual of type A *
+#******************
+
+# Left complement
+
+DualA.left_complement(a12,a12)==a00
+DualA.left_complement(a12,a23)==a13
+DualA.left_complement(a12,a34)==a34
+DualA.left_complement(a12,a24)==a14
+DualA.left_complement(a12,a14)==a14
+DualA.left_complement(a23,a12)==a12
+DualA.left_complement(a23,a23)==a00
+DualA.left_complement(a23,a13)==a12
+DualA.left_complement(a23,a34)==a24
+DualA.left_complement(a23,a24)==a24
+DualA.left_complement(a23,a14)==a14
+DualA.left_complement(a13,a12)==a23
+DualA.left_complement(a13,a23)==a23
+DualA.left_complement(a13,a13)==a00
+DualA.left_complement(a13,a34)==a14
+DualA.left_complement(a13,a24)==a23*a14
+DualA.left_complement(a13,a14)==a14
+DualA.left_complement(a34,a12)==a12
+DualA.left_complement(a34,a23)==a23
+DualA.left_complement(a34,a13)==a13
+DualA.left_complement(a34,a34)==a00
+DualA.left_complement(a34,a24)==a23
+DualA.left_complement(a34,a14)==a13
+DualA.left_complement(a24,a12)==a12
+DualA.left_complement(a24,a23)==a34
+DualA.left_complement(a24,a13)==a34*a12
+DualA.left_complement(a24,a34)==a34
+DualA.left_complement(a24,a24)==a00
+DualA.left_complement(a24,a14)==a12
+DualA.left_complement(a14,a12)==a24
+DualA.left_complement(a14,a23)==a23
+DualA.left_complement(a14,a13)==a34
+DualA.left_complement(a14,a34)==a34
+DualA.left_complement(a14,a24)==a24
+DualA.left_complement(a14,a14)==a00
+
+# Right complement
+
+DualA.right_complement(a12,a12)==a00
+DualA.right_complement(a12,a23)==a23
+DualA.right_complement(a12,a13)==a23
+DualA.right_complement(a12,a34)==a34
+DualA.right_complement(a12,a24)==a24
+DualA.right_complement(a12,a14)==a24
+DualA.right_complement(a23,a12)==a13
+DualA.right_complement(a23,a23)==a00
+DualA.right_complement(a23,a13)==a13
+DualA.right_complement(a23,a34)==a34
+DualA.right_complement(a23,a24)==a34
+DualA.right_complement(a23,a14)==a14
+DualA.right_complement(a13,a12)==a12
+DualA.right_complement(a13,a23)==a12
+DualA.right_complement(a13,a13)==a00
+DualA.right_complement(a13,a34)==a34
+DualA.right_complement(a13,a24)==a34*a12
+DualA.right_complement(a13,a14)==a34
+DualA.right_complement(a34,a12)==a12
+DualA.right_complement(a34,a23)==a24
+DualA.right_complement(a34,a13)==a14
+DualA.right_complement(a34,a34)==a00
+DualA.right_complement(a34,a24)==a24
+DualA.right_complement(a34,a14)==a14
+DualA.right_complement(a24,a12)==a14
+DualA.right_complement(a24,a23)==a23
+DualA.right_complement(a24,a13)==a23*a14
+DualA.right_complement(a24,a34)==a23
+DualA.right_complement(a24,a24)==a00
+DualA.right_complement(a24,a14)==a14
+DualA.right_complement(a14,a12)==a12
+DualA.right_complement(a14,a23)==a23
+DualA.right_complement(a14,a13)==a13
+DualA.right_complement(a14,a34)==a13
+DualA.right_complement(a14,a24)==a12
+DualA.right_complement(a14,a14)==a00
+
+# Garside structure
+
+DualA.left_lcm_complement(a12,a23)==a13
+DualA.left_lcm_complement(a12,a12*a23)==a13
+DualA.left_lcm_complement(a12,a23*a12)==a23
+
+DualA.left_lcm(a12,a23)==a13*a12
+DualA.left_lcm(a12,a12*a23)==a13*a12
+DualA.left_lcm(a12,a23*a12)==a23*a12
+
+DualA.right_lcm_complement(a12,a23)==a23
+DualA.right_lcm_complement(a12,a12*a23)==a23
+DualA.right_lcm_complement(a12,a23*a12)==a23*a12
+
+DualA.right_lcm(a12,a23)==a12*a23
+DualA.right_lcm(a12,a12*a23)==a12*a23
+DualA.right_lcm(a12,a23*a12)==a12*a23*a12
+
+DualA.left_gcd(a12,a12*a23)==a12
+DualA.left_gcd(a12,a23*a12)==a00
+DualA.left_gcd(a12*a23,a12*a12*a23)==a12*a23
+
+DualA.right_gcd(a12,a12*a23)==a12
+DualA.right_gcd(a12,a23*a12)==a12
+DualA.right_gcd(a12*a23,a12*a12*a23)==a12*a23
+
+DualA.left_gcd_x(a12*a23*a34,a12*a23*a12)==(a12*a23,a34)
+DualA.left_gcd_x(a12*a23*a12,a12*a23*a34)==(a12*a23,a12)
+
+DualA.right_gcd_x(a12*a23*a34,a12*a23*a12)==(a12*a23,a14)
+DualA.right_gcd_x(a12*a23*a12,a12*a23*a34)==(a13*a12,a23)
+
+DualA.is_left_divisible(a12*a23,a12)
+DualA.is_left_divisible(a12*a23,a23)
+DualA.is_left_divisible(a12*a23,a13)
+DualA.is_left_divisible(a12*a23,a14)==false
+DualA.is_left_divisible(a12*a23,a12*a12)==false
+
+DualA.is_right_divisible(a12*a23,a12)
+DualA.is_right_divisible(a12*a23,a23)
+DualA.is_right_divisible(a12*a23,a13)
+DualA.is_right_divisible(a12*a23,a14)==false
+DualA.is_right_divisible(a12*a23,a12*a12)==false
+
+DualA.is_left_divisible_x(a12*a23,a12)==(true,a23)
+DualA.is_left_divisible_x(a12*a23,a23)==(true,a13)
+DualA.is_left_divisible_x(a12*a23,a13)==(true,a12)
+DualA.is_left_divisible_x(a12*a23,a14)==(false,a00)
+DualA.is_left_divisible_x(a12*a23,a12*a12)==(false,a00)
+
+DualA.is_right_divisible_x(a12*a23,a12)==(true,a13)
+DualA.is_right_divisible_x(a12*a23,a23)==(true,a12)
+DualA.is_right_divisible_x(a12*a23,a13)==(true,a23)
+DualA.is_right_divisible_x(a12*a23,a14)==(false,a00)
+DualA.is_right_divisible_x(a12*a23,a12*a12)==(false,a00)

BIN
ext/garside/garside


+ 432 - 0
ext/garside/init.cpp

@@ -0,0 +1,432 @@
+/**
+ * This file is part of Gomu.
+ *
+ *  Copyright 2016 by Jean Fromentin <jean.fromentin@math.cnrs.fr>
+ *
+ * Gomu is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Gomu is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Gomu. If not, see <http://www.gnu.org/licenses/>. 
+ */
+
+#include "init.hpp"
+
+//******************
+//* Global objects *
+//******************
+
+Gomu::Type* type_ArtinWordA;
+Gomu::Type* type_DualWordA;
+Gomu::Type* type_monoid_family;
+Gomu::Type* type_word;
+
+//*************************
+//* Extension inilisation *
+//*************************
+
+extern "C"{
+  Word empty_word;
+  Word x1({1});
+  Word x2({2});
+  Word x3({3});
+  Word x4({4});
+  Word X1({-1});
+  Word X2({-2});
+  Word X3({-3});
+  Word X4({-4});
+  Word x12({generator(1,2)});
+  Word x13({generator(1,3)});
+  Word x23({generator(2,3)});
+  Word x14({generator(1,4)});
+  Word x24({generator(2,4)});
+  Word x34({generator(3,4)});
+  Word X12({(Generator)(-generator(1,2))});
+  Word X13({(Generator)(-generator(1,3))});
+  Word X23({(Generator)(-generator(2,3))});
+  Word X14({(Generator)(-generator(1,4))});
+  Word X24({(Generator)(-generator(2,4))});
+  Word X34({(Generator)(-generator(3,4))});
+  
+  void init(){
+    braids_init();
+  }
+  
+  Gomu::Module::Type types[]={
+    {"ArtinWordA",ArtinWordA_display,word_delete,word_copy,word_compare,&type_ArtinWordA},
+    {"DualWordA",DualWordA_display,word_delete,word_copy,word_compare,&type_DualWordA},
+
+    {"ArtinMonoidFamilyA",mf_display,mf_delete,Gomu::no_copy,Gomu::no_comp,&type_monoid_family},
+    {"DualMonoidFamilyA",mf_display,mf_delete,Gomu::no_copy,Gomu::no_comp,&type_monoid_family},
+    
+    {"MonoidFamily",mf_display,mf_delete,Gomu::no_copy,Gomu::no_comp,&type_monoid_family},
+    {"Word",word_display,word_delete,word_copy,word_compare,&type_word},
+    TYPE_SENTINEL
+  };
+  
+  Gomu::Module::Function functions[]={
+    {"ArtinWordA","operator*",{"ArtinWordA","ArtinWordA"},(void*)word_concatenate},
+    {"DualWordA","operator*",{"DualWordA","DualWordA"},(void*)word_concatenate},
+    {"Word","word",{"Array"},(void*)word_from_array},
+    FUNC_SENTINEL
+  };
+  
+  Gomu::Module::Function member_functions[]={
+    //ArtinMonoidFamilyA
+    {"Boolean","is_left_divisible",{"ArtinMonoidFamilyA","ArtinWordA","ArtinWordA"},(void*)mt_is_left_divisible},
+    {"Tuple","is_left_divisible_x",{"ArtinMonoidFamilyA","ArtinWordA","ArtinWordA"},(void*)mt_is_left_divisible_x},
+    {"Boolean","is_right_divisible",{"ArtinMonoidFamilyA","ArtinWordA","ArtinWordA"},(void*)mt_is_right_divisible},
+    {"Tuple","is_right_divisible_x",{"ArtinMonoidFamilyA","ArtinWordA","ArtinWordA"},(void*)mt_is_right_divisible_x},
+    {"ArtinWordA","left_complement",{"ArtinMonoidFamilyA","ArtinWordA","ArtinWordA"},(void*)mt_left_complement},
+    {"ArtinWordA","left_denominator",{"ArtinMonoidFamilyA"},(void*)mt_left_denominator},
+    {"ArtinWordA","left_lcm",{"ArtinMonoidFamilyA","ArtinWordA","ArtinWordA"},(void*)mt_left_lcm},
+    {"ArtinWordA","left_lcm_complement",{"ArtinMonoidFamilyA","ArtinWordA","ArtinWordA"},(void*)mt_left_lcm_complement},
+    {"ArtinWordA","left_gcd",{"ArtinMonoidFamilyA","ArtinWordA","ArtinWordA"},(void*)mt_left_gcd},
+    {"Tuple","left_gcd_x",{"ArtinMonoidFamilyA","ArtinWordA","ArtinWordA"},(void*)mt_left_gcd_x},
+    {"ArtinWordA","left_numerator",{"ArtinMonoidFamilyA"},(void*)mt_left_numerator},
+    {"ArtinWordA","left_reverse",{"ArtinMonoidFamilyA","ArtinWordA"},(void*)mt_left_reverse},
+    {"ArtinWordA","left_reverse",{"ArtinMonoidFamilyA","ArtinWordA","ArtinWordA"},(void*)mt_left_reverse2},
+    {"ArtinWordA","right_complement",{"ArtinMonoidFamilyA","ArtinWordA","ArtinWordA"},(void*)mt_right_complement},
+    {"ArtinWordA","right_denominator",{"ArtinMonoidFamilyA"},(void*)mt_right_denominator},
+    {"ArtinWordA","right_lcm",{"ArtinMonoidFamilyA","ArtinWordA","ArtinWordA"},(void*)mt_right_lcm},
+    {"ArtinWordA","right_lcm_complement",{"ArtinMonoidFamilyA","ArtinWordA","ArtinWordA"},(void*)mt_right_lcm_complement},
+    {"ArtinWordA","right_gcd",{"ArtinMonoidFamilyA","ArtinWordA","ArtinWordA"},(void*)mt_right_gcd},
+    {"Tuple","right_gcd_x",{"ArtinMonoidFamilyA","ArtinWordA","ArtinWordA"},(void*)mt_right_gcd_x},
+    {"ArtinWordA","right_numerator",{"ArtinMonoidFamilyA"},(void*)mt_right_numerator},
+    {"ArtinWordA","right_reverse",{"ArtinMonoidFamilyA","ArtinWordA"},(void*)mt_right_reverse},
+    {"ArtinWordA","right_reverse",{"ArtinMonoidFamilyA","ArtinWordA","ArtinWordA"},(void*)mt_right_reverse2},
+
+    //ArtinWordA
+    {"Integer","length",{"ArtinWordA"},(void*)word_length},
+    {"ArtinWordA","inverse",{"ArtinWordA"},(void*)word_inverse},
+
+    //DualMonoidFamilyA
+    {"Boolean","is_left_divisible",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_is_left_divisible},
+    {"Tuple","is_left_divisible_x",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_is_left_divisible_x},
+    {"Boolean","is_right_divisible",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_is_right_divisible},
+    {"Tuple","is_right_divisible_x",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_is_right_divisible_x},
+    {"DualWordA","left_complement",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_left_complement},
+    {"DualWordA","left_denominator",{"DualMonoidFamilyA"},(void*)mt_left_denominator},
+    {"DualWordA","left_lcm",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_left_lcm},
+    {"DualWordA","left_lcm_complement",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_left_lcm_complement},
+    {"DualWordA","left_gcd",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_left_gcd},
+    {"Tuple","left_gcd_x",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_left_gcd_x},
+    {"DualWordA","left_numerator",{"DualMonoidFamilyA"},(void*)mt_left_numerator},
+    {"DualWordA","left_reverse",{"DualMonoidFamilyA","DualWordA"},(void*)mt_left_reverse},
+    {"DualWordA","left_reverse",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_left_reverse2},
+    {"DualWordA","right_complement",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_right_complement},
+    {"DualWordA","right_denominator",{"DualMonoidFamilyA"},(void*)mt_right_denominator},
+    {"DualWordA","right_lcm",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_right_lcm},
+    {"DualWordA","right_lcm_complement",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_right_lcm_complement},
+    {"DualWordA","right_gcd",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_right_gcd},
+    {"Tuple","right_gcd_x",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_right_gcd_x},
+    {"DualWordA","right_numerator",{"DualMonoidFamilyA"},(void*)mt_right_numerator},
+    {"DualWordA","right_reverse",{"DualMonoidFamilyA","DualWordA"},(void*)mt_right_reverse},
+    {"DualWordA","right_reverse",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_right_reverse2},
+    
+    //DualWordA
+    {"Integer","length",{"DualWordA"},(void*)word_length},
+    {"ArtinWordA","inverse",{"DualWordA"},(void*)word_inverse},
+    
+    //MonoidFamily
+    {"Integer","generators_number",{"MonoidFamily","Integer"},(void*)mf_generators_number},
+    
+    //Word
+    {"Integer","length",{"Word"},(void*)word_length},
+    {"Word","inverse",{"Word"},(void*)word_inverse},
+    FUNC_SENTINEL
+  };
+    
+  Gomu::Module::Symbol symbols[]={
+    {"a0","ArtinWordA",(void*)&empty_word},
+    {"a1","ArtinWordA",(void*)&x1},
+    {"a2","ArtinWordA",(void*)&x2},
+    {"a3","ArtinWordA",(void*)&x3},
+    {"a4","ArtinWordA",(void*)&x4},
+    {"A1","ArtinWordA",(void*)&X1},
+    {"A2","ArtinWordA",(void*)&X2},
+    {"A3","ArtinWordA",(void*)&X3},
+    {"A4","ArtinWordA",(void*)&X4},
+    {"a00","DualWordA",(void*)&empty_word},
+    {"a12","DualWordA",(void*)&x12},
+    {"a13","DualWordA",(void*)&x13},
+    {"a23","DualWordA",(void*)&x23},
+    {"a14","DualWordA",(void*)&x14},
+    {"a24","DualWordA",(void*)&x24},
+    {"a34","DualWordA",(void*)&x34},
+    {"A12","DualWordA",(void*)&X12},
+    {"A13","DualWordA",(void*)&X13},
+    {"A23","DualWordA",(void*)&X23},
+    {"A14","DualWordA",(void*)&X14},
+    {"A24","DualWordA",(void*)&X24},
+    {"A34","DualWordA",(void*)&X34},
+    {"ArtinA","ArtinMonoidFamilyA",(void*)&ArtinA_mf},
+    {"DualA","DualMonoidFamilyA",(void*)&dualA_mf},
+    SYMB_SENTINEL
+  };
+};
+    
+//*************************
+//* Fonctions definitions *
+//*************************
+
+//--------------------------------------------------
+// Boolean is_left_divisible(MonoidTrait,Word,Word)
+//--------------------------------------------------
+
+void* mt_is_left_divisible(void* m,void* a,void* b){
+  MonoidTrait* monoid=(MonoidTrait*)m;
+  return Gomu::to_boolean(monoid->is_left_divisible(*(Word*)a,*(Word*)b));
+}
+
+//---------------------------------------------------------------
+// pair<Boolean,Word> is_left_divisible_x(MonoidTrait,Word,Word)
+//---------------------------------------------------------------
+
+void* mt_is_left_divisible_x(void* m,void* a,void* b){
+  MonoidTrait* monoid=(MonoidTrait*)m;
+  pair<bool,Word> p=monoid->is_left_divisible_x(*(Word*)a,*(Word*)b);
+  Gomu::TupleValue* res=new Gomu::TupleValue(2);
+  res->tab[0]=Gomu::Value(Gomu::type_boolean,Gomu::to_boolean(p.first));
+  res->tab[1]=Gomu::Value((Gomu::Type*)monoid->data,new Word(p.second));
+  return (void*)res;
+}
+
+//-----------------------------------------------
+// bool is_right_divisible(MonoidTrait,Word,Word)
+//-----------------------------------------------
+
+void* mt_is_right_divisible(void* m,void* a,void* b){
+  MonoidTrait* monoid=(MonoidTrait*)m;
+  return Gomu::to_boolean(monoid->is_right_divisible(*(Word*)a,*(Word*)b));
+}
+
+//----------------------------------------------------------------
+// pair<Boolean,Word> is_right_divisible_x(MonoidTrait,Word,Word)
+//----------------------------------------------------------------
+
+void* mt_is_right_divisible_x(void* m,void* a,void* b){
+  MonoidTrait* monoid=(MonoidTrait*)m;
+  pair<bool,Word> p=monoid->is_right_divisible_x(*(Word*)a,*(Word*)b);
+  Gomu::TupleValue* res=new Gomu::TupleValue(2);
+  res->tab[0]=Gomu::Value(Gomu::type_boolean,Gomu::to_boolean(p.first));
+  res->tab[1]=Gomu::Value((Gomu::Type*)monoid->data,new Word(p.second));
+  return (void*)res;
+}
+
+//---------------------------------------------
+// Word left_complement(MonoidTrait,Word,Word)
+//---------------------------------------------
+
+void* mt_left_complement(void* m,void* a,void* b){
+  MonoidTrait* monoid=(MonoidTrait*)m;
+  Word* u=(Word*)a;
+  Word* v=(Word*)b;
+  if(u->size()!=1 or v->size()!=1) RuntimeError("Words must be of length 1");
+  return new Word(monoid->left_complement(u->array[0],v->array[0]));  
+}
+
+//------------------------------------
+// Word left_denominator(MonoidTrait)
+//------------------------------------
+
+void* mt_left_denominator(void* m){
+  MonoidTrait* monoid=(MonoidTrait*)m;
+    if(not monoid->is_left_complemented())
+    RuntimeError("Monoid is not left complemented");
+  return new Word(monoid->left_denominator());
+}
+
+//---------------------------------------
+// Word left_gcd(MonoidTrait,Word,Word)
+//---------------------------------------
+
+void* mt_left_gcd(void* m,void* a,void *b){
+  MonoidTrait* monoid=(MonoidTrait*)m;
+  return new Word(monoid->left_gcd(*(Word*)a,*(Word*)b));
+}
+    
+//-----------------------------------------------
+// (Word,Word) left_gcd_x(MonoidTrait,Word,Word)
+//-----------------------------------------------
+
+void* mt_left_gcd_x(void* m,void* a,void *b){
+  MonoidTrait* monoid=(MonoidTrait*)m;
+  pair<Word,Word> p=monoid->left_gcd_x(*(Word*)a,*(Word*)b);
+  Gomu::TupleValue* res=new Gomu::TupleValue(2);
+  Gomu::Type* type=(Gomu::Type*)monoid->data;
+  res->tab[0]=Gomu::Value(type,new Word(p.first));
+  res->tab[1]=Gomu::Value(type,new Word(p.second));
+  return (void*)res;
+}
+
+//--------------------------------------
+// Word left_lcm(MonoidTrait,Word,Word)
+//--------------------------------------
+
+void* mt_left_lcm(void* m,void* a,void *b){
+  MonoidTrait* monoid=(MonoidTrait*)m;
+  return new Word(monoid->left_lcm(*(Word*)a,*(Word*)b));
+}
+
+//-------------------------------------------------
+// Word left_lcm_complement(MonoidTrait,Word,Word)
+//-------------------------------------------------
+
+void* mt_left_lcm_complement(void* m,void* a,void *b){
+  MonoidTrait* monoid=(MonoidTrait*)m;
+  return new Word(monoid->left_lcm_complement(*(Word*)a,*(Word*)b));
+}
+
+//----------------------------------
+// Word left_numerator(MonoidTrait)
+//----------------------------------
+
+void* mt_left_numerator(void* m){
+  MonoidTrait* monoid=(MonoidTrait*)m;
+  if(not monoid->is_left_complemented())
+    RuntimeError("Monoid is not left complemented");
+  return new Word(monoid->left_numerator());
+}
+
+//-------------------------------------
+// Word left_reverse(MonoidTrait,Word)
+//-------------------------------------
+
+void* mt_left_reverse(void* m,void* w){
+  MonoidTrait* monoid=(MonoidTrait*)m;
+  if(not monoid->is_left_complemented())
+    RuntimeError("Monoid is not left complemented");
+  return (void*)new Word(monoid->left_reverse(*(Word*)w));
+}
+
+//------------------------------------------
+// Word left_reverse(MonoidTrait,Word,Word)
+//------------------------------------------
+
+void* mt_left_reverse2(void* m,void* num,void* den){
+  MonoidTrait* monoid=(MonoidTrait*)m;
+  if(not monoid->is_left_complemented())
+    RuntimeError("Monoid is not left complemented");
+  return (void*)new Word(monoid->left_reverse(*(Word*)num,*(Word*)den));
+}
+
+//----------------------------------------------
+// Word right_complement(MonoidTrait,Word,Word)
+//----------------------------------------------
+
+void* mt_right_complement(void* m,void* a,void* b){
+  MonoidTrait* monoid=(MonoidTrait*)m;
+  Word* u=(Word*)a;
+  Word* v=(Word*)b;
+  if(u->size()!=1 or v->size()!=1) RuntimeError("Words must be of length 1");
+  return new Word(monoid->right_complement(u->array[0],v->array[0]));  
+}
+
+//-------------------------------------
+// Word right_denominator(MonoidTrait)
+//-------------------------------------
+
+void* mt_right_denominator(void* m){
+  MonoidTrait* monoid=(MonoidTrait*)m;
+  if(not monoid->is_right_complemented())
+    RuntimeError("Monoid is not right complemented");
+  return new Word(monoid->right_denominator());
+}
+
+//---------------------------------------
+// Word right_gcd(MonoidTrait,Word,Word)
+//---------------------------------------
+
+void* mt_right_gcd(void* m,void* a,void *b){
+  MonoidTrait* monoid=(MonoidTrait*)m;
+  return new Word(monoid->right_gcd(*(Word*)a,*(Word*)b));
+}
+
+//-----------------------------------------------
+// (Word,Word) right_gcd_x(MonoidTrait,Word,Word)
+//-----------------------------------------------
+
+void* mt_right_gcd_x(void* m,void* a,void *b){
+  MonoidTrait* monoid=(MonoidTrait*)m;
+  pair<Word,Word> p=monoid->right_gcd_x(*(Word*)a,*(Word*)b);
+  Gomu::TupleValue* res=new Gomu::TupleValue(2);
+  Gomu::Type* type=(Gomu::Type*)monoid->data;
+  res->tab[0]=Gomu::Value(type,new Word(p.first));
+  res->tab[1]=Gomu::Value(type,new Word(p.second));
+  return (void*)res;
+}
+
+//---------------------------------------
+// Word right_lcm(MonoidTrait,Word,Word)
+//---------------------------------------
+
+void* mt_right_lcm(void* m,void* a,void *b){
+  MonoidTrait* monoid=(MonoidTrait*)m;
+  return new Word(monoid->right_lcm(*(Word*)a,*(Word*)b));
+}
+
+//--------------------------------------------------
+// Word right_lcm_complement(MonoidTrait,Word,Word)
+//--------------------------------------------------
+
+void* mt_right_lcm_complement(void* m,void* a,void *b){
+  MonoidTrait* monoid=(MonoidTrait*)m;
+  return new Word(monoid->right_lcm_complement(*(Word*)a,*(Word*)b));
+}
+
+//-----------------------------------
+// Word right_numerator(MonoidTrait)
+//-----------------------------------
+
+void* mt_right_numerator(void* m){
+  MonoidTrait* monoid=(MonoidTrait*)m;
+  if(not monoid->is_right_complemented())
+    RuntimeError("Monoid is not right complemented");
+  return new Word(monoid->right_numerator());
+}
+
+//--------------------------------------
+// Word right_reverse(MonoidTrait,Word)
+//--------------------------------------
+
+void* mt_right_reverse(void* m,void* w){
+  MonoidTrait* monoid=(MonoidTrait*)m;
+  if(not monoid->is_right_complemented())
+    RuntimeError("Monoid is not right complemented");
+  return (void*)new Word(monoid->right_reverse(*(Word*)w));
+}
+
+//-------------------------------------------
+// Word right_reverse(MonoidTrair,Word,Word)
+//-------------------------------------------
+
+void* mt_right_reverse2(void* m,void* den,void* num){
+  MonoidTrait* monoid=(MonoidTrait*)m;
+  if(not monoid->is_right_complemented())
+    RuntimeError("Monoid is not right complemented");
+  return (void*)new Word(monoid->right_reverse(*(Word*)den,*(Word*)num));
+}
+
+//-----------------------
+// Word word(ArrayValue)
+//-----------------------
+
+void* word_from_array(void* arr){
+  Gomu::ArrayValue* array=(Gomu::ArrayValue*)arr;
+  if(array->type!=Gomu::type_integer)
+    RuntimeError("An array of integer is needed");
+  size_t size=array->size;
+  Word* res=new Word(size);
+  for(size_t i=0;i<size;++i){
+    res->write(i,Gomu::get_slong(array->tab[i]));
+  }
+  return res;		 
+}

+ 237 - 0
ext/garside/init.hpp

@@ -0,0 +1,237 @@
+/**
+ * This file is part of Gomu.
+ *
+ *  Copyright 2016 by Jean Fromentin <jean.fromentin@math.cnrs.fr>
+ *
+ * Gomu is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Gomu is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Gomu. If not, see <http://www.gnu.org/licenses/>. 
+ */
+
+#include <sstream>
+#include "../../module.hpp"
+#include "monoid.hpp"
+#include "braids.hpp"
+
+//*****************
+//* Global object *
+//*****************
+
+extern Gomu::Type* type_ArtinWordA;
+extern Gomu::Type* type_DualWordA;
+
+//****************
+//* MonoidFamily *
+//****************
+
+//! Display a MonoidFamily
+string mf_display(void* m);
+
+//! Delete a MonoidFamily
+void mf_delete(void* m);
+
+//! Return generators number fror rank n
+void* mf_generators_number(void* m,void* n);
+
+//***************
+//* MonoidTrait *
+//***************
+
+//! Test is a left divides b
+void* mt_is_left_divisible(void* m,void* a,void* b);
+
+//! Test is a left divides b and return extar informations
+void* mt_is_left_divisible_x(void* m,void* a,void* b);
+
+//! Test is a right divides b
+void* mt_is_right_divisible(void* m,void* a,void* b);
+
+//! Test is a right divides b and return extar informations
+void* mt_is_right_divisible_x(void* m,void* a,void* b);
+
+//! Return left complememnt
+void* mt_left_complement(void* m,void* a,void*b);
+
+//! Return left denominator
+void* mt_left_denominator(void* m);
+
+//! Return left gcd of a and b
+void* mt_left_gcd(void* m,void* a,void* b);
+
+//! Return left gcd with extra informations of a and b
+void* mt_left_gcd_x(void* m,void* a,void *b);
+
+//! Return left lcm of a and b
+void* mt_left_lcm(void* m,void* a,void* b);
+
+//! Return left lcm complement of a and b
+void* mt_left_lcm_complement(void* m,void* a,void* b);
+
+//! Return left numerator
+void* mt_left_numerator(void* m);
+
+//! Left reverse a word
+void* mt_left_reverse(void* m,void* w);
+
+//! Left reverse num*den^-1
+void* mt_left_reverse2(void* m,void* num,void* den);
+
+//! Return right complememnt
+void* mt_right_complement(void* m,void* a,void*b);
+
+//! Return right denominator
+void* mt_right_denominator(void* m);
+
+//! Return right gcd of a and b
+void* mt_right_gcd(void* m,void* a,void* b);
+
+//! Return right gcd with extra informations of a and b
+void* mt_right_gcd_x(void* m,void* a,void *b);
+
+//! Return right lcm of a and b
+void* mt_right_lcm(void* m,void* a,void* b);
+
+//! Return right lcm complement of a and b
+void* mt_right_lcm_complement(void* m,void* a,void* b);
+
+//! Right reverse a word
+void* mt_right_reverse(void* m,void* w);
+
+//! Right reverse den^-1*num
+void* mt_right_reverse2(void* m,void* den,void* num);
+
+//! Return right numerator
+void* mt_right_numerator(void* m);
+
+
+//********
+//* Word *
+//********
+
+//! Display a Word monoid
+string word_display(void* w);
+
+//! Delete a Word monoid
+void word_delete(void* w);
+
+//! Copy a word monoid
+void* word_copy(void* w);
+
+//! Compare to Word monoid
+int word_compare(void* w1,void* w2);
+
+//! Create a Word monoid from an array of integer
+void* word_from_array(void* arr);
+
+//! Return the length of a Word
+void* word_length(void*);
+
+//! Inverse a Word
+void* word_invserse(void*);
+
+//! Concatenate two words
+void* word_concatenate(void*,void*);
+
+//**************
+//* ArtinWordA *
+//**************
+
+//! Display a ArtinWordA
+string ArtinWordA_display(void* w);
+
+//*************
+//* DualWordA *
+//*************
+
+//! Display a DualWordA
+string DualWordA_display(void* w);
+
+//**********************
+//* Inline definitions *
+//**********************
+
+//--------------
+// MonoidFamily
+//--------------
+
+inline string
+mf_display(void* m){
+  return ((MonoidFamily*)m)->display();
+}
+
+inline void
+mf_delete(void* m){
+  delete (MonoidFamily*)m;
+}
+
+inline void*
+mf_generators_number(void* m,void* n){
+  return Gomu::to_integer(((MonoidFamily*)m)->generators_number(Gomu::get_slong(n)));
+}
+
+//------
+// Word
+//------
+
+inline string
+word_display(void* w){
+  return to_string(*((Word*)w));
+}
+
+inline void
+word_delete(void* w){
+  delete (Word*)w;
+}
+
+inline void*
+word_copy(void* w){
+  return (void*)new Word(*(Word*)w);
+}
+
+inline int
+word_compare(void* u,void* v){
+   return cmp(*(Word*)u,*(Word*)v);
+}
+
+inline void*
+word_length(void* u){
+  return Gomu::to_integer(((Word*)u)->size());
+}
+
+inline void*
+word_inverse(void* u){
+  return new Word(((Word*)u)->inverse());
+}
+
+inline void*
+word_concatenate(void* u,void *v){
+  return new Word(((Word*)u)->concatenate(*(Word*)v));
+}
+
+//------------
+// ArtinWordA
+//------------
+
+inline string
+ArtinWordA_display(void* w){
+  return ((Word*)w)->display(ArtinA_disp);
+}
+
+//------------
+// DualWordA
+//------------
+
+inline string
+DualWordA_display(void* w){
+  return ((Word*)w)->display(DualA_disp);
+}
+

+ 12 - 0
ext/garside/main.cpp

@@ -0,0 +1,12 @@
+#include "monoid.hpp"
+#include "braids.hpp"
+#include <list>
+
+using namespace std;
+
+int main(){
+  Generator x=generator(4,3);
+  cout<<generator(1,3)<<endl;
+  cout<<generator(2,3)<<endl;
+  cout<<(int)get_i(x)<<','<<(int)get_j(x)<<endl;
+}

+ 481 - 0
ext/garside/monoid.cpp

@@ -0,0 +1,481 @@
+/**
+ * This file is part of Gomu.
+ *
+ *  Copyright 2016 by Jean Fromentin <jean.fromentin@math.cnrs.fr>
+ *
+ * Gomu is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Gomu is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Gomu. If not, see <http://www.gnu.org/licenses/>. 
+ */
+
+#include "monoid.hpp"
+
+//*************
+//* Reversing *
+//*************
+
+Word
+Reversing::get_word() const{
+  size_t s=word.size;
+  Word res(s);
+  if(s==0) return res;
+  NInd ind=word.nodes[0].next;
+  res[0]=word.nodes[ind].data;
+  size_t i=1;
+  while((ind=word.nodes[ind].next)!=0){
+    res[i++]=word.nodes[ind].data;
+  }
+  return res;
+}
+
+//*****************
+//* LeftReversing *
+//*****************
+
+//-----------------------------------
+// LeftReversing::check_positivity()
+//-----------------------------------
+
+bool
+LeftReversing::check_positivity(){
+  while(not to_reverse.empty()){
+    reverse();
+    if(word.size>0 and word.first()<0) return false;
+  }
+  return true;
+}
+
+//------------------------------
+// LeftReversing::denominator()
+//------------------------------
+
+Word
+LeftReversing::denominator(){
+  size_t ind=word.nodes[0].next;
+  if(ind==0 or word.nodes[ind].data>0) return Word();
+  size_t s=1;
+  while((ind=word.nodes[ind].next)!=0 and word.nodes[ind].data<0){ 
+    ++s;
+  }
+  Word res(s);
+  s=0;
+  while((ind=word.nodes[ind].previous)!=0){
+    res[s++]=-word.nodes[ind].data;
+  }
+  return res;
+}
+
+//----------------------------
+// LeftReversing::numerator()
+//----------------------------
+
+Word
+LeftReversing::numerator(){
+  size_t ind=word.nodes[0].previous;
+  if(ind==0 or word.nodes[ind].data<0) return Word();
+  size_t s=1;
+  while((ind=word.nodes[ind].previous)!=0 and word.nodes[ind].data>0){ 
+    ++s;
+  }
+  Word res(s);
+  s=0;
+  while((ind=word.nodes[ind].next)!=0){
+    res[s++]=word.nodes[ind].data;
+  }
+  return res;
+}
+
+//--------------------------
+// LeftReversing::reverse()
+//--------------------------
+
+void
+LeftReversing::reverse(){
+  //replace ___x.Y___ by ___U.v___
+  NInd i=to_reverse.back();
+  to_reverse.pop_back();
+  Generator x=word.nodes[i].data;
+  NInd j=word.nodes[i].next;
+  NInd p=word.nodes[i].previous;
+  Generator y=-word.nodes[j].data;
+  NInd n=word.nodes[j].next;
+  //the word is __$.x.Y.#__ with $=[p],X=[i],y=[j],#=[n]
+  size_t s=set_comp(x,y,comp);
+  //TODO :: Unroll loop
+  for(size_t ind=0;ind<s;++ind){
+    word.insert_after(i,-comp[ind]);
+  }
+  word.erase(i);
+  s=set_comp(y,x,comp);
+  for(size_t ind=0;ind<s;++ind) word.insert_before(j,comp[ind]);
+  word.erase(j);
+
+  //the word is now __$.U.v.#___ with $=[p] and #=[n]
+  if(s>0){
+    if(word.nodes[p].data>0){
+      if(word.nodes[word.nodes[p].next].data<0){
+	to_reverse.push_back(p);
+      }
+    }
+    if(word.nodes[n].data<0){
+      if(word.nodes[word.nodes[n].previous].data>0){
+	to_reverse.push_back(word.nodes[n].previous);
+      }
+    }
+  }
+  else{
+    if(word.nodes[p].data>0 and word.nodes[n].data<0){
+      to_reverse.push_back(p);
+    }
+  }
+}
+
+//----------------------------------------
+// LeftReversing::set_word(const Word& w)
+//----------------------------------------
+
+void
+LeftReversing::set_word(const Word& w){
+  clear();
+  Reversing::set_word(w);
+  if(w.is_empty()) return;
+  for(size_t i=0;i<w.size()-1;++i){
+    if(w.read(i)>0 and w.read(i+1)<0){
+      to_reverse.push_back(i+1); 
+    }
+  }
+}
+
+//----------------------------------------------------------
+// LeftReversing::set_word(const Word& num,const Word& den)
+//----------------------------------------------------------
+
+void
+LeftReversing::set_word(const Word& num,const Word& den){
+  clear();
+  size_t ns=num.size();
+  size_t ds=den.size();
+  Reversing::init_word(ns+ds);
+  for(int i=0;i<ns;++i){
+    word.nodes[i+1].data=num[i];
+  }
+  for(int i=0;i<ds;++i){
+    word.nodes[i+ns+1].data=-den[ds-i-1];
+  }
+  if(ns*ds!=0) to_reverse.push_back(ns);
+}
+
+//******************
+//* RightReversing *
+//******************
+
+//------------------------------------
+// RightReversing::check_positivity()
+//------------------------------------
+
+bool
+RightReversing::check_positivity(){
+  while(not to_reverse.empty()){
+    reverse();
+    if(word.size>0 and word.last()<0) return false;
+  }
+  return true;
+}
+
+//-------------------------------
+// RightReversing::denominator()
+//-------------------------------
+
+Word
+RightReversing::denominator(){
+  size_t ind=word.nodes[0].previous;
+  if(ind==0 or word.nodes[ind].data>0) return Word();
+  size_t s=1;
+  while((ind=word.nodes[ind].previous)!=0 and word.nodes[ind].data<0){ 
+    ++s;
+  }
+  Word res(s);
+  size_t i=0;
+  while((ind=word.nodes[ind].next)!=0){
+    res[s-i-1]=-word.nodes[ind].data;
+    ++i;
+  }
+  return res;
+}
+
+//-----------------------------
+// RightReversing::numerator()
+//-----------------------------
+
+Word
+RightReversing::numerator(){
+  size_t ind=word.nodes[0].next;
+  if(ind==0 or word.nodes[ind].data<0) return Word();
+  size_t s=1;
+  while((ind=word.nodes[ind].next)!=0 and word.nodes[ind].data>0){ 
+    ++s;
+  }
+  Word res(s);
+  size_t i=0;
+  while((ind=word.nodes[ind].previous)!=0){
+    res[s-i-1]=word.nodes[ind].data;
+    ++i;
+  }
+  return res;
+}
+
+//---------------------------
+// RightReversing::reverse()
+//---------------------------
+
+void RightReversing::reverse(){
+  //replace ___X.y___ by ___u.V___
+  NInd i=to_reverse.back();
+  to_reverse.pop_back();
+  Generator x=-word.nodes[i].data;
+  NInd j=word.nodes[i].next;
+  NInd p=word.nodes[i].previous;
+  Generator y=word.nodes[j].data;
+  NInd n=word.nodes[j].next;
+
+  //the word is __$.X.y.#__ with $=[p],X=[i],y=[j],#=[n]
+  size_t s=set_comp(x,y,comp);
+  //TODO :: Unroll loop
+  for(size_t ind=0;ind<s;++ind) word.insert_before(i,comp[ind]);
+  word.erase(i);
+  s=set_comp(y,x,comp);
+  for(size_t ind=0;ind<s;++ind) word.insert_after(j,-comp[ind]);
+  word.erase(j);
+  
+  //the word is now __$.u.V.#___ with $=[p] and #=[n]
+  if(s>0){
+ 
+    if(word.nodes[p].data<0){
+      if(word.nodes[word.nodes[p].next].data>0){
+	to_reverse.push_back(p);
+      }
+    }
+    if(word.nodes[n].data>0){
+      if(word.nodes[word.nodes[n].previous].data<0){
+	to_reverse.push_back(word.nodes[n].previous);
+      }
+    }
+  }
+  else{
+    if(word.nodes[p].data<0 and word.nodes[n].data>0){
+      to_reverse.push_back(p);
+    }
+  }
+}
+
+//-----------------------------------------
+// RightReversing::set_word(const Word& w)
+//-----------------------------------------
+
+void
+RightReversing::set_word(const Word& w){
+  clear();
+  Reversing::set_word(w);
+  if(w.is_empty()) return;
+  for(size_t i=0;i<w.size()-1;++i){
+    if(w.read(i)<0 and w.read(i+1)>0){
+      to_reverse.push_back(i+1); 
+    }
+  }
+}
+
+//----------------------------------------------------------
+// RightReversing::set_word(const Word& num,const Word& den)
+//----------------------------------------------------------
+
+void
+RightReversing::set_word(const Word& den,const Word& num){
+  clear();
+  size_t ds=den.size();
+  size_t ns=num.size();
+  Reversing::init_word(ds+ns);
+  for(int i=0;i<ds;++i){
+    word.nodes[i+1].data=-den[ds-i-1];
+  }
+  for(int i=0;i<ns;++i){
+    word.nodes[i+ds+1].data=num[i];
+  }
+  if(ns*ds!=0) to_reverse.push_back(ds);
+}
+
+
+//****************
+//* MonoidFamily *
+//****************
+
+MonoidFamily::~MonoidFamily(){
+}
+
+//***************
+//* MonoidTrait *
+//***************
+
+//-----------------------------
+// MonoidTrait::~MonoidTrait()
+//-----------------------------
+
+MonoidTrait::~MonoidTrait(){
+  if(left_reversing!=nullptr) delete left_reversing;
+  if(right_reversing!=nullptr) delete right_reversing;
+}
+
+//-----------------------------------------------------------
+// MonoidTrait::is_left_divisible_x(const Word&,const Word&)
+//-----------------------------------------------------------
+
+pair<bool,Word>
+MonoidTrait::is_left_divisible_x(const Word& a,const Word& b){
+  right_reversing->set_word(b,a);
+  if(right_reversing->check_positivity())
+    return pair<bool,Word>(true,right_numerator());
+  return pair<bool,Word>(false,Word());
+}
+
+//------------------------------------------------------------
+// MonoidTrait::is_right_divisible_x(const Word&,const Word&)
+//------------------------------------------------------------
+
+pair<bool,Word>
+MonoidTrait::is_right_divisible_x(const Word& a,const Word& b){
+  left_reversing->set_word(a,b);
+  if(left_reversing->check_positivity())
+    return pair<bool,Word>(true,left_numerator());
+  return pair<bool,Word>(false,Word());
+}
+
+//---------------------------------------------------
+// MonoidTrait::left_complement(Generator,Generator)
+//---------------------------------------------------
+
+Word
+MonoidTrait::left_complement(const Generator& x,const Generator& y){
+  Generator comp[MAX_COMPLEMENT_SIZE];
+  size_t l=left_reversing->set_comp(x,y,comp);
+  Word res(l);
+  for(size_t i=0;i<l;++i) res[i]=comp[i];
+  return res;
+}
+
+//------------------------------------------------
+// MonoidTrait::left_gcd(const Word&,const Word&)
+//------------------------------------------------
+
+Word
+MonoidTrait::left_gcd(const Word& a,const Word& b){
+  right_reverse(a,b);
+  left_reverse(right_reversing->get_word());
+  left_reverse(a,left_denominator());
+  return left_numerator();
+}
+
+//--------------------------------------------------
+// MonoidTrait::left_gcd_x(const Word&,const Word&)
+//--------------------------------------------------
+
+pair<Word,Word>
+MonoidTrait::left_gcd_x(const Word& a,const Word& b){
+  right_reverse(a,b);
+  left_reverse(right_reversing->get_word());
+  Word div=left_denominator();
+  left_reverse(a,div);
+  return pair<Word,Word>(left_numerator(),div);
+}
+
+//----------------------------------------------------
+// MonoidTrait::right_complement(Generator,Generator)
+//----------------------------------------------------
+
+Word
+MonoidTrait::right_complement(const Generator& x,const Generator& y){
+  Generator comp[MAX_COMPLEMENT_SIZE];
+  size_t l=right_reversing->set_comp(x,y,comp);
+  Word res(l);
+  for(size_t i=0;i<l;++i) res[i]=comp[i];
+  return res;
+}
+
+//------------------------------------------------
+// MonoidTrait::right_gcd(const Word&,const Word&)
+//------------------------------------------------
+
+Word
+MonoidTrait::right_gcd(const Word& a,const Word& b){
+  left_reverse(b,a);
+  right_reverse(left_reversing->get_word());
+  right_reverse(right_denominator(),a);
+  return right_numerator();
+}
+
+//---------------------------------------------------
+// MonoidTrait::right_gcd_x(const Word&,const Word&)
+//---------------------------------------------------
+
+pair<Word,Word>
+MonoidTrait::right_gcd_x(const Word& a,const Word& b){
+  left_reverse(b,a);
+  right_reverse(left_reversing->get_word());
+  Word div=right_denominator();
+  right_reverse(div,a);
+  return pair<Word,Word>(right_numerator(),div);
+}
+
+//********
+//* Word *
+//********
+
+//------------------------------------------------
+// Word::Word(const initializer_list<Generator>&)
+//------------------------------------------------
+
+Word::Word(const initializer_list<Generator>& l):Array(l.size()){
+  size_t i=0;
+  for(auto it=l.begin();it!=l.end();++it){
+    array[i++]=*it;
+  }
+}
+
+//-----------------
+// Word::inverse() 
+//-----------------
+
+Word
+Word::inverse() const{
+  Word res(s);
+  for(size_t i=0;i<s;++i){
+    res.array[i]=-array[s-i-1];
+  }
+  return res;
+}
+
+//-----------------------------------
+// Word::display(DisplayGenerator d)
+//-----------------------------------
+
+string
+Word::display(DisplayGenerator d) const{
+  if(s==0) return "e";
+  string str=d(array[0]);
+  for(size_t i=1;i<s;++i){
+    str+='.';
+    str+=d(array[i]);
+  }
+  return str;
+}
+
+//***********************
+//* Auxiliary functions *
+//***********************

+ 588 - 0
ext/garside/monoid.hpp

@@ -0,0 +1,588 @@
+/**
+ * This file is part of Gomu.
+ *
+ *  Copyright 2016 by Jean Fromentin <jean.fromentin@math.cnrs.fr>
+ *
+ * Gomu is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Gomu is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Gomu. If not, see <http://www.gnu.org/licenses/>. 
+ */
+
+#ifndef MONOID_HPP
+#define MONOID_HPP
+
+#include <cstdint>
+#include "../../array.hpp"
+#include "stacked_list.hpp"
+
+#define MAX_COMPLEMENT_SIZE 64
+
+//************
+//* Typedefs *
+//************
+
+//! Monoid generator
+typedef int16_t Generator;
+//! Complement function of a monoid
+typedef int(*SetComplement)(const Generator& x,const Generator& y,Generator* comp);
+//! Display function for monoid generator
+typedef string(*DisplayGenerator)(const Generator& x);
+//! Return the number of generators of the monoid of rank n among a monoid familly
+typedef size_t(*GeneratorsNumber)(size_t n);
+
+//***************************
+//* Early class definitions *
+//***************************
+
+class Reversing;
+class LeftReversing;
+class RightReversing;
+class PresentedMonoid;
+class Word;
+
+//********************* 
+//* Class definitions *
+//*********************
+
+//-----------
+// Reversing
+//-----------
+
+//! Common data and function between left and right reversing algorithms
+class Reversing{
+public:
+  //! Internal word
+  StackedList word;
+  //! Next detected position to reverse
+  deque<NInd> to_reverse;
+  //! Destination structure for complement
+  Generator comp[MAX_COMPLEMENT_SIZE];
+  //! Complement function
+  SetComplement set_comp;
+
+  //! Clear internal word
+  void clear();
+
+  //! Display internal word
+  void disp_word() const;
+
+  //! Return internal word
+  Word get_word() const;
+  
+  //! Init internal word to be of size s
+  void init_word(size_t s);
+  
+  //! Number of detected position to reverse. O implies the word is reversed
+  size_t remaining_size() const;
+
+  //! Set internal word
+  void set_word(const Word& w);
+};
+
+//----------------
+// Left reversing
+//----------------
+
+//! A class for left reversing algorithm
+class LeftReversing:public Reversing{  
+public:
+  //! Unique constructor
+  LeftReversing(SetComplement sc);
+  
+  //! Test if full reversing gives a positive word when internal word is u.v^(-1)
+  bool check_positivity();
+
+  //! Return numerator of the word
+  Word denominator();
+
+  //! Reverse untill the is no more reversing step
+  void full_reverse();
+  
+  //! Return numerator of the word
+  Word numerator();
+
+  //! Perform one reversing step
+  void reverse();
+
+  //! Set internal word to be w
+  void set_word(const Word& w);
+
+  //! Set internal word to be num.den^(-1)
+  void set_word(const Word& num,const Word& den);
+};
+
+//-----------------
+// Right reversing
+//-----------------
+
+//! A class for right reversing
+class RightReversing:public Reversing{  
+public:
+  //! Unique constructor
+  RightReversing(SetComplement sc);
+
+  //! Test if full reversing gives a positive word when internal word is u^(-1).v
+  bool check_positivity();
+  
+  //! Return numerator of the word
+  Word denominator();
+  
+  //! Reverse untill the is no more reversing ste
+  void full_reverse();
+
+  //! Return numerator of the word
+  Word numerator();
+
+  //! Perform one reversing 
+  void reverse();
+
+  //! Set internal word
+  void set_word(const Word& w);
+
+  //! Set internal word to be den^(-1).num
+  void set_word(const Word& den,const Word& num);
+};
+
+//-------------
+// MonoidTrait
+//-------------
+//! Class for procedure attached to monoid
+
+class MonoidTrait{
+public:
+  //! Pointer to a LeftReversing
+  LeftReversing* left_reversing;
+  //! Pointer to a RightReversing
+  RightReversing* right_reversing;
+
+  //! Extra data
+  void* data;
+  //! Empty constructor
+  MonoidTrait();
+
+  //! Destructor
+  ~MonoidTrait();
+
+  //! Test if the family is left complemented
+  bool is_left_complemented() const;
+
+  //! Test if a is left divisible by b, i.e.,if it exists c such that a=b.c */
+  bool is_left_divisible(const Word& a,const Word& b);
+
+  //! Return a Couple (f,c) such that f equals true if a is left divisible by b,
+  //! i.e.,if it exists c such that a=b.c 
+  pair <bool,Word> is_left_divisible_x(const Word& a,const Word& b);
+  
+  //! Test if the family is right complemented
+  bool is_right_complemented() const;
+
+  //! Test if a is right divisible by b, i.e.,if it exists c such that a=c.b
+  bool is_right_divisible(const Word& a,const Word& b);
+
+  //! Return a Couple (f,c) such that f equals true if a is right divisible by b,
+  //! i.e.,if it exists c such that a=c.b
+  pair<bool,Word> is_right_divisible_x(const Word& a,const Word& b);
+
+  //! Return left complement of x and y
+  Word left_complement(const Generator& x,const Generator& y);
+  
+  //! Return the left denominator
+  Word left_denominator();
+  
+  //! Return the left gcd of a and b, i.e., a maximal element c 
+  //! such that there exist x with a=c.x and y with b=c.y 
+  Word left_gcd(const Word& a,const Word& b);
+
+  //! Return a Couple (c,d) where c is the left gcd of a and d is such that a=c.d
+  pair<Word,Word> left_gcd_x(const Word& a,const Word& b);
+  
+  //! Return the left lcm of a and b, i.e., a minimal element c
+  //! such that there exist x with c=x.a and y with c=y.a
+  Word left_lcm(const Word& a,const Word& b);
+
+  //! Return the left lcm complement of a and b, i.e.,
+  //! an element d such that d.a is equal to the left lcm of a and b
+  Word left_lcm_complement(const Word& a,const Word& b);
+  
+  //! Return the left numerator
+  Word left_numerator();
+  
+  //! Left reverse the word w
+  Word left_reverse(const Word& w);
+
+  //! Left reverse the u.v^(-1)
+  Word left_reverse(const Word& u,const Word& v);
+
+  //! Return right complement of x and y
+  Word right_complement(const Generator& x,const Generator& y);
+  
+  //! Return the right denominator
+  Word right_denominator();
+  
+  //! Return the left gcd of a and b, i.e., a maximal element c
+  //! such that there exist x with a=c.x and y with b=c.y
+  Word right_gcd(const Word& a,const Word& b);
+
+  //!  Return a Couple (c,d) where c is the right gcd of a and d is such that a=d.c
+  pair<Word,Word> right_gcd_x(const Word& a,const Word& b);
+  
+  //! Return the right lcm of a and b, i.e., a minimal element c
+  //! such that there exist x with c=a.x and y with c=a.y 
+  Word right_lcm(const Word& a,const Word& b);
+  
+  //! Return the right lcm complement of a and b, i.e.,
+  //! an element d such that a.d is equal to the right lcm of a and b 
+  Word right_lcm_complement(const Word& a,const Word& b);
+
+  //! Return right numerator
+  Word right_numerator();
+  
+  //! Right reverse the word w
+  Word right_reverse(const Word& w);
+
+  //! Right reverse the u^(-1).v
+  Word right_reverse(const Word& u,const Word& v);
+  
+  //! Set left complement
+  void set_left_complement(SetComplement sc);
+
+  //! Set right complement
+  void set_right_complement(SetComplement sc);
+};
+
+//--------------
+// MonoidFamily
+//--------------
+//! A class for familly of monoid
+
+class MonoidFamily:public MonoidTrait{
+public:
+  //! Function to display generators
+  DisplayGenerator gdisp;
+  //! Function returning the number of generators for a given rank 
+  GeneratorsNumber gnum;
+  //! Label of the monoid family
+  string label;
+  
+  //! Unique constructor
+  MonoidFamily(string l,DisplayGenerator d,GeneratorsNumber n);
+
+  //! Destructor
+  ~MonoidFamily();
+
+  //! Display
+  string display() const;
+  
+  //! Return number of generators for rank n
+  size_t generators_number(size_t n);
+};
+
+//------
+// Word
+//------
+
+//! Class for word 
+class Word:public Array<Generator>{
+public:
+  //! Empty constructor
+  Word();
+
+  //! Construct a word from a list of Generator
+  Word(const initializer_list<Generator>& l);
+  
+  //! Recopy constructor
+  Word(const Word&);
+  
+  //! Move constructor
+  Word(Word&&);
+  
+  //! Construct a word from an array
+  Word(const Array<Generator>&);
+  Word(Array<Generator>&&);
+  
+  //! Concatenate a word to this one
+  Word concatenate(const Word& w) const;
+
+  //! Return the word inverse of this one
+  Word inverse() const;
+
+  //! Display a word
+  string display(DisplayGenerator d) const;
+};
+
+//***********************
+//* Auxiliary functions *
+//***********************
+
+//! Comparison function for Generator
+//! \param x a generator
+//! \param y a generator
+//! \return -1 if x<y, 0 if x==y and 1 if x>y
+int cmp(const Generator& x,const Generator& y);
+
+
+//! Display a generator with letter
+string disp_alpha(const Generator& x);
+
+//! Multiply word
+//! \param u a word
+//! \param w a word
+//! \return the word uv
+Word operator*(const Word& u,const Word& v);
+
+
+//***********************
+//* Inline declarations *
+//***********************
+
+//-----------
+// Reversing
+//-----------
+
+inline void
+Reversing::clear(){
+  to_reverse.clear();
+}
+
+inline void
+Reversing::disp_word() const{
+  cout<<word<<endl;
+}
+
+inline void
+Reversing::init_word(size_t s){
+  word.init(s);
+}
+
+inline size_t
+Reversing::remaining_size() const{
+  return to_reverse.size();
+}
+
+inline void
+Reversing::set_word(const Word& w){
+  word.init((NData*)w.array,w.size());
+}
+
+//----------------
+// Left reversing
+//----------------
+
+inline
+LeftReversing::LeftReversing(SetComplement sc){
+  set_comp=sc;
+}
+
+inline void
+LeftReversing::full_reverse(){
+  while(not to_reverse.empty())
+    reverse();
+}
+
+
+//-----------------
+// Right reversing
+//-----------------
+
+inline
+RightReversing::RightReversing(SetComplement sc){
+  set_comp=sc;
+}
+
+inline void
+RightReversing::full_reverse(){
+  while(not to_reverse.empty()) reverse();
+}
+
+//--------------
+// MonoidFamily
+//--------------
+
+inline
+MonoidFamily::MonoidFamily(string l,DisplayGenerator d,GeneratorsNumber n):label(l),gdisp(d),gnum(n){
+  left_reversing=nullptr;
+  right_reversing=nullptr;
+}
+
+
+inline string
+MonoidFamily::display() const{
+  return label+" monoid family";
+}
+
+inline size_t
+MonoidFamily::generators_number(size_t n){
+  return gnum(n);
+}
+
+//-------------
+// MonoidTrait
+//-------------
+
+inline
+MonoidTrait::MonoidTrait(){
+  left_reversing=nullptr;
+  right_reversing=nullptr;
+}
+
+inline bool
+MonoidTrait::is_left_complemented() const{
+  return left_reversing!=nullptr;
+}
+
+inline bool
+MonoidTrait::is_left_divisible(const Word& a,const Word& b){
+  right_reversing->set_word(b,a);
+  return right_reversing->check_positivity();
+}
+
+inline bool
+MonoidTrait::is_right_divisible(const Word& a,const Word& b){
+  left_reversing->set_word(a,b);
+  return left_reversing->check_positivity();
+}
+
+inline bool
+MonoidTrait::is_right_complemented() const{
+  return right_reversing!=nullptr;
+}
+
+inline Word
+MonoidTrait::left_denominator(){
+  return left_reversing->denominator();
+}
+
+inline Word
+MonoidTrait::left_lcm_complement(const Word& a,const Word& b){
+  left_reverse(b,a);
+  return left_numerator();
+}
+
+inline Word
+MonoidTrait::left_lcm(const Word& a,const Word& b){
+  return left_lcm_complement(a,b)*a;
+}
+
+inline Word
+MonoidTrait::left_numerator(){
+  return left_reversing->numerator();
+}
+
+inline Word
+MonoidTrait::left_reverse(const Word& w){
+  left_reversing->set_word(w);
+  left_reversing->full_reverse();
+  return left_reversing->get_word();
+}
+
+inline Word
+MonoidTrait::left_reverse(const Word& u,const Word& v){
+  left_reversing->set_word(u,v);
+  left_reversing->full_reverse();
+  return left_reversing->get_word();
+}
+
+inline Word
+MonoidTrait::right_denominator(){
+  return right_reversing->denominator();
+}
+
+inline Word
+MonoidTrait::right_lcm(const Word& a,const Word& b){
+  return a*right_lcm_complement(a,b);
+}
+
+inline Word
+MonoidTrait::right_lcm_complement(const Word& a,const Word& b){
+  right_reverse(a,b);
+  return right_numerator();
+}
+
+inline Word
+MonoidTrait::right_numerator(){
+  return right_reversing->numerator();
+}
+
+inline Word
+MonoidTrait::right_reverse(const Word& w){
+  right_reversing->set_word(w);
+  right_reversing->full_reverse();
+  return right_reversing->get_word();
+}
+
+inline Word
+MonoidTrait::right_reverse(const Word& u,const Word& v){
+  right_reversing->set_word(u,v);
+  right_reversing->full_reverse();
+  return right_reversing->get_word();
+}
+
+inline void
+MonoidTrait::set_left_complement(SetComplement sc){
+  left_reversing=new LeftReversing(sc);
+}
+
+inline void
+MonoidTrait::set_right_complement(SetComplement sc){
+  right_reversing=new RightReversing(sc);
+}
+
+
+//------
+// Word
+//------
+
+inline
+Word::Word(){}
+
+inline
+Word::Word(const Word& w):Array(w){}
+
+inline
+Word::Word(Word&& w):Array(w){}
+
+inline
+Word::Word(const Array<Generator>& a):Array(a){}
+
+inline
+Word::Word(Array<Generator>&& a):Array(a){}
+
+inline Word
+Word::concatenate(const Word& w) const{
+  return Word(append(w));
+}
+
+//***********************
+//* Auxiliary functions *
+//***********************
+
+inline int
+cmp(const Generator& x,const Generator& y){
+  if(x<y) return -1;
+  if(x==y) return 0;
+  return 1;
+}
+
+inline string
+disp_alpha(const Generator& x){
+  if(x==0) return "e";
+  string res="";
+  if(x>0) return res+char(x-1+'a');
+  return res+char(-x-1+'A');
+}
+
+inline Word
+operator*(const Word& u,const Word& v){
+  return u.append(v);
+}
+				    
+#endif

+ 142 - 0
ext/garside/stacked_list.cpp

@@ -0,0 +1,142 @@
+/**
+ * This file is part of Gomu.
+ *
+ *  Copyright 2016 by Jean Fromentin <jean.fromentin@math.cnrs.fr>
+ *
+ * Gomu is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Gomu is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Gomu. If not, see <http://www.gnu.org/licenses/>. 
+ */
+
+#include "stacked_list.hpp"
+
+//***************
+//* StackedList *
+//****************
+
+
+//--------------------------
+// StackedList::erase(NInd)
+//--------------------------
+
+void StackedList::erase(NInd i){
+  NInd p=nodes[i].previous;
+  NInd n=nodes[i].next;
+  nodes[p].next=n;
+  nodes[n].previous=p;
+  indices[size--]=i;
+}
+
+//----------------------------------
+// StackedList::fill(NData*,size_t)
+//----------------------------------
+
+void
+StackedList::fill(NData* array,size_t s){
+  size=s;
+  nodes[0].data=0;
+  nodes[0].previous=s;
+  nodes[0].next=1;
+  for(size_t ind=0;ind<s;++ind){
+    nodes[ind+1].previous=ind;
+    nodes[ind+1].next=ind+2;
+    nodes[ind+1].data=array[ind];
+  }
+  nodes[s].next=0;
+}
+
+//---------------------------
+// StackedList::init(size_t)
+//--------------------------
+
+void
+StackedList::init(size_t s){
+  clear();
+  size=s;
+  nodes[0].previous=s;
+  nodes[0].next=1;
+  for(size_t ind=0;ind<s;++ind){
+    nodes[ind+1].previous=ind;
+    nodes[ind+1].next=ind+2;
+  }
+  nodes[s].next=0;
+}
+
+
+//----------------------------------------
+// StackedtList::insert_after(NInd,NData)
+//----------------------------------------
+
+NInd
+StackedList::insert_after(NInd i,NData data){
+  // p <-> i <-> n becomes p <-> i <-> j <-> n
+  NInd j=new_node();
+  NInd n=nodes[i].next;
+  nodes[j].previous=i;
+  nodes[j].next=n;
+  nodes[j].data=data;
+  nodes[i].next=j;
+  nodes[n].previous=j;
+  return j;
+}
+
+//----------------------------------------
+// StackedList::insert_before(NInd,Ndata)
+//----------------------------------------
+
+NInd
+StackedList::insert_before(NInd i,NData data){
+  //p <-> i <-> n becomes p <-> j <-> i <-> n
+  NInd j=new_node();
+  NInd p=nodes[i].previous;
+  nodes[j].previous=p;
+  nodes[j].next=i;
+  nodes[j].data=data;
+  nodes[i].previous=j;
+  nodes[p].next=j;
+  return j;
+}
+
+void
+StackedList::full_show() const{
+  NInd ind=0;
+  size_t i=0;
+  while(i<10){
+    cout<<"@"<<ind<<" : "<<nodes[ind].previous<<"<- "<<nodes[ind].data<<" -> "<<nodes[ind].next<<endl;
+    ind=nodes[ind].next;
+    if(ind==0) return;
+    ++i;
+  }
+  cout<<"@"<<ind<<" : "<<nodes[ind].previous<<"<- "<<nodes[ind].data<<" -> "<<nodes[ind].next<<endl;
+}
+
+//***********************
+//* Auxiliary Functions *
+//***********************
+
+ostream& operator<<(ostream& os,const StackedList& list){
+  os<<" Stack =";
+  for(size_t i=0;i<=list.size;++i) os<<' '<<list.indices[i];
+  os<<'#';
+  for(size_t i=list.size+1;i<=20;++i) os<<' '<<list.indices[i];
+  os<<endl;
+  if(list.is_empty()) return os<<"()";
+  NInd ind=list.nodes[0].next;
+  os<<'('<<list.nodes[ind].data;
+  size_t i=0;
+  while((ind=list.nodes[ind].next)!=0){
+    os<<','<<list.nodes[ind].data;
+    ++i;
+    if(i>10) return os<<"...)";
+  }
+  return os<<')';
+};

+ 182 - 0
ext/garside/stacked_list.hpp

@@ -0,0 +1,182 @@
+/**
+ * This file is part of Gomu.
+ *
+ *  Copyright 2016 by Jean Fromentin <jean.fromentin@math.cnrs.fr>
+ *
+ * Gomu is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Gomu is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Gomu. If not, see <http://www.gnu.org/licenses/>. 
+ */
+
+#ifndef STACKED_LIST_HPP
+#define STACKED_LIST_HPP
+
+#include <iostream>
+#include <cstdint>
+#include <deque>
+#include <stack>
+#include <cassert>
+
+using namespace std;
+
+#define SIZE 1024
+
+typedef uint16_t NInd;
+typedef int16_t NData;
+
+
+//**********************
+//* Class declarations *
+//**********************
+
+//! Node of a StackedList
+class StackedListNode{
+public:
+  StackedListNode();
+  NInd previous,next;
+  NData data;
+};
+
+//! A Both directionnal list structure based on stacks
+class StackedList{
+public:
+
+private:
+  //! Fill the current StackedList with ann arry of size s
+  void fill(NData* array,size_t s);
+
+  //Create a new node for the Stacked lisy
+  //\return index of the new created node
+  NInd new_node();
+
+public:
+  //! Size of the stacked list 0 for empty
+  //! Attention, there is exactly size+1 nodes used in the list
+  size_t size;
+  
+  //! An array of Node used or not in the list
+  StackedListNode nodes[SIZE];
+
+  //! Indices of all available nodes
+  NInd indices[SIZE];
+
+  //! The empty constructor
+  StackedList();
+
+  //! Construct a StackedList from an array of size s
+  StackedList(NData* array,size_t s);
+
+  //! Clear the current StackedList
+  void clear();
+  
+  //! Erase the node i in the list
+  void erase(NInd i);
+
+  //! Return first data of the list
+  NData first();
+  
+  //! Show all information of the nodes
+  void full_show() const;
+
+  //! Init the current StackedList to be of size s
+  void init(size_t s);
+  
+  //! Init the current StackedList with an array of size s
+  void init(NData* array,size_t s);
+
+  //! Insert a new node with data before the node i
+  //! \return index of the newly inserted node
+  NInd insert_before(NInd i,NData data);
+
+  //! Insert a new node with data aftre the node i
+  //! \return index of the newly inserted node
+  NInd insert_after(NInd i,NData data);
+
+  //! Test if the StackedList is empty
+  bool is_empty() const;
+
+  //! Return last data of the list
+  NData last();
+};
+
+
+//***********************
+//* Auxiliary Functions *
+//***********************
+
+ostream& operator<<(ostream& os,const StackedList&);
+
+//**********************
+//* Inline definitions *
+//**********************
+
+//-------------------
+// StackedList::Node
+//-------------------
+
+inline
+StackedListNode::StackedListNode(){}
+
+//-------------
+// StackedList
+//-------------
+
+inline
+StackedList::StackedList(){
+  clear();
+  nodes[0].data=0;
+  nodes[0].previous=0;
+  nodes[0].next=0;
+}
+
+inline
+StackedList::StackedList(NData* array,size_t s){
+  clear();
+  fill(array,s);
+}
+
+inline void
+StackedList::clear(){
+  size=0;
+  for(size_t i=0;i<SIZE;++i) indices[i]=i;
+  nodes[0].previous=0;
+  nodes[0].next=0;
+}
+
+inline void
+StackedList::init(NData* array,size_t s){
+  clear();
+  fill(array,s);
+}
+
+inline bool
+StackedList::is_empty() const{
+  return size==0;
+}
+
+inline NData
+StackedList::first(){
+  return nodes[nodes[0].next].data;
+}
+
+inline NData
+StackedList::last(){
+  return nodes[nodes[0].previous].data;
+}
+
+inline NInd
+StackedList::new_node(){
+  return indices[++size];
+}
+
+
+#endif

+ 22 - 0
ext/garside/temp

@@ -0,0 +1,22 @@
+//Artin Monoid of type A
+    {"Boolean","is_left_divisible",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_is_left_divisible},
+    {"Tuple","is_left_divisible_x",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_is_left_divisible_x},
+    {"Boolean","is_right_divisible",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_is_right_divisible},
+    {"Tuple","is_right_divisible_x",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_is_right_divisible_x},
+    {"DualWordA","left_denominator",{"DualMonoidFamilyA"},(void*)mt_left_denominator},
+    {"DualWordA","left_lcm",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_left_lcm},
+    {"DualWordA","left_lcm_complement",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_left_lcm_complement},
+    {"DualWordA","left_gcd",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_left_gcd},
+    {"Tuple","left_gcd_x",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_left_gcd_x},
+    {"DualWordA","left_numerator",{"DualMonoidFamilyA"},(void*)mt_left_numerator},
+    {"DualWordA","left_reverse",{"DualMonoidFamilyA","DualWordA"},(void*)mt_left_reverse},
+    {"DualWordA","left_reverse",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_left_reverse2},
+    {"DualWordA","right_denominator",{"DualMonoidFamilyA"},(void*)mt_right_denominator},
+    {"DualWordA","right_lcm",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_right_lcm},
+    {"DualWordA","right_lcm_complement",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_right_lcm_complement},
+    {"DualWordA","right_gcd",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_right_gcd},
+    {"Tuple","right_gcd_x",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_right_gcd_x},
+    {"DualWordA","right_numerator",{"DualMonoidFamilyA"},(void*)mt_right_numerator},
+    {"DualWordA","right_reverse",{"DualMonoidFamilyA","DualWordA"},(void*)mt_right_reverse},
+    {"DualWordA","right_reverse",{"DualMonoidFamilyA","DualWordA","DualWordA"},(void*)mt_right_reverse2},
+    

+ 172 - 47
interpreter.cpp

@@ -132,7 +132,7 @@ namespace Gomu{
   Context::add_symbol(string name,Type* type,void* ptr,bool lock){
     Symbol& s=symbols[name];
     if(s.locked) ContextError("A locked symbol named "+name+" already exist");
-    s.del();s.type=type;
+    s.pdel();s.type=type;
     s.ptr=ptr;s.locked=lock;
     s.name=name;
     s.hide=false;
@@ -151,9 +151,9 @@ namespace Gomu{
     return symbol->type==type_meta_function or symbol->type==type_function;
   }
 
-  //-----------------------------------------------
+  //------------------------------------------------------
   // Context::can_add_member_function(string,string_list)
-  //-----------------------------------------------
+  //------------------------------------------------------
   
   bool
   Context::can_add_member_function(string name,string_list targs){
@@ -161,7 +161,7 @@ namespace Gomu{
     string cname=*(targs.begin());
     Type* ctype=get_type(cname);
     if(ctype==nullptr) ContextError("The class type "+cname+" does not exist");
-    return can_add(cname+"."+name);
+    return can_add_function(cname+"."+name,targs);
   }
 
  
@@ -220,7 +220,7 @@ namespace Gomu{
     if(nargs!=func->signature.size())
       ContextError("The number of arguments is incorect ("+to_string(nargs)+" instead of "+to_string(func->signature.size())+").");
     for(size_t i=0;i<nargs;++i){
-      if(args[i]->type==type_symbol and signature[i]!=type_symbol){
+      if(args[i]->type==type_symbol and signature[i]!=type_symbol and signature[i]!=type_generic){
 	args[i]=(Value*)args[i]->ptr;
       }
       if(signature[i]!=type_generic and signature[i]!=args[i]->type)
@@ -279,6 +279,11 @@ namespace Gomu{
       return eval_function((Function*)symbol->ptr,args,nargs);
     }
     else if(symbol->type==type_meta_function){
+      for(size_t i=0;i<nargs;++i){
+	if(args[i]->type==type_symbol){
+	  args[i]=(Value*)(args[i]->ptr);
+	}
+      }
       string fullname=function_fullname(symbol->name,args,nargs);
       Value *val=get_symbol(fullname);
       if(val==nullptr) ContextError("There is no function "+fullname);
@@ -296,28 +301,50 @@ namespace Gomu{
   
   void
   Context::eval_member_function(Node& current,Node* nodes){
+    string name=current.str;
     Value* args[max_arguments_number];
     size_t nargs=set_arguments(current,nodes,args);
     Value* first=args[0]->eval();
     Type* type=first->type;
-    Value* val=get_symbol(type,current.str);
-    if(val==nullptr){
+    Symbol* symbol=get_symbol(type,name);
+    if(symbol==nullptr){
       if(type==type_type){
 	type=(Type*)first->ptr;
-	val=get_symbol(type,current.str);
+	symbol=get_symbol(type,name);
 	//current.son=nodes[current.son].bro;
-	if(val==nullptr)
-	  ContextError("No member function "+current.str+" for tyipe "+type->name);
-	current.value=eval_function((Function*)val->ptr,&args[1],nargs-1);
+	if(symbol==nullptr)
+	  ContextError("No member function "+name+" for tyipe "+type->name);
+	current.value=eval_function(symbol,&args[1],nargs-1);
 	return;
       }
       else{
-	ContextError("No member function "+current.str+" for type "+type->name);
+	ContextError("No member function "+name+" for type "+type->name);
       }
     }
-    if(val->type!=type_function)
-      ContextError("The symbol named "+current.str+" is not callable");
-    current.value=eval_function((Function*)val->ptr,args,nargs);
+    current.value=eval_function(symbol,args,nargs);
+  }
+
+  //--------------------------------------------------------
+  // Context::eval_member_symbol(Node& current,Node* nodes)
+  //--------------------------------------------------------
+
+  void
+  Context::eval_member_symbol(Node& current,Node* nodes){
+    string name=current.str;
+    Node& cnode=nodes[current.son];
+    Symbol* symbol=get_symbol(cnode.str);
+    if(symbol==nullptr) ContextError("Class type unkown");
+    Type* type=symbol->type;
+    if(type==type_type){
+      name=cnode.str+"."+name;
+    }
+    else{
+      name=type->name+"."+name;
+    }
+    symbol=get_symbol(name);
+    if(symbol==nullptr) ContextError("Symbol "+name+" does not exist");
+    current.value.type=type_symbol;
+    current.value.ptr=symbol;
   }
 
   //---------------------------------------
@@ -448,10 +475,11 @@ namespace Gomu{
     module->handle=handle;
     module->name=name;
     //Loading types
-    Type* types=(Type*)dlsym(handle,"types");
+    Module::Type* types=(Module::Type*)dlsym(handle,"types");
     module->functions=(Module::Function*)dlsym(handle,"functions");
     module->member_functions=(Module::Function*)dlsym(handle,"member_functions");
     module->contextual_functions=(Module::Function*)dlsym(handle,"contextual_functions");
+    module->symbols=(Module::Symbol*)dlsym(handle,"symbols");
     module->init(types);
     //Test if we can load all types
     for(size_t i=0;i<module->ntype;++i){
@@ -464,12 +492,18 @@ namespace Gomu{
     module->types=new string[module->ntype];
     for(size_t i=0;i<module->ntype;++i){
       Type* type=new Type(types[i]);
+      *(types[i].ptr)=type;
       module->types[i]=type->name;
       add_symbol(type->name,type_type,type);
     }
+    //Call init
+    void (*init)()=(void(*)())dlsym(handle,"init");
+    if(init!=nullptr) (*init)();
+    //Load functions and symbols
     load_module_functions(module,0);
     load_module_functions(module,1);
     load_module_functions(module,2);
+    load_module_symbols(module);
   }
 
   //---------------------------------------------
@@ -525,6 +559,26 @@ namespace Gomu{
     }
   }
 
+  //---------------------------------------
+  // Context::load_module_symbols(Module*)
+  //---------------------------------------
+  void
+  Context::load_module_symbols(Module* module){
+    for(size_t i=0;i<module->nsymb;++i){
+      Module::Symbol& symbol=module->symbols[i];
+      Type* type=get_type(symbol.type);
+      if(type==nullptr)
+	cout<<"Type "<<symbol.type<<" does not exist"<<endl;
+      if(can_add(symbol.name) and type!=nullptr){
+	add_symbol(symbol.name,type,symbol.ptr);
+	symbol.loaded=true;
+      }
+      else{
+	symbol.loaded=false;
+      }
+    }
+  }
+  
   //----------------------------------------------
   // Context::unload_function(string,string_list)
   //----------------------------------------------
@@ -556,6 +610,12 @@ namespace Gomu{
     for(size_t i=0;i<module->ntype;++i){
       unload_type(get_type(module->types[i]));
     }
+    //Unload module symbols
+    for(size_t i=0;i<module->nsymb;++i){
+      Module::Symbol& symbol=module->symbols[i];
+      if(symbol.loaded) unload_symbol(symbol.name);
+    }
+    //Unload module itself
     dlclose(module->handle);
     unload_symbol(module->name);
   }
@@ -602,12 +662,16 @@ namespace Gomu{
   Context::reload_module(Module* module){
     //** Unload some module member
     unload_module_functions(module); //unload functions
+    //Unload module symbols
+    for(size_t i=0;i<module->nsymb;++i){
+      Module::Symbol& symbol=module->symbols[i];
+      if(symbol.loaded) unload_symbol(symbol.name);
+    }
     if(module->handle!=nullptr){
       dlclose(module->handle); //close previous module handle
       module->handle=nullptr;
     }
     //we postpone the unload of module->types
-    
     //** Load the new version of the library
     string filename="ext/"+module->name+".so";
     void* handle=dlopen(filename.c_str(),RTLD_NOW);
@@ -616,11 +680,11 @@ namespace Gomu{
       RuntimeError("In loading module "+module->name+" : "+dlerror());
     }
     Module nmod; //A temporary module for the newly loaded data
-    
-    Type* types=(Type*)dlsym(handle,"types"); 
+    Module::Type* types=(Module::Type*)dlsym(handle,"types"); 
     nmod.functions=(Module::Function*)dlsym(handle,"functions");
     nmod.member_functions=(Module::Function*)dlsym(handle,"member_functions");
     nmod.contextual_functions=(Module::Function*)dlsym(handle,"contextual_functions");
+    nmod.symbols=(Module::Symbol*)dlsym(handle,"symbols");
     nmod.init(types);//init the module, ie, compute size of arrays
     
     //Test if we can load the new types
@@ -665,14 +729,16 @@ namespace Gomu{
     delete[] module->types; //unload types array
     module->types=new string[nmod.ntype];
     for(size_t i=0;i<nmod.ntype;++i){
-      Type& nmod_type=types[i];
+      Module::Type& nmod_type=types[i];
       module->types[i]=nmod_type.name;
       if(link[i]==-1){
 	Type *type=new Type(nmod_type);
+	*nmod_type.ptr=type;
 	add_symbol(type->name,type_type,type);
       }
       else{
 	Type* type=get_type(nmod_type.name);
+	*nmod_type.ptr=type;
 	type->disp=nmod_type.disp;
 	type->del=nmod_type.del;
 	type->copy=nmod_type.copy;
@@ -686,10 +752,16 @@ namespace Gomu{
     module->nmfunc=nmod.nmfunc;
     module->contextual_functions=nmod.contextual_functions;
     module->ncfunc=nmod.ncfunc;
+    module->symbols=nmod.symbols;
+    module->nsymb=nmod.nsymb;
     module->handle=handle;
+    //Call init
+    void (*init)()=(void(*)())dlsym(handle,"init");
+    if(init!=nullptr) (*init)();
     load_module_functions(module,0);
     load_module_functions(module,1);
     load_module_functions(module,2);
+    load_module_symbols(module);
   }
 
   //---------------------------------------------
@@ -723,6 +795,18 @@ namespace Gomu{
       return (*((CFunc1)ptr))(context,*args[0]);
     case 2:
       return (*((CFunc2)ptr))(context,*args[0],*args[1]);
+    case 3:
+      return (*((CFunc3)ptr))(context,*args[0],*args[1],*args[2]);
+    case 4:
+      return (*((CFunc4)ptr))(context,*args[0],*args[1],*args[2],*args[3]);
+    case 5:
+      return (*((CFunc5)ptr))(context,*args[0],*args[1],*args[2],*args[3],*args[4]);
+    case 6:
+      return (*((CFunc6)ptr))(context,*args[0],*args[1],*args[2],*args[3],*args[4],*args[5]);
+    case 7:
+      return (*((CFunc7)ptr))(context,*args[0],*args[1],*args[2],*args[3],*args[4],*args[5],*args[6]);
+    case 8:
+      return (*((CFunc8)ptr))(context,*args[0],*args[1],*args[2],*args[3],*args[4],*args[5],*args[6],*args[7]);
     default:
       Bug("Not yet implemented");
       break;
@@ -741,9 +825,33 @@ namespace Gomu{
     Value res;
     res.type=tr;
     switch(nargs){
+    case 0:
+      res.ptr=(*((Func0)ptr))();
+      break;
     case 1:
       res.ptr=(*((Func1)ptr))(args[0]->eval()->ptr);
       break;
+    case 2:
+      res.ptr=(*((Func2)ptr))(args[0]->eval()->ptr,args[1]->eval()->ptr);
+      break;
+    case 3:
+      res.ptr=(*((Func3)ptr))(args[0]->eval()->ptr,args[1]->eval()->ptr,args[2]->eval()->ptr);
+      break;
+    case 4:
+      res.ptr=(*((Func4)ptr))(args[0]->eval()->ptr,args[1]->eval()->ptr,args[2]->eval()->ptr,args[3]->eval()->ptr);
+      break;
+    case 5:
+      res.ptr=(*((Func5)ptr))(args[0]->eval()->ptr,args[1]->eval()->ptr,args[2]->eval()->ptr,args[3]->eval()->ptr,args[4]->eval()->ptr);
+      break;
+    case 6:
+      res.ptr=(*((Func6)ptr))(args[0]->eval()->ptr,args[1]->eval()->ptr,args[2]->eval()->ptr,args[3]->eval()->ptr,args[4]->eval()->ptr,args[5]->eval()->ptr);
+      break;
+    case 7:
+      res.ptr=(*((Func7)ptr))(args[0]->eval()->ptr,args[1]->eval()->ptr,args[2]->eval()->ptr,args[3]->eval()->ptr,args[4]->eval()->ptr,args[5]->eval()->ptr,args[6]->eval()->ptr);
+      break;
+    case 8:
+      res.ptr=(*((Func8)ptr))(args[0]->eval()->ptr,args[1]->eval()->ptr,args[2]->eval()->ptr,args[3]->eval()->ptr,args[4]->eval()->ptr,args[5]->eval()->ptr,args[6]->eval()->ptr,args[7]->eval()->ptr);
+      break;
     default:
       Bug("Not yet implemented");
     }
@@ -926,7 +1034,7 @@ namespace Gomu{
 	++first;
 	if(first>last or nodes[first].tokenType!=tName){
 	  if(nodes[first-1].tokenType==tDot) SyntaxError("Name missing after dot",nodes[first-1].pos,nodes[first-1].pos);
-	  SyntaxError("Name missing after ::",nodes[first-1].pos,nodes[first-1].pos+1);
+	  SyntaxError("Name missing after .",nodes[first-1].pos,nodes[first-1].pos+1);
 	}
 	string name=nodes[first].str;
 	++first;
@@ -943,7 +1051,7 @@ namespace Gomu{
 	else{
 	  Node& nnode=nodes[first-1];
 	  nnode.son=root;
-	  nnode.expressionType=expMemberFunction;
+	  nnode.expressionType=expMemberSymbol;
 	  nnode.str=name;
 	  node.expressionType=expLeaf;
 	  root=first-1;
@@ -1113,39 +1221,48 @@ namespace Gomu{
     }
   }
 
-  //---------------------------
-  // Interpreter::eval(string)
-  //---------------------------
+  //----------------------------------------
+  // Interpreter::eval(string,Context,bool)
+  //----------------------------------------
   
-  void Interpreter::eval(string cmd,Context& context,bool display){
-    size_t root;
-    Node* node;
+  void Interpreter::eval(string cmd,Context& context){
     bool error=false;
+    Value* res;
     try{
-      split_to_tokens(cmd);
-      size_t first=0;
-      root=construct_tree(first,nodes_number-1,max_precedence_level);
-      eval_expression(root,context);
-      node=&nodes[root];
-      Value* value=node->value.eval();
-      if(value->type!=nullptr and value->type!=type_void and display){
+      res=eval_basic(cmd,context);
+      Value* value=res->eval();
+      if(value->type!=nullptr and value->type!=type_void){
 	cout<<value->disp()<<endl;
-      }
+      }     
     }
     catch(Error err){
       err.disp(cout,cmd);
       cout<<endl;
       error=true;
+      purge_tree();
     }
     //Delete the return value
     if(not error){
-      if(node->erase){
-      node->value.del();
-      node->erase=false;
-      }
+      res->pdel();
     }
   }
 
+  //------------------------------------------------------
+  // Interpreter::eval_basic(string cmd,Context& context)
+  //------------------------------------------------------
+
+  Value* Interpreter::eval_basic(string cmd,Context& context){
+    size_t root;
+    Node* node;
+    bool error=false;
+    split_to_tokens(cmd);
+    size_t first=0;
+    root=construct_tree(first,nodes_number-1,max_precedence_level);
+    eval_expression(root,context);
+    node=&nodes[root];
+    return &node->value;
+  }
+  
   //-----------------------------------------------
   // Interpreter::eval_expression(size_t,Context&)
   //-----------------------------------------------
@@ -1180,6 +1297,9 @@ namespace Gomu{
     case expMemberFunction:
       context.eval_member_function(node,nodes);
       break;
+    case expMemberSymbol:
+      context.eval_member_symbol(node,nodes);
+      break;
     case expArray:
       context.eval_array(size,node,nodes);
       break;
@@ -1197,10 +1317,7 @@ namespace Gomu{
     }
     j=node.son;
     while(j!=-1){
-      if(nodes[j].erase){
-	nodes[j].value.del();
-	nodes[j].erase=false;
-      }
+      nodes[j].value.pdel();
       j=nodes[j].bro;
     }
   }
@@ -1260,6 +1377,17 @@ namespace Gomu{
     return str;
   }
 
+  //---------------------------
+  // Interpreter::purge_tree()
+  //---------------------------
+
+  void
+  Interpreter::purge_tree(){
+    for(size_t i=0;i<nodes_number;++i){
+      nodes[i].value.pdel();
+    }
+  }
+
   //-----------------------------------------------------
   // Interpreter::set_token(Node&,size_t&,const string&)
   //-----------------------------------------------------
@@ -1267,7 +1395,6 @@ namespace Gomu{
   void
   Interpreter::set_token(Node& node,size_t& pos,const string& cmd){
     node.value.type=nullptr;
-    node.erase=false;
     size_t oldPos;
     node.pos=pos;
     node.son=-1;
@@ -1283,7 +1410,6 @@ namespace Gomu{
       oldPos=pos;
       node.value.type=type_integer;
       node.value.ptr=(void*)(get_integer(pos,cmd));
-      node.erase=true;
       node.str=cmd.substr(oldPos,pos-oldPos+1);
       return;
     }
@@ -1294,7 +1420,6 @@ namespace Gomu{
       string* pstr=new string;
       *pstr=node.str;
       node.value.ptr=(void*)pstr;
-      node.erase=true;
       return;
     }
     if(('a'<=l and l<='z') or ('A'<=l and l<='Z') or l=='_'){

+ 41 - 8
interpreter.hpp

@@ -64,9 +64,24 @@ namespace Gomu{
   typedef Value (*CFunc0)(Context&);
   typedef Value (*CFunc1)(Context&,Value&);
   typedef Value (*CFunc2)(Context&,Value&,Value&);
-
+  typedef Value (*CFunc3)(Context&,Value&,Value&,Value&);
+  typedef Value (*CFunc4)(Context&,Value&,Value&,Value&,Value&);
+  typedef Value (*CFunc5)(Context&,Value&,Value&,Value&,Value&,Value&);
+  typedef Value (*CFunc6)(Context&,Value&,Value&,Value&,Value&,Value&,Value&);
+  typedef Value (*CFunc7)(Context&,Value&,Value&,Value&,Value&,Value&,Value&,Value&);
+  typedef Value (*CFunc8)(Context&,Value&,Value&,Value&,Value&,Value&,Value&,Value&,Value&);
+  
+  typedef void* (*Func0)();
   typedef void* (*Func1)(void*);
-
+  typedef void* (*Func2)(void*,void*);
+  typedef void* (*Func3)(void*,void*,void*);
+  typedef void* (*Func4)(void*,void*,void*,void*);
+  typedef void* (*Func5)(void*,void*,void*,void*,void*);
+  typedef void* (*Func6)(void*,void*,void*,void*,void*,void*);
+  typedef void* (*Func7)(void*,void*,void*,void*,void*,void*,void*);
+  typedef void* (*Func8)(void*,void*,void*,void*,void*,void*,void*,void*);
+  
+  
   typedef const initializer_list<string>& string_list;
   
 
@@ -88,6 +103,7 @@ namespace Gomu{
     expArraySet,
     expFunction,
     expMemberFunction,
+    expMemberSymbol,
     expLeaf,
     expTuple,
     expSet
@@ -242,9 +258,13 @@ namespace Gomu{
     //! Evaluate a member function node (contextual or not)
     //! \param current the node of the function to evaluate
     //! \param nodes array of all nodes
-    //! \param size size of the array
-    void eval_member_function(Node& current,Node* nodes);
-        
+     void eval_member_function(Node& current,Node* nodes);
+
+    //! Evaluate a member symbol
+    //! \param current the node of the symbol to evaluate
+    //! \param nodes array of all nodes
+    void eval_member_symbol(Node& current,Node* nodes);
+    
     //! Evaluate a set node
     //! \param size size of the set
     //! \param current the node of the set
@@ -287,6 +307,10 @@ namespace Gomu{
     //! \param src specify the src to load 0:functions 1:member_functions 2:contextual_functions 
     void load_module_functions(Module* module,int src);
 
+    //! Load symbols of a module
+    //! \param the module to load
+    void load_module_symbols(Module* module);
+    
     //! Unload a function
     //! \param name the name of the function to delete
     //! \param args the string list of the function arguments
@@ -404,7 +428,7 @@ namespace Gomu{
     //! Index of the node brother
     slong bro;
     //! Specify if the node can be erased or not
-    bool erase;
+    //bool erase;
   };
   
   //-------------
@@ -477,8 +501,13 @@ namespace Gomu{
     //! Evaluate a command
     //! \param cmd command to evaluate
     //! \param context context of the evaluation
-    //! \param display specify if we display the last valus
-    void eval(string cmd,Context& context,bool display=true);
+    //! \param display specify if we display the last value
+    void eval(string cmd,Context& context);
+
+    //! Evaluate a command in very basic way
+    //! \param cmd the check command
+    //! \param context context of the evaluation
+    Value* eval_basic(string cmd,Context& context);
 
     //! Evaluate an expression
     //! \param pos indice of the expression to evaluate
@@ -508,6 +537,9 @@ namespace Gomu{
     //! \param cmd command
     //! \return string
     string get_string(size_t& pos,const string& cmd);
+
+    //! Purge the expression tree
+    void purge_tree();
     
     //! Set node to be the token of command at position pos
     //! \param node destination node of the token
@@ -579,6 +611,7 @@ namespace Gomu{
   //! Get the fullname of a function
   //! \param name short name of the function
   //! \param args string array of argument type
+  //! \param member speicy if the fucntion is a member function or not
   //! \return fullname of the function
   string function_fullname(string name,string_list args);
 

+ 6 - 4
kernel.cpp

@@ -45,9 +45,11 @@ namespace Gomu{
   void
   array_del(void* v){
     ArrayValue* arr=(ArrayValue*)v;
-   Type* type=arr->type;
+    Value val;
+    val.type=arr->type;
     for(size_t i=0;i<arr->size;++i){
-      type->del(arr->tab[i]);
+      val.ptr=arr->tab[i];
+      val.pdel();
     }
     delete[] arr->tab;
     delete arr;
@@ -97,7 +99,7 @@ namespace Gomu{
     if((*(char*)v)==1)
       return "\033[35mtrue\033[0m";
     else
-      return "\033[35mtrue\033[0m";
+      return "\033[35mfalse\033[0m";
    }
 
   int
@@ -263,7 +265,7 @@ namespace Gomu{
   tuple_del(void* v){
     TupleValue* t=(TupleValue*)v;
     for(size_t i=0;i<t->size;++i){
-      t->tab[i].del();
+      t->tab[i].pdel();
     }
   }
   

+ 35 - 2
module.cpp

@@ -108,6 +108,12 @@ namespace Gomu{
     else{
       while(contextual_functions[i].ptr!=nullptr) ++i;
       ncfunc=i;
+      i=0;
+    }
+    if(symbols==nullptr) nsymb=0;
+    else{
+      while(symbols[i].ptr!=nullptr) ++i;
+      nsymb=i;
     }
   }
   //********
@@ -138,7 +144,18 @@ namespace Gomu{
     comp=t.comp;
   }
 
-
+  //---------------------------------
+  // Type::Type(const Module::Type&)
+  //---------------------------------
+  
+  Type::Type(const Module::Type& t){
+    name=t.name;
+    disp=t.disp;
+    del=t.del;
+    copy=t.copy;
+    comp=t.comp;
+  }
+  
   //**************
   //* TupleValue *
   //**************
@@ -184,7 +201,7 @@ namespace Gomu{
   // get_slong(void*)
   //------------------
   
-  uint64
+  int64
   get_slong(void* v){
     fmpz* z=(fmpz*)v;
     if(fmpz_fits_si(z)) return fmpz_get_si(z);
@@ -214,4 +231,20 @@ namespace Gomu{
     return z;
   }
 
+  //----------------
+  // no_copy(void*)
+  //----------------
+  
+  void*
+  no_copy(void*){
+    ContextError("Copy is undefined for this type");
+  }
+
+  //----------------------
+  // no_comp(void*,void*)
+  //----------------------
+  int
+  no_comp(void*,void*){
+    ContextError("Comparison is undefined for this type");
+  }
 }

+ 85 - 13
module.hpp

@@ -43,9 +43,9 @@ typedef int64_t int64;
 #define FUNC(f) (void*)(f)
 #define CONT_FUNC_SENTINEL {"",{""},nullptr}
 #define FUNC_SENTINEL {"","",{""},nullptr}
+#define SYMB_SENTINEL {"","",nullptr}
 #define TYPE_SENTINEL {"",nullptr,nullptr,nullptr,nullptr}
 
-
 #define SyntaxError(msg,first,last) throw Error(errSyntax,(msg),(first),(last),__FILE__,__LINE__,__PRETTY_FUNCTION__);
 #define Bug(msg) throw Gomu::Error(Gomu::errBug,(msg),0,0,__FILE__,__LINE__,__PRETTY_FUNCTION__);
 #define ContextError(msg) throw Error(errContext,(msg),0,0,__FILE__,__LINE__,__PRETTY_FUNCTION__);
@@ -119,7 +119,6 @@ namespace Gomu{
   //! Class for array of value of same type
   class  ArrayValue{
   public:
-
     //! size of the array
     size_t size;
     //! type of stored values
@@ -170,7 +169,9 @@ namespace Gomu{
   public:
     
     class Function;
-
+    class Symbol;
+    class Type;
+    
     //! Name of the module
     string name;
     
@@ -186,6 +187,9 @@ namespace Gomu{
     //! Number of defined contextual functions
     size_t ncfunc;
 
+    //! Nomber of defined symbols
+    size_t nsymb;
+
     //! Handle to the dinamic library object associated to the module
     void* handle;
 
@@ -200,6 +204,9 @@ namespace Gomu{
 
     //! Defined contextual function
     Function* contextual_functions;
+
+    //! Defined symbols
+    Symbol* symbols;
     
     //! Destructor
     ~Module();
@@ -209,7 +216,7 @@ namespace Gomu{
 
     //! Init module from types
     //! \param types types defined in the library
-    void init(Type* types);
+    void init(Module::Type* types);
   };
 
   //------------------
@@ -219,7 +226,6 @@ namespace Gomu{
   //! Class for the module function declarations
   class Module::Function{
   public:
-    
     //! Returned type
     string tr;
 
@@ -235,6 +241,52 @@ namespace Gomu{
     //! Specify if the function is loaded or not
     bool loaded;
   };
+
+  //----------------
+  // Module::Symbol 
+  //----------------
+
+  //! Class for the module symbol declarations
+  class Module::Symbol{
+  public:
+    //! Name of the symbol
+    string name;
+
+    //! Typre of the symbol
+    string type;
+
+    //! Pointer to the C++ data
+    void* ptr;
+
+    //! Specify if the symbol is loaded or not
+    bool loaded;
+  };
+
+  //--------------
+  // Module::Type
+  //--------------
+
+  //! Class for the module type declarations
+  class Module::Type{
+  public:
+    //! Name of the type
+    string name;
+
+    //! Display function of the type
+    DispFunc disp;
+
+    //! Delete function of the type
+    DelFunc del;
+
+    //! Copy function of the type
+    CopyFunc copy;
+
+    //! Compeare function of the type
+    CompFunc comp;
+
+    //! Poniter to the type
+    Gomu::Type** ptr;
+  };
   
   //--------------
   // SetValueComp
@@ -299,23 +351,32 @@ namespace Gomu{
   //! Class for type
   class Type{
   public:
-    
     //! Name of the type
     string name;
+
     //! Display function of the type
     DispFunc disp;
+
     //! Delete function of the type
     DelFunc del;
+
     //! Copy function of the type
     CopyFunc copy;
+
     //! Compeare function of the type
     CompFunc comp;
+
     //! Empty constructor
     Type();
+
     //! Full constructor
     Type(string,DispFunc disp,DelFunc del,CopyFunc copy,CompFunc comp);
+
     //! Recopy constructor
     Type(const Type&);
+
+    //! Construct a type from a Module::Type
+    Type(const Module::Type&);
   };
 
   //-------
@@ -340,8 +401,8 @@ namespace Gomu{
     //! \param ptr pointer to C++ value
     Value(Type* type,void* ptr);
     
-    //! Delete the current value
-    void del();
+    //! Delete the current value with protextions
+    void pdel();
     
     //! Display the current value
     //! \return a string of the diplay
@@ -360,14 +421,19 @@ namespace Gomu{
   //***********************
 
   //! Return an slong from a value ptr
-  uint64 get_slong(void* v);
-
+  int64 get_slong(void* v);
+  
   //! Return a value ptr for a bool 
   void* to_boolean(bool n);
 
   //! Return a value ptr from a slong integer
   void* to_integer(slong s);
 
+  //! Undefined copy function for type
+  void* no_copy(void*);
+
+  //! Undefined compare function for type
+  int no_comp(void*,void*);
 
   //**********************
   //* Inline definitions *
@@ -426,10 +492,12 @@ namespace Gomu{
   Value::Value(Type* t,void* p):type(t),ptr(p){}
 
   inline void
-  Value::del(){
-    if(ptr!=nullptr and type!=nullptr){
+  Value::pdel(){
+    if(ptr!=nullptr and type!=nullptr and type!=type_symbol){
+      // cout<<"Delete value of type "<<type->name<<endl;
       type->del(ptr);
     }
+    ptr=nullptr;
   }
 
   inline Value*
@@ -437,7 +505,11 @@ namespace Gomu{
     if(type!=type_symbol) return this;
     return (Value*)ptr;
   }
-   
+
+  //---------------------
+  // Auxiliary Functions
+  //---------------------
+
 }