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//---------------------------------------------------------------------------2425#include <stdlib.h>26#include <set>27#include <map>28#include <iostream>29#include <string>30#include <algorithm>31#include <time.h>32#include <deque>3334#include "libnormaliz/full_cone.h"35#include "libnormaliz/cone_helper.h"36#include "libnormaliz/vector_operations.h"37#include "libnormaliz/list_operations.h"38#include "libnormaliz/map_operations.h"39#include "libnormaliz/my_omp.h"40#include "libnormaliz/integer.h"41// #include "libnormaliz/sublattice_representation.h"42#include "libnormaliz/offload_handler.h"4344//---------------------------------------------------------------------------4546// const size_t RecBoundTriang=1000000; // if number(supphyps)*size(triang) > RecBoundTriang47// we pass to (non-recirsive) pyramids48// now in build_cone4950const size_t EvalBoundTriang=2500000; // if more than EvalBoundTriang simplices have been stored51// evaluation is started (whenever possible)5253const size_t EvalBoundPyr=200000; // the same for stored pyramids of level > 05455const size_t EvalBoundLevel0Pyr=200000; // 1000000; // the same for stored level 0 pyramids5657// const size_t EvalBoundRecPyr=200000; // the same for stored RECURSIVE pyramids5859// const size_t IntermedRedBoundHB=2000000; // bound for number of HB elements before60// intermediate reduction is called6162const int largePyramidFactor=20; // pyramid is large if largePyramidFactor*Comparisons[Pyramid_key.size()-dim] > old_nr_supp_hyps6364const int SuppHypRecursionFactor=200; // pyramids for supphyps formed if Pos*Neg > ...6566const size_t RAM_Size=1000000000; // we assume that there is at least 1 GB of RAM6768const long GMP_time_factor=10; // factor by which GMP arithmetic differs from long long6970//---------------------------------------------------------------------------7172namespace libnormaliz {73using namespace std;7475//---------------------------------------------------------------------------76//private77//---------------------------------------------------------------------------7879template<typename Integer>80void Full_Cone<Integer>::check_simpliciality_hyperplane(const FACETDATA& hyp) const{81size_t nr_gen_in_hyp=0;82for(size_t i=0; i<nr_gen;++i)83if(in_triang[i]&& hyp.GenInHyp.test(i))84nr_gen_in_hyp++;85if((hyp.simplicial && nr_gen_in_hyp!=dim-2) || (!hyp.simplicial && nr_gen_in_hyp==dim-2)){86// NOTE: in_triang set at END of main loop in build_cone87errorOutput() << "Simplicial " << hyp.simplicial << " dim " << dim << " gen_in_hyp " << nr_gen_in_hyp << endl;88assert(false);89}90}9192template<typename Integer>93void Full_Cone<Integer>::set_simplicial(FACETDATA& hyp){94size_t nr_gen_in_hyp=0;95for(size_t i=0; i<nr_gen;++i)96if(in_triang[i]&& hyp.GenInHyp.test(i))97nr_gen_in_hyp++;98hyp.simplicial=(nr_gen_in_hyp==dim-2);99}100101template<typename Integer>102void Full_Cone<Integer>::number_hyperplane(FACETDATA& hyp, const size_t born_at, const size_t mother){103// add identifying number, the birth day and the number of mother104105hyp.Mother=mother;106hyp.BornAt=born_at;107if(!multithreaded_pyramid){108hyp.Ident=HypCounter[0];109HypCounter[0]++;110return;111}112113int tn;114if(omp_get_level()==omp_start_level)115tn=0;116else117tn = omp_get_ancestor_thread_num(omp_start_level+1);118hyp.Ident=HypCounter[tn];119HypCounter[tn]+=omp_get_max_threads();120121}122123//---------------------------------------------------------------------------124125template<typename Integer>126bool Full_Cone<Integer>::is_hyperplane_included(FACETDATA& hyp) {127if (!is_pyramid) { // in the topcone we always have ov_sp > 0128return true;129}130//check if it would be an excluded hyperplane131Integer ov_sp = v_scalar_product(hyp.Hyp,Order_Vector);132if (ov_sp > 0) {133return true;134} else if (ov_sp == 0) {135for (size_t i=0; i<dim; i++) {136if (hyp.Hyp[i]>0) {137return true;138} else if (hyp.Hyp[i]<0) {139return false;140}141}142}143return false;144}145146//---------------------------------------------------------------------------147148template<typename Integer>149void Full_Cone<Integer>::add_hyperplane(const size_t& new_generator, const FACETDATA & positive,const FACETDATA & negative,150list<FACETDATA>& NewHyps, bool known_to_be_simplicial){151// adds a new hyperplane found in find_new_facets to this cone (restricted to generators processed)152153size_t k;154155FACETDATA NewFacet; NewFacet.Hyp.resize(dim); NewFacet.GenInHyp.resize(nr_gen);156NewFacet.is_positive_on_all_original_gens=false;157NewFacet.is_negative_on_some_original_gen=false;158159for (k = 0; k <dim; k++) {160NewFacet.Hyp[k]=positive.ValNewGen*negative.Hyp[k]-negative.ValNewGen*positive.Hyp[k];161if(!check_range(NewFacet.Hyp[k]))162break;163}164165if(k==dim)166v_make_prime(NewFacet.Hyp);167else{168#pragma omp atomic169GMP_hyp++;170vector<mpz_class> mpz_neg(dim), mpz_pos(dim), mpz_sum(dim);171convert(mpz_neg, negative.Hyp);172convert(mpz_pos, positive.Hyp);173for (k = 0; k <dim; k++)174mpz_sum[k]=convertTo<mpz_class>(positive.ValNewGen)*mpz_neg[k]-convertTo<mpz_class>(negative.ValNewGen)*mpz_pos[k];175v_make_prime(mpz_sum);176convert(NewFacet.Hyp, mpz_sum);177}178179NewFacet.ValNewGen=0;180NewFacet.GenInHyp=positive.GenInHyp & negative.GenInHyp; // new hyperplane contains old gen iff both pos and neg do181if(known_to_be_simplicial){182NewFacet.simplicial=true;183check_simpliciality_hyperplane(NewFacet);184}185else186set_simplicial(NewFacet);187NewFacet.GenInHyp.set(new_generator); // new hyperplane contains new generator188number_hyperplane(NewFacet,nrGensInCone,positive.Ident);189190NewHyps.push_back(NewFacet);191}192193194//---------------------------------------------------------------------------195196197template<typename Integer>198void Full_Cone<Integer>::find_new_facets(const size_t& new_generator){199// our Fourier-Motzkin implementation200// the special treatment of simplicial facets was inserted because of line shellings.201// At present these are not computed.202203//to see if possible to replace the function .end with constant iterator since push-back is performed.204205// for dimension 0 and 1 F-M is never necessary and can lead to problems206// when using dim-2207if (dim <= 1)208return;209210// NEW: new_generator is the index of the generator being inserted211212size_t i,k,nr_zero_i;213size_t subfacet_dim=dim-2; // NEW dimension of subfacet214size_t facet_dim=dim-1; // NEW dimension of facet215216const bool tv_verbose = false; //verbose && !is_pyramid; // && Support_Hyperplanes.nr_of_rows()>10000; //verbose in this method call217218219// preparing the computations, the various types of facets are sorted into the deques220deque <FACETDATA*> Pos_Simp,Pos_Non_Simp;221deque <FACETDATA*> Neg_Simp,Neg_Non_Simp;222deque <FACETDATA*> Neutral_Simp, Neutral_Non_Simp;223224boost::dynamic_bitset<> Zero_Positive(nr_gen),Zero_Negative(nr_gen); // here we collect the vertices that lie in a225// postive resp. negative hyperplane226227bool simplex;228229if (tv_verbose) verboseOutput()<<"transform_values:"<<flush;230231typename list<FACETDATA>::iterator ii = Facets.begin();232233for (; ii != Facets.end(); ++ii) {234// simplex=true;235// nr_zero_i=0;236simplex=ii->simplicial; // at present simplicial, will become nonsimplicial if neutral237/* for (size_t j=0; j<nr_gen; j++){238if (ii->GenInHyp.test(j)) {239if (++nr_zero_i > facet_dim) {240simplex=false;241break;242}243}244}*/245246if (ii->ValNewGen==0) {247ii->GenInHyp.set(new_generator); // Must be set explicitly !!248ii->simplicial=false; // simpliciality definitly gone with the new generator249if (simplex) {250Neutral_Simp.push_back(&(*ii)); // simplicial without the new generator251} else {252Neutral_Non_Simp.push_back(&(*ii)); // nonsim�plicial already without the new generator253}254}255else if (ii->ValNewGen>0) {256Zero_Positive |= ii->GenInHyp;257if (simplex) {258Pos_Simp.push_back(&(*ii));259} else {260Pos_Non_Simp.push_back(&(*ii));261}262}263else if (ii->ValNewGen<0) {264Zero_Negative |= ii->GenInHyp;265if (simplex) {266Neg_Simp.push_back(&(*ii));267} else {268Neg_Non_Simp.push_back(&(*ii));269}270}271}272273// TO DO: Negativliste mit Zero_Positive verfeinern, also die aussondern, die nicht genug positive Erz enthalten274// Eventuell sogar Rang-Test einbauen.275// Letzteres könnte man auch bei den positiven machen, bevor sie verarbeitet werden276277boost::dynamic_bitset<> Zero_PN(nr_gen);278Zero_PN = Zero_Positive & Zero_Negative;279280size_t nr_PosSimp = Pos_Simp.size();281size_t nr_PosNonSimp = Pos_Non_Simp.size();282size_t nr_NegSimp = Neg_Simp.size();283size_t nr_NegNonSimp = Neg_Non_Simp.size();284size_t nr_NeuSimp = Neutral_Simp.size();285size_t nr_NeuNonSimp = Neutral_Non_Simp.size();286287if (tv_verbose) verboseOutput()<<" PS "<<nr_PosSimp<<", P "<<nr_PosNonSimp<<", NS "<<nr_NegSimp<<", N "<<nr_NegNonSimp<<", ZS "<<nr_NeuSimp<<", Z "<<nr_NeuNonSimp<<endl;288289if (tv_verbose) verboseOutput()<<"transform_values: subfacet of NS: "<<flush;290291vector< list<pair < boost::dynamic_bitset<>, int> > > Neg_Subfacet_Multi(omp_get_max_threads()) ;292293boost::dynamic_bitset<> zero_i, subfacet;294295// This parallel region cannot throw a NormalizException296#pragma omp parallel for private(zero_i,subfacet,k,nr_zero_i)297for (i=0; i<nr_NegSimp;i++){298zero_i=Zero_PN & Neg_Simp[i]->GenInHyp;299300nr_zero_i=0;301for(size_t j=0;j<nr_gen;j++){302if(zero_i.test(j))303nr_zero_i++;304if(nr_zero_i>subfacet_dim){305break;306}307}308309if(nr_zero_i==subfacet_dim) // NEW This case treated separately310Neg_Subfacet_Multi[omp_get_thread_num()].push_back(pair <boost::dynamic_bitset<>, int> (zero_i,i));311312if(nr_zero_i==facet_dim){313for (k =0; k<nr_gen; k++) {314if(zero_i.test(k)) {315subfacet=zero_i;316subfacet.reset(k); // remove k-th element from facet to obtain subfacet317Neg_Subfacet_Multi[omp_get_thread_num()].push_back(pair <boost::dynamic_bitset<>, int> (subfacet,i));318}319}320}321}322323list < pair < boost::dynamic_bitset<>, int> > Neg_Subfacet_Multi_United;324for(int i=0;i<omp_get_max_threads();++i)325Neg_Subfacet_Multi_United.splice(Neg_Subfacet_Multi_United.begin(),Neg_Subfacet_Multi[i]);326Neg_Subfacet_Multi_United.sort();327328329if (tv_verbose) verboseOutput()<<Neg_Subfacet_Multi_United.size() << ", " << flush;330331list< pair < boost::dynamic_bitset<>, int > >::iterator jj;332list< pair < boost::dynamic_bitset<>, int > >::iterator del;333jj =Neg_Subfacet_Multi_United.begin(); // remove negative subfacets shared334while (jj!= Neg_Subfacet_Multi_United.end()) { // by two neg simpl facets335del=jj++;336if (jj!=Neg_Subfacet_Multi_United.end() && (*jj).first==(*del).first) { //delete since is the intersection of two negative simplicies337Neg_Subfacet_Multi_United.erase(del);338del=jj++;339Neg_Subfacet_Multi_United.erase(del);340}341}342343size_t nr_NegSubfMult = Neg_Subfacet_Multi_United.size();344if (tv_verbose) verboseOutput() << nr_NegSubfMult << ", " << flush;345346vector<list<FACETDATA> > NewHypsSimp(nr_PosSimp);347vector<list<FACETDATA> > NewHypsNonSimp(nr_PosNonSimp);348349map < boost::dynamic_bitset<>, int > Neg_Subfacet;350size_t nr_NegSubf=0;351352// size_t NrMatches=0, NrCSF=0, NrRank=0, NrComp=0, NrNewF=0;353354/* deque<bool> Indi(nr_NegNonSimp);355for(size_t j=0;j<nr_NegNonSimp;++j)356Indi[j]=false; */357358if(multithreaded_pyramid){359#pragma omp atomic360nrTotalComparisons+=nr_NegNonSimp*nr_PosNonSimp;361}362else{363nrTotalComparisons+=nr_NegNonSimp*nr_PosNonSimp;364}365366367//=====================================================================368// parallel from here369370bool skip_remaining = false;371#ifndef NCATCH372std::exception_ptr tmp_exception;373#endif374375#pragma omp parallel private(jj)376{377size_t i,j,k,nr_zero_i;378boost::dynamic_bitset<> subfacet(dim-2);379jj = Neg_Subfacet_Multi_United.begin();380size_t jjpos=0;381int tn = omp_get_ancestor_thread_num(omp_start_level+1);382383bool found;384// This for region cannot throw a NormalizException385#pragma omp for schedule(dynamic)386for (size_t j=0; j<nr_NegSubfMult; ++j) { // remove negative subfacets shared387for(;j > jjpos; ++jjpos, ++jj) ; // by non-simpl neg or neutral facets388for(;j < jjpos; --jjpos, --jj) ;389390subfacet=(*jj).first;391found=false;392for (i = 0; i <nr_NeuSimp; i++) {393found=subfacet.is_subset_of(Neutral_Simp[i]->GenInHyp);394if(found)395break;396}397if (!found) {398for (i = 0; i <nr_NeuNonSimp; i++) {399found=subfacet.is_subset_of(Neutral_Non_Simp[i]->GenInHyp);400if(found)401break;402}403if(!found) {404for (i = 0; i <nr_NegNonSimp; i++) {405found=subfacet.is_subset_of(Neg_Non_Simp[i]->GenInHyp);406if(found)407break;408}409}410}411if (found) {412jj->second=-1;413}414}415416#pragma omp single417{ //remove elements that where found in the previous loop418jj = Neg_Subfacet_Multi_United.begin();419map < boost::dynamic_bitset<>, int > ::iterator last_inserted=Neg_Subfacet.begin(); // used to speedup insertion into the new map420for (; jj!= Neg_Subfacet_Multi_United.end(); ++jj) {421if ((*jj).second != -1) {422last_inserted = Neg_Subfacet.insert(last_inserted,*jj);423}424}425nr_NegSubf=Neg_Subfacet.size();426}427428#pragma omp single nowait429{Neg_Subfacet_Multi_United.clear();}430431432boost::dynamic_bitset<> zero_i(nr_gen);433map <boost::dynamic_bitset<>, int> ::iterator jj_map;434435436#pragma omp single nowait437if (tv_verbose) {438verboseOutput() << "PS vs NS and PS vs N , " << flush;439}440441vector<key_t> key(nr_gen);442size_t nr_missing;443bool common_subfacet;444// we cannot use nowait here because of the way we handle exceptions in this loop445#pragma omp for schedule(dynamic) //nowait446for (size_t i =0; i<nr_PosSimp; i++){447448if (skip_remaining) continue;449#ifndef NCATCH450try {451#endif452453INTERRUPT_COMPUTATION_BY_EXCEPTION454455zero_i=Zero_PN & Pos_Simp[i]->GenInHyp;456nr_zero_i=0;457for(j=0;j<nr_gen && nr_zero_i<=facet_dim;j++)458if(zero_i.test(j)){459key[nr_zero_i]=j;460nr_zero_i++;461}462463if(nr_zero_i<subfacet_dim)464continue;465466// first PS vs NS467468if (nr_zero_i==subfacet_dim) { // NEW slight change in logic. Positive simpl facet shared at most469jj_map=Neg_Subfacet.find(zero_i); // one subfacet with negative simpl facet470if (jj_map!=Neg_Subfacet.end()) {471add_hyperplane(new_generator,*Pos_Simp[i],*Neg_Simp[(*jj_map).second],NewHypsSimp[i],true);472(*jj_map).second = -1; // block subfacet in further searches473}474}475if (nr_zero_i==facet_dim){ // now there could be more such subfacets. We make all and search them.476for (k =0; k<nr_gen; k++) { // BOOST ROUTINE477if(zero_i.test(k)) {478subfacet=zero_i;479subfacet.reset(k); // remove k-th element from facet to obtain subfacet480jj_map=Neg_Subfacet.find(subfacet);481if (jj_map!=Neg_Subfacet.end()) {482add_hyperplane(new_generator,*Pos_Simp[i],*Neg_Simp[(*jj_map).second],NewHypsSimp[i],true);483(*jj_map).second = -1;484// Indi[j]=true;485}486}487}488}489490// now PS vs N491492for (j=0; j<nr_NegNonSimp; j++){ // search negative facet with common subfacet493nr_missing=0;494common_subfacet=true;495for(k=0;k<nr_zero_i;k++) {496if(!Neg_Non_Simp[j]->GenInHyp.test(key[k])) {497nr_missing++;498if(nr_missing==2 || nr_zero_i==subfacet_dim) {499common_subfacet=false;500break;501}502}503}504505if(common_subfacet){506add_hyperplane(new_generator,*Pos_Simp[i],*Neg_Non_Simp[j],NewHypsSimp[i],true);507if(nr_zero_i==subfacet_dim) // only one subfacet can lie in negative hyperplane508break;509}510}511#ifndef NCATCH512} catch(const std::exception& ) {513tmp_exception = std::current_exception();514skip_remaining = true;515#pragma omp flush(skip_remaining)516}517#endif518519} // PS vs NS and PS vs N520521if (!skip_remaining) {522#pragma omp single nowait523if (tv_verbose) {524verboseOutput() << "P vs NS and P vs N" << endl;525}526527list<FACETDATA*> AllNonSimpHyp;528typename list<FACETDATA*>::iterator a;529530for(i=0;i<nr_PosNonSimp;++i)531AllNonSimpHyp.push_back(&(*Pos_Non_Simp[i]));532for(i=0;i<nr_NegNonSimp;++i)533AllNonSimpHyp.push_back(&(*Neg_Non_Simp[i]));534for(i=0;i<nr_NeuNonSimp;++i)535AllNonSimpHyp.push_back(&(*Neutral_Non_Simp[i]));536size_t nr_NonSimp = nr_PosNonSimp+nr_NegNonSimp+nr_NeuNonSimp;537538bool ranktest;539FACETDATA *hp_i, *hp_j, *hp_t; // pointers to current hyperplanes540541size_t missing_bound, nr_common_zero;542boost::dynamic_bitset<> common_zero(nr_gen);543vector<key_t> common_key;544common_key.reserve(nr_gen);545vector<int> key_start(nrGensInCone);546547#pragma omp for schedule(dynamic) // nowait548for (size_t i =0; i<nr_PosNonSimp; i++){ //Positive Non Simp vs.Negative Simp and Non Simp549550if (skip_remaining) continue;551552#ifndef NCATCH553try {554#endif555INTERRUPT_COMPUTATION_BY_EXCEPTION556557jj_map = Neg_Subfacet.begin(); // First the Simp558for (j=0; j<nr_NegSubf; ++j,++jj_map) {559if ( (*jj_map).second != -1 ) { // skip used subfacets560if(jj_map->first.is_subset_of(Pos_Non_Simp[i]->GenInHyp)){561add_hyperplane(new_generator,*Pos_Non_Simp[i],*Neg_Simp[(*jj_map).second],NewHypsNonSimp[i],true);562(*jj_map).second = -1; // has now been used563}564}565}566567// Now the NonSimp568569hp_i=Pos_Non_Simp[i];570zero_i=Zero_PN & hp_i->GenInHyp; // these are the potential vertices in an intersection571nr_zero_i=0;572int last_existing=-1;573for(size_t jj=0;jj<nrGensInCone;jj++) // we make a "key" of the potential vertices in the intersection574{575j=GensInCone[jj];576if(zero_i.test(j)){577key[nr_zero_i]=j;578for(size_t kk= last_existing+1;kk<=jj;kk++) // used in the extension test579key_start[kk]=nr_zero_i; // to find out from which generator on both have existed580nr_zero_i++;581last_existing= jj;582}583}584if(last_existing< (int)nrGensInCone-1)585for(size_t kk=last_existing+1;kk<nrGensInCone;kk++)586key_start[kk]=nr_zero_i;587588if (nr_zero_i<subfacet_dim)589continue;590591// now nr_zero_i is the number of vertices in hp_i that have a chance to lie in a negative facet592// and key contains the indices593594missing_bound=nr_zero_i-subfacet_dim; // at most this number of generators can be missing595// to have a chance for common subfacet596597for (j=0; j<nr_NegNonSimp; j++){598599600hp_j=Neg_Non_Simp[j];601602if(hp_i->Ident==hp_j->Mother || hp_j->Ident==hp_i->Mother){ // mother and daughter coming together603add_hyperplane(new_generator,*hp_i,*hp_j,NewHypsNonSimp[i],false); // their intersection is a subfacet604continue; // simplicial set in add_hyperplane605}606607608bool extension_test=hp_i->BornAt==hp_j->BornAt || (hp_i->BornAt<hp_j->BornAt && hp_j->Mother!=0)609|| (hp_j->BornAt<hp_i->BornAt && hp_i->Mother!=0);610611// extension_test=false;612613size_t both_existing_from=key_start[max(hp_i->BornAt,hp_j->BornAt)];614615nr_missing=0;616nr_common_zero=0;617common_key.clear();618size_t second_loop_bound=nr_zero_i;619common_subfacet=true;620621// We use the following criterion:622// if the two facets are not mother and daughter (taken care of already), then623// they cannot have intersected in a subfacet at the time when the second was born.624// In other words: they can only intersect in a subfacet now, if at least one common vertex625// has been added after the birth of the younger one.626// this is indicated by "extended".627628if(extension_test){629bool extended=false;630second_loop_bound=both_existing_from; // fisrt we find the common vertices inserted from the step631// where both facets existed the first time632for(k=both_existing_from;k<nr_zero_i;k++){633if(!hp_j->GenInHyp.test(key[k])) {634nr_missing++;635if(nr_missing>missing_bound) {636common_subfacet=false;637break;638}639}640else {641extended=true; // in this case they have a common vertex added after their common existence642common_key.push_back(key[k]);643nr_common_zero++;644}645}646647if(!extended || !common_subfacet) //648continue;649}650651652for(k=0;k<second_loop_bound;k++) { // now the remaining653if(!hp_j->GenInHyp.test(key[k])) {654nr_missing++;655if(nr_missing>missing_bound) {656common_subfacet=false;657break;658}659}660else {661common_key.push_back(key[k]);662nr_common_zero++;663}664}665666if(!common_subfacet)667continue;668/* #pragma omp atomic669NrCSF++;*/670671if(using_GMP<Integer>())672ranktest = (nr_NonSimp > GMP_time_factor*dim*dim*nr_common_zero/3); // in this case the rank computation takes longer673else674ranktest = (nr_NonSimp > dim*dim*nr_common_zero/3);675// ranktest=true;676677if(ranktest) { // cout << "Rang" << endl;678679/* #pragma omp atomic680NrRank++; */681682Matrix<Integer>& Test = Top_Cone->RankTest[tn];683if (Test.rank_submatrix(Generators,common_key)<subfacet_dim) {684common_subfacet=false;685}686} // ranktest687else{ // now the comparison test688689/* #pragma omp atomic690NrComp++; */691692common_zero = zero_i & hp_j->GenInHyp;693for (a=AllNonSimpHyp.begin();a!=AllNonSimpHyp.end();++a){694hp_t=*a;695if ((hp_t!=hp_i) && (hp_t!=hp_j) && common_zero.is_subset_of(hp_t->GenInHyp)) {696common_subfacet=false;697AllNonSimpHyp.splice(AllNonSimpHyp.begin(),AllNonSimpHyp,a); // for the "darwinistic" mewthod698break;699}700}701} // else702if (common_subfacet) { //intersection of i and j is a subfacet703add_hyperplane(new_generator,*hp_i,*hp_j,NewHypsNonSimp[i],false); //simplicial set in add_hyperplane704/* #pragma omp atomic705NrNewF++; */706// Indi[j]=true;707}708}709#ifndef NCATCH710} catch(const std::exception& ) {711tmp_exception = std::current_exception();712skip_remaining = true;713#pragma omp flush(skip_remaining)714}715#endif716} // end for717} // end !skip_remaining718} //END parallel719720#ifndef NCATCH721if (!(tmp_exception == 0)) std::rethrow_exception(tmp_exception);722#endif723//=====================================================================724// parallel until here725726727/* if(!is_pyramid)728cout << "Matches " << NrMatches << " pot. common subf " << NrCSF << " rank test " << NrRank << " comp test "729<< NrComp << " neww hyps " << NrNewF << endl; */730731732for(i=0;i<nr_PosSimp;i++)733Facets.splice(Facets.end(),NewHypsSimp[i]);734735for(i=0;i<nr_PosNonSimp;i++)736Facets.splice(Facets.end(),NewHypsNonSimp[i]);737738//removing the negative hyperplanes739// now done in build_cone740741if (tv_verbose) verboseOutput()<<"transform_values: done"<<endl;742743}744745//---------------------------------------------------------------------------746747template<typename Integer>748void Full_Cone<Integer>::extend_triangulation(const size_t& new_generator){749// extends the triangulation of this cone by including new_generator750// simplicial facets save us from searching the "brother" in the existing triangulation751// to which the new simplex gets attached752753size_t listsize =old_nr_supp_hyps; // Facets.size();754vector<typename list<FACETDATA>::iterator> visible;755visible.reserve(listsize);756typename list<FACETDATA>::iterator i = Facets.begin();757758listsize=0;759for (; i!=Facets.end(); ++i)760if (i->ValNewGen < 0){ // visible facet761visible.push_back(i);762listsize++;763}764765#ifndef NCATCH766std::exception_ptr tmp_exception;767#endif768769typename list< SHORTSIMPLEX<Integer> >::iterator oldTriBack = --TriangulationBuffer.end();770#pragma omp parallel private(i)771{772size_t k,l;773bool one_not_in_i, not_in_facet;774size_t not_in_i=0;775// size_t facet_dim=dim-1;776// size_t nr_in_i=0;777778list< SHORTSIMPLEX<Integer> > Triangulation_kk;779typename list< SHORTSIMPLEX<Integer> >::iterator j;780781vector<key_t> key(dim);782783// if we only want a partial triangulation but came here because of a deep level784// mark if this part of the triangulation has not to be evaluated785bool skip_eval = false;786787#pragma omp for schedule(dynamic)788for (size_t kk=0; kk<listsize; ++kk) {789790#ifndef NCATCH791try {792#endif793INTERRUPT_COMPUTATION_BY_EXCEPTION794795i=visible[kk];796797/* nr_in_i=0;798for(size_t m=0;m<nr_gen;m++){799if(i->GenInHyp.test(m))800nr_in_i++;801if(nr_in_i>facet_dim){802break;803}804}*/805806skip_eval = Top_Cone->do_partial_triangulation && i->ValNewGen == -1807&& is_hyperplane_included(*i);808809if (i->simplicial){ // simplicial810l=0;811for (k = 0; k <nr_gen; k++) {812if (i->GenInHyp[k]==1) {813key[l]=k;814l++;815}816}817key[dim-1]=new_generator;818819if (skip_eval)820store_key(key,0,0,Triangulation_kk);821else822store_key(key,-i->ValNewGen,0,Triangulation_kk);823continue;824} // end simplicial825826size_t irrelevant_vertices=0;827for(size_t vertex=0;vertex<nrGensInCone;++vertex){828829if(i->GenInHyp[GensInCone[vertex]]==0) // lead vertex not in hyperplane830continue;831832if(irrelevant_vertices<dim-2){833++irrelevant_vertices;834continue;835}836837j=TriSectionFirst[vertex];838bool done=false;839for(;!done;j++)840{841done=(j==TriSectionLast[vertex]);842key=j->key;843one_not_in_i=false; // true indicates that one gen of simplex is not in hyperplane844not_in_facet=false; // true indicates that a second gen of simplex is not in hyperplane845for(k=0;k<dim;k++){846if ( !i->GenInHyp.test(key[k])) {847if(one_not_in_i){848not_in_facet=true;849break;850}851one_not_in_i=true;852not_in_i=k;853}854}855856if(not_in_facet) // simplex does not share facet with hyperplane857continue;858859key[not_in_i]=new_generator;860if (skip_eval)861store_key(key,0,j->vol,Triangulation_kk);862else863store_key(key,-i->ValNewGen,j->vol,Triangulation_kk);864865} // j866867} // for vertex868869#ifndef NCATCH870} catch(const std::exception& ) {871tmp_exception = std::current_exception();872}873#endif874875} // omp for kk876877if (multithreaded_pyramid) {878#pragma omp critical(TRIANG)879TriangulationBuffer.splice(TriangulationBuffer.end(),Triangulation_kk);880} else881TriangulationBuffer.splice(TriangulationBuffer.end(),Triangulation_kk);882883} // parallel884885#ifndef NCATCH886if (!(tmp_exception == 0)) std::rethrow_exception(tmp_exception);887#endif888889// GensInCone.push_back(new_generator); // now in extend_cone890TriSectionFirst.push_back(++oldTriBack);891TriSectionLast.push_back(--TriangulationBuffer.end());892}893894//---------------------------------------------------------------------------895896template<typename Integer>897void Full_Cone<Integer>::store_key(const vector<key_t>& key, const Integer& height,898const Integer& mother_vol, list< SHORTSIMPLEX<Integer> >& Triangulation){899// stores a simplex given by key and height in Triangulation900// mother_vol is the volume of the simplex to which the new one is attached901902SHORTSIMPLEX<Integer> newsimplex;903newsimplex.key=key;904newsimplex.height=height;905newsimplex.vol=0;906907if(multithreaded_pyramid){908#pragma omp atomic909TriangulationBufferSize++;910}911else {912TriangulationBufferSize++;913}914int tn;915if(omp_get_level()==omp_start_level)916tn=0;917else918tn = omp_get_ancestor_thread_num(omp_start_level+1);919920if (do_only_multiplicity) {921// directly compute the volume922if (mother_vol==1)923newsimplex.vol = height;924// the multiplicity is computed in SimplexEvaluator925for(size_t i=0; i<dim; i++) // and needs the key in TopCone numbers926newsimplex.key[i]=Top_Key[newsimplex.key[i]];927928if (keep_triangulation)929sort(newsimplex.key.begin(),newsimplex.key.end());930Top_Cone->SimplexEval[tn].evaluate(newsimplex);931// restore the local generator numbering, needed in extend_triangulation932newsimplex.key=key;933}934if (height == 0) Top_Cone->triangulation_is_partial = true;935936if (keep_triangulation){937Triangulation.push_back(newsimplex);938return;939}940941bool Simpl_available=true;942943typename list< SHORTSIMPLEX<Integer> >::iterator F;944945if(Top_Cone->FS[tn].empty()){946if (Top_Cone->FreeSimpl.empty()) {947Simpl_available=false;948} else {949#pragma omp critical(FREESIMPL)950{951if (Top_Cone->FreeSimpl.empty()) {952Simpl_available=false;953} else {954// take 1000 simplices from FreeSimpl or what you can get955F = Top_Cone->FreeSimpl.begin();956size_t q;957for (q = 0; q < 1000; ++q, ++F) {958if (F == Top_Cone->FreeSimpl.end())959break;960}961962if(q<1000)963Top_Cone->FS[tn].splice(Top_Cone->FS[tn].begin(),964Top_Cone->FreeSimpl);965else966Top_Cone->FS[tn].splice(Top_Cone->FS[tn].begin(),967Top_Cone->FreeSimpl,Top_Cone->FreeSimpl.begin(),F);968} // if empty global (critical)969} // critical970} // if empty global971} // if empty thread972973if (Simpl_available) {974Triangulation.splice(Triangulation.end(),Top_Cone->FS[tn],975Top_Cone->FS[tn].begin());976Triangulation.back() = newsimplex;977} else {978Triangulation.push_back(newsimplex);979}980}981982//---------------------------------------------------------------------------983984template<typename Integer>985void Full_Cone<Integer>::process_pyramids(const size_t new_generator,const bool recursive){986987/*988989We distinguish two types of pyramids:990991(i) recursive pyramids that give their support hyperplanes back to the mother.992(ii) independent pyramids that are not linked to the mother.993994The parameter "recursive" indicates whether the pyramids that will be created995in process_pyramid(s) are of type (i) or (ii).996997Every pyramid can create subpyramids of both types (not the case in version 2.8 - 2.10).998999Whether "this" is of type (i) or (ii) is indicated by do_all_hyperplanes.10001001The creation of (sub)pyramids of type (i) can be blocked by setting recursion_allowed=false.1002(Not done in this version.)10031004is_pyramid==false for the top_cone and ==true else.10051006multithreaded_pyramid indicates whether parallelization takes place within the1007computation of a pyramid or whether it is computed in a single thread (defined in build_cone).10081009Recursie pyramids are processed immediately after creation (as in 2.8). However, there1010are two exceptions:10111012(a) In order to avoid very long waiting times for the computation of the "large" ones,1013these are treated as follows: the support hyperplanes of "this" coming from their bases1014(as negative hyperplanes of "this") are computed by matching them with the1015positive hyperplanes of "this". This Fourier-Motzkin step is much more1016efficient if a pyramid is large. For triangulation a large recursive1017pyramid is then stored as a pyramid of type (ii).10181019(b) If "this" is processed in a parallelized loop calling process_pyramids, then1020the loop in process_pyramids cannot be interrupted for the evaluation of simplices. As a1021consequence an extremely long lst of simplices could arise if many small subpyramids of "this"1022are created in process_pyramids. In order to prevent this dangeous effect, small recursive1023subpyramids are stored for later triangulation if the simplex buffer has reached its1024size bound.10251026Pyramids of type (ii) are stpred in Pyramids. The store_level of the created pyramids is 01027for all pyramids created (possibly recursively) from the top cone. Pyramids created1028in evaluate_stored_pyramids get the store level for their subpyramids in that routine and1029transfer it to their recursive daughters. (correction March 4, 2015).10301031Note: the top cone has pyr_level=-1. The pyr_level has no algorithmic relevance1032at present, but it shows the depth of the pyramid recursion at which the pyramid has been1033created.10341035*/103610371038size_t start_level=omp_get_level(); // allows us to check that we are on level 01039// outside the loop and can therefore call evaluation1040// in order to empty the buffers1041vector<key_t> Pyramid_key;1042Pyramid_key.reserve(nr_gen);1043bool skip_triang; // make hyperplanes but skip triangulation (recursive pyramids only)10441045deque<bool> done(old_nr_supp_hyps,false);1046bool skip_remaining;1047#ifndef NCATCH1048std::exception_ptr tmp_exception;1049#endif1050typename list< FACETDATA >::iterator hyp;1051size_t nr_done=0;10521053do{ // repeats processing until all hyperplanes have been processed10541055hyp=Facets.begin();1056size_t hyppos=0;1057skip_remaining = false;10581059const long VERBOSE_STEPS = 50;1060long step_x_size = old_nr_supp_hyps-VERBOSE_STEPS;1061const size_t RepBound=10000;10621063#pragma omp parallel for private(skip_triang) firstprivate(hyppos,hyp,Pyramid_key) schedule(dynamic) reduction(+: nr_done)1064for (size_t kk=0; kk<old_nr_supp_hyps; ++kk) {10651066if (skip_remaining) continue;10671068if(verbose && old_nr_supp_hyps>=RepBound){1069#pragma omp critical(VERBOSE)1070while ((long)(kk*VERBOSE_STEPS) >= step_x_size) {1071step_x_size += old_nr_supp_hyps;1072verboseOutput() << "." <<flush;1073}1074}10751076#ifndef NCATCH1077try {1078#endif1079for(;kk > hyppos; hyppos++, hyp++) ;1080for(;kk < hyppos; hyppos--, hyp--) ;10811082INTERRUPT_COMPUTATION_BY_EXCEPTION10831084if(done[hyppos])1085continue;10861087done[hyppos]=true;10881089nr_done++;10901091if (hyp->ValNewGen == 0){ // MUST BE SET HERE1092hyp->GenInHyp.set(new_generator);1093if(recursive) hyp->simplicial=false; // in the recursive case1094}10951096if (hyp->ValNewGen >= 0) // facet not visible1097continue;10981099skip_triang = false;1100if (Top_Cone->do_partial_triangulation && hyp->ValNewGen>=-1) { //ht1 criterion1101skip_triang = is_hyperplane_included(*hyp);1102if (skip_triang) {1103Top_Cone->triangulation_is_partial = true;1104if (!recursive) {1105continue;1106}1107}1108}11091110Pyramid_key.clear(); // make data of new pyramid1111Pyramid_key.push_back(new_generator);1112for(size_t i=0;i<nr_gen;i++){1113if(in_triang[i] && hyp->GenInHyp.test(i)) {1114Pyramid_key.push_back(i);1115}1116}11171118// now we can store the new pyramid at the right place (or finish the simplicial ones)1119if (recursive && skip_triang) { // mark as "do not triangulate"1120process_pyramid(Pyramid_key, new_generator,store_level,0, recursive,hyp,start_level);1121} else { //default1122process_pyramid(Pyramid_key, new_generator,store_level,-hyp->ValNewGen, recursive,hyp,start_level);1123}1124// interrupt parallel execution if it is really parallel1125// to keep the triangulationand pyramid buffers under control1126if (start_level==0) {1127if (check_evaluation_buffer_size() || Top_Cone->check_pyr_buffer(store_level)) {1128skip_remaining = true;1129}1130}11311132#ifndef NCATCH1133} catch(const std::exception& ) {1134tmp_exception = std::current_exception();1135skip_remaining = true;1136#pragma omp flush(skip_remaining)1137}1138#endif1139} // end parallel loop over hyperplanes11401141#ifndef NCATCH1142if (!(tmp_exception == 0)) std::rethrow_exception(tmp_exception);1143#endif11441145if (!omp_in_parallel())1146try_offload(0);11471148if (start_level==0 && check_evaluation_buffer_size()) {1149Top_Cone->evaluate_triangulation();1150}11511152if (start_level==0 && Top_Cone->check_pyr_buffer(store_level)) {1153Top_Cone->evaluate_stored_pyramids(store_level);1154}11551156if (verbose && old_nr_supp_hyps>=RepBound)1157verboseOutput() << endl;11581159} while (nr_done < old_nr_supp_hyps);116011611162evaluate_large_rec_pyramids(new_generator);11631164}11651166//---------------------------------------------------------------------------11671168template<typename Integer>1169void Full_Cone<Integer>::process_pyramid(const vector<key_t>& Pyramid_key,1170const size_t new_generator,const size_t store_level, Integer height, const bool recursive,1171typename list< FACETDATA >::iterator hyp, size_t start_level){1172// processes simplicial pyramids directly, stores other pyramids into their depots11731174#pragma omp atomic1175Top_Cone->totalNrPyr++;11761177if(Pyramid_key.size()==dim){ // simplicial pyramid completely done here1178#pragma omp atomic // only for saving memory1179Top_Cone->nrSimplicialPyr++;1180if(recursive){ // the facets may be facets of the mother cone and if recursive==true must be given back1181Matrix<Integer> H(dim,dim);1182Integer dummy_vol;1183Generators.simplex_data(Pyramid_key,H, dummy_vol,false);1184list<FACETDATA> NewFacets;1185FACETDATA NewFacet;1186NewFacet.GenInHyp.resize(nr_gen);1187for (size_t i=0; i<dim;i++) {1188NewFacet.Hyp = H[i];1189NewFacet.GenInHyp.set();1190NewFacet.GenInHyp.reset(i);1191NewFacet.simplicial=true;1192NewFacet.is_positive_on_all_original_gens=false;1193NewFacet.is_negative_on_some_original_gen=false;1194NewFacets.push_back(NewFacet);1195}1196select_supphyps_from(NewFacets,new_generator,Pyramid_key); // takes itself care of multithreaded_pyramid1197}1198if (height != 0 && (do_triangulation || do_partial_triangulation)) {1199if(multithreaded_pyramid) {1200#ifndef NCATCH1201std::exception_ptr tmp_exception;1202#endif1203#pragma omp critical(TRIANG)1204{1205#ifndef NCATCH1206try{1207#endif1208store_key(Pyramid_key,height,0,TriangulationBuffer);1209nrTotalComparisons+=dim*dim/2;1210#ifndef NCATCH1211} catch(const std::exception& ) {1212tmp_exception = std::current_exception();1213}1214#endif1215} // end critical1216#ifndef NCATCH1217if (!(tmp_exception == 0)) std::rethrow_exception(tmp_exception);1218#endif1219} else {1220store_key(Pyramid_key,height,0,TriangulationBuffer);1221nrTotalComparisons+=dim*dim/2;1222}1223}1224}1225else { // non-simplicial12261227bool large=(largePyramidFactor*Comparisons[Pyramid_key.size()-dim] > old_nr_supp_hyps); // Pyramid_key.size()>largePyramidFactor*dim;12281229if (!recursive || (large && (do_triangulation || do_partial_triangulation) && height!=0) ) { // must also store for triangulation if recursive and large1230vector<key_t> key_wrt_top(Pyramid_key.size());1231for(size_t i=0;i<Pyramid_key.size();i++)1232key_wrt_top[i]=Top_Key[Pyramid_key[i]];1233#pragma omp critical(STOREPYRAMIDS)1234{1235// cout << "store_level " << store_level << " large " << large << " pyr level " << pyr_level << endl;1236Top_Cone->Pyramids[store_level].push_back(key_wrt_top);1237Top_Cone->nrPyramids[store_level]++;1238} // critical1239if(!recursive) // in this case we need only store for future triangulation, and that has been done1240return;1241}1242// now we are in the recursive case and must compute support hyperplanes of the subpyramid1243if(large){ // large recursive pyramid1244if(multithreaded_pyramid){1245#pragma omp critical(LARGERECPYRS)1246LargeRecPyrs.push_back(*hyp); // LargeRecPyrs are kept and evaluated locally1247}1248else1249LargeRecPyrs.push_back(*hyp);1250return; // done with the large recusive pyramids1251}12521253// only recursive small ones left12541255Full_Cone<Integer> Pyramid(*this,Pyramid_key);1256Pyramid.Mother = this;1257Pyramid.Mother_Key = Pyramid_key; // need these data to give back supphyps1258Pyramid.apex=new_generator;1259if (height == 0) { //indicates "do not triangulate"1260Pyramid.do_triangulation = false;1261Pyramid.do_partial_triangulation = false;1262Pyramid.do_Hilbert_basis = false;1263Pyramid.do_deg1_elements=false;1264}12651266bool store_for_triangulation=(store_level!=0) //loop in process_pyramids cannot be interrupted1267&& (Pyramid.do_triangulation || Pyramid.do_partial_triangulation) // we must (partially) triangulate1268&& (start_level!=0 && Top_Cone->TriangulationBufferSize > 2*EvalBoundTriang); // evaluation buffer already full // EvalBoundTriang12691270if (store_for_triangulation) {1271vector<key_t> key_wrt_top(Pyramid_key.size());1272for(size_t i=0;i<Pyramid_key.size();i++)1273key_wrt_top[i]=Top_Key[Pyramid_key[i]];1274#pragma omp critical(STOREPYRAMIDS)1275{1276Top_Cone->Pyramids[store_level].push_back(key_wrt_top);1277Top_Cone->nrPyramids[store_level]++;1278} // critical1279// Now we must suppress immediate triangulation1280Pyramid.do_triangulation = false;1281Pyramid.do_partial_triangulation = false;1282Pyramid.do_Hilbert_basis = false;1283Pyramid.do_deg1_elements=false;1284}12851286Pyramid.build_cone();12871288if(multithreaded_pyramid){1289#pragma omp atomic1290nrTotalComparisons+=Pyramid.nrTotalComparisons;1291} else1292nrTotalComparisons+=Pyramid.nrTotalComparisons;1293} // else non-simplicial1294}129512961297//---------------------------------------------------------------------------12981299template<typename Integer>1300void Full_Cone<Integer>::find_and_evaluate_start_simplex(){13011302size_t i,j;1303Integer factor;130413051306/* Simplex<Integer> S = find_start_simplex();1307vector<key_t> key=S.read_key(); // generators indexed from 0 */13081309vector<key_t> key=find_start_simplex();1310assert(key.size()==dim); // safety heck1311if(verbose){1312verboseOutput() << "Start simplex ";1313for(size_t i=0;i<key.size();++i)1314verboseOutput() << key[i]+1 << " ";1315verboseOutput() << endl;1316}1317Matrix<Integer> H(dim,dim);1318Integer vol;1319Generators.simplex_data(key,H,vol,do_partial_triangulation || do_triangulation);13201321// H.pretty_print(cout);132213231324for (i = 0; i < dim; i++) {1325in_triang[key[i]]=true;1326GensInCone.push_back(key[i]);1327if (deg1_triangulation && isComputed(ConeProperty::Grading))1328deg1_triangulation = (gen_degrees[key[i]] == 1);1329}13301331nrGensInCone=dim;13321333nrTotalComparisons=dim*dim/2;1334if(using_GMP<Integer>())1335nrTotalComparisons*=GMP_time_factor; // because of the linear algebra involved in this routine1336Comparisons.push_back(nrTotalComparisons);13371338for (i = 0; i <dim; i++) {1339FACETDATA NewFacet; NewFacet.GenInHyp.resize(nr_gen);1340NewFacet.is_positive_on_all_original_gens=false;1341NewFacet.is_negative_on_some_original_gen=false;1342NewFacet.Hyp=H[i];1343NewFacet.simplicial=true; // indeed, the start simplex is simplicial1344for(j=0;j < dim;j++)1345if(j!=i)1346NewFacet.GenInHyp.set(key[j]);1347NewFacet.ValNewGen=-1; // must be taken negative since opposite facet1348number_hyperplane(NewFacet,0,0); // created with gen 01349Facets.push_back(NewFacet); // was visible before adding this vertex1350}13511352if(!is_pyramid){1353//define Order_Vector, decides which facets of the simplices are excluded1354Order_Vector = vector<Integer>(dim,0);1355// Matrix<Integer> G=S.read_generators();1356for(i=0;i<dim;i++){1357factor=(unsigned long) (1+i%10); // (2*(rand()%(2*dim))+3);1358for(j=0;j<dim;j++)1359Order_Vector[j]+=factor*Generators[key[i]][j];1360}1361}13621363//the volume is an upper bound for the height1364if(do_triangulation || (do_partial_triangulation && vol>1))1365{1366store_key(key,vol,1,TriangulationBuffer);1367if(do_only_multiplicity) {1368#pragma omp atomic1369TotDet++;1370}1371} else if (do_partial_triangulation) {1372triangulation_is_partial = true;1373}13741375if(do_triangulation){ // we must prepare the sections of the triangulation1376for(i=0;i<dim;i++)1377{1378// GensInCone.push_back(key[i]); // now done in first loop since always needed1379TriSectionFirst.push_back(TriangulationBuffer.begin());1380TriSectionLast.push_back(TriangulationBuffer.begin());1381}1382}13831384}138513861387//---------------------------------------------------------------------------13881389template<typename Integer>1390void Full_Cone<Integer>::select_supphyps_from(const list<FACETDATA>& NewFacets,1391const size_t new_generator, const vector<key_t>& Pyramid_key){1392// the mother cone (=this) selects supphyps from the list NewFacets supplied by the daughter1393// the daughter provides the necessary information via the parameters13941395size_t i;1396boost::dynamic_bitset<> in_Pyr(nr_gen);1397for (i=0; i<Pyramid_key.size(); i++) {1398in_Pyr.set(Pyramid_key[i]);1399}1400// the new generator is always the first in the pyramid1401assert(Pyramid_key[0] == new_generator);140214031404typename list<FACETDATA>::const_iterator pyr_hyp = NewFacets.begin();1405bool new_global_hyp;1406FACETDATA NewFacet;1407NewFacet.is_positive_on_all_original_gens=false;1408NewFacet.is_negative_on_some_original_gen=false;1409NewFacet.GenInHyp.resize(nr_gen);1410Integer test;1411for (; pyr_hyp!=NewFacets.end(); ++pyr_hyp) {1412if(!pyr_hyp->GenInHyp.test(0)) // new gen not in hyp1413continue;1414new_global_hyp=true;1415for (i=0; i<nr_gen; ++i){1416if(in_Pyr.test(i) || !in_triang[i])1417continue;1418test=v_scalar_product(Generators[i],pyr_hyp->Hyp);1419if(test<=0){1420new_global_hyp=false;1421break;1422}14231424}1425if(new_global_hyp){1426NewFacet.Hyp=pyr_hyp->Hyp;1427NewFacet.GenInHyp.reset();1428// size_t gens_in_facet=0;1429for (i=0; i<Pyramid_key.size(); ++i) {1430if (pyr_hyp->GenInHyp.test(i) && in_triang[Pyramid_key[i]]) {1431NewFacet.GenInHyp.set(Pyramid_key[i]);1432// gens_in_facet++;1433}1434}1435/* for (i=0; i<nr_gen; ++i) {1436if (NewFacet.GenInHyp.test(i) && in_triang[i]) {1437gens_in_facet++;1438}1439}*/1440// gens_in_facet++; // Note: new generator not yet in in_triang1441NewFacet.GenInHyp.set(new_generator);1442NewFacet.simplicial=pyr_hyp->simplicial; // (gens_in_facet==dim-1);1443check_simpliciality_hyperplane(NewFacet);1444number_hyperplane(NewFacet,nrGensInCone,0); //mother unknown1445if(multithreaded_pyramid){1446#pragma omp critical(GIVEBACKHYPS)1447Facets.push_back(NewFacet);1448} else {1449Facets.push_back(NewFacet);1450}1451}1452}1453}14541455//---------------------------------------------------------------------------1456template<typename Integer>1457void Full_Cone<Integer>::match_neg_hyp_with_pos_hyps(const FACETDATA& hyp, size_t new_generator,list<FACETDATA*>& PosHyps, boost::dynamic_bitset<>& Zero_P){14581459size_t missing_bound, nr_common_zero;1460boost::dynamic_bitset<> common_zero(nr_gen);1461vector<key_t> common_key;1462common_key.reserve(nr_gen);1463vector<key_t> key(nr_gen);1464bool common_subfacet;1465list<FACETDATA> NewHyp;1466size_t subfacet_dim=dim-2;1467size_t nr_missing;1468typename list<FACETDATA*>::iterator a;1469list<FACETDATA> NewHyps;1470Matrix<Integer> Test(0,dim);14711472boost::dynamic_bitset<> zero_hyp=hyp.GenInHyp & Zero_P; // we intersect with the set of gens in positive hyps14731474vector<int> key_start(nrGensInCone);1475size_t nr_zero_hyp=0;1476size_t j;1477int last_existing=-1;1478for(size_t jj=0;jj<nrGensInCone;jj++)1479{1480j=GensInCone[jj];1481if(zero_hyp.test(j)){1482key[nr_zero_hyp]=j;1483for(size_t kk= last_existing+1;kk<=jj;kk++)1484key_start[kk]=nr_zero_hyp;1485nr_zero_hyp++;1486last_existing= jj;1487}1488}1489if(last_existing< (int)nrGensInCone-1)1490for(size_t kk=last_existing+1;kk<nrGensInCone;kk++)1491key_start[kk]=nr_zero_hyp;14921493if (nr_zero_hyp<dim-2)1494return;14951496int tn = omp_get_ancestor_thread_num(omp_start_level+1);1497missing_bound=nr_zero_hyp-subfacet_dim; // at most this number of generators can be missing1498// to have a chance for common subfacet14991500typename list< FACETDATA*>::iterator hp_j_iterator=PosHyps.begin();15011502FACETDATA* hp_j;15031504for (;hp_j_iterator!=PosHyps.end();++hp_j_iterator){ //match hyp with the given Pos1505hp_j=*hp_j_iterator;15061507if(hyp.Ident==hp_j->Mother || hp_j->Ident==hyp.Mother){ // mother and daughter coming together1508// their intersection is a subfacet1509add_hyperplane(new_generator,*hp_j,hyp,NewHyps,false); // simplicial set in add_hyperplane1510continue;1511}151215131514bool extension_test=hyp.BornAt==hp_j->BornAt || (hyp.BornAt<hp_j->BornAt && hp_j->Mother!=0)1515|| (hp_j->BornAt<hyp.BornAt && hyp.Mother!=0);15161517size_t both_existing_from=key_start[max(hyp.BornAt,hp_j->BornAt)];15181519nr_missing=0;1520nr_common_zero=0;1521common_key.clear();1522size_t second_loop_bound=nr_zero_hyp;1523common_subfacet=true;1524boost::dynamic_bitset<> common_zero(nr_gen);15251526if(extension_test){1527bool extended=false;1528second_loop_bound=both_existing_from;1529for(size_t k=both_existing_from;k<nr_zero_hyp;k++){1530if(!hp_j->GenInHyp.test(key[k])) {1531nr_missing++;1532if(nr_missing>missing_bound) {1533common_subfacet=false;1534break;1535}1536}1537else {1538extended=true;1539common_key.push_back(key[k]);1540common_zero.set(key[k]);1541nr_common_zero++;1542}1543}15441545if(!extended || !common_subfacet) //1546continue;1547}15481549for(size_t k=0;k<second_loop_bound;k++) {1550if(!hp_j->GenInHyp.test(key[k])) {1551nr_missing++;1552if(nr_missing>missing_bound) {1553common_subfacet=false;1554break;1555}1556}1557else {1558common_key.push_back(key[k]);1559common_zero.set(key[k]);1560nr_common_zero++;1561}1562}15631564if(!common_subfacet)1565continue;15661567assert(nr_common_zero >=subfacet_dim);156815691570if (!hp_j->simplicial){15711572bool ranktest;1573/* if(using_GMP<Integer>())1574ranktest = (old_nr_supp_hyps > 10*GMP_time_factor*dim*dim*nr_common_zero/3); // in this case the rank computation takes longer1575else1576ranktest = (old_nr_supp_hyps > 10*dim*dim*nr_common_zero/3); */15771578ranktest=true;15791580if(ranktest){1581// cout << "Rank" << endl;1582Matrix<Integer>& Test = Top_Cone->RankTest[tn];1583if(Test.rank_submatrix(Generators,common_key)<subfacet_dim)1584common_subfacet=false; // don't make a hyperplane1585}1586else{ // now the comparison test1587// cout << "Compare" << endl;1588auto hp_t=Facets.begin();1589for (;hp_t!=Facets.end();++hp_t){1590if(hp_t->simplicial)1591continue;1592if ((hp_t->Ident!=hyp.Ident) && (hp_t->Ident!=hp_j->Ident) && common_zero.is_subset_of(hp_t->GenInHyp)) {1593common_subfacet=false;1594break;1595}1596}1597} // else1598} // !simplicial15991600if(common_subfacet)1601add_hyperplane(new_generator,*hp_j,hyp,NewHyps,false); // simplicial set in add_hyperplane1602} // for16031604if(multithreaded_pyramid)1605#pragma omp critical(GIVEBACKHYPS)1606Facets.splice(Facets.end(),NewHyps);1607else1608Facets.splice(Facets.end(),NewHyps);16091610}16111612//---------------------------------------------------------------------------1613template<typename Integer>1614void Full_Cone<Integer>::collect_pos_supphyps(list<FACETDATA*>& PosHyps, boost::dynamic_bitset<>& Zero_P, size_t& nr_pos){16151616// positive facets are collected in a list16171618typename list<FACETDATA>::iterator ii = Facets.begin();1619nr_pos=0;16201621for (size_t ij=0; ij< old_nr_supp_hyps; ++ij, ++ii)1622if (ii->ValNewGen>0) {1623Zero_P |= ii->GenInHyp;1624PosHyps.push_back(&(*ii));1625nr_pos++;1626}1627}16281629//---------------------------------------------------------------------------1630template<typename Integer>1631void Full_Cone<Integer>::evaluate_large_rec_pyramids(size_t new_generator){16321633size_t nrLargeRecPyrs=LargeRecPyrs.size();1634if(nrLargeRecPyrs==0)1635return;16361637if(verbose)1638verboseOutput() << "large pyramids " << nrLargeRecPyrs << endl;16391640list<FACETDATA*> PosHyps;1641boost::dynamic_bitset<> Zero_P(nr_gen);1642size_t nr_pos;1643collect_pos_supphyps(PosHyps,Zero_P,nr_pos);16441645nrTotalComparisons+=nr_pos*nrLargeRecPyrs;1646#ifndef NCATCH1647std::exception_ptr tmp_exception;1648#endif16491650const long VERBOSE_STEPS = 50;1651long step_x_size = nrLargeRecPyrs-VERBOSE_STEPS;1652const size_t RepBound=100;16531654bool skip_remaining=false;16551656#pragma omp parallel1657{1658size_t ppos=0;1659typename list<FACETDATA>::iterator p=LargeRecPyrs.begin();16601661#pragma omp for schedule(dynamic)1662for(size_t i=0; i<nrLargeRecPyrs; i++){16631664if(skip_remaining)1665continue;16661667for(; i > ppos; ++ppos, ++p) ;1668for(; i < ppos; --ppos, --p) ;16691670if(verbose && nrLargeRecPyrs>=RepBound){1671#pragma omp critical(VERBOSE)1672while ((long)(i*VERBOSE_STEPS) >= step_x_size) {1673step_x_size += nrLargeRecPyrs;1674verboseOutput() << "." <<flush;1675}1676}16771678#ifndef NCATCH1679try {1680#endif16811682INTERRUPT_COMPUTATION_BY_EXCEPTION16831684match_neg_hyp_with_pos_hyps(*p,new_generator,PosHyps,Zero_P);1685#ifndef NCATCH1686} catch(const std::exception& ) {1687tmp_exception = std::current_exception();1688skip_remaining = true;1689#pragma omp flush(skip_remaining)1690}1691#endif1692}1693} // parallel1694#ifndef NCATCH1695if (!(tmp_exception == 0)) std::rethrow_exception(tmp_exception);1696#endif16971698if(verbose && nrLargeRecPyrs>=RepBound)1699verboseOutput() << endl;17001701LargeRecPyrs.clear();1702}17031704//---------------------------------------------------------------------------17051706template<typename Integer>1707bool Full_Cone<Integer>::check_pyr_buffer(const size_t level){1708if(level==0)1709return(nrPyramids[0] > EvalBoundLevel0Pyr);1710else1711return(nrPyramids[level] > EvalBoundPyr);1712}17131714//---------------------------------------------------------------------------17151716#ifdef NMZ_MIC_OFFLOAD1717template<>1718void Full_Cone<long long>::try_offload(size_t max_level) {17191720if (!is_pyramid && _Offload_get_device_number() < 0) // dynamic check for being on CPU (-1)1721{17221723if (max_level >= nrPyramids.size()) max_level = nrPyramids.size()-1;1724for (size_t level = 0; level <= max_level; ++level) {1725if (nrPyramids[level] >= 100) {1726// cout << "XXX: Try offload of level " << level << " pyramids ..." << endl;1727mic_offloader.offload_pyramids(*this, level);1728break;1729}1730}1731}1732}17331734template<typename Integer>1735void Full_Cone<Integer>::try_offload(size_t max_level) {1736}1737//else it is implemented in the header173817391740template<typename Integer>1741void Full_Cone<Integer>::try_offload_loc(long place,size_t max_level){1742verboseOutput() << "From place " << place << " " << "level " << max_level << endl;1743try_offload(max_level);1744}17451746#endif // NMZ_MIC_OFFLOAD17471748//---------------------------------------------------------------------------17491750template<typename Integer>1751void Full_Cone<Integer>::evaluate_stored_pyramids(const size_t level){1752// evaluates the stored non-recursive pyramids17531754#ifdef NMZ_MIC_OFFLOAD1755Pyramids_scrambled[level]=false;17561757if(level==0 && _Offload_get_device_number() >= 0){1758verboseOutput() << "Start evaluation of " << nrPyramids[level] << " pyrs on level " << level << endl;1759// verboseOutput() << "In parallel " << omp_in_parallel() << endl;1760}1761#endif // NMZ_MIC_OFFLOAD17621763if(Pyramids[level].empty())1764return;17651766assert(omp_get_level()==omp_start_level); // assert(!omp_in_parallel());1767assert(!is_pyramid);17681769if (Pyramids.size() < level+2) {1770Pyramids.resize(level+2); // provide space for a new generation1771nrPyramids.resize(level+2, 0);1772Pyramids_scrambled.resize(level+2, false);1773}17741775size_t eval_down_to = 0;17761777#ifdef NMZ_MIC_OFFLOAD1778#ifndef __MIC__1779// only on host and if offload is available1780if (level == 0 && nrPyramids[0] > EvalBoundLevel0Pyr) {1781eval_down_to = EvalBoundLevel0Pyr;1782}1783#endif1784#endif17851786vector<char> Done(nrPyramids[level],0);1787if (verbose) {1788verboseOutput() << "**************************************************" << endl;17891790for (size_t l=0; l<=level; ++l) {1791if (nrPyramids[l]>0) {1792verboseOutput() << "level " << l << " pyramids remaining: "1793<< nrPyramids[l] << endl;1794}1795}1796verboseOutput() << "**************************************************" << endl;1797}1798typename list<vector<key_t> >::iterator p;1799size_t ppos;1800bool skip_remaining;1801#ifndef NCATCH1802std::exception_ptr tmp_exception;1803#endif18041805while (nrPyramids[level] > eval_down_to) {18061807p = Pyramids[level].begin();1808ppos=0;1809skip_remaining = false;18101811#pragma omp parallel for firstprivate(p,ppos) schedule(dynamic)1812for(size_t i=0; i<nrPyramids[level]; i++){1813if (skip_remaining)1814continue;1815for(; i > ppos; ++ppos, ++p) ;1816for(; i < ppos; --ppos, --p) ;18171818if(Done[i])1819continue;1820Done[i]=1;18211822#ifndef NCATCH1823try {1824#endif1825INTERRUPT_COMPUTATION_BY_EXCEPTION18261827Full_Cone<Integer> Pyramid(*this,*p);1828// Pyramid.recursion_allowed=false;1829Pyramid.do_all_hyperplanes=false;1830if (level>=2 && do_partial_triangulation){ // limits the descent of do_partial_triangulation1831Pyramid.do_triangulation=true;1832Pyramid.do_partial_triangulation=false;1833}1834Pyramid.store_level=level+1;1835Pyramid.build_cone();1836if (check_evaluation_buffer_size() || Top_Cone->check_pyr_buffer(level+1)) {1837// interrupt parallel execution to keep the buffer under control1838skip_remaining = true;1839}1840#ifndef NCATCH1841} catch(const std::exception& ) {1842tmp_exception = std::current_exception();1843skip_remaining = true;1844#pragma omp flush(skip_remaining)1845}1846#endif1847} //end parallel for1848#ifndef NCATCH1849if (!(tmp_exception == 0)) std::rethrow_exception(tmp_exception);1850#endif18511852// remove done pyramids1853p = Pyramids[level].begin();1854for(size_t i=0; p != Pyramids[level].end(); i++){1855if (Done[i]) {1856p=Pyramids[level].erase(p);1857nrPyramids[level]--;1858Done[i]=0;1859} else {1860++p;1861}1862}18631864try_offload(level+1);18651866if (check_evaluation_buffer_size()) {1867if (verbose)1868verboseOutput() << nrPyramids[level] <<1869" pyramids remaining on level " << level << ", ";1870Top_Cone->evaluate_triangulation();1871try_offload(level+1);1872}18731874if (Top_Cone->check_pyr_buffer(level+1)) {1875evaluate_stored_pyramids(level+1);1876}18771878} //end while (nrPyramids[level] > 0)18791880if (verbose) {1881verboseOutput() << "**************************************************" << endl;1882verboseOutput() << "all pyramids on level "<< level << " done!"<<endl;1883if (nrPyramids[level+1] == 0) {1884for (size_t l=0; l<=level; ++l) {1885if (nrPyramids[l]>0) {1886verboseOutput() << "level " << l << " pyramids remaining: "1887<< nrPyramids[l] << endl;1888}1889}1890verboseOutput() << "**************************************************" << endl;1891}1892}1893if(check_evaluation_buffer())1894{1895Top_Cone->evaluate_triangulation();1896}18971898evaluate_stored_pyramids(level+1);1899}1900190119021903//---------------------------------------------------------------------------19041905/* builds the cone successively by inserting generators */1906template<typename Integer>1907void Full_Cone<Integer>::build_cone() {1908// if(dim>0){ //correction needed to include the 0 cone;19091910// cout << "Pyr " << pyr_level << endl;19111912long long RecBoundSuppHyp;1913RecBoundSuppHyp = dim*dim*dim*SuppHypRecursionFactor; //dim^3 * 501914if(using_GMP<Integer>())1915RecBoundSuppHyp*=GMP_time_factor; // pyramid building is more difficult for complicated arithmetic19161917size_t RecBoundTriang=1000000; // if number(supphyps)*size(triang) > RecBoundTriang pass to pyramids1918if(using_GMP<Integer>())1919RecBoundTriang*=GMP_time_factor;19201921tri_recursion=false;19221923multithreaded_pyramid=(omp_get_level()==omp_start_level);19241925size_t nr_original_gen=0;1926size_t steps_in_approximation = 0;1927if (!is_pyramid && is_approximation)1928{1929nr_original_gen = OriginalGenerators.nr_of_rows();1930vector<size_t> nr_approx_points; // how many points are in the approximation1931for (size_t j=0;j<nr_original_gen;++j) {1932nr_approx_points.push_back(approx_points_keys[j].size());1933}1934// for every vertex sort the approximation points via: number of positive halfspaces / index1935vector<key_t> overall_perm;1936// stores the perm of every list1937vector<vector<key_t>> local_perms(nr_original_gen);19381939for (size_t current_gen = 0 ; current_gen<nr_original_gen;++current_gen){1940vector<key_t> local_perm;1941if (approx_points_keys[current_gen].size()>0){1942auto jt=approx_points_keys[current_gen].begin();1943list<pair<size_t,key_t>> max_halfspace_index_list;1944size_t tmp_hyp=0;1945// TODO: collect only those which belong to the current generator?1946for (;jt!=approx_points_keys[current_gen].end();++jt){1947// cout << dim << " " << Support_Hyperplanes.nr_of_columns()<< " " << Generators[*jt].size() << endl;1948tmp_hyp = v_nr_negative(Support_Hyperplanes.MxV(Generators[*jt])); // nr of negative halfspaces1949max_halfspace_index_list.insert(max_halfspace_index_list.end(),make_pair(tmp_hyp,*jt));1950}1951max_halfspace_index_list.sort([](const pair<size_t,key_t> &left, const pair<size_t,key_t> &right) {1952return right.first < left.first;1953});1954auto list_it = max_halfspace_index_list.begin();1955for(;list_it!=max_halfspace_index_list.end();++list_it){1956local_perm.push_back(list_it->second);1957}1958}1959local_perms[current_gen]=local_perm;1960}1961// concatenate the permutations1962size_t local_perm_counter=0;1963bool not_done = true;1964while (not_done){1965not_done=false;1966for (size_t current_gen=0;current_gen<nr_original_gen;++current_gen){1967if (local_perm_counter<nr_approx_points[current_gen]){1968not_done=true;1969overall_perm.push_back(local_perms[current_gen][local_perm_counter]);1970}1971}1972++local_perm_counter;1973}1974assert(overall_perm.size()==nr_gen);1975// sort the generators according to the permutations1976Generators.order_rows_by_perm(overall_perm);1977}19781979if(!use_existing_facets){1980if(multithreaded_pyramid){1981HypCounter.resize(omp_get_max_threads());1982for(size_t i=0;i<HypCounter.size();++i)1983HypCounter[i]=i+1;1984} else{1985HypCounter.resize(1);1986HypCounter[0]=1;1987}19881989find_and_evaluate_start_simplex();1990}19911992size_t last_to_be_inserted; // good to know in case of do_all_hyperplanes==false1993last_to_be_inserted=nr_gen-1; // because we don't need to compute support hyperplanes in this case1994for(int j=nr_gen-1;j>=0;--j){1995if(!in_triang[j]){1996last_to_be_inserted=j;1997break;1998}1999} // last_to_be_inserted now determined20002001bool is_new_generator;2002typename list< FACETDATA >::iterator l;20032004bool check_original_gens=true;20052006for (size_t i=start_from;i<nr_gen;++i) {20072008INTERRUPT_COMPUTATION_BY_EXCEPTION20092010time_t start,end;2011time (&start);20122013start_from=i;20142015if (in_triang[i])2016continue;20172018if (!is_pyramid && is_approximation) steps_in_approximation++;2019// we check whether all original generators are contained in the current cone2020if (!is_pyramid && is_approximation && check_original_gens){2021if (verbose)2022verboseOutput() << "Check...";2023size_t current_gen=0;2024l=Facets.begin();2025for (;l!=Facets.end();++l){2026if (l->is_positive_on_all_original_gens) continue;2027for (current_gen=0;current_gen<nr_original_gen;++current_gen){2028if (!v_scalar_product_nonnegative(l->Hyp,OriginalGenerators[current_gen])) {2029l->is_negative_on_some_original_gen=true;2030check_original_gens=false;2031break;2032}2033}2034if (current_gen==nr_original_gen){2035l->is_positive_on_all_original_gens=true;2036} else {2037break;2038}2039}2040if(verbose)2041verboseOutput() << " done." << endl;2042// now we need to stop2043if (l==Facets.end()){2044if(verbose)2045verboseOutput() << "The original cone is now contained." << endl;2046break;2047}2048}20492050if(do_triangulation && TriangulationBufferSize > 2*RecBoundTriang) // emermergency brake2051tri_recursion=true; // to switch off production of simplices in favor2052// of non-recursive pyramids2053Integer scalar_product;2054is_new_generator=false;2055l=Facets.begin();2056old_nr_supp_hyps=Facets.size(); // Facets will be xtended in the loop20572058long long nr_pos=0, nr_neg=0;2059long long nr_neg_simp=0, nr_pos_simp=0;2060vector<Integer> L;2061#ifndef NCATCH2062std::exception_ptr tmp_exception;2063#endif20642065size_t lpos=0;2066#pragma omp parallel for private(L,scalar_product) firstprivate(lpos,l) reduction(+: nr_pos, nr_neg)2067for (size_t k=0; k<old_nr_supp_hyps; k++) {2068#ifndef NCATCH2069try {2070#endif2071for(;k > lpos; lpos++, l++) ;2072for(;k < lpos; lpos--, l--) ;20732074L=Generators[i];2075scalar_product=v_scalar_product(L,(*l).Hyp);2076l->ValNewGen=scalar_product;2077if (scalar_product<0) {2078is_new_generator=true;2079nr_neg++;2080if(l->simplicial)2081#pragma omp atomic2082nr_neg_simp++;2083}2084if (scalar_product>0) {2085nr_pos++;2086if(l->simplicial)2087#pragma omp atomic2088nr_pos_simp++;2089}2090#ifndef NCATCH2091} catch(const std::exception& ) {2092tmp_exception = std::current_exception();2093}2094#endif2095} //end parallel for2096#ifndef NCATCH2097if (!(tmp_exception == 0)) std::rethrow_exception(tmp_exception);2098#endif20992100if(!is_new_generator)2101continue;21022103// the i-th generator is used in the triangulation2104// in_triang[i]=true; // now at end of loop2105if (deg1_triangulation && isComputed(ConeProperty::Grading))2106deg1_triangulation = (gen_degrees[i] == 1);21072108if (!omp_in_parallel())2109try_offload(0);2110/* if(!is_pyramid && verbose )2111verboseOutput() << "Neg " << nr_neg << " Pos " << nr_pos << " NegSimp " <<nr_neg_simp << " PosSimp " <<nr_pos_simp << endl; */2112// First we test whether to go to recursive pyramids because of too many supphyps2113if (recursion_allowed && nr_neg*nr_pos-(nr_neg_simp*nr_pos_simp) > RecBoundSuppHyp) { // use pyramids because of supphyps2114if(!is_pyramid && verbose )2115verboseOutput() << "Building pyramids" << endl;2116if (do_triangulation)2117tri_recursion = true; // We can not go back to classical triangulation2118if(check_evaluation_buffer()){2119Top_Cone->evaluate_triangulation();2120}21212122process_pyramids(i,true); //recursive2123lastGen=i;2124nextGen=i+1;2125}2126else{ // now we check whether to go to pyramids because of the size of triangulation2127// once we have done so, we must stay with it2128if( tri_recursion || (do_triangulation2129&& (nr_neg*TriangulationBufferSize > RecBoundTriang2130|| 3*omp_get_max_threads()*TriangulationBufferSize>EvalBoundTriang ))){ // go to pyramids because of triangulation2131if(check_evaluation_buffer()){2132Top_Cone->evaluate_triangulation();2133}2134tri_recursion=true;2135process_pyramids(i,false); //non-recursive2136}2137else{ // no pyramids necesary2138if(do_partial_triangulation)2139process_pyramids(i,false); // non-recursive2140if(do_triangulation)2141extend_triangulation(i);2142}21432144if(do_all_hyperplanes || i!=last_to_be_inserted)2145find_new_facets(i);2146}2147size_t nr_new_facets = Facets.size() - old_nr_supp_hyps;2148time (&end);2149/* double dif = difftime (end,start);21502151if (verbose) {2152verboseOutput() << "Generator took " << dif << " sec " <<endl;2153}*/21542155// removing the negative hyperplanes if necessary2156if(do_all_hyperplanes || i!=last_to_be_inserted){2157l=Facets.begin();2158for (size_t j=0; j<old_nr_supp_hyps;j++){2159if (l->ValNewGen<0) {2160if (is_approximation && l->is_negative_on_some_original_gen){2161check_original_gens = true;2162}2163l=Facets.erase(l);2164}2165else2166++l;2167}2168}21692170GensInCone.push_back(i);2171nrGensInCone++;21722173Comparisons.push_back(nrTotalComparisons);21742175if(verbose) {2176verboseOutput() << "gen="<< i+1 <<", ";2177if (do_all_hyperplanes || i!=last_to_be_inserted) {2178verboseOutput() << Facets.size()<<" hyp, " << nr_new_facets << " new";2179} else {2180verboseOutput() << Support_Hyperplanes.nr_of_rows()<<" hyp";2181}2182if(nrPyramids[0]>0)2183verboseOutput() << ", " << nrPyramids[0] << " pyr";2184if(do_triangulation||do_partial_triangulation)2185verboseOutput() << ", " << TriangulationBufferSize << " simpl";2186verboseOutput()<< endl;2187}21882189in_triang[i]=true;21902191} // loop over i21922193start_from=nr_gen;21942195if (is_pyramid && do_all_hyperplanes) // must give supphyps back to mother2196Mother->select_supphyps_from(Facets, apex, Mother_Key);21972198INTERRUPT_COMPUTATION_BY_EXCEPTION21992200// transfer Facets --> SupportHyperplanes2201if (do_all_hyperplanes) {2202nrSupport_Hyperplanes = Facets.size();2203Support_Hyperplanes = Matrix<Integer>(nrSupport_Hyperplanes,0);2204typename list<FACETDATA>::iterator IHV=Facets.begin();2205for (size_t i=0; i<nrSupport_Hyperplanes; ++i, ++IHV) {2206swap(Support_Hyperplanes[i],IHV->Hyp);2207}2208is_Computed.set(ConeProperty::SupportHyperplanes);2209}2210Support_Hyperplanes.set_nr_of_columns(dim);221122122213if(do_extreme_rays && do_all_hyperplanes)2214compute_extreme_rays(true);22152216INTERRUPT_COMPUTATION_BY_EXCEPTION22172218transfer_triangulation_to_top(); // transfer remaining simplices to top2219if(check_evaluation_buffer()){2220Top_Cone->evaluate_triangulation();2221}22222223if (!is_pyramid && is_approximation && verbose){2224verboseOutput() << "Performed " << steps_in_approximation << "/" << nr_gen << " steps." << endl;2225}2226// } // end if (dim>0)22272228Facets.clear();22292230}22312232//---------------------------------------------------------------------------22332234template<typename Integer>2235void Full_Cone<Integer>::find_bottom_facets() {22362237if(verbose)2238verboseOutput() << "Computing bottom decomposition" << endl;22392240vector<key_t> start_simpl=Generators.max_rank_submatrix_lex();2241Order_Vector = vector<Integer>(dim,0);2242for(size_t i=0;i<dim;++i)2243for(size_t j=0;j<dim;++j)2244Order_Vector[j]+=((unsigned long) (1+i%10))*Generators[start_simpl[i]][j];22452246// First the generators for the recession cone = our cone2247Matrix<Integer> BottomGen(0,dim+1);2248vector<Integer> help(dim+1);2249for(size_t i=0;i<nr_gen;++i){2250for(size_t j=0;j<dim; ++j)2251help[j]=Generators[i][j];2252help[dim]=0;2253BottomGen.append(help);2254}2255// then the same vectors as generators of the bottom polyhedron2256for(size_t i=0;i<nr_gen;++i){2257for(size_t j=0;j<dim; ++j)2258help[j]=Generators[i][j];2259help[dim]=1;2260BottomGen.append(help);2261}22622263Full_Cone BottomPolyhedron(BottomGen);2264BottomPolyhedron.verbose=verbose;2265BottomPolyhedron.do_extreme_rays=true;2266BottomPolyhedron.keep_order = true;2267try {2268BottomPolyhedron.dualize_cone(); // includes finding extreme rays2269} catch(const NonpointedException& ){};22702271// transfer pointedness2272assert( BottomPolyhedron.isComputed(ConeProperty::IsPointed) );2273pointed = BottomPolyhedron.pointed;2274is_Computed.set(ConeProperty::IsPointed);22752276// BottomPolyhedron.Support_Hyperplanes.pretty_print(cout);22772278help.resize(dim);22792280// find extreme rays of Bottom among the generators2281vector<key_t> BottomExtRays;2282for(size_t i=0;i<nr_gen;++i)2283if(BottomPolyhedron.Extreme_Rays_Ind[i+nr_gen])2284BottomExtRays.push_back(i);2285/* vector<key_t> BottomExtRays; // can be used if the bool vector should not exist anymore2286size_t start_search=0;2287for(size_t i=0;i<ExtStrahl.nr_of_rows();++i){2288if(BottomPolyhedron.ExtStrahl[i][dim]==1){2289BottomPolyhedron.ExtStrahl[i].resize(dim);2290for(size_t j=0;j<nr_gen;++j){2291size_t k=(j+start_search) % nr_gen;2292if(BottomPolyhedron.ExtStrahl[i]==Generators[k]){2293BottomExtRays.push_back(k);2294start_search++;2295}2296}2297}2298}*/22992300if(verbose)2301verboseOutput() << "Bottom has " << BottomExtRays.size() << " extreme rays" << endl;23022303INTERRUPT_COMPUTATION_BY_EXCEPTION23042305Matrix<Integer> BottomFacets(0,dim);2306vector<Integer> BottomDegs(0,dim);2307if (!isComputed(ConeProperty::SupportHyperplanes)) {2308Support_Hyperplanes = Matrix<Integer>(0,dim);2309nrSupport_Hyperplanes=0;2310}2311for(size_t i=0;i<BottomPolyhedron.nrSupport_Hyperplanes;++i){2312Integer test=BottomPolyhedron.Support_Hyperplanes[i][dim];2313for(size_t j=0;j<dim;++j)2314help[j]=BottomPolyhedron.Support_Hyperplanes[i][j];2315if(test==0 && !isComputed(ConeProperty::SupportHyperplanes)){2316Support_Hyperplanes.append(help);2317nrSupport_Hyperplanes++;2318}2319if (test < 0){2320BottomFacets.append(help);2321BottomDegs.push_back(-test);2322}2323}23242325is_Computed.set(ConeProperty::SupportHyperplanes);23262327if (!pointed)2328throw NonpointedException();23292330INTERRUPT_COMPUTATION_BY_EXCEPTION23312332vector<key_t> facet;2333for(size_t i=0;i<BottomFacets.nr_of_rows();++i){2334facet.clear();2335for(size_t k=0;k<BottomExtRays.size();++k)2336if(v_scalar_product(Generators[BottomExtRays[k]],BottomFacets[i])==BottomDegs[i])2337facet.push_back(BottomExtRays[k]);2338Pyramids[0].push_back(facet);2339nrPyramids[0]++;2340}2341if(verbose)2342verboseOutput() << "Bottom decomposition computed, " << nrPyramids[0] << " subcones" << endl;2343}23442345template<typename Integer>2346void Full_Cone<Integer>::start_message() {23472348if (verbose) {2349verboseOutput()<<"************************************************************"<<endl;2350verboseOutput()<<"starting primal algorithm ";2351if (do_partial_triangulation) verboseOutput()<<"with partial triangulation ";2352if (do_triangulation) {2353verboseOutput()<<"with full triangulation ";2354}2355if (!do_triangulation && !do_partial_triangulation) verboseOutput()<<"(only support hyperplanes) ";2356verboseOutput()<<"..."<<endl;2357}2358}23592360template<typename Integer>2361void Full_Cone<Integer>::end_message() {23622363if (verbose) {2364verboseOutput() << "------------------------------------------------------------"<<endl;2365}2366}236723682369//---------------------------------------------------------------------------23702371template<typename Integer>2372void Full_Cone<Integer>::build_top_cone() {23732374OldCandidates.verbose=verbose;2375NewCandidates.verbose=verbose;23762377if(dim==0)2378return;23792380if( ( !do_bottom_dec || deg1_generated || dim==1 || (!do_triangulation && !do_partial_triangulation))) {2381build_cone();2382}2383else{2384find_bottom_facets();2385start_from=nr_gen;2386deg1_triangulation=false;23872388vector<list<vector<key_t> >::iterator > level0_order;2389level0_order.reserve(nrPyramids[0]);2390auto p=Pyramids[0].begin();2391for(size_t k=0;k<nrPyramids[0];++k,++p){2392level0_order.push_back(p);2393}2394for(size_t k=0;k<5*nrPyramids[0];++k){2395swap(level0_order[rand()%nrPyramids[0]],level0_order[rand()%nrPyramids[0]]);2396}2397list<vector<key_t> > new_order;2398for(size_t k=0;k<nrPyramids[0];++k){2399new_order.push_back(*level0_order[k]);2400}2401Pyramids[0].clear();2402Pyramids[0].splice(Pyramids[0].begin(),new_order);24032404}24052406// try_offload(0); // superfluous since tried immediately in evaluate_stored_pyramids(0)24072408evaluate_stored_pyramids(0); // force evaluation of remaining pyramids24092410#ifdef NMZ_MIC_OFFLOAD2411if (_Offload_get_device_number() < 0) // dynamic check for being on CPU (-1)2412{2413evaluate_stored_pyramids(0); // previous run could have left over pyramids2414mic_offloader.evaluate_triangulation();2415}2416#endif // NMZ_MIC_OFFLOAD24172418}241924202421//---------------------------------------------------------------------------24222423template<typename Integer>2424bool Full_Cone<Integer>::check_evaluation_buffer(){24252426return(omp_get_level()==omp_start_level && check_evaluation_buffer_size());2427}24282429//---------------------------------------------------------------------------24302431template<typename Integer>2432bool Full_Cone<Integer>::check_evaluation_buffer_size(){24332434return(!Top_Cone->keep_triangulation &&2435Top_Cone->TriangulationBufferSize > EvalBoundTriang);2436}24372438//---------------------------------------------------------------------------24392440template<typename Integer>2441void Full_Cone<Integer>::transfer_triangulation_to_top(){24422443size_t i;24442445// cout << "Pyr level " << pyr_level << endl;24462447if(!is_pyramid) { // we are in top cone2448if(check_evaluation_buffer()){2449evaluate_triangulation();2450}2451return; // no transfer necessary2452}24532454// now we are in a pyramid24552456// cout << "In pyramid " << endl;2457int tn = 0;2458if (omp_in_parallel())2459tn = omp_get_ancestor_thread_num(omp_start_level+1);24602461auto pyr_simp=TriangulationBuffer.begin();2462while (pyr_simp!=TriangulationBuffer.end()) {2463if (pyr_simp->height == 0) { // it was marked to be skipped2464Top_Cone->FS[tn].splice(Top_Cone->FS[tn].end(), TriangulationBuffer, pyr_simp++);2465--TriangulationBufferSize;2466} else {2467for (i=0; i<dim; i++) // adjust key to topcone generators2468pyr_simp->key[i]=Top_Key[pyr_simp->key[i]];2469sort(pyr_simp->key.begin(),pyr_simp->key.end());2470++pyr_simp;2471}2472}24732474// cout << "Keys transferred " << endl;2475#pragma omp critical(TRIANG)2476{2477Top_Cone->TriangulationBuffer.splice(Top_Cone->TriangulationBuffer.end(),TriangulationBuffer);2478Top_Cone->TriangulationBufferSize += TriangulationBufferSize;2479}2480TriangulationBufferSize = 0;24812482}24832484//---------------------------------------------------------------------------2485template<typename Integer>2486void Full_Cone<Integer>::get_supphyps_from_copy(bool from_scratch){24872488if(isComputed(ConeProperty::SupportHyperplanes)) // we have them already2489return;24902491Full_Cone copy((*this).Generators);2492copy.verbose=verbose;2493if(!from_scratch){2494copy.start_from=start_from;2495copy.use_existing_facets=true;2496copy.keep_order=true;2497copy.HypCounter=HypCounter;2498copy.Extreme_Rays_Ind=Extreme_Rays_Ind;2499copy.in_triang=in_triang;2500copy.old_nr_supp_hyps=old_nr_supp_hyps;2501if(isComputed(ConeProperty::ExtremeRays))2502copy.is_Computed.set(ConeProperty::ExtremeRays);2503copy.GensInCone=GensInCone;2504copy.nrGensInCone=nrGensInCone;2505copy.Comparisons=Comparisons;2506if(!Comparisons.empty())2507copy.nrTotalComparisons=Comparisons[Comparisons.size()-1];25082509typename list< FACETDATA >::const_iterator l=Facets.begin();25102511for(size_t i=0;i<old_nr_supp_hyps;++i){2512copy.Facets.push_back(*l);2513++l;2514}2515}25162517copy.dualize_cone();25182519std::swap(Support_Hyperplanes,copy.Support_Hyperplanes);2520nrSupport_Hyperplanes = copy.nrSupport_Hyperplanes;2521is_Computed.set(ConeProperty::SupportHyperplanes);2522do_all_hyperplanes = false;2523}252425252526//---------------------------------------------------------------------------25272528template<typename Integer>2529void Full_Cone<Integer>::update_reducers(bool forced){25302531if((!do_Hilbert_basis || do_module_gens_intcl) && !forced)2532return;25332534if(NewCandidates.Candidates.empty())2535return;25362537INTERRUPT_COMPUTATION_BY_EXCEPTION25382539if(nr_gen==dim) // no global reduction in the simplicial case2540NewCandidates.sort_by_deg();2541if(nr_gen!=dim || forced){ // global reduction in the nonsimplicial case (or forced)2542NewCandidates.auto_reduce();2543if(verbose){2544verboseOutput() << "reducing " << OldCandidates.Candidates.size() << " candidates by " << NewCandidates.Candidates.size() << " reducers" << endl;2545}2546OldCandidates.reduce_by(NewCandidates);2547}2548OldCandidates.merge(NewCandidates);2549CandidatesSize=OldCandidates.Candidates.size();2550}25512552//---------------------------------------------------------------------------25532554template<typename Integer>2555void Full_Cone<Integer>::prepare_old_candidates_and_support_hyperplanes(){25562557if(!isComputed(ConeProperty::SupportHyperplanes)){2558if (verbose) {2559verboseOutput() << "**** Computing support hyperplanes for reduction:" << endl;2560}2561get_supphyps_from_copy(false);2562}25632564check_pointed();2565if(!pointed){2566throw NonpointedException();2567}25682569int max_threads = omp_get_max_threads();2570size_t Memory_per_gen=8*nrSupport_Hyperplanes;2571size_t max_nr_gen=RAM_Size/(Memory_per_gen*max_threads);2572// cout << "max_nr_gen " << max_nr_gen << endl;2573AdjustedReductionBound=max_nr_gen;2574if(AdjustedReductionBound < 2000)2575AdjustedReductionBound=2000;257625772578Sorting=compute_degree_function();2579if (!is_approximation) {2580bool save_do_module_gens_intcl=do_module_gens_intcl;2581do_module_gens_intcl=false; // to avoid multiplying sort_deg by 2 for the original generators2582for (size_t i = 0; i <nr_gen; i++) {2583// cout << gen_levels[i] << " ** " << Generators[i];2584if(!inhomogeneous || gen_levels[i]==0 || (!save_do_module_gens_intcl && gen_levels[i]<=1)) {2585OldCandidates.Candidates.push_back(Candidate<Integer>(Generators[i],*this));2586OldCandidates.Candidates.back().original_generator=true;2587}2588}2589do_module_gens_intcl=save_do_module_gens_intcl; // restore2590if(!do_module_gens_intcl) // if do_module_gens_intcl we don't want to change the original monoid2591OldCandidates.auto_reduce();2592else2593OldCandidates.sort_by_deg();2594}2595}25962597//---------------------------------------------------------------------------25982599template<typename Integer>2600void Full_Cone<Integer>::evaluate_triangulation(){26012602// prepare reduction2603if (do_Hilbert_basis && OldCandidates.Candidates.empty()) {2604prepare_old_candidates_and_support_hyperplanes();2605}26062607if (TriangulationBufferSize == 0)2608return;26092610assert(omp_get_level()==omp_start_level);26112612const long VERBOSE_STEPS = 50;2613long step_x_size = TriangulationBufferSize-VERBOSE_STEPS;2614if (verbose) {2615verboseOutput() << "evaluating "<<TriangulationBufferSize<<" simplices" <<endl;2616/* verboseOutput() << "---------+---------+---------+---------+---------+"2617<< " (one | per 2%)" << endl;*/2618}26192620totalNrSimplices += TriangulationBufferSize;26212622if(do_Stanley_dec || keep_triangulation){ // in these cases sorting is necessary2623auto simp=TriangulationBuffer.begin();2624for(;simp!=TriangulationBuffer.end();++simp)2625sort(simp->key.begin(),simp->key.end());2626}26272628if(do_evaluation && !do_only_multiplicity) {26292630deque<bool> done(TriangulationBufferSize,false);2631bool skip_remaining;2632#ifndef NCATCH2633std::exception_ptr tmp_exception;2634#endif26352636do{ // allows multiple run of loop below in case of interruption for the update of reducers26372638skip_remaining=false;2639step_x_size = TriangulationBufferSize-VERBOSE_STEPS;26402641#pragma omp parallel2642{2643typename list< SHORTSIMPLEX<Integer> >::iterator s = TriangulationBuffer.begin();2644size_t spos=0;2645int tn = omp_get_thread_num();2646#pragma omp for schedule(dynamic) nowait2647for(size_t i=0; i<TriangulationBufferSize; i++){2648#ifndef NCATCH2649try {2650#endif2651if(skip_remaining)2652continue;26532654for(; i > spos; ++spos, ++s) ;2655for(; i < spos; --spos, --s) ;26562657INTERRUPT_COMPUTATION_BY_EXCEPTION26582659if(done[spos])2660continue;26612662done[spos]=true;26632664/* if(keep_triangulation || do_Stanley_dec) -- now done above2665sort(s->key.begin(),s->key.end()); */2666if(!SimplexEval[tn].evaluate(*s)){2667#pragma omp critical(LARGESIMPLEX)2668LargeSimplices.push_back(SimplexEval[tn]);2669}2670if (verbose) {2671#pragma omp critical(VERBOSE)2672while ((long)(i*VERBOSE_STEPS) >= step_x_size) {2673step_x_size += TriangulationBufferSize;2674verboseOutput() << "|" <<flush;2675}2676}26772678if(do_Hilbert_basis && Results[tn].get_collected_elements_size() > AdjustedReductionBound)2679skip_remaining=true;2680#ifndef NCATCH2681} catch(const std::exception& ) {2682tmp_exception = std::current_exception();2683skip_remaining = true;2684#pragma omp flush(skip_remaining)2685}2686#endif2687}2688Results[tn].transfer_candidates();2689} // end parallel2690#ifndef NCATCH2691if (!(tmp_exception == 0)) std::rethrow_exception(tmp_exception);2692#endif26932694if (verbose)2695verboseOutput() << endl;26962697update_reducers();26982699} while(skip_remaining);27002701} // do_evaluation27022703if (verbose)2704{2705verboseOutput() << totalNrSimplices << " simplices";2706if(do_Hilbert_basis)2707verboseOutput() << ", " << CandidatesSize << " HB candidates";2708if(do_deg1_elements)2709verboseOutput() << ", " << CandidatesSize << " deg1 vectors";2710verboseOutput() << " accumulated." << endl;2711}27122713if (keep_triangulation) {2714Triangulation.splice(Triangulation.end(),TriangulationBuffer);2715} else {2716// #pragma omp critical(FREESIMPL)2717FreeSimpl.splice(FreeSimpl.begin(),TriangulationBuffer);2718}2719TriangulationBufferSize=0;27202721if (verbose && use_bottom_points) {2722size_t lss=LargeSimplices.size();2723if(lss>0)2724verboseOutput() << lss << " large simplices stored" << endl;2725}27262727for(size_t i=0;i<Results.size();++i)2728Results[i].transfer_candidates(); // any remaining ones27292730update_reducers();2731}27322733//---------------------------------------------------------------------------27342735template<typename Integer>2736void Full_Cone<Integer>::evaluate_large_simplices(){27372738size_t lss = LargeSimplices.size();2739if (lss == 0)2740return;27412742assert(omp_get_level()==omp_start_level);27432744if (verbose) {2745verboseOutput() << "Evaluating " << lss << " large simplices" << endl;2746}2747size_t j;2748for (j = 0; j < lss; ++j) {27492750INTERRUPT_COMPUTATION_BY_EXCEPTION27512752evaluate_large_simplex(j, lss);2753}27542755// decomposition might have created new simplices -- NO LONGER, now in Pyramids[0]2756// evaluate_triangulation();27572758// also new large simplices are possible2759/* if (!LargeSimplices.empty()) {2760use_bottom_points = false;2761lss += LargeSimplices.size();2762if (verbose) {2763verboseOutput() << "Continue evaluation of " << lss << " large simplices without new decompositions of simplicial cones." << endl;2764}2765for (; j < lss; ++j) {27662767INTERRUPT_COMPUTATION_BY_EXCEPTION27682769evaluate_large_simplex(j, lss);2770}2771}*/2772assert(LargeSimplices.empty());27732774for(size_t i=0;i<Results.size();++i)2775Results[i].transfer_candidates(); // any remaining ones27762777update_reducers();2778}27792780//---------------------------------------------------------------------------27812782template<typename Integer>2783void Full_Cone<Integer>::evaluate_large_simplex(size_t j, size_t lss) {2784if (verbose) {2785verboseOutput() << "Large simplex " << j+1 << " / " << lss << endl;2786}27872788if (do_deg1_elements && !do_h_vector && !do_Stanley_dec && !deg1_triangulation) {2789compute_deg1_elements_via_projection_simplicial(LargeSimplices.front().get_key());2790}2791else {2792LargeSimplices.front().Simplex_parallel_evaluation();2793if (do_Hilbert_basis && Results[0].get_collected_elements_size() > AdjustedReductionBound) {2794Results[0].transfer_candidates();2795update_reducers();2796}2797}2798LargeSimplices.pop_front();2799}28002801//---------------------------------------------------------------------------28022803template<typename Integer>2804void Full_Cone<Integer>::compute_deg1_elements_via_projection_simplicial(const vector<key_t>& key){28052806/* Full_Cone<Integer> SimplCone(Generators.submatrix(key));2807SimplCone.verbose=false; // verbose;2808SimplCone.Grading=Grading;2809SimplCone.is_Computed.set(ConeProperty::Grading);2810SimplCone.do_deg1_elements=true;2811SimplCone.do_approximation=true;28122813SimplCone.compute();*/2814Matrix<Integer> Gens=Generators.submatrix(key);2815Matrix<Integer> GradMat(0,dim);2816GradMat.append(Grading);2817Cone<Integer> ProjCone(Type::cone,Gens,Type::grading, GradMat);2818ProjCone.compute(ConeProperty::Projection);2819vector<vector<Integer> > Deg1=ProjCone.getDeg1Elements();2820Matrix<Integer> Supp=ProjCone.getSupportHyperplanesMatrix();;28212822vector<bool> Excluded(dim,false); // we want to discard duplicates2823for(size_t i=0;i<dim;++i){2824Integer test=v_scalar_product(Supp[i],Order_Vector);2825if(test>0)2826continue;2827if(test<0){2828Excluded[i]=true;2829continue;2830}2831size_t j;2832for(j=0;j<dim;++j){2833if(Supp[i][j]!=0)2834break;2835}2836if(Supp[i][j]<0)2837Excluded[i]=true;2838}28392840typename vector<vector<Integer> >::const_iterator E;2841for(E=Deg1.begin();E!=Deg1.end();++E){2842size_t i;2843for(i=0;i<dim;++i)2844if(v_scalar_product(*E,Supp[i])==0 && Excluded[i])2845break;2846if(i<dim)2847continue;28482849for(i=0;i<dim;++i) // exclude original generators2850if(*E==Gens[i])2851break;2852if(i==dim){2853Results[0].Deg1_Elements.push_back(*E); // Results[0].Deg1_Elements.push_back(*E);2854Results[0].collected_elements_size++;2855}2856}2857Results[0].transfer_candidates();2858}285928602861//---------------------------------------------------------------------------28622863template<typename Integer>2864void Full_Cone<Integer>::remove_duplicate_ori_gens_from_HB(){28652866return; //TODO reactivate!28672868set<vector<Integer> > OriGens;2869typename list<Candidate<Integer> >:: iterator c=OldCandidates.Candidates.begin();2870typename set<vector<Integer> >:: iterator found;2871for(;c!=OldCandidates.Candidates.end();){2872if(!c->original_generator){2873++c;2874continue;2875}2876found=OriGens.find(c->cand);2877if(found!=OriGens.end()){2878c=OldCandidates.Candidates.erase(c);2879}2880else{2881if(c->original_generator)2882OriGens.insert(c->cand);2883++c;2884}2885}2886}28872888//---------------------------------------------------------------------------28892890template<typename Integer>2891void Full_Cone<Integer>::primal_algorithm(){28922893primal_algorithm_initialize();28942895/***** Main Work is done in build_top_cone() *****/2896build_top_cone(); // evaluates if keep_triangulation==false2897/***** Main Work is done in build_top_cone() *****/28982899check_pointed();2900if(!pointed){2901throw NonpointedException();2902}29032904primal_algorithm_finalize();2905primal_algorithm_set_computed();2906}29072908//---------------------------------------------------------------------------29092910template<typename Integer>2911void Full_Cone<Integer>::primal_algorithm_initialize() {29122913prepare_inclusion_exclusion();29142915SimplexEval = vector< SimplexEvaluator<Integer> >(omp_get_max_threads(),SimplexEvaluator<Integer>(*this));2916for(size_t i=0;i<SimplexEval.size();++i)2917SimplexEval[i].set_evaluator_tn(i);2918Results = vector< Collector<Integer> >(omp_get_max_threads(),Collector<Integer>(*this));2919Hilbert_Series.setVerbose(verbose);2920}29212922//---------------------------------------------------------------------------29232924template<typename Integer>2925void Full_Cone<Integer>::primal_algorithm_finalize() {29262927if (isComputed(ConeProperty::Grading) && !deg1_generated) {2928deg1_triangulation = false;2929}2930if (keep_triangulation) {2931is_Computed.set(ConeProperty::Triangulation);2932}2933if (do_cone_dec) {2934is_Computed.set(ConeProperty::ConeDecomposition);2935}29362937evaluate_triangulation();2938assert(nrPyramids[0]==0);2939evaluate_large_simplices(); // can produce level 0 pyramids2940use_bottom_points=false; // block new attempts for subdivision2941evaluate_stored_pyramids(0); // in case subdivision took place2942evaluate_triangulation();2943FreeSimpl.clear();29442945compute_class_group();29462947// collect accumulated data from the SimplexEvaluators2948for (int zi=0; zi<omp_get_max_threads(); zi++) {2949detSum += Results[zi].getDetSum();2950multiplicity += Results[zi].getMultiplicitySum();2951if (do_h_vector) {2952Hilbert_Series += Results[zi].getHilbertSeriesSum();2953}2954}2955#ifdef NMZ_MIC_OFFLOAD2956// collect accumulated data from mics2957if (_Offload_get_device_number() < 0) // dynamic check for being on CPU (-1)2958{2959mic_offloader.finalize();2960}2961#endif // NMZ_MIC_OFFLOAD2962if (do_h_vector) {2963Hilbert_Series.collectData();2964}29652966if(verbose) {2967verboseOutput() << "Total number of pyramids = "<< totalNrPyr << ", among them simplicial " << nrSimplicialPyr << endl;2968// cout << "Uni "<< Unimod << " Ht1NonUni " << Ht1NonUni << " NonDecided " << NonDecided << " TotNonDec " << NonDecidedHyp<< endl;2969if(do_only_multiplicity)2970verboseOutput() << "Determinants computed = " << TotDet << endl;2971/* if(NrCompVect>0)2972cout << "Vector comparisons " << NrCompVect << " Value comparisons " << NrCompVal2973<< " Average " << NrCompVal/NrCompVect+1 << endl; */2974}29752976if(verbose && GMP_hyp+GMP_scal_prod+GMP_mat>0)2977verboseOutput() << "GMP transitions: matrices " << GMP_mat << " hyperplanes " << GMP_hyp << " vector operations " << GMP_scal_prod << endl;29782979}29802981//---------------------------------------------------------------------------29822983template<typename Integer>2984void Full_Cone<Integer>::make_module_gens(){29852986if(!inhomogeneous){2987NewCandidates.extract(ModuleGeneratorsOverOriginalMonoid);2988vector<Integer> Zero(dim,0);2989ModuleGeneratorsOverOriginalMonoid.push_front(Zero);2990// cout << "Mod " << endl;2991// Matrix<Integer>(ModuleGeneratorsOverOriginalMonoid).pretty_print(cout);2992// cout << "--------" << endl;2993is_Computed.set(ConeProperty::ModuleGeneratorsOverOriginalMonoid,true);2994return;2995}29962997CandidateList<Integer> Level1OriGens;2998for(size_t i=0;i<nr_gen;++i){2999if(gen_levels[i]==1){3000Level1OriGens.push_back(Candidate<Integer>(Generators[i],*this));3001}3002}3003CandidateList<Integer> Level1Generators=Level1OriGens;3004Candidate<Integer> new_cand(dim,Support_Hyperplanes.nr_of_rows());3005typename list<Candidate<Integer> >::const_iterator lnew,l1;3006for(lnew=NewCandidates.Candidates.begin();lnew!=NewCandidates.Candidates.end();++lnew){30073008INTERRUPT_COMPUTATION_BY_EXCEPTION30093010Integer level=v_scalar_product(lnew->cand,Truncation);3011if(level==1){3012new_cand=*lnew;3013Level1Generators.reduce_by_and_insert(new_cand,OldCandidates);3014}3015else{3016for(l1=Level1OriGens.Candidates.begin();l1!=Level1OriGens.Candidates.end();++l1){3017new_cand=sum(*l1,*lnew);3018Level1Generators.reduce_by_and_insert(new_cand,OldCandidates);3019}3020}3021}3022Level1Generators.extract(ModuleGeneratorsOverOriginalMonoid);3023ModuleGeneratorsOverOriginalMonoid.sort();3024ModuleGeneratorsOverOriginalMonoid.unique();3025is_Computed.set(ConeProperty::ModuleGeneratorsOverOriginalMonoid,true);30263027for (size_t i = 0; i <nr_gen; i++) { // the level 1 input generators have not yet ben inserted into OldCandidates3028if(gen_levels[i]==1) { // but they are needed for the truncated Hilbert basis com�putation3029NewCandidates.Candidates.push_back(Candidate<Integer>(Generators[i],*this));3030NewCandidates.Candidates.back().original_generator=true;3031}3032}3033}30343035//---------------------------------------------------------------------------30363037template<typename Integer>3038void Full_Cone<Integer>::make_module_gens_and_extract_HB(){30393040make_module_gens();30413042NewCandidates.divide_sortdeg_by2(); // was previously multplied by 23043NewCandidates.sort_by_deg();30443045OldCandidates.merge(NewCandidates);3046OldCandidates.auto_reduce();3047}304830493050//---------------------------------------------------------------------------30513052template<typename Integer>3053void Full_Cone<Integer>::primal_algorithm_set_computed() {30543055extreme_rays_and_deg1_check();3056if(!pointed){3057throw NonpointedException();3058}30593060if (do_triangulation || do_partial_triangulation) {3061is_Computed.set(ConeProperty::TriangulationSize,true);3062if (do_evaluation) {3063is_Computed.set(ConeProperty::TriangulationDetSum,true);3064}3065}3066if (do_triangulation && do_evaluation && isComputed(ConeProperty::Grading))3067is_Computed.set(ConeProperty::Multiplicity,true);30683069INTERRUPT_COMPUTATION_BY_EXCEPTION30703071if (do_Hilbert_basis) {3072if(do_module_gens_intcl){3073make_module_gens_and_extract_HB();3074}3075OldCandidates.sort_by_val();3076OldCandidates.extract(Hilbert_Basis);3077OldCandidates.Candidates.clear();3078Hilbert_Basis.unique();3079is_Computed.set(ConeProperty::HilbertBasis,true);3080if (isComputed(ConeProperty::Grading)) {3081select_deg1_elements();3082check_deg1_hilbert_basis();3083}3084}30853086INTERRUPT_COMPUTATION_BY_EXCEPTION30873088if (do_deg1_elements) {3089for(size_t i=0;i<nr_gen;i++)3090if(v_scalar_product(Grading,Generators[i])==1 && (!(is_approximation || is_global_approximation)3091|| subcone_contains(Generators[i])))3092Deg1_Elements.push_front(Generators[i]);3093is_Computed.set(ConeProperty::Deg1Elements,true);3094Deg1_Elements.sort();3095Deg1_Elements.unique();3096}30973098INTERRUPT_COMPUTATION_BY_EXCEPTION30993100if (do_h_vector) {3101Hilbert_Series.setShift(convertTo<long>(shift));3102Hilbert_Series.adjustShift();3103// now the shift in the HilbertSeries may change and we would have to adjust3104// the shift, the grading and more in the Full_Cone to continue to add data!3105// COMPUTE HSOP here3106if (do_hsop){3107compute_hsop();3108is_Computed.set(ConeProperty::HSOP);3109}3110Hilbert_Series.simplify();3111is_Computed.set(ConeProperty::HilbertSeries);3112}3113if(do_Stanley_dec){3114is_Computed.set(ConeProperty::StanleyDec);3115}31163117}311831193120//---------------------------------------------------------------------------3121// Normaliz modes (public)3122//---------------------------------------------------------------------------31233124// check the do_* bools, they must be set in advance3125// this method (de)activate them according to dependencies between them3126template<typename Integer>3127void Full_Cone<Integer>::do_vars_check(bool with_default) {31283129do_extreme_rays=true; // we always want to do this if compute() is called31303131/* if (do_default_mode && with_default) {3132do_Hilbert_basis = true;3133do_h_vector = true;3134if(!inhomogeneous)3135do_class_group=true;3136}3137*/31383139if (do_integrally_closed) {3140if (do_Hilbert_basis) {3141do_integrally_closed = false; // don't interrupt the computation3142} else {3143do_Hilbert_basis = true;3144}3145}31463147// activate implications3148if (do_module_gens_intcl) do_Hilbert_basis= true;3149if (do_module_gens_intcl) use_bottom_points= false;3150//if (do_hsop) do_Hilbert_basis = true;3151if (do_Stanley_dec) keep_triangulation = true;3152if (do_cone_dec) keep_triangulation = true;3153if (keep_triangulation) do_determinants = true;3154if (do_multiplicity) do_determinants = true;3155if ((do_multiplicity || do_h_vector) && inhomogeneous) do_module_rank = true;3156if (do_determinants) do_triangulation = true;3157if (do_h_vector && (with_default || explicit_h_vector)) do_triangulation = true;3158if (do_deg1_elements) do_partial_triangulation = true;3159if (do_Hilbert_basis) do_partial_triangulation = true;3160// activate3161do_only_multiplicity = do_determinants;3162stop_after_cone_dec = true;3163if(do_cone_dec) do_only_multiplicity=false;31643165if (do_Stanley_dec || do_h_vector || do_deg1_elements3166|| do_Hilbert_basis) {3167do_only_multiplicity = false;3168stop_after_cone_dec = false;3169do_evaluation = true;3170}3171if (do_determinants) do_evaluation = true;31723173// deactivate3174if (do_triangulation) do_partial_triangulation = false;3175if (do_Hilbert_basis) do_deg1_elements = false; // they will be extracted later31763177}317831793180// general purpose compute method3181// do_* bools must be set in advance, this method does sanity checks for it3182// if no bool is set it does support hyperplanes and extreme rays3183template<typename Integer>3184void Full_Cone<Integer>::compute() {31853186omp_start_level=omp_get_level();31873188if(dim==0){3189set_zero_cone();3190return;3191}319231933194do_vars_check(false);3195explicit_full_triang=do_triangulation; // to distinguish it from do_triangulation via default mode3196if(do_default_mode)3197do_vars_check(true);31983199if(inhomogeneous){3200if(do_default_mode && !do_Hilbert_basis && !isComputed(ConeProperty::Grading) &&isComputed(ConeProperty::ExtremeRays))3201return;3202}32033204start_message();32053206if(Support_Hyperplanes.nr_of_rows()==0 && !do_Hilbert_basis && !do_h_vector && !do_multiplicity && !do_deg1_elements3207&& !do_Stanley_dec && !do_triangulation && !do_determinants)3208assert(Generators.max_rank_submatrix_lex().size() == dim);32093210minimize_support_hyperplanes(); // if they are given3211if (inhomogeneous)3212set_levels();32133214check_given_grading();32153216if ((!do_triangulation && !do_partial_triangulation)3217|| (Grading.size()>0 && !isComputed(ConeProperty::Grading))){3218// in the second case there are only two possibilities:3219// either nonpointed or bad grading3220do_triangulation=false;3221do_partial_triangulation=false;3222support_hyperplanes();3223}3224else{3225// look for a grading if it is needed3226find_grading();3227if(isComputed(ConeProperty::IsPointed) && !pointed){3228end_message();3229return;3230}32313232if (!isComputed(ConeProperty::Grading))3233disable_grading_dep_comp();32343235bool polyhedron_is_polytope=inhomogeneous;3236if(inhomogeneous){3237find_level0_dim();3238for(size_t i=0;i<nr_gen;++i)3239if(gen_levels[i]==0){3240polyhedron_is_polytope=false;3241break;3242}3243}32443245set_degrees();3246sort_gens_by_degree(true);32473248if(do_approximation && !deg1_generated){3249if(!isComputed(ConeProperty::ExtremeRays) || !isComputed(ConeProperty::SupportHyperplanes)){3250do_extreme_rays=true;3251dualize_cone(false);// no start or end message3252}3253if(verbose)3254verboseOutput() << "Approximating rational by lattice polytope" << endl;3255if(do_deg1_elements){3256compute_deg1_elements_via_approx_global();3257is_Computed.set(ConeProperty::Deg1Elements,true);3258if(do_triangulation){3259do_deg1_elements=false;3260do_partial_triangulation=false;3261do_only_multiplicity = do_determinants;3262primal_algorithm();3263}3264} else { // now we want subdividing elements for a simplicial cone3265assert(do_Hilbert_basis);3266compute_elements_via_approx(Hilbert_Basis);3267}32683269}3270else{3271if(polyhedron_is_polytope && (do_Hilbert_basis || do_h_vector || do_multiplicity)){ // inthis situation we must find the3272convert_polyhedron_to_polytope(); // lattice points in a polytope3273}3274else{3275if(do_partial_triangulation || do_triangulation)3276primal_algorithm();3277else3278return;3279}3280}32813282if(inhomogeneous){3283find_module_rank();3284// cout << "module rank " << module_rank << endl;3285}32863287}32883289end_message();3290}32913292template<typename Integer>3293void Full_Cone<Integer>::compute_hsop(){3294vector<long> hsop_deg(dim,1);3295// if all extreme rays are in degree one, there is nothing to compute3296if (!isDeg1ExtremeRays()){3297if(verbose){3298verboseOutput() << "Computing heights ... " << flush;3299}33003301vector<bool> choice = Extreme_Rays_Ind;3302if (inhomogeneous){3303for (size_t i=0; i<Generators.nr_of_rows(); i++) {3304if (Extreme_Rays_Ind[i] && v_scalar_product(Generators[i],Truncation) != 0) {3305choice[i]=false;3306}3307}3308}3309Matrix<Integer> ER = Generators.submatrix(choice);3310Matrix<Integer> SH = getSupportHyperplanes();3311if (inhomogeneous){3312Sublattice_Representation<Integer> recession_lattice(ER,true);3313Matrix<Integer> SH_raw = recession_lattice.to_sublattice_dual(SH);3314Matrix<Integer> ER_embedded = recession_lattice.to_sublattice(ER);3315Full_Cone<Integer> recession_cone(ER_embedded);3316recession_cone.Support_Hyperplanes = SH_raw;3317recession_cone.dualize_cone();3318SH = recession_lattice.from_sublattice_dual(recession_cone.getSupportHyperplanes());3319}3320vector<size_t> ideal_heights(ER.nr_of_rows(),1);3321// the heights vector is clear in the simplicial case3322if (is_simplicial){3323for (size_t j=0;j<ideal_heights.size();j++) ideal_heights[j]=j+1;3324} else {3325list<pair<boost::dynamic_bitset<> , size_t>> facet_list;3326list<vector<key_t>> facet_keys;3327vector<key_t> key;3328size_t d = dim;3329if (inhomogeneous) d = level0_dim;3330for (size_t i=SH.nr_of_rows();i-->0;){3331boost::dynamic_bitset<> new_facet(ER.nr_of_rows());3332key.clear();3333for (size_t j=0;j<ER.nr_of_rows();j++){3334if (v_scalar_product(SH[i],ER[j])==0){3335new_facet[new_facet.size()-1-j]=1;3336} else {3337key.push_back(j);3338}3339}3340facet_list.push_back(make_pair(new_facet,d-1));3341facet_keys.push_back(key);3342}3343facet_list.sort(); // should be sorted lex3344//~ cout << "FACETS:" << endl;3345//~ //cout << "size: " << facet_list.size() << " | " << facet_list << endl;3346//~ for (auto jt=facet_list.begin();jt!=facet_list.end();++jt){3347//~ cout << jt->first << " | " << jt->second << endl;3348//~ }3349//cout << "facet non_keys: " << facet_keys << endl;3350heights(facet_keys,facet_list,ER.nr_of_rows()-1,ideal_heights,d-1);3351}3352if(verbose){3353verboseOutput() << "done." << endl;3354assert(ideal_heights[ER.nr_of_rows()-1]==dim);3355verboseOutput() << "Heights vector: " << ideal_heights << endl;3356}3357vector<Integer> er_deg = ER.MxV(Grading);3358hsop_deg = convertTo<vector<long> >(degrees_hsop(er_deg,ideal_heights));3359}3360if(verbose){3361verboseOutput() << "Degrees of HSOP: " << hsop_deg << endl;3362}3363Hilbert_Series.setHSOPDenom(hsop_deg);3364}3365336633673368// recursive method to compute the heights3369// TODO: at the moment: facets are a parameter. global would be better3370template<typename Integer>3371void Full_Cone<Integer>::heights(list<vector<key_t>>& facet_keys,list<pair<boost::dynamic_bitset<>,size_t>> faces, size_t index,vector<size_t>& ideal_heights,size_t max_dim){3372// since we count the index backwards, this is the actual nr of the extreme ray3373size_t ER_nr = ideal_heights.size()-index-1;3374//~ cout << "starting calculation for extreme ray nr " << ER_nr << endl;3375list<pair<boost::dynamic_bitset<>,size_t>> not_faces;3376auto face_it=faces.begin();3377for (;face_it!=faces.end();++face_it){3378if (face_it->first.test(index)){ // check whether index is set3379break;3380}3381// resize not_faces3382face_it->first.resize(index);3383}3384not_faces.splice(not_faces.begin(),faces,faces.begin(),face_it);3385//~ cout << "faces not containing it:" << endl;3386//~ for (auto jt=not_faces.begin();jt!=not_faces.end();++jt){3387//~ cout << jt->first << " | " << jt->second << endl;3388//~ }3389//~ cout << "faces containing it:" << endl;3390//~ for (auto jt=faces.begin();jt!=faces.end();++jt){3391//~ cout << jt->first << " | " << jt->second << endl;3392//~ }3393auto not_faces_it=not_faces.begin();3394// update the heights3395if (ER_nr>0){3396if (!not_faces.empty()){3397ideal_heights[ER_nr] = ideal_heights[ER_nr-1];3398// compute the dimensions of not_faces3399vector<bool> choice = Extreme_Rays_Ind;3400if (inhomogeneous){3401for (size_t i=0; i<Generators.nr_of_rows(); i++) {3402if (Extreme_Rays_Ind[i] && v_scalar_product(Generators[i],Truncation) != 0) {3403choice[i]=false;3404}3405}3406}3407Matrix<Integer> ER = Generators.submatrix(choice);3408int tn;3409if(omp_get_level()==omp_start_level)3410tn=0;3411else tn = omp_get_ancestor_thread_num(omp_start_level+1);3412Matrix<Integer>& Test = Top_Cone->RankTest[tn];3413vector<key_t> face_key;3414for (;not_faces_it!=not_faces.end();++not_faces_it){3415if (not_faces_it->second==0){ // dimension has not yet been computed3416// generate the key vector3417face_key.resize(0);3418for (size_t i=0;i<not_faces_it->first.size();++i){3419if (not_faces_it->first.test(i)){3420face_key.push_back(ER.nr_of_rows()-1-i);3421}3422}3423not_faces_it->second = Test.rank_submatrix(ER,face_key);3424}3425if (not_faces_it->second==max_dim) break;3426}3427if (not_faces_it==not_faces.end()) {3428--max_dim;3429ideal_heights[ER_nr] = ideal_heights[ER_nr-1]+1;3430}3431} else {3432ideal_heights[ER_nr] = ideal_heights[ER_nr-1]+1;3433--max_dim;3434}3435}3436// we computed all the heights3437if (index==0) return;3438// if inner point, we can skip now34393440// take the union of all faces not containing the current extreme ray3441boost::dynamic_bitset<> union_faces(index);3442not_faces_it = not_faces.begin();3443for (;not_faces_it!=not_faces.end();++not_faces_it){3444union_faces |= not_faces_it->first; // take the union3445}3446//cout << "Their union: " << union_faces << endl;3447// the not_faces now already have a size one smaller3448union_faces.resize(index+1);3449list<pair<boost::dynamic_bitset<>,size_t>> new_faces;3450// delete all facets which only consist of the previous extreme rays3451auto facet_it=facet_keys.begin();3452size_t counter=0;3453while(facet_it!=facet_keys.end()){34543455INTERRUPT_COMPUTATION_BY_EXCEPTION34563457counter=0;3458for (size_t i=0;i<facet_it->size();i++){3459if (facet_it->at(i)<=ER_nr) continue;3460// now we only have new extreme rays3461counter = i;3462break;3463}3464size_t j=ER_nr+1;3465for (;j<ideal_heights.size();j++){3466if (facet_it->at(counter)!=j){ // facet contains the element j3467break;3468} else if (counter < facet_it->size()-1) counter++;3469}3470if (j==ideal_heights.size()){3471facet_it = facet_keys.erase(facet_it);3472} else ++facet_it;3473}3474facet_it=facet_keys.begin();34753476// main loop3477for (;facet_it!=facet_keys.end();++facet_it){34783479INTERRUPT_COMPUTATION_BY_EXCEPTION34803481// check whether the facet is contained in the faces not containing the generator3482// and the previous generators3483// and check whether the generator is in the facet3484// check whether intersection with facet contributes3485bool not_containing_el =false;3486// bool whether the facet contains an element which is NOT in the faces not containing the current extreme ray3487bool containing_critical_el=false;3488counter=0;3489//cout << "check critical for facet " << *it << endl;3490for (size_t i=0;i<facet_it->size();i++){3491if (facet_it->at(i)==ER_nr){3492not_containing_el = true;3493}3494if (facet_it->at(i)<=ER_nr && i<facet_it->size()-1) continue;3495counter=i; // now we have elements which are bigger than the current extreme ray3496if (not_containing_el){3497for (size_t j=ER_nr+1;j<ideal_heights.size();j++){3498if (facet_it->at(counter)!=j){ // i.e. j is in the facet3499if (!union_faces.test(ideal_heights.size()-1-j)){3500containing_critical_el = true;3501break;3502}3503} else if (counter<facet_it->size()-1) counter++;3504}3505}3506break;3507}3508if(not_containing_el && containing_critical_el){ //facet contributes3509//cout << "Taking intersections with the facet " << *facet_it << endl;3510face_it =faces.begin();3511for (;face_it!=faces.end();++face_it){3512boost::dynamic_bitset<> intersection(face_it->first);3513for (size_t i=0;i<facet_it->size();i++){3514if (facet_it->at(i)>ER_nr) intersection.set(ideal_heights.size()-1-facet_it->at(i),false);3515}3516intersection.resize(index);3517if (intersection.any()){3518// check whether the intersection lies in any of the not_faces3519not_faces_it = not_faces.begin();3520for (;not_faces_it!=not_faces.end();++not_faces_it){3521if (intersection.is_subset_of(not_faces_it->first)) break;3522}3523if (not_faces_it== not_faces.end()) new_faces.push_back(make_pair(intersection,0));3524}3525}3526}3527}3528// the new faces need to be sort in lex order anyway. this can be used to reduce operations3529// for subset checking3530new_faces.sort();3531auto outer_it = new_faces.begin();3532auto inner_it = new_faces.begin();3533for (;outer_it!=new_faces.end();++outer_it){35343535INTERRUPT_COMPUTATION_BY_EXCEPTION35363537// work with a not-key vector3538vector<key_t> face_not_key;3539for (size_t i=0;i<outer_it->first.size();i++){3540if (!outer_it->first.test(i)){3541face_not_key.push_back(i);3542}3543}3544inner_it=new_faces.begin();3545size_t i=0;3546while (inner_it!=outer_it){3547i=0;3548for (;i<face_not_key.size();++i){3549if (inner_it->first.test(face_not_key[i])) break; //inner_it has an element which is not in outer_it3550}3551if (i==face_not_key.size()){3552inner_it = new_faces.erase(inner_it); //inner_it is a subface of outer_it3553} else ++inner_it;3554}3555}3556new_faces.merge(not_faces);3557/*cout << "The new faces: " << endl;3558for (auto jt=new_faces.begin();jt!=new_faces.end();++jt){3559cout << jt->first << " | " << jt->second << endl;3560}*/35613562heights(facet_keys,new_faces,index-1,ideal_heights,max_dim);3563}3564356535663567template<typename Integer>3568void Full_Cone<Integer>::convert_polyhedron_to_polytope() {35693570if(verbose){3571verboseOutput() << "Converting polyhedron to polytope" << endl;3572verboseOutput() << "Pointed since cone over polytope" << endl;3573}3574pointed=true;3575is_Computed.set(ConeProperty::IsPointed);3576Full_Cone Polytope(Generators);3577Polytope.pointed=true;3578Polytope.is_Computed.set(ConeProperty::IsPointed);3579Polytope.keep_order=true;3580Polytope.Grading=Truncation;3581Polytope.is_Computed.set(ConeProperty::Grading);3582if(isComputed(ConeProperty::SupportHyperplanes)){3583Polytope.Support_Hyperplanes=Support_Hyperplanes;3584Polytope.nrSupport_Hyperplanes=nrSupport_Hyperplanes;3585Polytope.is_Computed.set(ConeProperty::SupportHyperplanes);3586}3587if(isComputed(ConeProperty::ExtremeRays)){3588Polytope.Extreme_Rays_Ind=Extreme_Rays_Ind;3589Polytope.is_Computed.set(ConeProperty::ExtremeRays);3590}3591Polytope.do_deg1_elements=true;3592Polytope.verbose=verbose;3593Polytope.compute();3594if(Polytope.isComputed(ConeProperty::SupportHyperplanes) &&3595!isComputed(ConeProperty::SupportHyperplanes)){3596Support_Hyperplanes=Polytope.Support_Hyperplanes;3597nrSupport_Hyperplanes=Polytope.nrSupport_Hyperplanes;3598is_Computed.set(ConeProperty::SupportHyperplanes);3599}3600if(Polytope.isComputed(ConeProperty::ExtremeRays) &&3601!isComputed(ConeProperty::ExtremeRays)){3602Extreme_Rays_Ind=Polytope.Extreme_Rays_Ind;3603is_Computed.set(ConeProperty::ExtremeRays);3604}3605if(Polytope.isComputed(ConeProperty::Deg1Elements)){3606module_rank=Polytope.Deg1_Elements.size();3607if(do_Hilbert_basis){3608Hilbert_Basis=Polytope.Deg1_Elements;3609is_Computed.set(ConeProperty::HilbertBasis);3610}3611is_Computed.set(ConeProperty::ModuleRank);3612if(isComputed(ConeProperty::Grading) && module_rank>0){3613multiplicity=1; // of the recession cone;3614is_Computed.set(ConeProperty::Multiplicity);3615if(do_h_vector){3616vector<num_t> hv(1);3617typename list<vector<Integer> >::const_iterator hb=Polytope.Deg1_Elements.begin();3618for(;hb!=Polytope.Deg1_Elements.end();++hb){3619size_t deg = convertTo<long>(v_scalar_product(Grading,*hb));3620if(deg+1>hv.size())3621hv.resize(deg+1);3622hv[deg]++;3623}3624Hilbert_Series.add(hv,vector<denom_t>());3625Hilbert_Series.setShift(convertTo<long>(shift));3626Hilbert_Series.adjustShift();3627Hilbert_Series.simplify();3628is_Computed.set(ConeProperty::HilbertSeries);3629}3630}3631}3632}36333634//---------------------------------------------------------------------------36353636template<typename Integer>3637void Full_Cone<Integer>::compute_deg1_elements_via_approx_global() {36383639compute_elements_via_approx(Deg1_Elements);36403641/* typename list<vector<Integer> >::iterator e; // now already done in simplex.cpp and directly for generators3642for(e=Deg1_Elements.begin(); e!=Deg1_Elements.end();)3643if(!contains(*e))3644e=Deg1_Elements.erase(e);3645else3646++e; */3647if(verbose)3648verboseOutput() << Deg1_Elements.size() << " deg 1 elements found" << endl;3649}36503651//---------------------------------------------------------------------------36523653template<typename Integer>3654void Full_Cone<Integer>::compute_elements_via_approx(list<vector<Integer> >& elements_from_approx) {36553656if (!isComputed(ConeProperty::Grading)){3657support_hyperplanes(); // the only thing we can do now3658return;3659}3660assert(elements_from_approx.empty());3661vector<list<vector<Integer>>> approx_points = latt_approx();3662vector<vector<key_t>> approx_points_indices;3663key_t current_key =0;3664//cout << "Approximation points: " << endl;3665//for (size_t j=0;j<dim;++j){3666////cout << "Original generator " << j << ": " << Generators[j] << endl;3667////cout << approx_points[j] << endl;3668//}3669//cout << "Nr of ER: " << getExtremeRays().size() << endl;3670//Matrix<Integer> all_approx_points(Generators);3671Matrix<Integer> all_approx_points(0,dim);3672for (size_t i=0;i<nr_gen;i++){3673vector<key_t> indices(approx_points[i].size());3674if (!approx_points[i].empty()){36753676all_approx_points.append(approx_points[i]);3677for (size_t j=0;j<approx_points[i].size();++j){3678indices[j]=current_key;3679current_key++;3680}36813682}3683approx_points_indices.push_back(indices);3684}3685if(verbose){3686verboseOutput() << "Nr original generators: " << nr_gen << endl;3687verboseOutput() << "Nr approximation points: " << all_approx_points.nr_of_rows() << endl;3688}3689Full_Cone C_approx(all_approx_points);3690C_approx.OriginalGenerators = Generators;3691C_approx.approx_points_keys = approx_points_indices;3692C_approx.verbose = verbose;3693//C_temp.build_cone_approx(*this,approx_points_indices);369436953696//Full_Cone C_approx(C_temp.getGenerators());3697//Full_Cone C_approx(all_approx_points); // latt_approx computes a matrix of generators36983699C_approx.is_approximation=true;3700// C_approx.Generators.pretty_print(cout);3701C_approx.do_deg1_elements=do_deg1_elements; // for supercone C_approx that is generated in degree 13702C_approx.do_Hilbert_basis=do_Hilbert_basis;3703C_approx.do_all_hyperplanes=false; // not needed3704C_approx.Subcone_Support_Hyperplanes=Support_Hyperplanes; // *this is a subcone of C_approx, used to discard elements3705C_approx.Support_Hyperplanes=Support_Hyperplanes; // UNFORTUNATELY NEEDED IN REDUCTION FOR SUBDIVIUSION BY APPROX3706C_approx.is_Computed.set(ConeProperty::SupportHyperplanes);3707C_approx.nrSupport_Hyperplanes = nrSupport_Hyperplanes;3708C_approx.Grading = Grading;3709C_approx.is_Computed.set(ConeProperty::Grading);3710C_approx.Truncation=Truncation;3711C_approx.TruncLevel=TruncLevel;37123713//if(verbose)3714//verboseOutput() << "Computing elements in approximating cone with "3715//<< C_approx.Generators.nr_of_rows() << " generators." << endl;3716if(verbose){3717verboseOutput() << "Computing elements in approximating cone." << endl;3718}37193720bool verbose_tmp = verbose;3721verbose =false;3722C_approx.compute();3723verbose = verbose_tmp;37243725//vector<key_t> used_gens;3726//for (size_t j=0;j<nr_gen;++j){3727//if (C_approx.in_triang[j]) used_gens.push_back(j);3728//}3729//C_approx.Generators = C_approx.Generators.submatrix(used_gens);3730//if (verbose){3731//verboseOutput() << "Used "<< C_approx.Generators.nr_of_rows() << " / " << C_approx.nr_gen << " generators." << endl;3732//}3733//C_approx.nr_gen=C_approx.Generators.nr_of_rows();373437353736// TODO: with the current implementation, this is always the case!3737if(!C_approx.contains(*this) || Grading!=C_approx.Grading){3738throw FatalException("Wrong approximating cone.");3739}37403741if(verbose)3742verboseOutput() << "Sum of dets of simplicial cones evaluated in approximation = " << C_approx.detSum << endl;37433744if(verbose)3745verboseOutput() << "Returning to original cone" << endl;3746if(do_deg1_elements)3747elements_from_approx.splice(elements_from_approx.begin(),C_approx.Deg1_Elements);3748if(do_Hilbert_basis)3749elements_from_approx.splice(elements_from_approx.begin(),C_approx.Hilbert_Basis);3750}375137523753// -s3754template<typename Integer>3755void Full_Cone<Integer>::support_hyperplanes() {3756if(!isComputed(ConeProperty::SupportHyperplanes)){3757sort_gens_by_degree(false); // we do not want to triangulate here3758build_top_cone();3759}3760extreme_rays_and_deg1_check();3761if(inhomogeneous){3762find_level0_dim();3763if(do_module_rank)3764find_module_rank();3765}3766compute_class_group();3767}37683769//---------------------------------------------------------------------------3770// Checks and auxiliary algorithms3771//---------------------------------------------------------------------------37723773template<typename Integer>3774void Full_Cone<Integer>::extreme_rays_and_deg1_check() {3775check_pointed();3776if(!pointed){3777throw NonpointedException();3778}3779//cout << "Generators" << endl;3780//Generators.pretty_print(cout);3781//cout << "SupportHyperplanes" << endl;3782//Support_Hyperplanes.pretty_print(cout);3783compute_extreme_rays();3784deg1_check();3785}37863787//---------------------------------------------------------------------------37883789template<typename Integer>3790void Full_Cone<Integer>::check_given_grading(){37913792if(Grading.size()==0)3793return;37943795bool positively_graded=true;37963797if(!isComputed(ConeProperty::Grading)){3798size_t neg_index=0;3799Integer neg_value;3800bool nonnegative=true;3801vector<Integer> degrees = Generators.MxV(Grading);3802for (size_t i=0; i<degrees.size(); ++i) {3803if (degrees[i]<=0 && (!inhomogeneous || gen_levels[i]==0)) {3804// in the inhomogeneous case: test only generators of tail cone3805positively_graded=false;;3806if(degrees[i]<0){3807nonnegative=false;3808neg_index=i;3809neg_value=degrees[i];3810}3811}3812}38133814if(!nonnegative){3815throw BadInputException("Grading gives negative value "3816+ toString(neg_value) + " for generator "3817+ toString(neg_index+1) + "!");3818}3819}38203821if(positively_graded){3822is_Computed.set(ConeProperty::Grading);3823if(inhomogeneous)3824find_grading_inhom();3825set_degrees();3826}3827}38283829//---------------------------------------------------------------------------38303831template<typename Integer>3832void Full_Cone<Integer>::find_grading(){38333834if(inhomogeneous) // in the inhomogeneous case we do not allow implicit grading3835return;38363837deg1_check(); // trying to find grading under which all generators have the same degree3838if (!isComputed(ConeProperty::Grading) && (do_multiplicity || do_deg1_elements || do_h_vector)) {3839if (!isComputed(ConeProperty::ExtremeRays)) {3840if (verbose) {3841verboseOutput() << "Cannot find grading s.t. all generators have the degree 1! Computing Extreme rays first:" << endl;3842}3843get_supphyps_from_copy(true);3844extreme_rays_and_deg1_check();3845if(!pointed){3846throw NonpointedException();3847};38483849// We keep the SupportHyperplanes, so we do not need to recompute them3850// for the last generator, and use them to make a global reduction earlier3851}3852}3853}38543855//---------------------------------------------------------------------------38563857template<typename Integer>3858void Full_Cone<Integer>::find_level0_dim(){38593860if(!isComputed(ConeProperty::Generators)){3861throw FatalException("Missing Generators.");3862}38633864Matrix<Integer> Help(nr_gen,dim);3865for(size_t i=0; i<nr_gen;++i)3866if(gen_levels[i]==0)3867Help[i]=Generators[i];38683869ProjToLevel0Quot=Help.kernel();38703871level0_dim=dim-ProjToLevel0Quot.nr_of_rows();3872is_Computed.set(ConeProperty::RecessionRank);3873}38743875//---------------------------------------------------------------------------38763877template<typename Integer>3878void Full_Cone<Integer>::find_module_rank(){38793880if(isComputed(ConeProperty::ModuleRank))3881return;38823883if(level0_dim==dim){3884module_rank=0;3885is_Computed.set(ConeProperty::ModuleRank);3886return;3887}3888if(isComputed(ConeProperty::HilbertBasis)){3889find_module_rank_from_HB();3890return;3891}38923893// size_t HBrank = module_rank;38943895if(do_module_rank)3896find_module_rank_from_proj();38973898/* if(isComputed(ConeProperty::HilbertBasis))3899assert(HBrank==module_rank);3900*/39013902}39033904//---------------------------------------------------------------------------39053906template<typename Integer>3907void Full_Cone<Integer>::find_module_rank_from_proj(){39083909if(verbose){3910verboseOutput() << "Computing projection to quotient mod level 0" << endl;3911}39123913Matrix<Integer> ProjGen(nr_gen,dim-level0_dim);3914for(size_t i=0;i<nr_gen;++i){3915ProjGen[i]=ProjToLevel0Quot.MxV(Generators[i]);3916}39173918vector<Integer> GradingProj=ProjToLevel0Quot.transpose().solve_ZZ(Truncation);39193920Full_Cone<Integer> Cproj(ProjGen);3921Cproj.verbose=false;3922Cproj.Grading=GradingProj;3923Cproj.is_Computed.set(ConeProperty::Grading);3924Cproj.do_deg1_elements=true;3925Cproj.compute();39263927module_rank=Cproj.Deg1_Elements.size();3928is_Computed.set(ConeProperty::ModuleRank);3929return;3930}39313932//---------------------------------------------------------------------------39333934template<typename Integer>3935void Full_Cone<Integer>::find_module_rank_from_HB(){39363937if(level0_dim==0){3938module_rank=Hilbert_Basis.size();3939is_Computed.set(ConeProperty::ModuleRank);3940return;3941}394239433944set<vector<Integer> > Quotient;3945vector<Integer> v;39463947// cout << "=======================" << endl;3948// ProjToLevel0Quot.print(cout);3949// cout << "=======================" << endl;39503951typename list<vector<Integer> >::iterator h;39523953for(h=Hilbert_Basis.begin();h!=Hilbert_Basis.end();++h){39543955INTERRUPT_COMPUTATION_BY_EXCEPTION39563957v=ProjToLevel0Quot.MxV(*h);3958bool zero=true;3959for(size_t j=0;j<v.size();++j)3960if(v[j]!=0){3961zero=false;3962break;3963}3964if(!zero)3965Quotient.insert(v);3966}39673968module_rank=Quotient.size();3969is_Computed.set(ConeProperty::ModuleRank);39703971}39723973//---------------------------------------------------------------------------39743975template<typename Integer>3976void Full_Cone<Integer>::find_grading_inhom(){39773978if(Grading.size()==0 || Truncation.size()==0){3979throw FatalException("Cannot find grading in the inhomogeneous case!");3980}39813982if(shift!=0) // to avoid double computation3983return;39843985bool first=true;3986Integer level,degree,quot=0,min_quot=0;3987for(size_t i=0;i<nr_gen;++i){3988level=v_scalar_product(Truncation,Generators[i]);3989if(level==0)3990continue;3991degree=v_scalar_product(Grading,Generators[i]);3992quot=degree/level;3993// cout << Generators[i];3994// cout << "*** " << degree << " " << level << " " << quot << endl;3995if(level*quot>=degree)3996quot--;3997if(first){3998min_quot=quot;3999first=false;4000}4001if(quot<min_quot)4002min_quot=quot;4003// cout << "+++ " << min_quot << endl;4004}4005shift = min_quot;4006for(size_t i=0;i<dim;++i) // under this grading all generators have positive degree4007Grading[i] = Grading[i] - shift * Truncation[i];40084009// shift--; // NO LONGER correction for the Hilbert series computation to have it start in degree 04010}40114012//---------------------------------------------------------------------------40134014template<typename Integer>4015void Full_Cone<Integer>::set_degrees() {40164017// Generators.pretty_print(cout);4018// cout << "Grading " << Grading;4019if (gen_degrees.size() != nr_gen && isComputed(ConeProperty::Grading)) // now we set the degrees4020{4021gen_degrees.resize(nr_gen);4022vector<Integer> gen_degrees_Integer=Generators.MxV(Grading);4023for (size_t i=0; i<nr_gen; i++) {4024if (gen_degrees_Integer[i] < 1) {4025throw BadInputException("Grading gives non-positive value "4026+ toString(gen_degrees_Integer[i])4027+ " for generator " + toString(i+1) + ".");4028}4029convert(gen_degrees[i], gen_degrees_Integer[i]);4030}4031}40324033}40344035//---------------------------------------------------------------------------40364037template<typename Integer>4038void Full_Cone<Integer>::set_levels() {4039if(inhomogeneous && Truncation.size()!=dim){4040throw FatalException("Truncation not defined in inhomogeneous case.");4041}40424043// cout <<"trunc " << Truncation;40444045if(gen_levels.size()!=nr_gen) // now we compute the levels4046{4047gen_levels.resize(nr_gen);4048vector<Integer> gen_levels_Integer=Generators.MxV(Truncation);4049for (size_t i=0; i<nr_gen; i++) {4050if (gen_levels_Integer[i] < 0) {4051throw FatalException("Truncation gives non-positive value "4052+ toString(gen_levels_Integer[i]) + " for generator "4053+ toString(i+1) + ".");4054}4055convert(gen_levels[i], gen_levels_Integer[i]);4056// cout << "Gen " << Generators[i];4057// cout << "level " << gen_levels[i] << endl << "----------------------" << endl;4058}4059}40604061}40624063//---------------------------------------------------------------------------40644065template<typename Integer>4066void Full_Cone<Integer>::sort_gens_by_degree(bool triangulate) {4067// if(deg1_extreme_rays) // gen_degrees.size()==0 ||4068// return;40694070if(keep_order)4071return;40724073Matrix<Integer> Weights(0,dim);4074vector<bool> absolute;4075if(triangulate){4076if(isComputed(ConeProperty::Grading)){4077Weights.append(Grading);4078absolute.push_back(false);4079}4080else{4081Weights.append(vector<Integer>(dim,1));4082absolute.push_back(true);4083}4084}40854086vector<key_t> perm=Generators.perm_by_weights(Weights,absolute);4087Generators.order_rows_by_perm(perm);4088order_by_perm(Extreme_Rays_Ind,perm);4089if(isComputed(ConeProperty::Grading))4090order_by_perm(gen_degrees,perm);4091if(inhomogeneous && gen_levels.size()==nr_gen)4092order_by_perm(gen_levels,perm);4093compose_perm_gens(perm);40944095if(triangulate){4096Integer roughness;4097if(isComputed(ConeProperty::Grading)){4098roughness=gen_degrees[nr_gen-1]/gen_degrees[0];4099}4100else{4101Integer max_norm=0, min_norm=0;4102for(size_t i=0;i<dim;++i){4103max_norm+=Iabs(Generators[nr_gen-1][i]);4104min_norm+=Iabs(Generators[0][i]);4105}4106roughness=max_norm/min_norm;4107}4108if(verbose){4109verboseOutput() << "Roughness " << roughness << endl;4110}41114112if(roughness >= 10 && !suppress_bottom_dec){4113do_bottom_dec=true;4114if(verbose){4115verboseOutput() << "Bottom decomposition activated" << endl;4116}4117}4118}41194120if (verbose) {4121if(triangulate){4122if(isComputed(ConeProperty::Grading)){4123verboseOutput() <<"Generators sorted by degree and lexicographically" << endl;4124verboseOutput() << "Generators per degree:" << endl;4125verboseOutput() << count_in_map<Integer,long>(gen_degrees);4126}4127else4128verboseOutput() << "Generators sorted by 1-norm and lexicographically" << endl;4129}4130else{4131verboseOutput() << "Generators sorted lexicographically" << endl;4132}4133}4134keep_order=true;4135}41364137//---------------------------------------------------------------------------41384139template<typename Integer>4140void Full_Cone<Integer>::compose_perm_gens(const vector<key_t>& perm) {4141order_by_perm(PermGens,perm);4142}41434144//---------------------------------------------------------------------------41454146// an alternative to compute() for the basic tasks that need no triangulation4147template<typename Integer>4148void Full_Cone<Integer>::dualize_cone(bool print_message){41494150omp_start_level=omp_get_level();41514152if(dim==0){4153set_zero_cone();4154return;4155}41564157// DO NOT CALL do_vars_check!!41584159bool save_tri = do_triangulation;4160bool save_part_tri = do_partial_triangulation;4161do_triangulation = false;4162do_partial_triangulation = false;41634164if(print_message) start_message();41654166sort_gens_by_degree(false);41674168if(!isComputed(ConeProperty::SupportHyperplanes))4169build_top_cone();41704171if(do_pointed)4172check_pointed();41734174if(do_extreme_rays) // in case we have known the support hyperplanes4175compute_extreme_rays();41764177do_triangulation = save_tri;4178do_partial_triangulation = save_part_tri;4179if(print_message) end_message();4180}41814182//---------------------------------------------------------------------------41834184template<typename Integer>4185vector<key_t> Full_Cone<Integer>::find_start_simplex() const {4186return Generators.max_rank_submatrix_lex();4187}41884189//---------------------------------------------------------------------------41904191template<typename Integer>4192Matrix<Integer> Full_Cone<Integer>::select_matrix_from_list(const list<vector<Integer> >& S,4193vector<size_t>& selection){41944195sort(selection.begin(),selection.end());4196assert(selection.back()<S.size());4197size_t i=0,j=0;4198size_t k=selection.size();4199Matrix<Integer> M(selection.size(),S.front().size());4200typename list<vector<Integer> >::const_iterator ll=S.begin();4201for(;ll!=S.end()&&i<k;++ll){4202if(j==selection[i]){4203M[i]=*ll;4204i++;4205}4206j++;4207}4208return M;4209}42104211//---------------------------------------------------------------------------42124213template<typename Integer>42144215void Full_Cone<Integer>::minimize_support_hyperplanes(){4216if(Support_Hyperplanes.nr_of_rows() == 0)4217return;4218if(isComputed(ConeProperty::SupportHyperplanes)){4219nrSupport_Hyperplanes=Support_Hyperplanes.nr_of_rows();4220return;4221}4222if (verbose) {4223verboseOutput() << "Minimize the given set of support hyperplanes by "4224<< "computing the extreme rays of the dual cone" << endl;4225}4226Full_Cone<Integer> Dual(Support_Hyperplanes);4227Dual.verbose=verbose;4228Dual.Support_Hyperplanes = Generators;4229Dual.is_Computed.set(ConeProperty::SupportHyperplanes);4230Dual.compute_extreme_rays();4231Support_Hyperplanes = Dual.Generators.submatrix(Dual.Extreme_Rays_Ind); //only essential hyperplanes4232is_Computed.set(ConeProperty::SupportHyperplanes);4233nrSupport_Hyperplanes=Support_Hyperplanes.nr_of_rows();4234do_all_hyperplanes=false;4235}423642374238//---------------------------------------------------------------------------42394240template<typename Integer>4241void Full_Cone<Integer>::compute_extreme_rays(bool use_facets){42424243if (isComputed(ConeProperty::ExtremeRays))4244return;4245// when we do approximation, we do not have the correct hyperplanes4246// and cannot compute the extreme rays4247if (is_approximation)4248return;4249assert(isComputed(ConeProperty::SupportHyperplanes));42504251check_pointed();4252if(!pointed){4253throw NonpointedException();4254}42554256if(dim*Support_Hyperplanes.nr_of_rows() < nr_gen) {4257compute_extreme_rays_rank(use_facets);4258} else {4259compute_extreme_rays_compare(use_facets);4260}4261}42624263//---------------------------------------------------------------------------42644265template<typename Integer>4266void Full_Cone<Integer>::compute_extreme_rays_rank(bool use_facets){42674268if (verbose) verboseOutput() << "Select extreme rays via rank ... " << flush;42694270size_t i;4271vector<key_t> gen_in_hyperplanes;4272gen_in_hyperplanes.reserve(Support_Hyperplanes.nr_of_rows());4273Matrix<Integer> M(Support_Hyperplanes.nr_of_rows(),dim);42744275deque<bool> Ext(nr_gen,false);4276#pragma omp parallel for firstprivate(gen_in_hyperplanes,M)4277for(i=0;i<nr_gen;++i){4278// if (isComputed(ConeProperty::Triangulation) && !in_triang[i])4279// continue;42804281INTERRUPT_COMPUTATION_BY_EXCEPTION42824283gen_in_hyperplanes.clear();4284if(use_facets){4285typename list<FACETDATA>::const_iterator IHV=Facets.begin();4286for (size_t j=0; j<Support_Hyperplanes.nr_of_rows(); ++j, ++IHV){4287if(IHV->GenInHyp.test(i))4288gen_in_hyperplanes.push_back(j);4289}4290}4291else{4292for (size_t j=0; j<Support_Hyperplanes.nr_of_rows(); ++j){4293if(v_scalar_product(Generators[i],Support_Hyperplanes[j])==0)4294gen_in_hyperplanes.push_back(j);4295}4296}4297if (gen_in_hyperplanes.size() < dim-1)4298continue;4299if (M.rank_submatrix(Support_Hyperplanes,gen_in_hyperplanes) >= dim-1)4300Ext[i]=true;4301}4302for(i=0; i<nr_gen;++i)4303Extreme_Rays_Ind[i]=Ext[i];43044305is_Computed.set(ConeProperty::ExtremeRays);4306if (verbose) verboseOutput() << "done." << endl;4307}43084309//---------------------------------------------------------------------------43104311template<typename Integer>4312void Full_Cone<Integer>::compute_extreme_rays_compare(bool use_facets){43134314if (verbose) verboseOutput() << "Select extreme rays via comparison ... " << flush;43154316size_t i,j,k;4317// Matrix<Integer> SH=getSupportHyperplanes().transpose();4318// Matrix<Integer> Val=Generators.multiplication(SH);4319size_t nc=Support_Hyperplanes.nr_of_rows();43204321vector<vector<bool> > Val(nr_gen);4322for (i=0;i<nr_gen;++i)4323Val[i].resize(nc);43244325// In this routine Val[i][j]==1, i.e. true, indicates that4326// the i-th generator is contained in the j-th support hyperplane43274328vector<key_t> Zero(nc);4329vector<key_t> nr_ones(nr_gen);43304331for (i = 0; i <nr_gen; i++) {43324333INTERRUPT_COMPUTATION_BY_EXCEPTION43344335k=0;4336Extreme_Rays_Ind[i]=true;4337if(use_facets){4338typename list<FACETDATA>::const_iterator IHV=Facets.begin();4339for (j=0; j<Support_Hyperplanes.nr_of_rows(); ++j, ++IHV){4340if(IHV->GenInHyp.test(i)){4341k++;4342Val[i][j]=true;4343}4344else4345Val[i][j]=false;4346}4347}4348else{4349for (j = 0; j <nc; ++j) {4350if (v_scalar_product(Generators[i],Support_Hyperplanes[j])==0) {4351k++;4352Val[i][j]=true;4353}4354else4355Val[i][j]=false;4356}4357}4358nr_ones[i]=k;4359if (k<dim-1||k==nc) // not contained in enough facets or in all (0 as generator)4360Extreme_Rays_Ind[i]=false;4361}43624363maximal_subsets(Val,Extreme_Rays_Ind);43644365is_Computed.set(ConeProperty::ExtremeRays);4366if (verbose) verboseOutput() << "done." << endl;4367}43684369//---------------------------------------------------------------------------43704371template<typename Integer>4372void Full_Cone<Integer>::compute_class_group() { // from the support hyperplanes4373if(!do_class_group || !isComputed(ConeProperty::SupportHyperplanes) || isComputed(ConeProperty::ClassGroup))4374return;4375Matrix<Integer> Trans=Support_Hyperplanes; // .transpose();4376size_t rk;4377Trans.SmithNormalForm(rk);4378ClassGroup.push_back(Support_Hyperplanes.nr_of_rows()-rk);4379for(size_t i=0;i<rk;++i)4380if(Trans[i][i]!=1)4381ClassGroup.push_back(Trans[i][i]);4382is_Computed.set(ConeProperty::ClassGroup);4383}43844385//---------------------------------------------------------------------------43864387template<typename Integer>4388void Full_Cone<Integer>::select_deg1_elements() { // from the Hilbert basis43894390if(inhomogeneous)4391return;4392typename list<vector<Integer> >::iterator h = Hilbert_Basis.begin();4393for(;h!=Hilbert_Basis.end();h++){4394if(v_scalar_product(Grading,*h)==1)4395Deg1_Elements.push_back(*h);4396}4397is_Computed.set(ConeProperty::Deg1Elements,true);4398}43994400//---------------------------------------------------------------------------44014402template<typename Integer>4403bool Full_Cone<Integer>::subcone_contains(const vector<Integer>& v) {4404for (size_t i=0; i<Subcone_Support_Hyperplanes.nr_of_rows(); ++i)4405if (v_scalar_product(Subcone_Support_Hyperplanes[i],v) < 0)4406return false;4407for (size_t i=0; i<Subcone_Equations.nr_of_rows(); ++i)4408if (v_scalar_product(Subcone_Equations[i],v) != 0)4409return false;4410if(is_global_approximation)4411if(v_scalar_product(Subcone_Grading,v)!=1)4412return false;4413return true;4414}44154416//---------------------------------------------------------------------------44174418template<typename Integer>4419bool Full_Cone<Integer>::contains(const vector<Integer>& v) {4420for (size_t i=0; i<Support_Hyperplanes.nr_of_rows(); ++i)4421if (v_scalar_product(Support_Hyperplanes[i],v) < 0)4422return false;4423return true;4424}4425//---------------------------------------------------------------------------44264427template<typename Integer>4428bool Full_Cone<Integer>::contains(const Full_Cone& C) {4429for(size_t i=0;i<C.nr_gen;++i)4430if(!contains(C.Generators[i])){4431cerr << "Missing generator " << C.Generators[i] << endl;4432return(false);4433}4434return(true);4435}4436//---------------------------------------------------------------------------44374438template<typename Integer>4439void Full_Cone<Integer>::select_deg1_elements(const Full_Cone& C) { // from vectors computed in4440// the auxiliary cone C4441assert(isComputed(ConeProperty::SupportHyperplanes));4442assert(C.isComputed(ConeProperty::Deg1Elements));4443typename list<vector<Integer> >::const_iterator h = C.Deg1_Elements.begin();4444for(;h!=C.Deg1_Elements.end();++h){4445if(contains(*h))4446Deg1_Elements.push_back(*h);4447}4448is_Computed.set(ConeProperty::Deg1Elements,true);4449}44504451//---------------------------------------------------------------------------445244534454// so far only for experiments4455/*4456template<typename Integer>4457void Full_Cone<Integer>::select_Hilbert_Basis(const Full_Cone& C) { // from vectors computed in4458// the auxiliary cone C4459assert(isComputed(ConeProperty::SupportHyperplanes));4460assert(C.isComputed(ConeProperty::Deg1Elements));4461typename list<vector<Integer> >::const_iterator h = C.Hilbert_Basis.begin();4462for(;h!=C.Hilbert_Basis.end();++h){4463if(contains(*h))4464// Deg1_Elements.push_back(*h);4465cout << *h;4466}4467exit(0);4468is_Computed.set(ConeProperty::Deg1Elements,true);4469}4470*/44714472//---------------------------------------------------------------------------44734474template<typename Integer>4475void Full_Cone<Integer>::check_pointed() {4476if (isComputed(ConeProperty::IsPointed))4477return;4478assert(isComputed(ConeProperty::SupportHyperplanes));4479if (isComputed(ConeProperty::Grading)){4480pointed=true;4481if (verbose) verboseOutput() << "Pointed since graded" << endl;4482is_Computed.set(ConeProperty::IsPointed);4483return;4484}4485if (verbose) verboseOutput() << "Checking pointedness ... " << flush;4486if(Support_Hyperplanes.nr_of_rows() <= dim*dim/2){4487pointed = (Support_Hyperplanes.rank() == dim);4488}4489else4490pointed = (Support_Hyperplanes.max_rank_submatrix_lex().size() == dim);4491is_Computed.set(ConeProperty::IsPointed);4492if(pointed && Grading.size()>0){4493throw BadInputException("Grading not positive on pointed cone.");4494}4495if (verbose) verboseOutput() << "done." << endl;4496}449744984499//---------------------------------------------------------------------------4500template<typename Integer>4501void Full_Cone<Integer>::disable_grading_dep_comp() {45024503if (do_multiplicity || do_deg1_elements || do_h_vector) {4504if (do_default_mode) {4505// if (verbose)4506// verboseOutput() << "No grading specified and cannot find one. "4507// << "Disabling some computations!" << endl;4508do_deg1_elements = false;4509do_h_vector = false;4510if(!explicit_full_triang){4511do_triangulation=false;4512if(do_Hilbert_basis)4513do_partial_triangulation=true;4514}4515} else {4516throw BadInputException("No grading specified and cannot find one. Cannot compute some requested properties!");4517}4518}4519}45204521//---------------------------------------------------------------------------45224523template<typename Integer>4524void Full_Cone<Integer>::deg1_check() {45254526if(inhomogeneous) // deg 1 check disabled since it makes no sense in this case4527return;45284529if (!isComputed(ConeProperty::Grading) && Grading.size()==0 // we still need it and4530&& !isComputed(ConeProperty::IsDeg1ExtremeRays)) { // we have not tried it4531if (isComputed(ConeProperty::ExtremeRays)) {4532Matrix<Integer> Extreme=Generators.submatrix(Extreme_Rays_Ind);4533if (has_generator_with_common_divisor)4534Extreme.make_prime();4535try{4536Grading = Extreme.find_linear_form();4537} catch(const ArithmeticException& e) { // if the exception has been thrown, the grading has4538Grading.resize(0); // we consider the grafing as non existing -- though this may not be true4539if(verbose)4540verboseOutput() << "Giving up the check for a grading" << endl;4541}45424543if (Grading.size() == dim && v_scalar_product(Grading,Extreme[0])==1) {4544is_Computed.set(ConeProperty::Grading);4545} else {4546deg1_extreme_rays = false;4547Grading.clear();4548is_Computed.set(ConeProperty::IsDeg1ExtremeRays);4549}4550} else // extreme rays not known4551if (!deg1_generated_computed) {4552Matrix<Integer> GenCopy = Generators;4553if (has_generator_with_common_divisor)4554GenCopy.make_prime();4555try{4556Grading = GenCopy.find_linear_form();4557} catch(const ArithmeticException& e) { // if the exception has been thrown,4558Grading.resize(0); // we consider the grafing as non existing-- though this may not be true4559if(verbose)4560verboseOutput() << "Giving up the check for a grading" << endl;4561}4562if (Grading.size() == dim && v_scalar_product(Grading,GenCopy[0])==1) {4563is_Computed.set(ConeProperty::Grading);4564} else {4565deg1_generated = false;4566deg1_generated_computed = true;4567Grading.clear();4568}4569}4570}45714572//now we hopefully have a grading45734574if (!isComputed(ConeProperty::Grading)) {4575if (isComputed(ConeProperty::ExtremeRays)) {4576// there is no hope to find a grading later4577deg1_generated = false;4578deg1_generated_computed = true;4579deg1_extreme_rays = false;4580is_Computed.set(ConeProperty::IsDeg1ExtremeRays);4581disable_grading_dep_comp();4582}4583return; // we are done4584}45854586set_degrees();45874588vector<Integer> divided_gen_degrees = gen_degrees;4589if (has_generator_with_common_divisor) {4590Matrix<Integer> GenCopy = Generators;4591GenCopy.make_prime();4592convert(divided_gen_degrees, GenCopy.MxV(Grading));4593}45944595if (!deg1_generated_computed) {4596deg1_generated = true;4597for (size_t i = 0; i < nr_gen; i++) {4598if (divided_gen_degrees[i] != 1) {4599deg1_generated = false;4600break;4601}4602}4603deg1_generated_computed = true;4604if (deg1_generated) {4605deg1_extreme_rays = true;4606is_Computed.set(ConeProperty::IsDeg1ExtremeRays);4607}4608}4609if (!isComputed(ConeProperty::IsDeg1ExtremeRays)4610&& isComputed(ConeProperty::ExtremeRays)) {4611deg1_extreme_rays = true;4612for (size_t i = 0; i < nr_gen; i++) {4613if (Extreme_Rays_Ind[i] && divided_gen_degrees[i] != 1) {4614deg1_extreme_rays = false;4615break;4616}4617}4618is_Computed.set(ConeProperty::IsDeg1ExtremeRays);4619}4620}46214622//---------------------------------------------------------------------------46234624template<typename Integer>4625void Full_Cone<Integer>::check_deg1_hilbert_basis() {4626if (isComputed(ConeProperty::IsDeg1HilbertBasis) || inhomogeneous)4627return;46284629if ( !isComputed(ConeProperty::Grading) || !isComputed(ConeProperty::HilbertBasis)) {4630if (verbose) {4631errorOutput() << "WARNING: unsatisfied preconditions in check_deg1_hilbert_basis()!" <<endl;4632}4633return;4634}46354636if (isComputed(ConeProperty::Deg1Elements)) {4637deg1_hilbert_basis = (Deg1_Elements.size() == Hilbert_Basis.size());4638} else {4639deg1_hilbert_basis = true;4640typename list< vector<Integer> >::iterator h;4641for (h = Hilbert_Basis.begin(); h != Hilbert_Basis.end(); ++h) {4642if (v_scalar_product((*h),Grading)!=1) {4643deg1_hilbert_basis = false;4644break;4645}4646}4647}4648is_Computed.set(ConeProperty::IsDeg1HilbertBasis);4649}46504651//---------------------------------------------------------------------------46524653// Computes the generators of a supercone approximating "this" by a cone over a lattice polytope4654// for every vertex of the simplex, we get a matrix with the integer points of the respective Weyl chamber4655template<typename Integer>4656vector<list<vector<Integer>>> Full_Cone<Integer>::latt_approx() {46574658assert(isComputed(ConeProperty::Grading));4659assert(isComputed(ConeProperty::ExtremeRays));4660Matrix<Integer> G(1,dim);4661G[0]=Grading;4662Matrix<Integer> G_copy=G;46634664// Lineare_Transformation<Integer> NewBasis(G); // gives a new basis in which the grading is a coordinate4665size_t dummy;4666Matrix<Integer> U=G_copy.SmithNormalForm(dummy); // the basis elements are the columns of U46674668Integer dummy_denom;4669// vector<Integer> dummy_diag(dim);4670Matrix<Integer> T=U.invert(dummy_denom); // T is the coordinate transformation4671// to the new basis: v --> Tv (in this case)4672// for which the grading is the FIRST coordinate46734674assert(dummy_denom==1); // for safety46754676// It can happen that -Grading has become the first row of T, but we want Grading. If necessary we replace the4677// first row by its negative, and correspondingly the first column of U by its negative46784679if(T[0]!=Grading){4680for(size_t i=0;i<dim;++i){4681U[i][0]*=-1;4682T[0][i]*=-1;4683}4684}4685assert(T[0] == Grading);46864687Matrix<Integer> M;4688vector<list<vector<Integer>>> approx_points;4689size_t nr_approx=0;4690for(size_t i=0;i<nr_gen;++i){4691list<vector<Integer> > approx;4692if(Extreme_Rays_Ind[i]){4693//cout << "point before transformation: " << Generators[i];4694approx_simplex(T.MxV(Generators[i]),approx,1);4695// TODO: NECESSARY?4696//approx.unique()4697//cout << "Approximation points for generator " << i << ": " << Generators[i] << endl;4698nr_approx = 0;4699for(auto jt=approx.begin();jt!=approx.end();++jt){ // reverse transformation4700*jt=U.MxV(*jt);4701v_make_prime(*jt);4702++nr_approx;4703//cout << *jt << endl;4704}4705//~ M=Matrix<Integer>(approx);4706//~4707//~ // remove duplicates4708//~ for (size_t j=0;j<approx_points.size();j++){4709//~ M.remove_duplicate(approx_points[j]);4710//~ }4711// +++ TODO: REMOVE DUPLICATES MORE EFFICIENT +++4712if (nr_approx>1){4713for (size_t j=0;j<approx_points.size();j++){4714for (auto jt=approx_points[j].begin();jt!=approx_points[j].end();++jt){4715approx.remove(*jt);4716}4717}4718}4719}4720approx_points.push_back(approx);4721}472247234724//cout << "-------" << endl;4725//M.print(cout);4726//cout << "-------" << endl;47274728return(approx_points);4729}47304731//---------------------------------------------------------------------------47324733template<typename Integer>4734void Full_Cone<Integer>::prepare_inclusion_exclusion() {47354736if (ExcludedFaces.nr_of_rows() == 0)4737return;47384739do_excluded_faces = do_h_vector || do_Stanley_dec;47404741if (verbose && !do_excluded_faces) {4742errorOutput() << endl << "WARNING: exluded faces, but no h-vector computation or Stanley decomposition"4743<< endl << "Therefore excluded faces will be ignored" << endl;4744}47454746if (isComputed(ConeProperty::ExcludedFaces) &&4747(isComputed(ConeProperty::InclusionExclusionData) || !do_excluded_faces) ) {4748return;4749}47504751// indicates which generators lie in the excluded faces4752vector<boost::dynamic_bitset<> > GensInExcl(ExcludedFaces.nr_of_rows());47534754for(size_t j=0;j<ExcludedFaces.nr_of_rows();++j){ // now we produce these indicators4755bool first_neq_0=true; // and check whether the linear forms in ExcludedFaces4756bool non_zero=false; // have the cone on one side4757GensInExcl[j].resize(nr_gen,false);4758for(size_t i=0; i< nr_gen;++i){4759Integer test=v_scalar_product(ExcludedFaces[j],Generators[i]);4760if(test==0){4761GensInExcl[j].set(i);4762continue;4763}4764non_zero=true;4765if(first_neq_0){4766first_neq_0=false;4767if(test<0){4768for(size_t k=0;k<dim;++k) // replace linear form by its negative4769ExcludedFaces[j][k]*=-1; // to get cone in positive halfspace4770test*=-1; // (only for error check)4771}4772}4773if(test<0){4774throw FatalException("Excluded hyperplane does not define a face.");4775}47764777}4778if(!non_zero){ // not impossible if the hyperplane contains the vector space spanned by the cone4779throw FatalException("Excluded face contains the full cone.");4780}4781}47824783vector<bool> essential(ExcludedFaces.nr_of_rows(),true);4784bool remove_one=false;4785for(size_t i=0;i<essential.size();++i)4786for(size_t j=i+1;j<essential.size();++j){4787if(GensInExcl[j].is_subset_of(GensInExcl[i])){4788essential[j]=false;4789remove_one=true;4790continue;4791}4792if(GensInExcl[i].is_subset_of(GensInExcl[j])){4793essential[i]=false;4794remove_one=true;4795}4796}4797if(remove_one){4798Matrix<Integer> Help(0,dim);4799vector<boost::dynamic_bitset<> > HelpGensInExcl;4800for(size_t i=0;i<essential.size();++i)4801if(essential[i]){4802Help.append(ExcludedFaces[i]);4803HelpGensInExcl.push_back(GensInExcl[i]);4804}4805ExcludedFaces=Help;4806GensInExcl=HelpGensInExcl;4807}4808is_Computed.set(ConeProperty::ExcludedFaces);4809481048114812if (isComputed(ConeProperty::InclusionExclusionData) || !do_excluded_faces) {4813return;4814}48154816vector< pair<boost::dynamic_bitset<> , long> > InExScheme; // now we produce the formal4817boost::dynamic_bitset<> all_gens(nr_gen); // inclusion-exclusion scheme4818all_gens.set(); // by forming all intersections of4819// excluded faces4820InExScheme.push_back(pair<boost::dynamic_bitset<> , long> (all_gens, 1));4821size_t old_size=1;48224823for(size_t i=0;i<ExcludedFaces.nr_of_rows();++i){4824for(size_t j=0;j<old_size;++j)4825InExScheme.push_back(pair<boost::dynamic_bitset<> , long>4826(InExScheme[j].first & GensInExcl[i], -InExScheme[j].second));4827old_size*=2;4828}48294830vector<pair<boost::dynamic_bitset<>, long> >::iterator G;48314832InExScheme.erase(InExScheme.begin()); // remove full cone48334834// map<boost::dynamic_bitset<>, long> InExCollect;4835InExCollect.clear();4836map<boost::dynamic_bitset<>, long>::iterator F;48374838for(size_t i=0;i<old_size-1;++i){ // we compactify the list of faces4839F=InExCollect.find(InExScheme[i].first); // obtained as intersections4840if(F!=InExCollect.end()) // by listing each face only once4841F->second+=InExScheme[i].second; // but with the right multiplicity4842else4843InExCollect.insert(InExScheme[i]);4844}48454846for(F=InExCollect.begin();F!=InExCollect.end();){ // faces with multiplicity 04847if(F->second==0) // can be erased4848InExCollect.erase(F++);4849else{4850++F;4851}4852}48534854if(verbose){4855verboseOutput() << endl;4856verboseOutput() << "InEx complete, " << InExCollect.size() << " faces involved" << endl;4857}48584859is_Computed.set(ConeProperty::InclusionExclusionData);4860}4861486248634864//---------------------------------------------------------------------------48654866/* computes a degree function, s.t. every generator has value >0 */4867template<typename Integer>4868vector<Integer> Full_Cone<Integer>::compute_degree_function() const {4869size_t i;4870vector<Integer> degree_function(dim,0);4871if (isComputed(ConeProperty::Grading)) { //use the grading if we have one4872for (i=0; i<dim; i++) {4873degree_function[i] = Grading[i];4874}4875} else { // add hyperplanes to get a degree function4876if(verbose) {4877verboseOutput()<<"computing degree function... "<<flush;4878}4879size_t h;4880for (h=0; h<Support_Hyperplanes.nr_of_rows(); ++h) {4881for (i=0; i<dim; i++) {4882degree_function[i] += Support_Hyperplanes.get_elem(h,i);4883}4884}4885v_make_prime(degree_function);4886if(verbose) {4887verboseOutput()<<"done."<<endl;4888}4889}4890return degree_function;4891}48924893//---------------------------------------------------------------------------48944895/* adds generators, they have to lie inside the existing cone */4896template<typename Integer>4897void Full_Cone<Integer>::add_generators(const Matrix<Integer>& new_points) {4898is_simplicial = false;4899int nr_new_points = new_points.nr_of_rows();4900int nr_old_gen = nr_gen;4901Generators.append(new_points);4902nr_gen += nr_new_points;4903set_degrees();4904Top_Key.resize(nr_gen);4905Extreme_Rays_Ind.resize(nr_gen);4906for (size_t i=nr_old_gen; i<nr_gen; ++i) {4907Top_Key[i] = i;4908Extreme_Rays_Ind[i] = false;4909}4910// inhom cones4911if (inhomogeneous) {4912set_levels();4913}4914// excluded faces have to be reinitialized4915is_Computed.set(ConeProperty::ExcludedFaces, false);4916is_Computed.set(ConeProperty::InclusionExclusionData, false);4917prepare_inclusion_exclusion();49184919if (do_Hilbert_basis) {4920// add new points to HilbertBasis4921for (size_t i = nr_old_gen; i < nr_gen; ++i) {4922if(!inhomogeneous || gen_levels[i]<=1) {4923OldCandidates.Candidates.push_back(Candidate<Integer>(Generators[i],*this));4924OldCandidates.Candidates.back().original_generator=true;4925}4926}4927OldCandidates.auto_reduce();4928}4929}49304931//---------------------------------------------------------------------------4932// Constructors4933//---------------------------------------------------------------------------49344935template<typename Integer>4936void Full_Cone<Integer>::reset_tasks(){4937do_triangulation = false;4938do_partial_triangulation = false;4939do_determinants = false;4940do_multiplicity=false;4941do_integrally_closed = false;4942do_Hilbert_basis = false;4943do_deg1_elements = false;4944keep_triangulation = false;4945do_Stanley_dec=false;4946do_h_vector=false;4947do_hsop = false;4948do_excluded_faces=false;4949do_approximation=false;4950do_default_mode=false;4951do_class_group = false;4952do_module_gens_intcl = false;4953do_module_rank = false;4954do_cone_dec=false;4955stop_after_cone_dec=false;49564957do_extreme_rays=false;4958do_pointed=false;49594960do_evaluation = false;4961do_only_multiplicity=false;49624963use_bottom_points = true;49644965nrSimplicialPyr=0;4966totalNrPyr=0;4967is_pyramid = false;4968triangulation_is_nested = false;4969triangulation_is_partial = false;4970}497149724973//---------------------------------------------------------------------------49744975template<typename Integer>4976Full_Cone<Integer>::Full_Cone(const Matrix<Integer>& M, bool do_make_prime){ // constructor of the top cone49774978omp_start_level=omp_get_level();49794980dim=M.nr_of_columns();4981if(dim>0)4982Generators=M;4983/* M.pretty_print(cout);4984cout << "------------------" << endl;4985M.transpose().pretty_print(cout);4986cout << "==================" << endl;*/49874988// assert(M.row_echelon()== dim); rank check now done later49894990/*index=1; // not used at present4991for(size_t i=0;i<dim;++i)4992index*=M[i][i];4993index=Iabs(index); */49944995//make the generators coprime, remove 0 rows and duplicates4996has_generator_with_common_divisor = false;4997if (do_make_prime) {4998Generators.make_prime();4999} else {5000nr_gen = Generators.nr_of_rows();5001for (size_t i = 0; i < nr_gen; ++i) {5002if (v_gcd(Generators[i]) != 1) {5003has_generator_with_common_divisor = true;5004break;5005}5006}5007}5008Generators.remove_duplicate_and_zero_rows();5009nr_gen = Generators.nr_of_rows();50105011if (nr_gen != static_cast<size_t>(static_cast<key_t>(nr_gen))) {5012throw FatalException("Too many generators to fit in range of key_t!");5013}50145015multiplicity = 0;5016is_Computed = bitset<ConeProperty::EnumSize>(); //initialized to false5017is_Computed.set(ConeProperty::Generators);5018pointed = false;5019is_simplicial = nr_gen == dim;5020deg1_extreme_rays = false;5021deg1_generated = false;5022deg1_generated_computed = false;5023deg1_hilbert_basis = false;50245025reset_tasks();50265027Extreme_Rays_Ind = vector<bool>(nr_gen,false);5028in_triang = vector<bool> (nr_gen,false);5029deg1_triangulation = true;5030if(dim==0){ //correction needed to include the 0 cone;5031multiplicity = 1;5032Hilbert_Series.add(vector<num_t>(1,1),vector<denom_t>());5033is_Computed.set(ConeProperty::HilbertSeries);5034is_Computed.set(ConeProperty::Triangulation);5035}5036pyr_level=-1;5037Top_Cone=this;5038Top_Key.resize(nr_gen);5039for(size_t i=0;i<nr_gen;i++)5040Top_Key[i]=i;5041totalNrSimplices=0;5042TriangulationBufferSize=0;5043CandidatesSize=0;5044detSum = 0;5045shift = 0;50465047FS.resize(omp_get_max_threads());50485049Pyramids.resize(20); // prepare storage for pyramids5050nrPyramids.resize(20,0);5051Pyramids_scrambled.resize(20,false);50525053recursion_allowed=true;50545055do_all_hyperplanes=true;5056// multithreaded_pyramid=true; now in build_cone where it is defined dynamically505750585059nextGen=0;5060store_level=0;50615062Comparisons.reserve(nr_gen);5063nrTotalComparisons=0;50645065inhomogeneous=false;50665067level0_dim=dim; // must always be defined50685069use_existing_facets=false;5070start_from=0;5071old_nr_supp_hyps=0;50725073verbose=false;5074OldCandidates.dual=false;5075OldCandidates.verbose=verbose;5076NewCandidates.dual=false;5077NewCandidates.verbose=verbose;50785079RankTest = vector< Matrix<Integer> >(omp_get_max_threads(), Matrix<Integer>(0,dim));50805081do_bottom_dec=false;5082suppress_bottom_dec=false;5083keep_order=false;50845085is_approximation=false;5086is_global_approximation=false;50875088PermGens.resize(nr_gen);5089for(size_t i=0;i<nr_gen;++i)5090PermGens[i]=i;5091}50925093//---------------------------------------------------------------------------50945095template<typename Integer>5096Full_Cone<Integer>::Full_Cone(Cone_Dual_Mode<Integer> &C) {50975098omp_start_level=omp_get_level();50995100is_Computed = bitset<ConeProperty::EnumSize>(); //initialized to false51015102dim = C.dim;5103Generators.swap(C.Generators);5104nr_gen = Generators.nr_of_rows();5105if (Generators.nr_of_rows() > 0)5106is_Computed.set(ConeProperty::Generators);5107has_generator_with_common_divisor = false;5108Extreme_Rays_Ind.swap(C.ExtremeRaysInd);5109if (!Extreme_Rays_Ind.empty()) is_Computed.set(ConeProperty::ExtremeRays);51105111multiplicity = 0;5112in_triang = vector<bool>(nr_gen,false);51135114Basis_Max_Subspace=C.BasisMaxSubspace;5115is_Computed.set(ConeProperty::MaximalSubspace);5116pointed = (Basis_Max_Subspace.nr_of_rows()==0);5117is_Computed.set(ConeProperty::IsPointed);5118is_simplicial = nr_gen == dim;5119deg1_extreme_rays = false;5120deg1_generated = false;5121deg1_generated_computed = false;5122deg1_triangulation = false;5123deg1_hilbert_basis = false;51245125reset_tasks();51265127if (!Extreme_Rays_Ind.empty()) { // only then we can assume that all entries on C.Supp.. are relevant5128Support_Hyperplanes.swap(C.SupportHyperplanes);5129// there may be duplicates in the coordinates of the Full_Cone5130Support_Hyperplanes.remove_duplicate_and_zero_rows();5131is_Computed.set(ConeProperty::SupportHyperplanes);5132}5133if(!C.do_only_Deg1_Elements){5134Hilbert_Basis.swap(C.Hilbert_Basis);5135is_Computed.set(ConeProperty::HilbertBasis);5136}5137else {5138Deg1_Elements.swap(C.Hilbert_Basis);5139is_Computed.set(ConeProperty::Deg1Elements);5140}5141if(dim==0){ //correction needed to include the 0 cone;5142multiplicity = 1;5143Hilbert_Series.add(vector<num_t>(1,1),vector<denom_t>());5144is_Computed.set(ConeProperty::HilbertSeries);5145}5146pyr_level=-1;5147Top_Cone=this;5148Top_Key.resize(nr_gen);5149for(size_t i=0;i<nr_gen;i++)5150Top_Key[i]=i;5151totalNrSimplices=0;5152TriangulationBufferSize=0;5153CandidatesSize=0;5154detSum = 0;5155shift = 0;51565157do_all_hyperplanes=true;51585159tri_recursion=false;51605161nextGen=0;51625163inhomogeneous=C.inhomogeneous;51645165level0_dim=dim; // must always be defined51665167use_existing_facets=false;5168start_from=0;5169old_nr_supp_hyps=0;5170verbose = C.verbose;5171OldCandidates.dual=false;5172OldCandidates.verbose=verbose;5173NewCandidates.dual=false;5174NewCandidates.verbose=verbose;51755176is_approximation=false;51775178verbose=C.verbose;5179}51805181//---------------------------------------------------------------------------51825183template<typename Integer>5184void Full_Cone<Integer>::check_grading_after_dual_mode(){51855186if(dim>0 && Grading.size()>0 && !isComputed(ConeProperty::Grading)) {5187if(isComputed(ConeProperty::Generators)){5188vector<Integer> degrees=Generators.MxV(Grading);5189vector<Integer> levels;5190if(inhomogeneous)5191levels=Generators.MxV(Truncation);5192size_t i=0;5193for(;i<degrees.size();++i){5194if(degrees[i]<=0 &&(!inhomogeneous || levels[i]==0))5195break;5196}5197if(i==degrees.size())5198is_Computed.set(ConeProperty::Grading);5199}5200else if(isComputed(ConeProperty::HilbertBasis)){5201auto hb=Hilbert_Basis.begin();5202for(;hb!=Hilbert_Basis.end();++hb){5203if(v_scalar_product(*hb,Grading)<=0 && (!inhomogeneous || v_scalar_product(*hb,Truncation)==0))5204break;5205}5206if(hb==Hilbert_Basis.end())5207is_Computed.set(ConeProperty::Grading);5208}5209}5210if(isComputed(ConeProperty::Deg1Elements)){5211auto hb=Deg1_Elements.begin();5212for(;hb!=Deg1_Elements.end();++hb){5213if(v_scalar_product(*hb,Grading)<=0)5214break;5215}5216if(hb==Deg1_Elements.end())5217is_Computed.set(ConeProperty::Grading);5218}52195220if(Grading.size()>0 && !isComputed(ConeProperty::Grading)){5221throw BadInputException("Grading not positive on pointed cone.");5222}5223}52245225template<typename Integer>5226void Full_Cone<Integer>::dual_mode() {52275228omp_start_level=omp_get_level();52295230if(dim==0){5231set_zero_cone();5232return;5233}52345235use_existing_facets=false; // completely irrelevant here5236start_from=0;5237old_nr_supp_hyps=0;52385239INTERRUPT_COMPUTATION_BY_EXCEPTION52405241compute_class_group();52425243check_grading_after_dual_mode();52445245if(dim>0 && !inhomogeneous){5246deg1_check();5247if (isComputed(ConeProperty::Grading) && !isComputed(ConeProperty::Deg1Elements)) {5248if (verbose) {5249verboseOutput() << "Find degree 1 elements" << endl;5250}5251select_deg1_elements();5252}5253}52545255if(dim==0){5256deg1_extreme_rays = deg1_generated = true;5257Grading=vector<Integer>(dim);5258is_Computed.set(ConeProperty::IsDeg1ExtremeRays);5259deg1_generated_computed = true;5260is_Computed.set(ConeProperty::Grading);5261}5262if(!inhomogeneous && isComputed(ConeProperty::HilbertBasis)){5263if (isComputed(ConeProperty::Grading)) check_deg1_hilbert_basis();5264}52655266if (inhomogeneous && isComputed(ConeProperty::Generators)) {5267set_levels();5268find_level0_dim();5269find_module_rank();5270}52715272use_existing_facets=false;5273start_from=0;5274}52755276//---------------------------------------------------------------------------52775278/* constructor for pyramids */5279template<typename Integer>5280Full_Cone<Integer>::Full_Cone(Full_Cone<Integer>& C, const vector<key_t>& Key) {52815282omp_start_level=C.omp_start_level;52835284Generators = C.Generators.submatrix(Key);5285dim = Generators.nr_of_columns();5286nr_gen = Generators.nr_of_rows();5287has_generator_with_common_divisor = C.has_generator_with_common_divisor;5288is_simplicial = nr_gen == dim;52895290Top_Cone=C.Top_Cone; // relate to top cone5291Top_Key.resize(nr_gen);5292for(size_t i=0;i<nr_gen;i++)5293Top_Key[i]=C.Top_Key[Key[i]];52945295multiplicity = 0;52965297Extreme_Rays_Ind = vector<bool>(nr_gen,false);5298is_Computed.set(ConeProperty::ExtremeRays, C.isComputed(ConeProperty::ExtremeRays));5299if(isComputed(ConeProperty::ExtremeRays))5300for(size_t i=0;i<nr_gen;i++)5301Extreme_Rays_Ind[i]=C.Extreme_Rays_Ind[Key[i]];5302in_triang = vector<bool> (nr_gen,false);5303deg1_triangulation = true;53045305// not used in a pyramid, but set precaution5306deg1_extreme_rays = false;5307deg1_generated = false;5308deg1_generated_computed = false;5309deg1_hilbert_basis = false;53105311Grading=C.Grading;5312is_Computed.set(ConeProperty::Grading, C.isComputed(ConeProperty::Grading));5313Order_Vector=C.Order_Vector;53145315do_extreme_rays=false;5316do_triangulation=C.do_triangulation;5317do_partial_triangulation=C.do_partial_triangulation;5318do_determinants=C.do_determinants;5319do_multiplicity=C.do_multiplicity;5320do_deg1_elements=C.do_deg1_elements;5321do_h_vector=C.do_h_vector;5322do_Hilbert_basis=C.do_Hilbert_basis;5323keep_triangulation=C.keep_triangulation;5324do_only_multiplicity=C.do_only_multiplicity;5325do_evaluation=C.do_evaluation;5326do_Stanley_dec=C.do_Stanley_dec;5327inhomogeneous=C.inhomogeneous; // at present not used in proper pyramids5328is_pyramid=true;53295330pyr_level=C.pyr_level+1;53315332totalNrSimplices=0;5333detSum = 0;5334shift = C.shift;5335if(C.gen_degrees.size()>0){ // now we copy the degrees5336gen_degrees.resize(nr_gen);5337for (size_t i=0; i<nr_gen; i++) {5338gen_degrees[i] = C.gen_degrees[Key[i]];5339}5340}5341if(C.gen_levels.size()>0){ // now we copy the levels5342gen_levels.resize(nr_gen);5343for (size_t i=0; i<nr_gen; i++) {5344gen_levels[i] = C.gen_levels[Key[i]];5345}5346}5347TriangulationBufferSize=0;5348CandidatesSize=0;53495350recursion_allowed=C.recursion_allowed; // must be reset if necessary5351do_all_hyperplanes=true; // must be reset for non-recursive pyramids5352// multithreaded_pyramid=false; // SEE ABOVE53535354nextGen=0;5355store_level = C.store_level;53565357Comparisons.reserve(nr_gen);5358nrTotalComparisons=0;53595360level0_dim = C.level0_dim; // must always be defined53615362use_existing_facets=false;5363start_from=0;5364old_nr_supp_hyps=0;5365verbose=false;5366OldCandidates.dual=false;5367OldCandidates.verbose=verbose;5368NewCandidates.dual=false;5369NewCandidates.verbose=verbose;53705371is_approximation = C.is_approximation;5372is_global_approximation = C.is_global_approximation;53735374do_bottom_dec=false;5375suppress_bottom_dec=false;5376keep_order=true;5377}53785379//---------------------------------------------------------------------------53805381template<typename Integer>5382void Full_Cone<Integer>::set_zero_cone() {53835384assert(dim==0);53855386if (verbose) {5387verboseOutput() << "Zero cone detected!" << endl;5388}53895390// The basis change already is transforming to zero.5391is_Computed.set(ConeProperty::Sublattice);5392is_Computed.set(ConeProperty::Generators);5393is_Computed.set(ConeProperty::ExtremeRays);5394Support_Hyperplanes=Matrix<Integer> (0);5395is_Computed.set(ConeProperty::SupportHyperplanes);5396totalNrSimplices = 0;5397is_Computed.set(ConeProperty::TriangulationSize);5398detSum = 0;5399is_Computed.set(ConeProperty::TriangulationDetSum);5400is_Computed.set(ConeProperty::Triangulation);5401is_Computed.set(ConeProperty::StanleyDec);5402multiplicity = 1;5403is_Computed.set(ConeProperty::Multiplicity);5404is_Computed.set(ConeProperty::HilbertBasis);5405is_Computed.set(ConeProperty::Deg1Elements);54065407Hilbert_Series = HilbertSeries(vector<num_t>(1,1),vector<denom_t>()); // 1/15408is_Computed.set(ConeProperty::HilbertSeries);54095410if (!is_Computed.test(ConeProperty::Grading)) {5411Grading = vector<Integer>(dim);5412// GradingDenom = 1;5413is_Computed.set(ConeProperty::Grading);5414}54155416pointed = true;5417is_Computed.set(ConeProperty::IsPointed);54185419deg1_extreme_rays = true;5420is_Computed.set(ConeProperty::IsDeg1ExtremeRays);54215422deg1_hilbert_basis = true;5423is_Computed.set(ConeProperty::IsDeg1HilbertBasis);54245425if (inhomogeneous) { // empty set of solutions5426is_Computed.set(ConeProperty::VerticesOfPolyhedron);5427module_rank = 0;5428is_Computed.set(ConeProperty::ModuleRank);5429is_Computed.set(ConeProperty::ModuleGenerators);5430level0_dim=0;5431is_Computed.set(ConeProperty::RecessionRank);5432}54335434if (!inhomogeneous) {5435ClassGroup.resize(1,0);5436is_Computed.set(ConeProperty::ClassGroup);5437}54385439if (inhomogeneous || ExcludedFaces.nr_of_rows() != 0) {5440multiplicity = 0;5441is_Computed.set(ConeProperty::Multiplicity);5442Hilbert_Series.reset(); // 0/15443is_Computed.set(ConeProperty::HilbertSeries);5444}5445}54465447//---------------------------------------------------------------------------54485449template<typename Integer>5450bool Full_Cone<Integer>::isComputed(ConeProperty::Enum prop) const{5451return is_Computed.test(prop);5452}54535454//---------------------------------------------------------------------------5455// Data access5456//---------------------------------------------------------------------------54575458template<typename Integer>5459size_t Full_Cone<Integer>::getDimension()const{5460return dim;5461}54625463//---------------------------------------------------------------------------54645465template<typename Integer>5466size_t Full_Cone<Integer>::getNrGenerators()const{5467return nr_gen;5468}54695470//---------------------------------------------------------------------------54715472template<typename Integer>5473bool Full_Cone<Integer>::isPointed()const{5474return pointed;5475}54765477//---------------------------------------------------------------------------54785479template<typename Integer>5480bool Full_Cone<Integer>::isDeg1ExtremeRays() const{5481return deg1_extreme_rays;5482}54835484template<typename Integer>5485bool Full_Cone<Integer>::isDeg1HilbertBasis() const{5486return deg1_hilbert_basis;5487}54885489//---------------------------------------------------------------------------54905491template<typename Integer>5492vector<Integer> Full_Cone<Integer>::getGrading() const{5493return Grading;5494}54955496//---------------------------------------------------------------------------54975498template<typename Integer>5499mpq_class Full_Cone<Integer>::getMultiplicity()const{5500return multiplicity;5501}55025503//---------------------------------------------------------------------------55045505template<typename Integer>5506Integer Full_Cone<Integer>::getShift()const{5507return shift;5508}55095510//---------------------------------------------------------------------------55115512template<typename Integer>5513size_t Full_Cone<Integer>::getModuleRank()const{5514return module_rank;5515}551655175518//---------------------------------------------------------------------------55195520template<typename Integer>5521const Matrix<Integer>& Full_Cone<Integer>::getGenerators()const{5522return Generators;5523}55245525//---------------------------------------------------------------------------55265527template<typename Integer>5528vector<bool> Full_Cone<Integer>::getExtremeRays()const{5529return Extreme_Rays_Ind;5530}55315532//---------------------------------------------------------------------------55335534template<typename Integer>5535Matrix<Integer> Full_Cone<Integer>::getSupportHyperplanes()const{5536return Support_Hyperplanes;5537}55385539//---------------------------------------------------------------------------55405541template<typename Integer>5542Matrix<Integer> Full_Cone<Integer>::getHilbertBasis()const{5543if(Hilbert_Basis.empty())5544return Matrix<Integer>(0,dim);5545else5546return Matrix<Integer>(Hilbert_Basis);5547}55485549//---------------------------------------------------------------------------55505551template<typename Integer>5552Matrix<Integer> Full_Cone<Integer>::getModuleGeneratorsOverOriginalMonoid()const{5553if(ModuleGeneratorsOverOriginalMonoid.empty())5554return Matrix<Integer>(0,dim);5555else5556return Matrix<Integer>(ModuleGeneratorsOverOriginalMonoid);5557}555855595560//---------------------------------------------------------------------------55615562template<typename Integer>5563Matrix<Integer> Full_Cone<Integer>::getDeg1Elements()const{5564if(Deg1_Elements.empty())5565return Matrix<Integer>(0,dim);5566else5567return Matrix<Integer>(Deg1_Elements);5568}55695570//---------------------------------------------------------------------------55715572template<typename Integer>5573Matrix<Integer> Full_Cone<Integer>::getExcludedFaces()const{5574return(ExcludedFaces);5575}55765577//---------------------------------------------------------------------------55785579template<typename Integer>5580void Full_Cone<Integer>::error_msg(string s) const{5581errorOutput() <<"\nFull Cone "<< s<<"\n";5582}55835584//---------------------------------------------------------------------------55855586template<typename Integer>5587void Full_Cone<Integer>::print()const{5588verboseOutput()<<"\ndim="<<dim<<".\n";5589verboseOutput()<<"\nnr_gen="<<nr_gen<<".\n";5590// verboseOutput()<<"\nhyp_size="<<hyp_size<<".\n";5591verboseOutput()<<"\nGrading is:\n";5592verboseOutput()<< Grading;5593verboseOutput()<<"\nMultiplicity is "<<multiplicity<<".\n";5594verboseOutput()<<"\nGenerators are:\n";5595Generators.pretty_print(verboseOutput());5596verboseOutput()<<"\nExtreme_rays are:\n";5597verboseOutput()<< Extreme_Rays_Ind;5598verboseOutput()<<"\nSupport Hyperplanes are:\n";5599Support_Hyperplanes.pretty_print(verboseOutput());5600verboseOutput()<<"\nHilbert basis is:\n";5601verboseOutput()<< Hilbert_Basis;5602verboseOutput()<<"\nDeg1 elements are:\n";5603verboseOutput()<< Deg1_Elements;5604verboseOutput()<<"\nHilbert Series is:\n";5605verboseOutput()<<Hilbert_Series;5606}56075608} //end namespace560956105611