Add graph references
This commit is contained in:
+403
@@ -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 */
|
||||
+71
@@ -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 */
|
||||
+284
@@ -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 */
|
||||
@@ -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 */
|
||||
+145
@@ -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 */
|
||||
@@ -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 */
|
||||
+241
@@ -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 */
|
||||
+61
@@ -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 */
|
||||
+219
@@ -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 */
|
||||
@@ -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 */
|
||||
+162
@@ -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 */
|
||||
+135
@@ -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 */
|
||||
+74
@@ -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 */
|
||||
+100
@@ -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 */
|
||||
+530
@@ -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 */
|
||||
+124
@@ -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 */
|
||||
+150
@@ -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 */
|
||||
+30
@@ -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 */
|
||||
+233
@@ -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 */
|
||||
@@ -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 */
|
||||
+464
@@ -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 */
|
||||
+42
@@ -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 */
|
||||
+314
@@ -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 */
|
||||
@@ -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 */
|
||||
+301
@@ -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 */
|
||||
@@ -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 */
|
||||
+59
@@ -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 */
|
||||
+1110
File diff suppressed because it is too large
Load Diff
+277
@@ -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
|
||||
+32
@@ -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 */
|
||||
+1160
File diff suppressed because it is too large
Load Diff
+252
@@ -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 */
|
||||
+380
@@ -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 */
|
||||
@@ -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 */
|
||||
+99
@@ -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 */
|
||||
+56
@@ -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 */
|
||||
@@ -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 */
|
||||
+100
@@ -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 */
|
||||
+167
@@ -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 */
|
||||
+31
@@ -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 */
|
||||
+227
@@ -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 */
|
||||
+65
@@ -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 */
|
||||
+71
@@ -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 */
|
||||
@@ -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 */
|
||||
+844
@@ -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 */
|
||||
+162
@@ -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 */
|
||||
@@ -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 */
|
||||
+108
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
+309
@@ -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 */
|
||||
@@ -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 */
|
||||
+242
@@ -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 */
|
||||
@@ -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 */
|
||||
+315
@@ -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 */
|
||||
@@ -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 */
|
||||
Reference in New Issue
Block a user