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 <vector>27#include <map>28#include <set>29#include <iostream>30#include <string>31#include <algorithm>3233#include "libnormaliz/cone_dual_mode.h"34#include "libnormaliz/vector_operations.h"35#include "libnormaliz/list_operations.h"3637//---------------------------------------------------------------------------3839namespace libnormaliz {40using namespace std;4142//---------------------------------------------------------------------------43//private44//---------------------------------------------------------------------------4546template<typename Integer>47void Cone_Dual_Mode<Integer>::splice_them_sort(CandidateList< Integer>& Total, vector<CandidateList< Integer> >& Parts){4849CandidateList<Integer> New;50New.verbose=verbose;51New.dual=true;52for(int i=0;i<omp_get_max_threads();i++)53New.Candidates.splice(New.Candidates.end(),Parts[i].Candidates);54New.sort_by_val();55New.unique_vectors();56Total.merge_by_val(New);57}5859//---------------------------------------------------------------------------6061template<typename Integer>62void Cone_Dual_Mode<Integer>::select_HB(CandidateList<Integer>& Cand, size_t guaranteed_HB_deg,63CandidateList<Integer>& Irred, bool all_irreducible){6465if(all_irreducible){66Irred.merge_by_val(Cand);67return;68}6970typename list<Candidate<Integer> >::iterator h;71for(h=Cand.Candidates.begin(); h!=Cand.Candidates.end();){72if(h->old_tot_deg<=guaranteed_HB_deg){73Irred.Candidates.splice(Irred.Candidates.end(),Cand.Candidates,h++);74}75else{76++h;77}78}79Irred.auto_reduce_sorted(); // necessary since the guaranteed HB degree only determines80// in which degrees we can already decide whether an element belongs to the HB81}828384//---------------------------------------------------------------------------858687//public88//---------------------------------------------------------------------------8990template<typename Integer>91Cone_Dual_Mode<Integer>::Cone_Dual_Mode(Matrix<Integer>& M, const vector<Integer>& Truncation){92dim=M.nr_of_columns();93M.remove_duplicate_and_zero_rows();94// now we sort by L_1-norm and then lex95Matrix<Integer> Weights(0,dim);96vector<bool> absolute;97Weights.append(vector<Integer>(dim,1));98absolute.push_back(true);99vector<key_t> perm=M.perm_by_weights(Weights,absolute);100M.order_rows_by_perm(perm);101102SupportHyperplanes=Matrix<Integer>(0,dim);103BasisMaxSubspace=Matrix<Integer>(dim); // dim x dim identity matrix104if(Truncation.size()!=0){105vector<Integer> help=Truncation;106v_make_prime(help); // truncation need not be coprime107M.remove_row(help); // remove truncation if it should be a support hyperplane108SupportHyperplanes.append(Truncation); // now we insert it again as the first hyperplane109}110SupportHyperplanes.append(M);111nr_sh = SupportHyperplanes.nr_of_rows();112113verbose = false;114inhomogeneous = false;115do_only_Deg1_Elements = false;116truncate = false;117118Intermediate_HB.dual=true;119120if (nr_sh != static_cast<size_t>(static_cast<key_t>(nr_sh))) {121throw FatalException("Too many support hyperplanes to fit in range of key_t!");122}123}124125//---------------------------------------------------------------------------126127template<typename Integer>128Matrix<Integer> Cone_Dual_Mode<Integer>::get_support_hyperplanes() const {129return SupportHyperplanes;130}131132//---------------------------------------------------------------------------133134template<typename Integer>135Matrix<Integer> Cone_Dual_Mode<Integer>::get_generators()const{136return Generators;137}138139template<typename Integer>140vector<bool> Cone_Dual_Mode<Integer>::get_extreme_rays() const{141return ExtremeRaysInd;142143}144145146size_t counter=0,counter1=0, counter2=0;147148const size_t ReportBound=100000;149150//---------------------------------------------------------------------------151152// In the inhomogeneous case or when only degree 1 elements are to be found,153// we truncate the Hilbert basis at level 1. The level is the ordinary degree154// for degree 1 elements and the degree of the homogenizing variable155// in the inhomogeneous case.156//157// As soon as there are no positive or neutral (with respect to the current hyperplane)158// elements in the current Hilbert basis and truncate==true, new elements can only159// be produced as sums of positive irreds of level 1 and negative irreds of level 0.160// In particular no new negative elements can be produced, and the only type of161// reduction on the positive side is the elimination of duplicates.162//163// If there are no elements on level 0 at all, then new elements cannot be produced anymore,164// and the production of new elements can be skipped.165166template<typename Integer>167void Cone_Dual_Mode<Integer>::cut_with_halfspace_hilbert_basis(const size_t& hyp_counter,168const bool lifting, vector<Integer>& old_lin_subspace_half, bool pointed){169if (verbose==true) {170verboseOutput()<<"==================================================" << endl;171verboseOutput()<<"cut with halfspace "<<hyp_counter+1 <<" ..."<<endl;172}173174size_t i;175int sign;176177CandidateList<Integer> Positive_Irred(true),Negative_Irred(true),Neutral_Irred(true); // for the Hilbert basis elements178Positive_Irred.verbose=Negative_Irred.verbose=Neutral_Irred.verbose=verbose;179list<Candidate<Integer>* > Pos_Gen0, Pos_Gen1, Neg_Gen0, Neg_Gen1; // pointer lists for generation control180size_t pos_gen0_size=0, pos_gen1_size=0, neg_gen0_size=0, neg_gen1_size=0;181182Integer orientation, scalar_product,diff,factor;183vector <Integer> hyperplane=SupportHyperplanes[hyp_counter]; // the current hyperplane dividing the old cone184typename list<Candidate<Integer> >::iterator h;185186if (lifting==true) {187orientation=v_scalar_product<Integer>(hyperplane,old_lin_subspace_half);188if(orientation<0){189orientation=-orientation;190v_scalar_multiplication<Integer>(old_lin_subspace_half,-1); //transforming into the generator of the positive half of the old max lin subsapce191}192// from now on orientation > 0193194for (h = Intermediate_HB.Candidates.begin(); h != Intermediate_HB.Candidates.end(); ++h) { //reduction modulo the generators of the two halves of the old max lin subspace195scalar_product=v_scalar_product(hyperplane,h->cand); // allows us to declare "old" HB candiadtes as irreducible196sign=1;197if (scalar_product<0) {198scalar_product=-scalar_product;199sign=-1;200}201factor=scalar_product/orientation; // we reduce all elements by the generator of the halfspace202for (i = 0; i < dim; i++) {203h->cand[i]=h->cand[i]-sign*factor*old_lin_subspace_half[i];204}205}206207//adding the generators of the halves of the old max lin subspaces to the the "positive" and the "negative" generators208// ABSOLUTELY NECESSARY since we need a monoid system of generators of the full "old" cone209210Candidate<Integer> halfspace_gen_as_cand(old_lin_subspace_half,nr_sh);211halfspace_gen_as_cand.mother=0;212// halfspace_gen_as_cand.father=0;213halfspace_gen_as_cand.old_tot_deg=0;214(halfspace_gen_as_cand.values)[hyp_counter]=orientation; // value under the new linear form215halfspace_gen_as_cand.sort_deg=convertTo<long>(orientation);216assert(orientation!=0);217if(!truncate || halfspace_gen_as_cand.values[0] <=1){ // the only critical case is the positive halfspace gen in round 0218Positive_Irred.push_back(halfspace_gen_as_cand); // it must have value <= 1 under the truncation.219Pos_Gen0.push_back(&Positive_Irred.Candidates.front()); // Later on all these elements have value 0 under it.220pos_gen0_size=1;221}222v_scalar_multiplication<Integer>(halfspace_gen_as_cand.cand,-1);223Negative_Irred.push_back(halfspace_gen_as_cand);224Neg_Gen0.push_back(&Negative_Irred.Candidates.front());225neg_gen0_size=1;226} //end lifting227228long gen0_mindeg; // minimal degree of a generator229if(lifting)230gen0_mindeg=0; // sort_deg has already been set > 0 for half_space_gen231else232gen0_mindeg=Intermediate_HB.Candidates.begin()->sort_deg;233typename list<Candidate<Integer> >::const_iterator hh;234for(hh=Intermediate_HB.Candidates.begin();hh!=Intermediate_HB.Candidates.end();++hh)235if(hh->sort_deg < gen0_mindeg)236gen0_mindeg=hh->sort_deg;237238bool gen1_pos=false, gen1_neg=false;239bool no_pos_in_level0=pointed;240bool all_positice_level=pointed;241for (h = Intermediate_HB.Candidates.begin(); h != Intermediate_HB.Candidates.end(); ++h) { //dividing into negative and positive242Integer new_val=v_scalar_product<Integer>(hyperplane,h->cand);243long new_val_long=convertTo<long>(new_val);244h->reducible=false;245h->mother=0;246// h->father=0;247h->old_tot_deg=h->sort_deg;248if (new_val>0) {249gen1_pos=true;250h->values[hyp_counter]=new_val;251h->sort_deg+=new_val_long;252Positive_Irred.Candidates.push_back(*h); // could be spliced253Pos_Gen1.push_back(&Positive_Irred.Candidates.back());254pos_gen1_size++;255if(h->values[0]==0){256no_pos_in_level0=false;257all_positice_level=false;258}259}260if (new_val<0) {261gen1_neg=true;262h->values[hyp_counter]=-new_val;263h->sort_deg+=-new_val_long;264Negative_Irred.Candidates.push_back(*h);265Neg_Gen1.push_back(&Negative_Irred.Candidates.back());266neg_gen1_size++;267if(h->values[0]==0){268all_positice_level=false;269}270}271if (new_val==0) {272Neutral_Irred.Candidates.push_back(*h);273if(h->values[0]==0){274no_pos_in_level0=false;275all_positice_level=false;276}277}278}279280281if((truncate && (no_pos_in_level0 && !all_positice_level))){282if(verbose){283verboseOutput() << "Eliminating negative generators of level > 0" << endl;284}285Neg_Gen1.clear();286neg_gen1_size=0;287for (h = Negative_Irred.Candidates.begin(); h != Negative_Irred.Candidates.end();){288if(h->values[0]>0)289h=Negative_Irred.Candidates.erase(h);290else{291Neg_Gen1.push_back(&(*h));292neg_gen1_size++;293++h;294}295}296}297298#ifndef NCATCH299std::exception_ptr tmp_exception;300#endif301302#pragma omp parallel num_threads(3)303{304305#pragma omp single nowait306{307#ifndef NCATCH308try {309#endif310check_range_list(Negative_Irred);311Negative_Irred.sort_by_val();312Negative_Irred.last_hyp=hyp_counter;313#ifndef NCATCH314} catch(const std::exception& ) {315tmp_exception = std::current_exception();316}317#endif318}319320#pragma omp single nowait321{322#ifndef NCATCH323try {324#endif325check_range_list(Positive_Irred);326Positive_Irred.sort_by_val();327Positive_Irred.last_hyp=hyp_counter;328#ifndef NCATCH329} catch(const std::exception& ) {330tmp_exception = std::current_exception();331}332#endif333}334335#pragma omp single nowait336{337Neutral_Irred.sort_by_val();338Neutral_Irred.last_hyp=hyp_counter;339}340}341#ifndef NCATCH342if (!(tmp_exception == 0)) std::rethrow_exception(tmp_exception);343#endif344345CandidateList<Integer> New_Positive_Irred(true),New_Negative_Irred(true),New_Neutral_Irred(true);346New_Positive_Irred.verbose=New_Negative_Irred.verbose=New_Neutral_Irred.verbose=verbose;347New_Negative_Irred.last_hyp=hyp_counter; // for the newly generated vector in each thread348New_Positive_Irred.last_hyp=hyp_counter;349New_Neutral_Irred.last_hyp=hyp_counter;350351CandidateList<Integer> Positive_Depot(true),Negative_Depot(true),Neutral_Depot(true); // to store the new vectors after generation352Positive_Depot.verbose=Negative_Depot.verbose=Neutral_Depot.verbose=verbose;353354vector<CandidateList<Integer> > New_Positive_thread(omp_get_max_threads()),355New_Negative_thread(omp_get_max_threads()),356New_Neutral_thread(omp_get_max_threads());357358vector<CandidateTable<Integer> > Pos_Table, Neg_Table, Neutr_Table; // for reduction in each thread359360for(long i=0;i<omp_get_max_threads();++i){361New_Positive_thread[i].dual=true;362New_Positive_thread[i].verbose=verbose;363New_Negative_thread[i].dual=true;364New_Negative_thread[i].verbose=verbose;365New_Neutral_thread[i].dual=true;366New_Neutral_thread[i].verbose=verbose;367}368369for(int k=0;k<omp_get_max_threads();++k){370Pos_Table.push_back(CandidateTable<Integer>(Positive_Irred));371Neg_Table.push_back(CandidateTable<Integer>(Negative_Irred));372Neutr_Table.push_back(CandidateTable<Integer>(Neutral_Irred));373}374375typename list<Candidate<Integer>* >::iterator n,p;376Candidate<Integer> *p_cand, *n_cand;377// typename list<Candidate<Integer> >::iterator c;378379bool not_done;380if(lifting)381not_done=gen1_pos || gen1_neg;382else383not_done=gen1_pos && gen1_neg;384385bool do_reduction=!(truncate && no_pos_in_level0);386387bool do_only_selection=truncate && all_positice_level;388389size_t round=0;390391if(do_only_selection){392pos_gen0_size=pos_gen1_size; // otherwise wrong sizes in message at the end393neg_gen0_size=neg_gen1_size;394}395396while(not_done && !do_only_selection) {397398//generating new elements399round++;400401typename list<Candidate<Integer>* >::iterator pos_begin, pos_end, neg_begin, neg_end;402size_t pos_size, neg_size;403404// Steps are:405// 0: old pos vs. new neg406// 1: new pos vs. old neg407// 2: new pos vs. new neg408for(size_t step=0;step<=2;step++)409{410411if(step==0){412pos_begin=Pos_Gen0.begin();413pos_end=Pos_Gen0.end();414neg_begin=Neg_Gen1.begin();415neg_end=Neg_Gen1.end();416pos_size=pos_gen0_size;417neg_size=neg_gen1_size;418}419420if(step==1){421pos_begin=Pos_Gen1.begin();422pos_end=Pos_Gen1.end();423neg_begin=Neg_Gen0.begin();424neg_end=Neg_Gen0.end();425pos_size=pos_gen1_size;426neg_size=neg_gen0_size;;427}428429if(step==2){430pos_begin=Pos_Gen1.begin();431pos_end=Pos_Gen1.end();432neg_begin=Neg_Gen1.begin();433neg_end=Neg_Gen1.end();434pos_size=pos_gen1_size;435neg_size=neg_gen1_size;436}437438if(pos_size==0 || neg_size==0)439continue;440441vector<typename list<Candidate<Integer>* >::iterator > PosBlockStart, NegBlockStart;442443const size_t Blocksize=200;444445size_t nr_in_block=0, pos_block_nr=0;446for(p=pos_begin;p!=pos_end;++p){447if(nr_in_block%Blocksize==0){448PosBlockStart.push_back(p);449pos_block_nr++;450nr_in_block=0;451}452nr_in_block++;453}454PosBlockStart.push_back(p);455456nr_in_block=0;457size_t neg_block_nr=0;458for(n=neg_begin;n!=neg_end;++n){459if(nr_in_block%Blocksize==0){460NegBlockStart.push_back(n);461neg_block_nr++;462nr_in_block=0;463}464nr_in_block++;465}466NegBlockStart.push_back(n);467468// cout << "Step " << step << " pos " << pos_size << " neg " << neg_size << endl;469470if (verbose) {471// size_t neg_size=Negative_Irred.size();472// size_t zsize=Neutral_Irred.size();473if (pos_size*neg_size>=ReportBound)474verboseOutput()<<"Positive: "<<pos_size<<" Negative: "<<neg_size<< endl;475else{476if(round%100==0)477verboseOutput() << "Round " << round << endl;478}479}480481bool skip_remaining = false;482483const long VERBOSE_STEPS = 50;484long step_x_size = pos_block_nr*neg_block_nr-VERBOSE_STEPS;485486#pragma omp parallel private(p,n,diff,p_cand,n_cand)487{488Candidate<Integer> new_candidate(dim,nr_sh);489490size_t total=pos_block_nr*neg_block_nr;491492#pragma omp for schedule(dynamic)493for(size_t bb=0;bb<total;++bb){ // main loop over the blocks494495if (skip_remaining) continue;496497#ifndef NCATCH498try {499#endif500501INTERRUPT_COMPUTATION_BY_EXCEPTION502503if(verbose && pos_size*neg_size>=ReportBound){504#pragma omp critical(VERBOSE)505while ((long)(bb*VERBOSE_STEPS) >= step_x_size) {506step_x_size += total;507verboseOutput() << "." <<flush;508}509510}511512size_t nr_pos=bb/neg_block_nr;513size_t nr_neg=bb%neg_block_nr;514515for(p=PosBlockStart[nr_pos];p!=PosBlockStart[nr_pos+1];++p){516517518p_cand=*p;519520Integer pos_val=p_cand->values[hyp_counter];521522for (n= NegBlockStart[nr_neg];n!=NegBlockStart[nr_neg+1]; ++n){523524n_cand=*n;525526if(truncate && p_cand->values[0]+n_cand->values[0] >=2) // in the inhomogeneous case we truncate at level 1527continue;528529Integer neg_val=n_cand->values[hyp_counter];530diff=pos_val-neg_val;531532// prediction of reducibility533534if (diff >0 && n_cand->mother!=0 &&535(536n_cand->mother<=pos_val // sum of p_cand and n_cand would be irreducible by mother + the vector on the opposite side537|| (p_cand->mother >= n_cand->mother && p_cand->mother-n_cand->mother <=diff) // sum would reducible ny mother + mother538)539){540// #pragma omp atomic541// counter1++;542continue;543}544545546if ( diff <0 && p_cand->mother!=0 &&547(548p_cand->mother<=neg_val549|| (n_cand->mother >= p_cand->mother && n_cand->mother-p_cand->mother <= -diff)550)551){552// #pragma omp atomic // sum would be irreducible by mother + the vector on the opposite side553// counter1++;554continue;555}556557if(diff==0 && p_cand->mother!=0 && n_cand->mother == p_cand->mother){558// #pragma omp atomic559// counter1++;560continue;561}562563// #pragma omp atomic564// counter++;565566new_candidate.old_tot_deg=p_cand->old_tot_deg+n_cand->old_tot_deg;567v_add_result(new_candidate.values,hyp_counter,p_cand->values,n_cand->values); // new_candidate=v_add568569if (diff>0) {570new_candidate.values[hyp_counter]=diff;571new_candidate.sort_deg=p_cand->sort_deg+n_cand->sort_deg-2*convertTo<long>(neg_val);572if(do_reduction && (Pos_Table[omp_get_thread_num()].is_reducible_unordered(new_candidate) ||573Neutr_Table[omp_get_thread_num()].is_reducible_unordered(new_candidate)))574continue;575v_add_result(new_candidate.cand,dim,p_cand->cand,n_cand->cand);576new_candidate.mother=pos_val;577// new_candidate.father=neg_val;578New_Positive_thread[omp_get_thread_num()].push_back(new_candidate);579}580if (diff<0) {581if(!do_reduction) // don't need new negative elements anymore582continue;583new_candidate.values[hyp_counter]=-diff;584new_candidate.sort_deg=p_cand->sort_deg+n_cand->sort_deg-2*convertTo<long>(pos_val);585if(Neg_Table[omp_get_thread_num()].is_reducible_unordered(new_candidate)) {586continue;587}588if(Neutr_Table[omp_get_thread_num()].is_reducible_unordered(new_candidate)) {589continue;590}591v_add_result(new_candidate.cand,dim,p_cand->cand,n_cand->cand);592new_candidate.mother=neg_val;593// new_candidate.father=pos_val;594New_Negative_thread[omp_get_thread_num()].push_back(new_candidate);595}596if (diff==0) {597new_candidate.values[hyp_counter]=0;598new_candidate.sort_deg=p_cand->sort_deg+n_cand->sort_deg-2*convertTo<long>(pos_val); //pos_val==neg_val599if(do_reduction && Neutr_Table[omp_get_thread_num()].is_reducible_unordered(new_candidate)) {600continue;601}602v_add_result(new_candidate.cand,dim,p_cand->cand,n_cand->cand);603// new_candidate.mother=0; // irrelevant604New_Neutral_thread[omp_get_thread_num()].push_back(new_candidate);605}606} // neg607608} // pos609610#ifndef NCATCH611} catch(const std::exception& ) {612tmp_exception = std::current_exception();613skip_remaining = true;614#pragma omp flush(skip_remaining)615}616#endif617618} // bb, end generation of new elements619620#pragma omp single621{622if(verbose && pos_size*neg_size>=ReportBound)623verboseOutput() << endl;624}625626} //END PARALLEL627628#ifndef NCATCH629if (!(tmp_exception == 0)) std::rethrow_exception(tmp_exception);630#endif631632} // steps633634Pos_Gen0.splice(Pos_Gen0.end(),Pos_Gen1); // the new generation has become old635pos_gen0_size+=pos_gen1_size;636pos_gen1_size=0;637Neg_Gen0.splice(Neg_Gen0.end(),Neg_Gen1);638neg_gen0_size+=neg_gen1_size;639neg_gen1_size=0;640641splice_them_sort(Neutral_Depot,New_Neutral_thread); // sort by sort_deg and values642643splice_them_sort(Positive_Depot,New_Positive_thread);644645splice_them_sort(Negative_Depot,New_Negative_thread);646647if(Positive_Depot.empty() && Negative_Depot.empty())648not_done=false;649650// Attention: the element with smallest old_tot_deg need not be the first in the list which is ordered by sort_deg651size_t gen1_mindeg=0; // minimal old_tot_deg of a new element used for generation652bool first=true;653typename list<Candidate<Integer> >::iterator c;654for(c = Positive_Depot.Candidates.begin();c!=Positive_Depot.Candidates.end();++c){655if(first){656first=false;657gen1_mindeg=c->old_tot_deg;658}659if(c->old_tot_deg<gen1_mindeg)660gen1_mindeg=c->old_tot_deg;661}662663for(c = Negative_Depot.Candidates.begin();c!=Negative_Depot.Candidates.end();++c){664if(first){665first=false;666gen1_mindeg=c->old_tot_deg;667}668if(c->old_tot_deg<gen1_mindeg)669gen1_mindeg=c->old_tot_deg;670671}672673size_t min_deg_new=gen0_mindeg+gen1_mindeg;674if(not_done)675assert(min_deg_new>0);676677size_t all_known_deg=min_deg_new-1;678size_t guaranteed_HB_deg=2*all_known_deg+1; // the degree up to which we can decide whether an element belongs to the HB679680if(not_done){681select_HB(Neutral_Depot,guaranteed_HB_deg,New_Neutral_Irred,!do_reduction);682}683else{684Neutral_Depot.auto_reduce_sorted(); // in this case new elements will not be produced anymore685Neutral_Irred.merge_by_val(Neutral_Depot); // and there is nothing to do for positive or negative elements686// but the remaining neutral elements must be auto-reduced.687}688689CandidateTable<Integer> New_Pos_Table(true,hyp_counter), New_Neg_Table(true,hyp_counter), New_Neutr_Table(true,hyp_counter);690// for new elements691692if (!New_Neutral_Irred.empty()) {693if(do_reduction){694Positive_Depot.reduce_by(New_Neutral_Irred);695Neutral_Depot.reduce_by(New_Neutral_Irred);696}697Negative_Depot.reduce_by(New_Neutral_Irred);698list<Candidate<Integer>* > New_Elements;699Neutral_Irred.merge_by_val(New_Neutral_Irred,New_Elements);700typename list<Candidate<Integer>* >::iterator c;701for(c=New_Elements.begin(); c!=New_Elements.end(); ++c){702New_Neutr_Table.ValPointers.push_back(pair< size_t, vector<Integer>* >((*c)->sort_deg,&((*c)->values)));703}704New_Elements.clear();705}706707select_HB(Positive_Depot,guaranteed_HB_deg,New_Positive_Irred,!do_reduction);708709select_HB(Negative_Depot,guaranteed_HB_deg,New_Negative_Irred,!do_reduction);710711if (!New_Positive_Irred.empty()) {712if(do_reduction)713Positive_Depot.reduce_by(New_Positive_Irred);714check_range_list(New_Positive_Irred); // check for danger of overflow715Positive_Irred.merge_by_val(New_Positive_Irred,Pos_Gen1);716typename list<Candidate<Integer>* >::iterator c;717for(c=Pos_Gen1.begin(); c!=Pos_Gen1.end(); ++c){718New_Pos_Table.ValPointers.push_back(pair< size_t, vector<Integer>* >((*c)->sort_deg,&((*c)->values)));719pos_gen1_size++;720}721}722723if (!New_Negative_Irred.empty()) {724Negative_Depot.reduce_by(New_Negative_Irred);725check_range_list(New_Negative_Irred);726Negative_Irred.merge_by_val(New_Negative_Irred,Neg_Gen1);727typename list<Candidate<Integer>* >::iterator c;728for(c=Neg_Gen1.begin(); c!=Neg_Gen1.end(); ++c){729New_Neg_Table.ValPointers.push_back(pair< size_t, vector<Integer>* >((*c)->sort_deg,&((*c)->values)));730neg_gen1_size++;731}732}733734CandidateTable<Integer> Help(true,hyp_counter);735736for(int k=0;k<omp_get_max_threads();++k){737Help=New_Pos_Table;738Pos_Table[k].ValPointers.splice(Pos_Table[k].ValPointers.end(),Help.ValPointers);739Help=New_Neg_Table;740Neg_Table[k].ValPointers.splice(Neg_Table[k].ValPointers.end(),Help.ValPointers);741Help=New_Neutr_Table;742Neutr_Table[k].ValPointers.splice(Neutr_Table[k].ValPointers.end(),Help.ValPointers);743}744745} // while(not_done)746747if (verbose) {748verboseOutput()<<"Final sizes: Pos " << pos_gen0_size << " Neg " << neg_gen0_size << " Neutral " << Neutral_Irred.size() <<endl;749}750751Intermediate_HB.clear();752Intermediate_HB.Candidates.splice(Intermediate_HB.Candidates.begin(),Positive_Irred.Candidates);753Intermediate_HB.Candidates.splice(Intermediate_HB.Candidates.end(),Neutral_Irred.Candidates);754Intermediate_HB.sort_by_val();755}756757//---------------------------------------------------------------------------758759template<typename Integer>760Matrix<Integer> Cone_Dual_Mode<Integer>::cut_with_halfspace(const size_t& hyp_counter, const Matrix<Integer>& BasisMaxSubspace){761INTERRUPT_COMPUTATION_BY_EXCEPTION762763size_t i,rank_subspace=BasisMaxSubspace.nr_of_rows();764765vector <Integer> restriction,lin_form=SupportHyperplanes[hyp_counter],old_lin_subspace_half;766bool lifting=false;767Matrix<Integer> New_BasisMaxSubspace=BasisMaxSubspace; // the new maximal subspace is the intersection of the old with the new haperplane768if (rank_subspace!=0) {769restriction=BasisMaxSubspace.MxV(lin_form); // the restriction of the new linear form to Max_Subspace770for (i = 0; i <rank_subspace; i++)771if (restriction[i]!=0)772break;773if (i!=rank_subspace) { // the new hyperplane does not contain the intersection of the previous hyperplanes774// so we must intersect the new hyperplane and Max_Subspace775lifting=true;776777Matrix<Integer> M(1,rank_subspace); // this is the restriction of the new linear form to Max_Subspace778M[0]=restriction; // encoded as a matrix779780size_t dummy_rank;781Matrix<Integer> NewBasisOldMaxSubspace=M.AlmostHermite(dummy_rank).transpose(); // compute kernel of restriction and complementary subspace782783Matrix<Integer> NewBasisOldMaxSubspaceAmbient=NewBasisOldMaxSubspace.multiplication(BasisMaxSubspace);784// in coordinates of the ambient space785786old_lin_subspace_half=NewBasisOldMaxSubspaceAmbient[0];787788// old_lin_subspace_half refers to the fact that the complementary space is subdivided into789// two halfspaces generated by old_lin_subspace_half and -old_lin_subspace_half (taken care of in cut_with_halfspace_hilbert_basis)790791Matrix<Integer> temp(rank_subspace-1,dim);792for(size_t k=1;k<rank_subspace;++k)793temp[k-1]=NewBasisOldMaxSubspaceAmbient[k];794New_BasisMaxSubspace=temp;795}796}797bool pointed=(BasisMaxSubspace.nr_of_rows()==0);798799cut_with_halfspace_hilbert_basis(hyp_counter, lifting,old_lin_subspace_half,pointed);800801return New_BasisMaxSubspace;802}803804//---------------------------------------------------------------------------805806template<typename Integer>807void Cone_Dual_Mode<Integer>::hilbert_basis_dual(){808809truncate = inhomogeneous || do_only_Deg1_Elements;810811if(dim==0)812return;813814if (verbose==true) {815verboseOutput()<<"************************************************************\n";816verboseOutput()<<"computing Hilbert basis";817if(truncate)818verboseOutput() << " (truncated)";819verboseOutput() << " ..." << endl;820}821822if(Generators.nr_of_rows()!=ExtremeRaysInd.size()){823throw FatalException("Mismatch of extreme rays and generators in cone dual mode. THIS SHOULD NOT HAPPEN.");824}825826size_t hyp_counter; // current hyperplane827for (hyp_counter = 0; hyp_counter < nr_sh; hyp_counter++) {828BasisMaxSubspace=cut_with_halfspace(hyp_counter,BasisMaxSubspace);829}830831if (ExtremeRaysInd.size() > 0) { // implies that we have transformed everything to a pointed full-dimensional cone832// must produce the relevant support hyperplanes from the generators833// since the Hilbert basis may have been truncated834vector<Integer> test(SupportHyperplanes.nr_of_rows());835vector<key_t> key;836vector<key_t> relevant_sh;837size_t realdim=Generators.rank();838for(key_t h=0;h<SupportHyperplanes.nr_of_rows();++h){839840INTERRUPT_COMPUTATION_BY_EXCEPTION841842key.clear();843vector<Integer> test=Generators.MxV(SupportHyperplanes[h]);844for(key_t i=0;i<test.size();++i)845if(test[i]==0)846key.push_back(i);847if (key.size() >= realdim-1 && Generators.submatrix(key).rank() >= realdim-1)848relevant_sh.push_back(h);849}850SupportHyperplanes = SupportHyperplanes.submatrix(relevant_sh);851}852if (!truncate && ExtremeRaysInd.size()==0){ // no precomputed generators853extreme_rays_rank();854relevant_support_hyperplanes();855ExtremeRayList.clear();856}857858/* if(verbose)859verboseOutput() << "matches = " << counter << endl << "avoided = " << counter1 << endl <<860"comparisons = " << redcounter << endl << "comp/match " << (float) redcounter/(float) counter << endl;861// verboseOutput() << "matches = " << counter << endl << "avoided = " << counter1 << endl; // << "add avoided " << counter2 << endl;862*/863864Intermediate_HB.extract(Hilbert_Basis);865866if(verbose) {867verboseOutput() << "Hilbert basis ";868if(truncate)869verboseOutput() << "(truncated) ";870verboseOutput() << Hilbert_Basis.size() << endl;871}872if(SupportHyperplanes.nr_of_rows()>0 && inhomogeneous)873v_make_prime(SupportHyperplanes[0]); // it could be that the truncation was not coprime874}875876//---------------------------------------------------------------------------877878template<typename Integer>879void Cone_Dual_Mode<Integer>::extreme_rays_rank(){880if (verbose) {881verboseOutput() << "Find extreme rays" << endl;882}883size_t quotient_dim=dim-BasisMaxSubspace.nr_of_rows();884885typename list < Candidate <Integer> >::iterator c;886vector <key_t> zero_list;887size_t i,k;888for (c=Intermediate_HB.Candidates.begin(); c!=Intermediate_HB.Candidates.end(); ++c){889890INTERRUPT_COMPUTATION_BY_EXCEPTION891892zero_list.clear();893for (i = 0; i < nr_sh; i++) {894if(c->values[i]==0) {895zero_list.push_back(i);896}897}898k=zero_list.size();899if (k>=quotient_dim-1) {900901// Matrix<Integer> Test=SupportHyperplanes.submatrix(zero_list);902if (SupportHyperplanes.rank_submatrix(zero_list)>=quotient_dim-1) {903ExtremeRayList.push_back(&(*c));904}905}906}907size_t s = ExtremeRayList.size();908// cout << "nr extreme " << s << endl;909Generators = Matrix<Integer>(s,dim);910911typename list< Candidate<Integer>* >::const_iterator l;912for (i=0, l=ExtremeRayList.begin(); l != ExtremeRayList.end(); ++l, ++i) {913Generators[i]= (*l)->cand;914}915ExtremeRaysInd=vector<bool>(s,true);916}917918//---------------------------------------------------------------------------919920template<typename Integer>921void Cone_Dual_Mode<Integer>::relevant_support_hyperplanes(){922if (verbose) {923verboseOutput() << "Find relevant support hyperplanes" << endl;924}925typename list<Candidate<Integer>* >::iterator gen_it;926size_t i,k,k1;927928// size_t realdim = Generators.rank();929930vector<vector<bool> > ind(nr_sh,vector<bool>(ExtremeRayList.size(),false));931vector<bool> relevant(nr_sh,true);932933for (i = 0; i < nr_sh; ++i) {934935INTERRUPT_COMPUTATION_BY_EXCEPTION936937k = 0; k1=0;938for (gen_it = ExtremeRayList.begin(); gen_it != ExtremeRayList.end(); ++gen_it, ++k) {939if ((*gen_it)->values[i]==0) {940ind[i][k]=true;941k1++;942}943}944if (/* k1<realdim-1 || */ k1==Generators.nr_of_rows()) { // discard everything that vanishes on the cone945relevant[i]=false;946}947}948maximal_subsets(ind,relevant);949SupportHyperplanes = SupportHyperplanes.submatrix(relevant);950}951952//---------------------------------------------------------------------------953954template<typename Integer>955void Cone_Dual_Mode<Integer>::to_sublattice(const Sublattice_Representation<Integer>& SR) {956assert(SR.getDim() == dim);957958if(SR.IsIdentity())959return;960961dim = SR.getRank();962SupportHyperplanes = SR.to_sublattice_dual(SupportHyperplanes);963typename list<vector<Integer> >::iterator it;964vector<Integer> tmp;965966Generators = SR.to_sublattice(Generators);967BasisMaxSubspace=SR.to_sublattice(BasisMaxSubspace);968969for (it = Hilbert_Basis.begin(); it != Hilbert_Basis.end(); ) {970tmp = SR.to_sublattice(*it);971it = Hilbert_Basis.erase(it);972Hilbert_Basis.insert(it,tmp);973}974}975976} //end namespace libnormaliz977978979