/* * NormalizInterface: GAP wrapper for Normaliz * Copyright (C) 2014 Sebastian Gutsche, Max Horn, Christof Söger * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA.
*/
/* #! @Chapter Functions #! @Section YOU FORGOT TO SET A SECTION
*/
#define mpn_tdiv_q // workaround issue with FLINT's inline definition of // mpn_tdiv_q
#include"libnormaliz/libnormaliz.h"
#include <vector>
#include <csignal> using std::signal;
typedefvoid (*sighandler_t)(int);
// old versions of libnormaliz (before 2.99.1) did not include such a define #if !defined(NMZ_RELEASE) || NMZ_RELEASE < 30504 #error Your Normaliz version is to old! Update to 3.5.4 or newer. #endif
// Paranoia check #ifdef SYS_IS_64_BIT #if GMP_LIMB_BITS != 64 #error GAP compiled in 64 bit mode, but GMP limbs are not 64 bit #endif #else #if GMP_LIMB_BITS != 32 #error GAP compiled in 32 bit mode, but GMP limbs are not 32 bit #endif #endif
using libnormaliz::Cone; // using libnormaliz::ConeProperty; using libnormaliz::ConeProperties; using libnormaliz::Sublattice_Representation; using libnormaliz::Type::InputType;
#ifdef LIBNORMALIZ_DYNAMIC_BITSET_H using libnormaliz::dynamic_bitset; #else typedef boost::dynamic_bitset<> dynamic_bitset; #endif
using std::map; using std::string; using std::vector;
/* TODO: HSOP * There are two representations for Hilbert series in Normaliz, * standard and HSOP. Currently, only the standard representation is returned.
*/ static Obj NmzToGAP(const libnormaliz::HilbertSeries & HS)
{
Obj ret;
ret = NEW_PLIST(T_PLIST, 3);
ASS_LIST(ret, 1, NmzToGAP(HS.getNum()));
ASS_LIST(ret, 2, NmzToGAP(libnormaliz::to_vector(HS.getDenom())));
ASS_LIST(ret, 3, NmzToGAP(HS.getShift())); return ret;
}
template <typename Number> staticbool GAPToNmz(vector<Number> & out, Obj V)
{ if (!IS_PLIST(V) || !IS_DENSE_LIST(V)) returnfalse; constint n = LEN_PLIST(V);
out.resize(n); for (int i = 0; i < n; ++i) {
Obj tmp = ELM_PLIST(V, i + 1); if (!GAPToNmz(out[i], tmp)) returnfalse;
} returntrue;
}
// take either a GAP string, or a GAP small integer, and try to convert // it to a Normaliz ConeProperty enum value. static libnormaliz::ConeProperty::Enum GetConeProperty(Obj prop)
{ if (IS_STRING_REP(prop)) return libnormaliz::toConeProperty(CSTR_STRING(prop)); if (IS_NONNEG_INTOBJ(prop)) return (libnormaliz::ConeProperty::Enum)UInt8_ObjInt(prop);
ErrorQuit(" must be a string or a non-negative small integer", 0,
0);
}
template <typename Integer> static Obj _NmzConeIntern(Obj input_list)
{ bool has_polynomial_input = false;
string polynomial;
map<InputType, vector<vector<mpq_class>>> input; constint n = LEN_PLIST(input_list); if (n & 1) { throw std::runtime_error( "Input list must have even number of elements");
} for (int i = 0; i < n; i += 2) {
Obj type = ELM_PLIST(input_list, i + 1); if (!IS_STRING_REP(type)) { throw std::runtime_error( "Element " + std::to_string(i + 1) + " of the input list must be a type string");
}
string type_str(CSTR_STRING(type));
Obj M = ELM_PLIST(input_list, i + 2); if (type_str.compare("polynomial") == 0) { if (!IS_STRING_REP(M)) { throw std::runtime_error( "Element " + std::to_string(i + 2) + " of the input list must be a string");
}
polynomial = string(CSTR_STRING(M));
has_polynomial_input = true; continue;
}
vector<vector<mpq_class>> Mat; bool okay = GAPToNmz(Mat, M); if (!okay) { throw std::runtime_error( "Element " + std::to_string(i + 2) + " of the input list must be an integer matrix");
}
input[libnormaliz::to_type(type_str)] = Mat;
}
Cone<Integer> * C = new Cone<Integer>(input); if (has_polynomial_input) {
C->setPolynomial(polynomial);
}
Obj Cone = NewCone(C); return Cone;
}
static Obj Func_NmzCone(Obj self, Obj input_list)
{ if (!IS_PLIST(input_list) || !IS_DENSE_LIST(input_list))
ErrorQuit("Input argument must be a list", 0, 0);
static Obj Func_NmzCompute(Obj self, Obj cone, Obj to_compute)
{ if (!IS_CONE(cone))
ErrorQuit(" must be a Normaliz cone", 0, 0); if (!IS_PLIST(to_compute) || !IS_DENSE_LIST(to_compute))
ErrorQuit(" must be a list of strings", 0, 0);
FUNC_BEGIN
ConeProperties propsToCompute; // we have a list constint n = LEN_PLIST(to_compute);
for (int i = 0; i < n; ++i) {
Obj prop = ELM_PLIST(to_compute, i + 1); if (!IS_STRING_REP(prop)) { throw std::runtime_error( "Element " + std::to_string(i + 1) + " of the input list must be a type string");
}
string prop_str(CSTR_STRING(prop));
propsToCompute.set(libnormaliz::toConeProperty(prop_str));
}
// Cone.compute returns the not computed properties // we return a bool, true when everything requested was computed return notComputed.none() ? True : False;
FUNC_END
}
/* #! @Section Use a NmzCone #! @Arguments cone property #! @Returns whether the cone has already computed the given property #! @Description #! See <Ref Func="NmzConeProperty"/> for a list of recognized properties. #! #! @InsertChunk NmzHasConeProperty_example DeclareGlobalFunction("NmzHasConeProperty");
*/ static Obj FuncNmzHasConeProperty(Obj self, Obj cone, Obj prop)
{ if (!IS_CONE(cone))
ErrorQuit(" must be a Normaliz cone", 0, 0);
libnormaliz::ConeProperty::Enum p = GetConeProperty(prop);
Obj M = NEW_PREC(libnormaliz::ConeProperty::EnumSize);
for (int i = 0; i < libnormaliz::ConeProperty::EnumSize; ++i) {
libnormaliz::ConeProperty::Enum p =
(libnormaliz::ConeProperty::Enum)i;
#if NMZ_RELEASE >= 30500 // skip internal control properties if ( #if NMZ_RELEASE < 30800
p == libnormaliz::ConeProperty::ExplicitHilbertSeries || #endif
p == libnormaliz::ConeProperty::NakedDual) continue; #endif
AssPRec(M, RNamName(libnormaliz::toString(p).c_str()),
ObjInt_UInt8(p));
} return M;
FUNC_END
}
/* #! @Section Use a NmzCone #! @Arguments cone #! @Returns a list of strings representing the known (computed) cone #! properties #! @Description #! Given a Normaliz cone object, return a list of all properties already #! computed for the cone. #! #! @InsertChunk NmzKnownConeProperties_example DeclareGlobalFunction("NmzKnownConeProperties");
*/ static Obj FuncNmzKnownConeProperties(Obj self, Obj cone)
{ if (!IS_CONE(cone))
ErrorQuit(" must be a Normaliz cone", 0, 0);
FUNC_BEGIN
size_t n = 0;
Obj M = NEW_PLIST(T_PLIST, libnormaliz::ConeProperty::EnumSize);
Cone<mpz_class> * C = GET_CONE<mpz_class>(cone);
// FIXME: This code could be a lot simpler if there was // a Cone method for reading the value of is_Computed. for (int i = 0; i < libnormaliz::ConeProperty::EnumSize; ++i) {
libnormaliz::ConeProperty::Enum p =
(libnormaliz::ConeProperty::Enum)i;
// skip internal control properties if ( #if NMZ_RELEASE < 30800
p == libnormaliz::ConeProperty::ExplicitHilbertSeries || #endif
p == libnormaliz::ConeProperty::NakedDual) continue;
if (C->isComputed(p)) {
string prop_name(libnormaliz::toString(p));
ASS_LIST(M, ++n, MakeImmString(prop_name.c_str())); if (p == libnormaliz::ConeProperty::HilbertSeries) { const libnormaliz::HilbertSeries & HS = C->getHilbertSeries();
HS.computeHilbertQuasiPolynomial(); if (HS.isHilbertQuasiPolynomialComputed()) {
ASS_LIST(M, ++n, MakeImmString("HilbertQuasiPolynomial"));
}
}
}
}
SORT_LIST(M); return M;
#if NMZ_RELEASE >= 30700 // workaround a bug where computing HilbertQuasiPolynomial after // HilbertSeries was already computed returned notComputed equal to // NoGradingDenom, even though of course the quasi polynomial was // available.
notComputed.reset(libnormaliz::ConeProperty::NoGradingDenom); #endif if (notComputed.any()) {
ErrorQuit("Failed to compute %s, missing properties: %s",
(Int)(libnormaliz::toString(p).c_str()),
(Int)(libnormaliz::toString(notComputed).c_str())); return Fail;
}
// workaround bug in certain Normaliz versions, where the output type for // ClassGroups is reported as libnormaliz::OutputType::Vector, but calling // getVectorConeProperty on it produces an error if (p == libnormaliz::ConeProperty::ClassGroup) return NmzToGAP(C->getClassGroup());
#if NMZ_RELEASE >= 30700 && NMZ_RELEASE < 30703 // workaround bug where getMachineIntegerConeProperty does not support // NumberLatticePoints if (p == libnormaliz::ConeProperty::NumberLatticePoints) return NmzToGAP(C->getNumberLatticePoints()); #endif
#if NMZ_RELEASE < 30804 // workaround: these two properties are marked as having output type // "void" if (p == libnormaliz::ConeProperty::IsTriangulationNested) return C->isTriangulationNested() ? True : False; if (p == libnormaliz::ConeProperty::IsTriangulationPartial) return C->isTriangulationPartial() ? True : False; #endif
switch (libnormaliz::output_type(p)) { case libnormaliz::OutputType::Matrix: // TODO: switch to getMatrixConePropertyMatrix ? return NmzToGAP(C->getMatrixConeProperty(p));
case libnormaliz::OutputType::MatrixFloat: // TODO: switch to getFloatMatrixConePropertyMatrix ? return NmzToGAP(C->getFloatMatrixConeProperty(p));
case libnormaliz::OutputType::Vector: return NmzToGAP(C->getVectorConeProperty(p));
case libnormaliz::OutputType::Integer: return NmzToGAP(C->getIntegerConeProperty(p));
case libnormaliz::OutputType::GMPInteger: return NmzToGAP(C->getGMPIntegerConeProperty(p));
case libnormaliz::OutputType::Rational: return NmzToGAP(C->getRationalConeProperty(p));
#if NMZ_RELEASE >= 30700 case libnormaliz::OutputType::FieldElem: throw"OutputType::FieldElem not yet supported"; #endif
case libnormaliz::OutputType::Float: return NmzToGAP(C->getFloatConeProperty(p));
case libnormaliz::OutputType::MachineInteger: return NmzToGAP(C->getMachineIntegerConeProperty(p));
case libnormaliz::OutputType::Bool: return C->getBooleanConeProperty(p) ? True : False;
case libnormaliz::OutputType::Complex: // more complex data structures are handled below break;
case libnormaliz::OutputType::Void: // throw "cone property is input-only"; return Fail;
default: throw"unsupported output_type";
}
switch (p) { #if NMZ_RELEASE >= 30703 case libnormaliz::ConeProperty::AmbientAutomorphisms: case libnormaliz::ConeProperty::Automorphisms: case libnormaliz::ConeProperty::CombinatorialAutomorphisms: case libnormaliz::ConeProperty::EuclideanAutomorphisms: case libnormaliz::ConeProperty::RationalAutomorphisms: throw"querying automorphisms not yet supported"; #endif
/* #! @Section Use a NmzCone #! @Arguments verboseFlag #! @Returns the previous verbosity #! @Description #! Set the global default verbosity state in libnormaliz. #! This will influence all NmzCone created afterwards, but not any existing #! ones. #! #! See also <Ref Func="NmzSetVerbose"/> DeclareGlobalFunction("NmzSetVerboseDefault");
*/ static Obj FuncNmzSetVerboseDefault(Obj self, Obj value)
{ if (value != True && value != False)
ErrorQuit(" must be a boolean value", 0, 0);
FUNC_BEGIN return libnormaliz::setVerboseDefault(value == True) ? True : False;
FUNC_END
}
/* #! @Arguments cone verboseFlag #! @Returns the previous verbosity #! @Description #! Set the verbosity state for a cone. #! #! See also <Ref Func="NmzSetVerboseDefault"/> DeclareGlobalFunction("NmzSetVerbose");
*/ static Obj FuncNmzSetVerbose(Obj self, Obj cone, Obj value)
{ if (!IS_CONE(cone))
ErrorQuit(" must be a Normaliz cone", 0, 0); if (value != True && value != False)
ErrorQuit(" must be a boolean value", 0, 0); bool old_value;
template <typename Integer> static Obj _NmzBasisChangeIntern(Cone<Integer> * C)
{
Sublattice_Representation<Integer> bc;
SIGNAL_HANDLER_BEGIN
bc = C->getSublattice();
SIGNAL_HANDLER_END
Obj res = NEW_PLIST(T_PLIST, 3);
ASS_LIST(res, 1, NmzToGAP(bc.getEmbedding()));
ASS_LIST(res, 2, NmzToGAP(bc.getProjection()));
ASS_LIST(res, 3, NmzToGAP(bc.getAnnihilator())); // Dim, Rank, Equations and Congruences are already covered by special // functions The index is not always computed and not so relevant return res;
}
// GVAR_FUNC in GAP 4.9 and 4.10 triggers warnings when used in C++ code; so // we force it to the definition from GAP 4.11 #undef GVAR_FUNC #define GVAR_FUNC(name, nargs, args) \
{ \ #name, nargs, args, (ObjFunc)Func##name, __FILE__ ":"#name \
}
// Table of functions to export static StructGVarFunc GVarFuncs[] = {
GVAR_FUNC(_NmzCone, 1, "list"),
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.