From ac0b79e376e42f7e88175a3c9164356035164fe7 Mon Sep 17 00:00:00 2001
From: Matti Pellika <matti.pellikka@tut.fi>
Date: Sat, 13 Feb 2010 10:09:35 +0000
Subject: [PATCH] Patch by Richard.

---
 Geo/ChainComplex.h                      |   6 +-
 contrib/kbipack/CMakeLists.txt          |   8 +-
 contrib/kbipack/compute_normal_form.cpp | 355 +++++++++++
 contrib/kbipack/gmp_blas.cpp            | 227 +++++++
 contrib/kbipack/gmp_blas.h              |  14 +-
 contrib/kbipack/gmp_matrix.cpp          | 793 ++++++++++++++++++++++++
 contrib/kbipack/gmp_matrix.h            |   2 +-
 contrib/kbipack/gmp_matrix_io.cpp       | 135 ++++
 contrib/kbipack/gmp_matrix_io.h         |   2 +-
 contrib/kbipack/gmp_normal_form.cpp     | 783 +++++++++++++++++++++++
 contrib/kbipack/mpz.cpp                 |   2 +-
 11 files changed, 2308 insertions(+), 19 deletions(-)
 create mode 100644 contrib/kbipack/compute_normal_form.cpp
 create mode 100644 contrib/kbipack/gmp_blas.cpp
 create mode 100644 contrib/kbipack/gmp_matrix.cpp
 create mode 100644 contrib/kbipack/gmp_matrix_io.cpp
 create mode 100644 contrib/kbipack/gmp_normal_form.cpp

diff --git a/Geo/ChainComplex.h b/Geo/ChainComplex.h
index eeaec9b163..6ecb04e7b3 100644
--- a/Geo/ChainComplex.h
+++ b/Geo/ChainComplex.h
@@ -27,15 +27,11 @@
 
 
 #if defined(HAVE_GMP) 
-#include "gmp.h"
-extern "C" {
+  #include "gmp.h"
   #include "gmp_normal_form.h"
-}
 #else
-extern "C" {
   #include "mpz.h"
   #include "gmp_normal_form.h"
-}
 #endif
 
 // A class representing a chain complex of a cell complex.
diff --git a/contrib/kbipack/CMakeLists.txt b/contrib/kbipack/CMakeLists.txt
index ae9cf789de..253ced8236 100644
--- a/contrib/kbipack/CMakeLists.txt
+++ b/contrib/kbipack/CMakeLists.txt
@@ -4,10 +4,10 @@
 # bugs and problems to <gmsh@geuz.org>.
 
 set(SRC
-  gmp_normal_form.c
-  gmp_matrix_io.c
-  gmp_matrix.c
-  gmp_blas.c
+  gmp_normal_form.cpp
+  gmp_matrix_io.cpp
+  gmp_matrix.cpp
+  gmp_blas.cpp
   mpz.cpp
 )
 
diff --git a/contrib/kbipack/compute_normal_form.cpp b/contrib/kbipack/compute_normal_form.cpp
new file mode 100644
index 0000000000..f86e043cc2
--- /dev/null
+++ b/contrib/kbipack/compute_normal_form.cpp
@@ -0,0 +1,355 @@
+/* 
+   COMPUTE_NORMAL_FORM
+
+   Hermite and Smith normal forms of integer matrices. 
+
+   Implementation: Dense matrix with GMP-library's mpz_t elements to 
+                   hold huge integers. 
+
+   Algorithm: Kannan - Bachem algorithm with improvement by
+              Chou and Collins. Expects a large number of unit invariant 
+	      factors and takes advantage of them as they appear.
+
+   References: 
+    [1] Ravindran Kannan, Achim Bachem: 
+        "Polynomial algorithms for computing the Smith and Hermite normal 
+	forms of an integer matrix", 
+	SIAM J. Comput., vol. 8, no. 5, pp. 499-507, 1979.
+    [2] Tsu-Wu J.Chou, George E. Collins: 
+        "Algorithms for the solution of systems of linear Diophantine 
+	equations", 
+	SIAM J. Comput., vol. 11, no. 4, pp. 687-708, 1982.
+    [3] GMP homepage http://www.swox.com/gmp/
+    [4] GNU gmp page http://www.gnu.org/software/gmp/
+
+   Copyright (C) 3.11.2003 Saku Suuriniemi TUT/CEM
+
+   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
+   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+   Saku Suuriniemi, TUT/Electromagetics
+   P.O.Box 692, FIN-33101 Tampere, Finland
+   saku.suuriniemi@tut.fi
+   
+   $Id: compute_normal_form.c,v 1.1 2009-03-30 14:10:57 matti Exp $
+*/
+
+
+#include<stdlib.h>
+#include<stdio.h>
+#include<string.h>
+#include"gmp_matrix_io.h"
+#include"gmp_normal_form.h"
+
+typedef enum {HERMITE, SMITH}     nf_flag;
+typedef enum {NOT_WANTED, WANTED} w_flag;
+
+static int nf_parse_options(int arg_counter, char ** args, 
+			    char ** p_infile_name, char ** p_outfile_name, 
+			    nf_flag *       p_normal_form_requested, 
+			    inverted_flag * p_left_inverted, 
+			    inverted_flag * p_right_inverted, 
+			    w_flag *        p_help_wanted, 
+			    w_flag *        p_verbose_wanted)
+{
+  size_t ind1, ind2;
+  size_t outfilename_length;
+  
+  /* If no infile is specified, the error is indisputable. 
+      => Print help and exit. 
+     Infile should be the last argument. */
+
+  if(strncmp(args[arg_counter-1], "-", 1) == 0)
+    {
+      *(p_help_wanted) = WANTED;
+      return EXIT_SUCCESS;
+    }
+
+  /* Should I find arguments? */
+  if(arg_counter > 2)
+    {
+      for(ind1 = 1; ind1 < arg_counter-1; ind1++)
+	{
+	  /* No multiple infile names ! */
+	  if(strncmp(args[ind1], "-", 1) != 0)
+	    {
+	      *(p_help_wanted) = WANTED;
+	      return EXIT_SUCCESS;
+	    }
+
+	  /* Parse the option letters after '-' one by one */
+	  for(ind2 = 1; ind2 < strlen(args[ind1]); ind2++)
+	    {
+	      switch(args[ind1][ind2])
+		{
+		case 'h':
+		  *(p_help_wanted) = WANTED;
+		  return EXIT_SUCCESS;
+		  break;
+		case 'H':
+		  *(p_normal_form_requested) = HERMITE;
+		  break;
+		case 'S':
+		  *(p_normal_form_requested) = SMITH;
+		  break;
+		case 'l':
+		  *(p_left_inverted) = INVERTED;
+		  break;
+		case 'r':
+		  *(p_right_inverted) = INVERTED;
+		  break;
+		case 'v':
+		  *(p_verbose_wanted) = WANTED;
+		  break;
+		}
+	    }	  
+	}
+    }
+
+  /* Get the infile name */
+  * p_infile_name = (char *) calloc(strlen(args[arg_counter-1]) + 1, 
+				    sizeof(char));
+  if(* p_infile_name == NULL)
+    {
+      return EXIT_FAILURE;
+    }
+
+  strcpy(* p_infile_name, args[arg_counter-1]);
+
+  /* Create the outfile name */
+  outfilename_length = strcspn( * p_infile_name, ".");
+  * p_outfile_name = (char *) calloc(outfilename_length + 1, 
+				     sizeof(char));
+  if( * p_outfile_name == NULL)
+    {
+      free( * p_infile_name);
+      return EXIT_FAILURE;
+    }
+
+  strncpy(* p_outfile_name, * p_infile_name, outfilename_length);
+  (* p_outfile_name)[outfilename_length] = '\0';
+
+  return EXIT_SUCCESS;
+}
+
+static int nf_print_help(void)
+{
+  fprintf(stdout, "Usage: compute_normal_form [-hHSlrv] infile\n");
+  fprintf(stdout, "\n");
+  fprintf(stdout, "Description: Compute the Hermite/Smith normal form of an integer matrix.\n");
+  fprintf(stdout, "\n");
+  fprintf(stdout, "Input: \"infile\" is an ascii file, which contains an integer matrix\n");
+  fprintf(stdout, "       in the sparse coordinate format:\n"); 
+  fprintf(stdout, "\n");
+  fprintf(stdout, "        # All comments before the data\n");
+  fprintf(stdout, "        rows columns nonzeros\n");
+  fprintf(stdout, "        row1 col1    value1\n");
+  fprintf(stdout, "        row2 col2    value2\n");
+  fprintf(stdout, "        ...\n");
+  fprintf(stdout, "\n");
+  fprintf(stdout, "       No multiple infiles, please.\n");
+  fprintf(stdout, "\n");
+  fprintf(stdout, "Options: -h This help\n");
+  fprintf(stdout, "         -H Compute the Hermite normal form (default)\n");
+  fprintf(stdout, "         -S Compute the Smith normal form\n");
+  fprintf(stdout, "         -l Left factor inverted (A = P^(T)LU instead of PA = LU for Hermite, \n");
+  fprintf(stdout, "                                  U^(-1)A = SV instead of A = USV for Smith)\n");
+  fprintf(stdout, "         -r Right factor inverted (PAU^(-1) = L instead of PA = LU for Hermite, \n");
+  fprintf(stdout, "                                   AV^(-1) = US instead of A = USV for Smith)\n");
+  fprintf(stdout, "         -v Verbose. Print the matrix and the decomposition to sdtout, \n");
+  fprintf(stdout, "                     so that the user may check that the problem is read and written\n");
+  fprintf(stdout, "                     correctly.\n");
+  fprintf(stdout, "\n");
+  fprintf(stdout, "Output: For inpur matrix in e.g. \"infile.coord\", writes ascii files\n");
+  fprintf(stdout, "        \"infile.left\", \"infile.can\", and \"infile.right\", which \n");
+  fprintf(stdout, "        contain the left factor, canonical form, and the right factor, \n");
+  fprintf(stdout, "        respectively. The matrices are written in the sparse coordinate\n");
+  fprintf(stdout, "        format.\n");
+  fprintf(stdout, "\n");
+  fprintf(stdout, "Note: The return values may be big enough to not fit the standard integer types.\n");
+  fprintf(stdout, "\n");
+  fprintf(stdout, "Copyright (C) 3.11.2003 Saku Suuriniemi, Tampere University of Technology/Electromagnetics\n");
+  fprintf(stdout, "                        P.O.Box 692, FIN-33101 Tampere, Finland. saku.suuriniemi@tut.fi\n");
+  fprintf(stdout, "\n");
+  fprintf(stdout, "Licenced under GNU General Public Licence (GPL) version 2 or later, ABSOLUTELY NO WARRANTY.\n");
+
+  return EXIT_SUCCESS;
+}
+
+
+static char* append_suffix(const char * file_base_name, const char * suffix)
+{
+  char * filename;
+
+  if((file_base_name == NULL) || (suffix == NULL))
+    {
+      return NULL;
+    }
+
+  filename = 
+    (char*) calloc(strlen(file_base_name)+strlen(suffix)+2,
+		   sizeof(char));
+
+  if(filename == NULL)
+    {
+      return NULL;
+    }
+
+  strcpy(filename, file_base_name);
+  strcat(filename, ".");
+  strcat(filename, suffix);
+
+  return filename;
+}
+
+
+
+int main(int argc, char * argv[])
+{
+  char            * infile_name;
+  char            * file_base_name;
+  char            * outfile_name;
+  gmp_matrix      * A;
+  gmp_normal_form * normal_form;
+  w_flag            help_wanted;
+  w_flag            verbose_wanted;
+  nf_flag           normal_form_requested;
+  inverted_flag     left_inverted;
+  inverted_flag     right_inverted;
+
+  if(argc == 1)
+    {
+      fprintf(stdout, "Please try \"compute_normal_form -h\" for help.\n");
+      return EXIT_SUCCESS;
+    }
+
+  /* Default settings before option parsing */
+  normal_form_requested = HERMITE;
+  left_inverted         = NOT_INVERTED;
+  right_inverted        = NOT_INVERTED;
+  help_wanted           = NOT_WANTED;
+  verbose_wanted        = NOT_WANTED;
+
+  if( nf_parse_options(argc, argv, 
+		       &infile_name, &file_base_name, 
+		       &normal_form_requested, 
+		       &left_inverted, &right_inverted, 
+		       &help_wanted, 
+		       &verbose_wanted) 
+      == EXIT_FAILURE )
+    {
+      return EXIT_FAILURE;
+    }
+
+  /* In this case, no dynamical memory has been allocated by 
+     nf_parse_options ! */
+  if(help_wanted == WANTED)
+    {
+      return nf_print_help();
+    }
+
+  if(verbose_wanted == WANTED)
+    {
+      fprintf(stdout, "Computing ");
+      if(normal_form_requested == HERMITE)
+	{
+	  fprintf(stdout, "Hermite");
+	}
+      else
+	{
+	  fprintf(stdout, "Smith");
+	}
+      fprintf(stdout, " normal form\n");
+      if(left_inverted == INVERTED)
+	{
+	  fprintf(stdout, "The left factor will be inverted.\n");
+	}
+      if(right_inverted == INVERTED)
+	{
+	  fprintf(stdout, "The right factor will be inverted.\n");
+	}
+      fprintf(stdout, "Matrix read from file %s\n", infile_name);
+    }
+
+  /*************************************************************/
+  /* We have all we need to get to the computational business: */
+  /*************************************************************/
+
+  /* Read the matrix */
+  A = gmp_matrix_read_coord(infile_name);
+  free(infile_name);
+
+  if(verbose_wanted == WANTED)
+    {
+      fprintf(stdout, "Input matrix:\n");
+      gmp_matrix_fprintf(stdout, A);
+    }
+
+  /* Compute the requested normal form */
+  switch(normal_form_requested)
+    {
+    case SMITH:
+      normal_form = create_gmp_Smith_normal_form(A, left_inverted, right_inverted);
+      break;
+
+    default:
+      normal_form = create_gmp_Hermite_normal_form(A, left_inverted, right_inverted);
+      break;
+    }
+
+
+  if(verbose_wanted == WANTED)
+    {
+      fprintf(stdout, "Left factor:\n");
+      gmp_matrix_fprintf(stdout, normal_form->left);
+      fprintf(stdout, "Canonical form:\n");
+      gmp_matrix_fprintf(stdout, normal_form->canonical);
+      fprintf(stdout, "Right factor:\n");
+      gmp_matrix_fprintf(stdout, normal_form->right);
+    }
+
+  /* Save the result to the output files */
+  outfile_name = append_suffix(file_base_name, "left");
+  if( gmp_matrix_write_coord(outfile_name, normal_form -> left) 
+      == EXIT_SUCCESS)
+    {
+      if(verbose_wanted == WANTED)
+	fprintf(stdout, "Left factor successfully writen to file     %s\n", outfile_name);
+    }
+
+  free(outfile_name);
+
+  outfile_name = append_suffix(file_base_name, "can");
+  if( gmp_matrix_write_coord(outfile_name, normal_form -> canonical)
+      == EXIT_SUCCESS)
+    {
+      if(verbose_wanted == WANTED)
+	fprintf(stdout, "Canonical form successfully writen to file  %s\n", outfile_name);
+    }
+  free(outfile_name);
+
+  outfile_name = append_suffix(file_base_name, "right");
+  if( gmp_matrix_write_coord(outfile_name, normal_form -> right)
+      == EXIT_SUCCESS)
+    {
+      if(verbose_wanted == WANTED)
+	fprintf(stdout, "Right factor successfully writen to file    %s\n", outfile_name);
+    }
+  free(outfile_name);
+
+  free(file_base_name);
+  destroy_gmp_normal_form(normal_form);
+  
+  return EXIT_SUCCESS;
+}
diff --git a/contrib/kbipack/gmp_blas.cpp b/contrib/kbipack/gmp_blas.cpp
new file mode 100644
index 0000000000..4d0dd74eab
--- /dev/null
+++ b/contrib/kbipack/gmp_blas.cpp
@@ -0,0 +1,227 @@
+/* 
+   Source file for integer-oriented elementary versions of some 
+   subroutines of BLAS. There routines are chosen to facilitate the 
+   computation of Hermite and Smith normal forms of matrices of 
+   modest size. 
+
+   Copyright (C) 28.10.2003 Saku Suuriniemi TUT/CEM
+
+   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
+   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+   Saku Suuriniemi, TUT/Electromagetics
+   P.O.Box 692, FIN-33101 Tampere, Finland
+   saku.suuriniemi@tut.fi
+
+   $Id: gmp_blas.c,v 1.1 2009-03-30 14:10:57 matti Exp $
+*/
+
+/* #include<stdio.h> */
+#include"gmp_blas.h"
+
+void gmp_blas_swap(size_t n, mpz_t* x, size_t incx, mpz_t* y, size_t incy)
+{
+  mpz_t  elbow;
+  size_t ind;
+
+  mpz_init(elbow);
+
+  for(ind = 0; ind < n; ind++)
+    {
+      mpz_set(elbow      , x[ind*incx]);
+      mpz_set(x[ind*incx], y[ind*incy]);
+      mpz_set(y[ind*incy], elbow);
+    }
+  mpz_clear(elbow);
+
+  return;
+}
+
+void gmp_blas_scal(size_t n, mpz_t a, mpz_t* x, size_t incx)
+{
+  size_t ind;
+
+  for(ind = 0; ind < n; ind++)
+    {
+      mpz_mul (x[ind*incx], x[ind*incx], a);
+    }
+
+  return;
+}
+
+void gmp_blas_copy(size_t n, mpz_t* x, size_t incx, mpz_t* y, size_t incy)
+{
+  size_t ind;
+
+  for(ind = 0; ind < n; ind++)
+    {
+      mpz_set(y[ind*incy], x[ind*incx]);
+    }
+
+  return;
+}
+
+void gmp_blas_axpy(size_t n, mpz_t a, mpz_t* x, size_t incx, 
+		   mpz_t* y, size_t incy)
+{
+  size_t ind;
+
+  for(ind = 0; ind < n; ind++)
+    {
+      mpz_addmul (y[ind*incy], a, x[ind*incx]);
+    }
+
+  return;
+}
+
+void
+gmp_blas_dot(mpz_t * d, size_t n, 
+	     mpz_t* x, size_t incx, 
+	     mpz_t* y, size_t incy)
+{
+  size_t ind;
+
+  mpz_set_si(*d,0);
+
+  for(ind = 0; ind < n; ind++)
+    {
+      mpz_addmul (*d, x[ind*incx], y[ind*incy]);
+    }
+
+  return;  
+}
+
+/* x <- ax + by 
+   y <- cx + dy */
+void gmp_blas_rot(size_t n, 
+		  mpz_t a, mpz_t b, mpz_t* x, size_t incx, 
+		  mpz_t c, mpz_t d, mpz_t* y, size_t incy)
+{
+  mpz_t  ax;
+  mpz_t  by;
+  mpz_t  cx;
+  mpz_t  dy;
+
+  size_t ind;
+
+  mpz_init(ax);
+  mpz_init(by);
+  mpz_init(cx);
+  mpz_init(dy);
+
+  for(ind = 0; ind < n; ind++)
+    {
+      mpz_mul (ax, a, x[ind*incx]);
+      mpz_mul (by, b, y[ind*incy]);
+      mpz_mul (cx, c, x[ind*incx]);
+      mpz_mul (dy, d, y[ind*incy]);
+      mpz_add (x[ind*incx], ax, by);
+      mpz_add (y[ind*incy], cx, dy);
+    }
+
+  mpz_clear(ax);
+  mpz_clear(by);
+  mpz_clear(cx);
+  mpz_clear(dy);
+
+  return;
+}
+
+
+/* Returns k such that x[(k-1)*incx] != 0 holds for the first time. 
+   If none found, returns n+1. */
+size_t gmp_blas_inz  (size_t n, mpz_t* x, size_t incx)
+{
+  size_t ind;
+
+  for(ind = 0; ind < n; ind++)
+    {
+      if(mpz_sgn (x[ind*incx]) != 0)
+	{  
+	  return ind+1; 
+	}
+    }
+
+  /* No nonzeros found */
+  return n+1; 
+}
+
+size_t gmp_blas_iamax(size_t n, mpz_t* x, size_t incx)
+{
+  size_t ind;
+  size_t ind_so_far;
+  mpz_t  max_so_far;
+
+  mpz_init(max_so_far);
+  mpz_set_si(max_so_far, 0);
+  ind_so_far = 0;
+
+  for(ind = 0; ind < n; ind++)
+    {
+      if(mpz_cmpabs (x[ind*incx], max_so_far) > 0)
+	{  
+	  mpz_set(max_so_far, x[ind*incx]);
+	  ind_so_far = ind;
+	}
+    }
+
+  /* No nonzeros found */
+  if(mpz_sgn (max_so_far) == 0)
+    {
+      mpz_clear(max_so_far);
+      return n + 1; 
+    }
+
+  /* Nonzero maximal by modulus element found */
+  mpz_clear(max_so_far);
+  return ind_so_far + 1; 
+}
+
+
+size_t gmp_blas_iamin(size_t n, mpz_t* x, size_t incx)
+{
+  size_t ind;
+  size_t ind_so_far;
+  mpz_t  min_so_far;
+
+  ind_so_far = gmp_blas_inz (n, x, incx);
+
+  /* No nonzeros found? */
+  if(ind_so_far == n+1)
+    {
+      return n+1;
+    }
+
+  /* OK, There is at leat one nonzero element */
+  mpz_init(min_so_far);
+  mpz_set(min_so_far, x[(ind_so_far-1)*incx]);
+
+  /* Scan through te rest of the elements to see if smaller  
+     elements by modulus are found */
+  for(ind = ind_so_far-1; ind < n; ind++)
+    {
+      if(mpz_sgn (x[ind*incx]) != 0)
+	{
+	  if(mpz_cmpabs (x[ind*incx], min_so_far) < 0)
+	    { 
+	      mpz_set(min_so_far, x[ind*incx]);
+	      ind_so_far = ind + 1;
+	    }
+	}
+    }
+
+  /* Nonzero minimal by modulus element found */
+  mpz_clear(min_so_far);
+  return ind_so_far;
+}
diff --git a/contrib/kbipack/gmp_blas.h b/contrib/kbipack/gmp_blas.h
index b2800e5c2f..8a70cd4c6e 100644
--- a/contrib/kbipack/gmp_blas.h
+++ b/contrib/kbipack/gmp_blas.h
@@ -47,19 +47,19 @@ gmp_blas_scal(size_t n, mpz_t a, mpz_t * x, size_t incx);
 
 /* y <- x */
 void 
-gmp_blas_copy(size_t n, const mpz_t * x, size_t incx, mpz_t * y, size_t incy); 
+gmp_blas_copy(size_t n, mpz_t * x, size_t incx, mpz_t * y, size_t incy); 
 
 /* y <- ax + y */
 void 
 gmp_blas_axpy(size_t n, mpz_t a, 
-	      const mpz_t * x, size_t incx, 
+	      mpz_t * x, size_t incx, 
 	      mpz_t * y,       size_t incy); 
 
 /* d <- x^T y The integer * d has to be initialized by e.g. mpz_init() ! */
 void
 gmp_blas_dot(mpz_t * d, size_t n, 
-	     const mpz_t * x, size_t incx, 
-	     const mpz_t * y, size_t incy); 
+	     mpz_t * x, size_t incx, 
+	     mpz_t * y, size_t incy); 
 
 
 /* Givens rotations are obviously impossible. However, the extended Euclid  
@@ -92,12 +92,12 @@ void gmp_blas_rot(size_t n,
 /* Returns k such that x[(k-1)*incx] != 0 holds for the first time. 
    In FORTRAN, this is x((k-1)*incx + 1) .NE. 0.
    If none found, returns n+1. */
-size_t gmp_blas_inz  (size_t n, const mpz_t * x, size_t incx);
+size_t gmp_blas_inz  (size_t n, mpz_t * x, size_t incx);
 
 /* Similarly, x[(k-1)*incx] is maximal by modulus */
-size_t gmp_blas_iamax(size_t n, const mpz_t * x, size_t incx);
+size_t gmp_blas_iamax(size_t n, mpz_t * x, size_t incx);
 
 /* Similarly, x[(k-1)*incx] is nonzero and minimal by modulus */
-size_t gmp_blas_iamin(size_t n, const mpz_t * x, size_t incx);
+size_t gmp_blas_iamin(size_t n, mpz_t * x, size_t incx);
 
 #endif
diff --git a/contrib/kbipack/gmp_matrix.cpp b/contrib/kbipack/gmp_matrix.cpp
new file mode 100644
index 0000000000..aae01ec1e7
--- /dev/null
+++ b/contrib/kbipack/gmp_matrix.cpp
@@ -0,0 +1,793 @@
+/* 
+   Source file for integer-oriented matrix, relying on the arbitrary 
+   precision integers from the GNU gmp package. 
+
+   Copyright (C) 28.10.2003 Saku Suuriniemi TUT/CEM
+
+   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
+   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+   Saku Suuriniemi, TUT/Electromagetics
+   P.O.Box 692, FIN-33101 Tampere, Finland
+   saku.suuriniemi@tut.fi
+
+   $Id: gmp_matrix.c,v 1.5 2009-05-05 11:35:01 matti Exp $
+*/
+
+
+#include<stdlib.h>
+#include"gmp_matrix.h"
+
+gmp_matrix * 
+create_gmp_matrix(size_t r, size_t c, 
+		  mpz_t * e)
+{
+  gmp_matrix * new_matrix;
+  size_t       ind;
+
+  new_matrix = (gmp_matrix * ) malloc(sizeof(gmp_matrix));
+  if(new_matrix == NULL)
+    {
+      return NULL;
+    }
+
+  new_matrix -> storage = (mpz_t *) calloc(r*c, sizeof(mpz_t));
+  if(new_matrix -> storage == NULL)
+    {
+      free(new_matrix);
+      return NULL;
+    }
+
+  new_matrix -> rows = r;
+  new_matrix -> cols = c;
+
+  for(ind = 0; ind < r*c; ind ++)
+    {
+      mpz_init (new_matrix -> storage[ind]);
+      mpz_set  (new_matrix -> storage[ind], e[ind]);
+    }
+
+  return new_matrix;
+}
+
+gmp_matrix * 
+create_gmp_matrix_int(size_t r, size_t c, 
+		  const long int * e)
+{
+  gmp_matrix * new_matrix;
+  size_t       ind;
+
+  new_matrix = (gmp_matrix * ) malloc(sizeof(gmp_matrix));
+  if(new_matrix == NULL)
+    {
+      return NULL;
+    }
+
+  new_matrix -> storage = (mpz_t *) calloc(r*c, sizeof(mpz_t));
+  if(new_matrix -> storage == NULL)
+    {
+      free(new_matrix);
+      return NULL;
+    }
+
+  new_matrix -> rows = r;
+  new_matrix -> cols = c;
+
+  for(ind = 0; ind < r*c; ind ++)
+    {
+      mpz_init    (new_matrix -> storage[ind]);
+      mpz_set_si  (new_matrix -> storage[ind], e[ind]);
+    }
+
+  return new_matrix;
+}
+
+
+gmp_matrix * 
+create_gmp_matrix_identity(size_t dim)
+{
+  gmp_matrix * new_matrix;
+  size_t       ind;
+
+  new_matrix = (gmp_matrix * ) malloc(sizeof(gmp_matrix));
+  if(new_matrix == NULL)
+    {
+      return NULL;
+    }
+
+  new_matrix -> storage = (mpz_t *) calloc(dim*dim, sizeof(mpz_t));
+  if(new_matrix -> storage == NULL)
+    {
+      free(new_matrix);
+      return NULL;
+    }
+
+  new_matrix -> rows = dim;
+  new_matrix -> cols = dim;
+
+  for(ind = 0; ind < dim*dim; ind ++)
+    {
+      mpz_init_set_si (new_matrix -> storage[ind], 0);
+    }
+
+  for(ind = 0; ind < dim; ind ++)
+    {
+      mpz_set_ui(new_matrix -> storage[ind*(dim+1)], 1);
+    }
+
+  return new_matrix;
+}
+
+
+gmp_matrix * 
+create_gmp_matrix_zero(size_t rows, size_t cols)
+{ 
+  gmp_matrix * new_matrix;
+  size_t       ind;
+
+  new_matrix = (gmp_matrix * ) malloc(sizeof(gmp_matrix));
+  if(new_matrix == NULL)
+    {
+      return NULL;
+    }
+
+  new_matrix -> storage = (mpz_t *) calloc(rows*cols, sizeof(mpz_t));
+  if(new_matrix -> storage == NULL)
+    {
+      free(new_matrix);
+      return NULL;
+    }
+
+  new_matrix -> rows = rows;
+  new_matrix -> cols = cols;
+
+  for(ind = 0; ind < rows*cols; ind ++)
+    {
+      mpz_init_set_si (new_matrix -> storage[ind], 0);
+    }
+  return new_matrix;
+}
+
+gmp_matrix * 
+copy_gmp_matrix(const gmp_matrix * matrix, 
+		  const size_t start_row, const size_t start_col, 
+		  const size_t end_row, const size_t end_col)
+{
+  gmp_matrix * new_matrix;
+  size_t       ind;
+  size_t       r;
+  size_t       c;
+  size_t       old_rows;
+  size_t       old_cols;
+  size_t       i;
+  size_t       j;
+
+  new_matrix = (gmp_matrix * ) malloc(sizeof(gmp_matrix));
+  if(new_matrix == NULL)
+    {
+      return NULL;
+    }
+
+  r = end_row-start_row+1;
+  c = end_col-start_col+1;
+  if(r < 1 || c < 1) return NULL;
+  
+  new_matrix -> storage = (mpz_t *) calloc(r*c, sizeof(mpz_t));
+  if(new_matrix -> storage == NULL)
+    {
+      free(new_matrix);
+      return NULL;
+    }
+
+  new_matrix -> rows = r;
+  new_matrix -> cols = c;
+
+  old_rows = matrix -> rows;
+  old_cols = matrix -> cols;
+
+  ind = 0;
+  for(j = 1; j <= old_cols; j++){
+    if(j >= start_col && j <= end_col){
+      for(i = 1; i <= old_rows; i++){
+        if(i >= start_row && i <= end_row){
+          mpz_init (new_matrix -> storage[ind]);
+          mpz_set  (new_matrix -> storage[ind], matrix -> storage[(j-1)*old_rows+(i-1)]);
+          ind++;
+        }
+      }
+    }
+  }
+     
+  return new_matrix;
+}
+
+int 
+destroy_gmp_matrix(gmp_matrix * m)
+{
+  size_t       ind, nmb_storage;;
+
+  if(m == NULL)
+    {
+      return EXIT_FAILURE;
+    }
+
+  if(m -> storage == NULL)
+    {
+      free(m);
+      return EXIT_FAILURE;
+    }
+
+  nmb_storage = (m -> rows)*(m -> cols);
+
+  for(ind = 0; ind < nmb_storage; ind++)
+    {
+      mpz_clear(m -> storage[ind]);
+    }
+
+  free(m -> storage);
+  free(m);
+  return EXIT_SUCCESS;
+}
+
+
+size_t
+gmp_matrix_rows(const gmp_matrix * m)
+{
+  if(m == NULL)
+    {
+      return 0;
+    }
+
+  return m -> rows;
+}
+
+
+size_t
+gmp_matrix_cols(const gmp_matrix * m)
+{
+  if(m == NULL)
+    {
+      return 0;
+    }
+
+  return m -> cols;
+}
+
+/* elem <- (matrix(row, col)) */
+int
+gmp_matrix_get_elem(mpz_t elem, size_t row, size_t col,
+		    const gmp_matrix * m)
+{
+#ifdef DEBUG
+
+  if(m == NULL)
+    {
+      return EXIT_FAILURE;
+    }
+
+#endif
+
+  mpz_set(elem, m -> storage[(col-1)*(m -> rows)+row-1]);
+  return EXIT_SUCCESS;
+}
+
+/* (matrix(row, col)) <- elem */
+int
+gmp_matrix_set_elem(mpz_t elem, size_t row, size_t col,
+		    const gmp_matrix * m)
+{
+#ifdef DEBUG
+
+  if(m == NULL)
+    {
+      return EXIT_FAILURE;
+    }
+
+#endif
+
+  mpz_set(m -> storage[(col-1)*(m -> rows)+row-1], elem);
+  return EXIT_SUCCESS;
+}
+
+int  
+gmp_matrix_swap_rows(size_t row1, size_t row2, gmp_matrix * m)
+{
+  if(m == NULL)
+    {
+      return EXIT_FAILURE;
+    }
+  if((row1 < 1) || (row1 > m->rows) || (row2 < 1) || (row2 > m->rows))
+    {
+      return EXIT_FAILURE;
+    }
+
+  /* printf("Swapping rows %i %i\n", row1, row2); */
+  gmp_blas_swap(m -> cols,
+		&(m -> storage[row1-1]), m -> rows, 
+		&(m -> storage[row2-1]), m -> rows);
+
+  return EXIT_SUCCESS;
+}
+
+int
+gmp_matrix_swap_cols(size_t col1, size_t col2, gmp_matrix * m)
+{
+  if(m == NULL)
+    {
+      return EXIT_FAILURE;
+    }
+  if((col1 < 1) || (col1 > m->cols) || (col2 < 1) || (col2 > m->cols))
+    {
+      return EXIT_FAILURE;
+    }
+
+  /* printf("Swapping cols %i %i\n", col1, col2); */
+  gmp_blas_swap(m -> rows, 
+		&(m -> storage[(m->rows)*(col1-1)]), 1, 
+		&(m -> storage[(m->rows)*(col2-1)]), 1);
+
+  return EXIT_SUCCESS;
+}
+
+int
+gmp_matrix_negate_row(size_t row, gmp_matrix * m)
+{
+  mpz_t minus_one;
+
+  if(m == NULL)
+    {
+      return EXIT_FAILURE;
+    }
+  if((row < 1) || (row > m->rows))
+    {
+      return EXIT_FAILURE;
+    }
+
+  mpz_init(minus_one);
+  mpz_set_si(minus_one, -1);
+  gmp_blas_scal(m -> cols, minus_one, (&m -> storage[row-1]), m -> rows); 
+  mpz_clear(minus_one);
+  return EXIT_SUCCESS; 
+}
+
+int
+gmp_matrix_negate_col(size_t col, gmp_matrix * m)
+{
+  mpz_t minus_one;
+  if(m == NULL)
+    {
+      return EXIT_FAILURE;
+    }
+  if((col < 1) || (col > m->cols))
+    {
+      return EXIT_FAILURE;
+    }
+  mpz_init(minus_one);
+  mpz_set_si(minus_one, -1);
+  gmp_blas_scal(m -> rows, minus_one, 
+		&(m -> storage[(m->rows)*(col-1)]), 1); 
+  mpz_clear(minus_one);
+  return EXIT_SUCCESS;
+}
+
+/* row2 <- a*row1 + row2*/
+int
+gmp_matrix_add_row(mpz_t a, size_t row1, size_t row2,
+		   gmp_matrix * m)
+{
+  if(m == NULL)
+    {
+      return EXIT_FAILURE;
+    }
+  if((row1 < 1) || (row1 > m->rows) || (row2 < 1) || (row2 > m->rows))
+    {
+      return EXIT_FAILURE;
+    }
+
+  gmp_blas_axpy(m->cols, a, 
+		(mpz_t *) &(m->storage[row1-1]), m->rows, 
+		&(m->storage[row2-1]), m->rows); 
+
+  return EXIT_SUCCESS;
+}
+
+int
+gmp_matrix_add_col(mpz_t a, size_t col1, size_t col2,
+		   gmp_matrix * m)
+{
+  if(m == NULL)
+    {
+      return EXIT_FAILURE;
+    }
+  if((col1 < 1) || (col1 > m->cols) || (col2 < 1) || (col2 > m->cols))
+    {
+      return EXIT_FAILURE;
+    }
+
+  gmp_blas_axpy(m->rows, a, 
+		(mpz_t *) &(m -> storage[(m->rows)*(col1-1)]), 1, 
+		&(m -> storage[(m->rows)*(col2-1)]), 1); 
+
+  return EXIT_SUCCESS;
+}
+
+/* row1 <- a*row1 + b*row2
+   row2 <- c*row1 + d*row2 */
+int
+gmp_matrix_row_rot(mpz_t a, mpz_t b, size_t row1,
+		   mpz_t c, mpz_t d, size_t row2,
+		   gmp_matrix * m)
+{
+  if(m == NULL)
+    {
+      return EXIT_FAILURE;
+    }
+  if((row1 < 1) || (row1 > m->rows) || (row2 < 1) || (row2 > m->rows))
+    {
+      return EXIT_FAILURE;
+    }
+
+  gmp_blas_rot(m->cols, 
+	       a, b, &(m->storage[row1-1]), m->rows, 
+	       c, d, &(m->storage[row2-1]), m->rows); 
+
+  return EXIT_SUCCESS;
+}
+int
+gmp_matrix_col_rot(mpz_t a, mpz_t b, size_t col1,
+		   mpz_t c, mpz_t d, size_t col2,
+		   gmp_matrix * m)
+{
+  if(m == NULL)
+    {
+      return EXIT_FAILURE;
+    }
+  if((col1 < 1) || (col1 > m->cols) || (col2 < 1) || (col2 > m->cols))
+    {
+      return EXIT_FAILURE;
+    }
+
+/*   printf("a: %i b: %i c: %i d:%i col1: %i col2: %i\n", */
+/* 	 mpz_get_si(a), */
+/* 	 mpz_get_si(b), */
+/* 	 mpz_get_si(c), */
+/* 	 mpz_get_si(d), */
+/* 	 col1, col2); */
+
+  gmp_blas_rot(m->rows, 
+	       a, b, &(m -> storage[(m->rows)*(col1-1)]), 1, 
+	       c, d, &(m -> storage[(m->rows)*(col2-1)]), 1); 
+
+  return EXIT_SUCCESS;
+}
+
+size_t
+gmp_matrix_col_inz (size_t r1, size_t r2, size_t c, 
+		    gmp_matrix * m)
+{
+  size_t result;
+
+  if(m == NULL)
+    {
+      return 0;
+    }
+  if((r1 < 1) || (r1 > m->rows) || 
+     (r2 < 1) || (r2 > m->rows) ||
+     (r2 < r1) || (c < 1) || (c > m->cols))
+    {
+      return 0;
+    }
+
+  result = gmp_blas_inz(r2-r1+1, 
+			(mpz_t *) &(m->storage[(c-1)*(m->rows)+r1-1]), 
+			1);
+
+  if(result > r2-r1+1)
+    {
+      return 0;
+    }
+
+  return result;
+}
+
+size_t
+gmp_matrix_row_inz (size_t r, size_t c1, size_t c2, 
+		    gmp_matrix * m)
+{
+  size_t result;
+
+  if(m == NULL)
+    {
+      return 0;
+    }
+  if((r  < 1) || (r  > m->rows) || 
+     (c1 < 1) || (c1 > m->cols) ||
+     (c2 < c1) || (c2 < 1) || (c2 > m->cols))
+    {
+      return 0;
+    }
+
+  result = gmp_blas_inz(c2-c1+1, 
+			(mpz_t *) &(m->storage[(c1-1)*(m->rows)+r-1]), 
+			m->rows);
+
+  if(result > c2-c1+1)
+    {
+      return 0;
+    }
+
+  return result;
+}
+
+
+int
+gmp_matrix_is_diagonal(const gmp_matrix * M)
+{
+  size_t i,j;
+  size_t rows, cols;
+
+  if(M == NULL)
+    {
+      return 0;
+    }
+  
+  rows = M->rows;
+  cols = M->cols;
+
+  for(j = 1; j <= cols; j ++)
+    {
+      for(i = 1; i <= rows; i ++)
+	{
+	  if((mpz_cmp_si(M->storage[(i-1)+(j-1)*rows], 0) != 0) && 
+	     (i != j))
+	    {
+	      return 0;
+	    }
+	}
+    }
+
+  return 1;
+}
+
+
+int
+gmp_matrix_transp(gmp_matrix * M)
+{
+  mpz_t * new_storage;
+  size_t i,j;
+  size_t rows, cols;
+
+  if(M == NULL)
+    {
+      return EXIT_FAILURE;
+    }
+  
+  rows = M->rows;
+  cols = M->cols;
+
+  new_storage = (mpz_t *) calloc(rows*cols, sizeof(mpz_t));
+  if(new_storage == NULL)
+    {
+      return EXIT_FAILURE;
+    }
+
+  if(rows == 1){
+    for(i = 1; i <= cols; i++)
+    {
+      mpz_init_set(new_storage[i-1], 
+		       M-> storage[i-1]);
+	    mpz_clear(M-> storage[i-1]);
+    }
+  } 
+  else if(cols == 1){
+    for(i = 1; i <= rows; i++)
+    {
+      mpz_init_set(new_storage[i-1], 
+		       M-> storage[i-1]);
+	    mpz_clear(M-> storage[i-1]);
+    }
+  }
+  else{
+  for(i = 1; i <= rows; i++)
+    {
+      for(j = 1; j <= cols; j++)
+	{
+	  mpz_init_set(new_storage[(j-1)+(i-1)*cols], 
+		       M-> storage[(i-1)+(j-1)*rows]);
+	  mpz_clear(M-> storage[(i-1)+(j-1)*rows]);
+	}
+    }
+  }
+  
+  free(M->storage);
+
+  M -> storage = new_storage;
+  M -> rows = cols;
+  M -> cols = rows;
+
+  return EXIT_SUCCESS;
+}
+
+
+int
+gmp_matrix_right_mult(gmp_matrix * A, const gmp_matrix * B)
+{
+  mpz_t * new_storage;
+  size_t i,j;
+  size_t rows_A, cols_A, rows_B, cols_B;
+
+  if((A == NULL) || (B == NULL))
+    {
+      return EXIT_FAILURE;
+    }
+  
+  rows_A = A->rows;
+  cols_A = A->cols;
+  rows_B = B->rows;
+  cols_B = B->cols;
+
+  if(cols_A != rows_B)
+    {
+      return EXIT_FAILURE;
+    }
+
+  /* Create new storage for the product */
+  new_storage = (mpz_t *) calloc(rows_A*cols_B, sizeof(mpz_t));
+  if(new_storage == NULL)
+    {
+      return EXIT_FAILURE;
+    }
+
+  /* Compute the product to the storage */
+  for(j = 1; j <= cols_B; j++)
+    {
+      for(i = 1; i <= rows_A; i++)
+	{
+	  mpz_init (new_storage[(i-1)+(j-1)*rows_A]);
+	  gmp_blas_dot(&(new_storage[(i-1)+(j-1)*rows_A]),
+		       cols_A,
+		       (mpz_t *) &(A->storage[i-1]),          rows_A,
+		       (mpz_t *) &(B->storage[(j-1)*rows_B]), 1);
+	}
+    }
+
+  /* Get rid of the old storage */
+  for(i = 1; i <= rows_A*cols_A; i++)
+    {
+      mpz_clear (A->storage[i-1]);
+    }
+  free(A->storage);
+
+  /* Update A */
+  A -> storage = new_storage;
+  A -> cols    = cols_B;
+
+  return EXIT_SUCCESS;
+}
+
+int
+gmp_matrix_left_mult(const gmp_matrix * A, gmp_matrix * B)
+{
+  mpz_t * new_storage;
+  size_t i,j;
+  size_t rows_A, cols_A, rows_B, cols_B;
+
+  if((A == NULL) || (B == NULL))
+    {
+      return EXIT_FAILURE;
+    }
+  
+  rows_A = A->rows;
+  cols_A = A->cols;
+  rows_B = B->rows;
+  cols_B = B->cols;
+
+  if(cols_A != rows_B)
+    {
+      return EXIT_FAILURE;
+    }
+
+  /* Create new storage for the product */
+  new_storage = (mpz_t *) calloc(rows_A*cols_B, sizeof(mpz_t));
+  if(new_storage == NULL)
+    {
+      return EXIT_FAILURE;
+    }
+
+  /* Compute the product to the storage */
+  for(j = 1; j <= cols_B; j++)
+    {
+      for(i = 1; i <= rows_A; i++)
+	{
+	  mpz_init (new_storage[(i-1)+(j-1)*rows_A]);
+	  gmp_blas_dot(&(new_storage[(i-1)+(j-1)*rows_A]),
+		       cols_A,
+		       (mpz_t *) &(A->storage[i-1]),          rows_A,
+		       (mpz_t *) &(B->storage[(j-1)*rows_B]), 1);
+	}
+    }
+
+  /* Get rid of the old storage */
+  for(i = 1; i <= rows_B*cols_B; i++)
+    {
+      mpz_clear (B->storage[i-1]);
+    }
+  free(B->storage);
+
+  /* Update A */
+  B -> storage = new_storage;
+  B -> rows    = rows_A;
+
+  return EXIT_SUCCESS;
+}
+
+
+int gmp_matrix_printf(const gmp_matrix * m)
+{
+
+  mpz_t        outz;
+  size_t rows, cols, i, j;
+
+  if(m == NULL)
+    {
+      return EXIT_FAILURE;
+    }
+
+  rows = m->rows;
+  cols = m->cols;
+  mpz_init(outz);
+  for(i = 1; i <= rows ; i++)
+    {
+      for(j = 1; j <= cols ; j++)
+	{
+	  gmp_matrix_get_elem(outz, i, j, m);
+	  mpz_out_str (stdout, 10, outz);
+	  printf(" ");
+	}
+      printf("\n");
+    }
+
+  mpz_clear(outz);
+
+  return EXIT_SUCCESS;
+}
+
+int gmp_matrix_fprintf(FILE* stream, const gmp_matrix * m)
+{
+  mpz_t        outz;
+  size_t rows, cols, i, j;
+
+  if(m == NULL)
+    {
+      return EXIT_FAILURE;
+    }
+
+  rows = m->rows;
+  cols = m->cols;
+  mpz_init(outz);
+  for(i = 1; i <= rows ; i++)
+    {
+      for(j = 1; j <= cols ; j++)
+	{
+	  gmp_matrix_get_elem(outz, i, j, m);
+	  mpz_out_str (stream, 10, outz);
+	  printf(" ");
+	}
+      printf("\n");
+    }
+
+  mpz_clear(outz);
+
+  return EXIT_SUCCESS;
+}
diff --git a/contrib/kbipack/gmp_matrix.h b/contrib/kbipack/gmp_matrix.h
index ea0c9af66b..931f382803 100644
--- a/contrib/kbipack/gmp_matrix.h
+++ b/contrib/kbipack/gmp_matrix.h
@@ -41,7 +41,7 @@ typedef struct
    responsible for sufficient supply. */
 gmp_matrix * 
 create_gmp_matrix(size_t rows, size_t cols, 
-		  const mpz_t * elems);
+		  mpz_t * elems);
 gmp_matrix * 
 create_gmp_matrix_int(size_t rows, size_t cols, 
 		  const long int * elems);
diff --git a/contrib/kbipack/gmp_matrix_io.cpp b/contrib/kbipack/gmp_matrix_io.cpp
new file mode 100644
index 0000000000..14b0fe3650
--- /dev/null
+++ b/contrib/kbipack/gmp_matrix_io.cpp
@@ -0,0 +1,135 @@
+/*
+  IO-routines for gmp integer matrices in coordinate format.
+
+  Copyright (C) 19.11.2003 Saku Suuriniemi TUT/CEM
+
+  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
+  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+  Saku Suuriniemi, TUT/Electromagetics
+  P.O.Box 692, FIN-33101 Tampere, Finland
+  saku.suuriniemi@tut.fi
+
+  $Id: gmp_matrix_io.c,v 1.1 2009-03-30 14:10:57 matti Exp $
+ */
+
+#include<stdio.h>
+#include<stdlib.h>
+#include<string.h>
+#include "gmp_matrix_io.h"
+
+gmp_matrix * gmp_matrix_read_coord(char* filename)
+{
+  FILE *  p_file;
+  size_t  read_values;
+  size_t  row, col, nrows, ncols, dummy;
+  int     val;
+  char    buffer[1000];
+  gmp_matrix * new_matrix;
+  
+  p_file = fopen(filename, "r");
+  if(p_file == NULL)
+    return NULL;
+
+  /* Matlab and Octave typically include comments on ascii files. */
+  /* They start with # */
+  fgets(buffer, 999, p_file);
+  while(strncmp(buffer, "#",1) == 0)
+    {
+      fgets(buffer, 999, p_file);
+    }
+
+  /* First read the size of the matrix */
+  read_values = sscanf(buffer, "%u %u %u", &nrows, &ncols, &dummy);
+
+  /* Create the matrix */
+  new_matrix = create_gmp_matrix_zero(nrows, ncols);
+  if(new_matrix == NULL)
+    {
+      fclose(p_file);
+      return NULL;
+    }
+
+  /* Read the values to the matrix */
+  while(read_values != EOF)
+    {
+      read_values = fscanf(p_file, "%u %u %i\n", &row, &col, &val);
+      if( (row <= nrows) && (row > 0) && (col <= ncols) && (col > 0) )
+	{
+	  mpz_set_si ( new_matrix->storage[(row-1)+(col-1)*nrows], val );
+	}
+    }
+  fclose(p_file);
+
+  return new_matrix;
+}
+
+int gmp_matrix_write_coord(char* filename, gmp_matrix * M)
+{
+
+  FILE *  p_file;
+  size_t  written_values;
+  size_t  row, col, nrows, ncols, nnz;
+  mpz_t   outz;
+
+  if(M == NULL)
+    {
+      return EXIT_FAILURE;
+    }
+
+  nrows = M->rows;
+  ncols = M->cols;
+
+  p_file = fopen(filename, "w");
+  if(p_file == NULL)
+    return 0;
+
+  nnz = 0;
+  /* Compute the number of nonzeros for coordinate format */
+  mpz_init(outz);
+  for(col = 1; col <= ncols ; col++)
+    {
+      for(row = 1; row <= nrows ; row++)
+	{
+	  gmp_matrix_get_elem(outz, row, col, M);
+	  if( mpz_cmp_si (outz, 0) != 0)
+	    {
+	      nnz++;
+	    }
+	}
+    }
+
+  /* First write the size of the matrix */
+  written_values = fprintf(p_file, "%u %u %u\n", nrows, ncols, nnz);
+
+  /* Write the values to the matrix */
+  for(col = 1; col <= ncols ; col++)
+    {
+      for(row = 1; row <= nrows ; row++)
+	{
+	  gmp_matrix_get_elem(outz, row, col, M);
+	  if( mpz_cmp_si (outz, 0) != 0)
+	    {
+	      fprintf(p_file, "%u %u ", row, col);
+	      mpz_out_str (p_file, 10, outz);
+	      fprintf(p_file, "\n");
+	    }
+	}
+    }
+  mpz_clear(outz);  
+
+  fclose(p_file);
+
+  return EXIT_SUCCESS;
+}
diff --git a/contrib/kbipack/gmp_matrix_io.h b/contrib/kbipack/gmp_matrix_io.h
index 74df3f2ad1..65c23b9bff 100644
--- a/contrib/kbipack/gmp_matrix_io.h
+++ b/contrib/kbipack/gmp_matrix_io.h
@@ -31,7 +31,7 @@
 #include "gmp_matrix.h"
 
 gmp_matrix * gmp_matrix_read_coord(char* filename);
-int          gmp_matrix_write_coord(char* filename, const gmp_matrix * M);
+int          gmp_matrix_write_coord(char* filename, gmp_matrix * M);
 
 
 #endif
diff --git a/contrib/kbipack/gmp_normal_form.cpp b/contrib/kbipack/gmp_normal_form.cpp
new file mode 100644
index 0000000000..42785337e7
--- /dev/null
+++ b/contrib/kbipack/gmp_normal_form.cpp
@@ -0,0 +1,783 @@
+/* 
+   Implementation for integer computation of Hermite and Smith normal 
+   forms of matrices of modest size. 
+
+   Implementation: Dense matrix with GMP-library's mpz_t elements to 
+                   hold huge integers. 
+
+   Algorithm: Kannan - Bachem algorithm with improvement by
+              Chou and Collins. Expects a large number of unit invariant 
+	      factors and takes advantage of them as they appear. 
+
+   References: 
+    [1] Ravindran Kannan, Achim Bachem: 
+        "Polynomial algorithms for computing the Smith and Hermite normal 
+	forms of an integer matrix", 
+	SIAM J. Comput., vol. 8, no. 5, pp. 499-507, 1979.
+    [2] Tsu-Wu J.Chou, George E. Collins: 
+        "Algorithms for the solution of systems of linear Diophantine 
+	equations", 
+	SIAM J. Comput., vol. 11, no. 4, pp. 687-708, 1982.
+    [3] GMP homepage http://www.swox.com/gmp/
+    [4] GNU gmp page http://www.gnu.org/software/gmp/
+
+   Copyright (C) 30.10.2003 Saku Suuriniemi TUT/CEM
+
+   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
+   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+   Saku Suuriniemi, TUT/Electromagetics
+   P.O.Box 692, FIN-33101 Tampere, Finland
+   saku.suuriniemi@tut.fi
+
+   $Id: gmp_normal_form.c,v 1.1 2009-03-30 14:10:57 matti Exp $
+*/
+
+#include<stdlib.h>
+#include"gmp_blas.h"
+#include"gmp_matrix.h"
+#include"gmp_normal_form.h"
+
+
+/* The unaltered matrix and identity left and right factors */
+static gmp_normal_form *
+create_gmp_trivial_normal_form(gmp_matrix * A, 
+			       inverted_flag left_inverted,
+			       inverted_flag right_inverted)
+{
+  size_t rows, cols;
+
+  gmp_normal_form * new_nf;
+  if(A == NULL)
+    {
+      return NULL;
+    }
+
+  new_nf = (gmp_normal_form *) malloc(sizeof(gmp_normal_form));
+  if(new_nf == NULL)
+    {
+      destroy_gmp_matrix(A);
+      return NULL;
+    }
+
+  rows = A -> rows;
+  cols = A -> cols;
+
+  if((rows == 0) || (cols == 0))
+    {
+      destroy_gmp_matrix(A);
+      return NULL;
+    }
+
+  new_nf->left = create_gmp_matrix_identity(rows);
+  if(new_nf->left == NULL)
+    {
+      destroy_gmp_matrix(A);
+      free(new_nf);
+      return NULL;
+    }
+
+  new_nf->right = create_gmp_matrix_identity(cols);
+  if(new_nf->right == NULL)
+    {
+      destroy_gmp_matrix(A);
+      destroy_gmp_matrix(new_nf->left);
+      free(new_nf);
+      return NULL;
+    }
+
+  new_nf -> canonical = A;
+  new_nf -> left_inverted  = left_inverted;
+  new_nf -> right_inverted = right_inverted;
+
+  return new_nf;
+}
+
+static int
+gmp_Hermite_eliminate_step(gmp_matrix * L, gmp_matrix * U, 
+			   size_t col, inverted_flag right_inverted)
+{
+  size_t ind, row_limit;
+  mpz_t  pivot, elem;
+  mpz_t  bez1, bez2, gc_div;
+  mpz_t  cff1, cff2;
+
+  mpz_init(pivot);
+  mpz_init(elem);
+  mpz_init(bez1);
+  mpz_init(bez2);
+  mpz_init(cff1);
+  mpz_init(cff2);
+  mpz_init(gc_div);
+
+  row_limit = (L->rows >= col) ? 
+    col-1 : 
+    L->rows;
+
+  for(ind = 1; ind <= row_limit; ind++)
+    {
+      gmp_matrix_get_elem(elem, ind, col, L);
+
+      /* Eliminate only if nonzero */
+      if(mpz_sgn (elem) != 0)
+	{
+	  gmp_matrix_get_elem(pivot, ind, ind, L);
+
+	  /* Extended Euclid's: 
+	     bez1*pivot+bez2*elem = gc_div */
+	  gmp_blas_rotg(gc_div, bez1, bez2, pivot, elem);
+
+	  /* Make cff1 = -elem/gc_div */
+	  mpz_divexact(cff1, elem,  gc_div);
+	  mpz_neg     (cff1, cff1);
+	  /* Make cff2 = pivot/gc_div */
+	  mpz_divexact(cff2, pivot, gc_div);
+
+	  /* Update the HNF canonical matrix */
+	  gmp_matrix_col_rot(bez1, bez2, ind,
+			     cff1, cff2, col,
+			     L);
+
+	  /* Update the unimodular factor matrix */
+	  if(right_inverted == INVERTED)
+	    {
+	      gmp_matrix_col_rot(bez1, bez2, ind,
+				 cff1, cff2, col,
+				 U);
+	    }
+	  else
+	    {
+
+	      /* [bez1, -elem/gc_div] [pivot/gc_div, elem/gc_div]
+		 [bez2, pivot/gc_div] [-bez2,        bez1       ]  = I_2 */
+	      mpz_neg(cff1, cff1);
+	      mpz_neg(bez2, bez2);
+	      gmp_matrix_row_rot(cff2, cff1, ind,
+				 bez2, bez1, col,
+				 U);
+	    }
+	}
+    }
+  mpz_clear(pivot);
+  mpz_clear(elem);
+  mpz_clear(bez1);
+  mpz_clear(bez2);
+  mpz_clear(cff1);
+  mpz_clear(cff2);
+  mpz_clear(gc_div);
+
+  return EXIT_SUCCESS;
+}
+
+
+
+static int
+gmp_Hermite_reduce_step(gmp_matrix * L,  gmp_matrix * U, 
+			size_t col, inverted_flag right_inverted)
+{
+
+  size_t i, j;
+  mpz_t  pivot, elem;
+  mpz_t  cff;
+
+  mpz_init(pivot);
+  mpz_init(elem);
+  mpz_init(cff);
+
+  if(col > (L->rows))
+    {
+      return EXIT_FAILURE;
+    }
+
+  /*  printf("Col = %i\n", col);
+      printf("L before\n");
+      gmp_matrix_printf(L);*/
+
+  for(j = col-1; j >= 1; j--)
+    {
+      for(i = j+1; i <= col; i++)
+	{
+	  gmp_matrix_get_elem(pivot, i, i, L);
+	  gmp_matrix_get_elem(elem,  i, j, L);
+	  /* printf("   i %i j %i\n",i,j);  */
+
+	  if((mpz_cmpabs(elem, pivot) >= 0) || (mpz_sgn(elem) < 0))
+	    {
+	      /* The objective:
+		  0           <= elem + k*pivot < pivot
+		  -elem       <= k*pivot        < pivot - elem
+		  -elem/pivot <= k              < - elem/pivot + 1
+
+		  Solution:
+		  k = ceil(-elem/pivot)
+	      */
+
+	      /* Make cff = -elem */
+	      mpz_neg    (cff, elem);
+	      mpz_cdiv_q (cff, cff, pivot);
+
+	      /* printf("col %i j %i\n", i, j); 
+		 printf("elem %i k %i pivot %i\n", 
+		 mpz_get_si(elem), 
+		 mpz_get_si(cff), 
+		 mpz_get_si(pivot));*/
+
+
+	      gmp_matrix_add_col(cff, i, j, L);
+
+	      /* Update the unimodular factor matrix */
+	      if(right_inverted == INVERTED)
+		{
+		  gmp_matrix_add_col(cff, i, j, U);
+		}
+
+	      /* [1   0] [ 1   0] = [1 0]
+		 [cff 1] [-cff 1]   [0 1] */
+	      else
+		{
+		  mpz_neg (cff, cff);
+		  gmp_matrix_add_row(cff, j, i, U);
+		}
+
+	      /* printf("\n");
+		 gmp_matrix_printf(L);*/
+
+	    }
+	}
+    }
+
+/*  printf("L after\n"); */
+/*   gmp_matrix_printf(L); */
+
+  mpz_clear(pivot);
+  mpz_clear(elem);
+  mpz_clear(cff);
+  return EXIT_SUCCESS;
+}
+
+
+static int
+gmp_normal_form_make_Hermite(gmp_normal_form * nf)
+{
+  size_t rows, cols;
+  size_t pivot_ind;
+  size_t schur, colind;
+  mpz_t  pivot;
+  gmp_matrix * canonical;
+  gmp_matrix * left;
+  gmp_matrix * right;
+
+  if(nf == NULL)
+    {
+      return EXIT_FAILURE;
+    }
+
+  /* OK, it's safe to get to business */
+  canonical = nf->canonical;
+  left      = nf->left;
+  right     = nf->right;
+  rows      = canonical -> rows;
+  cols      = canonical -> cols;
+
+  mpz_init(pivot);
+
+  /* "schur" denotes where the present Schur complement starts */
+  schur = 1;
+
+  while((schur <= rows) && (schur <= cols))
+    {
+      /* Eliminate a column */
+      if (schur > 1)
+	{
+	  gmp_Hermite_eliminate_step(canonical, right, 
+				     schur, nf->right_inverted);
+	}
+
+      /* Find a pivot */
+      pivot_ind = gmp_matrix_col_inz(schur, rows, schur, canonical);
+
+
+      /* If no nonzeros was found, the column is all zero, hence 
+	 settled with. Permute it to the end and decrement cols. */
+      if(pivot_ind == 0)
+	{
+	  gmp_matrix_swap_cols(schur, cols, canonical);
+
+	  if(nf -> right_inverted == INVERTED)
+	    {
+	      gmp_matrix_swap_cols(schur, cols, right);
+	    }
+	  else
+	    {
+	      gmp_matrix_swap_rows(schur, cols, right);
+	    }
+
+	  cols--;
+
+	  /* When the whole column was zeroed, the diagonal 
+	     elements may have got reduced. Reduce the sub-
+	     diagonals as well*/
+
+	  if(schur > 1)
+	    {
+	      gmp_Hermite_reduce_step (canonical, right, schur-1, 
+				       nf -> right_inverted);
+	    }
+	}
+
+      /* A nonzero pivot was found. Permute it to the diagonal position, 
+	 make it positive, and reduce the off-diagonals. 
+	 The schur complement now starts from the next diagonal. */
+      else
+	{
+	  pivot_ind = schur+pivot_ind-1;
+	  gmp_matrix_swap_rows(schur, pivot_ind, canonical);
+
+	  if(nf->left_inverted == INVERTED)
+	    {
+	      gmp_matrix_swap_rows(schur, pivot_ind, left);
+	    }
+	  else
+	    {
+	      gmp_matrix_swap_cols(schur, pivot_ind, left);
+	    }
+
+	  /* Make the pivot positive */
+	  gmp_matrix_get_elem(pivot, schur, schur, canonical);
+
+	  if(mpz_cmp_si(pivot, 0) < 0)
+	    {
+	      gmp_matrix_negate_col(schur, canonical); 
+
+	      if(nf->right_inverted == INVERTED)
+		{
+		  gmp_matrix_negate_col(schur, right); 
+		}
+	      else
+		{
+		  gmp_matrix_negate_row(schur, right); 
+		}
+	    }
+
+	  /*  Reduce off-diagonals */
+	  gmp_Hermite_reduce_step (canonical, right, schur, nf -> right_inverted);
+
+	  schur++;
+	}
+    }
+
+  /* The Schur complement is now empty. There may still be uneliminated 
+     columns left (in case of a wide matrix) */
+
+  colind = schur;
+  while (colind <= cols)
+    {
+      gmp_Hermite_eliminate_step (canonical, right, colind,  nf->right_inverted);
+      gmp_Hermite_reduce_step    (canonical, right, schur-1, nf->right_inverted);
+      colind++;
+    }
+
+  mpz_clear(pivot);
+
+  return EXIT_SUCCESS;
+}
+
+
+
+gmp_normal_form * 
+create_gmp_Hermite_normal_form(gmp_matrix * A, 
+			       inverted_flag left_inverted,
+			       inverted_flag right_inverted)
+{
+  gmp_normal_form * new_nf;
+
+  if(A == NULL)
+    {
+      return NULL;
+    }
+
+  new_nf = 
+    create_gmp_trivial_normal_form(A, left_inverted, right_inverted);
+
+  if(new_nf == NULL)
+    {
+      /* A has been destroyed already */
+      return NULL;
+    }
+
+  if(gmp_normal_form_make_Hermite(new_nf) != EXIT_SUCCESS)
+    {
+      destroy_gmp_normal_form(new_nf);
+      return NULL;
+    }
+
+  return new_nf;
+}
+
+
+gmp_normal_form *
+create_gmp_Smith_normal_form(gmp_matrix * A,
+			     inverted_flag left_inverted,
+			     inverted_flag right_inverted)
+{
+
+  gmp_normal_form * new_nf;
+  gmp_matrix * canonical;
+  gmp_matrix * elbow;
+  inverted_flag elbow_flag;
+  size_t rows, cols;
+  size_t i, j;
+  size_t subd_ind, row_undivisible;
+  size_t last_ready_row, first_ready_col, ind;
+  mpz_t  pivot;
+  mpz_t  remainder;
+
+  if(A == NULL)
+    {
+      return NULL;
+    }
+
+  new_nf = 
+    create_gmp_trivial_normal_form(A, left_inverted, right_inverted);
+
+  if(new_nf == NULL)
+    {
+      /* A has been destroyed already */
+      return NULL;
+    }
+
+  canonical = new_nf -> canonical;
+  mpz_init(pivot);
+  mpz_init(remainder);
+  rows = canonical->rows;
+  cols = canonical->cols;
+  last_ready_row  = 0;
+  first_ready_col = (cols < rows) ? (cols+1) : (rows+1);
+
+  while(first_ready_col > last_ready_row + 1)
+    {
+      /*******/
+      /* HNF */
+      /*******/
+
+      if(gmp_normal_form_make_Hermite(new_nf) != EXIT_SUCCESS)
+	{
+	  destroy_gmp_normal_form(new_nf);
+	  mpz_clear(pivot);
+	  mpz_clear(remainder);
+	  return NULL;
+	}
+
+#ifdef DEBUG
+      printf("HNF\n");
+      gmp_matrix_printf (new_nf -> left);
+      gmp_matrix_printf (new_nf -> canonical);
+      gmp_matrix_printf (new_nf -> right);
+#endif
+
+      /**********************/
+      /* Find ready columns */
+      /**********************/
+
+      /* If a diagonal entry is zero, so is the corresponding 
+	 column. The zero diagonals always reside in the end. 
+	 Seek until zero diagonal encountered, but stay within the matrix! */
+      ind = 1;
+      while ( (ind < first_ready_col) && 
+	      (mpz_cmp_si(canonical -> storage[(ind-1)+(ind-1)*rows], 0) != 0) 
+	      )	     
+	{
+	  ind ++;
+	}
+      first_ready_col = ind;
+
+      /* Note: The number of ready cols is settled after the first HNF, 
+	 but the check is cheap. */
+
+      /**********************************************/
+      /* Permute unit diagonals such that they lead */
+      /**********************************************/
+
+      /* If the recently computed HNF has ones on the diagonal, their 
+	 corresponding rows are all zero (except the diagonal). 
+	 They are then settled, because the next LHNF kills the elements
+	 on their columns. */
+
+      ind = last_ready_row+1;
+  
+      /* Stay within the nonzero cols of the matrix */
+      while (ind < first_ready_col)
+	{
+	  /* Unit diagonal encountered */
+	  if(mpz_cmp_si ( canonical->storage[(ind-1) + (ind-1)*rows], 
+			  1) == 0)
+	    {
+	      /* If not in the beginning, permute to extend the leading minor 
+		 with unit diagonals */
+	      if(ind != last_ready_row+1)
+		{
+		  gmp_matrix_swap_rows(last_ready_row+1,     ind, 
+				       new_nf -> canonical);
+		  
+		  if(left_inverted == INVERTED)
+		    {
+		      gmp_matrix_swap_rows(last_ready_row+1, ind, 
+					   new_nf -> left);
+		    }
+		  else
+		    {
+		      gmp_matrix_swap_cols(last_ready_row+1, ind, 
+					   new_nf -> left);
+		    }
+		  
+		  gmp_matrix_swap_cols(last_ready_row+1,     ind, 
+				       new_nf -> canonical);
+		  
+		  if(right_inverted == INVERTED)
+		    {
+		      gmp_matrix_swap_cols(last_ready_row+1, ind, 
+					   new_nf -> right);
+		    }
+		  else
+		    {
+		      gmp_matrix_swap_rows(last_ready_row+1, ind, 
+					   new_nf -> right);
+		    }
+		}
+	      last_ready_row ++;
+	    }
+	  ind++;
+	}
+      
+#ifdef DEBUG
+      printf("Leading units\n");
+      gmp_matrix_printf (new_nf -> left);
+      gmp_matrix_printf (new_nf -> canonical);
+      gmp_matrix_printf (new_nf -> right);
+#endif
+
+      /********/
+      /* LHNF */
+      /********/
+
+      /* Extravagant strategy: Compute HNF of an explicit tranpose. */
+
+      /* 1. Transpose everything in the normal form */
+      if(gmp_matrix_transp(canonical) != EXIT_SUCCESS)
+	{
+	  destroy_gmp_normal_form(new_nf);
+	  mpz_clear(pivot);
+	  mpz_clear(remainder);
+	  return NULL;
+	}
+      if(gmp_matrix_transp(new_nf->left) != EXIT_SUCCESS)
+	{
+	  destroy_gmp_normal_form(new_nf);
+	  mpz_clear(pivot);
+	  mpz_clear(remainder);
+	  return NULL;
+	}
+      if(gmp_matrix_transp(new_nf->right) != EXIT_SUCCESS)
+	{
+	  destroy_gmp_normal_form(new_nf);
+	  mpz_clear(pivot);
+	  mpz_clear(remainder);
+	  return NULL;
+	}
+
+      elbow          = new_nf ->left;
+      new_nf ->left  = new_nf ->right;
+      new_nf ->right = elbow;
+      elbow_flag              = new_nf ->left_inverted;
+      new_nf ->left_inverted  = new_nf ->right_inverted;
+      new_nf ->right_inverted = elbow_flag;
+
+      /* 2. Compute HNF of the transpose */
+      if(gmp_normal_form_make_Hermite(new_nf) != EXIT_SUCCESS)
+	{
+	  destroy_gmp_normal_form(new_nf);
+	  mpz_clear(pivot);
+	  mpz_clear(remainder);
+	  return NULL;
+	}
+
+      /* 3. Transpose everything back */
+      if(gmp_matrix_transp(canonical) != EXIT_SUCCESS)
+	{
+	  destroy_gmp_normal_form(new_nf);
+	  mpz_clear(pivot);
+	  mpz_clear(remainder);
+	  return NULL;
+	}
+      if(gmp_matrix_transp(new_nf->left) != EXIT_SUCCESS)
+	{
+	  destroy_gmp_normal_form(new_nf);
+	  mpz_clear(pivot);
+	  mpz_clear(remainder);
+	  return NULL;
+	}
+      if(gmp_matrix_transp(new_nf->right) != EXIT_SUCCESS)
+	{
+	  destroy_gmp_normal_form(new_nf);
+	  mpz_clear(pivot);
+	  mpz_clear(remainder);
+	  return NULL;
+	}
+      elbow          = new_nf ->left;
+      new_nf ->left  = new_nf ->right;
+      new_nf ->right = elbow;
+      elbow_flag              = new_nf ->left_inverted;
+      new_nf ->left_inverted  = new_nf ->right_inverted;
+      new_nf ->right_inverted = elbow_flag;
+
+
+#ifdef DEBUG
+      printf("LHNF\n");
+      gmp_matrix_printf (new_nf -> left);
+      gmp_matrix_printf (new_nf -> canonical);
+      gmp_matrix_printf (new_nf -> right);
+#endif
+
+
+      /*****************************************************/
+      /* Check if more of the leading normal form is ready */
+      /*****************************************************/
+
+      /* The matrix is in LHNF, i.e. it is upper triangular. 
+	 If the row trailing the top left diagonal element is 
+	 zero, the diagonal element may be an invariant factor 
+	 on its final position, and the stage may be ready.
+
+	 The stage may not still be ready: The leading diagonal element 
+	 of D may not divide the rest of the Schur complement. */
+
+      subd_ind = 0;
+      row_undivisible = 0;
+
+      /* Explanation of loop conditions:
+	 1.) No relative primes found from Schur complement
+	 2.) Stay within the Schur complement
+	 3.) If a nonzero is found from the trailing row, the stage is 
+	     definitely not ready */
+      while (row_undivisible == 0 &&   
+	     last_ready_row + 1 < first_ready_col && 
+	     subd_ind == 0)        
+	{
+	  subd_ind = 
+	    gmp_matrix_row_inz(last_ready_row+1,
+			       last_ready_row+2, cols, 
+			       canonical);
+
+	  /* printf("subd_ind %i\n", subd_ind);
+	     printf("last_ready_row %i\n", last_ready_row); */
+      
+	  /* No nonzeros found, the stage may be ready */
+	  if (subd_ind == 0)
+	    {
+	      mpz_set (pivot, 
+		       canonical->storage[(last_ready_row)+
+					  (last_ready_row)*rows]);
+
+	      /* Check whether the pivot divides all elements in the Schur 
+		 complement */
+	      row_undivisible = 0;
+	      for(j = last_ready_row+2; j < first_ready_col; j++)
+		{
+		  for(i = last_ready_row+2; i <= j; i++)
+		    {
+		      mpz_tdiv_r (remainder, 
+				  canonical->storage[(i-1)+
+						     (j-1)*rows], 
+				  pivot);
+		  
+		      if(mpz_cmp_si(remainder, 0) !=0)
+			{
+			  row_undivisible = i;
+			  /* col_undivisible = j; */
+			}
+		    }
+		}
+
+	      /* printf("Row undivisible %i\n", row_undivisible); */
+
+	      /* If a relative prime was found from the Schur complement,  
+		 add that row to the first row of the Schur complement */
+	      if(row_undivisible != 0)
+		{
+		  mpz_set_si (remainder, 1);
+		  gmp_matrix_add_row(remainder, 
+				     row_undivisible, last_ready_row+1, 
+				     canonical);
+
+		  /* [ 1 0] [1 0] = [1 0]
+		     [-1 1] [1 1]   [0 1] */
+
+		  if(left_inverted == INVERTED)
+		    {
+		      gmp_matrix_add_row(remainder, 
+					 row_undivisible, last_ready_row+1, 
+					 new_nf->left);
+		    }
+		  else
+		    {
+		      mpz_neg (remainder, remainder);
+		      gmp_matrix_add_col(remainder, 
+					 last_ready_row+1, row_undivisible,
+					 new_nf->left);
+		    }
+		}
+	      /* The Schur complement is smaller by one again */
+	      else
+		{
+		  last_ready_row++;
+		}
+	    }
+	} 
+    }  /* The main loop ends here */
+  
+  mpz_clear(pivot);
+  mpz_clear(remainder);
+  return new_nf;
+}
+
+int destroy_gmp_normal_form(gmp_normal_form * nf)
+{
+  int status;
+
+  if(nf == NULL)
+    {
+      return EXIT_FAILURE;
+    }
+
+  status = EXIT_SUCCESS;
+  if(destroy_gmp_matrix(nf -> left) == EXIT_FAILURE)
+    {
+      status = EXIT_FAILURE;
+    }
+
+  if(destroy_gmp_matrix(nf -> canonical) == EXIT_FAILURE)
+    {
+      status = EXIT_FAILURE;
+    }
+
+  if(destroy_gmp_matrix(nf -> right) == EXIT_FAILURE)
+    {
+      status = EXIT_FAILURE;      
+    }
+  free(nf);
+
+  return status;
+}
+
+
diff --git a/contrib/kbipack/mpz.cpp b/contrib/kbipack/mpz.cpp
index 3ec1b2a4df..e4658189ec 100755
--- a/contrib/kbipack/mpz.cpp
+++ b/contrib/kbipack/mpz.cpp
@@ -19,7 +19,7 @@
 
 #if ! defined(HAVE_GMP)
 
-#include "GmshMessage.cpp"
+#include "GmshMessage.h"
 #include "limits.h"
 
 void overflow()
-- 
GitLab