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#include <iostream>24#include <cctype> // std::isdigit25#include <limits> // numeric_limits2627#include "options.h"28#include "libnormaliz/libnormaliz.h"29#include "libnormaliz/map_operations.h"30#include "libnormaliz/cone_property.h"3132// eats up a comment, stream must start with "/*", eats everything until "*/"33void skip_comment(istream& in) {34int i = in.get();35int j = in.get();36if (i != '/' || j != '*') {37throw BadInputException("Bad comment start!");38}39while (in.good()) {40in.ignore(numeric_limits<streamsize>::max(), '*'); //ignore everything until next '*'41i = in.get();42if (in.good() && i == '/') return; // successfully skipped comment43}44throw BadInputException("Incomplete comment!");45}4647void save_matrix(map<Type::InputType, vector<vector<mpq_class> > >& input_map,48InputType input_type, const vector<vector<mpq_class> >& M) {49//check if this type already exists50if (exists_element(input_map, input_type)) {51/*throw BadInputException("Multiple inputs of type \"" + type_string52+ "\" are not allowed!");*/53input_map[input_type].insert(input_map[input_type].end(),M.begin(),M.end());54return;55}56input_map[input_type] = M;57}5859void save_empty_matrix(map<Type::InputType, vector<vector<mpq_class> > >& input_map,60InputType input_type){6162vector<vector<mpq_class> > M;63save_matrix(input_map, input_type, M);64}656667vector<vector<mpq_class> > transpose_mat(const vector<vector<mpq_class> >& mat){6869if(mat.size()==0 || mat[0].size()==0)70return vector<vector<mpq_class> >(0);71size_t m=mat[0].size();72size_t n=mat.size();73vector<vector<mpq_class> > transpose(m,vector<mpq_class> (n,0));74for(size_t i=0;i<m;++i)75for(size_t j=0;j<n;++j)76transpose[i][j]=mat[j][i];77return transpose;78}798081void append_row(const vector<mpq_class> row, map <Type::InputType, vector< vector<mpq_class> > >& input_map,82Type::InputType input_type) {8384vector<vector<mpq_class> > one_row(1,row);85save_matrix(input_map,input_type,one_row);86}878889void process_constraint(const string& rel, const vector<mpq_class>& left, mpq_class right, const mpq_class modulus,90map <Type::InputType, vector< vector<mpq_class> > >& input_map, bool forced_hom) {9192vector<mpq_class> row=left;93bool inhomogeneous=false;94if(right!=0 || rel=="<" || rel==">")95inhomogeneous=true;96string modified_rel=rel;97bool strict_inequality=false;98if(rel=="<"){99strict_inequality=true;100right-=1;101modified_rel="<=";102103}104if(rel==">"){105strict_inequality=true;106right+=1;107modified_rel=">=";108}109if(strict_inequality && forced_hom){110throw BadInputException("Strict inequality not allowed in hom_constraints!");111}112if(inhomogeneous || forced_hom)113row.push_back(-right); // rhs --> lhs114if(modified_rel=="<="){ // convert <= to >=115for(size_t j=0; j<row.size();++j)116row[j]=-row[j];117modified_rel=">=";118}119if(rel=="~")120row.push_back(modulus);121122if(inhomogeneous && !forced_hom){123if(modified_rel=="="){124append_row(row,input_map,Type::inhom_equations);125return;126}127if(modified_rel==">="){128append_row(row,input_map,Type::inhom_inequalities);129return;130}131if(modified_rel=="~"){132append_row(row,input_map,Type::inhom_congruences);133return;134}135}136else {137if(modified_rel=="="){138append_row(row,input_map,Type::equations);139return;140}141if(modified_rel==">="){142append_row(row,input_map,Type::inequalities);143return;144}145if(modified_rel=="~"){146append_row(row,input_map,Type::congruences);147return;148}149}150throw BadInputException("Illegal constrint type "+rel+" !");151}152153mpq_class mpq_read(istream& in){154const string numeric="+-0123456789/.e";155in >> std::ws;156string s;157bool is_float=false;158while(true){159char c = in.peek();160size_t pos=numeric.find(c);161if(pos==string::npos)162break;163if(pos>12)164is_float=true;165in >> c;166s+=c;167}168169if(s=="")170throw BadInputException("Error in input file. Most lekely mismatch of amb_space and matrix format.");171172// cout << "t " << s << " f " << is_float << endl;173174if(!is_float)175return mpq_class(s);176177return dec_fraction_to_mpq(s);178}179180181bool read_modulus(istream& in, mpq_class& modulus) {182183in >> std::ws; // gobble any leading white space184char dummy;185in >> dummy;186if(dummy != '(')187return false;188in >> modulus;189if(in.fail() || modulus==0)190return false;191in >> std::ws; // gobble any white space before closing192in >> dummy;193if(dummy != ')')194return false;195return true;196}197198199void read_symbolic_constraint(istream& in, string& rel, vector<mpq_class>& left, mpq_class& right, mpq_class& modulus, bool forced_hom) {200201bool congruence=false;202bool modulus_read=false;203mpq_class side=1,sign;204right=0;205long hom_correction=0;206if(forced_hom)207hom_correction=1;208209in >> std::ws;210char c = in.peek();211212while(true){213if(c=='('){214if(modulus_read || !congruence || !read_modulus(in,modulus))215throw BadInputException("Error while reading modulus of congruence!");216modulus_read=true;217in >> std::ws;218c = in.peek();219}220if(modulus_read && c!=';')221throw BadInputException("Error while reading modulus of congruence!");222if(c==';'){223if(rel=="")224throw BadInputException("Missing relation in constraint");225in >> c;226if(congruence && !modulus_read)227throw BadInputException("Modulus missing in congrruence");228// cout << "LLLLL " << left << " " << rel << " RRR " << right << endl;229return;230}231232bool rel_read=false;233234if(c=='~' || c=='<' || c=='>' || c=='='){235rel_read=true;236if(rel!="")237throw BadInputException("Error while reading relation in constraint!");238if(c=='~')239congruence=true;240in >> c;241rel+=c;242}243c = in.peek();244if(rel!="" && (rel=="<" || rel==">") && c=='='){245in >> c;246rel+=c;247}248in >> std::ws;249c = in.peek();250if(rel_read){251side=-1;252continue;253}254sign=1;255if(c=='-'){256sign=-1;257in >> c;258}259if(c=='+'){260in >> c;261}262mpq_class entry=1;263in >> std::ws;264c = in.peek();265if(c!='x'){266if(c=='+' || c=='-')267throw BadInputException("Double sign in constraint");268entry=mpq_read(in);269if(in.fail())270throw BadInputException("Error while reading coefficient in constraint");271in >> std::ws;272c = in.peek();273}274if(c!='x'){275right-=side*sign*entry;276continue;277}278in >> c;279in >> std::ws;280c = in.peek();281if(c!='[')282throw BadInputException("Error while reading index in constraint");283in >> c;284long index;285in >> index;286if(in.fail() || index <1 || index+hom_correction> (long) left.size())287throw BadInputException("Error while reading index in constraint");288index-=1;289left[index]+=side*sign*entry;290in >> std::ws;291c = in.peek();292if(c!=']')293throw BadInputException("Error while reading index in constraint");294in >> c;295in >> std::ws;296c = in.peek();297continue;298}299300}301302303304void read_constraints(istream& in, long dim, map <Type::InputType, vector< vector<mpq_class> > >& input_map, bool forced_hom) {305306long nr_constraints;307in >> nr_constraints;308309if(in.fail() || nr_constraints < 0) {310throw BadInputException("Cannot read "311+ toString(nr_constraints) + " constraints!");312}313if(nr_constraints==0)314return;315316bool symbolic=false;317318in >> std::ws;319int c = in.peek();320if(c=='s'){321string dummy;322in >> dummy;323if(dummy!="symbolic")324throw BadInputException("Illegal keyword " + dummy325+ " in input!");326symbolic=true;327}328329long hom_correction=0;330if(forced_hom)331hom_correction=1;332for(long i=0;i< nr_constraints; ++i) {333334vector<mpq_class> left(dim-hom_correction);335string rel, modulus_str;336mpq_class right, modulus=0;337338if(symbolic){339read_symbolic_constraint(in,rel,left,right,modulus,forced_hom);340}341else{ // ordinary constraint read here342for(long j=0;j<dim-hom_correction;++j){343left[j]=mpq_read(in);344}345in >> rel;346right=mpq_read(in);347if(rel=="~") {348if(!read_modulus(in,modulus))349throw BadInputException("Error while reading modulus of congruence!");350}351if (in.fail()) {352throw BadInputException("Error while reading constraint!");353}354}355process_constraint(rel,left,right,modulus,input_map,forced_hom);356}357}358359void read_polynomial(istream& in, string& polynomial) {360361char c;362while(true){363in >> c;364if(in.fail())365throw BadInputException("Error while reading polynomial!");366if(c==';'){367if(polynomial.size()==0)368throw BadInputException("Error while reading polynomial!");369return;370}371polynomial+=c;372}373}374375376bool read_sparse_vector(istream& in, vector<mpq_class>& input_vec, long length){377378input_vec=vector<mpq_class> (length,0);379char dummy;380381while(true){382in >> std::ws;383int c = in.peek();384if(c==';'){385in >> dummy; // swallow ;386return true;387}388long pos;389in >> pos;390if(in.fail())391return false;392pos--;393if(pos<0 || pos>=length)394return false;395in >> std::ws;396c=in.peek();397if(c!=':')398return false;399in >> dummy; // skip :400mpq_class value;401// in >> value;402value=mpq_read(in);403if(in.fail())404return false;405input_vec[pos]=value;406}407}408409410bool read_formatted_vector(istream& in, vector<mpq_class>& input_vec) {411412input_vec.clear();413in >> std::ws;414char dummy;415in >> dummy; // read first proper character416if(dummy!='[')417return false;418bool one_more_entry_required=false;419while(true){420in >> std::ws;421if(!one_more_entry_required && in.peek()==']'){422in >> dummy;423return true;424}425mpq_class number;426number=mpq_read(in);427if(in.fail())428return false;429input_vec.push_back(number);430in >> std::ws;431one_more_entry_required=false;432if(in.peek()==',' || in.peek()==';'){ // skip potential separator433in >> dummy;434one_more_entry_required=true;435}436}437}438439440bool read_formatted_matrix(istream& in, vector<vector<mpq_class> >& input_mat, bool transpose) {441input_mat.clear();442in >> std::ws;443char dummy;444in >> dummy; // read first proper character445if(dummy!='[')446return false;447bool one_more_entry_required=false;448while(true){449in >> std::ws;450if(!one_more_entry_required && in.peek()==']'){ // closing ] found451in >> dummy;452if(transpose)453input_mat=transpose_mat(input_mat);454return true;455}456vector<mpq_class> input_vec;457if(!read_formatted_vector(in,input_vec)){458throw BadInputException("Error in reading input vector!");459}460if(input_mat.size()>0 && input_vec.size()!=input_mat[0].size()){461throw BadInputException("Rows of input matrix have unequal lengths!");462}463input_mat.push_back(input_vec);464in >> std::ws;465one_more_entry_required=false;466if(in.peek()==',' || in.peek()==';'){ // skip potential separator467in >> dummy;468one_more_entry_required=true;469}470}471}472473474475map <Type::InputType, vector< vector<mpq_class> > > readNormalizInput (istream& in, OptionsHandler& options, string& polynomial, long& nr_coeff_quasipol) {476477string type_string;478long i,j;479long nr_rows,nr_columns,nr_rows_or_columns;480InputType input_type;481mpq_class number;482ConeProperty::Enum cp;483bool we_have_a_polynomial=false;484bool we_have_nr_coeff=false;485486map<Type::InputType, vector< vector<mpq_class> > > input_map;487typename map<Type::InputType, vector< vector<mpq_class> > >::iterator it;488489in >> std::ws; // eat up any leading white spaces490int c = in.peek();491if ( c == EOF ) {492throw BadInputException("Empty input file!");493}494bool new_input_syntax = !std::isdigit(c);495496if (new_input_syntax) {497long dim;498while (in.peek() == '/') {499skip_comment(in);500in >> std::ws;501}502in >> type_string;503if (!in.good() || type_string != "amb_space") {504throw BadInputException("First entry must be \"amb_space\"!");505}506bool dim_known=false;507in >> std::ws;508c=in.peek();509if(c=='a'){510string dummy;511in >> dummy;512if(dummy!="auto"){513throw BadInputException("Bad amb_space value!");514}515}516else{517in >> dim;518if (!in.good() || dim <= 0) {519throw BadInputException("Bad amb_space value!");520}521dim_known=true;522}523while (in.good()) { //main loop524525bool transpose=false;526in >> std::ws; // eat up any leading white spaces527c = in.peek();528if (c == EOF) break;529if (c == '/') {530skip_comment(in);531} else {532in >> type_string;533if (in.fail()) {534throw BadInputException("Could not read type string!");535}536if (std::isdigit(c)) {537throw BadInputException("Unexpected number " + type_string538+ " when expecting a type!");539}540if (isConeProperty(cp, type_string)) {541options.activateInputFileConeProperty(cp);542continue;543}544/* if (type_string == "BigInt") {545options.activateInputFileBigInt();546continue;547} */548if (type_string == "LongLong") {549options.activateInputFileLongLong();550continue;551}552if (type_string == "NoExtRaysOutput") {553options.activateNoExtRaysOutput();554continue;555}556if (type_string == "total_degree") {557if(!dim_known){558throw BadInputException("Ambient space must be known for "+type_string+"!");559}560input_type = Type::grading;561save_matrix(input_map, input_type, vector< vector<mpq_class> >(1,vector<mpq_class>(dim+type_nr_columns_correction(input_type),1)));562continue;563}564if (type_string == "nonnegative") {565if(!dim_known){566throw BadInputException("Ambient space must be known for "+type_string+"!");567}568input_type = Type::signs;569save_matrix(input_map, input_type, vector< vector<mpq_class> >(1,vector<mpq_class>(dim+type_nr_columns_correction(input_type),1)));570continue;571}572if(type_string == "constraints") {573if(!dim_known){574throw BadInputException("Ambient space must be known for "+type_string+"!");575}576read_constraints(in,dim,input_map,false);577continue;578}579if(type_string == "hom_constraints") {580if(!dim_known){581throw BadInputException("Ambient space must be known for "+type_string+"!");582}583read_constraints(in,dim,input_map,true);584continue;585}586587if(type_string == "polynomial") {588if(we_have_a_polynomial)589throw BadInputException("Only one polynomial allowed");590read_polynomial(in,polynomial);591we_have_a_polynomial=true;592continue;593}594if(type_string=="nr_coeff_quasipol"){595if(we_have_nr_coeff)596throw BadInputException("Only one nr_coeff_quasipol allowed");597in >> nr_coeff_quasipol;598we_have_nr_coeff=true;599if(in.fail())600throw BadInputException("Error while reading nr_coeff_quasipol");601continue;602}603604605input_type = to_type(type_string);606if(dim_known)607nr_columns = dim + type_nr_columns_correction(input_type);608609if (type_is_vector(input_type)) {610nr_rows_or_columns = nr_rows = 1;611in >> std::ws; // eat up any leading white spaces612c = in.peek();613if (c=='u') { // must be unit vector614string vec_kind;615in >> vec_kind;616if (vec_kind != "unit_vector") {617throw BadInputException("Error while reading "618+ type_string619+ ": unit_vector expected!");620}621622long pos = 0;623in >> pos;624if (in.fail()) {625throw BadInputException("Error while reading "626+ type_string627+ " as a unit_vector!");628}629630if(!dim_known){631throw BadInputException("Ambient space must be known for unit vector "+type_string+"!");632}633634vector< vector<mpq_class> > e_i = vector< vector<mpq_class> >(1,vector<mpq_class>(nr_columns,0));635if (pos < 1 || pos > static_cast<long>(e_i[0].size())) {636throw BadInputException("Error while reading "637+ type_string + " as a unit_vector "638+ toString(pos) + "!");639}640pos--; // in input file counting starts from 1641e_i[0].at(pos) = 1;642save_matrix(input_map, input_type, e_i);643continue;644} // end unit vector645646if(c=='s'){ // must be "sparse"647string vec_kind;648in >> vec_kind;649if (vec_kind != "sparse") {650throw BadInputException("Error while reading "651+ type_string652+ ": sparse vector expected!");653}654655if(!dim_known){656throw BadInputException("Ambient space must be known for sparse vector "+type_string+"!");657}658659vector<mpq_class> sparse_vec;660nr_columns = dim + type_nr_columns_correction(input_type);661bool success = read_sparse_vector(in,sparse_vec,nr_columns);662if(!success){663throw BadInputException("Error while reading "664+ type_string665+ " as a sparse vector!");666}667save_matrix(input_map, input_type, vector<vector<mpq_class> > (1,sparse_vec));668continue;669}670671if (c == '[') { // must be formatted vector672vector<mpq_class> formatted_vec;673bool success = read_formatted_vector(in,formatted_vec);674if(!dim_known){675dim=formatted_vec.size()- type_nr_columns_correction(input_type);676dim_known=true;677nr_columns = dim + type_nr_columns_correction(input_type);678}679if(!success || (long) formatted_vec.size()!=nr_columns){680throw BadInputException("Error while reading "681+ type_string682+ " as a formatted vector!");683}684save_matrix(input_map, input_type, vector<vector<mpq_class> > (1,formatted_vec));685continue;686} // end formatted vector687688} else { // end vector, it is a matrix. Plain vector read as a one row matrix later on689in >> std::ws;690c = in.peek();691692if(c!='[' && !std::isdigit(c)){ // must be transpose693string transpose_str;694in >> transpose_str;695if(transpose_str!="transpose"){696throw BadInputException("Illegal keyword "+transpose_str+" following matrix type!");697}698transpose=true;699in >> std::ws;700c = in.peek();701}702if(c=='['){ // it is a formatted matrix703vector<vector<mpq_class> > formatted_mat;704bool success=read_formatted_matrix(in,formatted_mat, transpose);705if(!success){706throw BadInputException("Error while reading formatted matrix "707+ type_string + "!");708}709if(formatted_mat.size() ==0){ // empty matrix710input_type = to_type(type_string);711save_empty_matrix(input_map, input_type);712continue;713}714if(!dim_known){715dim=formatted_mat[0].size()- type_nr_columns_correction(input_type);716dim_known=true;717nr_columns = dim + type_nr_columns_correction(input_type);718}719720if((long) formatted_mat[0].size()!=nr_columns){721throw BadInputException("Error while reading formatted matrix "722+ type_string + "!");723}724725save_matrix(input_map, input_type, formatted_mat);726continue;727} // only plain matrix left728729in >> nr_rows_or_columns; // is number of columns if transposed730nr_rows=nr_rows_or_columns; // most of the time731}732733if(!dim_known){734throw BadInputException("Ambient space must be known for plain matrix or vector "+type_string+"!");735}736737if(transpose)738swap(nr_rows,nr_columns);739740if(in.fail() || nr_rows_or_columns < 0) {741throw BadInputException("Error while reading "742+ type_string + " (a " + toString(nr_rows)743+ "x" + toString(nr_columns)744+ " matrix) !");745}746if(nr_rows==0){747input_type = to_type(type_string);748save_empty_matrix(input_map, input_type);749continue;750}751752vector< vector<mpq_class> > M(nr_rows);753in >> std::ws;754c=in.peek();755if(c=='s'){ // must be sparse756string sparse_test;757in >> sparse_test;758if (sparse_test!= "sparse") {759throw BadInputException("Error while reading "760+ type_string761+ ": sparse matrix expected!");762}763for(long i=0;i<nr_rows;++i){764bool success=read_sparse_vector(in,M[i],nr_columns);765if(!success){766throw BadInputException("Error while reading "767+ type_string768+ ": corrupted sparse matrix");769}770771}772} else{ // dense matrix773for(i=0; i<nr_rows; i++){774M[i].resize(nr_columns);775for(j=0; j<nr_columns; j++) {776M[i][j]=mpq_read(in);777}778}779}780if(transpose)781M=transpose_mat(M);782save_matrix(input_map, input_type, M);783}784if (in.fail()) {785throw BadInputException("Error while reading " + type_string786+ " (a " + toString(nr_rows) + "x"787+ toString(nr_columns) + " matrix) !");788}789}790} else {791// old input syntax792while (in.good()) {793in >> nr_rows;794if(in.fail())795break;796in >> nr_columns;797if((nr_rows <0) || (nr_columns < 0)){798throw BadInputException("Error while reading a "799+ toString(nr_rows) + "x" + toString(nr_columns)800+ " matrix !");801}802vector< vector<mpq_class> > M(nr_rows,vector<mpq_class>(nr_columns));803for(i=0; i<nr_rows; i++){804for(j=0; j<nr_columns; j++) {805number=mpq_read(in);806M[i][j] = number;807}808}809810in >> type_string;811812if ( in.fail() ) {813throw BadInputException("Error while reading a "814+ toString(nr_rows) + "x" + toString(nr_columns)815+ " matrix!");816}817818input_type = to_type(type_string);819820//check if this type already exists821save_matrix(input_map, input_type, M);822}823}824return input_map;825}826827