/** * 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(string,DisplayGenerator,GeneratorsNumber) //---------------------------------------------------------------------- MonoidFamily::MonoidFamily(string l,DisplayGenerator d,GeneratorsNumber n,GeneratorRank r):label(l),gdisp(d),gnum(n),grank(r){ left_reversing=nullptr; right_reversing=nullptr; ranked_phi_germ=nullptr; ranked_garside_word_factory=nullptr; } //------------------------------------------ // MonoidFamily::apply_phi(size_t,Word,int) //------------------------------------------ void MonoidFamily::apply_phi(size_t r,Word& w,int p){ size_t s=w.size(); for(size_t i=0;i<s;++i){ w[i]=ranked_phi_germ(r,w[i],p); } } //------------------------------------ // MonoidFamily::phi(size_t,Word,int) //------------------------------------ Word MonoidFamily::phi(size_t r,const Word& w,int p){ size_t s=w.size(); Word res(s); for(size_t i=0;i<s;++i){ res[i]=ranked_phi_germ(r,w[i],p); } return res; } //--------------------------------------- // MonoidFamily::phi_normal(size_t,Word) //--------------------------------------- Word MonoidFamily::phi_normal(size_t r,const Word& w){ if(r<=1) return w; Array<Word> splitting=phi_splitting(r-1,w); size_t b=splitting.size(); for(size_t i=0;i<b;++i){ splitting[i]=phi_normal(r-1,splitting[i]); apply_phi(r,splitting[i],b-1-i); } Word res(w.size()); size_t ind=0; for(size_t i=0;i<b;++i){ Word& temp=splitting[i]; for(size_t j=0;j<temp.size();++j){ res[ind++]=temp[j]; } } return res; } //------------------------------------- // MonoidFamily::phi_tail(size_t,Word) //------------------------------------- Word MonoidFamily::phi_tail(size_t r,const Word& w){ Word u=w; Word res; Word delta=garside_element(r); while(true){ pair<Word,Word> temp=right_gcd_x(u,delta); if(temp.first.is_empty()) return res; res=res*temp.first; u=temp.second; } return res; } //--------------------------------------- // MonoidFamily::phi_tail_x(size_t,Word) //--------------------------------------- pair<Word,Word> MonoidFamily::phi_tail_x(size_t r,const Word& w){ Word u=w; Word res; Word delta=garside_element(r); while(true){ pair<Word,Word> temp=right_gcd_x(u,delta); if(temp.first.is_empty()) return pair<Word,Word>(u,res); res=res*temp.first; u=temp.second; } return pair<Word,Word>(u,res); } //------------------------------------------ // MonoidFamily::phi_splitting(size_t,Word) //------------------------------------------ Array<Word> MonoidFamily::phi_splitting(size_t r,const Word& w){ deque<Word> res; Word u=w; while(not u.is_empty()){ pair<Word,Word> p=phi_tail_x(r,u); u=phi(r+1,p.first,-1); res.push_front(p.second); } Array<Word> res_array(res.size()); for(size_t i=0;i<res.size();++i) res_array[i]=res[i]; return res_array; } //-------------------------- // MonoidFamily::rank(Word) //-------------------------- size_t MonoidFamily::rank(const Word& w){ if(w.is_empty()) return 0; size_t r=1; for(size_t i=0;i<w.size();++i){ size_t t=grank(w.read(i)); if(t>r) r=t; } return r; } //*************** //* MonoidTrait * //*************** //---------------------------- // MonoidTrait::MonoidTrait() //---------------------------- MonoidTrait::MonoidTrait(){ left_reversing=nullptr; right_reversing=nullptr; } //----------------------------- // MonoidTrait::~MonoidTrait() //----------------------------- MonoidTrait::~MonoidTrait(){ if(left_reversing!=nullptr) delete left_reversing; if(right_reversing!=nullptr) delete right_reversing; } //--------------------------------------- // MonoidTrait::are_equivalen(Word,Word) //--------------------------------------- bool MonoidTrait::are_equivalent(const Word& u,const Word& v){ left_reversing->set_word(u,v); left_reversing->check_positivity(); return left_reversing->word.is_empty(); } //----------------------------------------------------------- // 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 * //***********************