GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
/*1* Normaliz2* Copyright (C) 2007-2014 Winfried Bruns, Bogdan Ichim, Christof Soeger3* This program is free software: you can redistribute it and/or modify4* it under the terms of the GNU General Public License as published by5* the Free Software Foundation, either version 3 of the License, or6* (at your option) any later version.7*8* This program is distributed in the hope that it will be useful,9* but WITHOUT ANY WARRANTY; without even the implied warranty of10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the11* GNU General Public License for more details.12*13* You should have received a copy of the GNU General Public License14* along with this program. If not, see <http://www.gnu.org/licenses/>.15*16* As an exception, when this program is distributed through (i) the App Store17* by Apple Inc.; (ii) the Mac App Store by Apple Inc.; or (iii) Google Play18* by Google Inc., then that store may impose any digital rights management,19* device limits and/or redistribution restrictions that are required by its20* terms of service.21*/2223//---------------------------------------------------------------------------24#include<set>2526#include "libnormaliz/matrix.h"27#include "libnormaliz/nmz_nauty.h"28#include "libnormaliz/cone.h"29#include "libnormaliz/full_cone.h"3031namespace libnormaliz {32using namespace std;3334template<typename Integer>35const Matrix<Integer>& Automorphism_Group<Integer>::getGens() const {36return Gens;37}3839template<typename Integer>40const Matrix<Integer>& Automorphism_Group<Integer>::getLinForms() const{41return LinForms;42}4344template<typename Integer>45const Matrix<Integer>& Automorphism_Group<Integer>::getSpecialLinForms() const{46return SpecialLinForms;47}4849template<typename Integer>50vector<vector<key_t> > Automorphism_Group<Integer>::getGenPerms() const{51return GenPerms;52}5354template<typename Integer>55mpz_class Automorphism_Group<Integer>::getOrder() const{56return order;57}5859template<typename Integer>60vector<vector<key_t> > Automorphism_Group<Integer>::getLinFormPerms() const{61return LinFormPerms;62}6364template<typename Integer>65vector<vector<key_t> > Automorphism_Group<Integer>::getGenOrbits() const{66return GenOrbits;67}6869template<typename Integer>70vector<vector<key_t> > Automorphism_Group<Integer>::getLinFormOrbits() const{71return LinFormOrbits;72}7374template<typename Integer>75vector<Matrix<Integer> > Automorphism_Group<Integer>::getLinMaps() const{76return LinMaps;77}7879template<typename Integer>80vector<key_t> Automorphism_Group<Integer>::getCanLabellingGens() const{81return CanLabellingGens;82}8384template<typename Integer>85bool Automorphism_Group<Integer>::isFromAmbientSpace() const{86return from_ambient_space;87}8889template<typename Integer>90bool Automorphism_Group<Integer>::isFromHB() const{91return from_HB;92}9394template<typename Integer>95bool Automorphism_Group<Integer>::isLinMapsComputed() const{96return LinMaps_computed;97}9899template<typename Integer>100bool Automorphism_Group<Integer>::isGraded() const{101return graded;102}103104template<typename Integer>105bool Automorphism_Group<Integer>::isInhomogeneous() const{106return inhomogeneous;107}108109template<typename Integer>110void Automorphism_Group<Integer>::setInhomogeneous(bool on_off){111inhomogeneous=on_off;112}113114template<typename Integer>115void Automorphism_Group<Integer>::reset(){116LinMaps_computed=false;117from_ambient_space=false;118graded=false;119inhomogeneous=false;120from_HB=false;121}122123template<typename Integer>124Automorphism_Group<Integer>::Automorphism_Group(){125reset();126}127128template<typename Integer>129bool Automorphism_Group<Integer>::make_linear_maps_primal(const Matrix<Integer>& GivenGens,const vector<vector<key_t> >& ComputedGenPerms){130131LinMaps.clear();132vector<key_t> PreKey=GivenGens.max_rank_submatrix_lex();133vector<key_t> ImKey(PreKey.size());134for(size_t i=0;i<ComputedGenPerms.size();++i){135for(size_t j=0;j<ImKey.size();++j)136ImKey[j]=ComputedGenPerms[i][PreKey[j]];137Matrix<Integer> Pre=GivenGens.submatrix(PreKey);138Matrix<Integer> Im=GivenGens.submatrix(ImKey);139Integer denom,g;140Matrix<Integer> Map=Pre.solve(Im,denom);141g=Map.matrix_gcd();142if(g%denom !=0)143return false;144Map.scalar_division(denom);145if(Map.vol()!=1)146return false;147LinMaps.push_back(Map.transpose());148//Map.pretty_print(cout);149// cout << "--------------------------------------" << endl;150}151LinMaps_computed=true;152return true;153}154155template<typename Integer>156bool Automorphism_Group<Integer>::compute(const Matrix<Integer>& ExtRays,const Matrix<Integer>& GivenGens, bool given_gens_are_extrays,157const Matrix<Integer>& SuppHyps,const Matrix<Integer>& GivenLinForms, bool given_lf_are_supps,158size_t nr_special_gens, const size_t nr_special_linforms){159Gens=ExtRays;160LinForms=SuppHyps;161SpecialLinForms=Matrix<Integer>(0,ExtRays[0].size());162for(size_t i=GivenLinForms.nr_of_rows()-nr_special_linforms;i<GivenLinForms.nr_of_rows();++i){163SpecialLinForms.append(GivenLinForms[i]);164}165166from_HB=!given_gens_are_extrays;167from_ambient_space=!given_lf_are_supps;168169vector<vector<long> > result=compute_automs(GivenGens,nr_special_gens, GivenLinForms,nr_special_linforms,order,CanType);170size_t nr_automs=(result.size()-3)/2; // the last 3 have special information171172vector<vector<key_t> > ComputedGenPerms, ComputedLFPerms;173for(size_t i=0;i<nr_automs;++i){ // decode results174vector<key_t> dummy(result[0].size());175for(size_t j=0;j<dummy.size();++j)176dummy[j]=result[i][j];177ComputedGenPerms.push_back(dummy);178vector<key_t> dummy_too(result[nr_automs].size());179for(size_t j=0;j<dummy_too.size();++j)180dummy_too[j]=result[i+nr_automs][j];181LinFormPerms.push_back(dummy_too);182ComputedLFPerms.push_back(dummy_too);183}184185if(!make_linear_maps_primal(GivenGens,ComputedGenPerms))186return false;187188if(given_gens_are_extrays){189GenPerms=ComputedGenPerms;190GenOrbits=convert_to_orbits(result[result.size()-3]);191}192else{193gen_data_via_lin_maps();194}195196if(given_lf_are_supps){197LinFormPerms=ComputedLFPerms;198LinFormOrbits=convert_to_orbits(result[result.size()-2]);199}200else{201linform_data_via_lin_maps();202}203204CanLabellingGens.clear();205if(given_gens_are_extrays){206CanLabellingGens.resize(result[result.size()-1].size());207for(size_t i=0;i<CanLabellingGens.size();++i)208CanLabellingGens[i]=result[result.size()-1][i];209}210211return true;212}213214template<typename Integer>215void Automorphism_Group<Integer>::gen_data_via_lin_maps(){216217GenPerms.clear();218map<vector<Integer>,key_t> S;219for(key_t k=0;k<Gens.nr_of_rows();++k)220S[Gens[k]]=k;221for(size_t i=0; i<LinMaps.size();++i){222vector<key_t> Perm(Gens.nr_of_rows());223for(key_t j=0;j<Perm.size();++j){224vector<Integer> Im=LinMaps[i].MxV(Gens[j]);225assert(S.find(Im)!=S.end()); // for safety226Perm[j]=S[Im];227}228GenPerms.push_back(Perm);229}230GenOrbits=orbits(GenPerms,Gens.nr_of_rows());231}232233template<typename Integer>234void Automorphism_Group<Integer>::linform_data_via_lin_maps(){235236LinFormPerms.clear();237map<vector<Integer>,key_t> S;238for(key_t k=0;k<LinForms.nr_of_rows();++k)239S[LinForms[k]]=k;240for(size_t i=0; i<LinMaps.size();++i){241vector<key_t> Perm(LinForms.nr_of_rows());242Integer dummy;243Matrix<Integer> LM=LinMaps[i].invert(dummy).transpose();244for(key_t j=0;j<Perm.size();++j){245vector<Integer> Im=LM.MxV(LinForms[j]);246assert(S.find(Im)!=S.end()); // for safety247Perm[j]=S[Im];248}249LinFormPerms.push_back(Perm);250}251LinFormOrbits=orbits(LinFormPerms,LinForms.nr_of_rows());252}253254template<typename Integer>255void Automorphism_Group<Integer>::add_images_to_orbit(const vector<Integer>& v,set<vector<Integer> >& orbit) const{256257for(size_t i=0;i<LinMaps.size();++i){258vector<Integer> w=LinMaps[i].MxV(v);259typename set<vector<Integer> >::iterator f;260f=orbit.find(w);261if(f!=orbit.end())262continue;263else{264orbit.insert(w);265add_images_to_orbit(w,orbit);266}267}268}269270template<typename Integer>271list<vector<Integer> > Automorphism_Group<Integer>::orbit_primal(const vector<Integer>& v) const{272273set<vector<Integer> > orbit;274add_images_to_orbit(v,orbit);275list<vector<Integer> > orbit_list;276for(auto c=orbit.begin();c!=orbit.end();++c)277orbit_list.push_back(*c);278return orbit_list;279}280281/* MUCH TO DO282template<typename Integer>283IsoType<Integer>::IsoType(Full_Cone<Integer>& C, bool with_Hilbert_basis){284285dim=C.getDim();286if(dim=0)287return;288289if(with_Hilbert_basis){290if(!C.isComputed(ConeProperty::HilbertBasis)){291C.do_Hilbert_basis=true;292C.compute();293}294HilbertBasis=Matrix<Integer>(C.Hilbert_Basis);295}296297if(!C.isComputed(ConeProperty::ExtremeRays)){298C.get_supphyps_from_copy(true);299C.get_supphyps_from_copy(true,true);300}301302ExtremeRays=C.Generators.submatrix(C.Extreme_Rays_ind);303SupportHyperplanes=C.Support_Hyperplanes;304305if(C.isComputed(ConeProperty::Multiplicity))306Multiplicity=C.multiplicity;307308}*/309310template<typename Integer>311IsoType<Integer>::IsoType(){ // constructs a dummy object312rank=0;313nrExtremeRays=1; // impossible314}315316template<typename Integer>317IsoType<Integer>::IsoType(const Full_Cone<Integer>& C, bool& success){318319success=false;320assert(C.isComputed(ConeProperty::AutomorphismGroup));321322// we don't want the zero cone here. It should have been filtered out.323assert(C.dim>0);324// We insist that cones arriving here are have their extreme rays as generators325nrExtremeRays=C.getNrExtremeRays();326assert(nrExtremeRays==C.nr_gen);327328if(C.isComputed(ConeProperty::Grading))329Grading=C.Grading;330if(C.inhomogeneous)331Truncation=C.Truncation;332333if(C.Automs.isFromHB()) // not yet useful334return;335CanType=C.Automs.CanType;336CanLabellingGens=C.Automs.getCanLabellingGens();337rank=C.dim;338nrSupportHyperplanes=C.nrSupport_Hyperplanes;339if(C.isComputed(ConeProperty::Multiplicity))340Multiplicity=C.multiplicity;341342if(C.isComputed(ConeProperty::HilbertBasis)){343HilbertBasis=Matrix<Integer>(0,rank);344ExtremeRays=C.Generators;345// we compute the coordinate transformation to the first max linearly indepndent346// of extreme rays in canonical order347CanBasisKey=ExtremeRays.max_rank_submatrix_lex(CanLabellingGens);348CanTransform=ExtremeRays.submatrix(CanBasisKey).invert(CanDenom);349350// now we remove the extreme rays from the stored Hilbert CanBasisKey351// since the isomorphic copy knows its own extreme rays352if(C.Hilbert_Basis.size()>nrExtremeRays){ // otherwise nothing to do353set<vector<Integer> > ERSet;354typename set<vector<Integer> >::iterator e;355for(size_t i=0;i<nrExtremeRays;++i)356ERSet.insert(ExtremeRays[i]);357for(auto h=C.Hilbert_Basis.begin();h!=C.Hilbert_Basis.end();++h){358e=ERSet.find(*h);359if(e==ERSet.end())360HilbertBasis.append(*h);361}362}363}364success=true;365}366367template<typename Integer>368const Matrix<Integer>& IsoType<Integer>::getHilbertBasis() const{369return HilbertBasis;370}371372template<typename Integer>373const Matrix<Integer>& IsoType<Integer>::getCanTransform() const{374return CanTransform;375}376377template<typename Integer>378Integer IsoType<Integer>::getCanDenom() const{379return CanDenom;380}381382template<typename Integer>383bool IsoType<Integer>::isOfType(const Full_Cone<Integer>& C) const{384385if(C.dim!=rank || C.nrSupport_Hyperplanes!=nrSupportHyperplanes386|| nrExtremeRays!=C.getNrExtremeRays())387return false;388if(!CanType.equal(C.Automs.CanType))389return false;390return true;391}392393template<typename Integer>394mpq_class IsoType<Integer>::getMultiplicity() const{395return Multiplicity;396}397398template<typename Integer>399Isomorphism_Classes<Integer>::Isomorphism_Classes(){400401Classes.push_back(IsoType<Integer>());402}403404template<typename Integer>405void Isomorphism_Classes<Integer>::add_type(Full_Cone<Integer>& C, bool& success){406407Classes.push_back(IsoType<Integer>(C,success));408if(!success)409Classes.pop_back();410}411412size_t NOT_FOUND=0;413size_t FOUND=0;414415template<typename Integer>416const IsoType<Integer>& Isomorphism_Classes<Integer>::find_type(Full_Cone<Integer>& C, bool& found) const{417418assert(C.getNrExtremeRays()==C.nr_gen);419found=false;420if(C.Automs.from_HB)421return *Classes.begin();422auto it=Classes.begin();423++it;424for(;it!=Classes.end();++it){425if(it->isOfType(C)){426found=true;427FOUND++;428return *it;429}430}431NOT_FOUND++;432return *Classes.begin();433}434435list<boost::dynamic_bitset<> > partition(size_t n, const vector<vector<key_t> >& Orbits){436// produces a list of bitsets, namely the indicator vectors of the key vectors in Orbits437438list<boost::dynamic_bitset<> > Part;439for(size_t i=0;i<Orbits.size();++i){440boost::dynamic_bitset<> p(n);441for(size_t j=0;j<Orbits[i].size();++j)442p.set(Orbits[i][j],true);443Part.push_back(p);444}445return Part;446}447448vector<vector<key_t> > keys(const list<boost::dynamic_bitset<> >& Partition){449// inverse operation of partition450vector<vector<key_t> > Keys;451auto p=Partition.begin();452for(;p!=Partition.end();++p){453vector<key_t> key;454for(size_t j=0;j< p->size();++j)455if(p->test(j))456key.push_back(j);457Keys.push_back(key);458}459return Keys;460}461462463list<boost::dynamic_bitset<> > join_partitions(const list<boost::dynamic_bitset<> >& P1,464const list<boost::dynamic_bitset<> >& P2){465// computes the join of two partitions given as lusts of indicator vectors466list<boost::dynamic_bitset<> > J=P1; // work copy pf P1467auto p2=P2.begin();468for(;p2!=P2.end();++p2){469auto p1=J.begin();470for(;p1!=J.end();++p1){ // search the first member of J that intersects p1471if((*p2).intersects(*p1))472break;473}474if((*p2).is_subset_of(*p1)) // is contained in that member, nothing to do475continue;476// now we join the members of J that intersect p2477assert(p1!=J.end()); // to be on the safe side478auto p3=p1;479p3++;480while(p3!=J.end()){481if((*p2).intersects(*p3)){482*p1= *p1 | *p3; //the union483p3=J.erase(p3);484}else485p3++;486}487}488return J;489}490491vector<vector<key_t> > orbits(const vector<vector<key_t> >& Perms, size_t N){492// Perms is a list of permutations of 0,...,N-1493494vector<vector<key_t> > Orbits;495if(Perms.size()==0){ //each element is its own orbit496Orbits.reserve(N);497for(size_t i=0;i<N;++i)498Orbits.push_back(vector<key_t>(1,i));499return Orbits;500}501vector<bool> InOrbit(N,false);502for(size_t i=0;i<N;++i){503if(InOrbit[i])504continue;505vector<key_t> NewOrbit;506NewOrbit.push_back(i);507InOrbit[i]=true;508for(size_t j=0;j<NewOrbit.size();++j){509for(size_t k=0;k<Perms.size();++k){510key_t im=Perms[k][NewOrbit[j]];511if(InOrbit[im])512continue;513NewOrbit.push_back(im);514InOrbit[im]=true;515}516}517sort(NewOrbit.begin(),NewOrbit.end());518Orbits.push_back(NewOrbit);519}520521return Orbits;522}523524525/*526*/527528/*529vector<vector<key_t> > orbits(const vector<vector<key_t> >& Perms, size_t N){530531vector<vector<key_t> > Orbits;532if(Perms.size()==0){ //each element is its own orbit533Orbits.reserve(N);534for(size_t i=0;i<N;++i)535Orbits.push_back(vector<key_t>(1,i));536return Orbits;537}538Orbits=cycle_decomposition(Perms[0],true); // with fixed points!539list<boost::dynamic_bitset<> > P1=partition(Perms[0].size(),Orbits);540for(size_t i=1;i<Perms.size();++i){541vector<vector<key_t> > Orbits_1=cycle_decomposition(Perms[i]);542list<boost::dynamic_bitset<> > P2=partition(Perms[0].size(),Orbits_1);543P1=join_partitions(P1,P2);544}545return keys(P1);546}547*/548549vector<vector<key_t> > convert_to_orbits(const vector<long>& raw_orbits){550551vector<key_t> key(raw_orbits.size());552vector<vector<key_t> > orbits;553for(key_t i=0;i<raw_orbits.size();++i){554if(raw_orbits[i]==(long) i){555orbits.push_back(vector<key_t>(1,i));556key[i]=orbits.size()-1;557}558else{559orbits[key[raw_orbits[i]]].push_back(i);560}561}562return orbits;563}564565566vector<vector<key_t> > cycle_decomposition(vector<key_t> perm, bool with_fixed_points){567// computes the cacle decomposition of a permutation with or wothout fixed points568569vector<vector<key_t> > dec;570vector<bool> in_cycle(perm.size(),false);571for (size_t i=0;i<perm.size();++i){572if(in_cycle[i])573continue;574if(perm[i]==i){575if(!with_fixed_points)576continue;577vector<key_t> cycle(1,i);578in_cycle[i]=true;579dec.push_back(cycle);580continue;581}582in_cycle[i]=true;583key_t next=i;584vector<key_t> cycle(1,i);585while(true){586next=perm[next];587if(next==i)588break;589cycle.push_back(next);590in_cycle[next]=true;591}592dec.push_back(cycle);593}594return dec;595}596597void pretty_print_cycle_dec(const vector<vector<key_t> >& dec, ostream& out){598599for(size_t i=0;i<dec.size();++i){600out << "(";601for(size_t j=0;j<dec[i].size();++j){602out << dec[i][j];603if(j!=dec[i].size()-1)604out << " ";605}606out << ") ";607608}609out << "--" << endl;610}611612template<typename Integer>613vector<vector<long> > compute_automs(const Matrix<Integer>& Gens, const size_t nr_special_gens, const Matrix<Integer>& LinForms,614const size_t nr_special_linforms, mpz_class& group_order, BinaryMatrix<Integer>& CanType){615616vector<vector<long> > Automs=compute_automs_by_nauty(Gens.get_elements(), nr_special_gens, LinForms.get_elements(),617nr_special_linforms, group_order, CanType);618return Automs;619}620621} // namespace622623624