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#ifdef NMZ_MIC_OFFLOAD24#pragma offload_attribute (push, target(mic))25#endif2627#include <cassert>28#include <iostream>29#include <sstream>30#include <map>31#include <algorithm>3233#include "libnormaliz/HilbertSeries.h"34#include "libnormaliz/vector_operations.h"35#include "libnormaliz/map_operations.h"36#include "libnormaliz/integer.h"37#include "libnormaliz/convert.h"38#include "libnormaliz/my_omp.h"3940#include "libnormaliz/matrix.h"4142//---------------------------------------------------------------------------4344namespace libnormaliz {45using std::cout; using std::endl; using std::flush;46using std::istringstream; using std::ostringstream;47using std::pair;4849long lcm_of_keys(const map<long, denom_t>& m){50long l = 1;51map<long, denom_t>::const_iterator it;52for (it = m.begin(); it != m.end(); ++it) {53if (it->second != 0)54l = lcm(l,it->first);55}56return l;57}5859// compute the hsop numerator by multiplying the HS with a denominator60// of the form product of (1-t^i)61void HilbertSeries::compute_hsop_num() const{62// get the denominator as a polynomial by mutliplying the (1-t^i) terms63vector<mpz_class> hsop_denom_poly=vector<mpz_class>(1,1);64map<long,denom_t>::iterator it;65long factor;66for (it=hsop_denom.begin();it!=hsop_denom.end();++it){67factor = it->first;68denom_t& denom_i = it->second;69poly_mult_to(hsop_denom_poly,factor,denom_i);70}71//cout << "new denominator as polynomial: " << hsop_denom_poly << endl;72vector<mpz_class> quot,remainder,cyclo_poly;73//first divide the new denom by the cyclo polynomials74for (auto it=cyclo_denom.begin();it!=cyclo_denom.end();++it){75for(long i=0;i<it->second;i++){76cyclo_poly = cyclotomicPoly<mpz_class>(it->first);77//cout << "the cyclotomic polynomial is " << cyclo_poly << endl;78// TODO: easier polynomial division possible?79poly_div(quot,remainder,hsop_denom_poly,cyclo_poly);80//cout << "the quotient is " << quot << endl;81hsop_denom_poly=quot;82assert(remainder.size()==0);83}84}85// multiply with the old numerator86hsop_num = poly_mult(hsop_denom_poly,cyclo_num);87}8889//---------------------------------------------------------------------------9091void HilbertSeries::initialize(){9293is_simplified = false;94shift = 0;95verbose = false;96nr_coeff_quasipol=-1; // all coefficients97period_bounded=true;98}99100// Constructor, creates 0/1101HilbertSeries::HilbertSeries() {102num = vector<mpz_class>(1,0);103//denom just default constructed104initialize();105}106107// Constructor, creates num/denom, see class description for format108HilbertSeries::HilbertSeries(const vector<num_t>& numerator, const vector<denom_t>& gen_degrees) {109num = vector<mpz_class>(1,0);110add(numerator, gen_degrees);111initialize();112}113114// Constructor, creates num/denom, see class description for format115HilbertSeries::HilbertSeries(const vector<mpz_class>& numerator, const map<long, denom_t>& denominator) {116num = numerator;117denom = denominator;118initialize();119}120121// Constructor, string as created by to_string_rep122HilbertSeries::HilbertSeries(const string& str) {123from_string_rep(str);124initialize();125}126127128void HilbertSeries::reset() {129num.clear();130num.push_back(0);131denom.clear();132denom_classes.clear();133shift = 0;134is_simplified = false;135}136137void HilbertSeries::set_nr_coeff_quasipol(long nr_coeff){138nr_coeff_quasipol=nr_coeff;139}140141long HilbertSeries::get_nr_coeff_quasipol() const{142return nr_coeff_quasipol;143}144145void HilbertSeries::set_period_bounded(bool on_off) const{ //period_bounded is mutable146period_bounded=on_off;147}148149bool HilbertSeries::get_period_bounded() const{150return period_bounded;151}152// add another HilbertSeries to this153void HilbertSeries::add(const vector<num_t>& num, const vector<denom_t>& gen_degrees) {154vector<denom_t> sorted_gd(gen_degrees);155sort(sorted_gd.begin(), sorted_gd.end());156if (gen_degrees.size() > 0)157assert(sorted_gd[0]>0); //TODO InputException?158poly_add_to(denom_classes[sorted_gd], num);159if (denom_classes.size() > DENOM_CLASSES_BOUND)160collectData();161is_simplified = false;162}163164165// add another HilbertSeries to this166HilbertSeries& HilbertSeries::operator+=(const HilbertSeries& other) {167// add denom_classes168map< vector<denom_t>, vector<num_t> >::const_iterator it;169for (it = other.denom_classes.begin(); it != other.denom_classes.end(); ++it) {170poly_add_to(denom_classes[it->first], it->second);171}172// add accumulated data173vector<mpz_class> num_copy(other.num);174performAdd(num_copy, other.denom);175return (*this);176}177178void HilbertSeries::performAdd(const vector<num_t>& numerator, const vector<denom_t>& gen_degrees) const {179map<long, denom_t> other_denom;180size_t i, s = gen_degrees.size();181for (i=0; i<s; ++i) {182assert(gen_degrees[i]>0);183other_denom[gen_degrees[i]]++;184}185// convert numerator to mpz186vector<mpz_class> other_num(numerator.size());187convert(other_num, numerator);188performAdd(other_num, other_denom);189}190191//modifies other_num!!192void HilbertSeries::performAdd(vector<mpz_class>& other_num, const map<long, denom_t>& oth_denom) const {193map<long, denom_t> other_denom(oth_denom); //TODO redesign, dont change other_denom194// adjust denominators195denom_t diff;196map<long, denom_t>::iterator it;197for (it = denom.begin(); it != denom.end(); ++it) { // augment other198denom_t& ref = other_denom[it->first];199diff = it->second - ref;200if (diff > 0) {201ref += diff;202poly_mult_to(other_num, it->first, diff);203}204}205for (it = other_denom.begin(); it != other_denom.end(); ++it) { // augment this206denom_t& ref = denom[it->first];207diff = it->second - ref;208if (diff > 0) {209ref += diff;210poly_mult_to(num, it->first, diff);211}212}213assert (denom == other_denom);214215// now just add the numerators216poly_add_to(num,other_num);217remove_zeros(num);218is_simplified = false;219}220221void HilbertSeries::collectData() const {222if (denom_classes.empty()) return;223if (verbose) verboseOutput() << "Adding " << denom_classes.size() << " denominator classes..." << flush;224map< vector<denom_t>, vector<num_t> >::iterator it;225for (it = denom_classes.begin(); it != denom_classes.end(); ++it) {226227INTERRUPT_COMPUTATION_BY_EXCEPTION228229performAdd(it->second, it->first);230}231denom_classes.clear();232if (verbose) verboseOutput() << " done." << endl;233}234235// simplify, see class description236void HilbertSeries::simplify() const {237if (is_simplified)238return;239collectData();240/* if (verbose) {241verboseOutput() << "Hilbert series before simplification: "<< endl << *this;242}*/243vector<mpz_class> q, r, poly; //polynomials244// In denom_cyclo we collect cyclotomic polynomials in the denominator.245// During this method the Hilbert series is given by num/(denom*cdenom)246// where denom | cdenom are exponent vectors of (1-t^i) | i-th cyclotminc poly.247map<long, denom_t> cdenom;248249map<long, denom_t> save_denom=denom;250map<long, denom_t>::reverse_iterator rit;251long i;252for (rit = denom.rbegin(); rit != denom.rend(); ++rit) {253// check if we can divide the numerator by (1-t^i)254i = rit->first;255denom_t& denom_i = rit->second;256poly = coeff_vector<mpz_class>(i);257while (denom_i > 0) {258poly_div(q, r, num, poly);259if (r.size() == 0) { // numerator is divisable by poly260num = q;261denom_i--;262}263else {264break;265}266}267if (denom_i == 0)268continue;269270// decompose (1-t^i) into cyclotomic polynomial271for(long d=1; d<=i/2; ++d) {272if (i % d == 0)273cdenom[d] += denom_i;274}275cdenom[i] += denom_i;276// the product of the cyclo. is t^i-1 = -(1-t^i)277if (denom_i%2 == 1)278v_scalar_multiplication(num,mpz_class(-1));279} // end for280denom.clear();281282map<long, denom_t>::iterator it = cdenom.begin();283while (it != cdenom.end()) {284// check if we can divide the numerator by i-th cyclotomic polynomial285286INTERRUPT_COMPUTATION_BY_EXCEPTION287288i = it->first;289denom_t& cyclo_i = it->second;290poly = cyclotomicPoly<mpz_class>(i);291while (cyclo_i > 0) {292poly_div(q, r, num, poly);293if (r.empty()) { // numerator is divisable by poly294num = q;295cyclo_i--;296}297else {298break;299}300}301302if (cyclo_i == 0) {303cdenom.erase(it++);304} else {305++it;306}307}308// done with canceling309// save this representation310cyclo_num = num;311cyclo_denom = cdenom;312313// now collect the cyclotomic polynomials in (1-t^i) factors314it = cdenom.find(1);315if (it != cdenom.end())316dim = it->second;317else318dim = 0;319period = lcm_of_keys(cdenom);320if (period_bounded && period > 10*PERIOD_BOUND) {321if (verbose) {322errorOutput() << "WARNING: Period is too big, the representation of the Hilbert series may have more than dimension many factors in the denominator!" << endl;323}324denom=save_denom;325}326else{327while(true){328//create a (1-t^k) factor in the denominator out of all cyclotomic poly.329330INTERRUPT_COMPUTATION_BY_EXCEPTION331332long k=1;333bool empty=true;334vector<mpz_class> existing_factor(1,1); //collects the existing cyclotomic gactors in the denom335for(it=cdenom.begin();it!=cdenom.end();++it){ // with multiplicvity 1336if(it-> second>0){337empty=false;338k=libnormaliz::lcm(k,it->first);339existing_factor=poly_mult(existing_factor,cyclotomicPoly<mpz_class>(it->first));340it->second--;341}342}343if(empty)344break;345denom[k]++;346vector<mpz_class> new_factor=coeff_vector<mpz_class>(k);347vector<mpz_class> quotient, dummy;348poly_div(quotient,dummy,new_factor,existing_factor);349assert(dummy.empty()); //assert remainder r is 0350num=poly_mult(num,quotient);351}352}353354/* if (verbose) {355verboseOutput() << "Simplified Hilbert series: " << endl << *this;356}*/357if (!hsop_denom.empty()){358compute_hsop_num();359}360is_simplified = true;361computeDegreeAsRationalFunction();362quasi_poly.clear();363}364365void HilbertSeries::computeDegreeAsRationalFunction() const {366simplify();367long num_deg = num.size() - 1 + shift;368long denom_deg = 0;369for (auto it = denom.begin(); it != denom.end(); ++it) {370denom_deg += it->first * it->second;371}372degree = num_deg - denom_deg;373}374375long HilbertSeries::getDegreeAsRationalFunction() const {376simplify();377return degree;378}379380long HilbertSeries::getPeriod() const {381simplify();382return period;383}384385bool HilbertSeries::isHilbertQuasiPolynomialComputed() const {386return is_simplified && !quasi_poly.empty();387}388389vector< vector<mpz_class> > HilbertSeries::getHilbertQuasiPolynomial() const {390computeHilbertQuasiPolynomial();391if (quasi_poly.empty()) throw NotComputableException("HilbertQuasiPolynomial");392return quasi_poly;393}394395mpz_class HilbertSeries::getHilbertQuasiPolynomialDenom() const {396computeHilbertQuasiPolynomial();397if (quasi_poly.empty()) throw NotComputableException("HilbertQuasiPolynomial");398return quasi_denom;399}400401void HilbertSeries::computeHilbertQuasiPolynomial() const {402403if (isHilbertQuasiPolynomialComputed() || nr_coeff_quasipol==0) return;404simplify();405406omp_set_nested(0);407408vector<long> denom_vec=to_vector(denom);409if(nr_coeff_quasipol > (long) denom_vec.size()){410if(verbose)411verboseOutput() << "Number of coeff of quasipol too large. Reset to deault value." << endl;412nr_coeff_quasipol=-1;413}414415if (period_bounded && period > PERIOD_BOUND) {416if (verbose) {417errorOutput()<<"WARNING: We skip the computation of the Hilbert-quasi-polynomial because the period "<< period <<" is too big!" <<endl;418}419return;420}421if (verbose && period > 1) {422verboseOutput() << "Computing Hilbert quasipolynomial of period "423<< period <<" ..." << flush;424}425long i,j;426//period und dim encode the denominator427//now adjust the numerator428long num_size = num.size();429vector<mpz_class> norm_num(num_size); //normalized numerator430for (i = 0; i < num_size; ++i) {431norm_num[i] = num[i];432}433map<long, denom_t>::reverse_iterator rit;434long d;435vector<mpz_class> r;436for (rit = denom.rbegin(); rit != denom.rend(); ++rit) {437438INTERRUPT_COMPUTATION_BY_EXCEPTION439440d = rit->first;441//nothing to do if it already has the correct t-power442if (d != period) {443//norm_num *= (1-t^p / 1-t^d)^denom[d]444//first by multiply: norm_num *= (1-t^p)^denom[d]445poly_mult_to(norm_num, period, rit->second);446447//then divide: norm_num /= (1-t^d)^denom[d]448for (i=0; i < rit->second; ++i) {449poly_div(norm_num, r, norm_num, coeff_vector<mpz_class>(d));450assert(r.empty()); //assert remainder r is 0451}452}453}454455// determine the common period of the coefficients that will be computed and printed456long reduced_period;457if(nr_coeff_quasipol>=0){458reduced_period=1;459for(long j=0;j< nr_coeff_quasipol;++j)460reduced_period=lcm(reduced_period,denom_vec[j]);461}462else463reduced_period=period;464465//cut numerator into period many pieces and apply standard method466// we make only reduced_period many components467quasi_poly = vector< vector<mpz_class> >(reduced_period);468long nn_size = norm_num.size();469for (j=0; j<reduced_period; ++j) {470quasi_poly[j].reserve(dim);471}472for (i=0; i<nn_size; ++i) {473if(i%period<reduced_period)474quasi_poly[i%period].push_back(norm_num[i]);475}476477#pragma omp parallel for478for (j=0; j<reduced_period; ++j) {479480INTERRUPT_COMPUTATION_BY_EXCEPTION481482quasi_poly[j] = compute_polynomial(quasi_poly[j], dim);483}484485//substitute t by t/period:486//dividing by period^dim and multipling the coeff with powers of period487mpz_class pp=1;488for (i = dim-2; i >= 0; --i) {489pp *= period; //p^i ok, it is p^(dim-1-i)490for (j=0; j<reduced_period; ++j) {491quasi_poly[j][i] *= pp;492}493} //at the end pp=p^dim-1494//the common denominator for all coefficients, dim! * pp495quasi_denom = permutations<mpz_class>(1,dim) * pp;496//substitute t by t-j497for (j=0; j<reduced_period; ++j) {498// X |--> X - (j + shift)499linear_substitution<mpz_class>(quasi_poly[j], j + shift); // replaces quasi_poly[j]500}501//divide by gcd //TODO operate directly on vector502Matrix<mpz_class> QP(quasi_poly);503mpz_class g = QP.matrix_gcd();504g = libnormaliz::gcd(g,quasi_denom);505quasi_denom /= g;506QP.scalar_division(g);507//we use a normed shift, so that the cylcic shift % period always yields a non-negative integer508long normed_shift = -shift;509while (normed_shift < 0) normed_shift += reduced_period;510for (j=0; j<reduced_period; ++j) {511quasi_poly[j] = QP[(j+normed_shift)%reduced_period]; // QP[ (j - shift) % p ]512}513514long delete_coeff=0;515if(nr_coeff_quasipol>=0)516delete_coeff=(long) quasi_poly[0].size()-nr_coeff_quasipol;517518for(size_t i=0;i<quasi_poly.size();++i) // delete coefficients that have not been computed completely519for(long j=0;j <delete_coeff;++j)520quasi_poly[i][j]=0;521522if (verbose && period > 1) {523verboseOutput() << " done." << endl;524}525}526527// returns the numerator, repr. as vector of coefficients, the h-vector528const vector<mpz_class>& HilbertSeries::getNum() const {529simplify();530return num;531}532// returns the denominator, repr. as a map of the exponents of (1-t^i)^e533const map<long, denom_t>& HilbertSeries::getDenom() const {534simplify();535return denom;536}537538// returns the numerator, repr. as vector of coefficients539const vector<mpz_class>& HilbertSeries::getCyclotomicNum() const {540simplify();541return cyclo_num;542}543// returns the denominator, repr. as a map of the exponents of (1-t^i)^e544const map<long, denom_t>& HilbertSeries::getCyclotomicDenom() const {545simplify();546return cyclo_denom;547}548549const map<long, denom_t>& HilbertSeries::getHSOPDenom() const {550simplify();551return hsop_denom;552}553554const vector<mpz_class>& HilbertSeries::getHSOPNum() const {555simplify();556assert(v_is_nonnegative(hsop_num));557return hsop_num;558}559560// shift561void HilbertSeries::setShift(long s) {562if (shift != s) {563is_simplified = false;564// remove quasi-poly //TODO could also be adjusted565quasi_poly.clear();566quasi_denom = 1;567shift = s;568}569}570571void HilbertSeries::setHSOPDenom(vector<denom_t> new_denom){572hsop_denom=count_in_map<long,denom_t>(new_denom);573}574575void HilbertSeries::setHSOPDenom(map<long,denom_t> new_denom){576hsop_denom=new_denom;577}578579long HilbertSeries::getShift() const {580return shift;581}582583void HilbertSeries::adjustShift() {584collectData();585size_t adj = 0; // adjust shift by586while (adj < num.size() && num[adj] == 0) adj++;587if (adj > 0) {588shift += adj;589num.erase(num.begin(),num.begin()+adj);590if (cyclo_num.size() != 0) {591assert (cyclo_num.size() >= adj);592cyclo_num.erase(cyclo_num.begin(),cyclo_num.begin()+adj);593}594}595}596597// methods for textual transfer of a Hilbert Series598string HilbertSeries::to_string_rep() const {599600collectData();601ostringstream s;602603s << num.size() << " ";604s << num;605vector<denom_t> denom_vector(to_vector(denom));606s << denom_vector.size() << " ";607s << denom_vector;608return s.str();609}610611void HilbertSeries::from_string_rep(const string& input) {612613istringstream s(input);614long i,size;615616s >> size;617num.resize(size);618for (i = 0; i < size; ++i) {619s >> num[i];620}621622vector<denom_t> denom_vector;623s >> size;624denom_vector.resize(size);625for (i = 0; i < size; ++i) {626s >> denom_vector[i];627}628629denom = count_in_map<long,denom_t>(denom_vector);630is_simplified = false;631}632633// writes in a human readable format634ostream& operator<< (ostream& out, const HilbertSeries& HS) {635HS.collectData();636out << "(";637// i == 0638if (HS.num.size()>0) out << " " << HS.num[0];639if (HS.shift != 0) out << "*t^" << HS.shift;640for (size_t i=1; i<HS.num.size(); ++i) {641if ( HS.num[i]== 1 ) out << " +t^"<< i + HS.shift;642else if ( HS.num[i]==-1 ) out << " -t^"<< i + HS.shift;643else if ( HS.num[i] > 0 ) out << " +" << HS.num[i] << "*t^" << i + HS.shift;644else if ( HS.num[i] < 0 ) out << " -" <<-HS.num[i] << "*t^" << i + HS.shift;645}646out << " ) / (";647if (HS.denom.empty()) {648out << " 1";649}650map<long, denom_t>::const_iterator it;651for (it = HS.denom.begin(); it != HS.denom.end(); ++it) {652if ( it->second != 0 ) out << " (1-t^"<< it->first <<")^" << it->second;653}654out << " )" << std::endl;655return out;656}657658659660//---------------------------------------------------------------------------661// polynomial operations, for polynomials repr. as vector of coefficients662//---------------------------------------------------------------------------663664// returns the coefficient vector of 1-t^i665template<typename Integer>666vector<Integer> coeff_vector(size_t i) {667vector<Integer> p(i+1,0);668p[0] = 1;669p[i] = -1;670return p;671}672673template<typename Integer>674void remove_zeros(vector<Integer>& a) {675size_t i=a.size();676while ( i>0 && a[i-1]==0 ) --i;677678if (i < a.size()) {679a.resize(i);680}681}682683// a += b (also possible to define the += op for vector)684template<typename Integer>685void poly_add_to (vector<Integer>& a, const vector<Integer>& b) {686size_t b_size = b.size();687if (a.size() < b_size) {688a.resize(b_size);689}690for (size_t i=0; i<b_size; ++i) {691a[i]+=b[i];692}693remove_zeros(a);694}695696// a += b*t^m697template<typename Integer>698void poly_add_to_tm (vector<Integer>& a, const vector<Integer>& b,long m) {699size_t b_size=b.size();700size_t b_m = b_size+m;701if (a.size() < b_m) {702a.resize(b_m);703}704for (size_t i=0; i<b_size; ++i) {705a[i+m]+=b[i];706}707remove_zeros(a);708}709710// a -= b (also possible to define the -= op for vector)711template<typename Integer>712void poly_sub_to (vector<Integer>& a, const vector<Integer>& b) {713size_t b_size = b.size();714if (a.size() < b_size) {715a.resize(b_size);716}717for (size_t i=0; i<b_size; ++i) {718a[i]-=b[i];719}720remove_zeros(a);721}722723// a *= t^m724template<typename Integer>725void poly_mult_by_tm(vector<Integer>& a, long m){726long a_ori_size=a.size();727a.resize(a_ori_size+m);728for(long i=a_ori_size-1; i>=0;--i)729a[i+m]=a[i];730for(long i=0;i<m;++i)731a[i]=0;732}733734// a * b735736/* template<typename Integer>737vector<Integer> old_poly_mult(const vector<Integer>& a, const vector<Integer>& b) {738size_t a_size = a.size();739size_t b_size = b.size();740741742vector<Integer> p( a_size + b_size - 1 );743size_t i,j;744for (i=0; i<a_size; ++i) {745if (a[i] == 0) continue;746for (j=0; j<b_size; ++j) {747if (b[j] == 0) continue;748p[i+j] += a[i]*b[j];749}750}751return p;752}*/753754template<typename Integer>755vector<Integer> karatsubamult(const vector<Integer>& a, const vector<Integer>& b) {756757size_t a_size = a.size();758size_t b_size = b.size();759if(a_size*b_size<=1000 || a_size <=10 || b_size<=10){760return poly_mult(a,b);761}762763size_t m=(a_size+1)/2;764if(2*m<(b_size+1)){765m=(b_size+1)/2;766}767768vector<Integer> f0(m),f1(m),g0(m),g1(m);769for(size_t i=0;i<m && i<a_size;++i)770f0[i]=a[i];771for(size_t i=m;i<a_size;++i)772f1[i-m]=a[i];773for(size_t i=0;i<m && i<b_size;++i)774g0[i]=b[i];775for(size_t i=m;i< b_size;++i)776g1[i-m]=b[i];777remove_zeros(f0);778remove_zeros(f1);779remove_zeros(g0);780remove_zeros(g1);781782vector<Integer> sf=f0;783vector<Integer> sg=g0;784785vector<Integer> mix;786vector<Integer> h00;787vector<Integer> h11;788789#pragma omp parallel // num_threads(3)790{791792#pragma omp single nowait793{794h00=karatsubamult(f0,g0); // h00 = f0 * g0795}796797#pragma omp single nowait798{799h11=karatsubamult(f1,g1); // h11 = f1 * g1800}801802#pragma omp single nowait803{804poly_add_to(sf,f1); // f0+f1805poly_add_to(sg,g1); // g0 + g1806mix=karatsubamult(sf,sg); // (f0 + f1)*(g0 + g1)807}808809} // parallel810811f0.clear();812g0.clear();813f1.clear();814g1.clear();815816poly_sub_to(mix,h00); // mix = mix - f0*g0817poly_sub_to(mix,h11); // mix = mix - f1*g1818819poly_add_to_tm(h00,mix,m);820poly_add_to_tm(h00,h11,2*m);821822return h00;823}824825template<typename Integer>826vector<Integer> poly_mult(const vector<Integer>& a, const vector<Integer>& b) {827size_t a_size = a.size();828size_t b_size = b.size();829830if(a_size*b_size>1000 && a_size >10 && b_size>10){831// omp_set_nested(1);832return karatsubamult(a,b);833// omp_set_nested(0);834}835836vector<Integer> p( a_size + b_size - 1 );837size_t i,j;838for (i=0; i<a_size; ++i) {839if (a[i] == 0) continue;840for (j=0; j<b_size; ++j) {841if (b[j] == 0) continue;842p[i+j] += a[i]*b[j];843}844}845return p;846}847848// a *= (1-t^d)^e849template<typename Integer>850void poly_mult_to(vector<Integer>& a, long d, long e) {851assert(d>0);852assert(e>=0);853long i;854a.reserve(a.size() + d*e);855while (e>0) {856a.resize(a.size() + d);857for (i=a.size()-1; i>=d; --i) {858a[i] -= a[i-d];859}860e--;861}862}863864// division with remainder, a = q * b + r, deg(r) < deg(b), needs |leadcoef(b)| = 1865template<typename Integer>866void poly_div(vector<Integer>& q, vector<Integer>& r, const vector<Integer>& a, const vector<Integer>&b) {867assert(b.back()!=0); // no unneeded zeros868assert(b.back()==1 || b.back()==-1); // then division is always possible869r = a;870remove_zeros(r);871size_t b_size = b.size();872int degdiff = r.size()-b_size; // degree differenz873if (r.size() < b_size) {874q = vector<Integer>();875} else {876q = vector<Integer>(degdiff+1);877}878Integer divisor;879size_t i=0;880881while (r.size() >= b_size) {882883divisor = r.back()/b.back();884q[degdiff] = divisor;885// r -= divisor * t^degdiff * b886for (i=0; i<b_size; ++i) {887r[i+degdiff] -= divisor * b[i];888}889remove_zeros(r);890degdiff = r.size()-b_size;891}892893return;894}895896template<typename Integer>897vector<Integer> cyclotomicPoly(long n) {898899// the static variable is initialized only once and then stored900static map<long, vector<Integer> > CyclotomicPoly = map<long, vector<Integer> >();901if (CyclotomicPoly.count(n) == 0) { //it was not computed so far902vector<Integer> poly, q, r;903for (long i = 1; i <= n; ++i) {904// compute needed and uncomputed factors905if( n % i == 0 && CyclotomicPoly.count(i) == 0) {906// compute the i-th poly by dividing X^i-1 by the907// d-th cycl.poly. with d divides i908poly = vector<Integer>(i+1);909poly[0] = -1; poly[i] = 1; // X^i - 1910for (long d = 1; d < i; ++d) { // <= i/2 should be ok911if( i % d == 0) {912poly_div(q, r, poly, CyclotomicPoly[d]);913assert(r.empty());914poly = q;915}916}917CyclotomicPoly[i] = poly;918//cout << i << "-th cycl. pol.: " << CyclotomicPoly[i];919}920}921}922assert(CyclotomicPoly.count(n)>0);923return CyclotomicPoly[n];924}925926927928//---------------------------------------------------------------------------929// computing the Hilbert polynomial from h-vector930//---------------------------------------------------------------------------931932// The algorithm follows "Cohen-Macaulay rings", 4.1.5 and 4.1.9.933// The E_vector is the vector of higher multiplicities.934// It is assumed that (d-1)! is used as a common denominator in the calling routine.935936template<typename Integer>937vector<Integer> compute_e_vector(vector<Integer> Q, int dim){938size_t j;939int i;940vector <Integer> E_Vector(dim,0);941// cout << "QQQ " << Q;942// Q.resize(dim+1);943int bound=Q.size();944if(bound>dim)945bound=dim;946for (i = 0; i <bound; i++) {947for (j = 0; j < Q.size()-i; j++) {948E_Vector[i] += Q[j];949}950E_Vector[i]/=permutations<Integer>(1,i);951for (j = 1; j <Q.size()-i; j++) {952Q[j-1]=j*Q[j];953}954}955return E_Vector;956}957958//---------------------------------------------------------------------------959960template<typename Integer>961vector<Integer> compute_polynomial(vector<Integer> h_vector, int dim) {962// handle dimension 0963if (dim == 0)964return vector<Integer>(dim);965966vector<Integer> Hilbert_Polynomial = vector<Integer>(dim);967int i,j;968969Integer mult_factor;970vector <Integer> E_Vector=compute_e_vector(h_vector, dim);971vector <Integer> C(dim,0);972C[0]=1;973for (i = 0; i <dim; i++) {974mult_factor=permutations<Integer>(i,dim);975if (((dim-1-i)%2)==0) {976for (j = 0; j <dim; j++) {977Hilbert_Polynomial[j]+=mult_factor*E_Vector[dim-1-i]*C[j];978}979}980else {981for (j = 0; j <dim; j++) {982Hilbert_Polynomial[j]-=mult_factor*E_Vector[dim-1-i]*C[j];983}984}985for (j = dim-1; 0 <j; j--) {986C[j]=(unsigned long)(i+1)*C[j]+C[j-1];987}988C[0]=permutations<Integer>(1,i+1);989}990991return Hilbert_Polynomial;992}993994//---------------------------------------------------------------------------995996// substitutes t by (t-a), overwrites the polynomial!997template<typename Integer>998void linear_substitution(vector<Integer>& poly, const Integer& a) {999long deg = poly.size()-1;1000// Iterated division by (t+a)1001for (long step=0; step<deg; ++step) {1002for (long i = deg-1; i >= step; --i) {1003poly[i] -= a * poly[i+1];1004}1005//the remainders are the coefficients of the transformed polynomial1006}1007}10081009//---------------------------------------------------------------------------1010IntegrationData::IntegrationData(){1011}10121013void IntegrationData::set_nr_coeff_quasipol(long nr_coeff){1014weighted_Ehrhart_series.first.set_nr_coeff_quasipol(nr_coeff);1015}10161017string IntegrationData::getPolynomial() const{1018return polynomial;1019}10201021long IntegrationData::getDegreeOfPolynomial() const{1022return degree_of_polynomial;1023}10241025void IntegrationData::setDegreeOfPolynomial(const long d){1026degree_of_polynomial=d;1027}10281029IntegrationData::IntegrationData(const string& poly){1030polynomial=poly;1031polynomial_is_homogeneous=false; // to be on the safe side1032}10331034bool IntegrationData::isWeightedEhrhartQuasiPolynomialComputed() const{1035return weighted_Ehrhart_series.first.isHilbertQuasiPolynomialComputed();1036}10371038vector< vector<mpz_class> > IntegrationData::getWeightedEhrhartQuasiPolynomial() const{1039return weighted_Ehrhart_series.first.getHilbertQuasiPolynomial();1040}10411042void IntegrationData::computeWeightedEhrhartQuasiPolynomial(){1043weighted_Ehrhart_series.first.computeHilbertQuasiPolynomial();1044}104510461047mpz_class IntegrationData::getWeightedEhrhartQuasiPolynomialDenom() const{1048return weighted_Ehrhart_series.first.getHilbertQuasiPolynomialDenom()*weighted_Ehrhart_series.second;1049}10501051const vector<mpz_class>& IntegrationData::getNum_ZZ() const{1052return weighted_Ehrhart_series.first.getNum();1053}10541055const map<long, denom_t>& IntegrationData::getDenom() const{1056return weighted_Ehrhart_series.first.getDenom();1057}10581059const vector<mpz_class>& IntegrationData::getCyclotomicNum_ZZ() const{1060return weighted_Ehrhart_series.first.getCyclotomicNum();1061}10621063const map<long, denom_t>& IntegrationData::getCyclotomicDenom() const{1064return weighted_Ehrhart_series.first.getCyclotomicDenom();1065}10661067const pair<HilbertSeries, mpz_class>& IntegrationData::getWeightedEhrhartSeries() const{1068return weighted_Ehrhart_series;1069}10701071mpq_class IntegrationData::getIntegral() const{1072return integral;1073}10741075mpz_class IntegrationData::getNumeratorCommonDenom() const{1076return weighted_Ehrhart_series.second;1077}10781079mpq_class IntegrationData::getVirtualMultiplicity() const{1080return virtual_multiplicity;1081}10821083void IntegrationData::setIntegral(const mpq_class I){1084integral=I;1085}10861087void IntegrationData::setVirtualMultiplicity(const mpq_class I){1088virtual_multiplicity=I;1089}10901091void IntegrationData::setWeightedEhrhartSeries(const pair<HilbertSeries, mpz_class>& E){1092weighted_Ehrhart_series=E;1093weighted_Ehrhart_series.first.adjustShift();1094}10951096void IntegrationData::setHomogeneity(const bool hom){1097polynomial_is_homogeneous=hom;1098}109911001101bool IntegrationData::isPolynomialHomogeneous() const{1102return polynomial_is_homogeneous;1103}11041105} //end namespace libnormaliz11061107#ifdef NMZ_MIC_OFFLOAD1108#pragma offload_attribute (pop)1109#endif111011111112