diff options
| author | Pasha <pasha@member.fsf.org> | 2023-01-27 00:54:07 +0000 | 
|---|---|---|
| committer | Pasha <pasha@member.fsf.org> | 2023-01-27 00:54:07 +0000 | 
| commit | ef800d4ffafdbde7d7a172ad73bd984b1695c138 (patch) | |
| tree | 920cc189130f1e98f252283fce94851443641a6d /glpk-5.0/src/misc | |
| parent | ec4ae3c2b5cb0e83fb667f14f832ea94f68ef075 (diff) | |
| download | oneapi-ef800d4ffafdbde7d7a172ad73bd984b1695c138.tar.gz oneapi-ef800d4ffafdbde7d7a172ad73bd984b1695c138.tar.bz2 | |
Diffstat (limited to 'glpk-5.0/src/misc')
56 files changed, 10812 insertions, 0 deletions
| diff --git a/glpk-5.0/src/misc/avl.c b/glpk-5.0/src/misc/avl.c new file mode 100644 index 0000000..05ce7fb --- /dev/null +++ b/glpk-5.0/src/misc/avl.c @@ -0,0 +1,403 @@ +/* avl.c (binary search tree) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2000-2013 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "avl.h" +#include "dmp.h" +#include "env.h" + +struct AVL +{     /* AVL tree (Adelson-Velsky & Landis binary search tree) */ +      DMP *pool; +      /* memory pool for allocating nodes */ +      AVLNODE *root; +      /* pointer to the root node */ +      int (*fcmp)(void *info, const void *key1, const void *key2); +      /* application-defined key comparison routine */ +      void *info; +      /* transit pointer passed to the routine fcmp */ +      int size; +      /* the tree size (the total number of nodes) */ +      int height; +      /* the tree height */ +}; + +struct AVLNODE +{     /* node of AVL tree */ +      const void *key; +      /* pointer to the node key (data structure for representing keys +         is supplied by the application) */ +      int rank; +      /* node rank = relative position of the node in its own subtree = +         the number of nodes in the left subtree plus one */ +      int type; +      /* reserved for the application specific information */ +      void *link; +      /* reserved for the application specific information */ +      AVLNODE *up; +      /* pointer to the parent node */ +      short int flag; +      /* node flag: +         0 - this node is the left child of its parent (or this node is +             the root of the tree and has no parent) +         1 - this node is the right child of its parent */ +      short int bal; +      /* node balance = the difference between heights of the right and +         left subtrees: +         -1 - the left subtree is higher than the right one; +          0 - the left and right subtrees have the same height; +         +1 - the left subtree is lower than the right one */ +      AVLNODE *left; +      /* pointer to the root of the left subtree */ +      AVLNODE *right; +      /* pointer to the root of the right subtree */ +}; + +AVL *avl_create_tree(int (*fcmp)(void *info, const void *key1, +      const void *key2), void *info) +{     /* create AVL tree */ +      AVL *tree; +      tree = xmalloc(sizeof(AVL)); +      tree->pool = dmp_create_pool(); +      tree->root = NULL; +      tree->fcmp = fcmp; +      tree->info = info; +      tree->size = 0; +      tree->height = 0; +      return tree; +} + +int avl_strcmp(void *info, const void *key1, const void *key2) +{     /* compare character string keys */ +      xassert(info == info); +      return strcmp(key1, key2); +} + +static AVLNODE *rotate_subtree(AVL *tree, AVLNODE *node); + +AVLNODE *avl_insert_node(AVL *tree, const void *key) +{     /* insert new node into AVL tree */ +      AVLNODE *p, *q, *r; +      short int flag; +      /* find an appropriate point for insertion */ +      p = NULL; q = tree->root; +      while (q != NULL) +      {  p = q; +         if (tree->fcmp(tree->info, key, p->key) <= 0) +         {  flag = 0; +            q = p->left; +            p->rank++; +         } +         else +         {  flag = 1; +            q = p->right; +         } +      } +      /* create new node and insert it into the tree */ +      r = dmp_get_atom(tree->pool, sizeof(AVLNODE)); +      r->key = key; r->type = 0; r->link = NULL; +      r->rank = 1; r->up = p; +      r->flag = (short int)(p == NULL ? 0 : flag); +      r->bal = 0; r->left = NULL; r->right = NULL; +      tree->size++; +      if (p == NULL) +         tree->root = r; +      else +         if (flag == 0) p->left = r; else p->right = r; +      /* go upstairs to the root and correct all subtrees affected by +         insertion */ +      while (p != NULL) +      {  if (flag == 0) +         {  /* the height of the left subtree of [p] is increased */ +            if (p->bal > 0) +            {  p->bal = 0; +               break; +            } +            if (p->bal < 0) +            {  rotate_subtree(tree, p); +               break; +            } +            p->bal = -1; flag = p->flag; p = p->up; +         } +         else +         {  /* the height of the right subtree of [p] is increased */ +            if (p->bal < 0) +            {  p->bal = 0; +               break; +            } +            if (p->bal > 0) +            {  rotate_subtree(tree, p); +               break; +            } +            p->bal = +1; flag = p->flag; p = p->up; +         } +      } +      /* if the root has been reached, the height of the entire tree is +         increased */ +      if (p == NULL) tree->height++; +      return r; +} + +void avl_set_node_type(AVLNODE *node, int type) +{     /* assign the type field of specified node */ +      node->type = type; +      return; +} + +void avl_set_node_link(AVLNODE *node, void *link) +{     /* assign the link field of specified node */ +      node->link = link; +      return; +} + +AVLNODE *avl_find_node(AVL *tree, const void *key) +{     /* find node in AVL tree */ +      AVLNODE *p; +      int c; +      p = tree->root; +      while (p != NULL) +      {  c = tree->fcmp(tree->info, key, p->key); +         if (c == 0) break; +         p = (c < 0 ? p->left : p->right); +      } +      return p; +} + +int avl_get_node_type(AVLNODE *node) +{     /* retrieve the type field of specified node */ +      return node->type; +} + +void *avl_get_node_link(AVLNODE *node) +{     /* retrieve the link field of specified node */ +      return node->link; +} + +static AVLNODE *find_next_node(AVL *tree, AVLNODE *node) +{     /* find next node in AVL tree */ +      AVLNODE *p, *q; +      if (tree->root == NULL) return NULL; +      p = node; +      q = (p == NULL ? tree->root : p->right); +      if (q == NULL) +      {  /* go upstairs from the left subtree */ +         for (;;) +         {  q = p->up; +            if (q == NULL) break; +            if (p->flag == 0) break; +            p = q; +         } +      } +      else +      {  /* go downstairs into the right subtree */ +         for (;;) +         {  p = q->left; +            if (p == NULL) break; +            q = p; +         } +      } +      return q; +} + +void avl_delete_node(AVL *tree, AVLNODE *node) +{     /* delete specified node from AVL tree */ +      AVLNODE *f, *p, *q, *r, *s, *x, *y; +      short int flag; +      p = node; +      /* if both subtrees of the specified node are non-empty, the node +         should be interchanged with the next one, at least one subtree +         of which is always empty */ +      if (p->left == NULL || p->right == NULL) goto skip; +      f = p->up; q = p->left; +      r = find_next_node(tree, p); s = r->right; +      if (p->right == r) +      {  if (f == NULL) +            tree->root = r; +         else +            if (p->flag == 0) f->left = r; else f->right = r; +         r->rank = p->rank; r->up = f; +         r->flag = p->flag; r->bal = p->bal; +         r->left = q; r->right = p; +         q->up = r; +         p->rank = 1; p->up = r; p->flag = 1; +         p->bal = (short int)(s == NULL ? 0 : +1); +         p->left = NULL; p->right = s; +         if (s != NULL) s->up = p; +      } +      else +      {  x = p->right; y = r->up; +         if (f == NULL) +            tree->root = r; +         else +            if (p->flag == 0) f->left = r; else f->right = r; +         r->rank = p->rank; r->up = f; +         r->flag = p->flag; r->bal = p->bal; +         r->left = q; r->right = x; +         q->up = r; x->up = r; y->left = p; +         p->rank = 1; p->up = y; p->flag = 0; +         p->bal = (short int)(s == NULL ? 0 : +1); +         p->left = NULL; p->right = s; +         if (s != NULL) s->up = p; +      } +skip: /* now the specified node [p] has at least one empty subtree; +         go upstairs to the root and adjust the rank field of all nodes +         affected by deletion */ +      q = p; f = q->up; +      while (f != NULL) +      {  if (q->flag == 0) f->rank--; +         q = f; f = q->up; +      } +      /* delete the specified node from the tree */ +      f = p->up; flag = p->flag; +      q = p->left != NULL ? p->left : p->right; +      if (f == NULL) +         tree->root = q; +      else +         if (flag == 0) f->left = q; else f->right = q; +      if (q != NULL) q->up = f, q->flag = flag; +      tree->size--; +      /* go upstairs to the root and correct all subtrees affected by +         deletion */ +      while (f != NULL) +      {  if (flag == 0) +         {  /* the height of the left subtree of [f] is decreased */ +            if (f->bal == 0) +            {  f->bal = +1; +               break; +            } +            if (f->bal < 0) +               f->bal = 0; +            else +            {  f = rotate_subtree(tree, f); +               if (f->bal < 0) break; +            } +            flag = f->flag; f = f->up; +         } +         else +         {  /* the height of the right subtree of [f] is decreased */ +            if (f->bal == 0) +            {  f->bal = -1; +               break; +            } +            if (f->bal > 0) +               f->bal = 0; +            else +            {  f = rotate_subtree(tree, f); +               if (f->bal > 0) break; +            } +            flag = f->flag; f = f->up; +         } +      } +      /* if the root has been reached, the height of the entire tree is +         decreased */ +      if (f == NULL) tree->height--; +      /* returns the deleted node to the memory pool */ +      dmp_free_atom(tree->pool, p, sizeof(AVLNODE)); +      return; +} + +static AVLNODE *rotate_subtree(AVL *tree, AVLNODE *node) +{     /* restore balance of AVL subtree */ +      AVLNODE *f, *p, *q, *r, *x, *y; +      xassert(node != NULL); +      p = node; +      if (p->bal < 0) +      {  /* perform negative (left) rotation */ +         f = p->up; q = p->left; r = q->right; +         if (q->bal <= 0) +         {  /* perform single negative rotation */ +            if (f == NULL) +               tree->root = q; +            else +               if (p->flag == 0) f->left = q; else f->right = q; +            p->rank -= q->rank; +            q->up = f; q->flag = p->flag; q->bal++; q->right = p; +            p->up = q; p->flag = 1; +            p->bal = (short int)(-q->bal); p->left = r; +            if (r != NULL) r->up = p, r->flag = 0; +            node = q; +         } +         else +         {  /* perform double negative rotation */ +            x = r->left; y = r->right; +            if (f == NULL) +               tree->root = r; +            else +               if (p->flag == 0) f->left = r; else f->right = r; +            p->rank -= (q->rank + r->rank); +            r->rank += q->rank; +            p->bal = (short int)(r->bal >= 0 ? 0 : +1); +            q->bal = (short int)(r->bal <= 0 ? 0 : -1); +            r->up = f; r->flag = p->flag; r->bal = 0; +            r->left = q; r->right = p; +            p->up = r; p->flag = 1; p->left = y; +            q->up = r; q->flag = 0; q->right = x; +            if (x != NULL) x->up = q, x->flag = 1; +            if (y != NULL) y->up = p, y->flag = 0; +            node = r; +         } +      } +      else +      {  /* perform positive (right) rotation */ +         f = p->up; q = p->right; r = q->left; +         if (q->bal >= 0) +         {  /* perform single positive rotation */ +            if (f == NULL) +               tree->root = q; +            else +               if (p->flag == 0) f->left = q; else f->right = q; +            q->rank += p->rank; +            q->up = f; q->flag = p->flag; q->bal--; q->left = p; +            p->up = q; p->flag = 0; +            p->bal = (short int)(-q->bal); p->right = r; +            if (r != NULL) r->up = p, r->flag = 1; +            node = q; +         } +         else +         {  /* perform double positive rotation */ +            x = r->left; y = r->right; +            if (f == NULL) +               tree->root = r; +            else +               if (p->flag == 0) f->left = r; else f->right = r; +            q->rank -= r->rank; +            r->rank += p->rank; +            p->bal = (short int)(r->bal <= 0 ? 0 : -1); +            q->bal = (short int)(r->bal >= 0 ? 0 : +1); +            r->up = f; r->flag = p->flag; r->bal = 0; +            r->left = p; r->right = q; +            p->up = r; p->flag = 0; p->right = x; +            q->up = r; q->flag = 1; q->left = y; +            if (x != NULL) x->up = p, x->flag = 1; +            if (y != NULL) y->up = q, y->flag = 0; +            node = r; +         } +      } +      return node; +} + +void avl_delete_tree(AVL *tree) +{     /* delete AVL tree */ +      dmp_delete_pool(tree->pool); +      xfree(tree); +      return; +} + +/* eof */ diff --git a/glpk-5.0/src/misc/avl.h b/glpk-5.0/src/misc/avl.h new file mode 100644 index 0000000..7f45963 --- /dev/null +++ b/glpk-5.0/src/misc/avl.h @@ -0,0 +1,71 @@ +/* avl.h (binary search tree) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2000-2013 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#ifndef AVL_H +#define AVL_H + +typedef struct AVL AVL; +typedef struct AVLNODE AVLNODE; + +#define avl_create_tree _glp_avl_create_tree +AVL *avl_create_tree(int (*fcmp)(void *info, const void *key1, +      const void *key2), void *info); +/* create AVL tree */ + +#define avl_strcmp _glp_avl_strcmp +int avl_strcmp(void *info, const void *key1, const void *key2); +/* compare character string keys */ + +#define avl_insert_node _glp_avl_insert_node +AVLNODE *avl_insert_node(AVL *tree, const void *key); +/* insert new node into AVL tree */ + +#define avl_set_node_type _glp_avl_set_node_type +void avl_set_node_type(AVLNODE *node, int type); +/* assign the type field of specified node */ + +#define avl_set_node_link _glp_avl_set_node_link +void avl_set_node_link(AVLNODE *node, void *link); +/* assign the link field of specified node */ + +#define avl_find_node _glp_avl_find_node +AVLNODE *avl_find_node(AVL *tree, const void *key); +/* find node in AVL tree */ + +#define avl_get_node_type _glp_avl_get_node_type +int avl_get_node_type(AVLNODE *node); +/* retrieve the type field of specified node */ + +#define avl_get_node_link _glp_avl_get_node_link +void *avl_get_node_link(AVLNODE *node); +/* retrieve the link field of specified node */ + +#define avl_delete_node _glp_avl_delete_node +void avl_delete_node(AVL *tree, AVLNODE *node); +/* delete specified node from AVL tree */ + +#define avl_delete_tree _glp_avl_delete_tree +void avl_delete_tree(AVL *tree); +/* delete AVL tree */ + +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/bignum.c b/glpk-5.0/src/misc/bignum.c new file mode 100644 index 0000000..1d29a82 --- /dev/null +++ b/glpk-5.0/src/misc/bignum.c @@ -0,0 +1,284 @@ +/* bignum.c (bignum arithmetic) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2006-2013 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "bignum.h" + +/*********************************************************************** +*  Two routines below are intended to multiply and divide unsigned +*  integer numbers of arbitrary precision. +* +*  The routines assume that an unsigned integer number is represented in +*  the positional numeral system with the base 2^16 = 65536, i.e. each +*  "digit" of the number is in the range [0, 65535] and represented as +*  a 16-bit value of the unsigned short type. In other words, a number x +*  has the following representation: +* +*         n-1 +*     x = sum d[j] * 65536^j, +*         j=0 +* +*  where n is the number of places (positions), and d[j] is j-th "digit" +*  of x, 0 <= d[j] <= 65535. +***********************************************************************/ + +/*********************************************************************** +*  NAME +* +*  bigmul - multiply unsigned integer numbers of arbitrary precision +* +*  SYNOPSIS +* +*  #include "bignum.h" +*  void bigmul(int n, int m, unsigned short x[], unsigned short y[]); +* +*  DESCRIPTION +* +*  The routine bigmul multiplies unsigned integer numbers of arbitrary +*  precision. +* +*  n is the number of digits of multiplicand, n >= 1; +* +*  m is the number of digits of multiplier, m >= 1; +* +*  x is an array containing digits of the multiplicand in elements +*  x[m], x[m+1], ..., x[n+m-1]. Contents of x[0], x[1], ..., x[m-1] are +*  ignored on entry. +* +*  y is an array containing digits of the multiplier in elements y[0], +*  y[1], ..., y[m-1]. +* +*  On exit digits of the product are stored in elements x[0], x[1], ..., +*  x[n+m-1]. The array y is not changed. */ + +void bigmul(int n, int m, unsigned short x[], unsigned short y[]) +{     int i, j; +      unsigned int t; +      xassert(n >= 1); +      xassert(m >= 1); +      for (j = 0; j < m; j++) x[j] = 0; +      for (i = 0; i < n; i++) +      {  if (x[i+m]) +         {  t = 0; +            for (j = 0; j < m; j++) +            {  t += (unsigned int)x[i+m] * (unsigned int)y[j] + +                    (unsigned int)x[i+j]; +               x[i+j] = (unsigned short)t; +               t >>= 16; +            } +            x[i+m] = (unsigned short)t; +         } +      } +      return; +} + +/*********************************************************************** +*  NAME +* +*  bigdiv - divide unsigned integer numbers of arbitrary precision +* +*  SYNOPSIS +* +*  #include "bignum.h" +*  void bigdiv(int n, int m, unsigned short x[], unsigned short y[]); +* +*  DESCRIPTION +* +*  The routine bigdiv divides one unsigned integer number of arbitrary +*  precision by another with the algorithm described in [1]. +* +*  n is the difference between the number of digits of dividend and the +*  number of digits of divisor, n >= 0. +* +*  m is the number of digits of divisor, m >= 1. +* +*  x is an array containing digits of the dividend in elements x[0], +*  x[1], ..., x[n+m-1]. +* +*  y is an array containing digits of the divisor in elements y[0], +*  y[1], ..., y[m-1]. The highest digit y[m-1] must be non-zero. +* +*  On exit n+1 digits of the quotient are stored in elements x[m], +*  x[m+1], ..., x[n+m], and m digits of the remainder are stored in +*  elements x[0], x[1], ..., x[m-1]. The array y is changed but then +*  restored. +* +*  REFERENCES +* +*  1. D. Knuth. The Art of Computer Programming. Vol. 2: Seminumerical +*  Algorithms. Stanford University, 1969. */ + +void bigdiv(int n, int m, unsigned short x[], unsigned short y[]) +{     int i, j; +      unsigned int t; +      unsigned short d, q, r; +      xassert(n >= 0); +      xassert(m >= 1); +      xassert(y[m-1] != 0); +      /* special case when divisor has the only digit */ +      if (m == 1) +      {  d = 0; +         for (i = n; i >= 0; i--) +         {  t = ((unsigned int)d << 16) + (unsigned int)x[i]; +            x[i+1] = (unsigned short)(t / y[0]); +            d = (unsigned short)(t % y[0]); +         } +         x[0] = d; +         goto done; +      } +      /* multiply dividend and divisor by a normalizing coefficient in +       * order to provide the condition y[m-1] >= base / 2 */ +      d = (unsigned short)(0x10000 / ((unsigned int)y[m-1] + 1)); +      if (d == 1) +         x[n+m] = 0; +      else +      {  t = 0; +         for (i = 0; i < n+m; i++) +         {  t += (unsigned int)x[i] * (unsigned int)d; +            x[i] = (unsigned short)t; +            t >>= 16; +         } +         x[n+m] = (unsigned short)t; +         t = 0; +         for (j = 0; j < m; j++) +         {  t += (unsigned int)y[j] * (unsigned int)d; +            y[j] = (unsigned short)t; +            t >>= 16; +         } +      } +      /* main loop */ +      for (i = n; i >= 0; i--) +      {  /* estimate and correct the current digit of quotient */ +         if (x[i+m] < y[m-1]) +         {  t = ((unsigned int)x[i+m] << 16) + (unsigned int)x[i+m-1]; +            q = (unsigned short)(t / (unsigned int)y[m-1]); +            r = (unsigned short)(t % (unsigned int)y[m-1]); +            if (q == 0) goto putq; else goto test; +         } +         q = 0; +         r = x[i+m-1]; +decr:    q--; /* if q = 0 then q-- = 0xFFFF */ +         t = (unsigned int)r + (unsigned int)y[m-1]; +         r = (unsigned short)t; +         if (t > 0xFFFF) goto msub; +test:    t = (unsigned int)y[m-2] * (unsigned int)q; +         if ((unsigned short)(t >> 16) > r) goto decr; +         if ((unsigned short)(t >> 16) < r) goto msub; +         if ((unsigned short)t > x[i+m-2]) goto decr; +msub:    /* now subtract divisor multiplied by the current digit of +          * quotient from the current dividend */ +         if (q == 0) goto putq; +         t = 0; +         for (j = 0; j < m; j++) +         {  t += (unsigned int)y[j] * (unsigned int)q; +            if (x[i+j] < (unsigned short)t) t += 0x10000; +            x[i+j] -= (unsigned short)t; +            t >>= 16; +         } +         if (x[i+m] >= (unsigned short)t) goto putq; +         /* perform correcting addition, because the current digit of +          * quotient is greater by one than its correct value */ +         q--; +         t = 0; +         for (j = 0; j < m; j++) +         {  t += (unsigned int)x[i+j] + (unsigned int)y[j]; +            x[i+j] = (unsigned short)t; +            t >>= 16; +         } +putq:    /* store the current digit of quotient */ +         x[i+m] = q; +      } +      /* divide divisor and remainder by the normalizing coefficient in +       * order to restore their original values */ +      if (d > 1) +      {  t = 0; +         for (i = m-1; i >= 0; i--) +         {  t = (t << 16) + (unsigned int)x[i]; +            x[i] = (unsigned short)(t / (unsigned int)d); +            t %= (unsigned int)d; +         } +         t = 0; +         for (j = m-1; j >= 0; j--) +         {  t = (t << 16) + (unsigned int)y[j]; +            y[j] = (unsigned short)(t / (unsigned int)d); +            t %= (unsigned int)d; +         } +      } +done: return; +} + +/**********************************************************************/ + +#ifdef GLP_TEST +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include "rng.h" + +#define N_MAX 7 +/* maximal number of digits in multiplicand */ + +#define M_MAX 5 +/* maximal number of digits in multiplier */ + +#define N_TEST 1000000 +/* number of tests */ + +int main(void) +{     RNG *rand; +      int d, j, n, m, test; +      unsigned short x[N_MAX], y[M_MAX], z[N_MAX+M_MAX]; +      rand = rng_create_rand(); +      for (test = 1; test <= N_TEST; test++) +      {  /* x[0,...,n-1] := multiplicand */ +         n = 1 + rng_unif_rand(rand, N_MAX-1); +         assert(1 <= n && n <= N_MAX); +         for (j = 0; j < n; j++) +         {  d = rng_unif_rand(rand, 65536); +            assert(0 <= d && d <= 65535); +            x[j] = (unsigned short)d; +         } +         /* y[0,...,m-1] := multiplier */ +         m = 1 + rng_unif_rand(rand, M_MAX-1); +         assert(1 <= m && m <= M_MAX); +         for (j = 0; j < m; j++) +         {  d = rng_unif_rand(rand, 65536); +            assert(0 <= d && d <= 65535); +            y[j] = (unsigned short)d; +         } +         if (y[m-1] == 0) y[m-1] = 1; +         /* z[0,...,n+m-1] := x * y */ +         for (j = 0; j < n; j++) z[m+j] = x[j]; +         bigmul(n, m, z, y); +         /* z[0,...,m-1] := z mod y, z[m,...,n+m-1] := z div y */ +         bigdiv(n, m, z, y); +         /* z mod y must be 0 */ +         for (j = 0; j < m; j++) assert(z[j] == 0); +         /* z div y must be x */ +         for (j = 0; j < n; j++) assert(z[m+j] == x[j]); +      } +      fprintf(stderr, "%d tests successfully passed\n", N_TEST); +      rng_delete_rand(rand); +      return 0; +} +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/bignum.h b/glpk-5.0/src/misc/bignum.h new file mode 100644 index 0000000..2e19e3a --- /dev/null +++ b/glpk-5.0/src/misc/bignum.h @@ -0,0 +1,35 @@ +/* bignum.h (bignum arithmetic) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2006-2013 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#ifndef BIGNUM_H +#define BIGNUM_H + +#define bigmul _glp_bigmul +void bigmul(int n, int m, unsigned short x[], unsigned short y[]); +/* multiply unsigned integer numbers of arbitrary precision */ + +#define bigdiv _glp_bigdiv +void bigdiv(int n, int m, unsigned short x[], unsigned short y[]); +/* divide unsigned integer numbers of arbitrary precision */ + +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/dimacs.c b/glpk-5.0/src/misc/dimacs.c new file mode 100644 index 0000000..66dfbb9 --- /dev/null +++ b/glpk-5.0/src/misc/dimacs.c @@ -0,0 +1,145 @@ +/* dimacs.c (reading data in DIMACS format) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2015 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "dimacs.h" + +void dmx_error(DMX *csa, const char *fmt, ...) +{     /* print error message and terminate processing */ +      va_list arg; +      xprintf("%s:%d: error: ", csa->fname, csa->count); +      va_start(arg, fmt); +      xvprintf(fmt, arg); +      va_end(arg); +      xprintf("\n"); +      longjmp(csa->jump, 1); +      /* no return */ +} + +void dmx_warning(DMX *csa, const char *fmt, ...) +{     /* print warning message and continue processing */ +      va_list arg; +      xprintf("%s:%d: warning: ", csa->fname, csa->count); +      va_start(arg, fmt); +      xvprintf(fmt, arg); +      va_end(arg); +      xprintf("\n"); +      return; +} + +void dmx_read_char(DMX *csa) +{     /* read character from input text file */ +      int c; +      if (csa->c == '\n') csa->count++; +      c = glp_getc(csa->fp); +      if (c < 0) +      {  if (glp_ioerr(csa->fp)) +            dmx_error(csa, "read error - %s", get_err_msg()); +         else if (csa->c == '\n') +            dmx_error(csa, "unexpected end of file"); +         else +         {  dmx_warning(csa, "missing final end of line"); +            c = '\n'; +         } +      } +      else if (c == '\n') +         ; +      else if (isspace(c)) +         c = ' '; +      else if (iscntrl(c)) +         dmx_error(csa, "invalid control character 0x%02X", c); +      csa->c = c; +      return; +} + +void dmx_read_designator(DMX *csa) +{     /* read one-character line designator */ +      xassert(csa->c == '\n'); +      dmx_read_char(csa); +      for (;;) +      {  /* skip preceding white-space characters */ +         while (csa->c == ' ') +            dmx_read_char(csa); +         if (csa->c == '\n') +         {  /* ignore empty line */ +            if (!csa->empty) +            {  dmx_warning(csa, "empty line ignored"); +               csa->empty = 1; +            } +            dmx_read_char(csa); +         } +         else if (csa->c == 'c') +         {  /* skip comment line */ +            while (csa->c != '\n') +               dmx_read_char(csa); +            dmx_read_char(csa); +         } +         else +         {  /* hmm... looks like a line designator */ +            csa->field[0] = (char)csa->c, csa->field[1] = '\0'; +            /* check that it is followed by a white-space character */ +            dmx_read_char(csa); +            if (!(csa->c == ' ' || csa->c == '\n')) +               dmx_error(csa, "line designator missing or invalid"); +            break; +         } +      } +      return; +} + +void dmx_read_field(DMX *csa) +{     /* read data field */ +      int len = 0; +      /* skip preceding white-space characters */ +      while (csa->c == ' ') +         dmx_read_char(csa); +      /* scan data field */ +      if (csa->c == '\n') +         dmx_error(csa, "unexpected end of line"); +      while (!(csa->c == ' ' || csa->c == '\n')) +      {  if (len == sizeof(csa->field)-1) +            dmx_error(csa, "data field '%.15s...' too long", +               csa->field); +         csa->field[len++] = (char)csa->c; +         dmx_read_char(csa); +      } +      csa->field[len] = '\0'; +      return; +} + +void dmx_end_of_line(DMX *csa) +{     /* skip white-space characters until end of line */ +      while (csa->c == ' ') +         dmx_read_char(csa); +      if (csa->c != '\n') +         dmx_error(csa, "too many data fields specified"); +      return; +} + +void dmx_check_int(DMX *csa, double num) +{     /* print a warning if non-integer data are detected */ +      if (!csa->nonint && num != floor(num)) +      {  dmx_warning(csa, "non-integer data detected"); +         csa->nonint = 1; +      } +      return; +} + +/* eof */ diff --git a/glpk-5.0/src/misc/dimacs.h b/glpk-5.0/src/misc/dimacs.h new file mode 100644 index 0000000..2c86b28 --- /dev/null +++ b/glpk-5.0/src/misc/dimacs.h @@ -0,0 +1,79 @@ +/* dimacs.h (reading data in DIMACS format) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2015 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#ifndef DIMACS_H +#define DIMACS_H + +#include "env.h" + +typedef struct DMX DMX; + +struct DMX +{     /* DIMACS data reader */ +      jmp_buf jump; +      /* label for go to in case of error */ +      const char *fname; +      /* name of input text file */ +      glp_file *fp; +      /* stream assigned to input text file */ +      int count; +      /* line count */ +      int c; +      /* current character */ +      char field[255+1]; +      /* data field */ +      int empty; +      /* warning 'empty line ignored' was printed */ +      int nonint; +      /* warning 'non-integer data detected' was printed */ +}; + +#define dmx_error _glp_dmx_error +void dmx_error(DMX *csa, const char *fmt, ...); +/* print error message and terminate processing */ + +#define dmx_warning _glp_dmx_warning +void dmx_warning(DMX *csa, const char *fmt, ...); +/* print warning message and continue processing */ + +#define dmx_read_char _glp_dmx_read_char +void dmx_read_char(DMX *csa); +/* read character from input text file */ + +#define dmx_read_designator _glp_dmx_read_designator +void dmx_read_designator(DMX *csa); +/* read one-character line designator */ + +#define dmx_read_field _glp_dmx_read_field +void dmx_read_field(DMX *csa); +/* read data field */ + +#define dmx_end_of_line _glp_dmx_end_of_line +void dmx_end_of_line(DMX *csa); +/* skip white-space characters until end of line */ + +#define dmx_check_int _glp_dmx_check_int +void dmx_check_int(DMX *csa, double num); +/* print a warning if non-integer data are detected */ + +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/dmp.c b/glpk-5.0/src/misc/dmp.c new file mode 100644 index 0000000..bfaf642 --- /dev/null +++ b/glpk-5.0/src/misc/dmp.c @@ -0,0 +1,241 @@ +/* dmp.c (dynamic memory pool) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2000-2013 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "dmp.h" + +struct DMP +{     /* dynamic memory pool */ +      void *avail[32]; +      /* avail[k], 0 <= k <= 31, is a pointer to first available (free) +       * atom of (k+1)*8 bytes long; at the beginning of each free atom +       * there is a pointer to another free atom of the same size */ +      void *block; +      /* pointer to most recently allocated memory block; at the +       * beginning of each allocated memory block there is a pointer to +       * previously allocated memory block */ +      int used; +      /* number of bytes used in most recently allocated memory block */ +      size_t count; +      /* number of atoms which are currently in use */ +}; + +#define DMP_BLK_SIZE 8000 +/* size of memory blocks, in bytes, allocated for memory pools */ + +struct prefix +{     /* atom prefix (for debugging only) */ +      DMP *pool; +      /* dynamic memory pool */ +      int size; +      /* original atom size, in bytes */ +}; + +#define prefix_size ((sizeof(struct prefix) + 7) & ~7) +/* size of atom prefix rounded up to multiple of 8 bytes */ + +int dmp_debug; +/* debug mode flag */ + +/*********************************************************************** +*  NAME +* +*  dmp_create_pool - create dynamic memory pool +* +*  SYNOPSIS +* +*  #include "dmp.h" +*  DMP *dmp_create_pool(void); +* +*  DESCRIPTION +* +*  The routine dmp_create_pool creates a dynamic memory pool. +* +*  RETURNS +* +*  The routine returns a pointer to the memory pool created. */ + +DMP *dmp_create_pool(void) +{     DMP *pool; +      int k; +      xassert(sizeof(void *) <= 8); +      if (dmp_debug) +         xprintf("dmp_create_pool: warning: debug mode is on\n"); +      pool = talloc(1, DMP); +      for (k = 0; k <= 31; k++) +         pool->avail[k] = NULL; +      pool->block = NULL; +      pool->used = DMP_BLK_SIZE; +      pool->count = 0; +      return pool; +} + +/*********************************************************************** +*  NAME +* +*  dmp_get_atom - get free atom from dynamic memory pool +* +*  SYNOPSIS +* +*  #include "dmp.h" +*  void *dmp_get_atom(DMP *pool, int size); +* +*  DESCRIPTION +* +*  The routine dmp_get_atom obtains a free atom (memory space) from the +*  specified memory pool. +* +*  The parameter size is the atom size, in bytes, 1 <= size <= 256. +* +*  Note that the free atom contains arbitrary data, not binary zeros. +* +*  RETURNS +* +*  The routine returns a pointer to the free atom obtained. */ + +void *dmp_get_atom(DMP *pool, int size) +{     void *atom; +      int k, need; +      xassert(1 <= size && size <= 256); +      /* round up atom size to multiple of 8 bytes */ +      need = (size + 7) & ~7; +      /* determine number of corresponding list of free atoms */ +      k = (need >> 3) - 1; +      /* obtain free atom */ +      if (pool->avail[k] == NULL) +      {  /* corresponding list of free atoms is empty */ +         /* if debug mode is on, add atom prefix size */ +         if (dmp_debug) +            need += prefix_size; +         if (pool->used + need > DMP_BLK_SIZE) +         {  /* allocate new memory block */ +            void *block = talloc(DMP_BLK_SIZE, char); +            *(void **)block = pool->block; +            pool->block = block; +            pool->used = 8; /* sufficient to store pointer */ +         } +         /* allocate new atom in current memory block */ +         atom = (char *)pool->block + pool->used; +         pool->used += need; +      } +      else +      {  /* obtain atom from corresponding list of free atoms */ +         atom  = pool->avail[k]; +         pool->avail[k] = *(void **)atom; +      } +      /* if debug mode is on, fill atom prefix */ +      if (dmp_debug) +      {  ((struct prefix *)atom)->pool = pool; +         ((struct prefix *)atom)->size = size; +         atom = (char *)atom + prefix_size; +      } +      /* increase number of allocated atoms */ +      pool->count++; +      return atom; +} + +/*********************************************************************** +*  NAME +* +*  dmp_free_atom - return atom to dynamic memory pool +* +*  SYNOPSIS +* +*  #include "dmp.h" +*  void dmp_free_atom(DMP *pool, void *atom, int size); +* +*  DESCRIPTION +* +*  The routine dmp_free_atom returns the specified atom (memory space) +*  to the specified memory pool, making the atom free. +* +*  The parameter size is the atom size, in bytes, 1 <= size <= 256. +* +*  Note that the atom can be returned only to the pool, from which it +*  was obtained, and its size must be exactly the same as on obtaining +*  it from the pool. */ + +void dmp_free_atom(DMP *pool, void *atom, int size) +{     int k; +      xassert(1 <= size && size <= 256); +      /* determine number of corresponding list of free atoms */ +      k = ((size + 7) >> 3) - 1; +      /* if debug mode is on, check atom prefix */ +      if (dmp_debug) +      {  atom = (char *)atom - prefix_size; +         xassert(((struct prefix *)atom)->pool == pool); +         xassert(((struct prefix *)atom)->size == size); +      } +      /* return atom to corresponding list of free atoms */ +      *(void **)atom = pool->avail[k]; +      pool->avail[k] = atom; +      /* decrease number of allocated atoms */ +      xassert(pool->count > 0); +      pool->count--; +      return; +} + +/*********************************************************************** +*  NAME +* +*  dmp_in_use - determine how many atoms are still in use +* +*  SYNOPSIS +* +*  #include "dmp.h" +*  size_t dmp_in_use(DMP *pool); +* +*  RETURNS +* +*  The routine returns the number of atoms of the specified memory pool +*  which are still in use. */ + +size_t dmp_in_use(DMP *pool) +{     return +         pool->count; +} + +/*********************************************************************** +*  NAME +* +*  dmp_delete_pool - delete dynamic memory pool +* +*  SYNOPSIS +* +*  #include "dmp.h" +*  void dmp_delete_pool(DMP *pool); +* +*  DESCRIPTION +* +*  The routine dmp_delete_pool deletes the specified dynamic memory +*  pool freeing all the memory allocated to this object. */ + +void dmp_delete_pool(DMP *pool) +{     while (pool->block != NULL) +      {  void *block = pool->block; +         pool->block = *(void **)block; +         tfree(block); +      } +      tfree(pool); +      return; +} + +/* eof */ diff --git a/glpk-5.0/src/misc/dmp.h b/glpk-5.0/src/misc/dmp.h new file mode 100644 index 0000000..cde0991 --- /dev/null +++ b/glpk-5.0/src/misc/dmp.h @@ -0,0 +1,61 @@ +/* dmp.h (dynamic memory pool) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2000-2013 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#ifndef DMP_H +#define DMP_H + +#include "stdc.h" + +typedef struct DMP DMP; + +#define dmp_debug _glp_dmp_debug +extern int dmp_debug; +/* debug mode flag */ + +#define dmp_create_pool _glp_dmp_create_pool +DMP *dmp_create_pool(void); +/* create dynamic memory pool */ + +#define dmp_talloc(pool, type) \ +      ((type *)dmp_get_atom(pool, sizeof(type))) + +#define dmp_get_atom _glp_dmp_get_atom +void *dmp_get_atom(DMP *pool, int size); +/* get free atom from dynamic memory pool */ + +#define dmp_tfree(pool, atom) \ +      dmp_free_atom(pool, atom, sizeof(*(atom))) + +#define dmp_free_atom _glp_dmp_free_atom +void dmp_free_atom(DMP *pool, void *atom, int size); +/* return atom to dynamic memory pool */ + +#define dmp_in_use _glp_dmp_in_use +size_t dmp_in_use(DMP *pool); +/* determine how many atoms are still in use */ + +#define dmp_delete_pool _glp_dmp_delete_pool +void dmp_delete_pool(DMP *pool); +/* delete dynamic memory pool */ + +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/ffalg.c b/glpk-5.0/src/misc/ffalg.c new file mode 100644 index 0000000..bf3ed0c --- /dev/null +++ b/glpk-5.0/src/misc/ffalg.c @@ -0,0 +1,219 @@ +/* ffalg.c (Ford-Fulkerson algorithm) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2013 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "ffalg.h" + +/*********************************************************************** +*  NAME +* +*  ffalg - Ford-Fulkerson algorithm +* +*  SYNOPSIS +* +*  #include "ffalg.h" +*  void ffalg(int nv, int na, const int tail[], const int head[], +*     int s, int t, const int cap[], int x[], char cut[]); +* +*  DESCRIPTION +* +*  The routine ffalg implements the Ford-Fulkerson algorithm to find a +*  maximal flow in the specified flow network. +* +*  INPUT PARAMETERS +* +*  nv is the number of nodes, nv >= 2. +* +*  na is the number of arcs, na >= 0. +* +*  tail[a], a = 1,...,na, is the index of tail node of arc a. +* +*  head[a], a = 1,...,na, is the index of head node of arc a. +* +*  s is the source node index, 1 <= s <= nv. +* +*  t is the sink node index, 1 <= t <= nv, t != s. +* +*  cap[a], a = 1,...,na, is the capacity of arc a, cap[a] >= 0. +* +*  NOTE: Multiple arcs are allowed, but self-loops are not allowed. +* +*  OUTPUT PARAMETERS +* +*  x[a], a = 1,...,na, is optimal value of the flow through arc a. +* +*  cut[i], i = 1,...,nv, is 1 if node i is labelled, and 0 otherwise. +*  The set of arcs, whose one endpoint is labelled and other is not, +*  defines the minimal cut corresponding to the maximal flow found. +*  If the parameter cut is NULL, the cut information are not stored. +* +*  REFERENCES +* +*  L.R.Ford, Jr., and D.R.Fulkerson, "Flows in Networks," The RAND +*  Corp., Report R-375-PR (August 1962), Chap. I "Static Maximal Flow," +*  pp.30-33. */ + +void ffalg(int nv, int na, const int tail[], const int head[], +      int s, int t, const int cap[], int x[], char cut[]) +{     int a, delta, i, j, k, pos1, pos2, temp, +         *ptr, *arc, *link, *list; +      /* sanity checks */ +      xassert(nv >= 2); +      xassert(na >= 0); +      xassert(1 <= s && s <= nv); +      xassert(1 <= t && t <= nv); +      xassert(s != t); +      for (a = 1; a <= na; a++) +      {  i = tail[a], j = head[a]; +         xassert(1 <= i && i <= nv); +         xassert(1 <= j && j <= nv); +         xassert(i != j); +         xassert(cap[a] >= 0); +      } +      /* allocate working arrays */ +      ptr = xcalloc(1+nv+1, sizeof(int)); +      arc = xcalloc(1+na+na, sizeof(int)); +      link = xcalloc(1+nv, sizeof(int)); +      list = xcalloc(1+nv, sizeof(int)); +      /* ptr[i] := (degree of node i) */ +      for (i = 1; i <= nv; i++) +         ptr[i] = 0; +      for (a = 1; a <= na; a++) +      {  ptr[tail[a]]++; +         ptr[head[a]]++; +      } +      /* initialize arc pointers */ +      ptr[1]++; +      for (i = 1; i < nv; i++) +         ptr[i+1] += ptr[i]; +      ptr[nv+1] = ptr[nv]; +      /* build arc lists */ +      for (a = 1; a <= na; a++) +      {  arc[--ptr[tail[a]]] = a; +         arc[--ptr[head[a]]] = a; +      } +      xassert(ptr[1] == 1); +      xassert(ptr[nv+1] == na+na+1); +      /* now the indices of arcs incident to node i are stored in +       * locations arc[ptr[i]], arc[ptr[i]+1], ..., arc[ptr[i+1]-1] */ +      /* initialize arc flows */ +      for (a = 1; a <= na; a++) +         x[a] = 0; +loop: /* main loop starts here */ +      /* build augmenting tree rooted at s */ +      /* link[i] = 0 means that node i is not labelled yet; +       * link[i] = a means that arc a immediately precedes node i */ +      /* initially node s is labelled as the root */ +      for (i = 1; i <= nv; i++) +         link[i] = 0; +      link[s] = -1, list[1] = s, pos1 = pos2 = 1; +      /* breadth first search */ +      while (pos1 <= pos2) +      {  /* dequeue node i */ +         i = list[pos1++]; +         /* consider all arcs incident to node i */ +         for (k = ptr[i]; k < ptr[i+1]; k++) +         {  a = arc[k]; +            if (tail[a] == i) +            {  /* a = i->j is a forward arc from s to t */ +               j = head[a]; +               /* if node j has been labelled, skip the arc */ +               if (link[j] != 0) continue; +               /* if the arc does not allow increasing the flow through +                * it, skip the arc */ +               if (x[a] == cap[a]) continue; +            } +            else if (head[a] == i) +            {  /* a = i<-j is a backward arc from s to t */ +               j = tail[a]; +               /* if node j has been labelled, skip the arc */ +               if (link[j] != 0) continue; +               /* if the arc does not allow decreasing the flow through +                * it, skip the arc */ +               if (x[a] == 0) continue; +            } +            else +               xassert(a != a); +            /* label node j and enqueue it */ +            link[j] = a, list[++pos2] = j; +            /* check for breakthrough */ +            if (j == t) goto brkt; +         } +      } +      /* NONBREAKTHROUGH */ +      /* no augmenting path exists; current flow is maximal */ +      /* store minimal cut information, if necessary */ +      if (cut != NULL) +      {  for (i = 1; i <= nv; i++) +            cut[i] = (char)(link[i] != 0); +      } +      goto done; +brkt: /* BREAKTHROUGH */ +      /* walk through arcs of the augmenting path (s, ..., t) found in +       * the reverse order and determine maximal change of the flow */ +      delta = 0; +      for (j = t; j != s; j = i) +      {  /* arc a immediately precedes node j in the path */ +         a = link[j]; +         if (head[a] == j) +         {  /* a = i->j is a forward arc of the cycle */ +            i = tail[a]; +            /* x[a] may be increased until its upper bound */ +            temp = cap[a] - x[a]; +         } +         else if (tail[a] == j) +         {  /* a = i<-j is a backward arc of the cycle */ +            i = head[a]; +            /* x[a] may be decreased until its lower bound */ +            temp = x[a]; +         } +         else +            xassert(a != a); +         if (delta == 0 || delta > temp) delta = temp; +      } +      xassert(delta > 0); +      /* increase the flow along the path */ +      for (j = t; j != s; j = i) +      {  /* arc a immediately precedes node j in the path */ +         a = link[j]; +         if (head[a] == j) +         {  /* a = i->j is a forward arc of the cycle */ +            i = tail[a]; +            x[a] += delta; +         } +         else if (tail[a] == j) +         {  /* a = i<-j is a backward arc of the cycle */ +            i = head[a]; +            x[a] -= delta; +         } +         else +            xassert(a != a); +      } +      goto loop; +done: /* free working arrays */ +      xfree(ptr); +      xfree(arc); +      xfree(link); +      xfree(list); +      return; +} + +/* eof */ diff --git a/glpk-5.0/src/misc/ffalg.h b/glpk-5.0/src/misc/ffalg.h new file mode 100644 index 0000000..32d5cfd --- /dev/null +++ b/glpk-5.0/src/misc/ffalg.h @@ -0,0 +1,32 @@ +/* ffalg.h (Ford-Fulkerson algorithm) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2013 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#ifndef FFALG_H +#define FFALG_H + +#define ffalg _glp_ffalg +void ffalg(int nv, int na, const int tail[], const int head[], +      int s, int t, const int cap[], int x[], char cut[]); +/* Ford-Fulkerson algorithm */ + +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/fp2rat.c b/glpk-5.0/src/misc/fp2rat.c new file mode 100644 index 0000000..eae7660 --- /dev/null +++ b/glpk-5.0/src/misc/fp2rat.c @@ -0,0 +1,162 @@ +/* fp2rat.c (convert floating-point number to rational number) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2000-2013 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "misc.h" + +/*********************************************************************** +*  NAME +* +*  fp2rat - convert floating-point number to rational number +* +*  SYNOPSIS +* +*  #include "misc.h" +*  int fp2rat(double x, double eps, double *p, double *q); +* +*  DESCRIPTION +* +*  Given a floating-point number 0 <= x < 1 the routine fp2rat finds +*  its "best" rational approximation p / q, where p >= 0 and q > 0 are +*  integer numbers, such that |x - p / q| <= eps. +* +*  RETURNS +* +*  The routine fp2rat returns the number of iterations used to achieve +*  the specified precision eps. +* +*  EXAMPLES +* +*  For x = sqrt(2) - 1 = 0.414213562373095 and eps = 1e-6 the routine +*  gives p = 408 and q = 985, where 408 / 985 = 0.414213197969543. +* +*  BACKGROUND +* +*  It is well known that every positive real number x can be expressed +*  as the following continued fraction: +* +*     x = b[0] + a[1] +*                ------------------------ +*                b[1] + a[2] +*                       ----------------- +*                       b[2] + a[3] +*                              ---------- +*                              b[3] + ... +* +*  where: +* +*     a[k] = 1,                  k = 0, 1, 2, ... +* +*     b[k] = floor(x[k]),        k = 0, 1, 2, ... +* +*     x[0] = x, +* +*     x[k] = 1 / frac(x[k-1]),   k = 1, 2, 3, ... +* +*  To find the "best" rational approximation of x the routine computes +*  partial fractions f[k] by dropping after k terms as follows: +* +*     f[k] = A[k] / B[k], +* +*  where: +* +*     A[-1] = 1,   A[0] = b[0],   B[-1] = 0,   B[0] = 1, +* +*     A[k] = b[k] * A[k-1] + a[k] * A[k-2], +* +*     B[k] = b[k] * B[k-1] + a[k] * B[k-2]. +* +*  Once the condition +* +*     |x - f[k]| <= eps +* +*  has been satisfied, the routine reports p = A[k] and q = B[k] as the +*  final answer. +* +*  In the table below here is some statistics obtained for one million +*  random numbers uniformly distributed in the range [0, 1). +* +*      eps      max p   mean p      max q    mean q  max k   mean k +*     ------------------------------------------------------------- +*     1e-1          8      1.6          9       3.2    3      1.4 +*     1e-2         98      6.2         99      12.4    5      2.4 +*     1e-3        997     20.7        998      41.5    8      3.4 +*     1e-4       9959     66.6       9960     133.5   10      4.4 +*     1e-5      97403    211.7      97404     424.2   13      5.3 +*     1e-6     479669    669.9     479670    1342.9   15      6.3 +*     1e-7    1579030   2127.3    3962146    4257.8   16      7.3 +*     1e-8   26188823   6749.4   26188824   13503.4   19      8.2 +* +*  REFERENCES +* +*  W. B. Jones and W. J. Thron, "Continued Fractions: Analytic Theory +*  and Applications," Encyclopedia on Mathematics and Its Applications, +*  Addison-Wesley, 1980. */ + +int fp2rat(double x, double eps, double *p, double *q) +{     int k; +      double xk, Akm1, Ak, Bkm1, Bk, ak, bk, fk, temp; +      xassert(0.0 <= x && x < 1.0); +      for (k = 0; ; k++) +      {  xassert(k <= 100); +         if (k == 0) +         {  /* x[0] = x */ +            xk = x; +            /* A[-1] = 1 */ +            Akm1 = 1.0; +            /* A[0] = b[0] = floor(x[0]) = 0 */ +            Ak = 0.0; +            /* B[-1] = 0 */ +            Bkm1 = 0.0; +            /* B[0] = 1 */ +            Bk = 1.0; +         } +         else +         {  /* x[k] = 1 / frac(x[k-1]) */ +            temp = xk - floor(xk); +            xassert(temp != 0.0); +            xk = 1.0 / temp; +            /* a[k] = 1 */ +            ak = 1.0; +            /* b[k] = floor(x[k]) */ +            bk = floor(xk); +            /* A[k] = b[k] * A[k-1] + a[k] * A[k-2] */ +            temp = bk * Ak + ak * Akm1; +            Akm1 = Ak, Ak = temp; +            /* B[k] = b[k] * B[k-1] + a[k] * B[k-2] */ +            temp = bk * Bk + ak * Bkm1; +            Bkm1 = Bk, Bk = temp; +         } +         /* f[k] = A[k] / B[k] */ +         fk = Ak / Bk; +#if 0 +         print("%.*g / %.*g = %.*g", +            DBL_DIG, Ak, DBL_DIG, Bk, DBL_DIG, fk); +#endif +         if (fabs(x - fk) <= eps) +            break; +      } +      *p = Ak; +      *q = Bk; +      return k; +} + +/* eof */ diff --git a/glpk-5.0/src/misc/fvs.c b/glpk-5.0/src/misc/fvs.c new file mode 100644 index 0000000..1b5f04b --- /dev/null +++ b/glpk-5.0/src/misc/fvs.c @@ -0,0 +1,135 @@ +/* fvs.c (sparse vector in FVS format) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "fvs.h" + +void fvs_alloc_vec(FVS *x, int n) +{     /* allocate sparse vector */ +      int j; +      xassert(n >= 0); +      x->n = n; +      x->nnz = 0; +      x->ind = talloc(1+n, int); +      x->vec = talloc(1+n, double); +      for (j = 1; j <= n; j++) +         x->vec[j] = 0.0; +      return; +} + +void fvs_check_vec(const FVS *x) +{     /* check sparse vector */ +      /* NOTE: for testing/debugging only */ +      int n = x->n; +      int nnz = x->nnz; +      int *ind = x->ind; +      double *vec = x->vec; +      char *map; +      int j, k; +      xassert(n >= 0); +      xassert(0 <= nnz && nnz <= n); +      map = talloc(1+n, char); +      for (j = 1; j <= n; j++) +         map[j] = (vec[j] != 0.0); +      for (k = 1; k <= nnz; k++) +      {  j = ind[k]; +         xassert(1 <= j && j <= n); +         xassert(map[j]); +         map[j] = 0; +      } +      for (j = 1; j <= n; j++) +         xassert(!map[j]); +      tfree(map); +      return; +} + +void fvs_gather_vec(FVS *x, double eps) +{     /* gather sparse vector */ +      int n = x->n; +      int *ind = x->ind; +      double *vec = x->vec; +      int j, nnz = 0; +      for (j = n; j >= 1; j--) +      {  if (-eps < vec[j] && vec[j] < +eps) +            vec[j] = 0.0; +         else +            ind[++nnz] = j; +      } +      x->nnz = nnz; +      return; +} + +void fvs_clear_vec(FVS *x) +{     /* clear sparse vector */ +      int *ind = x->ind; +      double *vec = x->vec; +      int k; +      for (k = x->nnz; k >= 1; k--) +         vec[ind[k]] = 0.0; +      x->nnz = 0; +      return; +} + +void fvs_copy_vec(FVS *x, const FVS *y) +{     /* copy sparse vector */ +      int *x_ind = x->ind; +      double *x_vec = x->vec; +      int *y_ind = y->ind; +      double *y_vec = y->vec; +      int j, k; +      xassert(x != y); +      xassert(x->n == y->n); +      fvs_clear_vec(x); +      for (k = x->nnz = y->nnz; k >= 1; k--) +      {  j = x_ind[k] = y_ind[k]; +         x_vec[j] = y_vec[j]; +      } +      return; +} + +void fvs_adjust_vec(FVS *x, double eps) +{     /* replace tiny vector elements by exact zeros */ +      int nnz = x->nnz; +      int *ind = x->ind; +      double *vec = x->vec; +      int j, k, cnt = 0; +      for (k = 1; k <= nnz; k++) +      {  j = ind[k]; +         if (-eps < vec[j] && vec[j] < +eps) +            vec[j] = 0.0; +         else +            ind[++cnt] = j; +      } +      x->nnz = cnt; +      return; +} + +void fvs_free_vec(FVS *x) +{     /* deallocate sparse vector */ +      tfree(x->ind); +      tfree(x->vec); +      x->n = x->nnz = -1; +      x->ind = NULL; +      x->vec = NULL; +      return; +} + +/* eof */ diff --git a/glpk-5.0/src/misc/fvs.h b/glpk-5.0/src/misc/fvs.h new file mode 100644 index 0000000..5b59c68 --- /dev/null +++ b/glpk-5.0/src/misc/fvs.h @@ -0,0 +1,74 @@ +/* fvs.h (sparse vector in FVS format) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#ifndef FVS_H +#define FVS_H + +typedef struct FVS FVS; + +struct FVS +{     /* sparse vector in FVS (Full Vector Storage) format */ +      int n; +      /* vector dimension (total number of elements) */ +      int nnz; +      /* number of non-zero elements, 0 <= nnz <= n */ +      int *ind; /* int ind[1+n]; */ +      /* ind[0] is not used; +       * ind[k] = j, 1 <= k <= nnz, means that vec[j] != 0 +       * non-zero indices in the array ind are stored in arbitrary +       * order; if vec[j] = 0, its index j SHOULD NOT be presented in +       * the array ind */ +      double *vec; /* double vec[1+n]; */ +      /* vec[0] is not used; +       * vec[j], 1 <= j <= n, is a numeric value of j-th element */ +}; + +#define fvs_alloc_vec _glp_fvs_alloc_vec +void fvs_alloc_vec(FVS *x, int n); +/* allocate sparse vector */ + +#define fvs_check_vec _glp_fvs_check_vec +void fvs_check_vec(const FVS *x); +/* check sparse vector */ + +#define fvs_gather_vec _glp_fvs_gather_vec +void fvs_gather_vec(FVS *x, double eps); +/* gather sparse vector */ + +#define fvs_clear_vec _glp_fvs_clear_vec +void fvs_clear_vec(FVS *x); +/* clear sparse vector */ + +#define fvs_copy_vec _glp_fvs_copy_vec +void fvs_copy_vec(FVS *x, const FVS *y); +/* copy sparse vector */ + +#define fvs_adjust_vec _glp_fvs_adjust_vec +void fvs_adjust_vec(FVS *x, double eps); +/* replace tiny vector elements by exact zeros */ + +#define fvs_free_vec _glp_fvs_free_vec +void fvs_free_vec(FVS *x); +/* deallocate sparse vector */ + +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/gcd.c b/glpk-5.0/src/misc/gcd.c new file mode 100644 index 0000000..78a4e51 --- /dev/null +++ b/glpk-5.0/src/misc/gcd.c @@ -0,0 +1,100 @@ +/* gcd.c (greatest common divisor) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2000 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "misc.h" + +/*********************************************************************** +*  NAME +* +*  gcd - find greatest common divisor of two integers +* +*  SYNOPSIS +* +*  #include "misc.h" +*  int gcd(int x, int y); +* +*  RETURNS +* +*  The routine gcd returns gcd(x, y), the greatest common divisor of +*  the two positive integers given. +* +*  ALGORITHM +* +*  The routine gcd is based on Euclid's algorithm. +* +*  REFERENCES +* +*  Don Knuth, The Art of Computer Programming, Vol.2: Seminumerical +*  Algorithms, 3rd Edition, Addison-Wesley, 1997. Section 4.5.2: The +*  Greatest Common Divisor, pp. 333-56. */ + +int gcd(int x, int y) +{     int r; +      xassert(x > 0 && y > 0); +      while (y > 0) +         r = x % y, x = y, y = r; +      return x; +} + +/*********************************************************************** +*  NAME +* +*  gcdn - find greatest common divisor of n integers +* +*  SYNOPSIS +* +*  #include "misc.h" +*  int gcdn(int n, int x[]); +* +*  RETURNS +* +*  The routine gcdn returns gcd(x[1], x[2], ..., x[n]), the greatest +*  common divisor of n positive integers given, n > 0. +* +*  BACKGROUND +* +*  The routine gcdn is based on the following identity: +* +*     gcd(x, y, z) = gcd(gcd(x, y), z). +* +*  REFERENCES +* +*  Don Knuth, The Art of Computer Programming, Vol.2: Seminumerical +*  Algorithms, 3rd Edition, Addison-Wesley, 1997. Section 4.5.2: The +*  Greatest Common Divisor, pp. 333-56. */ + +int gcdn(int n, int x[]) +{     int d, j; +      xassert(n > 0); +      for (j = 1; j <= n; j++) +      {  xassert(x[j] > 0); +         if (j == 1) +            d = x[1]; +         else +            d = gcd(d, x[j]); +         if (d == 1) +            break; +      } +      return d; +} + +/* eof */ diff --git a/glpk-5.0/src/misc/hbm.c b/glpk-5.0/src/misc/hbm.c new file mode 100644 index 0000000..aa0594d --- /dev/null +++ b/glpk-5.0/src/misc/hbm.c @@ -0,0 +1,530 @@ +/* hbm.c (Harwell-Boeing sparse matrix format) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2004-2018 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "hbm.h" +#include "misc.h" + +/*********************************************************************** +*  NAME +* +*  hbm_read_mat - read sparse matrix in Harwell-Boeing format +* +*  SYNOPSIS +* +*  #include "glphbm.h" +*  HBM *hbm_read_mat(const char *fname); +* +*  DESCRIPTION +* +*  The routine hbm_read_mat reads a sparse matrix in the Harwell-Boeing +*  format from a text file whose name is the character string fname. +* +*  Detailed description of the Harwell-Boeing format recognised by this +*  routine is given in the following report: +* +*  I.S.Duff, R.G.Grimes, J.G.Lewis. User's Guide for the Harwell-Boeing +*  Sparse Matrix Collection (Release I), TR/PA/92/86, October 1992. +* +*  RETURNS +* +*  If no error occured, the routine hbm_read_mat returns a pointer to +*  a data structure containing the matrix. In case of error the routine +*  prints an appropriate error message and returns NULL. */ + +struct dsa +{     /* working area used by routine hbm_read_mat */ +      const char *fname; +      /* name of input text file */ +      FILE *fp; +      /* stream assigned to input text file */ +      int seqn; +      /* card sequential number */ +      char card[80+1]; +      /* card image buffer */ +      int fmt_p; +      /* scale factor */ +      int fmt_k; +      /* iterator */ +      int fmt_f; +      /* format code */ +      int fmt_w; +      /* field width */ +      int fmt_d; +      /* number of decimal places after point */ +}; + +/*********************************************************************** +*  read_card - read next data card +* +*  This routine reads the next 80-column card from the input text file +*  and stores its image into the character string card. If the card was +*  read successfully, the routine returns zero, otherwise non-zero. */ + +#if 1 /* 11/III-2012 */ +static int read_card(struct dsa *dsa) +{     int c, len = 0; +      char buf[255+1]; +      dsa->seqn++; +      for (;;) +      {  c = fgetc(dsa->fp); +         if (c == EOF) +         {  if (ferror(dsa->fp)) +               xprintf("%s:%d: read error\n", +                  dsa->fname, dsa->seqn); +            else +               xprintf("%s:%d: unexpected end-of-file\n", +                  dsa->fname, dsa->seqn); +            return 1; +         } +         else if (c == '\r') +            /* nop */; +         else if (c == '\n') +            break; +         else if (iscntrl(c)) +         {  xprintf("%s:%d: invalid control character\n", +               dsa->fname, dsa->seqn, c); +            return 1; +         } +         else +         {  if (len == sizeof(buf)-1) +               goto err; +            buf[len++] = (char)c; +         } +      } +      /* remove trailing spaces */ +      while (len > 80 && buf[len-1] == ' ') +         len--; +      buf[len] = '\0'; +      /* line should not be longer than 80 chars */ +      if (len > 80) +err:  {  xerror("%s:%d: card image too long\n", +            dsa->fname, dsa->seqn); +         return 1; +      } +      /* padd by spaces to 80-column card image */ +      strcpy(dsa->card, buf); +      memset(&dsa->card[len], ' ', 80 - len); +      dsa->card[80] = '\0'; +      return 0; +} +#endif + +/*********************************************************************** +*  scan_int - scan integer value from the current card +* +*  This routine scans an integer value from the current card, where fld +*  is the name of the field, pos is the position of the field, width is +*  the width of the field, val points to a location to which the scanned +*  value should be stored. If the value was scanned successfully, the +*  routine returns zero, otherwise non-zero. */ + +static int scan_int(struct dsa *dsa, char *fld, int pos, int width, +      int *val) +{     char str[80+1]; +      xassert(1 <= width && width <= 80); +      memcpy(str, dsa->card + pos, width), str[width] = '\0'; +      if (str2int(strspx(str), val)) +      {  xprintf("%s:%d: field '%s' contains invalid value '%s'\n", +            dsa->fname, dsa->seqn, fld, str); +         return 1; +      } +      return 0; +} + +/*********************************************************************** +*  parse_fmt - parse Fortran format specification +* +*  This routine parses the Fortran format specification represented as +*  character string which fmt points to and stores format elements into +*  appropriate static locations. Should note that not all valid Fortran +*  format specifications may be recognised. If the format specification +*  was recognised, the routine returns zero, otherwise non-zero. */ + +static int parse_fmt(struct dsa *dsa, char *fmt) +{     int k, s, val; +      char str[80+1]; +      /* first character should be left parenthesis */ +      if (fmt[0] != '(') +fail: {  xprintf("hbm_read_mat: format '%s' not recognised\n", fmt); +         return 1; +      } +      k = 1; +      /* optional scale factor */ +      dsa->fmt_p = 0; +      if (isdigit((unsigned char)fmt[k])) +      {  s = 0; +         while (isdigit((unsigned char)fmt[k])) +         {  if (s == 80) goto fail; +            str[s++] = fmt[k++]; +         } +         str[s] = '\0'; +         if (str2int(str, &val)) goto fail; +         if (toupper((unsigned char)fmt[k]) != 'P') goto iter; +         dsa->fmt_p = val, k++; +         if (!(0 <= dsa->fmt_p && dsa->fmt_p <= 255)) goto fail; +         /* optional comma may follow scale factor */ +         if (fmt[k] == ',') k++; +      } +      /* optional iterator */ +      dsa->fmt_k = 1; +      if (isdigit((unsigned char)fmt[k])) +      {  s = 0; +         while (isdigit((unsigned char)fmt[k])) +         {  if (s == 80) goto fail; +            str[s++] = fmt[k++]; +         } +         str[s] = '\0'; +         if (str2int(str, &val)) goto fail; +iter:    dsa->fmt_k = val; +         if (!(1 <= dsa->fmt_k && dsa->fmt_k <= 255)) goto fail; +      } +      /* format code */ +      dsa->fmt_f = toupper((unsigned char)fmt[k++]); +      if (!(dsa->fmt_f == 'D' || dsa->fmt_f == 'E' || +            dsa->fmt_f == 'F' || dsa->fmt_f == 'G' || +            dsa->fmt_f == 'I')) goto fail; +      /* field width */ +      if (!isdigit((unsigned char)fmt[k])) goto fail; +      s = 0; +      while (isdigit((unsigned char)fmt[k])) +      {  if (s == 80) goto fail; +         str[s++] = fmt[k++]; +      } +      str[s] = '\0'; +      if (str2int(str, &dsa->fmt_w)) goto fail; +      if (!(1 <= dsa->fmt_w && dsa->fmt_w <= 255)) goto fail; +      /* optional number of decimal places after point */ +      dsa->fmt_d = 0; +      if (fmt[k] == '.') +      {  k++; +         if (!isdigit((unsigned char)fmt[k])) goto fail; +         s = 0; +         while (isdigit((unsigned char)fmt[k])) +         {  if (s == 80) goto fail; +            str[s++] = fmt[k++]; +         } +         str[s] = '\0'; +         if (str2int(str, &dsa->fmt_d)) goto fail; +         if (!(0 <= dsa->fmt_d && dsa->fmt_d <= 255)) goto fail; +      } +      /* last character should be right parenthesis */ +      if (!(fmt[k] == ')' && fmt[k+1] == '\0')) goto fail; +      return 0; +} + +/*********************************************************************** +*  read_int_array - read array of integer type +* +*  This routine reads an integer array from the input text file, where +*  name is array name, fmt is Fortran format specification that controls +*  reading, n is number of array elements, val is array of integer type. +*  If the array was read successful, the routine returns zero, otherwise +*  non-zero. */ + +static int read_int_array(struct dsa *dsa, char *name, char *fmt, +      int n, int val[]) +{     int k, pos; +      char str[80+1]; +      if (parse_fmt(dsa, fmt)) return 1; +      if (!(dsa->fmt_f == 'I' && dsa->fmt_w <= 80 && +            dsa->fmt_k * dsa->fmt_w <= 80)) +      {  xprintf( +            "%s:%d: can't read array '%s' - invalid format '%s'\n", +            dsa->fname, dsa->seqn, name, fmt); +         return 1; +      } +      for (k = 1, pos = INT_MAX; k <= n; k++, pos++) +      {  if (pos >= dsa->fmt_k) +         {  if (read_card(dsa)) return 1; +            pos = 0; +         } +         memcpy(str, dsa->card + dsa->fmt_w * pos, dsa->fmt_w); +         str[dsa->fmt_w] = '\0'; +         strspx(str); +         if (str2int(str, &val[k])) +         {  xprintf( +               "%s:%d: can't read array '%s' - invalid value '%s'\n", +               dsa->fname, dsa->seqn, name, str); +            return 1; +         } +      } +      return 0; +} + +/*********************************************************************** +*  read_real_array - read array of real type +* +*  This routine reads a real array from the input text file, where name +*  is array name, fmt is Fortran format specification that controls +*  reading, n is number of array elements, val is array of real type. +*  If the array was read successful, the routine returns zero, otherwise +*  non-zero. */ + +static int read_real_array(struct dsa *dsa, char *name, char *fmt, +      int n, double val[]) +{     int k, pos; +      char str[80+1], *ptr; +      if (parse_fmt(dsa, fmt)) return 1; +      if (!(dsa->fmt_f != 'I' && dsa->fmt_w <= 80 && +            dsa->fmt_k * dsa->fmt_w <= 80)) +      {  xprintf( +            "%s:%d: can't read array '%s' - invalid format '%s'\n", +            dsa->fname, dsa->seqn, name, fmt); +         return 1; +      } +      for (k = 1, pos = INT_MAX; k <= n; k++, pos++) +      {  if (pos >= dsa->fmt_k) +         {  if (read_card(dsa)) return 1; +            pos = 0; +         } +         memcpy(str, dsa->card + dsa->fmt_w * pos, dsa->fmt_w); +         str[dsa->fmt_w] = '\0'; +         strspx(str); +         if (strchr(str, '.') == NULL && strcmp(str, "0")) +         {  xprintf("%s(%d): can't read array '%s' - value '%s' has no " +               "decimal point\n", dsa->fname, dsa->seqn, name, str); +            return 1; +         } +         /* sometimes lower case letters appear */ +         for (ptr = str; *ptr; ptr++) +            *ptr = (char)toupper((unsigned char)*ptr); +         ptr = strchr(str, 'D'); +         if (ptr != NULL) *ptr = 'E'; +         /* value may appear with decimal exponent but without letters +            E or D (for example, -123.456-012), so missing letter should +            be inserted */ +         ptr = strchr(str+1, '+'); +         if (ptr == NULL) ptr = strchr(str+1, '-'); +         if (ptr != NULL && *(ptr-1) != 'E') +         {  xassert(strlen(str) < 80); +            memmove(ptr+1, ptr, strlen(ptr)+1); +            *ptr = 'E'; +         } +         if (str2num(str, &val[k])) +         {  xprintf( +               "%s:%d: can't read array '%s' - invalid value '%s'\n", +               dsa->fname, dsa->seqn, name, str); +            return 1; +         } +      } +      return 0; +} + +HBM *hbm_read_mat(const char *fname) +{     struct dsa _dsa, *dsa = &_dsa; +      HBM *hbm = NULL; +      dsa->fname = fname; +      xprintf("hbm_read_mat: reading matrix from '%s'...\n", +         dsa->fname); +      dsa->fp = fopen(dsa->fname, "r"); +      if (dsa->fp == NULL) +      {  xprintf("hbm_read_mat: unable to open '%s' - %s\n", +#if 0 /* 29/I-2017 */ +            dsa->fname, strerror(errno)); +#else +            dsa->fname, xstrerr(errno)); +#endif +         goto fail; +      } +      dsa->seqn = 0; +      hbm = xmalloc(sizeof(HBM)); +      memset(hbm, 0, sizeof(HBM)); +      /* read the first heading card */ +      if (read_card(dsa)) goto fail; +      memcpy(hbm->title, dsa->card, 72), hbm->title[72] = '\0'; +      strtrim(hbm->title); +      xprintf("%s\n", hbm->title); +      memcpy(hbm->key, dsa->card+72, 8), hbm->key[8] = '\0'; +      strspx(hbm->key); +      xprintf("key = %s\n", hbm->key); +      /* read the second heading card */ +      if (read_card(dsa)) goto fail; +      if (scan_int(dsa, "totcrd",  0, 14, &hbm->totcrd)) goto fail; +      if (scan_int(dsa, "ptrcrd", 14, 14, &hbm->ptrcrd)) goto fail; +      if (scan_int(dsa, "indcrd", 28, 14, &hbm->indcrd)) goto fail; +      if (scan_int(dsa, "valcrd", 42, 14, &hbm->valcrd)) goto fail; +      if (scan_int(dsa, "rhscrd", 56, 14, &hbm->rhscrd)) goto fail; +      xprintf("totcrd = %d; ptrcrd = %d; indcrd = %d; valcrd = %d; rhsc" +         "rd = %d\n", hbm->totcrd, hbm->ptrcrd, hbm->indcrd, +         hbm->valcrd, hbm->rhscrd); +      /* read the third heading card */ +      if (read_card(dsa)) goto fail; +      memcpy(hbm->mxtype, dsa->card, 3), hbm->mxtype[3] = '\0'; +      if (strchr("RCP",   hbm->mxtype[0]) == NULL || +          strchr("SUHZR", hbm->mxtype[1]) == NULL || +          strchr("AE",    hbm->mxtype[2]) == NULL) +      {  xprintf("%s:%d: matrix type '%s' not recognised\n", +            dsa->fname, dsa->seqn, hbm->mxtype); +         goto fail; +      } +      if (scan_int(dsa, "nrow", 14, 14, &hbm->nrow)) goto fail; +      if (scan_int(dsa, "ncol", 28, 14, &hbm->ncol)) goto fail; +      if (scan_int(dsa, "nnzero", 42, 14, &hbm->nnzero)) goto fail; +      if (scan_int(dsa, "neltvl", 56, 14, &hbm->neltvl)) goto fail; +      xprintf("mxtype = %s; nrow = %d; ncol = %d; nnzero = %d; neltvl =" +         " %d\n", hbm->mxtype, hbm->nrow, hbm->ncol, hbm->nnzero, +         hbm->neltvl); +      /* read the fourth heading card */ +      if (read_card(dsa)) goto fail; +      memcpy(hbm->ptrfmt, dsa->card, 16), hbm->ptrfmt[16] = '\0'; +      strspx(hbm->ptrfmt); +      memcpy(hbm->indfmt, dsa->card+16, 16), hbm->indfmt[16] = '\0'; +      strspx(hbm->indfmt); +      memcpy(hbm->valfmt, dsa->card+32, 20), hbm->valfmt[20] = '\0'; +      strspx(hbm->valfmt); +      memcpy(hbm->rhsfmt, dsa->card+52, 20), hbm->rhsfmt[20] = '\0'; +      strspx(hbm->rhsfmt); +      xprintf("ptrfmt = %s; indfmt = %s; valfmt = %s; rhsfmt = %s\n", +         hbm->ptrfmt, hbm->indfmt, hbm->valfmt, hbm->rhsfmt); +      /* read the fifth heading card (optional) */ +      if (hbm->rhscrd <= 0) +      {  strcpy(hbm->rhstyp, "???"); +         hbm->nrhs = 0; +         hbm->nrhsix = 0; +      } +      else +      {  if (read_card(dsa)) goto fail; +         memcpy(hbm->rhstyp, dsa->card, 3), hbm->rhstyp[3] = '\0'; +         if (scan_int(dsa, "nrhs", 14, 14, &hbm->nrhs)) goto fail; +         if (scan_int(dsa, "nrhsix", 28, 14, &hbm->nrhsix)) goto fail; +         xprintf("rhstyp = '%s'; nrhs = %d; nrhsix = %d\n", +            hbm->rhstyp, hbm->nrhs, hbm->nrhsix); +      } +      /* read matrix structure */ +      hbm->colptr = xcalloc(1+hbm->ncol+1, sizeof(int)); +      if (read_int_array(dsa, "colptr", hbm->ptrfmt, hbm->ncol+1, +         hbm->colptr)) goto fail; +      hbm->rowind = xcalloc(1+hbm->nnzero, sizeof(int)); +      if (read_int_array(dsa, "rowind", hbm->indfmt, hbm->nnzero, +         hbm->rowind)) goto fail; +      /* read matrix values */ +      if (hbm->valcrd <= 0) goto done; +      if (hbm->mxtype[2] == 'A') +      {  /* assembled matrix */ +         hbm->values = xcalloc(1+hbm->nnzero, sizeof(double)); +         if (read_real_array(dsa, "values", hbm->valfmt, hbm->nnzero, +            hbm->values)) goto fail; +      } +      else +      {  /* elemental (unassembled) matrix */ +         hbm->values = xcalloc(1+hbm->neltvl, sizeof(double)); +         if (read_real_array(dsa, "values", hbm->valfmt, hbm->neltvl, +            hbm->values)) goto fail; +      } +      /* read right-hand sides */ +      if (hbm->nrhs <= 0) goto done; +      if (hbm->rhstyp[0] == 'F') +      {  /* dense format */ +         hbm->nrhsvl = hbm->nrow * hbm->nrhs; +         hbm->rhsval = xcalloc(1+hbm->nrhsvl, sizeof(double)); +         if (read_real_array(dsa, "rhsval", hbm->rhsfmt, hbm->nrhsvl, +            hbm->rhsval)) goto fail; +      } +      else if (hbm->rhstyp[0] == 'M' && hbm->mxtype[2] == 'A') +      {  /* sparse format */ +         /* read pointers */ +         hbm->rhsptr = xcalloc(1+hbm->nrhs+1, sizeof(int)); +         if (read_int_array(dsa, "rhsptr", hbm->ptrfmt, hbm->nrhs+1, +            hbm->rhsptr)) goto fail; +         /* read sparsity pattern */ +         hbm->rhsind = xcalloc(1+hbm->nrhsix, sizeof(int)); +         if (read_int_array(dsa, "rhsind", hbm->indfmt, hbm->nrhsix, +            hbm->rhsind)) goto fail; +         /* read values */ +         hbm->rhsval = xcalloc(1+hbm->nrhsix, sizeof(double)); +         if (read_real_array(dsa, "rhsval", hbm->rhsfmt, hbm->nrhsix, +            hbm->rhsval)) goto fail; +      } +      else if (hbm->rhstyp[0] == 'M' && hbm->mxtype[2] == 'E') +      {  /* elemental format */ +         hbm->rhsval = xcalloc(1+hbm->nrhsvl, sizeof(double)); +         if (read_real_array(dsa, "rhsval", hbm->rhsfmt, hbm->nrhsvl, +            hbm->rhsval)) goto fail; +      } +      else +      {  xprintf("%s:%d: right-hand side type '%c' not recognised\n", +            dsa->fname, dsa->seqn, hbm->rhstyp[0]); +         goto fail; +      } +      /* read starting guesses */ +      if (hbm->rhstyp[1] == 'G') +      {  hbm->nguess = hbm->nrow * hbm->nrhs; +         hbm->sguess = xcalloc(1+hbm->nguess, sizeof(double)); +         if (read_real_array(dsa, "sguess", hbm->rhsfmt, hbm->nguess, +            hbm->sguess)) goto fail; +      } +      /* read solution vectors */ +      if (hbm->rhstyp[2] == 'X') +      {  hbm->nexact = hbm->nrow * hbm->nrhs; +         hbm->xexact = xcalloc(1+hbm->nexact, sizeof(double)); +         if (read_real_array(dsa, "xexact", hbm->rhsfmt, hbm->nexact, +            hbm->xexact)) goto fail; +      } +done: /* reading has been completed */ +      xprintf("hbm_read_mat: %d cards were read\n", dsa->seqn); +      fclose(dsa->fp); +      return hbm; +fail: /* something wrong in Danish kingdom */ +      if (hbm != NULL) +      {  if (hbm->colptr != NULL) xfree(hbm->colptr); +         if (hbm->rowind != NULL) xfree(hbm->rowind); +         if (hbm->rhsptr != NULL) xfree(hbm->rhsptr); +         if (hbm->rhsind != NULL) xfree(hbm->rhsind); +         if (hbm->values != NULL) xfree(hbm->values); +         if (hbm->rhsval != NULL) xfree(hbm->rhsval); +         if (hbm->sguess != NULL) xfree(hbm->sguess); +         if (hbm->xexact != NULL) xfree(hbm->xexact); +         xfree(hbm); +      } +      if (dsa->fp != NULL) fclose(dsa->fp); +      return NULL; +} + +/*********************************************************************** +*  NAME +* +*  hbm_free_mat - free sparse matrix in Harwell-Boeing format +* +*  SYNOPSIS +* +*  #include "glphbm.h" +*  void hbm_free_mat(HBM *hbm); +* +*  DESCRIPTION +* +*  The hbm_free_mat routine frees all the memory allocated to the data +*  structure containing a sparse matrix in the Harwell-Boeing format. */ + +void hbm_free_mat(HBM *hbm) +{     if (hbm->colptr != NULL) xfree(hbm->colptr); +      if (hbm->rowind != NULL) xfree(hbm->rowind); +      if (hbm->rhsptr != NULL) xfree(hbm->rhsptr); +      if (hbm->rhsind != NULL) xfree(hbm->rhsind); +      if (hbm->values != NULL) xfree(hbm->values); +      if (hbm->rhsval != NULL) xfree(hbm->rhsval); +      if (hbm->sguess != NULL) xfree(hbm->sguess); +      if (hbm->xexact != NULL) xfree(hbm->xexact); +      xfree(hbm); +      return; +} + +/* eof */ diff --git a/glpk-5.0/src/misc/hbm.h b/glpk-5.0/src/misc/hbm.h new file mode 100644 index 0000000..cd6d55f --- /dev/null +++ b/glpk-5.0/src/misc/hbm.h @@ -0,0 +1,124 @@ +/* hbm.h (Harwell-Boeing sparse matrix format) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2004-2018 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#ifndef HBM_H +#define HBM_H + +typedef struct HBM HBM; + +struct HBM +{     /* sparse matrix in Harwell-Boeing format; for details see the +         report: I.S.Duff, R.G.Grimes, J.G.Lewis. User's Guide for the +         Harwell-Boeing Sparse Matrix Collection (Release I), 1992 */ +      char title[72+1]; +      /* matrix title (informative) */ +      char key[8+1]; +      /* matrix key (informative) */ +      char mxtype[3+1]; +      /* matrix type: +         R.. real matrix +         C.. complex matrix +         P.. pattern only (no numerical values supplied) +         .S. symmetric (lower triangle + main diagonal) +         .U. unsymmetric +         .H. hermitian (lower triangle + main diagonal) +         .Z. skew symmetric (lower triangle only) +         .R. rectangular +         ..A assembled +         ..E elemental (unassembled) */ +      char rhstyp[3+1]; +      /* optional types: +         F.. right-hand sides in dense format +         M.. right-hand sides in same format as matrix +         .G. starting vector(s) (guess) is supplied +         ..X exact solution vector(s) is supplied */ +      char ptrfmt[16+1]; +      /* format for pointers */ +      char indfmt[16+1]; +      /* format for row (or variable) indices */ +      char valfmt[20+1]; +      /* format for numerical values of coefficient matrix */ +      char rhsfmt[20+1]; +      /* format for numerical values of right-hand sides */ +      int totcrd; +      /* total number of cards excluding header */ +      int ptrcrd; +      /* number of cards for ponters */ +      int indcrd; +      /* number of cards for row (or variable) indices */ +      int valcrd; +      /* number of cards for numerical values */ +      int rhscrd; +      /* number of lines for right-hand sides; +         including starting guesses and solution vectors if present; +         zero indicates no right-hand side data is present */ +      int nrow; +      /* number of rows (or variables) */ +      int ncol; +      /* number of columns (or elements) */ +      int nnzero; +      /* number of row (or variable) indices; +         equal to number of entries for assembled matrix */ +      int neltvl; +      /* number of elemental matrix entries; +         zero in case of assembled matrix */ +      int nrhs; +      /* number of right-hand sides */ +      int nrhsix; +      /* number of row indices; +         ignored in case of unassembled matrix */ +      int nrhsvl; +      /* total number of entries in all right-hand sides */ +      int nguess; +      /* total number of entries in all starting guesses */ +      int nexact; +      /* total number of entries in all solution vectors */ +      int *colptr; /* alias: eltptr */ +      /* column pointers (in case of assembled matrix); +         elemental matrix pointers (in case of unassembled matrix) */ +      int *rowind; /* alias: varind */ +      /* row indices (in case of assembled matrix); +         variable indices (in case of unassembled matrix) */ +      int *rhsptr; +      /* right-hand side pointers */ +      int *rhsind; +      /* right-hand side indices */ +      double *values; +      /* matrix values */ +      double *rhsval; +      /* right-hand side values */ +      double *sguess; +      /* starting guess values */ +      double *xexact; +      /* solution vector values */ +}; + +#define hbm_read_mat _glp_hbm_read_mat +HBM *hbm_read_mat(const char *fname); +/* read sparse matrix in Harwell-Boeing format */ + +#define hbm_free_mat _glp_hbm_free_mat +void hbm_free_mat(HBM *hbm); +/* free sparse matrix in Harwell-Boeing format */ + +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/jd.c b/glpk-5.0/src/misc/jd.c new file mode 100644 index 0000000..b637387 --- /dev/null +++ b/glpk-5.0/src/misc/jd.c @@ -0,0 +1,150 @@ +/* jd.c (conversions between calendar date and Julian day number) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2000 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include <stddef.h> +#include "jd.h" + +/*********************************************************************** +*  NAME +* +*  jday - convert calendar date to Julian day number +* +*  SYNOPSIS +* +*  #include "jd.h" +*  int jday(int d, int m, int y); +* +*  DESCRIPTION +* +*  The routine jday converts a calendar date, Gregorian calendar, to +*  corresponding Julian day number j. +* +*  From the given day d, month m, and year y, the Julian day number j +*  is computed without using tables. +* +*  The routine is valid for 1 <= y <= 4000. +* +*  RETURNS +* +*  The routine jday returns the Julian day number, or negative value if +*  the specified date is incorrect. +* +*  REFERENCES +* +*  R. G. Tantzen, Algorithm 199: conversions between calendar date and +*  Julian day number, Communications of the ACM, vol. 6, no. 8, p. 444, +*  Aug. 1963. */ + +int jday(int d, int m, int y) +{     int c, ya, j, dd; +      if (!(1 <= d && d <= 31 && +            1 <= m && m <= 12 && +            1 <= y && y <= 4000)) +         return -1; +      if (m >= 3) +         m -= 3; +      else +         m += 9, y--; +      c = y / 100; +      ya = y - 100 * c; +      j = (146097 * c) / 4 + (1461 * ya) / 4 + (153 * m + 2) / 5 + d + +         1721119; +      jdate(j, &dd, NULL, NULL); +      if (d != dd) +         return -1; +      return j; +} + +/*********************************************************************** +*  NAME +* +*  jdate - convert Julian day number to calendar date +* +*  SYNOPSIS +* +*  #include "jd.h" +*  int jdate(int j, int *d, int *m, int *y); +* +*  DESCRIPTION +* +*  The routine jdate converts a Julian day number j to corresponding +*  calendar date, Gregorian calendar. +* +*  The day d, month m, and year y are computed without using tables and +*  stored in corresponding locations. +* +*  The routine is valid for 1721426 <= j <= 3182395. +* +*  RETURNS +* +*  If the conversion is successful, the routine returns zero, otherwise +*  non-zero. +* +*  REFERENCES +* +*  R. G. Tantzen, Algorithm 199: conversions between calendar date and +*  Julian day number, Communications of the ACM, vol. 6, no. 8, p. 444, +*  Aug. 1963. */ + +int jdate(int j, int *d_, int *m_, int *y_) +{     int d, m, y; +      if (!(1721426 <= j && j <= 3182395)) +         return 1; +      j -= 1721119; +      y = (4 * j - 1) / 146097; +      j = (4 * j - 1) % 146097; +      d = j / 4; +      j = (4 * d + 3) / 1461; +      d = (4 * d + 3) % 1461; +      d = (d + 4) / 4; +      m = (5 * d - 3) / 153; +      d = (5 * d - 3) % 153; +      d = (d + 5) / 5; +      y = 100 * y + j; +      if (m <= 9) +         m += 3; +      else m -= 9, +         y++; +      if (d_ != NULL) *d_ = d; +      if (m_ != NULL) *m_ = m; +      if (y_ != NULL) *y_ = y; +      return 0; +} + +#ifdef GLP_TEST +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> + +int main(void) +{     int jbeg, jend, j, d, m, y; +      jbeg = jday(1, 1, 1); +      jend = jday(31, 12, 4000); +      for (j = jbeg; j <= jend; j++) +      {  assert(jdate(j, &d, &m, &y) == 0); +         assert(jday(d, m, y) == j); +      } +      printf("Routines jday and jdate work correctly.\n"); +      return 0; +} +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/jd.h b/glpk-5.0/src/misc/jd.h new file mode 100644 index 0000000..f59b063 --- /dev/null +++ b/glpk-5.0/src/misc/jd.h @@ -0,0 +1,30 @@ +/* jd.h (conversions between calendar date and Julian day number) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2000 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#define jday _glp_jday +int jday(int d, int m, int y); +/* convert calendar date to Julian day number */ + +#define jdate _glp_jdate +int jdate(int j, int *d, int *m, int *y); +/* convert Julian day number to calendar date */ + +/* eof */ diff --git a/glpk-5.0/src/misc/keller.c b/glpk-5.0/src/misc/keller.c new file mode 100644 index 0000000..bb4576b --- /dev/null +++ b/glpk-5.0/src/misc/keller.c @@ -0,0 +1,233 @@ +/* keller.c (cover edges by cliques, Kellerman's heuristic) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2013 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "glpk.h" +#include "env.h" +#include "keller.h" + +/*********************************************************************** +*  NAME +* +*  kellerman - cover edges by cliques with Kellerman's heuristic +* +*  SYNOPSIS +* +*  #include "keller.h" +*  int kellerman(int n, int (*func)(void *info, int i, int ind[]), +*     void *info, glp_graph *H); +* +*  DESCRIPTION +* +*  The routine kellerman implements Kellerman's heuristic algorithm +*  to find a minimal set of cliques which cover all edges of specified +*  graph G = (V, E). +* +*  The parameter n specifies the number of vertices |V|, n >= 0. +* +*  Formal routine func specifies the set of edges E in the following +*  way. Running the routine kellerman calls the routine func and passes +*  to it parameter i, which is the number of some vertex, 1 <= i <= n. +*  In response the routine func should store numbers of all vertices +*  adjacent to vertex i to locations ind[1], ind[2], ..., ind[len] and +*  return the value of len, which is the number of adjacent vertices, +*  0 <= len <= n. Self-loops are allowed, but ignored. Multiple edges +*  are not allowed. +* +*  The parameter info is a transit pointer (magic cookie) passed to the +*  formal routine func as its first parameter. +* +*  The result provided by the routine kellerman is the bipartite graph +*  H = (V union C, F), which defines the covering found. (The program +*  object of type glp_graph specified by the parameter H should be +*  previously created with the routine glp_create_graph. On entry the +*  routine kellerman erases the content of this object with the routine +*  glp_erase_graph.) Vertices of first part V correspond to vertices of +*  the graph G and have the same ordinal numbers 1, 2, ..., n. Vertices +*  of second part C correspond to cliques and have ordinal numbers +*  n+1, n+2, ..., n+k, where k is the total number of cliques in the +*  edge covering found. Every edge f in F in the program object H is +*  represented as arc f = (i->j), where i in V and j in C, which means +*  that vertex i of the graph G is in clique C[j], 1 <= j <= k. (Thus, +*  if two vertices of the graph G are in the same clique, these vertices +*  are adjacent in G, and corresponding edge is covered by that clique.) +* +*  RETURNS +* +*  The routine Kellerman returns k, the total number of cliques in the +*  edge covering found. +* +*  REFERENCE +* +*  For more details see: glpk/doc/notes/keller.pdf (in Russian). */ + +struct set +{     /* set of vertices */ +      int size; +      /* size (cardinality) of the set, 0 <= card <= n */ +      int *list; /* int list[1+n]; */ +      /* the set contains vertices list[1,...,size] */ +      int *pos; /* int pos[1+n]; */ +      /* pos[i] > 0 means that vertex i is in the set and +       * list[pos[i]] = i; pos[i] = 0 means that vertex i is not in +       * the set */ +}; + +int kellerman(int n, int (*func)(void *info, int i, int ind[]), +      void *info, void /* glp_graph */ *H_) +{     glp_graph *H = H_; +      struct set W_, *W = &W_, V_, *V = &V_; +      glp_arc *a; +      int i, j, k, m, t, len, card, best; +      xassert(n >= 0); +      /* H := (V, 0; 0), where V is the set of vertices of graph G */ +      glp_erase_graph(H, H->v_size, H->a_size); +      glp_add_vertices(H, n); +      /* W := 0 */ +      W->size = 0; +      W->list = xcalloc(1+n, sizeof(int)); +      W->pos = xcalloc(1+n, sizeof(int)); +      memset(&W->pos[1], 0, sizeof(int) * n); +      /* V := 0 */ +      V->size = 0; +      V->list = xcalloc(1+n, sizeof(int)); +      V->pos = xcalloc(1+n, sizeof(int)); +      memset(&V->pos[1], 0, sizeof(int) * n); +      /* main loop */ +      for (i = 1; i <= n; i++) +      {  /* W must be empty */ +         xassert(W->size == 0); +         /* W := { j : i > j and (i,j) in E } */ +         len = func(info, i, W->list); +         xassert(0 <= len && len <= n); +         for (t = 1; t <= len; t++) +         {  j = W->list[t]; +            xassert(1 <= j && j <= n); +            if (j >= i) continue; +            xassert(W->pos[j] == 0); +            W->list[++W->size] = j, W->pos[j] = W->size; +         } +         /* on i-th iteration we need to cover edges (i,j) for all +          * j in W */ +         /* if W is empty, it is a special case */ +         if (W->size == 0) +         {  /* set k := k + 1 and create new clique C[k] = { i } */ +            k = glp_add_vertices(H, 1) - n; +            glp_add_arc(H, i, n + k); +            continue; +         } +         /* try to include vertex i into existing cliques */ +         /* V must be empty */ +         xassert(V->size == 0); +         /* k is the number of cliques found so far */ +         k = H->nv - n; +         for (m = 1; m <= k; m++) +         {  /* do while V != W; since here V is within W, we can use +             * equivalent condition: do while |V| < |W| */ +            if (V->size == W->size) break; +            /* check if C[m] is within W */ +            for (a = H->v[n + m]->in; a != NULL; a = a->h_next) +            {  j = a->tail->i; +               if (W->pos[j] == 0) break; +            } +            if (a != NULL) continue; +            /* C[m] is within W, expand clique C[m] with vertex i */ +            /* C[m] := C[m] union {i} */ +            glp_add_arc(H, i, n + m); +            /* V is a set of vertices whose incident edges are already +             * covered by existing cliques */ +            /* V := V union C[m] */ +            for (a = H->v[n + m]->in; a != NULL; a = a->h_next) +            {  j = a->tail->i; +               if (V->pos[j] == 0) +                  V->list[++V->size] = j, V->pos[j] = V->size; +            } +         } +         /* remove from set W the vertices whose incident edges are +          * already covered by existing cliques */ +         /* W := W \ V, V := 0 */ +         for (t = 1; t <= V->size; t++) +         {  j = V->list[t], V->pos[j] = 0; +            if (W->pos[j] != 0) +            {  /* remove vertex j from W */ +               if (W->pos[j] != W->size) +               {  int jj = W->list[W->size]; +                  W->list[W->pos[j]] = jj; +                  W->pos[jj] = W->pos[j]; +               } +               W->size--, W->pos[j] = 0; +            } +         } +         V->size = 0; +         /* now set W contains only vertices whose incident edges are +          * still not covered by existing cliques; create new cliques +          * to cover remaining edges until set W becomes empty */ +         while (W->size > 0) +         {  /* find clique C[m], 1 <= m <= k, which shares maximal +             * number of vertices with W; to break ties choose clique +             * having smallest number m */ +            m = 0, best = -1; +            k = H->nv - n; +            for (t = 1; t <= k; t++) +            {  /* compute cardinality of intersection of W and C[t] */ +               card = 0; +               for (a = H->v[n + t]->in; a != NULL; a = a->h_next) +               {  j = a->tail->i; +                  if (W->pos[j] != 0) card++; +               } +               if (best < card) +                  m = t, best = card; +            } +            xassert(m > 0); +            /* set k := k + 1 and create new clique: +             * C[k] := (W intersect C[m]) union { i }, which covers all +             * edges incident to vertices from (W intersect C[m]) */ +            k = glp_add_vertices(H, 1) - n; +            for (a = H->v[n + m]->in; a != NULL; a = a->h_next) +            {  j = a->tail->i; +               if (W->pos[j] != 0) +               {  /* vertex j is in both W and C[m]; include it in new +                   * clique C[k] */ +                  glp_add_arc(H, j, n + k); +                  /* remove vertex j from W, since edge (i,j) will be +                   * covered by new clique C[k] */ +                  if (W->pos[j] != W->size) +                  {  int jj = W->list[W->size]; +                     W->list[W->pos[j]] = jj; +                     W->pos[jj] = W->pos[j]; +                  } +                  W->size--, W->pos[j] = 0; +               } +            } +            /* include vertex i to new clique C[k] to cover edges (i,j) +             * incident to all vertices j just removed from W */ +            glp_add_arc(H, i, n + k); +         } +      } +      /* free working arrays */ +      xfree(W->list); +      xfree(W->pos); +      xfree(V->list); +      xfree(V->pos); +      /* return the number of cliques in the edge covering found */ +      return H->nv - n; +} + +/* eof */ diff --git a/glpk-5.0/src/misc/keller.h b/glpk-5.0/src/misc/keller.h new file mode 100644 index 0000000..2768f35 --- /dev/null +++ b/glpk-5.0/src/misc/keller.h @@ -0,0 +1,32 @@ +/* keller.h (cover edges by cliques, Kellerman's heuristic) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2013 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#ifndef KELLER_H +#define KELLER_H + +#define kellerman _glp_kellerman +int kellerman(int n, int (*func)(void *info, int i, int ind[]), +      void *info, void /* glp_graph */ *H); +/* cover edges by cliques with Kellerman's heuristic */ + +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/ks.c b/glpk-5.0/src/misc/ks.c new file mode 100644 index 0000000..894c91a --- /dev/null +++ b/glpk-5.0/src/misc/ks.c @@ -0,0 +1,464 @@ +/* ks.c (0-1 knapsack problem) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2017-2018 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "ks.h" +#include "mt1.h" + +/*********************************************************************** +*  0-1 knapsack problem has the following formulation: +* +*     maximize z = sum{j in 1..n} c[j]x[j]                           (1) +* +*         s.t. sum{j in 1..n} a[j]x[j] <= b                          (2) +* +*              x[j] in {0, 1} for all j in 1..n                      (3) +* +*  In general case it is assumed that the instance is non-normalized, +*  i.e. parameters a, b, and c may have any sign. +***********************************************************************/ + +/*********************************************************************** +*  ks_enum - solve 0-1 knapsack problem by complete enumeration +* +*  This routine finds optimal solution to 0-1 knapsack problem (1)-(3) +*  by complete enumeration. It is intended mainly for testing purposes. +* +*  The instance to be solved is specified by parameters n, a, b, and c. +*  Note that these parameters can have any sign, i.e. normalization is +*  not needed. +* +*  On exit the routine stores the optimal point found in locations +*  x[1], ..., x[n] and returns the optimal objective value. However, if +*  the instance is infeasible, the routine returns INT_MIN. +* +*  Since the complete enumeration is inefficient, this routine can be +*  used only for small instances (n <= 20-30). */ + +#define N_MAX 40 + +int ks_enum(int n, const int a[/*1+n*/], int b, const int c[/*1+n*/], +      char x[/*1+n*/]) +{     int j, s, z, z_best; +      char x_best[1+N_MAX]; +      xassert(0 <= n && n <= N_MAX); +      /* initialization */ +      memset(&x[1], 0, n * sizeof(char)); +      z_best = INT_MIN; +loop: /* compute constraint and objective at current x */ +      s = z = 0; +      for (j = 1; j <= n; j++) +      {  if (x[j]) +            s += a[j], z += c[j]; +      } +      /* check constraint violation */ +      if (s > b) +         goto next; +      /* check objective function */ +      if (z_best < z) +      {  /* better solution has been found */ +         memcpy(&x_best[1], &x[1], n * sizeof(char)); +         z_best = z; +      } +next: /* generate next x */ +      for (j = 1; j <= n; j++) +      {  if (!x[j]) +         {  x[j] = 1; +            goto loop; +         } +         x[j] = 0; +      } +      /* report best (optimal) solution */ +      memcpy(&x[1], &x_best[1], n * sizeof(char)); +      return z_best; +} + +/*********************************************************************** +*  reduce - prepare reduced instance of 0-1 knapsack +* +*  Given original instance of 0-1 knapsack (1)-(3) specified by the +*  parameters n, a, b, and c this routine transforms it to equivalent +*  reduced instance in the same format. The reduced instance is +*  normalized, i.e. the following additional conditions are met: +* +*     n >= 2                                                         (4) +* +*     1 <= a[j] <= b for all j in 1..n                               (5) +* +*     sum{j in 1..n} a[j] >= b+1                                     (6) +* +*     c[j] >= 1      for all j in 1..n                               (7) +* +*  The routine creates the structure ks and stores there parameters n, +*  a, b, and c of the reduced instance as well as template of solution +*  to original instance. +* +*  Normally the routine returns a pointer to the structure ks created. +*  However, if the original instance is infeasible, the routine returns +*  a null pointer. */ + +struct ks +{     int orig_n; +      /* original problem dimension */ +      int n; +      /* reduced problem dimension */ +      int *a; /* int a[1+orig_n]; */ +      /* a{j in 1..n} are constraint coefficients (2) */ +      int b; +      /* b is constraint right-hand side (2) */ +      int *c; /* int c[1+orig_n]; */ +      /* c{j in 1..n} are objective coefficients (1) */ +      int c0; +      /* c0 is objective constant term */ +      char *x; /* char x[1+orig_n]; */ +      /* x{j in 1..orig_n} is solution template to original instance: +       * x[j] = 0       x[j] is fixed at 0 +       * x[j] = 1       x[j] is fixed at 1 +       * x[j] = 0x10    x[j] = x[j'] +       * x[j] = 0x11    x[j] = 1 - x[j'] +       * where x[j'] is corresponding solution to reduced instance */ +}; + +static void free_ks(struct ks *ks); + +static struct ks *reduce(const int n, const int a[/*1+n*/], int b, +      const int c[/*1+n*/]) +{     struct ks *ks; +      int j, s; +      xassert(n >= 0); +      /* initially reduced instance is the same as original one */ +      ks = talloc(1, struct ks); +      ks->orig_n = n; +      ks->n = 0; +      ks->a = talloc(1+n, int); +      memcpy(&ks->a[1], &a[1], n * sizeof(int)); +      ks->b = b; +      ks->c = talloc(1+n, int); +      memcpy(&ks->c[1], &c[1], n * sizeof(int)); +      ks->c0 = 0; +      ks->x = talloc(1+n, char); +      /* make all a[j] non-negative */ +      for (j = 1; j <= n; j++) +      {  if (a[j] >= 0) +         {  /* keep original x[j] */ +            ks->x[j] = 0x10; +         } +         else /* a[j] < 0 */ +         {  /* substitute x[j] = 1 - x'[j] */ +            ks->x[j] = 0x11; +            /* ... + a[j]x[j]        + ... <= b +             * ... + a[j](1 - x'[j]) + ... <= b +             * ... - a[j]x'[j]       + ... <= b - a[j] */ +            ks->a[j] = - ks->a[j]; +            ks->b += ks->a[j]; +            /* z = ... + c[j]x[j]        + ... + c0 = +             *   = ... + c[j](1 - x'[j]) + ... + c0 = +             *   = ... - c[j]x'[j]       + ... + (c0 + c[j]) */ +            ks->c0 += ks->c[j]; +            ks->c[j] = - ks->c[j]; +         } +      } +      /* now a[j] >= 0 for all j in 1..n */ +      if (ks->b < 0) +      {  /* instance is infeasible */ +         free_ks(ks); +         return NULL; +      } +      /* build reduced instance */ +      for (j = 1; j <= n; j++) +      {  if (ks->a[j] == 0) +         {  if (ks->c[j] <= 0) +            {  /* fix x[j] at 0 */ +               ks->x[j] ^= 0x10; +            } +            else +            {  /* fix x[j] at 1 */ +               ks->x[j] ^= 0x11; +               ks->c0 += ks->c[j]; +            } +         } +         else if (ks->a[j] > ks->b || ks->c[j] <= 0) +         {  /* fix x[j] at 0 */ +            ks->x[j] ^= 0x10; +         } +         else +         {  /* include x[j] in reduced instance */ +            ks->n++; +            ks->a[ks->n] = ks->a[j]; +            ks->c[ks->n] = ks->c[j]; +         } +      } +      /* now conditions (5) and (7) are met */ +      /* check condition (6) */ +      s = 0; +      for (j = 1; j <= ks->n; j++) +      {  xassert(1 <= ks->a[j] && ks->a[j] <= ks->b); +         xassert(ks->c[j] >= 1); +         s += ks->a[j]; +      } +      if (s <= ks->b) +      {  /* sum{j in 1..n} a[j] <= b */ +         /* fix all remaining x[j] at 1 to obtain trivial solution */ +         for (j = 1; j <= n; j++) +         {  if (ks->x[j] & 0x10) +               ks->x[j] ^= 0x11; +         } +         for (j = 1; j <= ks->n; j++) +            ks->c0 += ks->c[j]; +         /* reduced instance is empty */ +         ks->n = 0; +      } +      /* here n = 0 or n >= 2 due to condition (6) */ +      xassert(ks->n == 0 || ks->n >= 2); +      return ks; +} + +/*********************************************************************** +*  restore - restore solution to original 0-1 knapsack instance +* +*  Given optimal solution x{j in 1..ks->n} to the reduced 0-1 knapsack +*  instance (previously prepared by the routine reduce) this routine +*  constructs optimal solution to the original instance and stores it +*  in the array ks->x{j in 1..ks->orig_n}. +* +*  On exit the routine returns optimal objective value for the original +*  instance. +* +*  NOTE: This operation should be performed only once. */ + +static int restore(struct ks *ks, char x[]) +{     int j, k, z; +      z = ks->c0; +      for (j = 1, k = 0; j <= ks->orig_n; j++) +      {  if (ks->x[j] & 0x10) +         {  k++; +            xassert(k <= ks->n); +            xassert(x[k] == 0 || x[k] == 1); +            if (ks->x[j] & 1) +               ks->x[j] = 1 - x[k]; +            else +               ks->x[j] = x[k]; +            if (x[k]) +               z += ks->c[k]; +         } +      } +      xassert(k == ks->n); +      return z; +} + +/*********************************************************************** +*  free_ks - deallocate structure ks +* +*  This routine frees memory previously allocated to the structure ks +*  and all its components. */ + +static void free_ks(struct ks *ks) +{     xassert(ks != NULL); +      tfree(ks->a); +      tfree(ks->c); +      tfree(ks->x); +      tfree(ks); +} + +/*********************************************************************** +*  ks_mt1 - solve 0-1 knapsack problem with Martello & Toth algorithm +* +*  This routine finds optimal solution to 0-1 knapsack problem (1)-(3) +*  with Martello & Toth algorithm MT1. +* +*  The instance to be solved is specified by parameters n, a, b, and c. +*  Note that these parameters can have any sign, i.e. normalization is +*  not needed. +* +*  On exit the routine stores the optimal point found in locations +*  x[1], ..., x[n] and returns the optimal objective value. However, if +*  the instance is infeasible, the routine returns INT_MIN. +* +*  REFERENCES +* +*  S.Martello, P.Toth. Knapsack Problems: Algorithms and Computer Imp- +*  lementations. John Wiley & Sons, 1990. */ + +struct mt +{     int j; +      float r; /* r[j] = c[j] / a[j] */ +}; + +static int CDECL fcmp(const void *p1, const void *p2) +{     if (((struct mt *)p1)->r > ((struct mt *)p2)->r) +         return -1; +      else if (((struct mt *)p1)->r < ((struct mt *)p2)->r) +         return +1; +      else +         return 0; +} + +static int mt1a(int n, const int a[], int b, const int c[], char x[]) +{     /* interface routine to MT1 */ +      struct mt *mt; +      int j, z, *p, *w, *x1, *xx, *min, *psign, *wsign, *zsign; +      xassert(n >= 2); +      /* allocate working arrays */ +      mt = talloc(1+n, struct mt); +      p = talloc(1+n+1, int); +      w = talloc(1+n+1, int); +      x1 = talloc(1+n+1, int); +      xx = talloc(1+n+1, int); +      min = talloc(1+n+1, int); +      psign = talloc(1+n+1, int); +      wsign = talloc(1+n+1, int); +      zsign = talloc(1+n+1, int); +      /* reorder items to provide c[j] / a[j] >= a[j+1] / a[j+1] */ +      for (j = 1; j <= n; j++) +      {  mt[j].j = j; +         mt[j].r = (float)c[j] / (float)a[j]; +      } +      qsort(&mt[1], n, sizeof(struct mt), fcmp); +      /* load instance parameters */ +      for (j = 1; j <= n; j++) +      {  p[j] = c[mt[j].j]; +         w[j] = a[mt[j].j]; +      } +      /* find optimal solution */ +      z = mt1(n, p, w, b, x1, 1, xx, min, psign, wsign, zsign); +      xassert(z >= 0); +      /* store optimal point found */ +      for (j = 1; j <= n; j++) +      {  xassert(x1[j] == 0 || x1[j] == 1); +         x[mt[j].j] = x1[j]; +      } +      /* free working arrays */ +      tfree(mt); +      tfree(p); +      tfree(w); +      tfree(x1); +      tfree(xx); +      tfree(min); +      tfree(psign); +      tfree(wsign); +      tfree(zsign); +      return z; +} + +int ks_mt1(int n, const int a[/*1+n*/], int b, const int c[/*1+n*/], +      char x[/*1+n*/]) +{     struct ks *ks; +      int j, s1, s2, z; +      xassert(n >= 0); +      /* prepare reduced instance */ +      ks = reduce(n, a, b, c); +      if (ks == NULL) +      {  /* original instance is infeasible */ +         return INT_MIN; +      } +      /* find optimal solution to reduced instance */ +      if (ks->n > 0) +         mt1a(ks->n, ks->a, ks->b, ks->c, x); +      /* restore solution to original instance */ +      z = restore(ks, x); +      memcpy(&x[1], &ks->x[1], n * sizeof(char)); +      free_ks(ks); +      /* check solution found */ +      s1 = s2 = 0; +      for (j = 1; j <= n; j++) +      {  xassert(x[j] == 0 || x[j] == 1); +         if (x[j]) +            s1 += a[j], s2 += c[j]; +      } +      xassert(s1 <= b); +      xassert(s2 == z); +      return z; +} + +/*********************************************************************** +*  ks_greedy - solve 0-1 knapsack problem with greedy heuristic +* +*  This routine finds (sub)optimal solution to 0-1 knapsack problem +*  (1)-(3) with greedy heuristic. +* +*  The instance to be solved is specified by parameters n, a, b, and c. +*  Note that these parameters can have any sign, i.e. normalization is +*  not needed. +* +*  On exit the routine stores the optimal point found in locations +*  x[1], ..., x[n] and returns the optimal objective value. However, if +*  the instance is infeasible, the routine returns INT_MIN. */ + +static int greedy(int n, const int a[], int b, const int c[], char x[]) +{     /* core routine for normalized 0-1 knapsack instance */ +      struct mt *mt; +      int j, s, z; +      xassert(n >= 2); +      /* reorder items to provide c[j] / a[j] >= a[j+1] / a[j+1] */ +      mt = talloc(1+n, struct mt); +      for (j = 1; j <= n; j++) +      {  mt[j].j = j; +         mt[j].r = (float)c[j] / (float)a[j]; +      } +      qsort(&mt[1], n, sizeof(struct mt), fcmp); +      /* take items starting from most valuable ones until the knapsack +       * is full */ +      s = z = 0; +      for (j = 1; j <= n; j++) +      {  if (s + a[mt[j].j] > b) +            break; +         x[mt[j].j] = 1; +         s += a[mt[j].j]; +         z += c[mt[j].j]; +      } +      /* don't take remaining items */ +      for (j = j; j <= n; j++) +         x[mt[j].j] = 0; +      tfree(mt); +      return z; +} + +int ks_greedy(int n, const int a[/*1+n*/], int b, const int c[/*1+n*/], +      char x[/*1+n*/]) +{     struct ks *ks; +      int j, s1, s2, z; +      xassert(n >= 0); +      /* prepare reduced instance */ +      ks = reduce(n, a, b, c); +      if (ks == NULL) +      {  /* original instance is infeasible */ +         return INT_MIN; +      } +      /* find suboptimal solution to reduced instance */ +      if (ks->n > 0) +         greedy(ks->n, ks->a, ks->b, ks->c, x); +      /* restore solution to original instance */ +      z = restore(ks, x); +      memcpy(&x[1], &ks->x[1], n * sizeof(char)); +      free_ks(ks); +      /* check solution found */ +      s1 = s2 = 0; +      for (j = 1; j <= n; j++) +      {  xassert(x[j] == 0 || x[j] == 1); +         if (x[j]) +            s1 += a[j], s2 += c[j]; +      } +      xassert(s1 <= b); +      xassert(s2 == z); +      return z; +} + +/* eof */ diff --git a/glpk-5.0/src/misc/ks.h b/glpk-5.0/src/misc/ks.h new file mode 100644 index 0000000..37368d2 --- /dev/null +++ b/glpk-5.0/src/misc/ks.h @@ -0,0 +1,42 @@ +/* ks.h (0-1 knapsack problem) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2017-2018 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#ifndef KS_H +#define KS_H + +#define ks_enum _glp_ks_enum +int ks_enum(int n, const int a[/*1+n*/], int b, const int c[/*1+n*/], +      char x[/*1+n*/]); +/* solve 0-1 knapsack problem by complete enumeration */ + +#define ks_mt1 _glp_ks_mt1 +int ks_mt1(int n, const int a[/*1+n*/], int b, const int c[/*1+n*/], +      char x[/*1+n*/]); +/* solve 0-1 knapsack problem with Martello & Toth algorithm */ + +#define ks_greedy _glp_ks_greedy +int ks_greedy(int n, const int a[/*1+n*/], int b, const int c[/*1+n*/], +      char x[/*1+n*/]); +/* solve 0-1 knapsack problem with greedy heuristic */ + +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/mc13d.c b/glpk-5.0/src/misc/mc13d.c new file mode 100644 index 0000000..d8bab39 --- /dev/null +++ b/glpk-5.0/src/misc/mc13d.c @@ -0,0 +1,314 @@ +/* mc13d.c (permutations to block triangular form) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +* +*  This code is the result of translation of the Fortran subroutines +*  MC13D and MC13E associated with the following paper: +* +*  I.S.Duff, J.K.Reid, Algorithm 529: Permutations to block triangular +*  form, ACM Trans. on Math. Softw. 4 (1978), 189-192. +* +*  Use of ACM Algorithms is subject to the ACM Software Copyright and +*  License Agreement. See <http://www.acm.org/publications/policies>. +* +*  The translation was made by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "mc13d.h" + +/*********************************************************************** +*  NAME +* +*  mc13d - permutations to block triangular form +* +*  SYNOPSIS +* +*  #include "mc13d.h" +*  int mc13d(int n, const int icn[], const int ip[], const int lenr[], +*     int ior[], int ib[], int lowl[], int numb[], int prev[]); +* +*  DESCRIPTION +* +*  Given the column numbers of the nonzeros in each row of the sparse +*  matrix, the routine mc13d finds a symmetric permutation that makes +*  the matrix block lower triangular. +* +*  INPUT PARAMETERS +* +*  n     order of the matrix. +* +*  icn   array containing the column indices of the non-zeros. Those +*        belonging to a single row must be contiguous but the ordering +*        of column indices within each row is unimportant and wasted +*        space between rows is permitted. +* +*  ip    ip[i], i = 1,2,...,n, is the position in array icn of the +*        first column index of a non-zero in row i. +* +*  lenr  lenr[i], i = 1,2,...,n, is the number of non-zeros in row i. +* +*  OUTPUT PARAMETERS +* +*  ior   ior[i], i = 1,2,...,n, gives the position on the original +*        ordering of the row or column which is in position i in the +*        permuted form. +* +*  ib    ib[i], i = 1,2,...,num, is the row number in the permuted +*        matrix of the beginning of block i, 1 <= num <= n. +* +*  WORKING ARRAYS +* +*  arp   working array of length [1+n], where arp[0] is not used. +*        arp[i] is one less than the number of unsearched edges leaving +*        node i. At the end of the algorithm it is set to a permutation +*        which puts the matrix in block lower triangular form. +* +*  ib    working array of length [1+n], where ib[0] is not used. +*        ib[i] is the position in the ordering of the start of the ith +*        block. ib[n+1-i] holds the node number of the ith node on the +*        stack. +* +*  lowl  working array of length [1+n], where lowl[0] is not used. +*        lowl[i] is the smallest stack position of any node to which a +*        path from node i has been found. It is set to n+1 when node i +*        is removed from the stack. +* +*  numb  working array of length [1+n], where numb[0] is not used. +*        numb[i] is the position of node i in the stack if it is on it, +*        is the permuted order of node i for those nodes whose final +*        position has been found and is otherwise zero. +* +*  prev  working array of length [1+n], where prev[0] is not used. +*        prev[i] is the node at the end of the path when node i was +*        placed on the stack. +* +*  RETURNS +* +*  The routine mc13d returns num, the number of blocks found. */ + +int mc13d(int n, const int icn[], const int ip[], const int lenr[], +      int ior[], int ib[], int lowl[], int numb[], int prev[]) +{     int *arp = ior; +      int dummy, i, i1, i2, icnt, ii, isn, ist, ist1, iv, iw, j, lcnt, +         nnm1, num, stp; +      /* icnt is the number of nodes whose positions in final ordering +       * have been found. */ +      icnt = 0; +      /* num is the number of blocks that have been found. */ +      num = 0; +      nnm1 = n + n - 1; +      /* Initialization of arrays. */ +      for (j = 1; j <= n; j++) +      {  numb[j] = 0; +         arp[j] = lenr[j] - 1; +      } +      for (isn = 1; isn <= n; isn++) +      {  /* Look for a starting node. */ +         if (numb[isn] != 0) continue; +         iv = isn; +         /* ist is the number of nodes on the stack ... it is the stack +          * pointer. */ +         ist = 1; +         /* Put node iv at beginning of stack. */ +         lowl[iv] = numb[iv] = 1; +         ib[n] = iv; +         /* The body of this loop puts a new node on the stack or +          * backtracks. */ +         for (dummy = 1; dummy <= nnm1; dummy++) +         {  i1 = arp[iv]; +            /* Have all edges leaving node iv been searched? */ +            if (i1 >= 0) +            {  i2 = ip[iv] + lenr[iv] - 1; +               i1 = i2 - i1; +               /* Look at edges leaving node iv until one enters a new +                * node or all edges are exhausted. */ +               for (ii = i1; ii <= i2; ii++) +               {  iw = icn[ii]; +                  /* Has node iw been on stack already? */ +                  if (numb[iw] == 0) goto L70; +                  /* Update value of lowl[iv] if necessary. */ +                  if (lowl[iw] < lowl[iv]) lowl[iv] = lowl[iw]; +               } +               /* There are no more edges leaving node iv. */ +               arp[iv] = -1; +            } +            /* Is node iv the root of a block? */ +            if (lowl[iv] < numb[iv]) goto L60; +            /* Order nodes in a block. */ +            num++; +            ist1 = n + 1 - ist; +            lcnt = icnt + 1; +            /* Peel block off the top of the stack starting at the top +             * and working down to the root of the block. */ +            for (stp = ist1; stp <= n; stp++) +            {  iw = ib[stp]; +               lowl[iw] = n + 1; +               numb[iw] = ++icnt; +               if (iw == iv) break; +            } +            ist = n - stp; +            ib[num] = lcnt; +            /* Are there any nodes left on the stack? */ +            if (ist != 0) goto L60; +            /* Have all the nodes been ordered? */ +            if (icnt < n) break; +            goto L100; +L60:        /* Backtrack to previous node on path. */ +            iw = iv; +            iv = prev[iv]; +            /* Update value of lowl[iv] if necessary. */ +            if (lowl[iw] < lowl[iv]) lowl[iv] = lowl[iw]; +            continue; +L70:        /* Put new node on the stack. */ +            arp[iv] = i2 - ii - 1; +            prev[iw] = iv; +            iv = iw; +            lowl[iv] = numb[iv] = ++ist; +            ib[n+1-ist] = iv; +         } +      } +L100: /* Put permutation in the required form. */ +      for (i = 1; i <= n; i++) +         arp[numb[i]] = i; +      return num; +} + +/**********************************************************************/ + +#ifdef GLP_TEST +#include "env.h" + +void test(int n, int ipp); + +int main(void) +{     /* test program for routine mc13d */ +      test( 1,   0); +      test( 2,   1); +      test( 2,   2); +      test( 3,   3); +      test( 4,   4); +      test( 5,  10); +      test(10,  10); +      test(10,  20); +      test(20,  20); +      test(20,  50); +      test(50,  50); +      test(50, 200); +      return 0; +} + +void fa01bs(int max, int *nrand); + +void setup(int n, char a[1+50][1+50], int ip[], int icn[], int lenr[]); + +void test(int n, int ipp) +{     int ip[1+50], icn[1+1000], ior[1+50], ib[1+51], iw[1+150], +         lenr[1+50]; +      char a[1+50][1+50], hold[1+100]; +      int i, ii, iblock, ij, index, j, jblock, jj, k9, num; +      xprintf("\n\n\nMatrix is of order %d and has %d off-diagonal non-" +         "zeros\n", n, ipp); +      for (j = 1; j <= n; j++) +      {  for (i = 1; i <= n; i++) +            a[i][j] = 0; +         a[j][j] = 1; +      } +      for (k9 = 1; k9 <= ipp; k9++) +      {  /* these statements should be replaced by calls to your +          * favorite random number generator to place two pseudo-random +          * numbers between 1 and n in the variables i and j */ +         for (;;) +         {  fa01bs(n, &i); +            fa01bs(n, &j); +            if (!a[i][j]) break; +         } +         a[i][j] = 1; +      } +      /* setup converts matrix a[i,j] to required sparsity-oriented +       * storage format */ +      setup(n, a, ip, icn, lenr); +      num = mc13d(n, icn, ip, lenr, ior, ib, &iw[0], &iw[n], &iw[n+n]); +      /* output reordered matrix with blocking to improve clarity */ +      xprintf("\nThe reordered matrix which has %d block%s is of the fo" +         "rm\n", num, num == 1 ? "" : "s"); +      ib[num+1] = n + 1; +      index = 100; +      iblock = 1; +      for (i = 1; i <= n; i++) +      {  for (ij = 1; ij <= index; ij++) +            hold[ij] = ' '; +         if (i == ib[iblock]) +         {  xprintf("\n"); +            iblock++; +         } +         jblock = 1; +         index = 0; +         for (j = 1; j <= n; j++) +         {  if (j == ib[jblock]) +            {  hold[++index] = ' '; +               jblock++; +            } +            ii = ior[i]; +            jj = ior[j]; +            hold[++index] = (char)(a[ii][jj] ? 'X' : '0'); +         } +         xprintf("%.*s\n", index, &hold[1]); +      } +      xprintf("\nThe starting point for each block is given by\n"); +      for (i = 1; i <= num; i++) +      {  if ((i - 1) % 12 == 0) xprintf("\n"); +         xprintf(" %4d", ib[i]); +      } +      xprintf("\n"); +      return; +} + +void setup(int n, char a[1+50][1+50], int ip[], int icn[], int lenr[]) +{     int i, j, ind; +      for (i = 1; i <= n; i++) +         lenr[i] = 0; +      ind = 1; +      for (i = 1; i <= n; i++) +      {  ip[i] = ind; +         for (j = 1; j <= n; j++) +         {  if (a[i][j]) +            {  lenr[i]++; +               icn[ind++] = j; +            } +         } +      } +      return; +} + +double g = 1431655765.0; + +double fa01as(int i) +{     /* random number generator */ +      g = fmod(g * 9228907.0, 4294967296.0); +      if (i >= 0) +         return g / 4294967296.0; +      else +         return 2.0 * g / 4294967296.0 - 1.0; +} + +void fa01bs(int max, int *nrand) +{     *nrand = (int)(fa01as(1) * (double)max) + 1; +      return; +} +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/mc13d.h b/glpk-5.0/src/misc/mc13d.h new file mode 100644 index 0000000..ceb9df4 --- /dev/null +++ b/glpk-5.0/src/misc/mc13d.h @@ -0,0 +1,32 @@ +/* mc13d.h */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2013 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#ifndef MC13D_H +#define MC13D_H + +#define mc13d _glp_mc13d +int mc13d(int n, const int icn[], const int ip[], const int lenr[], +      int ior[], int ib[], int lowl[], int numb[], int prev[]); +/* permutations to block triangular form */ + +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/mc21a.c b/glpk-5.0/src/misc/mc21a.c new file mode 100644 index 0000000..700d0f4 --- /dev/null +++ b/glpk-5.0/src/misc/mc21a.c @@ -0,0 +1,301 @@ +/* mc21a.c (permutations for zero-free diagonal) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +* +*  This code is the result of translation of the Fortran subroutines +*  MC21A and MC21B associated with the following paper: +* +*  I.S.Duff, Algorithm 575: Permutations for zero-free diagonal, ACM +*  Trans. on Math. Softw. 7 (1981), 387-390. +* +*  Use of ACM Algorithms is subject to the ACM Software Copyright and +*  License Agreement. See <http://www.acm.org/publications/policies>. +* +*  The translation was made by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "mc21a.h" + +/*********************************************************************** +*  NAME +* +*  mc21a - permutations for zero-free diagonal +* +*  SYNOPSIS +* +*  #include "mc21a.h" +*  int mc21a(int n, const int icn[], const int ip[], const int lenr[], +*     int iperm[], int pr[], int arp[], int cv[], int out[]); +* +*  DESCRIPTION +* +*  Given the pattern of nonzeros of a sparse matrix, the routine mc21a +*  attempts to find a permutation of its rows that makes the matrix have +*  no zeros on its diagonal. +* +*  INPUT PARAMETERS +* +*  n     order of matrix. +* +*  icn   array containing the column indices of the non-zeros. Those +*        belonging to a single row must be contiguous but the ordering +*        of column indices within each row is unimportant and wasted +*        space between rows is permitted. +* +*  ip    ip[i], i = 1,2,...,n, is the position in array icn of the +*        first column index of a non-zero in row i. +* +*  lenr  lenr[i], i = 1,2,...,n, is the number of non-zeros in row i. +* +*  OUTPUT PARAMETER +* +*  iperm contains permutation to make diagonal have the smallest +*        number of zeros on it. Elements (iperm[i], i), i = 1,2,...,n, +*        are non-zero at the end of the algorithm unless the matrix is +*        structurally singular. In this case, (iperm[i], i) will be +*        zero for n - numnz entries. +* +*  WORKING ARRAYS +* +*  pr    working array of length [1+n], where pr[0] is not used. +*        pr[i] is the previous row to i in the depth first search. +* +*  arp   working array of length [1+n], where arp[0] is not used. +*        arp[i] is one less than the number of non-zeros in row i which +*        have not been scanned when looking for a cheap assignment. +* +*  cv    working array of length [1+n], where cv[0] is not used. +*        cv[i] is the most recent row extension at which column i was +*        visited. +* +*  out   working array of length [1+n], where out[0] is not used. +*        out[i] is one less than the number of non-zeros in row i +*        which have not been scanned during one pass through the main +*        loop. +* +*  RETURNS +* +*  The routine mc21a returns numnz, the number of non-zeros on diagonal +*  of permuted matrix. */ + +int mc21a(int n, const int icn[], const int ip[], const int lenr[], +      int iperm[], int pr[], int arp[], int cv[], int out[]) +{     int i, ii, in1, in2, j, j1, jord, k, kk, numnz; +      /* Initialization of arrays. */ +      for (i = 1; i <= n; i++) +      {  arp[i] = lenr[i] - 1; +         cv[i] = iperm[i] = 0; +      } +      numnz = 0; +      /* Main loop. */ +      /* Each pass round this loop either results in a new assignment +       * or gives a row with no assignment. */ +      for (jord = 1; jord <= n; jord++) +      {  j = jord; +         pr[j] = -1; +         for (k = 1; k <= jord; k++) +         {  /* Look for a cheap assignment. */ +            in1 = arp[j]; +            if (in1 >= 0) +            {  in2 = ip[j] + lenr[j] - 1; +               in1 = in2 - in1; +               for (ii = in1; ii <= in2; ii++) +               {  i = icn[ii]; +                  if (iperm[i] == 0) goto L110; +               } +               /* No cheap assignment in row. */ +               arp[j] = -1; +            } +            /* Begin looking for assignment chain starting with row j.*/ +            out[j] = lenr[j] - 1; +            /* Inner loop. Extends chain by one or backtracks. */ +            for (kk = 1; kk <= jord; kk++) +            {  in1 = out[j]; +               if (in1 >= 0) +               {  in2 = ip[j] + lenr[j] - 1; +                  in1 = in2 - in1; +                  /* Forward scan. */ +                  for (ii = in1; ii <= in2; ii++) +                  {  i = icn[ii]; +                     if (cv[i] != jord) +                     {  /* Column i has not yet been accessed during +                         * this pass. */ +                        j1 = j; +                        j = iperm[i]; +                        cv[i] = jord; +                        pr[j] = j1; +                        out[j1] = in2 - ii - 1; +                        goto L100; +                     } +                  } +               } +               /* Backtracking step. */ +               j = pr[j]; +               if (j == -1) goto L130; +            } +L100:       ; +         } +L110:    /* New assignment is made. */ +         iperm[i] = j; +         arp[j] = in2 - ii - 1; +         numnz++; +         for (k = 1; k <= jord; k++) +         {  j = pr[j]; +            if (j == -1) break; +            ii = ip[j] + lenr[j] - out[j] - 2; +            i = icn[ii]; +            iperm[i] = j; +         } +L130:    ; +      } +      /* If matrix is structurally singular, we now complete the +       * permutation iperm. */ +      if (numnz < n) +      {  for (i = 1; i <= n; i++) +            arp[i] = 0; +         k = 0; +         for (i = 1; i <= n; i++) +         {  if (iperm[i] == 0) +               out[++k] = i; +            else +               arp[iperm[i]] = i; +         } +         k = 0; +         for (i = 1; i <= n; i++) +         {  if (arp[i] == 0) +               iperm[out[++k]] = i; +         } +      } +      return numnz; +} + +/**********************************************************************/ + +#ifdef GLP_TEST +#include "env.h" + +int sing; + +void ranmat(int m, int n, int icn[], int iptr[], int nnnp1, int *knum, +      int iw[]); + +void fa01bs(int max, int *nrand); + +int main(void) +{     /* test program for the routine mc21a */ +      /* these runs on random matrices cause all possible statements in +       * mc21a to be executed */ +      int i, iold, j, j1, j2, jj, knum, l, licn, n, nov4, num, numnz; +      int ip[1+21], icn[1+1000], iperm[1+20], lenr[1+20], iw1[1+80]; +      licn = 1000; +      /* run on random matrices of orders 1 through 20 */ +      for (n = 1; n <= 20; n++) +      {  nov4 = n / 4; +         if (nov4 < 1) nov4 = 1; +L10:     fa01bs(nov4, &l); +         knum = l * n; +         /* knum is requested number of non-zeros in random matrix */ +         if (knum > licn) goto L10; +         /* if sing is false, matrix is guaranteed structurally +          * non-singular */ +         sing = ((n / 2) * 2 == n); +         /* call to subroutine to generate random matrix */ +         ranmat(n, n, icn, ip, n+1, &knum, iw1); +         /* knum is now actual number of non-zeros in random matrix */ +         if (knum > licn) goto L10; +         xprintf("n = %2d; nz = %4d; sing = %d\n", n, knum, sing); +         /* set up array of row lengths */ +         for (i = 1; i <= n; i++) +            lenr[i] = ip[i+1] - ip[i]; +         /* call to mc21a */ +         numnz = mc21a(n, icn, ip, lenr, iperm, &iw1[0], &iw1[n], +            &iw1[n+n], &iw1[n+n+n]); +         /* testing to see if there are numnz non-zeros on the diagonal +          * of the permuted matrix. */ +         num = 0; +         for (i = 1; i <= n; i++) +         {  iold = iperm[i]; +            j1 = ip[iold]; +            j2 = j1 + lenr[iold] - 1; +            if (j2 < j1) continue; +            for (jj = j1; jj <= j2; jj++) +            {  j = icn[jj]; +               if (j == i) +               {  num++; +                  break; +               } +            } +         } +         if (num != numnz) +            xprintf("Failure in mc21a, numnz = %d instead of %d\n", +               numnz, num); +      } +      return 0; +} + +void ranmat(int m, int n, int icn[], int iptr[], int nnnp1, int *knum, +      int iw[]) +{     /* subroutine to generate random matrix */ +      int i, ii, inum, j, lrow, matnum; +      inum = (*knum / n) * 2; +      if (inum > n-1) inum = n-1; +      matnum = 1; +      /* each pass through this loop generates a row of the matrix */ +      for (j = 1; j <= m; j++) +      {  iptr[j] = matnum; +         if (!(sing || j > n)) +            icn[matnum++] = j; +         if (n == 1) continue; +         for (i = 1; i <= n; i++) iw[i] = 0; +         if (!sing) iw[j] = 1; +         fa01bs(inum, &lrow); +         lrow--; +         if (lrow == 0) continue; +         /* lrow off-diagonal non-zeros in row j of the matrix */ +         for (ii = 1; ii <= lrow; ii++) +         {  for (;;) +            {  fa01bs(n, &i); +               if (iw[i] != 1) break; +            } +            iw[i] = 1; +            icn[matnum++] = i; +         } +      } +      for (i = m+1; i <= nnnp1; i++) +         iptr[i] = matnum; +      *knum = matnum - 1; +      return; +} + +double g = 1431655765.0; + +double fa01as(int i) +{     /* random number generator */ +      g = fmod(g * 9228907.0, 4294967296.0); +      if (i >= 0) +         return g / 4294967296.0; +      else +         return 2.0 * g / 4294967296.0 - 1.0; +} + +void fa01bs(int max, int *nrand) +{     *nrand = (int)(fa01as(1) * (double)max) + 1; +      return; +} +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/mc21a.h b/glpk-5.0/src/misc/mc21a.h new file mode 100644 index 0000000..882bf3a --- /dev/null +++ b/glpk-5.0/src/misc/mc21a.h @@ -0,0 +1,32 @@ +/* mc21a.h (permutations for zero-free diagonal) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2013 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#ifndef MC21A_H +#define MC21A_H + +#define mc21a _glp_mc21a +int mc21a(int n, const int icn[], const int ip[], const int lenr[], +      int iperm[], int pr[], int arp[], int cv[], int out[]); +/* permutations for zero-free diagonal */ + +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/misc.h b/glpk-5.0/src/misc/misc.h new file mode 100644 index 0000000..dd16a24 --- /dev/null +++ b/glpk-5.0/src/misc/misc.h @@ -0,0 +1,59 @@ +/* misc.h (miscellaneous routines) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2000-2013 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#ifndef MISC_H +#define MISC_H + +#define str2int _glp_str2int +int str2int(const char *str, int *val); +/* convert character string to value of int type */ + +#define str2num _glp_str2num +int str2num(const char *str, double *val); +/* convert character string to value of double type */ + +#define strspx _glp_strspx +char *strspx(char *str); +/* remove all spaces from character string */ + +#define strtrim _glp_strtrim +char *strtrim(char *str); +/* remove trailing spaces from character string */ + +#define gcd _glp_gcd +int gcd(int x, int y); +/* find greatest common divisor of two integers */ + +#define gcdn _glp_gcdn +int gcdn(int n, int x[]); +/* find greatest common divisor of n integers */ + +#define round2n _glp_round2n +double round2n(double x); +/* round floating-point number to nearest power of two */ + +#define fp2rat _glp_fp2rat +int fp2rat(double x, double eps, double *p, double *q); +/* convert floating-point number to rational number */ + +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/mt1.c b/glpk-5.0/src/misc/mt1.c new file mode 100644 index 0000000..63a0f80 --- /dev/null +++ b/glpk-5.0/src/misc/mt1.c @@ -0,0 +1,1110 @@ +/* mt1.c (0-1 knapsack problem; Martello & Toth algorithm) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +* +*  THIS CODE IS THE RESULT OF TRANSLATION OF THE FORTRAN SUBROUTINES +*  MT1 FROM THE BOOK: +* +*  SILVANO MARTELLO, PAOLO TOTH. KNAPSACK PROBLEMS: ALGORITHMS AND +*  COMPUTER IMPLEMENTATIONS. JOHN WILEY & SONS, 1990. +* +*  THE TRANSLATION HAS BEEN DONE WITH THE PERMISSION OF THE AUTHORS OF +*  THE ORIGINAL FORTRAN SUBROUTINES: SILVANO MARTELLO AND PAOLO TOTH. +* +*  The translation was made by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#line 1 "" +/*  -- translated by f2c (version 20100827). +   You must link the resulting object file with libf2c: +	on Microsoft Windows system, link with libf2c.lib; +	on Linux or Unix systems, link with .../path/to/libf2c.a -lm +	or, if you install libf2c.a in a standard place, with -lf2c -lm +	-- in that order, at the end of the command line, as in +		cc *.o -lf2c -lm +	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g., + +		http://www.netlib.org/f2c/libf2c.zip +*/ + +#if 0 /* by mao */ +#include "f2c.h" +#else +#include "env.h" +#include "mt1.h" + +typedef int integer; +typedef float real; +#endif + +#line 1 "" +/*<       SUBROUTINE MT1(N,P,W,C,Z,X,JDIM,JCK,XX,MIN,PSIGN,WSIGN,ZSIGN) >*/ +#if 1 /* by mao */ +static int chmt1_(int *, int *, int *, int *, int *, int *); + +static +#endif +/* Subroutine */ int mt1_(integer *n, integer *p, integer *w, integer *c__, +	integer *z__, integer *x, integer *jdim, integer *jck, integer *xx, +	integer *min__, integer *psign, integer *wsign, integer *zsign) +{ +    /* System generated locals */ +    integer i__1; + +    /* Local variables */ +    static real a, b; +    static integer j, r__, t, j1, n1, ch, ii, jj, kk, in, ll, ip, nn, iu, ii1, +	     chs, lim, lim1, diff, lold, mink; +    extern /* Subroutine */ int chmt1_(integer *, integer *, integer *, +	    integer *, integer *, integer *); +    static integer profit; + + +/* THIS SUBROUTINE SOLVES THE 0-1 SINGLE KNAPSACK PROBLEM */ + +/* MAXIMIZE  Z = P(1)*X(1) + ... + P(N)*X(N) */ + +/* SUBJECT TO:   W(1)*X(1) + ... + W(N)*X(N) .LE. C , */ +/*               X(J) = 0 OR 1  FOR J=1,...,N. */ + +/* THE PROGRAM IS INCLUDED IN THE VOLUME */ +/*   S. MARTELLO, P. TOTH, "KNAPSACK PROBLEMS: ALGORITHMS */ +/*   AND COMPUTER IMPLEMENTATIONS", JOHN WILEY, 1990 */ +/* AND IMPLEMENTS THE BRANCH-AND-BOUND ALGORITHM DESCRIBED IN */ +/* SECTION  2.5.2 . */ +/* THE PROGRAM DERIVES FROM AN EARLIER CODE PRESENTED IN */ +/*  S. MARTELLO, P. TOTH, "ALGORITHM FOR THE SOLUTION OF THE 0-1 SINGLE */ +/*  KNAPSACK PROBLEM", COMPUTING, 1978. */ + +/* THE INPUT PROBLEM MUST SATISFY THE CONDITIONS */ + +/*   1) 2 .LE. N .LE. JDIM - 1 ; */ +/*   2) P(J), W(J), C  POSITIVE INTEGERS; */ +/*   3) MAX (W(J)) .LE. C ; */ +/*   4) W(1) + ... + W(N) .GT. C ; */ +/*   5) P(J)/W(J) .GE. P(J+1)/W(J+1) FOR J=1,...,N-1. */ + +/* MT1 CALLS  1  PROCEDURE: CHMT1. */ + +/* THE PROGRAM IS COMPLETELY SELF-CONTAINED AND COMMUNICATION TO IT IS */ +/* ACHIEVED SOLELY THROUGH THE PARAMETER LIST OF MT1. */ +/* NO MACHINE-DEPENDENT CONSTANT IS USED. */ +/* THE PROGRAM IS WRITTEN IN 1967 AMERICAN NATIONAL STANDARD FORTRAN */ +/* AND IS ACCEPTED BY THE PFORT VERIFIER (PFORT IS THE PORTABLE */ +/* SUBSET OF ANSI DEFINED BY THE ASSOCIATION FOR COMPUTING MACHINERY). */ +/* THE PROGRAM HAS BEEN TESTED ON A DIGITAL VAX 11/780 AND AN H.P. */ +/* 9000/840. */ + +/* MT1 NEEDS  8  ARRAYS ( P ,  W ,  X ,  XX ,  MIN ,  PSIGN ,  WSIGN */ +/*                        AND  ZSIGN ) OF LENGTH AT LEAST  N + 1 . */ + +/* MEANING OF THE INPUT PARAMETERS: */ +/* N    = NUMBER OF ITEMS; */ +/* P(J) = PROFIT OF ITEM  J  (J=1,...,N); */ +/* W(J) = WEIGHT OF ITEM  J  (J=1,...,N); */ +/* C    = CAPACITY OF THE KNAPSACK; */ +/* JDIM = DIMENSION OF THE 8 ARRAYS; */ +/* JCK  = 1 IF CHECK ON THE INPUT DATA IS DESIRED, */ +/*      = 0 OTHERWISE. */ + +/* MEANING OF THE OUTPUT PARAMETERS: */ +/* Z    = VALUE OF THE OPTIMAL SOLUTION IF  Z .GT. 0 , */ +/*      = ERROR IN THE INPUT DATA (WHEN JCK=1) IF Z .LT. 0 : CONDI- */ +/*        TION  - Z  IS VIOLATED; */ +/* X(J) = 1 IF ITEM  J  IS IN THE OPTIMAL SOLUTION, */ +/*      = 0 OTHERWISE. */ + +/* ARRAYS XX, MIN, PSIGN, WSIGN AND ZSIGN ARE DUMMY. */ + +/* ALL THE PARAMETERS ARE INTEGER. ON RETURN OF MT1 ALL THE INPUT */ +/* PARAMETERS ARE UNCHANGED. */ + +/*<       INTEGER P(JDIM),W(JDIM),X(JDIM),C,Z >*/ +/*<       INTEGER XX(JDIM),MIN(JDIM),PSIGN(JDIM),WSIGN(JDIM),ZSIGN(JDIM) >*/ +/*<       INTEGER CH,CHS,DIFF,PROFIT,R,T >*/ +/*<       Z = 0 >*/ +#line 65 "" +    /* Parameter adjustments */ +#line 65 "" +    --zsign; +#line 65 "" +    --wsign; +#line 65 "" +    --psign; +#line 65 "" +    --min__; +#line 65 "" +    --xx; +#line 65 "" +    --x; +#line 65 "" +    --w; +#line 65 "" +    --p; +#line 65 "" + +#line 65 "" +    /* Function Body */ +#line 65 "" +    *z__ = 0; +/*<       IF ( JCK .EQ. 1 ) CALL CHMT1(N,P,W,C,Z,JDIM) >*/ +#line 66 "" +    if (*jck == 1) { +#line 66 "" +	chmt1_(n, &p[1], &w[1], c__, z__, jdim); +#line 66 "" +    } +/*<       IF ( Z .LT. 0 ) RETURN >*/ +#line 67 "" +    if (*z__ < 0) { +#line 67 "" +	return 0; +#line 67 "" +    } +/* INITIALIZE. */ +/*<       CH = C >*/ +#line 69 "" +    ch = *c__; +/*<       IP = 0 >*/ +#line 70 "" +    ip = 0; +/*<       CHS = CH >*/ +#line 71 "" +    chs = ch; +/*<       DO 10 LL=1,N >*/ +#line 72 "" +    i__1 = *n; +#line 72 "" +    for (ll = 1; ll <= i__1; ++ll) { +/*<         IF ( W(LL) .GT. CHS ) GO TO 20 >*/ +#line 73 "" +	if (w[ll] > chs) { +#line 73 "" +	    goto L20; +#line 73 "" +	} +/*<         IP = IP + P(LL) >*/ +#line 74 "" +	ip += p[ll]; +/*<         CHS = CHS - W(LL) >*/ +#line 75 "" +	chs -= w[ll]; +/*<    10 CONTINUE >*/ +#line 76 "" +/* L10: */ +#line 76 "" +    } +/*<    20 LL = LL - 1 >*/ +#line 77 "" +L20: +#line 77 "" +    --ll; +/*<       IF ( CHS .EQ. 0 ) GO TO 50 >*/ +#line 78 "" +    if (chs == 0) { +#line 78 "" +	goto L50; +#line 78 "" +    } +/*<       P(N+1) = 0 >*/ +#line 79 "" +    p[*n + 1] = 0; +/*<       W(N+1) = CH + 1 >*/ +#line 80 "" +    w[*n + 1] = ch + 1; +/*<       LIM = IP + CHS*P(LL+2)/W(LL+2) >*/ +#line 81 "" +    lim = ip + chs * p[ll + 2] / w[ll + 2]; +/*<       A = W(LL+1) - CHS >*/ +#line 82 "" +    a = (real) (w[ll + 1] - chs); +/*<       B = IP + P(LL+1) >*/ +#line 83 "" +    b = (real) (ip + p[ll + 1]); +/*<       LIM1 = B - A*FLOAT(P(LL))/FLOAT(W(LL)) >*/ +#line 84 "" +    lim1 = b - a * (real) p[ll] / (real) w[ll]; +/*<       IF ( LIM1 .GT. LIM ) LIM = LIM1 >*/ +#line 85 "" +    if (lim1 > lim) { +#line 85 "" +	lim = lim1; +#line 85 "" +    } +/*<       MINK = CH + 1 >*/ +#line 86 "" +    mink = ch + 1; +/*<       MIN(N) = MINK >*/ +#line 87 "" +    min__[*n] = mink; +/*<       DO 30 J=2,N >*/ +#line 88 "" +    i__1 = *n; +#line 88 "" +    for (j = 2; j <= i__1; ++j) { +/*<         KK = N + 2 - J >*/ +#line 89 "" +	kk = *n + 2 - j; +/*<         IF ( W(KK) .LT. MINK ) MINK = W(KK) >*/ +#line 90 "" +	if (w[kk] < mink) { +#line 90 "" +	    mink = w[kk]; +#line 90 "" +	} +/*<         MIN(KK-1) = MINK >*/ +#line 91 "" +	min__[kk - 1] = mink; +/*<    30 CONTINUE >*/ +#line 92 "" +/* L30: */ +#line 92 "" +    } +/*<       DO 40 J=1,N >*/ +#line 93 "" +    i__1 = *n; +#line 93 "" +    for (j = 1; j <= i__1; ++j) { +/*<         XX(J) = 0 >*/ +#line 94 "" +	xx[j] = 0; +/*<    40 CONTINUE >*/ +#line 95 "" +/* L40: */ +#line 95 "" +    } +/*<       Z = 0 >*/ +#line 96 "" +    *z__ = 0; +/*<       PROFIT = 0 >*/ +#line 97 "" +    profit = 0; +/*<       LOLD = N >*/ +#line 98 "" +    lold = *n; +/*<       II = 1 >*/ +#line 99 "" +    ii = 1; +/*<       GO TO 170 >*/ +#line 100 "" +    goto L170; +/*<    50 Z = IP >*/ +#line 101 "" +L50: +#line 101 "" +    *z__ = ip; +/*<       DO 60 J=1,LL >*/ +#line 102 "" +    i__1 = ll; +#line 102 "" +    for (j = 1; j <= i__1; ++j) { +/*<         X(J) = 1 >*/ +#line 103 "" +	x[j] = 1; +/*<    60 CONTINUE >*/ +#line 104 "" +/* L60: */ +#line 104 "" +    } +/*<       NN = LL + 1 >*/ +#line 105 "" +    nn = ll + 1; +/*<       DO 70 J=NN,N >*/ +#line 106 "" +    i__1 = *n; +#line 106 "" +    for (j = nn; j <= i__1; ++j) { +/*<         X(J) = 0 >*/ +#line 107 "" +	x[j] = 0; +/*<    70 CONTINUE >*/ +#line 108 "" +/* L70: */ +#line 108 "" +    } +/*<       RETURN >*/ +#line 109 "" +    return 0; +/* TRY TO INSERT THE II-TH ITEM INTO THE CURRENT SOLUTION. */ +/*<    80 IF ( W(II) .LE. CH ) GO TO 90 >*/ +#line 111 "" +L80: +#line 111 "" +    if (w[ii] <= ch) { +#line 111 "" +	goto L90; +#line 111 "" +    } +/*<       II1 = II + 1 >*/ +#line 112 "" +    ii1 = ii + 1; +/*<       IF ( Z .GE. CH*P(II1)/W(II1) + PROFIT ) GO TO 280 >*/ +#line 113 "" +    if (*z__ >= ch * p[ii1] / w[ii1] + profit) { +#line 113 "" +	goto L280; +#line 113 "" +    } +/*<       II = II1 >*/ +#line 114 "" +    ii = ii1; +/*<       GO TO 80 >*/ +#line 115 "" +    goto L80; +/* BUILD A NEW CURRENT SOLUTION. */ +/*<    90 IP = PSIGN(II) >*/ +#line 117 "" +L90: +#line 117 "" +    ip = psign[ii]; +/*<       CHS = CH - WSIGN(II) >*/ +#line 118 "" +    chs = ch - wsign[ii]; +/*<       IN = ZSIGN(II) >*/ +#line 119 "" +    in = zsign[ii]; +/*<       DO 100 LL=IN,N >*/ +#line 120 "" +    i__1 = *n; +#line 120 "" +    for (ll = in; ll <= i__1; ++ll) { +/*<         IF ( W(LL) .GT. CHS ) GO TO 160 >*/ +#line 121 "" +	if (w[ll] > chs) { +#line 121 "" +	    goto L160; +#line 121 "" +	} +/*<         IP = IP + P(LL) >*/ +#line 122 "" +	ip += p[ll]; +/*<         CHS = CHS - W(LL) >*/ +#line 123 "" +	chs -= w[ll]; +/*<   100 CONTINUE >*/ +#line 124 "" +/* L100: */ +#line 124 "" +    } +/*<       LL = N >*/ +#line 125 "" +    ll = *n; +/*<   110 IF ( Z .GE. IP + PROFIT ) GO TO 280 >*/ +#line 126 "" +L110: +#line 126 "" +    if (*z__ >= ip + profit) { +#line 126 "" +	goto L280; +#line 126 "" +    } +/*<       Z = IP + PROFIT >*/ +#line 127 "" +    *z__ = ip + profit; +/*<       NN = II - 1 >*/ +#line 128 "" +    nn = ii - 1; +/*<       DO 120 J=1,NN >*/ +#line 129 "" +    i__1 = nn; +#line 129 "" +    for (j = 1; j <= i__1; ++j) { +/*<         X(J) = XX(J) >*/ +#line 130 "" +	x[j] = xx[j]; +/*<   120 CONTINUE >*/ +#line 131 "" +/* L120: */ +#line 131 "" +    } +/*<       DO 130 J=II,LL >*/ +#line 132 "" +    i__1 = ll; +#line 132 "" +    for (j = ii; j <= i__1; ++j) { +/*<         X(J) = 1 >*/ +#line 133 "" +	x[j] = 1; +/*<   130 CONTINUE >*/ +#line 134 "" +/* L130: */ +#line 134 "" +    } +/*<       IF ( LL .EQ. N ) GO TO 150 >*/ +#line 135 "" +    if (ll == *n) { +#line 135 "" +	goto L150; +#line 135 "" +    } +/*<       NN = LL + 1 >*/ +#line 136 "" +    nn = ll + 1; +/*<       DO 140 J=NN,N >*/ +#line 137 "" +    i__1 = *n; +#line 137 "" +    for (j = nn; j <= i__1; ++j) { +/*<         X(J) = 0 >*/ +#line 138 "" +	x[j] = 0; +/*<   140 CONTINUE >*/ +#line 139 "" +/* L140: */ +#line 139 "" +    } +/*<   150 IF ( Z .NE. LIM ) GO TO 280 >*/ +#line 140 "" +L150: +#line 140 "" +    if (*z__ != lim) { +#line 140 "" +	goto L280; +#line 140 "" +    } +/*<       RETURN >*/ +#line 141 "" +    return 0; +/*<   160 IU = CHS*P(LL)/W(LL) >*/ +#line 142 "" +L160: +#line 142 "" +    iu = chs * p[ll] / w[ll]; +/*<       LL = LL - 1 >*/ +#line 143 "" +    --ll; +/*<       IF ( IU .EQ. 0 ) GO TO 110 >*/ +#line 144 "" +    if (iu == 0) { +#line 144 "" +	goto L110; +#line 144 "" +    } +/*<       IF ( Z .GE. PROFIT + IP + IU ) GO TO 280 >*/ +#line 145 "" +    if (*z__ >= profit + ip + iu) { +#line 145 "" +	goto L280; +#line 145 "" +    } +/* SAVE THE CURRENT SOLUTION. */ +/*<   170 WSIGN(II) = CH - CHS >*/ +#line 147 "" +L170: +#line 147 "" +    wsign[ii] = ch - chs; +/*<       PSIGN(II) = IP >*/ +#line 148 "" +    psign[ii] = ip; +/*<       ZSIGN(II) = LL + 1 >*/ +#line 149 "" +    zsign[ii] = ll + 1; +/*<       XX(II) = 1 >*/ +#line 150 "" +    xx[ii] = 1; +/*<       NN = LL - 1 >*/ +#line 151 "" +    nn = ll - 1; +/*<       IF ( NN .LT. II) GO TO 190 >*/ +#line 152 "" +    if (nn < ii) { +#line 152 "" +	goto L190; +#line 152 "" +    } +/*<       DO 180 J=II,NN >*/ +#line 153 "" +    i__1 = nn; +#line 153 "" +    for (j = ii; j <= i__1; ++j) { +/*<         WSIGN(J+1) = WSIGN(J) - W(J) >*/ +#line 154 "" +	wsign[j + 1] = wsign[j] - w[j]; +/*<         PSIGN(J+1) = PSIGN(J) - P(J) >*/ +#line 155 "" +	psign[j + 1] = psign[j] - p[j]; +/*<         ZSIGN(J+1) = LL + 1 >*/ +#line 156 "" +	zsign[j + 1] = ll + 1; +/*<         XX(J+1) = 1 >*/ +#line 157 "" +	xx[j + 1] = 1; +/*<   180 CONTINUE >*/ +#line 158 "" +/* L180: */ +#line 158 "" +    } +/*<   190 J1 = LL + 1 >*/ +#line 159 "" +L190: +#line 159 "" +    j1 = ll + 1; +/*<       DO 200 J=J1,LOLD >*/ +#line 160 "" +    i__1 = lold; +#line 160 "" +    for (j = j1; j <= i__1; ++j) { +/*<         WSIGN(J) = 0 >*/ +#line 161 "" +	wsign[j] = 0; +/*<         PSIGN(J) = 0 >*/ +#line 162 "" +	psign[j] = 0; +/*<         ZSIGN(J) = J >*/ +#line 163 "" +	zsign[j] = j; +/*<   200 CONTINUE >*/ +#line 164 "" +/* L200: */ +#line 164 "" +    } +/*<       LOLD = LL >*/ +#line 165 "" +    lold = ll; +/*<       CH = CHS >*/ +#line 166 "" +    ch = chs; +/*<       PROFIT = PROFIT + IP >*/ +#line 167 "" +    profit += ip; +/*<       IF ( LL - (N - 2) ) 240, 220, 210 >*/ +#line 168 "" +    if ((i__1 = ll - (*n - 2)) < 0) { +#line 168 "" +	goto L240; +#line 168 "" +    } else if (i__1 == 0) { +#line 168 "" +	goto L220; +#line 168 "" +    } else { +#line 168 "" +	goto L210; +#line 168 "" +    } +/*<   210 II = N >*/ +#line 169 "" +L210: +#line 169 "" +    ii = *n; +/*<       GO TO 250 >*/ +#line 170 "" +    goto L250; +/*<   220 IF ( CH .LT. W(N) ) GO TO 230 >*/ +#line 171 "" +L220: +#line 171 "" +    if (ch < w[*n]) { +#line 171 "" +	goto L230; +#line 171 "" +    } +/*<       CH = CH - W(N) >*/ +#line 172 "" +    ch -= w[*n]; +/*<       PROFIT = PROFIT + P(N) >*/ +#line 173 "" +    profit += p[*n]; +/*<       XX(N) = 1 >*/ +#line 174 "" +    xx[*n] = 1; +/*<   230 II = N - 1 >*/ +#line 175 "" +L230: +#line 175 "" +    ii = *n - 1; +/*<       GO TO 250 >*/ +#line 176 "" +    goto L250; +/*<   240 II = LL + 2 >*/ +#line 177 "" +L240: +#line 177 "" +    ii = ll + 2; +/*<       IF ( CH .GE. MIN(II-1) ) GO TO 80 >*/ +#line 178 "" +    if (ch >= min__[ii - 1]) { +#line 178 "" +	goto L80; +#line 178 "" +    } +/* SAVE THE CURRENT OPTIMAL SOLUTION. */ +/*<   250 IF ( Z .GE. PROFIT ) GO TO 270 >*/ +#line 180 "" +L250: +#line 180 "" +    if (*z__ >= profit) { +#line 180 "" +	goto L270; +#line 180 "" +    } +/*<       Z = PROFIT >*/ +#line 181 "" +    *z__ = profit; +/*<       DO 260 J=1,N >*/ +#line 182 "" +    i__1 = *n; +#line 182 "" +    for (j = 1; j <= i__1; ++j) { +/*<         X(J) = XX(J) >*/ +#line 183 "" +	x[j] = xx[j]; +/*<   260 CONTINUE >*/ +#line 184 "" +/* L260: */ +#line 184 "" +    } +/*<       IF ( Z .EQ. LIM ) RETURN >*/ +#line 185 "" +    if (*z__ == lim) { +#line 185 "" +	return 0; +#line 185 "" +    } +/*<   270 IF ( XX(N) .EQ. 0 ) GO TO 280 >*/ +#line 186 "" +L270: +#line 186 "" +    if (xx[*n] == 0) { +#line 186 "" +	goto L280; +#line 186 "" +    } +/*<       XX(N) = 0 >*/ +#line 187 "" +    xx[*n] = 0; +/*<       CH = CH + W(N) >*/ +#line 188 "" +    ch += w[*n]; +/*<       PROFIT = PROFIT - P(N) >*/ +#line 189 "" +    profit -= p[*n]; +/* BACKTRACK. */ +/*<   280 NN = II - 1 >*/ +#line 191 "" +L280: +#line 191 "" +    nn = ii - 1; +/*<       IF ( NN .EQ. 0 ) RETURN >*/ +#line 192 "" +    if (nn == 0) { +#line 192 "" +	return 0; +#line 192 "" +    } +/*<       DO 290 J=1,NN >*/ +#line 193 "" +    i__1 = nn; +#line 193 "" +    for (j = 1; j <= i__1; ++j) { +/*<         KK = II - J >*/ +#line 194 "" +	kk = ii - j; +/*<         IF ( XX(KK) .EQ. 1 ) GO TO 300 >*/ +#line 195 "" +	if (xx[kk] == 1) { +#line 195 "" +	    goto L300; +#line 195 "" +	} +/*<   290 CONTINUE >*/ +#line 196 "" +/* L290: */ +#line 196 "" +    } +/*<       RETURN >*/ +#line 197 "" +    return 0; +/*<   300 R = CH >*/ +#line 198 "" +L300: +#line 198 "" +    r__ = ch; +/*<       CH = CH + W(KK) >*/ +#line 199 "" +    ch += w[kk]; +/*<       PROFIT = PROFIT - P(KK) >*/ +#line 200 "" +    profit -= p[kk]; +/*<       XX(KK) = 0 >*/ +#line 201 "" +    xx[kk] = 0; +/*<       IF ( R .LT. MIN(KK) ) GO TO 310 >*/ +#line 202 "" +    if (r__ < min__[kk]) { +#line 202 "" +	goto L310; +#line 202 "" +    } +/*<       II = KK + 1 >*/ +#line 203 "" +    ii = kk + 1; +/*<       GO TO 80 >*/ +#line 204 "" +    goto L80; +/*<   310 NN = KK + 1 >*/ +#line 205 "" +L310: +#line 205 "" +    nn = kk + 1; +/*<       II = KK >*/ +#line 206 "" +    ii = kk; +/* TRY TO SUBSTITUTE THE NN-TH ITEM FOR THE KK-TH. */ +/*<   320 IF ( Z .GE. PROFIT + CH*P(NN)/W(NN) ) GO TO 280 >*/ +#line 208 "" +L320: +#line 208 "" +    if (*z__ >= profit + ch * p[nn] / w[nn]) { +#line 208 "" +	goto L280; +#line 208 "" +    } +/*<       DIFF = W(NN) - W(KK) >*/ +#line 209 "" +    diff = w[nn] - w[kk]; +/*<       IF ( DIFF ) 370, 330, 340 >*/ +#line 210 "" +    if (diff < 0) { +#line 210 "" +	goto L370; +#line 210 "" +    } else if (diff == 0) { +#line 210 "" +	goto L330; +#line 210 "" +    } else { +#line 210 "" +	goto L340; +#line 210 "" +    } +/*<   330 NN = NN + 1 >*/ +#line 211 "" +L330: +#line 211 "" +    ++nn; +/*<       GO TO 320 >*/ +#line 212 "" +    goto L320; +/*<   340 IF ( DIFF .GT. R ) GO TO 330 >*/ +#line 213 "" +L340: +#line 213 "" +    if (diff > r__) { +#line 213 "" +	goto L330; +#line 213 "" +    } +/*<       IF ( Z .GE. PROFIT + P(NN) ) GO TO 330 >*/ +#line 214 "" +    if (*z__ >= profit + p[nn]) { +#line 214 "" +	goto L330; +#line 214 "" +    } +/*<       Z = PROFIT + P(NN) >*/ +#line 215 "" +    *z__ = profit + p[nn]; +/*<       DO 350 J=1,KK >*/ +#line 216 "" +    i__1 = kk; +#line 216 "" +    for (j = 1; j <= i__1; ++j) { +/*<         X(J) = XX(J) >*/ +#line 217 "" +	x[j] = xx[j]; +/*<   350 CONTINUE >*/ +#line 218 "" +/* L350: */ +#line 218 "" +    } +/*<       JJ = KK + 1 >*/ +#line 219 "" +    jj = kk + 1; +/*<       DO 360 J=JJ,N >*/ +#line 220 "" +    i__1 = *n; +#line 220 "" +    for (j = jj; j <= i__1; ++j) { +/*<         X(J) = 0 >*/ +#line 221 "" +	x[j] = 0; +/*<   360 CONTINUE >*/ +#line 222 "" +/* L360: */ +#line 222 "" +    } +/*<       X(NN) = 1 >*/ +#line 223 "" +    x[nn] = 1; +/*<       IF ( Z .EQ. LIM ) RETURN >*/ +#line 224 "" +    if (*z__ == lim) { +#line 224 "" +	return 0; +#line 224 "" +    } +/*<       R = R - DIFF >*/ +#line 225 "" +    r__ -= diff; +/*<       KK = NN >*/ +#line 226 "" +    kk = nn; +/*<       NN = NN + 1 >*/ +#line 227 "" +    ++nn; +/*<       GO TO 320 >*/ +#line 228 "" +    goto L320; +/*<   370 T = R - DIFF >*/ +#line 229 "" +L370: +#line 229 "" +    t = r__ - diff; +/*<       IF ( T .LT. MIN(NN) ) GO TO 330 >*/ +#line 230 "" +    if (t < min__[nn]) { +#line 230 "" +	goto L330; +#line 230 "" +    } +/*<       IF ( Z .GE. PROFIT + P(NN) + T*P(NN+1)/W(NN+1)) GO TO 280 >*/ +#line 231 "" +    if (*z__ >= profit + p[nn] + t * p[nn + 1] / w[nn + 1]) { +#line 231 "" +	goto L280; +#line 231 "" +    } +/*<       CH = CH - W(NN) >*/ +#line 232 "" +    ch -= w[nn]; +/*<       PROFIT = PROFIT + P(NN) >*/ +#line 233 "" +    profit += p[nn]; +/*<       XX(NN) = 1 >*/ +#line 234 "" +    xx[nn] = 1; +/*<       II = NN + 1 >*/ +#line 235 "" +    ii = nn + 1; +/*<       WSIGN(NN) = W(NN) >*/ +#line 236 "" +    wsign[nn] = w[nn]; +/*<       PSIGN(NN) = P(NN) >*/ +#line 237 "" +    psign[nn] = p[nn]; +/*<       ZSIGN(NN) = II >*/ +#line 238 "" +    zsign[nn] = ii; +/*<       N1 = NN + 1 >*/ +#line 239 "" +    n1 = nn + 1; +/*<       DO 380 J=N1,LOLD >*/ +#line 240 "" +    i__1 = lold; +#line 240 "" +    for (j = n1; j <= i__1; ++j) { +/*<         WSIGN(J) = 0 >*/ +#line 241 "" +	wsign[j] = 0; +/*<         PSIGN(J) = 0 >*/ +#line 242 "" +	psign[j] = 0; +/*<         ZSIGN(J) = J >*/ +#line 243 "" +	zsign[j] = j; +/*<   380 CONTINUE >*/ +#line 244 "" +/* L380: */ +#line 244 "" +    } +/*<       LOLD = NN >*/ +#line 245 "" +    lold = nn; +/*<       GO TO 80 >*/ +#line 246 "" +    goto L80; +/*<       END >*/ +} /* mt1_ */ + +/*<       SUBROUTINE CHMT1(N,P,W,C,Z,JDIM) >*/ +#if 1 /* by mao */ +static +#endif +/* Subroutine */ int chmt1_(integer *n, integer *p, integer *w, integer *c__, +	integer *z__, integer *jdim) +{ +    /* System generated locals */ +    integer i__1; + +    /* Local variables */ +    static integer j; +    static real r__, rr; +    static integer jsw; + + +/* CHECK THE INPUT DATA. */ + +/*<       INTEGER P(JDIM),W(JDIM),C,Z >*/ +/*<       IF ( N .GE. 2 .AND. N .LE. JDIM - 1 ) GO TO 10 >*/ +#line 253 "" +    /* Parameter adjustments */ +#line 253 "" +    --w; +#line 253 "" +    --p; +#line 253 "" + +#line 253 "" +    /* Function Body */ +#line 253 "" +    if (*n >= 2 && *n <= *jdim - 1) { +#line 253 "" +	goto L10; +#line 253 "" +    } +/*<       Z = - 1 >*/ +#line 254 "" +    *z__ = -1; +/*<       RETURN >*/ +#line 255 "" +    return 0; +/*<    10 IF ( C .GT. 0 ) GO TO 30 >*/ +#line 256 "" +L10: +#line 256 "" +    if (*c__ > 0) { +#line 256 "" +	goto L30; +#line 256 "" +    } +/*<    20 Z = - 2 >*/ +#line 257 "" +L20: +#line 257 "" +    *z__ = -2; +/*<       RETURN >*/ +#line 258 "" +    return 0; +/*<    30 JSW = 0 >*/ +#line 259 "" +L30: +#line 259 "" +    jsw = 0; +/*<       RR = FLOAT(P(1))/FLOAT(W(1)) >*/ +#line 260 "" +    rr = (real) p[1] / (real) w[1]; +/*<       DO 50 J=1,N >*/ +#line 261 "" +    i__1 = *n; +#line 261 "" +    for (j = 1; j <= i__1; ++j) { +/*<         R = RR >*/ +#line 262 "" +	r__ = rr; +/*<         IF ( P(J) .LE. 0 ) GO TO 20 >*/ +#line 263 "" +	if (p[j] <= 0) { +#line 263 "" +	    goto L20; +#line 263 "" +	} +/*<         IF ( W(J) .LE. 0 ) GO TO 20 >*/ +#line 264 "" +	if (w[j] <= 0) { +#line 264 "" +	    goto L20; +#line 264 "" +	} +/*<         JSW = JSW + W(J) >*/ +#line 265 "" +	jsw += w[j]; +/*<         IF ( W(J) .LE. C ) GO TO 40 >*/ +#line 266 "" +	if (w[j] <= *c__) { +#line 266 "" +	    goto L40; +#line 266 "" +	} +/*<         Z = - 3 >*/ +#line 267 "" +	*z__ = -3; +/*<         RETURN >*/ +#line 268 "" +	return 0; +/*<    40   RR = FLOAT(P(J))/FLOAT(W(J)) >*/ +#line 269 "" +L40: +#line 269 "" +	rr = (real) p[j] / (real) w[j]; +/*<         IF ( RR .LE. R ) GO TO 50 >*/ +#line 270 "" +	if (rr <= r__) { +#line 270 "" +	    goto L50; +#line 270 "" +	} +/*<         Z = - 5 >*/ +#line 271 "" +	*z__ = -5; +/*<         RETURN >*/ +#line 272 "" +	return 0; +/*<    50 CONTINUE >*/ +#line 273 "" +L50: +#line 273 "" +	; +#line 273 "" +    } +/*<       IF ( JSW .GT. C ) RETURN >*/ +#line 274 "" +    if (jsw > *c__) { +#line 274 "" +	return 0; +#line 274 "" +    } +/*<       Z = - 4 >*/ +#line 275 "" +    *z__ = -4; +/*<       RETURN >*/ +#line 276 "" +    return 0; +/*<       END >*/ +} /* chmt1_ */ + +#if 1 /* by mao */ +int mt1(int n, int p[], int w[], int c, int x[], int jck, int xx[], +      int min[], int psign[], int wsign[], int zsign[]) +{     /* solve 0-1 knapsack problem */ +      int z, jdim = n+1, j, s1, s2; +      mt1_(&n, &p[1], &w[1], &c, &z, &x[1], &jdim, &jck, &xx[1], +         &min[1], &psign[1], &wsign[1], &zsign[1]); +      /* check solution found */ +      s1 = s2 = 0; +      for (j = 1; j <= n; j++) +      {  xassert(x[j] == 0 || x[j] == 1); +         if (x[j]) +            s1 += p[j], s2 += w[j]; +      } +      xassert(s1 == z); +      xassert(s2 <= c); +      return z; +} +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/mt1.f b/glpk-5.0/src/misc/mt1.f new file mode 100644 index 0000000..82cc4a1 --- /dev/null +++ b/glpk-5.0/src/misc/mt1.f @@ -0,0 +1,277 @@ +      SUBROUTINE MT1(N,P,W,C,Z,X,JDIM,JCK,XX,MIN,PSIGN,WSIGN,ZSIGN) +C +C THIS SUBROUTINE SOLVES THE 0-1 SINGLE KNAPSACK PROBLEM +C +C MAXIMIZE  Z = P(1)*X(1) + ... + P(N)*X(N) +C +C SUBJECT TO:   W(1)*X(1) + ... + W(N)*X(N) .LE. C , +C               X(J) = 0 OR 1  FOR J=1,...,N. +C +C THE PROGRAM IS INCLUDED IN THE VOLUME +C   S. MARTELLO, P. TOTH, "KNAPSACK PROBLEMS: ALGORITHMS +C   AND COMPUTER IMPLEMENTATIONS", JOHN WILEY, 1990 +C AND IMPLEMENTS THE BRANCH-AND-BOUND ALGORITHM DESCRIBED IN +C SECTION  2.5.2 . +C THE PROGRAM DERIVES FROM AN EARLIER CODE PRESENTED IN +C  S. MARTELLO, P. TOTH, "ALGORITHM FOR THE SOLUTION OF THE 0-1 SINGLE +C  KNAPSACK PROBLEM", COMPUTING, 1978. +C +C THE INPUT PROBLEM MUST SATISFY THE CONDITIONS +C +C   1) 2 .LE. N .LE. JDIM - 1 ; +C   2) P(J), W(J), C  POSITIVE INTEGERS; +C   3) MAX (W(J)) .LE. C ; +C   4) W(1) + ... + W(N) .GT. C ; +C   5) P(J)/W(J) .GE. P(J+1)/W(J+1) FOR J=1,...,N-1. +C +C MT1 CALLS  1  PROCEDURE: CHMT1. +C +C THE PROGRAM IS COMPLETELY SELF-CONTAINED AND COMMUNICATION TO IT IS +C ACHIEVED SOLELY THROUGH THE PARAMETER LIST OF MT1. +C NO MACHINE-DEPENDENT CONSTANT IS USED. +C THE PROGRAM IS WRITTEN IN 1967 AMERICAN NATIONAL STANDARD FORTRAN +C AND IS ACCEPTED BY THE PFORT VERIFIER (PFORT IS THE PORTABLE +C SUBSET OF ANSI DEFINED BY THE ASSOCIATION FOR COMPUTING MACHINERY). +C THE PROGRAM HAS BEEN TESTED ON A DIGITAL VAX 11/780 AND AN H.P. +C 9000/840. +C +C MT1 NEEDS  8  ARRAYS ( P ,  W ,  X ,  XX ,  MIN ,  PSIGN ,  WSIGN +C                        AND  ZSIGN ) OF LENGTH AT LEAST  N + 1 . +C +C MEANING OF THE INPUT PARAMETERS: +C N    = NUMBER OF ITEMS; +C P(J) = PROFIT OF ITEM  J  (J=1,...,N); +C W(J) = WEIGHT OF ITEM  J  (J=1,...,N); +C C    = CAPACITY OF THE KNAPSACK; +C JDIM = DIMENSION OF THE 8 ARRAYS; +C JCK  = 1 IF CHECK ON THE INPUT DATA IS DESIRED, +C      = 0 OTHERWISE. +C +C MEANING OF THE OUTPUT PARAMETERS: +C Z    = VALUE OF THE OPTIMAL SOLUTION IF  Z .GT. 0 , +C      = ERROR IN THE INPUT DATA (WHEN JCK=1) IF Z .LT. 0 : CONDI- +C        TION  - Z  IS VIOLATED; +C X(J) = 1 IF ITEM  J  IS IN THE OPTIMAL SOLUTION, +C      = 0 OTHERWISE. +C +C ARRAYS XX, MIN, PSIGN, WSIGN AND ZSIGN ARE DUMMY. +C +C ALL THE PARAMETERS ARE INTEGER. ON RETURN OF MT1 ALL THE INPUT +C PARAMETERS ARE UNCHANGED. +C +      INTEGER P(JDIM),W(JDIM),X(JDIM),C,Z +      INTEGER XX(JDIM),MIN(JDIM),PSIGN(JDIM),WSIGN(JDIM),ZSIGN(JDIM) +      INTEGER CH,CHS,DIFF,PROFIT,R,T +      Z = 0 +      IF ( JCK .EQ. 1 ) CALL CHMT1(N,P,W,C,Z,JDIM) +      IF ( Z .LT. 0 ) RETURN +C INITIALIZE. +      CH = C +      IP = 0 +      CHS = CH +      DO 10 LL=1,N +        IF ( W(LL) .GT. CHS ) GO TO 20 +        IP = IP + P(LL) +        CHS = CHS - W(LL) +   10 CONTINUE +   20 LL = LL - 1 +      IF ( CHS .EQ. 0 ) GO TO 50 +      P(N+1) = 0 +      W(N+1) = CH + 1 +      LIM = IP + CHS*P(LL+2)/W(LL+2) +      A = W(LL+1) - CHS +      B = IP + P(LL+1) +      LIM1 = B - A*FLOAT(P(LL))/FLOAT(W(LL)) +      IF ( LIM1 .GT. LIM ) LIM = LIM1 +      MINK = CH + 1 +      MIN(N) = MINK +      DO 30 J=2,N +        KK = N + 2 - J +        IF ( W(KK) .LT. MINK ) MINK = W(KK) +        MIN(KK-1) = MINK +   30 CONTINUE +      DO 40 J=1,N +        XX(J) = 0 +   40 CONTINUE +      Z = 0 +      PROFIT = 0 +      LOLD = N +      II = 1 +      GO TO 170 +   50 Z = IP +      DO 60 J=1,LL +        X(J) = 1 +   60 CONTINUE +      NN = LL + 1 +      DO 70 J=NN,N +        X(J) = 0 +   70 CONTINUE +      RETURN +C TRY TO INSERT THE II-TH ITEM INTO THE CURRENT SOLUTION. +   80 IF ( W(II) .LE. CH ) GO TO 90 +      II1 = II + 1 +      IF ( Z .GE. CH*P(II1)/W(II1) + PROFIT ) GO TO 280 +      II = II1 +      GO TO 80 +C BUILD A NEW CURRENT SOLUTION. +   90 IP = PSIGN(II) +      CHS = CH - WSIGN(II) +      IN = ZSIGN(II) +      DO 100 LL=IN,N +        IF ( W(LL) .GT. CHS ) GO TO 160 +        IP = IP + P(LL) +        CHS = CHS - W(LL) +  100 CONTINUE +      LL = N +  110 IF ( Z .GE. IP + PROFIT ) GO TO 280 +      Z = IP + PROFIT +      NN = II - 1 +      DO 120 J=1,NN +        X(J) = XX(J) +  120 CONTINUE +      DO 130 J=II,LL +        X(J) = 1 +  130 CONTINUE +      IF ( LL .EQ. N ) GO TO 150 +      NN = LL + 1 +      DO 140 J=NN,N +        X(J) = 0 +  140 CONTINUE +  150 IF ( Z .NE. LIM ) GO TO 280 +      RETURN +  160 IU = CHS*P(LL)/W(LL) +      LL = LL - 1 +      IF ( IU .EQ. 0 ) GO TO 110 +      IF ( Z .GE. PROFIT + IP + IU ) GO TO 280 +C SAVE THE CURRENT SOLUTION. +  170 WSIGN(II) = CH - CHS +      PSIGN(II) = IP +      ZSIGN(II) = LL + 1 +      XX(II) = 1 +      NN = LL - 1 +      IF ( NN .LT. II) GO TO 190 +      DO 180 J=II,NN +        WSIGN(J+1) = WSIGN(J) - W(J) +        PSIGN(J+1) = PSIGN(J) - P(J) +        ZSIGN(J+1) = LL + 1 +        XX(J+1) = 1 +  180 CONTINUE +  190 J1 = LL + 1 +      DO 200 J=J1,LOLD +        WSIGN(J) = 0 +        PSIGN(J) = 0 +        ZSIGN(J) = J +  200 CONTINUE +      LOLD = LL +      CH = CHS +      PROFIT = PROFIT + IP +      IF ( LL - (N - 2) ) 240, 220, 210 +  210 II = N +      GO TO 250 +  220 IF ( CH .LT. W(N) ) GO TO 230 +      CH = CH - W(N) +      PROFIT = PROFIT + P(N) +      XX(N) = 1 +  230 II = N - 1 +      GO TO 250 +  240 II = LL + 2 +      IF ( CH .GE. MIN(II-1) ) GO TO 80 +C SAVE THE CURRENT OPTIMAL SOLUTION. +  250 IF ( Z .GE. PROFIT ) GO TO 270 +      Z = PROFIT +      DO 260 J=1,N +        X(J) = XX(J) +  260 CONTINUE +      IF ( Z .EQ. LIM ) RETURN +  270 IF ( XX(N) .EQ. 0 ) GO TO 280 +      XX(N) = 0 +      CH = CH + W(N) +      PROFIT = PROFIT - P(N) +C BACKTRACK. +  280 NN = II - 1 +      IF ( NN .EQ. 0 ) RETURN +      DO 290 J=1,NN +        KK = II - J +        IF ( XX(KK) .EQ. 1 ) GO TO 300 +  290 CONTINUE +      RETURN +  300 R = CH +      CH = CH + W(KK) +      PROFIT = PROFIT - P(KK) +      XX(KK) = 0 +      IF ( R .LT. MIN(KK) ) GO TO 310 +      II = KK + 1 +      GO TO 80 +  310 NN = KK + 1 +      II = KK +C TRY TO SUBSTITUTE THE NN-TH ITEM FOR THE KK-TH. +  320 IF ( Z .GE. PROFIT + CH*P(NN)/W(NN) ) GO TO 280 +      DIFF = W(NN) - W(KK) +      IF ( DIFF ) 370, 330, 340 +  330 NN = NN + 1 +      GO TO 320 +  340 IF ( DIFF .GT. R ) GO TO 330 +      IF ( Z .GE. PROFIT + P(NN) ) GO TO 330 +      Z = PROFIT + P(NN) +      DO 350 J=1,KK +        X(J) = XX(J) +  350 CONTINUE +      JJ = KK + 1 +      DO 360 J=JJ,N +        X(J) = 0 +  360 CONTINUE +      X(NN) = 1 +      IF ( Z .EQ. LIM ) RETURN +      R = R - DIFF +      KK = NN +      NN = NN + 1 +      GO TO 320 +  370 T = R - DIFF +      IF ( T .LT. MIN(NN) ) GO TO 330 +      IF ( Z .GE. PROFIT + P(NN) + T*P(NN+1)/W(NN+1)) GO TO 280 +      CH = CH - W(NN) +      PROFIT = PROFIT + P(NN) +      XX(NN) = 1 +      II = NN + 1 +      WSIGN(NN) = W(NN) +      PSIGN(NN) = P(NN) +      ZSIGN(NN) = II +      N1 = NN + 1 +      DO 380 J=N1,LOLD +        WSIGN(J) = 0 +        PSIGN(J) = 0 +        ZSIGN(J) = J +  380 CONTINUE +      LOLD = NN +      GO TO 80 +      END +      SUBROUTINE CHMT1(N,P,W,C,Z,JDIM) +C +C CHECK THE INPUT DATA. +C +      INTEGER P(JDIM),W(JDIM),C,Z +      IF ( N .GE. 2 .AND. N .LE. JDIM - 1 ) GO TO 10 +      Z = - 1 +      RETURN +   10 IF ( C .GT. 0 ) GO TO 30 +   20 Z = - 2 +      RETURN +   30 JSW = 0 +      RR = FLOAT(P(1))/FLOAT(W(1)) +      DO 50 J=1,N +        R = RR +        IF ( P(J) .LE. 0 ) GO TO 20 +        IF ( W(J) .LE. 0 ) GO TO 20 +        JSW = JSW + W(J) +        IF ( W(J) .LE. C ) GO TO 40 +        Z = - 3 +        RETURN +   40   RR = FLOAT(P(J))/FLOAT(W(J)) +        IF ( RR .LE. R ) GO TO 50 +        Z = - 5 +        RETURN +   50 CONTINUE +      IF ( JSW .GT. C ) RETURN +      Z = - 4 +      RETURN +      END diff --git a/glpk-5.0/src/misc/mt1.h b/glpk-5.0/src/misc/mt1.h new file mode 100644 index 0000000..37bc44c --- /dev/null +++ b/glpk-5.0/src/misc/mt1.h @@ -0,0 +1,32 @@ +/* mt1.h (0-1 knapsack problem; Martello & Toth algorithm) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2017-2018 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#ifndef MT1_H +#define MT1_H + +#define mt1 _glp_mt1 +int mt1(int n, int p[], int w[], int c, int x[], int jck, int xx[], +      int min[], int psign[], int wsign[], int zsign[]); +/* solve 0-1 single knapsack problem */ + +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/mygmp.c b/glpk-5.0/src/misc/mygmp.c new file mode 100644 index 0000000..87ef681 --- /dev/null +++ b/glpk-5.0/src/misc/mygmp.c @@ -0,0 +1,1160 @@ +/* mygmp.c (integer and rational arithmetic) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2008-2015 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "mygmp.h" + +#ifdef HAVE_GMP               /* use GNU MP library */ + +/* nothing is needed */ + +#else                         /* use GLPK MP module */ + +#include "bignum.h" +#include "dmp.h" +#include "env.h" + +#define gmp_pool env->gmp_pool +#define gmp_size env->gmp_size +#define gmp_work env->gmp_work + +void *gmp_get_atom(int size) +{     ENV *env = get_env_ptr(); +      if (gmp_pool == NULL) +         gmp_pool = dmp_create_pool(); +      return dmp_get_atom(gmp_pool, size); +} + +void gmp_free_atom(void *ptr, int size) +{     ENV *env = get_env_ptr(); +      xassert(gmp_pool != NULL); +      dmp_free_atom(gmp_pool, ptr, size); +      return; +} + +int gmp_pool_count(void) +{     ENV *env = get_env_ptr(); +      if (gmp_pool == NULL) +         return 0; +      else +         return dmp_in_use(gmp_pool); +} + +unsigned short *gmp_get_work(int size) +{     ENV *env = get_env_ptr(); +      xassert(size > 0); +      if (gmp_size < size) +      {  if (gmp_size == 0) +         {  xassert(gmp_work == NULL); +            gmp_size = 100; +         } +         else +         {  xassert(gmp_work != NULL); +            xfree(gmp_work); +         } +         while (gmp_size < size) +            gmp_size += gmp_size; +         gmp_work = xcalloc(gmp_size, sizeof(unsigned short)); +      } +      return gmp_work; +} + +void gmp_free_mem(void) +{     ENV *env = get_env_ptr(); +      if (gmp_pool != NULL) +         dmp_delete_pool(gmp_pool); +      if (gmp_work != NULL) +         xfree(gmp_work); +      gmp_pool = NULL; +      gmp_size = 0; +      gmp_work = NULL; +      return; +} + +/*--------------------------------------------------------------------*/ + +mpz_t _mpz_init(void) +{     /* initialize x and set its value to 0 */ +      mpz_t x; +      x = gmp_get_atom(sizeof(struct mpz)); +      x->val = 0; +      x->ptr = NULL; +      return x; +} + +void mpz_clear(mpz_t x) +{     /* free the space occupied by x */ +      mpz_set_si(x, 0); +      xassert(x->ptr == NULL); +      /* free the number descriptor */ +      gmp_free_atom(x, sizeof(struct mpz)); +      return; +} + +void mpz_set(mpz_t z, mpz_t x) +{     /* set the value of z from x */ +      struct mpz_seg *e, *ee, *es; +      if (z != x) +      {  mpz_set_si(z, 0); +         z->val = x->val; +         xassert(z->ptr == NULL); +         for (e = x->ptr, es = NULL; e != NULL; e = e->next) +         {  ee = gmp_get_atom(sizeof(struct mpz_seg)); +            memcpy(ee->d, e->d, 12); +            ee->next = NULL; +            if (z->ptr == NULL) +               z->ptr = ee; +            else +               es->next = ee; +            es = ee; +         } +      } +      return; +} + +void mpz_set_si(mpz_t x, int val) +{     /* set the value of x to val */ +      struct mpz_seg *e; +      /* free existing segments, if any */ +      while (x->ptr != NULL) +      {  e = x->ptr; +         x->ptr = e->next; +         gmp_free_atom(e, sizeof(struct mpz_seg)); +      } +      /* assign new value */ +      if (val == 0x80000000) +      {  /* long format is needed */ +         x->val = -1; +         x->ptr = e = gmp_get_atom(sizeof(struct mpz_seg)); +         memset(e->d, 0, 12); +         e->d[1] = 0x8000; +         e->next = NULL; +      } +      else +      {  /* short format is enough */ +         x->val = val; +      } +      return; +} + +double mpz_get_d(mpz_t x) +{     /* convert x to a double, truncating if necessary */ +      struct mpz_seg *e; +      int j; +      double val, deg; +      if (x->ptr == NULL) +         val = (double)x->val; +      else +      {  xassert(x->val != 0); +         val = 0.0; +         deg = 1.0; +         for (e = x->ptr; e != NULL; e = e->next) +         {  for (j = 0; j <= 5; j++) +            {  val += deg * (double)((int)e->d[j]); +               deg *= 65536.0; +            } +         } +         if (x->val < 0) +            val = - val; +      } +      return val; +} + +double mpz_get_d_2exp(int *exp, mpz_t x) +{     /* convert x to a double, truncating if necessary (i.e. rounding +       * towards zero), and returning the exponent separately; +       * the return value is in the range 0.5 <= |d| < 1 and the +       * exponent is stored to *exp; d*2^exp is the (truncated) x value; +       * if x is zero, the return is 0.0 and 0 is stored to *exp; +       * this is similar to the standard C frexp function */ +      struct mpz_seg *e; +      int j, n, n1; +      double val; +      if (x->ptr == NULL) +         val = (double)x->val, n = 0; +      else +      {  xassert(x->val != 0); +         val = 0.0, n = 0; +         for (e = x->ptr; e != NULL; e = e->next) +         {  for (j = 0; j <= 5; j++) +            {  val += (double)((int)e->d[j]); +               val /= 65536.0, n += 16; +            } +         } +         if (x->val < 0) +            val = - val; +      } +      val = frexp(val, &n1); +      *exp = n + n1; +      return val; +} + +void mpz_swap(mpz_t x, mpz_t y) +{     /* swap the values x and y efficiently */ +      int val; +      void *ptr; +      val = x->val, ptr = x->ptr; +      x->val = y->val, x->ptr = y->ptr; +      y->val = val, y->ptr = ptr; +      return; +} + +static void normalize(mpz_t x) +{     /* normalize integer x that includes removing non-significant +       * (leading) zeros and converting to short format, if possible */ +      struct mpz_seg *es, *e; +      /* if the integer is in short format, it remains unchanged */ +      if (x->ptr == NULL) +      {  xassert(x->val != 0x80000000); +         goto done; +      } +      xassert(x->val == +1 || x->val == -1); +      /* find the last (most significant) non-zero segment */ +      es = NULL; +      for (e = x->ptr; e != NULL; e = e->next) +      {  if (e->d[0] || e->d[1] || e->d[2] || +             e->d[3] || e->d[4] || e->d[5]) +            es = e; +      } +      /* if all segments contain zeros, the integer is zero */ +      if (es == NULL) +      {  mpz_set_si(x, 0); +         goto done; +      } +      /* remove non-significant (leading) zero segments */ +      while (es->next != NULL) +      {  e = es->next; +         es->next = e->next; +         gmp_free_atom(e, sizeof(struct mpz_seg)); +      } +      /* convert the integer to short format, if possible */ +      e = x->ptr; +      if (e->next == NULL && e->d[1] <= 0x7FFF && +         !e->d[2] && !e->d[3] && !e->d[4] && !e->d[5]) +      {  int val; +         val = (int)e->d[0] + ((int)e->d[1] << 16); +         if (x->val < 0) +            val = - val; +         mpz_set_si(x, val); +      } +done: return; +} + +void mpz_add(mpz_t z, mpz_t x, mpz_t y) +{     /* set z to x + y */ +      static struct mpz_seg zero = { { 0, 0, 0, 0, 0, 0 }, NULL }; +      struct mpz_seg dumx, dumy, *ex, *ey, *ez, *es, *ee; +      int k, sx, sy, sz; +      unsigned int t; +      /* if [x] = 0 then [z] = [y] */ +      if (x->val == 0) +      {  xassert(x->ptr == NULL); +         mpz_set(z, y); +         goto done; +      } +      /* if [y] = 0 then [z] = [x] */ +      if (y->val == 0) +      {  xassert(y->ptr == NULL); +         mpz_set(z, x); +         goto done; +      } +      /* special case when both [x] and [y] are in short format */ +      if (x->ptr == NULL && y->ptr == NULL) +      {  int xval = x->val, yval = y->val, zval = x->val + y->val; +         xassert(xval != 0x80000000 && yval != 0x80000000); +         if (!(xval > 0 && yval > 0 && zval <= 0 || +               xval < 0 && yval < 0 && zval >= 0)) +         {  mpz_set_si(z, zval); +            goto done; +         } +      } +      /* convert [x] to long format, if necessary */ +      if (x->ptr == NULL) +      {  xassert(x->val != 0x80000000); +         if (x->val >= 0) +         {  sx = +1; +            t = (unsigned int)(+ x->val); +         } +         else +         {  sx = -1; +            t = (unsigned int)(- x->val); +         } +         ex = &dumx; +         ex->d[0] = (unsigned short)t; +         ex->d[1] = (unsigned short)(t >> 16); +         ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0; +         ex->next = NULL; +      } +      else +      {  sx = x->val; +         xassert(sx == +1 || sx == -1); +         ex = x->ptr; +      } +      /* convert [y] to long format, if necessary */ +      if (y->ptr == NULL) +      {  xassert(y->val != 0x80000000); +         if (y->val >= 0) +         {  sy = +1; +            t = (unsigned int)(+ y->val); +         } +         else +         {  sy = -1; +            t = (unsigned int)(- y->val); +         } +         ey = &dumy; +         ey->d[0] = (unsigned short)t; +         ey->d[1] = (unsigned short)(t >> 16); +         ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0; +         ey->next = NULL; +      } +      else +      {  sy = y->val; +         xassert(sy == +1 || sy == -1); +         ey = y->ptr; +      } +      /* main fragment */ +      sz = sx; +      ez = es = NULL; +      if (sx > 0 && sy > 0 || sx < 0 && sy < 0) +      {  /* [x] and [y] have identical signs -- addition */ +         t = 0; +         for (; ex || ey; ex = ex->next, ey = ey->next) +         {  if (ex == NULL) +               ex = &zero; +            if (ey == NULL) +               ey = &zero; +            ee = gmp_get_atom(sizeof(struct mpz_seg)); +            for (k = 0; k <= 5; k++) +            {  t += (unsigned int)ex->d[k]; +               t += (unsigned int)ey->d[k]; +               ee->d[k] = (unsigned short)t; +               t >>= 16; +            } +            ee->next = NULL; +            if (ez == NULL) +               ez = ee; +            else +               es->next = ee; +            es = ee; +         } +         if (t) +         {  /* overflow -- one extra digit is needed */ +            ee = gmp_get_atom(sizeof(struct mpz_seg)); +            ee->d[0] = 1; +            ee->d[1] = ee->d[2] = ee->d[3] = ee->d[4] = ee->d[5] = 0; +            ee->next = NULL; +            xassert(es != NULL); +            es->next = ee; +         } +      } +      else +      {  /* [x] and [y] have different signs -- subtraction */ +         t = 1; +         for (; ex || ey; ex = ex->next, ey = ey->next) +         {  if (ex == NULL) +               ex = &zero; +            if (ey == NULL) +               ey = &zero; +            ee = gmp_get_atom(sizeof(struct mpz_seg)); +            for (k = 0; k <= 5; k++) +            {  t += (unsigned int)ex->d[k]; +               t += (0xFFFF - (unsigned int)ey->d[k]); +               ee->d[k] = (unsigned short)t; +               t >>= 16; +            } +            ee->next = NULL; +            if (ez == NULL) +               ez = ee; +            else +               es->next = ee; +            es = ee; +         } +         if (!t) +         {  /* |[x]| < |[y]| -- result in complement coding */ +            sz = - sz; +            t = 1; +            for (ee = ez; ee != NULL; ee = ee->next) +            {  for (k = 0; k <= 5; k++) +               {  t += (0xFFFF - (unsigned int)ee->d[k]); +                  ee->d[k] = (unsigned short)t; +                  t >>= 16; +               } +            } +         } +      } +      /* contruct and normalize result */ +      mpz_set_si(z, 0); +      z->val = sz; +      z->ptr = ez; +      normalize(z); +done: return; +} + +void mpz_sub(mpz_t z, mpz_t x, mpz_t y) +{     /* set z to x - y */ +      if (x == y) +         mpz_set_si(z, 0); +      else +      {  y->val = - y->val; +         mpz_add(z, x, y); +         if (y != z) +            y->val = - y->val; +      } +      return; +} + +void mpz_mul(mpz_t z, mpz_t x, mpz_t y) +{     /* set z to x * y */ +      struct mpz_seg dumx, dumy, *ex, *ey, *es, *e; +      int sx, sy, k, nx, ny, n; +      unsigned int t; +      unsigned short *work, *wx, *wy; +      /* if [x] = 0 then [z] = 0 */ +      if (x->val == 0) +      {  xassert(x->ptr == NULL); +         mpz_set_si(z, 0); +         goto done; +      } +      /* if [y] = 0 then [z] = 0 */ +      if (y->val == 0) +      {  xassert(y->ptr == NULL); +         mpz_set_si(z, 0); +         goto done; +      } +      /* special case when both [x] and [y] are in short format */ +      if (x->ptr == NULL && y->ptr == NULL) +      {  int xval = x->val, yval = y->val, sz = +1; +         xassert(xval != 0x80000000 && yval != 0x80000000); +         if (xval < 0) +            xval = - xval, sz = - sz; +         if (yval < 0) +            yval = - yval, sz = - sz; +         if (xval <= 0x7FFFFFFF / yval) +         {  mpz_set_si(z, sz * (xval * yval)); +            goto done; +         } +      } +      /* convert [x] to long format, if necessary */ +      if (x->ptr == NULL) +      {  xassert(x->val != 0x80000000); +         if (x->val >= 0) +         {  sx = +1; +            t = (unsigned int)(+ x->val); +         } +         else +         {  sx = -1; +            t = (unsigned int)(- x->val); +         } +         ex = &dumx; +         ex->d[0] = (unsigned short)t; +         ex->d[1] = (unsigned short)(t >> 16); +         ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0; +         ex->next = NULL; +      } +      else +      {  sx = x->val; +         xassert(sx == +1 || sx == -1); +         ex = x->ptr; +      } +      /* convert [y] to long format, if necessary */ +      if (y->ptr == NULL) +      {  xassert(y->val != 0x80000000); +         if (y->val >= 0) +         {  sy = +1; +            t = (unsigned int)(+ y->val); +         } +         else +         {  sy = -1; +            t = (unsigned int)(- y->val); +         } +         ey = &dumy; +         ey->d[0] = (unsigned short)t; +         ey->d[1] = (unsigned short)(t >> 16); +         ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0; +         ey->next = NULL; +      } +      else +      {  sy = y->val; +         xassert(sy == +1 || sy == -1); +         ey = y->ptr; +      } +      /* determine the number of digits of [x] */ +      nx = n = 0; +      for (e = ex; e != NULL; e = e->next) +      {  for (k = 0; k <= 5; k++) +         {  n++; +            if (e->d[k]) +               nx = n; +         } +      } +      xassert(nx > 0); +      /* determine the number of digits of [y] */ +      ny = n = 0; +      for (e = ey; e != NULL; e = e->next) +      {  for (k = 0; k <= 5; k++) +         {  n++; +            if (e->d[k]) +               ny = n; +         } +      } +      xassert(ny > 0); +      /* we need working array containing at least nx+ny+ny places */ +      work = gmp_get_work(nx+ny+ny); +      /* load digits of [x] */ +      wx = &work[0]; +      for (n = 0; n < nx; n++) +         wx[ny+n] = 0; +      for (n = 0, e = ex; e != NULL; e = e->next) +      {  for (k = 0; k <= 5; k++, n++) +         {  if (e->d[k]) +               wx[ny+n] = e->d[k]; +         } +      } +      /* load digits of [y] */ +      wy = &work[nx+ny]; +      for (n = 0; n < ny; n++) wy[n] = 0; +      for (n = 0, e = ey; e != NULL; e = e->next) +      {  for (k = 0; k <= 5; k++, n++) +         {  if (e->d[k]) +               wy[n] = e->d[k]; +         } +      } +      /* compute [x] * [y] */ +      bigmul(nx, ny, wx, wy); +      /* construct and normalize result */ +      mpz_set_si(z, 0); +      z->val = sx * sy; +      es = NULL; +      k = 6; +      for (n = 0; n < nx+ny; n++) +      {  if (k > 5) +         {  e = gmp_get_atom(sizeof(struct mpz_seg)); +            e->d[0] = e->d[1] = e->d[2] = 0; +            e->d[3] = e->d[4] = e->d[5] = 0; +            e->next = NULL; +            if (z->ptr == NULL) +               z->ptr = e; +            else +               es->next = e; +            es = e; +            k = 0; +         } +         es->d[k++] = wx[n]; +      } +      normalize(z); +done: return; +} + +void mpz_neg(mpz_t z, mpz_t x) +{     /* set z to 0 - x */ +      mpz_set(z, x); +      z->val = - z->val; +      return; +} + +void mpz_abs(mpz_t z, mpz_t x) +{     /* set z to the absolute value of x */ +      mpz_set(z, x); +      if (z->val < 0) +         z->val = - z->val; +      return; +} + +void mpz_div(mpz_t q, mpz_t r, mpz_t x, mpz_t y) +{     /* divide x by y, forming quotient q and/or remainder r +       * if q = NULL then quotient is not stored; if r = NULL then +       * remainder is not stored +       * the sign of quotient is determined as in algebra while the +       * sign of remainder is the same as the sign of dividend: +       * +26 : +7 = +3, remainder is +5 +       * -26 : +7 = -3, remainder is -5 +       * +26 : -7 = -3, remainder is +5 +       * -26 : -7 = +3, remainder is -5 */ +      struct mpz_seg dumx, dumy, *ex, *ey, *es, *e; +      int sx, sy, k, nx, ny, n; +      unsigned int t; +      unsigned short *work, *wx, *wy; +      /* divide by zero is not allowed */ +      if (y->val == 0) +      {  xassert(y->ptr == NULL); +         xerror("mpz_div: divide by zero not allowed\n"); +      } +      /* if [x] = 0 then [q] = [r] = 0 */ +      if (x->val == 0) +      {  xassert(x->ptr == NULL); +         if (q != NULL) +            mpz_set_si(q, 0); +         if (r != NULL) +            mpz_set_si(r, 0); +         goto done; +      } +      /* special case when both [x] and [y] are in short format */ +      if (x->ptr == NULL && y->ptr == NULL) +      {  int xval = x->val, yval = y->val; +         xassert(xval != 0x80000000 && yval != 0x80000000); +         /* FIXME: use div function */ +         if (q != NULL) +            mpz_set_si(q, xval / yval); +         if (r != NULL) +            mpz_set_si(r, xval % yval); +         goto done; +      } +      /* convert [x] to long format, if necessary */ +      if (x->ptr == NULL) +      {  xassert(x->val != 0x80000000); +         if (x->val >= 0) +         {  sx = +1; +            t = (unsigned int)(+ x->val); +         } +         else +         {  sx = -1; +            t = (unsigned int)(- x->val); +         } +         ex = &dumx; +         ex->d[0] = (unsigned short)t; +         ex->d[1] = (unsigned short)(t >> 16); +         ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0; +         ex->next = NULL; +      } +      else +      {  sx = x->val; +         xassert(sx == +1 || sx == -1); +         ex = x->ptr; +      } +      /* convert [y] to long format, if necessary */ +      if (y->ptr == NULL) +      {  xassert(y->val != 0x80000000); +         if (y->val >= 0) +         {  sy = +1; +            t = (unsigned int)(+ y->val); +         } +         else +         {  sy = -1; +            t = (unsigned int)(- y->val); +         } +         ey = &dumy; +         ey->d[0] = (unsigned short)t; +         ey->d[1] = (unsigned short)(t >> 16); +         ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0; +         ey->next = NULL; +      } +      else +      {  sy = y->val; +         xassert(sy == +1 || sy == -1); +         ey = y->ptr; +      } +      /* determine the number of digits of [x] */ +      nx = n = 0; +      for (e = ex; e != NULL; e = e->next) +      {  for (k = 0; k <= 5; k++) +         {  n++; +            if (e->d[k]) +               nx = n; +         } +      } +      xassert(nx > 0); +      /* determine the number of digits of [y] */ +      ny = n = 0; +      for (e = ey; e != NULL; e = e->next) +      {  for (k = 0; k <= 5; k++) +         {  n++; +            if (e->d[k]) +               ny = n; +         } +      } +      xassert(ny > 0); +      /* if nx < ny then [q] = 0 and [r] = [x] */ +      if (nx < ny) +      {  if (r != NULL) +            mpz_set(r, x); +         if (q != NULL) +            mpz_set_si(q, 0); +         goto done; +      } +      /* we need working array containing at least nx+ny+1 places */ +      work = gmp_get_work(nx+ny+1); +      /* load digits of [x] */ +      wx = &work[0]; +      for (n = 0; n < nx; n++) +         wx[n] = 0; +      for (n = 0, e = ex; e != NULL; e = e->next) +      {  for (k = 0; k <= 5; k++, n++) +            if (e->d[k]) wx[n] = e->d[k]; +      } +      /* load digits of [y] */ +      wy = &work[nx+1]; +      for (n = 0; n < ny; n++) +         wy[n] = 0; +      for (n = 0, e = ey; e != NULL; e = e->next) +      {  for (k = 0; k <= 5; k++, n++) +            if (e->d[k]) wy[n] = e->d[k]; +      } +      /* compute quotient and remainder */ +      xassert(wy[ny-1] != 0); +      bigdiv(nx-ny, ny, wx, wy); +      /* construct and normalize quotient */ +      if (q != NULL) +      {  mpz_set_si(q, 0); +         q->val = sx * sy; +         es = NULL; +         k = 6; +         for (n = ny; n <= nx; n++) +         {  if (k > 5) +            {  e = gmp_get_atom(sizeof(struct mpz_seg)); +               e->d[0] = e->d[1] = e->d[2] = 0; +               e->d[3] = e->d[4] = e->d[5] = 0; +               e->next = NULL; +               if (q->ptr == NULL) +                  q->ptr = e; +               else +                  es->next = e; +               es = e; +               k = 0; +            } +            es->d[k++] = wx[n]; +         } +         normalize(q); +      } +      /* construct and normalize remainder */ +      if (r != NULL) +      {  mpz_set_si(r, 0); +         r->val = sx; +         es = NULL; +         k = 6; +         for (n = 0; n < ny; n++) +         {  if (k > 5) +            {  e = gmp_get_atom(sizeof(struct mpz_seg)); +               e->d[0] = e->d[1] = e->d[2] = 0; +               e->d[3] = e->d[4] = e->d[5] = 0; +               e->next = NULL; +               if (r->ptr == NULL) +                  r->ptr = e; +               else +                  es->next = e; +               es = e; +               k = 0; +            } +            es->d[k++] = wx[n]; +         } +         normalize(r); +      } +done: return; +} + +void mpz_gcd(mpz_t z, mpz_t x, mpz_t y) +{     /* set z to the greatest common divisor of x and y */ +      /* in case of arbitrary integers GCD(x, y) = GCD(|x|, |y|), and, +       * in particular, GCD(0, 0) = 0 */ +      mpz_t u, v, r; +      mpz_init(u); +      mpz_init(v); +      mpz_init(r); +      mpz_abs(u, x); +      mpz_abs(v, y); +      while (mpz_sgn(v)) +      {  mpz_div(NULL, r, u, v); +         mpz_set(u, v); +         mpz_set(v, r); +      } +      mpz_set(z, u); +      mpz_clear(u); +      mpz_clear(v); +      mpz_clear(r); +      return; +} + +int mpz_cmp(mpz_t x, mpz_t y) +{     /* compare x and y; return a positive value if x > y, zero if +       * x = y, or a nefative value if x < y */ +      static struct mpz_seg zero = { { 0, 0, 0, 0, 0, 0 }, NULL }; +      struct mpz_seg dumx, dumy, *ex, *ey; +      int cc, sx, sy, k; +      unsigned int t; +      if (x == y) +      {  cc = 0; +         goto done; +      } +      /* special case when both [x] and [y] are in short format */ +      if (x->ptr == NULL && y->ptr == NULL) +      {  int xval = x->val, yval = y->val; +         xassert(xval != 0x80000000 && yval != 0x80000000); +         cc = (xval > yval ? +1 : xval < yval ? -1 : 0); +         goto done; +      } +      /* special case when [x] and [y] have different signs */ +      if (x->val > 0 && y->val <= 0 || x->val == 0 && y->val < 0) +      {  cc = +1; +         goto done; +      } +      if (x->val < 0 && y->val >= 0 || x->val == 0 && y->val > 0) +      {  cc = -1; +         goto done; +      } +      /* convert [x] to long format, if necessary */ +      if (x->ptr == NULL) +      {  xassert(x->val != 0x80000000); +         if (x->val >= 0) +         {  sx = +1; +            t = (unsigned int)(+ x->val); +         } +         else +         {  sx = -1; +            t = (unsigned int)(- x->val); +         } +         ex = &dumx; +         ex->d[0] = (unsigned short)t; +         ex->d[1] = (unsigned short)(t >> 16); +         ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0; +         ex->next = NULL; +      } +      else +      {  sx = x->val; +         xassert(sx == +1 || sx == -1); +         ex = x->ptr; +      } +      /* convert [y] to long format, if necessary */ +      if (y->ptr == NULL) +      {  xassert(y->val != 0x80000000); +         if (y->val >= 0) +         {  sy = +1; +            t = (unsigned int)(+ y->val); +         } +         else +         {  sy = -1; +            t = (unsigned int)(- y->val); +         } +         ey = &dumy; +         ey->d[0] = (unsigned short)t; +         ey->d[1] = (unsigned short)(t >> 16); +         ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0; +         ey->next = NULL; +      } +      else +      {  sy = y->val; +         xassert(sy == +1 || sy == -1); +         ey = y->ptr; +      } +      /* main fragment */ +      xassert(sx > 0 && sy > 0 || sx < 0 && sy < 0); +      cc = 0; +      for (; ex || ey; ex = ex->next, ey = ey->next) +      {  if (ex == NULL) +            ex = &zero; +         if (ey == NULL) +            ey = &zero; +         for (k = 0; k <= 5; k++) +         {  if (ex->d[k] > ey->d[k]) +               cc = +1; +            if (ex->d[k] < ey->d[k]) +               cc = -1; +         } +      } +      if (sx < 0) cc = - cc; +done: return cc; +} + +int mpz_sgn(mpz_t x) +{     /* return +1 if x > 0, 0 if x = 0, and -1 if x < 0 */ +      int s; +      s = (x->val > 0 ? +1 : x->val < 0 ? -1 : 0); +      return s; +} + +int mpz_out_str(void *_fp, int base, mpz_t x) +{     /* output x on stream fp, as a string in given base; the base +       * may vary from 2 to 36; +       * return the number of bytes written, or if an error occurred, +       * return 0 */ +      FILE *fp = _fp; +      mpz_t b, y, r; +      int n, j, nwr = 0; +      unsigned char *d; +      static char *set = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +      if (!(2 <= base && base <= 36)) +         xerror("mpz_out_str: base = %d; invalid base\n", base); +      mpz_init(b); +      mpz_set_si(b, base); +      mpz_init(y); +      mpz_init(r); +      /* determine the number of digits */ +      mpz_abs(y, x); +      for (n = 0; mpz_sgn(y) != 0; n++) +         mpz_div(y, NULL, y, b); +      if (n == 0) n = 1; +      /* compute the digits */ +      d = xmalloc(n); +      mpz_abs(y, x); +      for (j = 0; j < n; j++) +      {  mpz_div(y, r, y, b); +         xassert(0 <= r->val && r->val < base && r->ptr == NULL); +         d[j] = (unsigned char)r->val; +      } +      /* output the integer to the stream */ +      if (fp == NULL) +         fp = stdout; +      if (mpz_sgn(x) < 0) +         fputc('-', fp), nwr++; +      for (j = n-1; j >= 0; j--) +         fputc(set[d[j]], fp), nwr++; +      if (ferror(fp)) +         nwr = 0; +      mpz_clear(b); +      mpz_clear(y); +      mpz_clear(r); +      xfree(d); +      return nwr; +} + +/*--------------------------------------------------------------------*/ + +mpq_t _mpq_init(void) +{     /* initialize x, and set its value to 0/1 */ +      mpq_t x; +      x = gmp_get_atom(sizeof(struct mpq)); +      x->p.val = 0; +      x->p.ptr = NULL; +      x->q.val = 1; +      x->q.ptr = NULL; +      return x; +} + +void mpq_clear(mpq_t x) +{     /* free the space occupied by x */ +      mpz_set_si(&x->p, 0); +      xassert(x->p.ptr == NULL); +      mpz_set_si(&x->q, 0); +      xassert(x->q.ptr == NULL); +      /* free the number descriptor */ +      gmp_free_atom(x, sizeof(struct mpq)); +      return; +} + +void mpq_canonicalize(mpq_t x) +{     /* remove any factors that are common to the numerator and +       * denominator of x, and make the denominator positive */ +      mpz_t f; +      xassert(x->q.val != 0); +      if (x->q.val < 0) +      {  mpz_neg(&x->p, &x->p); +         mpz_neg(&x->q, &x->q); +      } +      mpz_init(f); +      mpz_gcd(f, &x->p, &x->q); +      if (!(f->val == 1 && f->ptr == NULL)) +      {  mpz_div(&x->p, NULL, &x->p, f); +         mpz_div(&x->q, NULL, &x->q, f); +      } +      mpz_clear(f); +      return; +} + +void mpq_set(mpq_t z, mpq_t x) +{     /* set the value of z from x */ +      if (z != x) +      {  mpz_set(&z->p, &x->p); +         mpz_set(&z->q, &x->q); +      } +      return; +} + +void mpq_set_si(mpq_t x, int p, unsigned int q) +{     /* set the value of x to p/q */ +      if (q == 0) +         xerror("mpq_set_si: zero denominator not allowed\n"); +      mpz_set_si(&x->p, p); +      xassert(q <= 0x7FFFFFFF); +      mpz_set_si(&x->q, q); +      return; +} + +double mpq_get_d(mpq_t x) +{     /* convert x to a double, truncating if necessary */ +      int np, nq; +      double p, q; +      p = mpz_get_d_2exp(&np, &x->p); +      q = mpz_get_d_2exp(&nq, &x->q); +      return ldexp(p / q, np - nq); +} + +void mpq_set_d(mpq_t x, double val) +{     /* set x to val; there is no rounding, the conversion is exact */ +      int s, n, d, j; +      double f; +      mpz_t temp; +      xassert(-DBL_MAX <= val && val <= +DBL_MAX); +      mpq_set_si(x, 0, 1); +      if (val > 0.0) +         s = +1; +      else if (val < 0.0) +         s = -1; +      else +         goto done; +      f = frexp(fabs(val), &n); +      /* |val| = f * 2^n, where 0.5 <= f < 1.0 */ +      mpz_init(temp); +      while (f != 0.0) +      {  f *= 16.0, n -= 4; +         d = (int)f; +         xassert(0 <= d && d <= 15); +         f -= (double)d; +         /* x := 16 * x + d */ +         mpz_set_si(temp, 16); +         mpz_mul(&x->p, &x->p, temp); +         mpz_set_si(temp, d); +         mpz_add(&x->p, &x->p, temp); +      } +      mpz_clear(temp); +      /* x := x * 2^n */ +      if (n > 0) +      {  for (j = 1; j <= n; j++) +            mpz_add(&x->p, &x->p, &x->p); +      } +      else if (n < 0) +      {  for (j = 1; j <= -n; j++) +            mpz_add(&x->q, &x->q, &x->q); +         mpq_canonicalize(x); +      } +      if (s < 0) +         mpq_neg(x, x); +done: return; +} + +void mpq_add(mpq_t z, mpq_t x, mpq_t y) +{     /* set z to x + y */ +      mpz_t p, q; +      mpz_init(p); +      mpz_init(q); +      mpz_mul(p, &x->p, &y->q); +      mpz_mul(q, &x->q, &y->p); +      mpz_add(p, p, q); +      mpz_mul(q, &x->q, &y->q); +      mpz_set(&z->p, p); +      mpz_set(&z->q, q); +      mpz_clear(p); +      mpz_clear(q); +      mpq_canonicalize(z); +      return; +} + +void mpq_sub(mpq_t z, mpq_t x, mpq_t y) +{     /* set z to x - y */ +      mpz_t p, q; +      mpz_init(p); +      mpz_init(q); +      mpz_mul(p, &x->p, &y->q); +      mpz_mul(q, &x->q, &y->p); +      mpz_sub(p, p, q); +      mpz_mul(q, &x->q, &y->q); +      mpz_set(&z->p, p); +      mpz_set(&z->q, q); +      mpz_clear(p); +      mpz_clear(q); +      mpq_canonicalize(z); +      return; +} + +void mpq_mul(mpq_t z, mpq_t x, mpq_t y) +{     /* set z to x * y */ +      mpz_mul(&z->p, &x->p, &y->p); +      mpz_mul(&z->q, &x->q, &y->q); +      mpq_canonicalize(z); +      return; +} + +void mpq_div(mpq_t z, mpq_t x, mpq_t y) +{     /* set z to x / y */ +      mpz_t p, q; +      if (mpq_sgn(y) == 0) +         xerror("mpq_div: zero divisor not allowed\n"); +      mpz_init(p); +      mpz_init(q); +      mpz_mul(p, &x->p, &y->q); +      mpz_mul(q, &x->q, &y->p); +      mpz_set(&z->p, p); +      mpz_set(&z->q, q); +      mpz_clear(p); +      mpz_clear(q); +      mpq_canonicalize(z); +      return; +} + +void mpq_neg(mpq_t z, mpq_t x) +{     /* set z to 0 - x */ +      mpq_set(z, x); +      mpz_neg(&z->p, &z->p); +      return; +} + +void mpq_abs(mpq_t z, mpq_t x) +{     /* set z to the absolute value of x */ +      mpq_set(z, x); +      mpz_abs(&z->p, &z->p); +      xassert(mpz_sgn(&x->q) > 0); +      return; +} + +int mpq_cmp(mpq_t x, mpq_t y) +{     /* compare x and y; return a positive value if x > y, zero if +       * x = y, or a negative value if x < y */ +      mpq_t temp; +      int s; +      mpq_init(temp); +      mpq_sub(temp, x, y); +      s = mpq_sgn(temp); +      mpq_clear(temp); +      return s; +} + +int mpq_sgn(mpq_t x) +{     /* return +1 if x > 0, 0 if x = 0, and -1 if x < 0 */ +      int s; +      s = mpz_sgn(&x->p); +      xassert(mpz_sgn(&x->q) > 0); +      return s; +} + +int mpq_out_str(void *_fp, int base, mpq_t x) +{     /* output x on stream fp, as a string in given base; the base +       * may vary from 2 to 36; output is in the form 'num/den' or if +       * the denominator is 1 then just 'num'; +       * if the parameter fp is a null pointer, stdout is assumed; +       * return the number of bytes written, or if an error occurred, +       * return 0 */ +      FILE *fp = _fp; +      int nwr; +      if (!(2 <= base && base <= 36)) +         xerror("mpq_out_str: base = %d; invalid base\n", base); +      if (fp == NULL) +         fp = stdout; +      nwr = mpz_out_str(fp, base, &x->p); +      if (x->q.val == 1 && x->q.ptr == NULL) +         ; +      else +      {  fputc('/', fp), nwr++; +         nwr += mpz_out_str(fp, base, &x->q); +      } +      if (ferror(fp)) +         nwr = 0; +      return nwr; +} + +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/mygmp.h b/glpk-5.0/src/misc/mygmp.h new file mode 100644 index 0000000..a0a87ec --- /dev/null +++ b/glpk-5.0/src/misc/mygmp.h @@ -0,0 +1,252 @@ +/* mygmp.h (integer and rational arithmetic) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2008-2015 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#ifndef MYGMP_H +#define MYGMP_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef HAVE_GMP               /* use GNU MP library */ + +#include <gmp.h> + +#define gmp_pool_count() 0 + +#define gmp_free_mem() ((void)0) + +#else                         /* use GLPK MP module */ + +/*********************************************************************** +*  INTEGER NUMBERS +*  --------------- +*  Depending on its magnitude an integer number of arbitrary precision +*  is represented either in short format or in long format. +* +*  Short format corresponds to the int type and allows representing +*  integer numbers in the range [-(2^31-1), +(2^31-1)]. Note that for +*  the most negative number of int type the short format is not used. +* +*  In long format integer numbers are represented using the positional +*  system with the base (radix) 2^16 = 65536: +* +*     x = (-1)^s sum{j in 0..n-1} d[j] * 65536^j, +* +*  where x is the integer to be represented, s is its sign (+1 or -1), +*  d[j] are its digits (0 <= d[j] <= 65535). +* +*  RATIONAL NUMBERS +*  ---------------- +*  A rational number is represented as an irreducible fraction: +* +*     p / q, +* +*  where p (numerator) and q (denominator) are integer numbers (q > 0) +*  having no common divisors. */ + +struct mpz +{     /* integer number */ +      int val; +      /* if ptr is a null pointer, the number is in short format, and +         val is its value; otherwise, the number is in long format, and +         val is its sign (+1 or -1) */ +      struct mpz_seg *ptr; +      /* pointer to the linked list of the number segments ordered in +         ascending of powers of the base */ +}; + +struct mpz_seg +{     /* integer number segment */ +      unsigned short d[6]; +      /* six digits of the number ordered in ascending of powers of the +         base */ +      struct mpz_seg *next; +      /* pointer to the next number segment */ +}; + +struct mpq +{     /* rational number (p / q) */ +      struct mpz p; +      /* numerator */ +      struct mpz q; +      /* denominator */ +}; + +typedef struct mpz *mpz_t; +typedef struct mpq *mpq_t; + +#define gmp_get_atom _glp_gmp_get_atom +void *gmp_get_atom(int size); + +#define gmp_free_atom _glp_gmp_free_atom +void gmp_free_atom(void *ptr, int size); + +#define gmp_pool_count _glp_gmp_pool_count +int gmp_pool_count(void); + +#define gmp_get_work _glp_gmp_get_work +unsigned short *gmp_get_work(int size); + +#define gmp_free_mem _glp_gmp_free_mem +void gmp_free_mem(void); + +#define mpz_init(x) (void)((x) = _mpz_init()) + +#define _mpz_init _glp_mpz_init +mpz_t _mpz_init(void); +/* initialize x and set its value to 0 */ + +#define mpz_clear _glp_mpz_clear +void mpz_clear(mpz_t x); +/* free the space occupied by x */ + +#define mpz_set _glp_mpz_set +void mpz_set(mpz_t z, mpz_t x); +/* set the value of z from x */ + +#define mpz_set_si _glp_mpz_set_si +void mpz_set_si(mpz_t x, int val); +/* set the value of x to val */ + +#define mpz_get_d _glp_mpz_get_d +double mpz_get_d(mpz_t x); +/* convert x to a double, truncating if necessary */ + +#define mpz_get_d_2exp _glp_mpz_get_d_2exp +double mpz_get_d_2exp(int *exp, mpz_t x); +/* convert x to a double, returning the exponent separately */ + +#define mpz_swap _glp_mpz_swap +void mpz_swap(mpz_t x, mpz_t y); +/* swap the values x and y efficiently */ + +#define mpz_add _glp_mpz_add +void mpz_add(mpz_t, mpz_t, mpz_t); +/* set z to x + y */ + +#define mpz_sub _glp_mpz_sub +void mpz_sub(mpz_t, mpz_t, mpz_t); +/* set z to x - y */ + +#define mpz_mul _glp_mpz_mul +void mpz_mul(mpz_t, mpz_t, mpz_t); +/* set z to x * y */ + +#define mpz_neg _glp_mpz_neg +void mpz_neg(mpz_t z, mpz_t x); +/* set z to 0 - x */ + +#define mpz_abs _glp_mpz_abs +void mpz_abs(mpz_t z, mpz_t x); +/* set z to the absolute value of x */ + +#define mpz_div _glp_mpz_div +void mpz_div(mpz_t q, mpz_t r, mpz_t x, mpz_t y); +/* divide x by y, forming quotient q and/or remainder r */ + +#define mpz_gcd _glp_mpz_gcd +void mpz_gcd(mpz_t z, mpz_t x, mpz_t y); +/* set z to the greatest common divisor of x and y */ + +#define mpz_cmp _glp_mpz_cmp +int mpz_cmp(mpz_t x, mpz_t y); +/* compare x and y */ + +#define mpz_sgn _glp_mpz_sgn +int mpz_sgn(mpz_t x); +/* return +1 if x > 0, 0 if x = 0, and -1 if x < 0 */ + +#define mpz_out_str _glp_mpz_out_str +int mpz_out_str(void *fp, int base, mpz_t x); +/* output x on stream fp, as a string in given base */ + +#define mpq_init(x) (void)((x) = _mpq_init()) + +#define _mpq_init _glp_mpq_init +mpq_t _mpq_init(void); +/* initialize x, and set its value to 0/1 */ + +#define mpq_clear _glp_mpq_clear +void mpq_clear(mpq_t x); +/* free the space occupied by x */ + +#define mpq_canonicalize _glp_mpq_canonicalize +void mpq_canonicalize(mpq_t x); +/* canonicalize x */ + +#define mpq_set _glp_mpq_set +void mpq_set(mpq_t z, mpq_t x); +/* set the value of z from x */ + +#define mpq_set_si _glp_mpq_set_si +void mpq_set_si(mpq_t x, int p, unsigned int q); +/* set the value of x to p/q */ + +#define mpq_get_d _glp_mpq_get_d +double mpq_get_d(mpq_t x); +/* convert x to a double, truncating if necessary */ + +#define mpq_set_d _glp_mpq_set_d +void mpq_set_d(mpq_t x, double val); +/* set x to val; there is no rounding, the conversion is exact */ + +#define mpq_add _glp_mpq_add +void mpq_add(mpq_t z, mpq_t x, mpq_t y); +/* set z to x + y */ + +#define mpq_sub _glp_mpq_sub +void mpq_sub(mpq_t z, mpq_t x, mpq_t y); +/* set z to x - y */ + +#define mpq_mul _glp_mpq_mul +void mpq_mul(mpq_t z, mpq_t x, mpq_t y); +/* set z to x * y */ + +#define mpq_div _glp_mpq_div +void mpq_div(mpq_t z, mpq_t x, mpq_t y); +/* set z to x / y */ + +#define mpq_neg _glp_mpq_neg +void mpq_neg(mpq_t z, mpq_t x); +/* set z to 0 - x */ + +#define mpq_abs _glp_mpq_abs +void mpq_abs(mpq_t z, mpq_t x); +/* set z to the absolute value of x */ + +#define mpq_cmp _glp_mpq_cmp +int mpq_cmp(mpq_t x, mpq_t y); +/* compare x and y */ + +#define mpq_sgn _glp_mpq_sgn +int mpq_sgn(mpq_t x); +/* return +1 if x > 0, 0 if x = 0, and -1 if x < 0 */ + +#define mpq_out_str _glp_mpq_out_str +int mpq_out_str(void *fp, int base, mpq_t x); +/* output x on stream fp, as a string in given base */ + +#endif + +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/okalg.c b/glpk-5.0/src/misc/okalg.c new file mode 100644 index 0000000..788f5b3 --- /dev/null +++ b/glpk-5.0/src/misc/okalg.c @@ -0,0 +1,380 @@ +/* okalg.c (out-of-kilter algorithm) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2013 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "okalg.h" + +/*********************************************************************** +*  NAME +* +*  okalg - out-of-kilter algorithm +* +*  SYNOPSIS +* +*  #include "okalg.h" +*  int okalg(int nv, int na, const int tail[], const int head[], +*     const int low[], const int cap[], const int cost[], int x[], +*     int pi[]); +* +*  DESCRIPTION +* +*  The routine okalg implements the out-of-kilter algorithm to find a +*  minimal-cost circulation in the specified flow network. +* +*  INPUT PARAMETERS +* +*  nv is the number of nodes, nv >= 0. +* +*  na is the number of arcs, na >= 0. +* +*  tail[a], a = 1,...,na, is the index of tail node of arc a. +* +*  head[a], a = 1,...,na, is the index of head node of arc a. +* +*  low[a], a = 1,...,na, is an lower bound to the flow through arc a. +* +*  cap[a], a = 1,...,na, is an upper bound to the flow through arc a, +*  which is the capacity of the arc. +* +*  cost[a], a = 1,...,na, is a per-unit cost of the flow through arc a. +* +*  NOTES +* +*  1. Multiple arcs are allowed, but self-loops are not allowed. +* +*  2. It is required that 0 <= low[a] <= cap[a] for all arcs. +* +*  3. Arc costs may have any sign. +* +*  OUTPUT PARAMETERS +* +*  x[a], a = 1,...,na, is optimal value of the flow through arc a. +* +*  pi[i], i = 1,...,nv, is Lagrange multiplier for flow conservation +*  equality constraint corresponding to node i (the node potential). +* +*  RETURNS +* +*  0  optimal circulation found; +* +*  1  there is no feasible circulation; +* +*  2  integer overflow occured; +* +*  3  optimality test failed (logic error). +* +*  REFERENCES +* +*  L.R.Ford, Jr., and D.R.Fulkerson, "Flows in Networks," The RAND +*  Corp., Report R-375-PR (August 1962), Chap. III "Minimal Cost Flow +*  Problems," pp.113-26. */ + +static int overflow(int u, int v) +{     /* check for integer overflow on computing u + v */ +      if (u > 0 && v > 0 && u + v < 0) return 1; +      if (u < 0 && v < 0 && u + v > 0) return 1; +      return 0; +} + +int okalg(int nv, int na, const int tail[], const int head[], +      const int low[], const int cap[], const int cost[], int x[], +      int pi[]) +{     int a, aok, delta, i, j, k, lambda, pos1, pos2, s, t, temp, ret, +         *ptr, *arc, *link, *list; +      /* sanity checks */ +      xassert(nv >= 0); +      xassert(na >= 0); +      for (a = 1; a <= na; a++) +      {  i = tail[a], j = head[a]; +         xassert(1 <= i && i <= nv); +         xassert(1 <= j && j <= nv); +         xassert(i != j); +         xassert(0 <= low[a] && low[a] <= cap[a]); +      } +      /* allocate working arrays */ +      ptr = xcalloc(1+nv+1, sizeof(int)); +      arc = xcalloc(1+na+na, sizeof(int)); +      link = xcalloc(1+nv, sizeof(int)); +      list = xcalloc(1+nv, sizeof(int)); +      /* ptr[i] := (degree of node i) */ +      for (i = 1; i <= nv; i++) +         ptr[i] = 0; +      for (a = 1; a <= na; a++) +      {  ptr[tail[a]]++; +         ptr[head[a]]++; +      } +      /* initialize arc pointers */ +      ptr[1]++; +      for (i = 1; i < nv; i++) +         ptr[i+1] += ptr[i]; +      ptr[nv+1] = ptr[nv]; +      /* build arc lists */ +      for (a = 1; a <= na; a++) +      {  arc[--ptr[tail[a]]] = a; +         arc[--ptr[head[a]]] = a; +      } +      xassert(ptr[1] == 1); +      xassert(ptr[nv+1] == na+na+1); +      /* now the indices of arcs incident to node i are stored in +       * locations arc[ptr[i]], arc[ptr[i]+1], ..., arc[ptr[i+1]-1] */ +      /* initialize arc flows and node potentials */ +      for (a = 1; a <= na; a++) +         x[a] = 0; +      for (i = 1; i <= nv; i++) +         pi[i] = 0; +loop: /* main loop starts here */ +      /* find out-of-kilter arc */ +      aok = 0; +      for (a = 1; a <= na; a++) +      {  i = tail[a], j = head[a]; +         if (overflow(cost[a], pi[i] - pi[j])) +         {  ret = 2; +            goto done; +         } +         lambda = cost[a] + (pi[i] - pi[j]); +         if (x[a] < low[a] || (lambda < 0 && x[a] < cap[a])) +         {  /* arc a = i->j is out of kilter, and we need to increase +             * the flow through this arc */ +            aok = a, s = j, t = i; +            break; +         } +         if (x[a] > cap[a] || (lambda > 0 && x[a] > low[a])) +         {  /* arc a = i->j is out of kilter, and we need to decrease +             * the flow through this arc */ +            aok = a, s = i, t = j; +            break; +         } +      } +      if (aok == 0) +      {  /* all arcs are in kilter */ +         /* check for feasibility */ +         for (a = 1; a <= na; a++) +         {  if (!(low[a] <= x[a] && x[a] <= cap[a])) +            {  ret = 3; +               goto done; +            } +         } +         for (i = 1; i <= nv; i++) +         {  temp = 0; +            for (k = ptr[i]; k < ptr[i+1]; k++) +            {  a = arc[k]; +               if (tail[a] == i) +               {  /* a is outgoing arc */ +                  temp += x[a]; +               } +               else if (head[a] == i) +               {  /* a is incoming arc */ +                  temp -= x[a]; +               } +               else +                  xassert(a != a); +            } +            if (temp != 0) +            {  ret = 3; +               goto done; +            } +         } +         /* check for optimality */ +         for (a = 1; a <= na; a++) +         {  i = tail[a], j = head[a]; +            lambda = cost[a] + (pi[i] - pi[j]); +            if ((lambda > 0 && x[a] != low[a]) || +                (lambda < 0 && x[a] != cap[a])) +            {  ret = 3; +               goto done; +            } +         } +         /* current circulation is optimal */ +         ret = 0; +         goto done; +      } +      /* now we need to find a cycle (t, a, s, ..., t), which allows +       * increasing the flow along it, where a is the out-of-kilter arc +       * just found */ +      /* link[i] = 0 means that node i is not labelled yet; +       * link[i] = a means that arc a immediately precedes node i */ +      /* initially only node s is labelled */ +      for (i = 1; i <= nv; i++) +         link[i] = 0; +      link[s] = aok, list[1] = s, pos1 = pos2 = 1; +      /* breadth first search */ +      while (pos1 <= pos2) +      {  /* dequeue node i */ +         i = list[pos1++]; +         /* consider all arcs incident to node i */ +         for (k = ptr[i]; k < ptr[i+1]; k++) +         {  a = arc[k]; +            if (tail[a] == i) +            {  /* a = i->j is a forward arc from s to t */ +               j = head[a]; +               /* if node j has been labelled, skip the arc */ +               if (link[j] != 0) continue; +               /* if the arc does not allow increasing the flow through +                * it, skip the arc */ +               if (x[a] >= cap[a]) continue; +               if (overflow(cost[a], pi[i] - pi[j])) +               {  ret = 2; +                  goto done; +               } +               lambda = cost[a] + (pi[i] - pi[j]); +               if (lambda > 0 && x[a] >= low[a]) continue; +            } +            else if (head[a] == i) +            {  /* a = i<-j is a backward arc from s to t */ +               j = tail[a]; +               /* if node j has been labelled, skip the arc */ +               if (link[j] != 0) continue; +               /* if the arc does not allow decreasing the flow through +                * it, skip the arc */ +               if (x[a] <= low[a]) continue; +               if (overflow(cost[a], pi[j] - pi[i])) +               {  ret = 2; +                  goto done; +               } +               lambda = cost[a] + (pi[j] - pi[i]); +               if (lambda < 0 && x[a] <= cap[a]) continue; +            } +            else +               xassert(a != a); +            /* label node j and enqueue it */ +            link[j] = a, list[++pos2] = j; +            /* check for breakthrough */ +            if (j == t) goto brkt; +         } +      } +      /* NONBREAKTHROUGH */ +      /* consider all arcs, whose one endpoint is labelled and other is +       * not, and determine maximal change of node potentials */ +      delta = 0; +      for (a = 1; a <= na; a++) +      {  i = tail[a], j = head[a]; +         if (link[i] != 0 && link[j] == 0) +         {  /* a = i->j, where node i is labelled, node j is not */ +            if (overflow(cost[a], pi[i] - pi[j])) +            {  ret = 2; +               goto done; +            } +            lambda = cost[a] + (pi[i] - pi[j]); +            if (x[a] <= cap[a] && lambda > 0) +               if (delta == 0 || delta > + lambda) delta = + lambda; +         } +         else if (link[i] == 0 && link[j] != 0) +         {  /* a = j<-i, where node j is labelled, node i is not */ +            if (overflow(cost[a], pi[i] - pi[j])) +            {  ret = 2; +               goto done; +            } +            lambda = cost[a] + (pi[i] - pi[j]); +            if (x[a] >= low[a] && lambda < 0) +               if (delta == 0 || delta > - lambda) delta = - lambda; +         } +      } +      if (delta == 0) +      {  /* there is no feasible circulation */ +         ret = 1; +         goto done; +      } +      /* increase potentials of all unlabelled nodes */ +      for (i = 1; i <= nv; i++) +      {  if (link[i] == 0) +         {  if (overflow(pi[i], delta)) +            {  ret = 2; +               goto done; +            } +            pi[i] += delta; +         } +      } +      goto loop; +brkt: /* BREAKTHROUGH */ +      /* walk through arcs of the cycle (t, a, s, ..., t) found in the +       * reverse order and determine maximal change of the flow */ +      delta = 0; +      for (j = t;; j = i) +      {  /* arc a immediately precedes node j in the cycle */ +         a = link[j]; +         if (head[a] == j) +         {  /* a = i->j is a forward arc of the cycle */ +            i = tail[a]; +            lambda = cost[a] + (pi[i] - pi[j]); +            if (lambda > 0 && x[a] < low[a]) +            {  /* x[a] may be increased until its lower bound */ +               temp = low[a] - x[a]; +            } +            else if (lambda <= 0 && x[a] < cap[a]) +            {  /* x[a] may be increased until its upper bound */ +               temp = cap[a] - x[a]; +            } +            else +               xassert(a != a); +         } +         else if (tail[a] == j) +         {  /* a = i<-j is a backward arc of the cycle */ +            i = head[a]; +            lambda = cost[a] + (pi[j] - pi[i]); +            if (lambda < 0 && x[a] > cap[a]) +            {  /* x[a] may be decreased until its upper bound */ +               temp = x[a] - cap[a]; +            } +            else if (lambda >= 0 && x[a] > low[a]) +            {  /* x[a] may be decreased until its lower bound */ +               temp = x[a] - low[a]; +            } +            else +               xassert(a != a); +         } +         else +            xassert(a != a); +         if (delta == 0 || delta > temp) delta = temp; +         /* check for end of the cycle */ +         if (i == t) break; +      } +      xassert(delta > 0); +      /* increase the flow along the cycle */ +      for (j = t;; j = i) +      {  /* arc a immediately precedes node j in the cycle */ +         a = link[j]; +         if (head[a] == j) +         {  /* a = i->j is a forward arc of the cycle */ +            i = tail[a]; +            /* overflow cannot occur */ +            x[a] += delta; +         } +         else if (tail[a] == j) +         {  /* a = i<-j is a backward arc of the cycle */ +            i = head[a]; +            /* overflow cannot occur */ +            x[a] -= delta; +         } +         else +            xassert(a != a); +         /* check for end of the cycle */ +         if (i == t) break; +      } +      goto loop; +done: /* free working arrays */ +      xfree(ptr); +      xfree(arc); +      xfree(link); +      xfree(list); +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/misc/okalg.h b/glpk-5.0/src/misc/okalg.h new file mode 100644 index 0000000..95fdcf5 --- /dev/null +++ b/glpk-5.0/src/misc/okalg.h @@ -0,0 +1,33 @@ +/* okalg.h (out-of-kilter algorithm) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2013 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#ifndef OKALG_H +#define OKALG_H + +#define okalg _glp_okalg +int okalg(int nv, int na, const int tail[], const int head[], +      const int low[], const int cap[], const int cost[], int x[], +      int pi[]); +/* out-of-kilter algorithm */ + +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/qmd.c b/glpk-5.0/src/misc/qmd.c new file mode 100644 index 0000000..e5cbd5c --- /dev/null +++ b/glpk-5.0/src/misc/qmd.c @@ -0,0 +1,99 @@ +/* qmd.c */ + +#include "env.h" +#include "qmd.h" + +void genqmd(int *neqns, int xadj[], int adjncy[], int perm[], +      int invp[], int deg[], int marker[], int rchset[], int nbrhd[], +      int qsize[], int qlink[], int *nofsub) +{     static const char func[] = "genqmd"; +      xassert(neqns == neqns); +      xassert(xadj == xadj); +      xassert(adjncy == adjncy); +      xassert(perm == perm); +      xassert(invp == invp); +      xassert(deg == deg); +      xassert(marker == marker); +      xassert(rchset == rchset); +      xassert(nbrhd == nbrhd); +      xassert(qsize == qsize); +      xassert(qlink == qlink); +      xassert(nofsub == nofsub); +      xerror("%s: sorry, this routine is temporarily disabled due to li" +         "censing problems\n", func); +      abort(); +} + +void qmdrch(int *root, int xadj[], int adjncy[], int deg[], +      int marker[], int *rchsze, int rchset[], int *nhdsze, +      int nbrhd[]) +{     static const char func[] = "qmdrch"; +      xassert(root == root); +      xassert(xadj == xadj); +      xassert(adjncy == adjncy); +      xassert(deg == deg); +      xassert(marker == marker); +      xassert(rchsze == rchsze); +      xassert(rchset == rchset); +      xassert(nhdsze == nhdsze); +      xassert(nbrhd == nbrhd); +      xerror("%s: sorry, this routine is temporarily disabled due to li" +         "censing problems\n", func); +      abort(); +} + +void qmdqt(int *root, int xadj[], int adjncy[], int marker[], +      int *rchsze, int rchset[], int nbrhd[]) +{     static const char func[] = "qmdqt"; +      xassert(root == root); +      xassert(xadj == xadj); +      xassert(adjncy == adjncy); +      xassert(marker == marker); +      xassert(rchsze == rchsze); +      xassert(rchset == rchset); +      xassert(nbrhd == nbrhd); +      xerror("%s: sorry, this routine is temporarily disabled due to li" +         "censing problems\n", func); +      abort(); +} + +void qmdupd(int xadj[], int adjncy[], int *nlist, int list[], +      int deg[], int qsize[], int qlink[], int marker[], int rchset[], +      int nbrhd[]) +{     static const char func[] = "qmdupd"; +      xassert(xadj == xadj); +      xassert(adjncy == adjncy); +      xassert(nlist == nlist); +      xassert(list == list); +      xassert(deg == deg); +      xassert(qsize == qsize); +      xassert(qlink == qlink); +      xassert(marker == marker); +      xassert(rchset == rchset); +      xassert(nbrhd == nbrhd); +      xerror("%s: sorry, this routine is temporarily disabled due to li" +         "censing problems\n", func); +      abort(); +} + +void qmdmrg(int xadj[], int adjncy[], int deg[], int qsize[], +      int qlink[], int marker[], int *deg0, int *nhdsze, int nbrhd[], +      int rchset[], int ovrlp[]) +{     static const char func[] = "qmdmrg"; +      xassert(xadj == xadj); +      xassert(adjncy == adjncy); +      xassert(deg == deg); +      xassert(qsize == qsize); +      xassert(qlink == qlink); +      xassert(marker == marker); +      xassert(deg0 == deg0); +      xassert(nhdsze == nhdsze); +      xassert(nbrhd == nbrhd); +      xassert(rchset == rchset); +      xassert(ovrlp == ovrlp); +      xerror("%s: sorry, this routine is temporarily disabled due to li" +         "censing problems\n", func); +      abort(); +} + +/* eof */ diff --git a/glpk-5.0/src/misc/qmd.h b/glpk-5.0/src/misc/qmd.h new file mode 100644 index 0000000..6c6f1d2 --- /dev/null +++ b/glpk-5.0/src/misc/qmd.h @@ -0,0 +1,56 @@ +/* qmd.h (quotient minimum degree algorithm) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2001 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#ifndef QMD_H +#define QMD_H + +#define genqmd _glp_genqmd +void genqmd(int *neqns, int xadj[], int adjncy[], int perm[], +      int invp[], int deg[], int marker[], int rchset[], int nbrhd[], +      int qsize[], int qlink[], int *nofsub); +/* GENeral Quotient Minimum Degree algorithm */ + +#define qmdrch _glp_qmdrch +void qmdrch(int *root, int xadj[], int adjncy[], int deg[], +      int marker[], int *rchsze, int rchset[], int *nhdsze, +      int nbrhd[]); +/* Quotient MD ReaCHable set */ + +#define qmdqt _glp_qmdqt +void qmdqt(int *root, int xadj[], int adjncy[], int marker[], +      int *rchsze, int rchset[], int nbrhd[]); +/* Quotient MD Quotient graph Transformation */ + +#define qmdupd _glp_qmdupd +void qmdupd(int xadj[], int adjncy[], int *nlist, int list[], +      int deg[], int qsize[], int qlink[], int marker[], int rchset[], +      int nbrhd[]); +/* Quotient MD UPDate */ + +#define qmdmrg _glp_qmdmrg +void qmdmrg(int xadj[], int adjncy[], int deg[], int qsize[], +      int qlink[], int marker[], int *deg0, int *nhdsze, int nbrhd[], +      int rchset[], int ovrlp[]); +/* Quotient MD MeRGe */ + +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/relax4.c b/glpk-5.0/src/misc/relax4.c new file mode 100644 index 0000000..807cf9c --- /dev/null +++ b/glpk-5.0/src/misc/relax4.c @@ -0,0 +1,23 @@ +/* relax4.c */ + +#include "env.h" +#include "relax4.h" + +int relax4(struct relax4_csa *csa) +{     static const char func[] = "relax4"; +      xassert(csa == csa); +      xerror("%s: sorry, this routine is temporarily disabled due to li" +         "censing problems\n", func); +      abort(); +      return -1; +} + +void relax4_inidat(struct relax4_csa *csa) +{     static const char func[] = "relax4_inidat"; +      xassert(csa == csa); +      xerror("%s: sorry, this routine is temporarily disabled due to li" +         "censing problems\n", func); +      abort(); +} + +/* eof */ diff --git a/glpk-5.0/src/misc/relax4.h b/glpk-5.0/src/misc/relax4.h new file mode 100644 index 0000000..abcef0e --- /dev/null +++ b/glpk-5.0/src/misc/relax4.h @@ -0,0 +1,100 @@ +/* relax4.h */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2012-2013 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#ifndef RELAX4_H +#define RELAX4_H + +struct relax4_csa +{     /* common storage area */ +      /* input parameters --------------------------------------------*/ +      int n; +      /* number of nodes */ +      int na; +      /* number of arcs */ +      int large; +      /* very large int to represent infinity */ +      int repeat; +      /* true if initialization is to be skipped (false otherwise) */ +      int crash; +      /* 0 if default initialization is used +       * 1 if auction initialization is used */ +      int *startn; /* int startn[1+na]; */ +      /* startn[j] = starting node for arc j, j = 1,...,na */ +      int *endn; /* int endn[1+na] */ +      /* endn[j] = ending node for arc j, j = 1,...,na */ +      int *fou; /* int fou[1+n]; */ +      /* fou[i] = first arc out of node i, i = 1,...,n */ +      int *nxtou; /* int nxtou[1+na]; */ +      /* nxtou[j] = next arc out of the starting node of arc j, +       * j = 1,...,na */ +      int *fin; /* int fin[1+n]; */ +      /* fin[i] = first arc into node i, i = 1,...,n */ +      int *nxtin; /* int nxtin[1+na]; */ +      /* nxtin[j] = next arc into the ending node of arc j, +       * j = 1,...,na */ +      /* updated parameters ------------------------------------------*/ +      int *rc; /* int rc[1+na]; */ +      /* rc[j] = reduced cost of arc j, j = 1,...,na */ +      int *u; /* int u[1+na]; */ +      /* u[j] = capacity of arc j on input +       * and (capacity of arc j) - x(j) on output, j = 1,...,na */ +      int *dfct; /* int dfct[1+n]; */ +      /* dfct[i] = demand at node i on input +       * and zero on output, i = 1,...,n */ +      /* output parameters -------------------------------------------*/ +      int *x; /* int x[1+na]; */ +      /* x[j] = flow on arc j, j = 1,...,na */ +      int nmultinode; +      /* number of multinode relaxation iterations in RELAX4 */ +      int iter; +      /* number of relaxation iterations in RELAX4 */ +      int num_augm; +      /* number of flow augmentation steps in RELAX4 */ +      int num_ascnt; +      /* number of multinode ascent steps in RELAX4 */ +      int nsp; +      /* number of auction/shortest path iterations */ +      /* working parameters ------------------------------------------*/ +      int *label; /* int label, tempin, p[1+n]; */ +      int *prdcsr; /* int prdcsr, tempou, price[1+n]; */ +      int *save; /* int save[1+na]; */ +      int *tfstou; /* int tfstou, fpushf[1+n]; */ +      int *tnxtou; /* int tnxtou, nxtpushf[1+na]; */ +      int *tfstin; /* int tfstin, fpushb[1+n]; */ +      int *tnxtin; /* int tnxtin, nxtpushb[1+na]; */ +      int *nxtqueue; /* int nxtqueue[1+n]; */ +      char *scan; /* bool scan[1+n]; */ +      char *mark; /* bool mark, path_id[1+n]; */ +      /* working parameters used by routine auction only -------------*/ +      int *extend_arc; /* int extend_arc[1+n]; */ +      int *sb_level; /* int sb_level[1+n]; */ +      int *sb_arc; /* int sb_arc[1+n]; */ +}; + +#define relax4 _glp_relax4 +int relax4(struct relax4_csa *csa); + +#define relax4_inidat _glp_relax4_inidat +void relax4_inidat(struct relax4_csa *csa); + +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/rgr.c b/glpk-5.0/src/misc/rgr.c new file mode 100644 index 0000000..f2dc371 --- /dev/null +++ b/glpk-5.0/src/misc/rgr.c @@ -0,0 +1,167 @@ +/* rgr.c (raster graphics) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2004-2018 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "rgr.h" + +/*********************************************************************** +*  NAME +* +*  rgr_write_bmp16 - write 16-color raster image in BMP file format +* +*  SYNOPSIS +* +*  #include "rgr.h" +*  int rgr_write_bmp16(const char *fname, int m, int n, const char +*     map[]); +* +*  DESCRIPTION +* +*  The routine rgr_write_bmp16 writes 16-color raster image in +*  uncompressed BMP file format (Windows bitmap) to a binary file whose +*  name is specified by the character string fname. +* +*  The parameters m and n specify, respectively, the number of rows and +*  the numbers of columns (i.e. height and width) of the raster image. +* +*  The character array map has m*n elements. Elements map[0, ..., n-1] +*  correspond to the first (top) scanline, elements map[n, ..., 2*n-1] +*  correspond to the second scanline, etc. +* +*  Each element of the array map specifies a color of the corresponding +*  pixel as 8-bit binary number XXXXIRGB, where four high-order bits (X) +*  are ignored, I is high intensity bit, R is red color bit, G is green +*  color bit, and B is blue color bit. Thus, all 16 possible colors are +*  coded as following hexadecimal numbers: +* +*     0x00 = black         0x08 = dark gray +*     0x01 = blue          0x09 = bright blue +*     0x02 = green         0x0A = bright green +*     0x03 = cyan          0x0B = bright cyan +*     0x04 = red           0x0C = bright red +*     0x05 = magenta       0x0D = bright magenta +*     0x06 = brown         0x0E = yellow +*     0x07 = light gray    0x0F = white +* +*  RETURNS +* +*  If no error occured, the routine returns zero; otherwise, it prints +*  an appropriate error message and returns non-zero. */ + +static void put_byte(FILE *fp, int c) +{     fputc(c, fp); +      return; +} + +static void put_word(FILE *fp, int w) +{     /* big endian */ +      put_byte(fp, w); +      put_byte(fp, w >> 8); +      return; +} + +static void put_dword(FILE *fp, int d) +{     /* big endian */ +      put_word(fp, d); +      put_word(fp, d >> 16); +      return; +} + +int rgr_write_bmp16(const char *fname, int m, int n, const char map[]) +{     FILE *fp; +      int offset, bmsize, i, j, b, ret = 0; +      if (!(1 <= m && m <= 32767)) +         xerror("rgr_write_bmp16: m = %d; invalid height\n", m); +      if (!(1 <= n && n <= 32767)) +         xerror("rgr_write_bmp16: n = %d; invalid width\n", n); +      fp = fopen(fname, "wb"); +      if (fp == NULL) +      {  xprintf("rgr_write_bmp16: unable to create '%s' - %s\n", +#if 0 /* 29/I-2017 */ +            fname, strerror(errno)); +#else +            fname, xstrerr(errno)); +#endif +         ret = 1; +         goto fini; +      } +      offset = 14 + 40 + 16 * 4; +      bmsize = (4 * n + 31) / 32; +      /* struct BMPFILEHEADER (14 bytes) */ +      /* UINT bfType */          put_byte(fp, 'B'), put_byte(fp, 'M'); +      /* DWORD bfSize */         put_dword(fp, offset + bmsize * 4); +      /* UINT bfReserved1 */     put_word(fp, 0); +      /* UNIT bfReserved2 */     put_word(fp, 0); +      /* DWORD bfOffBits */      put_dword(fp, offset); +      /* struct BMPINFOHEADER (40 bytes) */ +      /* DWORD biSize */         put_dword(fp, 40); +      /* LONG biWidth */         put_dword(fp, n); +      /* LONG biHeight */        put_dword(fp, m); +      /* WORD biPlanes */        put_word(fp, 1); +      /* WORD biBitCount */      put_word(fp, 4); +      /* DWORD biCompression */  put_dword(fp, 0 /* BI_RGB */); +      /* DWORD biSizeImage */    put_dword(fp, 0); +      /* LONG biXPelsPerMeter */ put_dword(fp, 2953 /* 75 dpi */); +      /* LONG biYPelsPerMeter */ put_dword(fp, 2953 /* 75 dpi */); +      /* DWORD biClrUsed */      put_dword(fp, 0); +      /* DWORD biClrImportant */ put_dword(fp, 0); +      /* struct RGBQUAD (16 * 4 = 64 bytes) */ +      /* CGA-compatible colors: */ +      /* 0x00 = black */         put_dword(fp, 0x000000); +      /* 0x01 = blue */          put_dword(fp, 0x000080); +      /* 0x02 = green */         put_dword(fp, 0x008000); +      /* 0x03 = cyan */          put_dword(fp, 0x008080); +      /* 0x04 = red */           put_dword(fp, 0x800000); +      /* 0x05 = magenta */       put_dword(fp, 0x800080); +      /* 0x06 = brown */         put_dword(fp, 0x808000); +      /* 0x07 = light gray */    put_dword(fp, 0xC0C0C0); +      /* 0x08 = dark gray */     put_dword(fp, 0x808080); +      /* 0x09 = bright blue */   put_dword(fp, 0x0000FF); +      /* 0x0A = bright green */  put_dword(fp, 0x00FF00); +      /* 0x0B = bright cyan */   put_dword(fp, 0x00FFFF); +      /* 0x0C = bright red */    put_dword(fp, 0xFF0000); +      /* 0x0D = bright magenta */ put_dword(fp, 0xFF00FF); +      /* 0x0E = yellow */        put_dword(fp, 0xFFFF00); +      /* 0x0F = white */         put_dword(fp, 0xFFFFFF); +      /* pixel data bits */ +      b = 0; +      for (i = m - 1; i >= 0; i--) +      {  for (j = 0; j < ((n + 7) / 8) * 8; j++) +         {  b <<= 4; +            b |= (j < n ? map[i * n + j] & 15 : 0); +            if (j & 1) put_byte(fp, b); +         } +      } +      fflush(fp); +      if (ferror(fp)) +      {  xprintf("rgr_write_bmp16: write error on '%s' - %s\n", +#if 0 /* 29/I-2017 */ +            fname, strerror(errno)); +#else +            fname, xstrerr(errno)); +#endif +         ret = 1; +      } +fini: if (fp != NULL) fclose(fp); +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/misc/rgr.h b/glpk-5.0/src/misc/rgr.h new file mode 100644 index 0000000..027cb7a --- /dev/null +++ b/glpk-5.0/src/misc/rgr.h @@ -0,0 +1,31 @@ +/* rgr.h (raster graphics) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2004-2018 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#ifndef RGR_H +#define RGR_H + +#define rgr_write_bmp16 _glp_rgr_write_bmp16 +int rgr_write_bmp16(const char *fname, int m, int n, const char map[]); +/* write 16-color raster image in BMP file format */ + +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/rng.c b/glpk-5.0/src/misc/rng.c new file mode 100644 index 0000000..e0acb53 --- /dev/null +++ b/glpk-5.0/src/misc/rng.c @@ -0,0 +1,227 @@ +/* rng.c (pseudo-random number generator) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +* +*  This code is a modified version of the module GB_FLIP, a portable +*  pseudo-random number generator. The original version of GB_FLIP is +*  a part of The Stanford GraphBase developed by Donald E. Knuth (see +*  http://www-cs-staff.stanford.edu/~knuth/sgb.html). +* +*  Note that all changes concern only external names, so this modified +*  version produces exactly the same results as the original version. +* +*  Changes were made by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "rng.h" + +#if 0 +int A[56] = { -1 }; +#else +#define A (rand->A) +#endif +/* pseudo-random values */ + +#if 0 +int *fptr = A; +#else +#define fptr (rand->fptr) +#endif +/* the next A value to be exported */ + +#define mod_diff(x, y) (((x) - (y)) & 0x7FFFFFFF) +/* difference modulo 2^31 */ + +static int flip_cycle(RNG *rand) +{     /* this is an auxiliary routine to do 55 more steps of the basic +       * recurrence, at high speed, and to reset fptr */ +      int *ii, *jj; +      for (ii = &A[1], jj = &A[32]; jj <= &A[55]; ii++, jj++) +         *ii = mod_diff(*ii, *jj); +      for (jj = &A[1]; ii <= &A[55]; ii++, jj++) +         *ii = mod_diff(*ii, *jj); +      fptr = &A[54]; +      return A[55]; +} + +/*********************************************************************** +*  NAME +* +*  rng_create_rand - create pseudo-random number generator +* +*  SYNOPSIS +* +*  #include "rng.h" +*  RNG *rng_create_rand(void); +* +*  DESCRIPTION +* +*  The routine rng_create_rand creates and initializes a pseudo-random +*  number generator. +* +*  RETURNS +* +*  The routine returns a pointer to the generator created. */ + +RNG *rng_create_rand(void) +{     RNG *rand; +      int i; +      rand = talloc(1, RNG); +      A[0] = -1; +      for (i = 1; i <= 55; i++) A[i] = 0; +      fptr = A; +      rng_init_rand(rand, 1); +      return rand; +} + +/*********************************************************************** +*  NAME +* +*  rng_init_rand - initialize pseudo-random number generator +* +*  SYNOPSIS +* +*  #include "rng.h" +*  void rng_init_rand(RNG *rand, int seed); +* +*  DESCRIPTION +* +*  The routine rng_init_rand initializes the pseudo-random number +*  generator. The parameter seed may be any integer number. Note that +*  on creating the generator this routine is called with the parameter +*  seed equal to 1. */ + +void rng_init_rand(RNG *rand, int seed) +{     int i; +      int prev = seed, next = 1; +      seed = prev = mod_diff(prev, 0); +      A[55] = prev; +      for (i = 21; i; i = (i + 21) % 55) +      {  A[i] = next; +         next = mod_diff(prev, next); +         if (seed & 1) +            seed = 0x40000000 + (seed >> 1); +         else +            seed >>= 1; +         next = mod_diff(next, seed); +         prev = A[i]; +      } +      flip_cycle(rand); +      flip_cycle(rand); +      flip_cycle(rand); +      flip_cycle(rand); +      flip_cycle(rand); +      return; +} + +/*********************************************************************** +*  NAME +* +*  rng_next_rand - obtain pseudo-random integer in the range [0, 2^31-1] +* +*  SYNOPSIS +* +*  #include "rng.h" +*  int rng_next_rand(RNG *rand); +* +*  RETURNS +* +*  The routine rng_next_rand returns a next pseudo-random integer which +*  is uniformly distributed between 0 and 2^31-1, inclusive. The period +*  length of the generated numbers is 2^85 - 2^30. The low order bits of +*  the generated numbers are just as random as the high-order bits. */ + +int rng_next_rand(RNG *rand) +{     return +         *fptr >= 0 ? *fptr-- : flip_cycle(rand); +} + +/*********************************************************************** +*  NAME +* +*  rng_unif_rand - obtain pseudo-random integer in the range [0, m-1] +* +*  SYNOPSIS +* +*  #include "rng.h" +*  int rng_unif_rand(RNG *rand, int m); +* +*  RETURNS +* +*  The routine rng_unif_rand returns a next pseudo-random integer which +*  is uniformly distributed between 0 and m-1, inclusive, where m is any +*  positive integer less than 2^31. */ + +#define two_to_the_31 ((unsigned int)0x80000000) + +int rng_unif_rand(RNG *rand, int m) +{     unsigned int t = two_to_the_31 - (two_to_the_31 % m); +      int r; +      xassert(m > 0); +      do { r = rng_next_rand(rand); } while (t <= (unsigned int)r); +      return r % m; +} + +/*********************************************************************** +*  NAME +* +*  rng_delete_rand - delete pseudo-random number generator +* +*  SYNOPSIS +* +*  #include "rng.h" +*  void rng_delete_rand(RNG *rand); +* +*  DESCRIPTION +* +*  The routine rng_delete_rand frees all the memory allocated to the +*  specified pseudo-random number generator. */ + +void rng_delete_rand(RNG *rand) +{     tfree(rand); +      return; +} + +/**********************************************************************/ + +#ifdef GLP_TEST +/* To be sure that this modified version produces the same results as + * the original version, run this validation program. */ + +int main(void) +{     RNG *rand; +      int j; +      rand = rng_create_rand(); +      rng_init_rand(rand, -314159); +      if (rng_next_rand(rand) != 119318998) +      {  fprintf(stderr, "Failure on the first try!\n"); +         return -1; +      } +      for (j = 1; j <= 133; j++) rng_next_rand(rand); +      if (rng_unif_rand(rand, 0x55555555) != 748103812) +      {  fprintf(stderr, "Failure on the second try!\n"); +         return -2; +      } +      fprintf(stderr, "OK, the random-number generator routines seem to" +         " work!\n"); +      rng_delete_rand(rand); +      return 0; +} +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/rng.h b/glpk-5.0/src/misc/rng.h new file mode 100644 index 0000000..09e1e5c --- /dev/null +++ b/glpk-5.0/src/misc/rng.h @@ -0,0 +1,65 @@ +/* rng.h (pseudo-random number generator) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2003 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#ifndef RNG_H +#define RNG_H + +typedef struct RNG RNG; + +struct RNG +{     /* Knuth's portable pseudo-random number generator */ +      int A[56]; +      /* pseudo-random values */ +      int *fptr; +      /* the next A value to be exported */ +}; + +#define rng_create_rand _glp_rng_create_rand +RNG *rng_create_rand(void); +/* create pseudo-random number generator */ + +#define rng_init_rand _glp_rng_init_rand +void rng_init_rand(RNG *rand, int seed); +/* initialize pseudo-random number generator */ + +#define rng_next_rand _glp_rng_next_rand +int rng_next_rand(RNG *rand); +/* obtain pseudo-random integer in the range [0, 2^31-1] */ + +#define rng_unif_rand _glp_rng_unif_rand +int rng_unif_rand(RNG *rand, int m); +/* obtain pseudo-random integer in the range [0, m-1] */ + +#define rng_delete_rand _glp_rng_delete_rand +void rng_delete_rand(RNG *rand); +/* delete pseudo-random number generator */ + +#define rng_unif_01 _glp_rng_unif_01 +double rng_unif_01(RNG *rand); +/* obtain pseudo-random number in the range [0, 1] */ + +#define rng_uniform _glp_rng_uniform +double rng_uniform(RNG *rand, double a, double b); +/* obtain pseudo-random number in the range [a, b] */ + +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/rng1.c b/glpk-5.0/src/misc/rng1.c new file mode 100644 index 0000000..4184682 --- /dev/null +++ b/glpk-5.0/src/misc/rng1.c @@ -0,0 +1,71 @@ +/* rng1.c (pseudo-random number generator) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2003 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "rng.h" + +/*********************************************************************** +*  NAME +* +*  rng_unif_01 - obtain pseudo-random number in the range [0, 1] +* +*  SYNOPSIS +* +*  #include "rng.h" +*  double rng_unif_01(RNG *rand); +* +*  RETURNS +* +*  The routine rng_unif_01 returns a next pseudo-random number which is +*  uniformly distributed in the range [0, 1]. */ + +double rng_unif_01(RNG *rand) +{     double x; +      x = (double)rng_next_rand(rand) / 2147483647.0; +      xassert(0.0 <= x && x <= 1.0); +      return x; +} + +/*********************************************************************** +*  NAME +* +*  rng_uniform - obtain pseudo-random number in the range [a, b] +* +*  SYNOPSIS +* +*  #include "rng.h" +*  double rng_uniform(RNG *rand, double a, double b); +* +*  RETURNS +* +*  The routine rng_uniform returns a next pseudo-random number which is +*  uniformly distributed in the range [a, b]. */ + +double rng_uniform(RNG *rand, double a, double b) +{     double x; +      xassert(a < b); +      x = rng_unif_01(rand); +      x = a * (1.0 - x) + b * x; +      xassert(a <= x && x <= b); +      return x; +} + +/* eof */ diff --git a/glpk-5.0/src/misc/round2n.c b/glpk-5.0/src/misc/round2n.c new file mode 100644 index 0000000..1caa000 --- /dev/null +++ b/glpk-5.0/src/misc/round2n.c @@ -0,0 +1,62 @@ +/* round2n.c (round floating-point number to nearest power of two) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2000 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "misc.h" + +/*********************************************************************** +*  NAME +* +*  round2n - round floating-point number to nearest power of two +* +*  SYNOPSIS +* +*  #include "misc.h" +*  double round2n(double x); +* +*  RETURNS +* +*  Given a positive floating-point value x the routine round2n returns +*  2^n such that |x - 2^n| is minimal. +* +*  EXAMPLES +* +*  round2n(10.1) = 2^3 = 8 +*  round2n(15.3) = 2^4 = 16 +*  round2n(0.01) = 2^(-7) = 0.0078125 +* +*  BACKGROUND +* +*  Let x = f * 2^e, where 0.5 <= f < 1 is a normalized fractional part, +*  e is an integer exponent. Then, obviously, 0.5 * 2^e <= x < 2^e, so +*  if x - 0.5 * 2^e <= 2^e - x, we choose 0.5 * 2^e = 2^(e-1), and 2^e +*  otherwise. The latter condition can be written as 2 * x <= 1.5 * 2^e +*  or 2 * f * 2^e <= 1.5 * 2^e or, finally, f <= 0.75. */ + +double round2n(double x) +{     int e; +      double f; +      xassert(x > 0.0); +      f = frexp(x, &e); +      return ldexp(1.0, f <= 0.75 ? e-1 : e); +} + +/* eof */ diff --git a/glpk-5.0/src/misc/spm.c b/glpk-5.0/src/misc/spm.c new file mode 100644 index 0000000..7c1bd96 --- /dev/null +++ b/glpk-5.0/src/misc/spm.c @@ -0,0 +1,844 @@ +/* glpspm.c (general sparse matrices) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2004-2018 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "hbm.h" +#include "rgr.h" +#include "spm.h" + +/*********************************************************************** +*  NAME +* +*  spm_create_mat - create general sparse matrix +* +*  SYNOPSIS +* +*  #include "glpspm.h" +*  SPM *spm_create_mat(int m, int n); +* +*  DESCRIPTION +* +*  The routine spm_create_mat creates a general sparse matrix having +*  m rows and n columns. Being created the matrix is zero (empty), i.e. +*  has no elements. +* +*  RETURNS +* +*  The routine returns a pointer to the matrix created. */ + +SPM *spm_create_mat(int m, int n) +{     SPM *A; +      xassert(0 <= m && m < INT_MAX); +      xassert(0 <= n && n < INT_MAX); +      A = xmalloc(sizeof(SPM)); +      A->m = m; +      A->n = n; +      if (m == 0 || n == 0) +      {  A->pool = NULL; +         A->row = NULL; +         A->col = NULL; +      } +      else +      {  int i, j; +         A->pool = dmp_create_pool(); +         A->row = xcalloc(1+m, sizeof(SPME *)); +         for (i = 1; i <= m; i++) A->row[i] = NULL; +         A->col = xcalloc(1+n, sizeof(SPME *)); +         for (j = 1; j <= n; j++) A->col[j] = NULL; +      } +      return A; +} + +/*********************************************************************** +*  NAME +* +*  spm_new_elem - add new element to sparse matrix +* +*  SYNOPSIS +* +*  #include "glpspm.h" +*  SPME *spm_new_elem(SPM *A, int i, int j, double val); +* +*  DESCRIPTION +* +*  The routine spm_new_elem adds a new element to the specified sparse +*  matrix. Parameters i, j, and val specify the row number, the column +*  number, and a numerical value of the element, respectively. +* +*  RETURNS +* +*  The routine returns a pointer to the new element added. */ + +SPME *spm_new_elem(SPM *A, int i, int j, double val) +{     SPME *e; +      xassert(1 <= i && i <= A->m); +      xassert(1 <= j && j <= A->n); +      e = dmp_get_atom(A->pool, sizeof(SPME)); +      e->i = i; +      e->j = j; +      e->val = val; +      e->r_prev = NULL; +      e->r_next = A->row[i]; +      if (e->r_next != NULL) e->r_next->r_prev = e; +      e->c_prev = NULL; +      e->c_next = A->col[j]; +      if (e->c_next != NULL) e->c_next->c_prev = e; +      A->row[i] = A->col[j] = e; +      return e; +} + +/*********************************************************************** +*  NAME +* +*  spm_delete_mat - delete general sparse matrix +* +*  SYNOPSIS +* +*  #include "glpspm.h" +*  void spm_delete_mat(SPM *A); +* +*  DESCRIPTION +* +*  The routine deletes the specified general sparse matrix freeing all +*  the memory allocated to this object. */ + +void spm_delete_mat(SPM *A) +{     /* delete sparse matrix */ +      if (A->pool != NULL) dmp_delete_pool(A->pool); +      if (A->row != NULL) xfree(A->row); +      if (A->col != NULL) xfree(A->col); +      xfree(A); +      return; +} + +/*********************************************************************** +*  NAME +* +*  spm_test_mat_e - create test sparse matrix of E(n,c) class +* +*  SYNOPSIS +* +*  #include "glpspm.h" +*  SPM *spm_test_mat_e(int n, int c); +* +*  DESCRIPTION +* +*  The routine spm_test_mat_e creates a test sparse matrix of E(n,c) +*  class as described in the book: Ole 0sterby, Zahari Zlatev. Direct +*  Methods for Sparse Matrices. Springer-Verlag, 1983. +* +*  Matrix of E(n,c) class is a symmetric positive definite matrix of +*  the order n. It has the number 4 on its main diagonal and the number +*  -1 on its four co-diagonals, two of which are neighbour to the main +*  diagonal and two others are shifted from the main diagonal on the +*  distance c. +* +*  It is necessary that n >= 3 and 2 <= c <= n-1. +* +*  RETURNS +* +*  The routine returns a pointer to the matrix created. */ + +SPM *spm_test_mat_e(int n, int c) +{     SPM *A; +      int i; +      xassert(n >= 3 && 2 <= c && c <= n-1); +      A = spm_create_mat(n, n); +      for (i = 1; i <= n; i++) +         spm_new_elem(A, i, i, 4.0); +      for (i = 1; i <= n-1; i++) +      {  spm_new_elem(A, i, i+1, -1.0); +         spm_new_elem(A, i+1, i, -1.0); +      } +      for (i = 1; i <= n-c; i++) +      {  spm_new_elem(A, i, i+c, -1.0); +         spm_new_elem(A, i+c, i, -1.0); +      } +      return A; +} + +/*********************************************************************** +*  NAME +* +*  spm_test_mat_d - create test sparse matrix of D(n,c) class +* +*  SYNOPSIS +* +*  #include "glpspm.h" +*  SPM *spm_test_mat_d(int n, int c); +* +*  DESCRIPTION +* +*  The routine spm_test_mat_d creates a test sparse matrix of D(n,c) +*  class as described in the book: Ole 0sterby, Zahari Zlatev. Direct +*  Methods for Sparse Matrices. Springer-Verlag, 1983. +* +*  Matrix of D(n,c) class is a non-singular matrix of the order n. It +*  has unity main diagonal, three co-diagonals above the main diagonal +*  on the distance c, which are cyclically continued below the main +*  diagonal, and a triangle block of the size 10x10 in the upper right +*  corner. +* +*  It is necessary that n >= 14 and 1 <= c <= n-13. +* +*  RETURNS +* +*  The routine returns a pointer to the matrix created. */ + +SPM *spm_test_mat_d(int n, int c) +{     SPM *A; +      int i, j; +      xassert(n >= 14 && 1 <= c && c <= n-13); +      A = spm_create_mat(n, n); +      for (i = 1; i <= n; i++) +         spm_new_elem(A, i, i, 1.0); +      for (i = 1; i <= n-c; i++) +         spm_new_elem(A, i, i+c, (double)(i+1)); +      for (i = n-c+1; i <= n; i++) +         spm_new_elem(A, i, i-n+c, (double)(i+1)); +      for (i = 1; i <= n-c-1; i++) +         spm_new_elem(A, i, i+c+1, (double)(-i)); +      for (i = n-c; i <= n; i++) +         spm_new_elem(A, i, i-n+c+1, (double)(-i)); +      for (i = 1; i <= n-c-2; i++) +         spm_new_elem(A, i, i+c+2, 16.0); +      for (i = n-c-1; i <= n; i++) +         spm_new_elem(A, i, i-n+c+2, 16.0); +      for (j = 1; j <= 10; j++) +         for (i = 1; i <= 11-j; i++) +            spm_new_elem(A, i, n-11+i+j, 100.0 * (double)j); +      return A; +} + +/*********************************************************************** +*  NAME +* +*  spm_show_mat - write sparse matrix pattern in BMP file format +* +*  SYNOPSIS +* +*  #include "glpspm.h" +*  int spm_show_mat(const SPM *A, const char *fname); +* +*  DESCRIPTION +* +*  The routine spm_show_mat writes pattern of the specified sparse +*  matrix in uncompressed BMP file format (Windows bitmap) to a binary +*  file whose name is specified by the character string fname. +* +*  Each pixel corresponds to one matrix element. The pixel colors have +*  the following meaning: +* +*  Black    structurally zero element +*  White    positive element +*  Cyan     negative element +*  Green    zero element +*  Red      duplicate element +* +*  RETURNS +* +*  If no error occured, the routine returns zero. Otherwise, it prints +*  an appropriate error message and returns non-zero. */ + +int spm_show_mat(const SPM *A, const char *fname) +{     int m = A->m; +      int n = A->n; +      int i, j, k, ret; +      char *map; +      xprintf("spm_show_mat: writing matrix pattern to '%s'...\n", +         fname); +      xassert(1 <= m && m <= 32767); +      xassert(1 <= n && n <= 32767); +      map = xmalloc(m * n); +      memset(map, 0x08, m * n); +      for (i = 1; i <= m; i++) +      {  SPME *e; +         for (e = A->row[i]; e != NULL; e = e->r_next) +         {  j = e->j; +            xassert(1 <= j && j <= n); +            k = n * (i - 1) + (j - 1); +            if (map[k] != 0x08) +               map[k] = 0x0C; +            else if (e->val > 0.0) +               map[k] = 0x0F; +            else if (e->val < 0.0) +               map[k] = 0x0B; +            else +               map[k] = 0x0A; +         } +      } +      ret = rgr_write_bmp16(fname, m, n, map); +      xfree(map); +      return ret; +} + +/*********************************************************************** +*  NAME +* +*  spm_read_hbm - read sparse matrix in Harwell-Boeing format +* +*  SYNOPSIS +* +*  #include "glpspm.h" +*  SPM *spm_read_hbm(const char *fname); +* +*  DESCRIPTION +* +*  The routine spm_read_hbm reads a sparse matrix in the Harwell-Boeing +*  format from a text file whose name is the character string fname. +* +*  Detailed description of the Harwell-Boeing format recognised by this +*  routine can be found in the following report: +* +*  I.S.Duff, R.G.Grimes, J.G.Lewis. User's Guide for the Harwell-Boeing +*  Sparse Matrix Collection (Release I), TR/PA/92/86, October 1992. +* +*  NOTE +* +*  The routine spm_read_hbm reads the matrix "as is", due to which zero +*  and/or duplicate elements can appear in the matrix. +* +*  RETURNS +* +*  If no error occured, the routine returns a pointer to the matrix +*  created. Otherwise, the routine prints an appropriate error message +*  and returns NULL. */ + +SPM *spm_read_hbm(const char *fname) +{     SPM *A = NULL; +      HBM *hbm; +      int nrow, ncol, nnzero, i, j, beg, end, ptr, *colptr, *rowind; +      double val, *values; +      char *mxtype; +      hbm = hbm_read_mat(fname); +      if (hbm == NULL) +      {  xprintf("spm_read_hbm: unable to read matrix\n"); +         goto fini; +      } +      mxtype = hbm->mxtype; +      nrow = hbm->nrow; +      ncol = hbm->ncol; +      nnzero = hbm->nnzero; +      colptr = hbm->colptr; +      rowind = hbm->rowind; +      values = hbm->values; +      if (!(strcmp(mxtype, "RSA") == 0 || strcmp(mxtype, "PSA") == 0 || +            strcmp(mxtype, "RUA") == 0 || strcmp(mxtype, "PUA") == 0 || +            strcmp(mxtype, "RRA") == 0 || strcmp(mxtype, "PRA") == 0)) +      {  xprintf("spm_read_hbm: matrix type '%s' not supported\n", +            mxtype); +         goto fini; +      } +      A = spm_create_mat(nrow, ncol); +      if (mxtype[1] == 'S' || mxtype[1] == 'U') +         xassert(nrow == ncol); +      for (j = 1; j <= ncol; j++) +      {  beg = colptr[j]; +         end = colptr[j+1]; +         xassert(1 <= beg && beg <= end && end <= nnzero + 1); +         for (ptr = beg; ptr < end; ptr++) +         {  i = rowind[ptr]; +            xassert(1 <= i && i <= nrow); +            if (mxtype[0] == 'R') +               val = values[ptr]; +            else +               val = 1.0; +            spm_new_elem(A, i, j, val); +            if (mxtype[1] == 'S' && i != j) +               spm_new_elem(A, j, i, val); +         } +      } +fini: if (hbm != NULL) hbm_free_mat(hbm); +      return A; +} + +/*********************************************************************** +*  NAME +* +*  spm_count_nnz - determine number of non-zeros in sparse matrix +* +*  SYNOPSIS +* +*  #include "glpspm.h" +*  int spm_count_nnz(const SPM *A); +* +*  RETURNS +* +*  The routine spm_count_nnz returns the number of structural non-zero +*  elements in the specified sparse matrix. */ + +int spm_count_nnz(const SPM *A) +{     SPME *e; +      int i, nnz = 0; +      for (i = 1; i <= A->m; i++) +         for (e = A->row[i]; e != NULL; e = e->r_next) nnz++; +      return nnz; +} + +/*********************************************************************** +*  NAME +* +*  spm_drop_zeros - remove zero elements from sparse matrix +* +*  SYNOPSIS +* +*  #include "glpspm.h" +*  int spm_drop_zeros(SPM *A, double eps); +* +*  DESCRIPTION +* +*  The routine spm_drop_zeros removes all elements from the specified +*  sparse matrix, whose absolute value is less than eps. +* +*  If the parameter eps is 0, only zero elements are removed from the +*  matrix. +* +*  RETURNS +* +*  The routine returns the number of elements removed. */ + +int spm_drop_zeros(SPM *A, double eps) +{     SPME *e, *next; +      int i, count = 0; +      for (i = 1; i <= A->m; i++) +      {  for (e = A->row[i]; e != NULL; e = next) +         {  next = e->r_next; +            if (e->val == 0.0 || fabs(e->val) < eps) +            {  /* remove element from the row list */ +               if (e->r_prev == NULL) +                  A->row[e->i] = e->r_next; +               else +                  e->r_prev->r_next = e->r_next; +               if (e->r_next == NULL) +                  ; +               else +                  e->r_next->r_prev = e->r_prev; +               /* remove element from the column list */ +               if (e->c_prev == NULL) +                  A->col[e->j] = e->c_next; +               else +                  e->c_prev->c_next = e->c_next; +               if (e->c_next == NULL) +                  ; +               else +                  e->c_next->c_prev = e->c_prev; +               /* return element to the memory pool */ +               dmp_free_atom(A->pool, e, sizeof(SPME)); +               count++; +            } +         } +      } +      return count; +} + +/*********************************************************************** +*  NAME +* +*  spm_read_mat - read sparse matrix from text file +* +*  SYNOPSIS +* +*  #include "glpspm.h" +*  SPM *spm_read_mat(const char *fname); +* +*  DESCRIPTION +* +*  The routine reads a sparse matrix from a text file whose name is +*  specified by the parameter fname. +* +*  For the file format see description of the routine spm_write_mat. +* +*  RETURNS +* +*  On success the routine returns a pointer to the matrix created, +*  otherwise NULL. */ + +#if 1 +SPM *spm_read_mat(const char *fname) +{     xassert(fname != fname); +      return NULL; +} +#else +SPM *spm_read_mat(const char *fname) +{     SPM *A = NULL; +      PDS *pds; +      jmp_buf jump; +      int i, j, k, m, n, nnz, fail = 0; +      double val; +      xprintf("spm_read_mat: reading matrix from '%s'...\n", fname); +      pds = pds_open_file(fname); +      if (pds == NULL) +      {  xprintf("spm_read_mat: unable to open '%s' - %s\n", fname, +            strerror(errno)); +         fail = 1; +         goto done; +      } +      if (setjmp(jump)) +      {  fail = 1; +         goto done; +      } +      pds_set_jump(pds, jump); +      /* number of rows, number of columns, number of non-zeros */ +      m = pds_scan_int(pds); +      if (m < 0) +         pds_error(pds, "invalid number of rows\n"); +      n = pds_scan_int(pds); +      if (n < 0) +         pds_error(pds, "invalid number of columns\n"); +      nnz = pds_scan_int(pds); +      if (nnz < 0) +         pds_error(pds, "invalid number of non-zeros\n"); +      /* create matrix */ +      xprintf("spm_read_mat: %d rows, %d columns, %d non-zeros\n", +         m, n, nnz); +      A = spm_create_mat(m, n); +      /* read matrix elements */ +      for (k = 1; k <= nnz; k++) +      {  /* row index, column index, element value */ +         i = pds_scan_int(pds); +         if (!(1 <= i && i <= m)) +            pds_error(pds, "row index out of range\n"); +         j = pds_scan_int(pds); +         if (!(1 <= j && j <= n)) +            pds_error(pds, "column index out of range\n"); +         val = pds_scan_num(pds); +         /* add new element to the matrix */ +         spm_new_elem(A, i, j, val); +      } +      xprintf("spm_read_mat: %d lines were read\n", pds->count); +done: if (pds != NULL) pds_close_file(pds); +      if (fail && A != NULL) spm_delete_mat(A), A = NULL; +      return A; +} +#endif + +/*********************************************************************** +*  NAME +* +*  spm_write_mat - write sparse matrix to text file +* +*  SYNOPSIS +* +*  #include "glpspm.h" +*  int spm_write_mat(const SPM *A, const char *fname); +* +*  DESCRIPTION +* +*  The routine spm_write_mat writes the specified sparse matrix to a +*  text file whose name is specified by the parameter fname. This file +*  can be read back with the routine spm_read_mat. +* +*  RETURNS +* +*  On success the routine returns zero, otherwise non-zero. +* +*  FILE FORMAT +* +*  The file created by the routine spm_write_mat is a plain text file, +*  which contains the following information: +* +*     m n nnz +*     row[1] col[1] val[1] +*     row[2] col[2] val[2] +*     . . . +*     row[nnz] col[nnz] val[nnz] +* +*  where: +*  m is the number of rows; +*  n is the number of columns; +*  nnz is the number of non-zeros; +*  row[k], k = 1,...,nnz, are row indices; +*  col[k], k = 1,...,nnz, are column indices; +*  val[k], k = 1,...,nnz, are element values. */ + +#if 1 +int spm_write_mat(const SPM *A, const char *fname) +{     xassert(A != A); +      xassert(fname != fname); +      return 0; +} +#else +int spm_write_mat(const SPM *A, const char *fname) +{     FILE *fp; +      int i, nnz, ret = 0; +      xprintf("spm_write_mat: writing matrix to '%s'...\n", fname); +      fp = fopen(fname, "w"); +      if (fp == NULL) +      {  xprintf("spm_write_mat: unable to create '%s' - %s\n", fname, +            strerror(errno)); +         ret = 1; +         goto done; +      } +      /* number of rows, number of columns, number of non-zeros */ +      nnz = spm_count_nnz(A); +      fprintf(fp, "%d %d %d\n", A->m, A->n, nnz); +      /* walk through rows of the matrix */ +      for (i = 1; i <= A->m; i++) +      {  SPME *e; +         /* walk through elements of i-th row */ +         for (e = A->row[i]; e != NULL; e = e->r_next) +         {  /* row index, column index, element value */ +            fprintf(fp, "%d %d %.*g\n", e->i, e->j, DBL_DIG, e->val); +         } +      } +      fflush(fp); +      if (ferror(fp)) +      {  xprintf("spm_write_mat: writing error on '%s' - %s\n", fname, +            strerror(errno)); +         ret = 1; +         goto done; +      } +      xprintf("spm_write_mat: %d lines were written\n", 1 + nnz); +done: if (fp != NULL) fclose(fp); +      return ret; +} +#endif + +/*********************************************************************** +*  NAME +* +*  spm_transpose - transpose sparse matrix +* +*  SYNOPSIS +* +*  #include "glpspm.h" +*  SPM *spm_transpose(const SPM *A); +* +*  RETURNS +* +*  The routine computes and returns sparse matrix B, which is a matrix +*  transposed to sparse matrix A. */ + +SPM *spm_transpose(const SPM *A) +{     SPM *B; +      int i; +      B = spm_create_mat(A->n, A->m); +      for (i = 1; i <= A->m; i++) +      {  SPME *e; +         for (e = A->row[i]; e != NULL; e = e->r_next) +            spm_new_elem(B, e->j, i, e->val); +      } +      return B; +} + +SPM *spm_add_sym(const SPM *A, const SPM *B) +{     /* add two sparse matrices (symbolic phase) */ +      SPM *C; +      int i, j, *flag; +      xassert(A->m == B->m); +      xassert(A->n == B->n); +      /* create resultant matrix */ +      C = spm_create_mat(A->m, A->n); +      /* allocate and clear the flag array */ +      flag = xcalloc(1+C->n, sizeof(int)); +      for (j = 1; j <= C->n; j++) +         flag[j] = 0; +      /* compute pattern of C = A + B */ +      for (i = 1; i <= C->m; i++) +      {  SPME *e; +         /* at the beginning i-th row of C is empty */ +         /* (i-th row of C) := (i-th row of C) union (i-th row of A) */ +         for (e = A->row[i]; e != NULL; e = e->r_next) +         {  /* (note that i-th row of A may have duplicate elements) */ +            j = e->j; +            if (!flag[j]) +            {  spm_new_elem(C, i, j, 0.0); +               flag[j] = 1; +            } +         } +         /* (i-th row of C) := (i-th row of C) union (i-th row of B) */ +         for (e = B->row[i]; e != NULL; e = e->r_next) +         {  /* (note that i-th row of B may have duplicate elements) */ +            j = e->j; +            if (!flag[j]) +            {  spm_new_elem(C, i, j, 0.0); +               flag[j] = 1; +            } +         } +         /* reset the flag array */ +         for (e = C->row[i]; e != NULL; e = e->r_next) +            flag[e->j] = 0; +      } +      /* check and deallocate the flag array */ +      for (j = 1; j <= C->n; j++) +         xassert(!flag[j]); +      xfree(flag); +      return C; +} + +void spm_add_num(SPM *C, double alfa, const SPM *A, double beta, +      const SPM *B) +{     /* add two sparse matrices (numeric phase) */ +      int i, j; +      double *work; +      /* allocate and clear the working array */ +      work = xcalloc(1+C->n, sizeof(double)); +      for (j = 1; j <= C->n; j++) +         work[j] = 0.0; +      /* compute matrix C = alfa * A + beta * B */ +      for (i = 1; i <= C->n; i++) +      {  SPME *e; +         /* work := alfa * (i-th row of A) + beta * (i-th row of B) */ +         /* (note that A and/or B may have duplicate elements) */ +         for (e = A->row[i]; e != NULL; e = e->r_next) +            work[e->j] += alfa * e->val; +         for (e = B->row[i]; e != NULL; e = e->r_next) +            work[e->j] += beta * e->val; +         /* (i-th row of C) := work, work := 0 */ +         for (e = C->row[i]; e != NULL; e = e->r_next) +         {  j = e->j; +            e->val = work[j]; +            work[j] = 0.0; +         } +      } +      /* check and deallocate the working array */ +      for (j = 1; j <= C->n; j++) +         xassert(work[j] == 0.0); +      xfree(work); +      return; +} + +SPM *spm_add_mat(double alfa, const SPM *A, double beta, const SPM *B) +{     /* add two sparse matrices (driver routine) */ +      SPM *C; +      C = spm_add_sym(A, B); +      spm_add_num(C, alfa, A, beta, B); +      return C; +} + +SPM *spm_mul_sym(const SPM *A, const SPM *B) +{     /* multiply two sparse matrices (symbolic phase) */ +      int i, j, k, *flag; +      SPM *C; +      xassert(A->n == B->m); +      /* create resultant matrix */ +      C = spm_create_mat(A->m, B->n); +      /* allocate and clear the flag array */ +      flag = xcalloc(1+C->n, sizeof(int)); +      for (j = 1; j <= C->n; j++) +         flag[j] = 0; +      /* compute pattern of C = A * B */ +      for (i = 1; i <= C->m; i++) +      {  SPME *e, *ee; +         /* compute pattern of i-th row of C */ +         for (e = A->row[i]; e != NULL; e = e->r_next) +         {  k = e->j; +            for (ee = B->row[k]; ee != NULL; ee = ee->r_next) +            {  j = ee->j; +               /* if a[i,k] != 0 and b[k,j] != 0 then c[i,j] != 0 */ +               if (!flag[j]) +               {  /* c[i,j] does not exist, so create it */ +                  spm_new_elem(C, i, j, 0.0); +                  flag[j] = 1; +               } +            } +         } +         /* reset the flag array */ +         for (e = C->row[i]; e != NULL; e = e->r_next) +            flag[e->j] = 0; +      } +      /* check and deallocate the flag array */ +      for (j = 1; j <= C->n; j++) +         xassert(!flag[j]); +      xfree(flag); +      return C; +} + +void spm_mul_num(SPM *C, const SPM *A, const SPM *B) +{     /* multiply two sparse matrices (numeric phase) */ +      int i, j; +      double *work; +      /* allocate and clear the working array */ +      work = xcalloc(1+A->n, sizeof(double)); +      for (j = 1; j <= A->n; j++) +         work[j] = 0.0; +      /* compute matrix C = A * B */ +      for (i = 1; i <= C->m; i++) +      {  SPME *e, *ee; +         double temp; +         /* work := (i-th row of A) */ +         /* (note that A may have duplicate elements) */ +         for (e = A->row[i]; e != NULL; e = e->r_next) +            work[e->j] += e->val; +         /* compute i-th row of C */ +         for (e = C->row[i]; e != NULL; e = e->r_next) +         {  j = e->j; +            /* c[i,j] := work * (j-th column of B) */ +            temp = 0.0; +            for (ee = B->col[j]; ee != NULL; ee = ee->c_next) +               temp += work[ee->i] * ee->val; +            e->val = temp; +         } +         /* reset the working array */ +         for (e = A->row[i]; e != NULL; e = e->r_next) +            work[e->j] = 0.0; +      } +      /* check and deallocate the working array */ +      for (j = 1; j <= A->n; j++) +         xassert(work[j] == 0.0); +      xfree(work); +      return; +} + +SPM *spm_mul_mat(const SPM *A, const SPM *B) +{     /* multiply two sparse matrices (driver routine) */ +      SPM *C; +      C = spm_mul_sym(A, B); +      spm_mul_num(C, A, B); +      return C; +} + +PER *spm_create_per(int n) +{     /* create permutation matrix */ +      PER *P; +      int k; +      xassert(n >= 0); +      P = xmalloc(sizeof(PER)); +      P->n = n; +      P->row = xcalloc(1+n, sizeof(int)); +      P->col = xcalloc(1+n, sizeof(int)); +      /* initially it is identity matrix */ +      for (k = 1; k <= n; k++) +         P->row[k] = P->col[k] = k; +      return P; +} + +void spm_check_per(PER *P) +{     /* check permutation matrix for correctness */ +      int i, j; +      xassert(P->n >= 0); +      for (i = 1; i <= P->n; i++) +      {  j = P->row[i]; +         xassert(1 <= j && j <= P->n); +         xassert(P->col[j] == i); +      } +      return; +} + +void spm_delete_per(PER *P) +{     /* delete permutation matrix */ +      xfree(P->row); +      xfree(P->col); +      xfree(P); +      return; +} + +/* eof */ diff --git a/glpk-5.0/src/misc/spm.h b/glpk-5.0/src/misc/spm.h new file mode 100644 index 0000000..a3a22c5 --- /dev/null +++ b/glpk-5.0/src/misc/spm.h @@ -0,0 +1,162 @@ +/* spm.h (general sparse matrices) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2004-2018 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#ifndef SPM_H +#define SPM_H + +#include "dmp.h" + +typedef struct SPM SPM; +typedef struct SPME SPME; + +struct SPM +{     /* general sparse matrix */ +      int m; +      /* number of rows, m >= 0 */ +      int n; +      /* number of columns, n >= 0 */ +      DMP *pool; +      /* memory pool to store matrix elements */ +      SPME **row; /* SPME *row[1+m]; */ +      /* row[i], 1 <= i <= m, is a pointer to i-th row list */ +      SPME **col; /* SPME *col[1+n]; */ +      /* col[j], 1 <= j <= n, is a pointer to j-th column list */ +}; + +struct SPME +{     /* sparse matrix element */ +      int i; +      /* row number */ +      int j; +      /* column number */ +      double val; +      /* element value */ +      SPME *r_prev; +      /* pointer to previous element in the same row */ +      SPME *r_next; +      /* pointer to next element in the same row */ +      SPME *c_prev; +      /* pointer to previous element in the same column */ +      SPME *c_next; +      /* pointer to next element in the same column */ +}; + +typedef struct PER PER; + +struct PER +{     /* permutation matrix */ +      int n; +      /* matrix order, n >= 0 */ +      int *row; /* int row[1+n]; */ +      /* row[i] = j means p[i,j] = 1 */ +      int *col; /* int col[1+n]; */ +      /* col[j] = i means p[i,j] = 1 */ +}; + +#define spm_create_mat _glp_spm_create_mat +SPM *spm_create_mat(int m, int n); +/* create general sparse matrix */ + +#define spm_new_elem _glp_spm_new_elem +SPME *spm_new_elem(SPM *A, int i, int j, double val); +/* add new element to sparse matrix */ + +#define spm_delete_mat _glp_spm_delete_mat +void spm_delete_mat(SPM *A); +/* delete general sparse matrix */ + +#define spm_test_mat_e _glp_spm_test_mat_e +SPM *spm_test_mat_e(int n, int c); +/* create test sparse matrix of E(n,c) class */ + +#define spm_test_mat_d _glp_spm_test_mat_d +SPM *spm_test_mat_d(int n, int c); +/* create test sparse matrix of D(n,c) class */ + +#define spm_show_mat _glp_spm_show_mat +int spm_show_mat(const SPM *A, const char *fname); +/* write sparse matrix pattern in BMP file format */ + +#define spm_read_hbm _glp_spm_read_hbm +SPM *spm_read_hbm(const char *fname); +/* read sparse matrix in Harwell-Boeing format */ + +#define spm_count_nnz _glp_spm_count_nnz +int spm_count_nnz(const SPM *A); +/* determine number of non-zeros in sparse matrix */ + +#define spm_drop_zeros _glp_spm_drop_zeros +int spm_drop_zeros(SPM *A, double eps); +/* remove zero elements from sparse matrix */ + +#define spm_read_mat _glp_spm_read_mat +SPM *spm_read_mat(const char *fname); +/* read sparse matrix from text file */ + +#define spm_write_mat _glp_spm_write_mat +int spm_write_mat(const SPM *A, const char *fname); +/* write sparse matrix to text file */ + +#define spm_transpose _glp_spm_transpose +SPM *spm_transpose(const SPM *A); +/* transpose sparse matrix */ + +#define spm_add_sym _glp_spm_add_sym +SPM *spm_add_sym(const SPM *A, const SPM *B); +/* add two sparse matrices (symbolic phase) */ + +#define spm_add_num _glp_spm_add_num +void spm_add_num(SPM *C, double alfa, const SPM *A, double beta, +      const SPM *B); +/* add two sparse matrices (numeric phase) */ + +#define spm_add_mat _glp_spm_add_mat +SPM *spm_add_mat(double alfa, const SPM *A, double beta, +      const SPM *B); +/* add two sparse matrices (driver routine) */ + +#define spm_mul_sym _glp_spm_mul_sym +SPM *spm_mul_sym(const SPM *A, const SPM *B); +/* multiply two sparse matrices (symbolic phase) */ + +#define spm_mul_num _glp_spm_mul_num +void spm_mul_num(SPM *C, const SPM *A, const SPM *B); +/* multiply two sparse matrices (numeric phase) */ + +#define spm_mul_mat _glp_spm_mul_mat +SPM *spm_mul_mat(const SPM *A, const SPM *B); +/* multiply two sparse matrices (driver routine) */ + +#define spm_create_per _glp_spm_create_per +PER *spm_create_per(int n); +/* create permutation matrix */ + +#define spm_check_per _glp_spm_check_per +void spm_check_per(PER *P); +/* check permutation matrix for correctness */ + +#define spm_delete_per _glp_spm_delete_per +void spm_delete_per(PER *P); +/* delete permutation matrix */ + +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/str2int.c b/glpk-5.0/src/misc/str2int.c new file mode 100644 index 0000000..20325d5 --- /dev/null +++ b/glpk-5.0/src/misc/str2int.c @@ -0,0 +1,90 @@ +/* str2int.c (convert string to int) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2000 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "misc.h" +#include "stdc.h" + +/*********************************************************************** +*  NAME +* +*  str2int - convert character string to value of int type +* +*  SYNOPSIS +* +*  #include "misc.h" +*  int str2int(const char *str, int *val); +* +*  DESCRIPTION +* +*  The routine str2int converts the character string str to a value of +*  integer type and stores the value into location, which the parameter +*  val points to (in the case of error content of this location is not +*  changed). +* +*  RETURNS +* +*  The routine returns one of the following error codes: +* +*  0 - no error; +*  1 - value out of range; +*  2 - character string is syntactically incorrect. */ + +int str2int(const char *str, int *val_) +{     int d, k, s, val = 0; +      /* scan optional sign */ +      if (str[0] == '+') +         s = +1, k = 1; +      else if (str[0] == '-') +         s = -1, k = 1; +      else +         s = +1, k = 0; +      /* check for the first digit */ +      if (!isdigit((unsigned char)str[k])) +         return 2; +      /* scan digits */ +      while (isdigit((unsigned char)str[k])) +      {  d = str[k++] - '0'; +         if (s > 0) +         {  if (val > INT_MAX / 10) +               return 1; +            val *= 10; +            if (val > INT_MAX - d) +               return 1; +            val += d; +         } +         else /* s < 0 */ +         {  if (val < INT_MIN / 10) +               return 1; +            val *= 10; +            if (val < INT_MIN + d) +               return 1; +            val -= d; +         } +      } +      /* check for terminator */ +      if (str[k] != '\0') +         return 2; +      /* conversion has been done */ +      *val_ = val; +      return 0; +} + +/* eof */ diff --git a/glpk-5.0/src/misc/str2num.c b/glpk-5.0/src/misc/str2num.c new file mode 100644 index 0000000..3543667 --- /dev/null +++ b/glpk-5.0/src/misc/str2num.c @@ -0,0 +1,108 @@ +/* str2num.c (convert string to double) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2000 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "misc.h" +#include "stdc.h" + +/*********************************************************************** +*  NAME +* +*  str2num - convert character string to value of double type +* +*  SYNOPSIS +* +*  #include "misc.h" +*  int str2num(const char *str, double *val); +* +*  DESCRIPTION +* +*  The routine str2num converts the character string str to a value of +*  double type and stores the value into location, which the parameter +*  val points to (in the case of error content of this location is not +*  changed). +* +*  RETURNS +* +*  The routine returns one of the following error codes: +* +*  0 - no error; +*  1 - value out of range; +*  2 - character string is syntactically incorrect. */ + +int str2num(const char *str, double *val_) +{     int k; +      double val; +      /* scan optional sign */ +      k = (str[0] == '+' || str[0] == '-' ? 1 : 0); +      /* check for decimal point */ +      if (str[k] == '.') +      {  k++; +         /* a digit should follow it */ +         if (!isdigit((unsigned char)str[k])) +            return 2; +         k++; +         goto frac; +      } +      /* integer part should start with a digit */ +      if (!isdigit((unsigned char)str[k])) +         return 2; +      /* scan integer part */ +      while (isdigit((unsigned char)str[k])) +         k++; +      /* check for decimal point */ +      if (str[k] == '.') k++; +frac: /* scan optional fraction part */ +      while (isdigit((unsigned char)str[k])) +         k++; +      /* check for decimal exponent */ +      if (str[k] == 'E' || str[k] == 'e') +      {  k++; +         /* scan optional sign */ +         if (str[k] == '+' || str[k] == '-') +            k++; +         /* a digit should follow E, E+ or E- */ +         if (!isdigit((unsigned char)str[k])) +            return 2; +      } +      /* scan optional exponent part */ +      while (isdigit((unsigned char)str[k])) +         k++; +      /* check for terminator */ +      if (str[k] != '\0') +         return 2; +      /* perform conversion */ +      {  char *endptr; +         val = strtod(str, &endptr); +         if (*endptr != '\0') +            return 2; +      } +      /* check for overflow */ +      if (!(-DBL_MAX <= val && val <= +DBL_MAX)) +         return 1; +      /* check for underflow */ +      if (-DBL_MIN < val && val < +DBL_MIN) +         val = 0.0; +      /* conversion has been done */ +      *val_ = val; +      return 0; +} + +/* eof */ diff --git a/glpk-5.0/src/misc/strspx.c b/glpk-5.0/src/misc/strspx.c new file mode 100644 index 0000000..6be016b --- /dev/null +++ b/glpk-5.0/src/misc/strspx.c @@ -0,0 +1,58 @@ +/* strspx.c (remove all spaces from string) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2000 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "misc.h" + +/*********************************************************************** +*  NAME +* +*  strspx - remove all spaces from character string +* +*  SYNOPSIS +* +*  #include "misc.h" +*  char *strspx(char *str); +* +*  DESCRIPTION +* +*  The routine strspx removes all spaces from the character string str. +* +*  RETURNS +* +*  The routine returns a pointer to the character string. +* +*  EXAMPLES +* +*  strspx("   Errare   humanum   est   ") => "Errarehumanumest" +* +*  strspx("      ")                       => ""                       */ + +char *strspx(char *str) +{     char *s, *t; +      for (s = t = str; *s; s++) +      {  if (*s != ' ') +            *t++ = *s; +      } +      *t = '\0'; +      return str; +} + +/* eof */ diff --git a/glpk-5.0/src/misc/strtrim.c b/glpk-5.0/src/misc/strtrim.c new file mode 100644 index 0000000..d3528cb --- /dev/null +++ b/glpk-5.0/src/misc/strtrim.c @@ -0,0 +1,60 @@ +/* strtrim.c (remove trailing spaces from string) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2000 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "misc.h" +#include "stdc.h" + +/*********************************************************************** +*  NAME +* +*  strtrim - remove trailing spaces from character string +* +*  SYNOPSIS +* +*  #include "misc.h" +*  char *strtrim(char *str); +* +*  DESCRIPTION +* +*  The routine strtrim removes trailing spaces from the character +*  string str. +* +*  RETURNS +* +*  The routine returns a pointer to the character string. +* +*  EXAMPLES +* +*  strtrim("Errare humanum est   ") => "Errare humanum est" +* +*  strtrim("      ")                => ""                             */ + +char *strtrim(char *str) +{     char *t; +      for (t = strrchr(str, '\0') - 1; t >= str; t--) +      {  if (*t != ' ') +            break; +         *t = '\0'; +      } +      return str; +} + +/* eof */ diff --git a/glpk-5.0/src/misc/triang.c b/glpk-5.0/src/misc/triang.c new file mode 100644 index 0000000..e70eaa9 --- /dev/null +++ b/glpk-5.0/src/misc/triang.c @@ -0,0 +1,309 @@ +/* triang.c (find maximal triangular part of rectangular matrix) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2012-2013 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "triang.h" + +/*********************************************************************** +*  triang - find maximal triangular part of rectangular matrix +* +*  Given a mxn sparse matrix A this routine finds permutation matrices +*  P and Q such that matrix A' = P * A * Q has the following structure: +* +*        1         s         n +*     1  * . . . . . x x x x x +*        * * . . . . x x x x x +*        * * * . . . x x x x x +*        * * * * . . x x x x x +*        * * * * * . x x x x x +*     s  * * * * * * x x x x x +*        x x x x x x x x x x x +*        x x x x x x x x x x x +*     m  x x x x x x x x x x x +* +*  where '*' are elements of the triangular part, '.' are structural +*  zeros, 'x' are other elements. +* +*  The formal routine mat specifies the original matrix A in both row- +*  and column-wise format. If the routine mat is called with k = +i, +*  1 <= i <= m, it should store column indices and values of non-zero +*  elements of i-th row of A in locations ind[1], ..., ind[len] and +*  val[1], ..., val[len], resp., where len is the returned number of +*  non-zeros in the row, 0 <= len <= n. Similarly, if the routine mat +*  is called with k = -j, 1 <= j <= n, it should store row indices and +*  values of non-zero elements of j-th column of A and return len, the +*  number of non-zeros in the column, 0 <= len <= m. Should note that +*  duplicate indices are not allowed. +* +*  The parameter info is a transit pointer passed to the routine mat. +* +*  The parameter tol is a tolerance. The routine triang guarantees that +*  each diagonal element in the triangular part of matrix A' is not +*  less in magnitude than tol * max, where max is the maximal magnitude +*  of elements in corresponding column. +* +*  On exit the routine triang stores information on the triangular part +*  found in the arrays rn and cn. Elements rn[1], ..., rn[s] specify +*  row numbers and elements cn[1], ..., cn[s] specify column numbers +*  of the original matrix A, which correspond to rows/columns 1, ..., s +*  of matrix A', where s is the size of the triangular part returned by +*  the routine, 0 <= s <= min(m, n). The order of rows and columns that +*  are not included in the triangular part remains unspecified. +* +*  ALGORITHM +* +*  The routine triang uses a simple greedy heuristic. +* +*  At some step the matrix A' = P * A * Q has the following structure: +* +*        1                   n +*     1  * . . . . . . . x x x +*        * * . . . . . . x x x +*        * * * . . . . . x x x +*        * * * * . . . . x x x +*        x x x x # # # # x x x +*        x x x x # # # # x x x +*        x x x x # # # # x x x +*        x x x x # # # # x x x +*     m  x x x x # # # # x x x +* +*  where '#' are elements of active submatrix. Initially P = Q = I, so +*  the active submatrix is the original matrix A = A'. +* +*  If some row has exactly one non-zero in the active submatrix (row +*  singleton), the routine includes this row and corresponding column +*  in the triangular part, and removes the column from the active +*  submatrix. Otherwise, the routine simply removes a column having +*  maximal number of non-zeros from the active submatrix in the hope +*  that new row singleton(s) will appear. +* +*  COMPLEXITY +* +*  The time complexity of the routine triang is O(nnz), where nnz is +*  number of non-zeros in the original matrix A. */ + +int triang(int m, int n, int (*mat)(void *info, int k, int ind[], +      double val[]), void *info, double tol, int rn[], int cn[]) +{     int head, i, j, jj, k, kk, ks, len, len2, next_j, ns, size; +      int *cind, *rind, *cnt, *ptr, *list, *prev, *next; +      double *cval, *rval, *big; +      char *flag; +      /* allocate working arrays */ +      cind = talloc(1+m, int); +      cval = talloc(1+m, double); +      rind = talloc(1+n, int); +      rval = talloc(1+n, double); +      cnt = ptr = talloc(1+m, int); +      list = talloc(1+n, int); +      prev = talloc(1+n, int); +      next = talloc(1+n, int); +      big = talloc(1+n, double); +      flag = talloc(1+n, char); +      /*--------------------------------------------------------------*/ +      /* build linked lists of columns having equal lengths           */ +      /*--------------------------------------------------------------*/ +      /* ptr[len], 0 <= len <= m, is number of first column of length +       * len; +       * next[j], 1 <= j <= n, is number of next column having the same +       * length as column j; +       * big[j], 1 <= j <= n, is maximal magnitude of elements in j-th +       * column */ +      for (len = 0; len <= m; len++) +         ptr[len] = 0; +      for (j = 1; j <= n; j++) +      {  /* get j-th column */ +         len = mat(info, -j, cind, cval); +         xassert(0 <= len && len <= m); +         /* add this column to beginning of list ptr[len] */ +         next[j] = ptr[len]; +         ptr[len] = j; +         /* determine maximal magnitude of elements in this column */ +         big[j] = 0.0; +         for (k = 1; k <= len; k++) +         {  if (big[j] < fabs(cval[k])) +               big[j] = fabs(cval[k]); +         } +      } +      /*--------------------------------------------------------------*/ +      /* build doubly linked list of columns ordered by decreasing    */ +      /* column lengths                                               */ +      /*--------------------------------------------------------------*/ +      /* head is number of first column in the list; +       * prev[j], 1 <= j <= n, is number of column that precedes j-th +       * column in the list; +       * next[j], 1 <= j <= n, is number of column that follows j-th +       * column in the list */ +      head = 0; +      for (len = 0; len <= m; len++) +      {  /* walk thru list of columns of length len */ +         for (j = ptr[len]; j != 0; j = next_j) +         {  next_j = next[j]; +            /* add j-th column to beginning of the column list */ +            prev[j] = 0; +            next[j] = head; +            if (head != 0) +               prev[head] = j; +            head = j; +         } +      } +      /*--------------------------------------------------------------*/ +      /* build initial singleton list                                 */ +      /*--------------------------------------------------------------*/ +      /* there are used two list of columns: +       * 1) doubly linked list of active columns, in which all columns +       *    are ordered by decreasing column lengths; +       * 2) singleton list; an active column is included in this list +       *    if it has at least one row singleton in active submatrix */ +      /* flag[j], 1 <= j <= n, is a flag of j-th column: +       * 0  j-th column is inactive; +       * 1  j-th column is active; +       * 2  j-th column is active and has row singleton(s) */ +      /* initially all columns are active */ +      for (j = 1; j <= n; j++) +         flag[j] = 1; +      /* initialize row counts and build initial singleton list */ +      /* cnt[i], 1 <= i <= m, is number of non-zeros, which i-th row +       * has in active submatrix; +       * ns is size of singleton list; +       * list[1], ..., list[ns] are numbers of active columns included +       * in the singleton list */ +      ns = 0; +      for (i = 1; i <= m; i++) +      {  /* get i-th row */ +         len = cnt[i] = mat(info, +i, rind, rval); +         xassert(0 <= len && len <= n); +         if (len == 1) +         {  /* a[i,j] is row singleton */ +            j = rind[1]; +            xassert(1 <= j && j <= n); +            if (flag[j] != 2) +            {  /* include j-th column in singleton list */ +               flag[j] = 2; +               list[++ns] = j; +            } +         } +      } +      /*--------------------------------------------------------------*/ +      /* main loop                                                    */ +      /*--------------------------------------------------------------*/ +      size = 0; /* size of triangular part */ +      /* loop until active column list is non-empty, i.e. until the +       * active submatrix has at least one column */ +      while (head != 0) +      {  if (ns == 0) +         {  /* singleton list is empty */ +            /* remove from the active submatrix a column of maximal +             * length in the hope that some row singletons appear */ +            j = head; +            len = mat(info, -j, cind, cval); +            xassert(0 <= len && len <= m); +            goto drop; +         } +         /* take column j from the singleton list */ +         j = list[ns--]; +         xassert(flag[j] == 2); +         /* j-th column has at least one row singleton in the active +          * submatrix; choose one having maximal magnitude */ +         len = mat(info, -j, cind, cval); +         xassert(0 <= len && len <= m); +         kk = 0; +         for (k = 1; k <= len; k++) +         {  i = cind[k]; +            xassert(1 <= i && i <= m); +            if (cnt[i] == 1) +            {  /* a[i,j] is row singleton */ +               if (kk == 0 || fabs(cval[kk]) < fabs(cval[k])) +                  kk = k; +            } +         } +         xassert(kk > 0); +         /* check magnitude of the row singleton chosen */ +         if (fabs(cval[kk]) < tol * big[j]) +         {  /* all row singletons are too small in magnitude; drop j-th +             * column */ +            goto drop; +         } +         /* row singleton a[i,j] is ok; add i-th row and j-th column to +          * the triangular part */ +         size++; +         rn[size] = cind[kk]; +         cn[size] = j; +drop:    /* remove j-th column from the active submatrix */ +         xassert(flag[j]); +         flag[j] = 0; +         if (prev[j] == 0) +            head = next[j]; +         else +            next[prev[j]] = next[j]; +         if (next[j] == 0) +            ; +         else +            prev[next[j]] = prev[j]; +         /* decrease row counts */ +         for (k = 1; k <= len; k++) +         {  i = cind[k]; +            xassert(1 <= i && i <= m); +            xassert(cnt[i] > 0); +            cnt[i]--; +            if (cnt[i] == 1) +            {  /* new singleton appeared in i-th row; determine number +                * of corresponding column (it is the only active column +                * in this row) */ +               len2 = mat(info, +i, rind, rval); +               xassert(0 <= len2 && len2 <= n); +               ks = 0; +               for (kk = 1; kk <= len2; kk++) +               {  jj = rind[kk]; +                  xassert(1 <= jj && jj <= n); +                  if (flag[jj]) +                  {  xassert(ks == 0); +                     ks = kk; +                  } +               } +               xassert(ks > 0); +               /* a[i,jj] is new row singleton */ +               jj = rind[ks]; +               if (flag[jj] != 2) +               {  /* include jj-th column in the singleton list */ +                  flag[jj] = 2; +                  list[++ns] = jj; +               } +            } +         } +      } +      /* now all row counts should be zero */ +      for (i = 1; i <= m; i++) +         xassert(cnt[i] == 0); +      /* deallocate working arrays */ +      tfree(cind); +      tfree(cval); +      tfree(rind); +      tfree(rval); +      tfree(ptr); +      tfree(list); +      tfree(prev); +      tfree(next); +      tfree(big); +      tfree(flag); +      return size; +} + +/* eof */ diff --git a/glpk-5.0/src/misc/triang.h b/glpk-5.0/src/misc/triang.h new file mode 100644 index 0000000..47c33b1 --- /dev/null +++ b/glpk-5.0/src/misc/triang.h @@ -0,0 +1,32 @@ +/* triang.h (find maximal triangular part of rectangular matrix) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2012-2013 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#ifndef TRIANG_H +#define TRIANG_H + +#define triang _glp_triang +int triang(int m, int n, int (*mat)(void *info, int k, int ind[], +      double val[]), void *info, double tol, int rn[], int cn[]); +/* find maximal triangular part of rectangular matrix */ + +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/wclique.c b/glpk-5.0/src/misc/wclique.c new file mode 100644 index 0000000..5daa69c --- /dev/null +++ b/glpk-5.0/src/misc/wclique.c @@ -0,0 +1,242 @@ +/* wclique.c (maximum weight clique, Ostergard's algorithm) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +* +*  Two subroutines sub() and wclique() below are intended to find a +*  maximum weight clique in a given undirected graph. These subroutines +*  are slightly modified version of the program WCLIQUE developed by +*  Patric Ostergard <http://www.tcs.hut.fi/~pat/wclique.html> and based +*  on ideas from the article "P. R. J. Ostergard, A new algorithm for +*  the maximum-weight clique problem, submitted for publication", which +*  in turn is a generalization of the algorithm for unweighted graphs +*  presented in "P. R. J. Ostergard, A fast algorithm for the maximum +*  clique problem, submitted for publication". +* +*  USED WITH PERMISSION OF THE AUTHOR OF THE ORIGINAL CODE. +* +*  Changes were made by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "wclique.h" + +/*********************************************************************** +*  NAME +* +*  wclique - find maximum weight clique with Ostergard's algorithm +* +*  SYNOPSIS +* +*  #include "wclique.h" +*  int wclique(int n, const int w[], const unsigned char a[], +*     int ind[]); +* +*  DESCRIPTION +* +*  The routine wclique finds a maximum weight clique in an undirected +*  graph with Ostergard's algorithm. +* +*  INPUT PARAMETERS +* +*  n is the number of vertices, n > 0. +* +*  w[i], i = 1,...,n, is a weight of vertex i. +* +*  a[*] is the strict (without main diagonal) lower triangle of the +*  graph adjacency matrix in packed format. +* +*  OUTPUT PARAMETER +* +*  ind[k], k = 1,...,size, is the number of a vertex included in the +*  clique found, 1 <= ind[k] <= n, where size is the number of vertices +*  in the clique returned on exit. +* +*  RETURNS +* +*  The routine returns the clique size, i.e. the number of vertices in +*  the clique. */ + +struct csa +{     /* common storage area */ +      int n; +      /* number of vertices */ +      const int *wt; /* int wt[0:n-1]; */ +      /* weights */ +      const unsigned char *a; +      /* adjacency matrix (packed lower triangle without main diag.) */ +      int record; +      /* weight of best clique */ +      int rec_level; +      /* number of vertices in best clique */ +      int *rec; /* int rec[0:n-1]; */ +      /* best clique so far */ +      int *clique; /* int clique[0:n-1]; */ +      /* table for pruning */ +      int *set; /* int set[0:n-1]; */ +      /* current clique */ +}; + +#define n         (csa->n) +#define wt        (csa->wt) +#define a         (csa->a) +#define record    (csa->record) +#define rec_level (csa->rec_level) +#define rec       (csa->rec) +#define clique    (csa->clique) +#define set       (csa->set) + +#if 0 +static int is_edge(struct csa *csa, int i, int j) +{     /* if there is arc (i,j), the routine returns true; otherwise +       * false; 0 <= i, j < n */ +      int k; +      xassert(0 <= i && i < n); +      xassert(0 <= j && j < n); +      if (i == j) return 0; +      if (i < j) k = i, i = j, j = k; +      k = (i * (i - 1)) / 2 + j; +      return a[k / CHAR_BIT] & +         (unsigned char)(1 << ((CHAR_BIT - 1) - k % CHAR_BIT)); +} +#else +#define is_edge(csa, i, j) ((i) == (j) ? 0 : \ +      (i) > (j) ? is_edge1(i, j) : is_edge1(j, i)) +#define is_edge1(i, j) is_edge2(((i) * ((i) - 1)) / 2 + (j)) +#define is_edge2(k) (a[(k) / CHAR_BIT] & \ +      (unsigned char)(1 << ((CHAR_BIT - 1) - (k) % CHAR_BIT))) +#endif + +static void sub(struct csa *csa, int ct, int table[], int level, +      int weight, int l_weight) +{     int i, j, k, curr_weight, left_weight, *p1, *p2, *newtable; +      newtable = xcalloc(n, sizeof(int)); +      if (ct <= 0) +      {  /* 0 or 1 elements left; include these */ +         if (ct == 0) +         {  set[level++] = table[0]; +            weight += l_weight; +         } +         if (weight > record) +         {  record = weight; +            rec_level = level; +            for (i = 0; i < level; i++) rec[i] = set[i]; +         } +         goto done; +      } +      for (i = ct; i >= 0; i--) +      {  if ((level == 0) && (i < ct)) goto done; +         k = table[i]; +         if ((level > 0) && (clique[k] <= (record - weight))) +            goto done; /* prune */ +         set[level] = k; +         curr_weight = weight + wt[k]; +         l_weight -= wt[k]; +         if (l_weight <= (record - curr_weight)) +            goto done; /* prune */ +         p1 = newtable; +         p2 = table; +         left_weight = 0; +         while (p2 < table + i) +         {  j = *p2++; +            if (is_edge(csa, j, k)) +            {  *p1++ = j; +               left_weight += wt[j]; +            } +         } +         if (left_weight <= (record - curr_weight)) continue; +         sub(csa, p1 - newtable - 1, newtable, level + 1, curr_weight, +            left_weight); +      } +done: xfree(newtable); +      return; +} + +int wclique(int n_, const int w[], const unsigned char a_[], int ind[]) +{     struct csa csa_, *csa = &csa_; +      int i, j, p, max_wt, max_nwt, wth, *used, *nwt, *pos; +      double timer; +      n = n_; +      xassert(n > 0); +      wt = &w[1]; +      a = a_; +      record = 0; +      rec_level = 0; +      rec = &ind[1]; +      clique = xcalloc(n, sizeof(int)); +      set = xcalloc(n, sizeof(int)); +      used = xcalloc(n, sizeof(int)); +      nwt = xcalloc(n, sizeof(int)); +      pos = xcalloc(n, sizeof(int)); +      /* start timer */ +      timer = xtime(); +      /* order vertices */ +      for (i = 0; i < n; i++) +      {  nwt[i] = 0; +         for (j = 0; j < n; j++) +            if (is_edge(csa, i, j)) nwt[i] += wt[j]; +      } +      for (i = 0; i < n; i++) +         used[i] = 0; +      for (i = n-1; i >= 0; i--) +      {  max_wt = -1; +         max_nwt = -1; +         for (j = 0; j < n; j++) +         {  if ((!used[j]) && ((wt[j] > max_wt) || (wt[j] == max_wt +               && nwt[j] > max_nwt))) +            {  max_wt = wt[j]; +               max_nwt = nwt[j]; +               p = j; +            } +         } +         pos[i] = p; +         used[p] = 1; +         for (j = 0; j < n; j++) +            if ((!used[j]) && (j != p) && (is_edge(csa, p, j))) +               nwt[j] -= wt[p]; +      } +      /* main routine */ +      wth = 0; +      for (i = 0; i < n; i++) +      {  wth += wt[pos[i]]; +         sub(csa, i, pos, 0, 0, wth); +         clique[pos[i]] = record; +         if (xdifftime(xtime(), timer) >= 5.0 - 0.001) +         {  /* print current record and reset timer */ +            xprintf("level = %d (%d); best = %d\n", i+1, n, record); +            timer = xtime(); +         } +      } +      xfree(clique); +      xfree(set); +      xfree(used); +      xfree(nwt); +      xfree(pos); +      /* return the solution found */ +      for (i = 1; i <= rec_level; i++) ind[i]++; +      return rec_level; +} + +#undef n +#undef wt +#undef a +#undef record +#undef rec_level +#undef rec +#undef clique +#undef set + +/* eof */ diff --git a/glpk-5.0/src/misc/wclique.h b/glpk-5.0/src/misc/wclique.h new file mode 100644 index 0000000..7ee4468 --- /dev/null +++ b/glpk-5.0/src/misc/wclique.h @@ -0,0 +1,31 @@ +/* wclique.h (maximum weight clique, Ostergard's algorithm) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#ifndef WCLIQUE_H +#define WCLIQUE_H + +#define wclique _glp_wclique +int wclique(int n, const int w[], const unsigned char a[], int ind[]); +/* find maximum weight clique with Ostergard's algorithm */ + +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/wclique1.c b/glpk-5.0/src/misc/wclique1.c new file mode 100644 index 0000000..c0cb082 --- /dev/null +++ b/glpk-5.0/src/misc/wclique1.c @@ -0,0 +1,315 @@ +/* wclique1.c (maximum weight clique, greedy heuristic) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2012-2018 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "wclique1.h" + +/*********************************************************************** +*  NAME +* +*  wclique1 - find maximum weight clique with greedy heuristic +* +*  SYNOPSIS +* +*  #include "wclique1.h" +*  int wclique1(int n, const double w[], +*     int (*func)(void *info, int i, int ind[]), void *info, int c[]); +* +*  DESCRIPTION +* +*  The routine wclique1 implements a sequential greedy heuristic to +*  find maximum weight clique in a given (undirected) graph G = (V, E). +* +*  The parameter n specifies the number of vertices |V| in the graph, +*  n >= 0. +* +*  The array w specifies vertex weights in locations w[i], i = 1,...,n. +*  All weights must be non-negative. +* +*  The formal routine func specifies the graph. For a given vertex i, +*  1 <= i <= n, it stores indices of all vertices adjacent to vertex i +*  in locations ind[1], ..., ind[deg], where deg is the degree of +*  vertex i, 0 <= deg < n, returned on exit. Note that self-loops and +*  multiple edges are not allowed. +* +*  The parameter info is a cookie passed to the routine func. +* +*  On exit the routine wclique1 stores vertex indices included in +*  the clique found to locations c[1], ..., c[size], where size is the +*  clique size returned by the routine, 0 <= size <= n. +* +*  RETURNS +* +*  The routine wclique1 returns the size of the clique found. */ + +struct vertex { int i; double cw; }; + +static int CDECL fcmp(const void *xx, const void *yy) +{     const struct vertex *x = xx, *y = yy; +      if (x->cw > y->cw) return -1; +      if (x->cw < y->cw) return +1; +      return 0; +} + +int wclique1(int n, const double w[], +      int (*func)(void *info, int i, int ind[]), void *info, int c[]) +{     struct vertex *v_list; +      int deg, c_size, d_size, i, j, k, kk, l, *ind, *c_list, *d_list, +         size = 0; +      double c_wght, d_wght, *sw, best = 0.0; +      char *d_flag, *skip; +      /* perform sanity checks */ +      xassert(n >= 0); +      for (i = 1; i <= n; i++) +         xassert(w[i] >= 0.0); +      /* if the graph is empty, nothing to do */ +      if (n == 0) goto done; +      /* allocate working arrays */ +      ind = xcalloc(1+n, sizeof(int)); +      v_list = xcalloc(1+n, sizeof(struct vertex)); +      c_list = xcalloc(1+n, sizeof(int)); +      d_list = xcalloc(1+n, sizeof(int)); +      d_flag = xcalloc(1+n, sizeof(char)); +      skip = xcalloc(1+n, sizeof(char)); +      sw = xcalloc(1+n, sizeof(double)); +      /* build the vertex list */ +      for (i = 1; i <= n; i++) +      {  v_list[i].i = i; +         /* compute the cumulative weight of each vertex i, which is +          * cw[i] = w[i] + sum{j : (i,j) in E} w[j] */ +         v_list[i].cw = w[i]; +         deg = func(info, i, ind); +         xassert(0 <= deg && deg < n); +         for (k = 1; k <= deg; k++) +         {  j = ind[k]; +            xassert(1 <= j && j <= n && j != i); +            v_list[i].cw += w[j]; +         } +      } +      /* sort the vertex list to access vertices in descending order of +       * cumulative weights */ +      qsort(&v_list[1], n, sizeof(struct vertex), fcmp); +      /* initially all vertices are unmarked */ +      memset(&skip[1], 0, sizeof(char) * n); +      /* clear flags of all vertices */ +      memset(&d_flag[1], 0, sizeof(char) * n); +      /* look through all vertices of the graph */ +      for (l = 1; l <= n; l++) +      {  /* take vertex i */ +         i = v_list[l].i; +         /* if this vertex was already included in one of previosuly +          * constructed cliques, skip it */ +         if (skip[i]) continue; +         /* use vertex i as the initial clique vertex */ +         c_size = 1;    /* size of current clique */ +         c_list[1] = i; /* list of vertices in current clique */ +         c_wght = w[i]; /* weight of current clique */ +         /* determine the candidate set D = { j : (i,j) in E } */ +         d_size = func(info, i, d_list); +         xassert(0 <= d_size && d_size < n); +         d_wght = 0.0;  /* weight of set D */ +         for (k = 1; k <= d_size; k++) +         {  j = d_list[k]; +            xassert(1 <= j && j <= n && j != i); +            xassert(!d_flag[j]); +            d_flag[j] = 1; +            d_wght += w[j]; +         } +         /* check an upper bound to the final clique weight */ +         if (c_wght + d_wght < best + 1e-5 * (1.0 + fabs(best))) +         {  /* skip constructing the current clique */ +            goto next; +         } +         /* compute the summary weight of each vertex i in D, which is +          * sw[i] = w[i] + sum{j in D and (i,j) in E} w[j] */ +         for (k = 1; k <= d_size; k++) +         {  i = d_list[k]; +            sw[i] = w[i]; +            /* consider vertices adjacent to vertex i */ +            deg = func(info, i, ind); +            xassert(0 <= deg && deg < n); +            for (kk = 1; kk <= deg; kk++) +            {  j = ind[kk]; +               xassert(1 <= j && j <= n && j != i); +               if (d_flag[j]) sw[i] += w[j]; +            } +         } +         /* grow the current clique by adding vertices from D */ +         while (d_size > 0) +         {  /* check an upper bound to the final clique weight */ +            if (c_wght + d_wght < best + 1e-5 * (1.0 + fabs(best))) +            {  /* skip constructing the current clique */ +               goto next; +            } +            /* choose vertex i in D having maximal summary weight */ +            i = d_list[1]; +            for (k = 2; k <= d_size; k++) +            {  j = d_list[k]; +               if (sw[i] < sw[j]) i = j; +            } +            /* include vertex i in the current clique */ +            c_size++; +            c_list[c_size] = i; +            c_wght += w[i]; +            /* remove all vertices not adjacent to vertex i, including +             * vertex i itself, from the candidate set D */ +            deg = func(info, i, ind); +            xassert(0 <= deg && deg < n); +            for (k = 1; k <= deg; k++) +            {  j = ind[k]; +               xassert(1 <= j && j <= n && j != i); +               /* vertex j is adjacent to vertex i */ +               if (d_flag[j]) +               {  xassert(d_flag[j] == 1); +                  /* mark vertex j to keep it in D */ +                  d_flag[j] = 2; +               } +            } +            kk = d_size, d_size = 0; +            for (k = 1; k <= kk; k++) +            {  j = d_list[k]; +               if (d_flag[j] == 1) +               {  /* remove vertex j from D */ +                  d_flag[j] = 0; +                  d_wght -= w[j]; +               } +               else if (d_flag[j] == 2) +               {  /* keep vertex j in D */ +                  d_list[++d_size] = j; +                  d_flag[j] = 1; +               } +               else +                  xassert(d_flag != d_flag); +            } +         } +         /* the current clique has been completely constructed */ +         if (best < c_wght) +         {  best = c_wght; +            size = c_size; +            xassert(1 <= size && size <= n); +            memcpy(&c[1], &c_list[1], size * sizeof(int)); +         } +next:    /* mark the current clique vertices in order not to use them +          * as initial vertices anymore */ +         for (k = 1; k <= c_size; k++) +            skip[c_list[k]] = 1; +         /* set D can be non-empty, so clean up vertex flags */ +         for (k = 1; k <= d_size; k++) +            d_flag[d_list[k]] = 0; +      } +      /* free working arrays */ +      xfree(ind); +      xfree(v_list); +      xfree(c_list); +      xfree(d_list); +      xfree(d_flag); +      xfree(skip); +      xfree(sw); +done: /* return to the calling program */ +      return size; +} + +/**********************************************************************/ + +#ifdef GLP_TEST +#include "glpk.h" +#include "rng.h" + +typedef struct { double w; } v_data; + +#define weight(v) (((v_data *)((v)->data))->w) + +glp_graph *G; + +char *flag; + +int func(void *info, int i, int ind[]) +{     glp_arc *e; +      int j, k, deg = 0; +      xassert(info == NULL); +      xassert(1 <= i && i <= G->nv); +      /* look through incoming arcs */ +      for (e = G->v[i]->in; e != NULL; e = e->h_next) +      {  j = e->tail->i; /* j->i */ +         if (j != i && !flag[j]) ind[++deg] = j, flag[j] = 1; +      } +      /* look through outgoing arcs */ +      for (e = G->v[i]->out; e != NULL; e = e->t_next) +      {  j = e->head->i; /* i->j */ +         if (j != i && !flag[j]) ind[++deg] = j, flag[j] = 1; +      } +      /* clear the flag array */ +      xassert(deg < G->nv); +      for (k = 1; k <= deg; k++) flag[ind[k]] = 0; +      return deg; +} + +int main(int argc, char *argv[]) +{     RNG *rand; +      int i, k, kk, size, *c, *ind, deg; +      double *w, sum, t; +      /* read graph in DIMACS format */ +      G = glp_create_graph(sizeof(v_data), 0); +      xassert(argc == 2); +      xassert(glp_read_ccdata(G, offsetof(v_data, w), argv[1]) == 0); +      /* print the number of connected components */ +      xprintf("nc = %d\n", glp_weak_comp(G, -1)); +      /* assign random weights unformly distributed in [1,100] */ +      w = xcalloc(1+G->nv, sizeof(double)); +      rand = rng_create_rand(); +      for (i = 1; i <= G->nv; i++) +#if 0 +         w[i] = weight(G->v[i]) = 1.0; +#else +         w[i] = weight(G->v[i]) = rng_unif_rand(rand, 100) + 1; +#endif +      /* write graph in DIMACS format */ +      xassert(glp_write_ccdata(G, offsetof(v_data, w), "graph") == 0); +      /* find maximum weight clique */ +      c = xcalloc(1+G->nv, sizeof(int)); +      flag = xcalloc(1+G->nv, sizeof(char)); +      memset(&flag[1], 0, G->nv); +      t = xtime(); +      size = wclique1(G->nv, w, func, NULL, c); +      xprintf("Time used: %.1f s\n", xdifftime(xtime(), t)); +      /* check the clique found */ +      ind = xcalloc(1+G->nv, sizeof(int)); +      for (k = 1; k <= size; k++) +      {  i = c[k]; +         deg = func(NULL, i, ind); +         for (kk = 1; kk <= size; kk++) +            flag[c[kk]] = 1; +         flag[i] = 0; +         for (kk = 1; kk <= deg; kk++) +            flag[ind[kk]] = 0; +         for (kk = 1; kk <= size; kk++) +            xassert(flag[c[kk]] == 0); +      } +      /* compute the clique weight */ +      sum = 0.0; +      for (i = 1; i <= size; i++) +         sum += w[c[i]]; +      xprintf("size = %d; sum = %g\n", size, sum); +      return 0; +} +#endif + +/* eof */ diff --git a/glpk-5.0/src/misc/wclique1.h b/glpk-5.0/src/misc/wclique1.h new file mode 100644 index 0000000..52596b1 --- /dev/null +++ b/glpk-5.0/src/misc/wclique1.h @@ -0,0 +1,32 @@ +/* wclique1.h (maximum weight clique, greedy heuristic) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2012-2013 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK 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 3 of the License, or +*  (at your option) any later version. +* +*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#ifndef WCLIQUE1_H +#define WCLIQUE1_H + +#define wclique1 _glp_wclique1 +int wclique1(int n, const double w[], +      int (*func)(void *info, int i, int ind[]), void *info, int c[]); +/* find maximum weight clique with greedy heuristic */ + +#endif + +/* eof */ | 
