From feb8ebaeb76fa1c94de2dd7c4e5a0999b313f8c6 Mon Sep 17 00:00:00 2001 From: David Monniaux Date: Thu, 6 Jun 2019 20:09:32 +0200 Subject: GLPK 4.65 --- test/monniaux/glpk-4.65/src/misc/avl.c | 405 ++++ test/monniaux/glpk-4.65/src/misc/avl.h | 73 + test/monniaux/glpk-4.65/src/misc/bignum.c | 286 +++ test/monniaux/glpk-4.65/src/misc/bignum.h | 37 + test/monniaux/glpk-4.65/src/misc/dimacs.c | 147 ++ test/monniaux/glpk-4.65/src/misc/dimacs.h | 81 + test/monniaux/glpk-4.65/src/misc/dmp.c | 243 +++ test/monniaux/glpk-4.65/src/misc/dmp.h | 63 + test/monniaux/glpk-4.65/src/misc/ffalg.c | 221 +++ test/monniaux/glpk-4.65/src/misc/ffalg.h | 34 + test/monniaux/glpk-4.65/src/misc/fp2rat.c | 164 ++ test/monniaux/glpk-4.65/src/misc/fvs.c | 137 ++ test/monniaux/glpk-4.65/src/misc/fvs.h | 76 + test/monniaux/glpk-4.65/src/misc/gcd.c | 102 + test/monniaux/glpk-4.65/src/misc/jd.c | 152 ++ test/monniaux/glpk-4.65/src/misc/jd.h | 32 + test/monniaux/glpk-4.65/src/misc/keller.c | 235 +++ test/monniaux/glpk-4.65/src/misc/keller.h | 34 + test/monniaux/glpk-4.65/src/misc/ks.c | 466 +++++ test/monniaux/glpk-4.65/src/misc/ks.h | 44 + test/monniaux/glpk-4.65/src/misc/mc13d.c | 314 +++ test/monniaux/glpk-4.65/src/misc/mc13d.h | 34 + test/monniaux/glpk-4.65/src/misc/mc21a.c | 301 +++ test/monniaux/glpk-4.65/src/misc/mc21a.h | 34 + test/monniaux/glpk-4.65/src/misc/misc.h | 61 + test/monniaux/glpk-4.65/src/misc/mt1.c | 1110 +++++++++++ test/monniaux/glpk-4.65/src/misc/mt1.f | 277 +++ test/monniaux/glpk-4.65/src/misc/mt1.h | 34 + test/monniaux/glpk-4.65/src/misc/mygmp.c | 1162 +++++++++++ test/monniaux/glpk-4.65/src/misc/mygmp.h | 254 +++ test/monniaux/glpk-4.65/src/misc/okalg.c | 382 ++++ test/monniaux/glpk-4.65/src/misc/okalg.h | 35 + test/monniaux/glpk-4.65/src/misc/qmd.c | 584 ++++++ test/monniaux/glpk-4.65/src/misc/qmd.h | 58 + test/monniaux/glpk-4.65/src/misc/relax4.c | 2850 +++++++++++++++++++++++++++ test/monniaux/glpk-4.65/src/misc/relax4.h | 102 + test/monniaux/glpk-4.65/src/misc/rng.c | 227 +++ test/monniaux/glpk-4.65/src/misc/rng.h | 67 + test/monniaux/glpk-4.65/src/misc/rng1.c | 73 + test/monniaux/glpk-4.65/src/misc/round2n.c | 64 + test/monniaux/glpk-4.65/src/misc/str2int.c | 92 + test/monniaux/glpk-4.65/src/misc/str2num.c | 110 ++ test/monniaux/glpk-4.65/src/misc/strspx.c | 60 + test/monniaux/glpk-4.65/src/misc/strtrim.c | 62 + test/monniaux/glpk-4.65/src/misc/triang.c | 311 +++ test/monniaux/glpk-4.65/src/misc/triang.h | 34 + test/monniaux/glpk-4.65/src/misc/wclique.c | 242 +++ test/monniaux/glpk-4.65/src/misc/wclique.h | 33 + test/monniaux/glpk-4.65/src/misc/wclique1.c | 317 +++ test/monniaux/glpk-4.65/src/misc/wclique1.h | 34 + 50 files changed, 12350 insertions(+) create mode 100644 test/monniaux/glpk-4.65/src/misc/avl.c create mode 100644 test/monniaux/glpk-4.65/src/misc/avl.h create mode 100644 test/monniaux/glpk-4.65/src/misc/bignum.c create mode 100644 test/monniaux/glpk-4.65/src/misc/bignum.h create mode 100644 test/monniaux/glpk-4.65/src/misc/dimacs.c create mode 100644 test/monniaux/glpk-4.65/src/misc/dimacs.h create mode 100644 test/monniaux/glpk-4.65/src/misc/dmp.c create mode 100644 test/monniaux/glpk-4.65/src/misc/dmp.h create mode 100644 test/monniaux/glpk-4.65/src/misc/ffalg.c create mode 100644 test/monniaux/glpk-4.65/src/misc/ffalg.h create mode 100644 test/monniaux/glpk-4.65/src/misc/fp2rat.c create mode 100644 test/monniaux/glpk-4.65/src/misc/fvs.c create mode 100644 test/monniaux/glpk-4.65/src/misc/fvs.h create mode 100644 test/monniaux/glpk-4.65/src/misc/gcd.c create mode 100644 test/monniaux/glpk-4.65/src/misc/jd.c create mode 100644 test/monniaux/glpk-4.65/src/misc/jd.h create mode 100644 test/monniaux/glpk-4.65/src/misc/keller.c create mode 100644 test/monniaux/glpk-4.65/src/misc/keller.h create mode 100644 test/monniaux/glpk-4.65/src/misc/ks.c create mode 100644 test/monniaux/glpk-4.65/src/misc/ks.h create mode 100644 test/monniaux/glpk-4.65/src/misc/mc13d.c create mode 100644 test/monniaux/glpk-4.65/src/misc/mc13d.h create mode 100644 test/monniaux/glpk-4.65/src/misc/mc21a.c create mode 100644 test/monniaux/glpk-4.65/src/misc/mc21a.h create mode 100644 test/monniaux/glpk-4.65/src/misc/misc.h create mode 100644 test/monniaux/glpk-4.65/src/misc/mt1.c create mode 100644 test/monniaux/glpk-4.65/src/misc/mt1.f create mode 100644 test/monniaux/glpk-4.65/src/misc/mt1.h create mode 100644 test/monniaux/glpk-4.65/src/misc/mygmp.c create mode 100644 test/monniaux/glpk-4.65/src/misc/mygmp.h create mode 100644 test/monniaux/glpk-4.65/src/misc/okalg.c create mode 100644 test/monniaux/glpk-4.65/src/misc/okalg.h create mode 100644 test/monniaux/glpk-4.65/src/misc/qmd.c create mode 100644 test/monniaux/glpk-4.65/src/misc/qmd.h create mode 100644 test/monniaux/glpk-4.65/src/misc/relax4.c create mode 100644 test/monniaux/glpk-4.65/src/misc/relax4.h create mode 100644 test/monniaux/glpk-4.65/src/misc/rng.c create mode 100644 test/monniaux/glpk-4.65/src/misc/rng.h create mode 100644 test/monniaux/glpk-4.65/src/misc/rng1.c create mode 100644 test/monniaux/glpk-4.65/src/misc/round2n.c create mode 100644 test/monniaux/glpk-4.65/src/misc/str2int.c create mode 100644 test/monniaux/glpk-4.65/src/misc/str2num.c create mode 100644 test/monniaux/glpk-4.65/src/misc/strspx.c create mode 100644 test/monniaux/glpk-4.65/src/misc/strtrim.c create mode 100644 test/monniaux/glpk-4.65/src/misc/triang.c create mode 100644 test/monniaux/glpk-4.65/src/misc/triang.h create mode 100644 test/monniaux/glpk-4.65/src/misc/wclique.c create mode 100644 test/monniaux/glpk-4.65/src/misc/wclique.h create mode 100644 test/monniaux/glpk-4.65/src/misc/wclique1.c create mode 100644 test/monniaux/glpk-4.65/src/misc/wclique1.h (limited to 'test/monniaux/glpk-4.65/src/misc') diff --git a/test/monniaux/glpk-4.65/src/misc/avl.c b/test/monniaux/glpk-4.65/src/misc/avl.c new file mode 100644 index 00000000..c97cf13a --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/avl.c @@ -0,0 +1,405 @@ +/* avl.c (binary search tree) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2000-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#include "avl.h" +#include "dmp.h" +#include "env.h" + +struct AVL +{ /* AVL tree (Adelson-Velsky & Landis binary search tree) */ + DMP *pool; + /* memory pool for allocating nodes */ + AVLNODE *root; + /* pointer to the root node */ + int (*fcmp)(void *info, const void *key1, const void *key2); + /* application-defined key comparison routine */ + void *info; + /* transit pointer passed to the routine fcmp */ + int size; + /* the tree size (the total number of nodes) */ + int height; + /* the tree height */ +}; + +struct AVLNODE +{ /* node of AVL tree */ + const void *key; + /* pointer to the node key (data structure for representing keys + is supplied by the application) */ + int rank; + /* node rank = relative position of the node in its own subtree = + the number of nodes in the left subtree plus one */ + int type; + /* reserved for the application specific information */ + void *link; + /* reserved for the application specific information */ + AVLNODE *up; + /* pointer to the parent node */ + short int flag; + /* node flag: + 0 - this node is the left child of its parent (or this node is + the root of the tree and has no parent) + 1 - this node is the right child of its parent */ + short int bal; + /* node balance = the difference between heights of the right and + left subtrees: + -1 - the left subtree is higher than the right one; + 0 - the left and right subtrees have the same height; + +1 - the left subtree is lower than the right one */ + AVLNODE *left; + /* pointer to the root of the left subtree */ + AVLNODE *right; + /* pointer to the root of the right subtree */ +}; + +AVL *avl_create_tree(int (*fcmp)(void *info, const void *key1, + const void *key2), void *info) +{ /* create AVL tree */ + AVL *tree; + tree = xmalloc(sizeof(AVL)); + tree->pool = dmp_create_pool(); + tree->root = NULL; + tree->fcmp = fcmp; + tree->info = info; + tree->size = 0; + tree->height = 0; + return tree; +} + +int avl_strcmp(void *info, const void *key1, const void *key2) +{ /* compare character string keys */ + xassert(info == info); + return strcmp(key1, key2); +} + +static AVLNODE *rotate_subtree(AVL *tree, AVLNODE *node); + +AVLNODE *avl_insert_node(AVL *tree, const void *key) +{ /* insert new node into AVL tree */ + AVLNODE *p, *q, *r; + short int flag; + /* find an appropriate point for insertion */ + p = NULL; q = tree->root; + while (q != NULL) + { p = q; + if (tree->fcmp(tree->info, key, p->key) <= 0) + { flag = 0; + q = p->left; + p->rank++; + } + else + { flag = 1; + q = p->right; + } + } + /* create new node and insert it into the tree */ + r = dmp_get_atom(tree->pool, sizeof(AVLNODE)); + r->key = key; r->type = 0; r->link = NULL; + r->rank = 1; r->up = p; + r->flag = (short int)(p == NULL ? 0 : flag); + r->bal = 0; r->left = NULL; r->right = NULL; + tree->size++; + if (p == NULL) + tree->root = r; + else + if (flag == 0) p->left = r; else p->right = r; + /* go upstairs to the root and correct all subtrees affected by + insertion */ + while (p != NULL) + { if (flag == 0) + { /* the height of the left subtree of [p] is increased */ + if (p->bal > 0) + { p->bal = 0; + break; + } + if (p->bal < 0) + { rotate_subtree(tree, p); + break; + } + p->bal = -1; flag = p->flag; p = p->up; + } + else + { /* the height of the right subtree of [p] is increased */ + if (p->bal < 0) + { p->bal = 0; + break; + } + if (p->bal > 0) + { rotate_subtree(tree, p); + break; + } + p->bal = +1; flag = p->flag; p = p->up; + } + } + /* if the root has been reached, the height of the entire tree is + increased */ + if (p == NULL) tree->height++; + return r; +} + +void avl_set_node_type(AVLNODE *node, int type) +{ /* assign the type field of specified node */ + node->type = type; + return; +} + +void avl_set_node_link(AVLNODE *node, void *link) +{ /* assign the link field of specified node */ + node->link = link; + return; +} + +AVLNODE *avl_find_node(AVL *tree, const void *key) +{ /* find node in AVL tree */ + AVLNODE *p; + int c; + p = tree->root; + while (p != NULL) + { c = tree->fcmp(tree->info, key, p->key); + if (c == 0) break; + p = (c < 0 ? p->left : p->right); + } + return p; +} + +int avl_get_node_type(AVLNODE *node) +{ /* retrieve the type field of specified node */ + return node->type; +} + +void *avl_get_node_link(AVLNODE *node) +{ /* retrieve the link field of specified node */ + return node->link; +} + +static AVLNODE *find_next_node(AVL *tree, AVLNODE *node) +{ /* find next node in AVL tree */ + AVLNODE *p, *q; + if (tree->root == NULL) return NULL; + p = node; + q = (p == NULL ? tree->root : p->right); + if (q == NULL) + { /* go upstairs from the left subtree */ + for (;;) + { q = p->up; + if (q == NULL) break; + if (p->flag == 0) break; + p = q; + } + } + else + { /* go downstairs into the right subtree */ + for (;;) + { p = q->left; + if (p == NULL) break; + q = p; + } + } + return q; +} + +void avl_delete_node(AVL *tree, AVLNODE *node) +{ /* delete specified node from AVL tree */ + AVLNODE *f, *p, *q, *r, *s, *x, *y; + short int flag; + p = node; + /* if both subtrees of the specified node are non-empty, the node + should be interchanged with the next one, at least one subtree + of which is always empty */ + if (p->left == NULL || p->right == NULL) goto skip; + f = p->up; q = p->left; + r = find_next_node(tree, p); s = r->right; + if (p->right == r) + { if (f == NULL) + tree->root = r; + else + if (p->flag == 0) f->left = r; else f->right = r; + r->rank = p->rank; r->up = f; + r->flag = p->flag; r->bal = p->bal; + r->left = q; r->right = p; + q->up = r; + p->rank = 1; p->up = r; p->flag = 1; + p->bal = (short int)(s == NULL ? 0 : +1); + p->left = NULL; p->right = s; + if (s != NULL) s->up = p; + } + else + { x = p->right; y = r->up; + if (f == NULL) + tree->root = r; + else + if (p->flag == 0) f->left = r; else f->right = r; + r->rank = p->rank; r->up = f; + r->flag = p->flag; r->bal = p->bal; + r->left = q; r->right = x; + q->up = r; x->up = r; y->left = p; + p->rank = 1; p->up = y; p->flag = 0; + p->bal = (short int)(s == NULL ? 0 : +1); + p->left = NULL; p->right = s; + if (s != NULL) s->up = p; + } +skip: /* now the specified node [p] has at least one empty subtree; + go upstairs to the root and adjust the rank field of all nodes + affected by deletion */ + q = p; f = q->up; + while (f != NULL) + { if (q->flag == 0) f->rank--; + q = f; f = q->up; + } + /* delete the specified node from the tree */ + f = p->up; flag = p->flag; + q = p->left != NULL ? p->left : p->right; + if (f == NULL) + tree->root = q; + else + if (flag == 0) f->left = q; else f->right = q; + if (q != NULL) q->up = f, q->flag = flag; + tree->size--; + /* go upstairs to the root and correct all subtrees affected by + deletion */ + while (f != NULL) + { if (flag == 0) + { /* the height of the left subtree of [f] is decreased */ + if (f->bal == 0) + { f->bal = +1; + break; + } + if (f->bal < 0) + f->bal = 0; + else + { f = rotate_subtree(tree, f); + if (f->bal < 0) break; + } + flag = f->flag; f = f->up; + } + else + { /* the height of the right subtree of [f] is decreased */ + if (f->bal == 0) + { f->bal = -1; + break; + } + if (f->bal > 0) + f->bal = 0; + else + { f = rotate_subtree(tree, f); + if (f->bal > 0) break; + } + flag = f->flag; f = f->up; + } + } + /* if the root has been reached, the height of the entire tree is + decreased */ + if (f == NULL) tree->height--; + /* returns the deleted node to the memory pool */ + dmp_free_atom(tree->pool, p, sizeof(AVLNODE)); + return; +} + +static AVLNODE *rotate_subtree(AVL *tree, AVLNODE *node) +{ /* restore balance of AVL subtree */ + AVLNODE *f, *p, *q, *r, *x, *y; + xassert(node != NULL); + p = node; + if (p->bal < 0) + { /* perform negative (left) rotation */ + f = p->up; q = p->left; r = q->right; + if (q->bal <= 0) + { /* perform single negative rotation */ + if (f == NULL) + tree->root = q; + else + if (p->flag == 0) f->left = q; else f->right = q; + p->rank -= q->rank; + q->up = f; q->flag = p->flag; q->bal++; q->right = p; + p->up = q; p->flag = 1; + p->bal = (short int)(-q->bal); p->left = r; + if (r != NULL) r->up = p, r->flag = 0; + node = q; + } + else + { /* perform double negative rotation */ + x = r->left; y = r->right; + if (f == NULL) + tree->root = r; + else + if (p->flag == 0) f->left = r; else f->right = r; + p->rank -= (q->rank + r->rank); + r->rank += q->rank; + p->bal = (short int)(r->bal >= 0 ? 0 : +1); + q->bal = (short int)(r->bal <= 0 ? 0 : -1); + r->up = f; r->flag = p->flag; r->bal = 0; + r->left = q; r->right = p; + p->up = r; p->flag = 1; p->left = y; + q->up = r; q->flag = 0; q->right = x; + if (x != NULL) x->up = q, x->flag = 1; + if (y != NULL) y->up = p, y->flag = 0; + node = r; + } + } + else + { /* perform positive (right) rotation */ + f = p->up; q = p->right; r = q->left; + if (q->bal >= 0) + { /* perform single positive rotation */ + if (f == NULL) + tree->root = q; + else + if (p->flag == 0) f->left = q; else f->right = q; + q->rank += p->rank; + q->up = f; q->flag = p->flag; q->bal--; q->left = p; + p->up = q; p->flag = 0; + p->bal = (short int)(-q->bal); p->right = r; + if (r != NULL) r->up = p, r->flag = 1; + node = q; + } + else + { /* perform double positive rotation */ + x = r->left; y = r->right; + if (f == NULL) + tree->root = r; + else + if (p->flag == 0) f->left = r; else f->right = r; + q->rank -= r->rank; + r->rank += p->rank; + p->bal = (short int)(r->bal <= 0 ? 0 : -1); + q->bal = (short int)(r->bal >= 0 ? 0 : +1); + r->up = f; r->flag = p->flag; r->bal = 0; + r->left = p; r->right = q; + p->up = r; p->flag = 0; p->right = x; + q->up = r; q->flag = 1; q->left = y; + if (x != NULL) x->up = p, x->flag = 1; + if (y != NULL) y->up = q, y->flag = 0; + node = r; + } + } + return node; +} + +void avl_delete_tree(AVL *tree) +{ /* delete AVL tree */ + dmp_delete_pool(tree->pool); + xfree(tree); + return; +} + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/avl.h b/test/monniaux/glpk-4.65/src/misc/avl.h new file mode 100644 index 00000000..b0aaef61 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/avl.h @@ -0,0 +1,73 @@ +/* avl.h (binary search tree) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2000-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#ifndef AVL_H +#define AVL_H + +typedef struct AVL AVL; +typedef struct AVLNODE AVLNODE; + +#define avl_create_tree _glp_avl_create_tree +AVL *avl_create_tree(int (*fcmp)(void *info, const void *key1, + const void *key2), void *info); +/* create AVL tree */ + +#define avl_strcmp _glp_avl_strcmp +int avl_strcmp(void *info, const void *key1, const void *key2); +/* compare character string keys */ + +#define avl_insert_node _glp_avl_insert_node +AVLNODE *avl_insert_node(AVL *tree, const void *key); +/* insert new node into AVL tree */ + +#define avl_set_node_type _glp_avl_set_node_type +void avl_set_node_type(AVLNODE *node, int type); +/* assign the type field of specified node */ + +#define avl_set_node_link _glp_avl_set_node_link +void avl_set_node_link(AVLNODE *node, void *link); +/* assign the link field of specified node */ + +#define avl_find_node _glp_avl_find_node +AVLNODE *avl_find_node(AVL *tree, const void *key); +/* find node in AVL tree */ + +#define avl_get_node_type _glp_avl_get_node_type +int avl_get_node_type(AVLNODE *node); +/* retrieve the type field of specified node */ + +#define avl_get_node_link _glp_avl_get_node_link +void *avl_get_node_link(AVLNODE *node); +/* retrieve the link field of specified node */ + +#define avl_delete_node _glp_avl_delete_node +void avl_delete_node(AVL *tree, AVLNODE *node); +/* delete specified node from AVL tree */ + +#define avl_delete_tree _glp_avl_delete_tree +void avl_delete_tree(AVL *tree); +/* delete AVL tree */ + +#endif + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/bignum.c b/test/monniaux/glpk-4.65/src/misc/bignum.c new file mode 100644 index 00000000..540dd9fd --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/bignum.c @@ -0,0 +1,286 @@ +/* bignum.c (bignum arithmetic) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2006-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#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 +#include +#include +#include "rng.h" + +#define N_MAX 7 +/* maximal number of digits in multiplicand */ + +#define M_MAX 5 +/* maximal number of digits in multiplier */ + +#define N_TEST 1000000 +/* number of tests */ + +int main(void) +{ RNG *rand; + int d, j, n, m, test; + unsigned short x[N_MAX], y[M_MAX], z[N_MAX+M_MAX]; + rand = rng_create_rand(); + for (test = 1; test <= N_TEST; test++) + { /* x[0,...,n-1] := multiplicand */ + n = 1 + rng_unif_rand(rand, N_MAX-1); + assert(1 <= n && n <= N_MAX); + for (j = 0; j < n; j++) + { d = rng_unif_rand(rand, 65536); + assert(0 <= d && d <= 65535); + x[j] = (unsigned short)d; + } + /* y[0,...,m-1] := multiplier */ + m = 1 + rng_unif_rand(rand, M_MAX-1); + assert(1 <= m && m <= M_MAX); + for (j = 0; j < m; j++) + { d = rng_unif_rand(rand, 65536); + assert(0 <= d && d <= 65535); + y[j] = (unsigned short)d; + } + if (y[m-1] == 0) y[m-1] = 1; + /* z[0,...,n+m-1] := x * y */ + for (j = 0; j < n; j++) z[m+j] = x[j]; + bigmul(n, m, z, y); + /* z[0,...,m-1] := z mod y, z[m,...,n+m-1] := z div y */ + bigdiv(n, m, z, y); + /* z mod y must be 0 */ + for (j = 0; j < m; j++) assert(z[j] == 0); + /* z div y must be x */ + for (j = 0; j < n; j++) assert(z[m+j] == x[j]); + } + fprintf(stderr, "%d tests successfully passed\n", N_TEST); + rng_delete_rand(rand); + return 0; +} +#endif + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/bignum.h b/test/monniaux/glpk-4.65/src/misc/bignum.h new file mode 100644 index 00000000..8567519b --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/bignum.h @@ -0,0 +1,37 @@ +/* bignum.h (bignum arithmetic) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2006-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#ifndef BIGNUM_H +#define BIGNUM_H + +#define bigmul _glp_bigmul +void bigmul(int n, int m, unsigned short x[], unsigned short y[]); +/* multiply unsigned integer numbers of arbitrary precision */ + +#define bigdiv _glp_bigdiv +void bigdiv(int n, int m, unsigned short x[], unsigned short y[]); +/* divide unsigned integer numbers of arbitrary precision */ + +#endif + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/dimacs.c b/test/monniaux/glpk-4.65/src/misc/dimacs.c new file mode 100644 index 00000000..6aa630a5 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/dimacs.c @@ -0,0 +1,147 @@ +/* dimacs.c (reading data in DIMACS format) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2009-2015 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#include "dimacs.h" + +void dmx_error(DMX *csa, const char *fmt, ...) +{ /* print error message and terminate processing */ + va_list arg; + xprintf("%s:%d: error: ", csa->fname, csa->count); + va_start(arg, fmt); + xvprintf(fmt, arg); + va_end(arg); + xprintf("\n"); + longjmp(csa->jump, 1); + /* no return */ +} + +void dmx_warning(DMX *csa, const char *fmt, ...) +{ /* print warning message and continue processing */ + va_list arg; + xprintf("%s:%d: warning: ", csa->fname, csa->count); + va_start(arg, fmt); + xvprintf(fmt, arg); + va_end(arg); + xprintf("\n"); + return; +} + +void dmx_read_char(DMX *csa) +{ /* read character from input text file */ + int c; + if (csa->c == '\n') csa->count++; + c = glp_getc(csa->fp); + if (c < 0) + { if (glp_ioerr(csa->fp)) + dmx_error(csa, "read error - %s", get_err_msg()); + else if (csa->c == '\n') + dmx_error(csa, "unexpected end of file"); + else + { dmx_warning(csa, "missing final end of line"); + c = '\n'; + } + } + else if (c == '\n') + ; + else if (isspace(c)) + c = ' '; + else if (iscntrl(c)) + dmx_error(csa, "invalid control character 0x%02X", c); + csa->c = c; + return; +} + +void dmx_read_designator(DMX *csa) +{ /* read one-character line designator */ + xassert(csa->c == '\n'); + dmx_read_char(csa); + for (;;) + { /* skip preceding white-space characters */ + while (csa->c == ' ') + dmx_read_char(csa); + if (csa->c == '\n') + { /* ignore empty line */ + if (!csa->empty) + { dmx_warning(csa, "empty line ignored"); + csa->empty = 1; + } + dmx_read_char(csa); + } + else if (csa->c == 'c') + { /* skip comment line */ + while (csa->c != '\n') + dmx_read_char(csa); + dmx_read_char(csa); + } + else + { /* hmm... looks like a line designator */ + csa->field[0] = (char)csa->c, csa->field[1] = '\0'; + /* check that it is followed by a white-space character */ + dmx_read_char(csa); + if (!(csa->c == ' ' || csa->c == '\n')) + dmx_error(csa, "line designator missing or invalid"); + break; + } + } + return; +} + +void dmx_read_field(DMX *csa) +{ /* read data field */ + int len = 0; + /* skip preceding white-space characters */ + while (csa->c == ' ') + dmx_read_char(csa); + /* scan data field */ + if (csa->c == '\n') + dmx_error(csa, "unexpected end of line"); + while (!(csa->c == ' ' || csa->c == '\n')) + { if (len == sizeof(csa->field)-1) + dmx_error(csa, "data field '%.15s...' too long", + csa->field); + csa->field[len++] = (char)csa->c; + dmx_read_char(csa); + } + csa->field[len] = '\0'; + return; +} + +void dmx_end_of_line(DMX *csa) +{ /* skip white-space characters until end of line */ + while (csa->c == ' ') + dmx_read_char(csa); + if (csa->c != '\n') + dmx_error(csa, "too many data fields specified"); + return; +} + +void dmx_check_int(DMX *csa, double num) +{ /* print a warning if non-integer data are detected */ + if (!csa->nonint && num != floor(num)) + { dmx_warning(csa, "non-integer data detected"); + csa->nonint = 1; + } + return; +} + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/dimacs.h b/test/monniaux/glpk-4.65/src/misc/dimacs.h new file mode 100644 index 00000000..42fb9996 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/dimacs.h @@ -0,0 +1,81 @@ +/* dimacs.h (reading data in DIMACS format) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2009-2015 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#ifndef DIMACS_H +#define DIMACS_H + +#include "env.h" + +typedef struct DMX DMX; + +struct DMX +{ /* DIMACS data reader */ + jmp_buf jump; + /* label for go to in case of error */ + const char *fname; + /* name of input text file */ + glp_file *fp; + /* stream assigned to input text file */ + int count; + /* line count */ + int c; + /* current character */ + char field[255+1]; + /* data field */ + int empty; + /* warning 'empty line ignored' was printed */ + int nonint; + /* warning 'non-integer data detected' was printed */ +}; + +#define dmx_error _glp_dmx_error +void dmx_error(DMX *csa, const char *fmt, ...); +/* print error message and terminate processing */ + +#define dmx_warning _glp_dmx_warning +void dmx_warning(DMX *csa, const char *fmt, ...); +/* print warning message and continue processing */ + +#define dmx_read_char _glp_dmx_read_char +void dmx_read_char(DMX *csa); +/* read character from input text file */ + +#define dmx_read_designator _glp_dmx_read_designator +void dmx_read_designator(DMX *csa); +/* read one-character line designator */ + +#define dmx_read_field _glp_dmx_read_field +void dmx_read_field(DMX *csa); +/* read data field */ + +#define dmx_end_of_line _glp_dmx_end_of_line +void dmx_end_of_line(DMX *csa); +/* skip white-space characters until end of line */ + +#define dmx_check_int _glp_dmx_check_int +void dmx_check_int(DMX *csa, double num); +/* print a warning if non-integer data are detected */ + +#endif + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/dmp.c b/test/monniaux/glpk-4.65/src/misc/dmp.c new file mode 100644 index 00000000..a4882c86 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/dmp.c @@ -0,0 +1,243 @@ +/* dmp.c (dynamic memory pool) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2000-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#include "env.h" +#include "dmp.h" + +struct DMP +{ /* dynamic memory pool */ + void *avail[32]; + /* avail[k], 0 <= k <= 31, is a pointer to first available (free) + * atom of (k+1)*8 bytes long; at the beginning of each free atom + * there is a pointer to another free atom of the same size */ + void *block; + /* pointer to most recently allocated memory block; at the + * beginning of each allocated memory block there is a pointer to + * previously allocated memory block */ + int used; + /* number of bytes used in most recently allocated memory block */ + size_t count; + /* number of atoms which are currently in use */ +}; + +#define DMP_BLK_SIZE 8000 +/* size of memory blocks, in bytes, allocated for memory pools */ + +struct prefix +{ /* atom prefix (for debugging only) */ + DMP *pool; + /* dynamic memory pool */ + int size; + /* original atom size, in bytes */ +}; + +#define prefix_size ((sizeof(struct prefix) + 7) & ~7) +/* size of atom prefix rounded up to multiple of 8 bytes */ + +int dmp_debug; +/* debug mode flag */ + +/*********************************************************************** +* NAME +* +* dmp_create_pool - create dynamic memory pool +* +* SYNOPSIS +* +* #include "dmp.h" +* DMP *dmp_create_pool(void); +* +* DESCRIPTION +* +* The routine dmp_create_pool creates a dynamic memory pool. +* +* RETURNS +* +* The routine returns a pointer to the memory pool created. */ + +DMP *dmp_create_pool(void) +{ DMP *pool; + int k; + xassert(sizeof(void *) <= 8); + if (dmp_debug) + xprintf("dmp_create_pool: warning: debug mode is on\n"); + pool = talloc(1, DMP); + for (k = 0; k <= 31; k++) + pool->avail[k] = NULL; + pool->block = NULL; + pool->used = DMP_BLK_SIZE; + pool->count = 0; + return pool; +} + +/*********************************************************************** +* NAME +* +* dmp_get_atom - get free atom from dynamic memory pool +* +* SYNOPSIS +* +* #include "dmp.h" +* void *dmp_get_atom(DMP *pool, int size); +* +* DESCRIPTION +* +* The routine dmp_get_atom obtains a free atom (memory space) from the +* specified memory pool. +* +* The parameter size is the atom size, in bytes, 1 <= size <= 256. +* +* Note that the free atom contains arbitrary data, not binary zeros. +* +* RETURNS +* +* The routine returns a pointer to the free atom obtained. */ + +void *dmp_get_atom(DMP *pool, int size) +{ void *atom; + int k, need; + xassert(1 <= size && size <= 256); + /* round up atom size to multiple of 8 bytes */ + need = (size + 7) & ~7; + /* determine number of corresponding list of free atoms */ + k = (need >> 3) - 1; + /* obtain free atom */ + if (pool->avail[k] == NULL) + { /* corresponding list of free atoms is empty */ + /* if debug mode is on, add atom prefix size */ + if (dmp_debug) + need += prefix_size; + if (pool->used + need > DMP_BLK_SIZE) + { /* allocate new memory block */ + void *block = talloc(DMP_BLK_SIZE, char); + *(void **)block = pool->block; + pool->block = block; + pool->used = 8; /* sufficient to store pointer */ + } + /* allocate new atom in current memory block */ + atom = (char *)pool->block + pool->used; + pool->used += need; + } + else + { /* obtain atom from corresponding list of free atoms */ + atom = pool->avail[k]; + pool->avail[k] = *(void **)atom; + } + /* if debug mode is on, fill atom prefix */ + if (dmp_debug) + { ((struct prefix *)atom)->pool = pool; + ((struct prefix *)atom)->size = size; + atom = (char *)atom + prefix_size; + } + /* increase number of allocated atoms */ + pool->count++; + return atom; +} + +/*********************************************************************** +* NAME +* +* dmp_free_atom - return atom to dynamic memory pool +* +* SYNOPSIS +* +* #include "dmp.h" +* void dmp_free_atom(DMP *pool, void *atom, int size); +* +* DESCRIPTION +* +* The routine dmp_free_atom returns the specified atom (memory space) +* to the specified memory pool, making the atom free. +* +* The parameter size is the atom size, in bytes, 1 <= size <= 256. +* +* Note that the atom can be returned only to the pool, from which it +* was obtained, and its size must be exactly the same as on obtaining +* it from the pool. */ + +void dmp_free_atom(DMP *pool, void *atom, int size) +{ int k; + xassert(1 <= size && size <= 256); + /* determine number of corresponding list of free atoms */ + k = ((size + 7) >> 3) - 1; + /* if debug mode is on, check atom prefix */ + if (dmp_debug) + { atom = (char *)atom - prefix_size; + xassert(((struct prefix *)atom)->pool == pool); + xassert(((struct prefix *)atom)->size == size); + } + /* return atom to corresponding list of free atoms */ + *(void **)atom = pool->avail[k]; + pool->avail[k] = atom; + /* decrease number of allocated atoms */ + xassert(pool->count > 0); + pool->count--; + return; +} + +/*********************************************************************** +* NAME +* +* dmp_in_use - determine how many atoms are still in use +* +* SYNOPSIS +* +* #include "dmp.h" +* size_t dmp_in_use(DMP *pool); +* +* RETURNS +* +* The routine returns the number of atoms of the specified memory pool +* which are still in use. */ + +size_t dmp_in_use(DMP *pool) +{ return + pool->count; +} + +/*********************************************************************** +* NAME +* +* dmp_delete_pool - delete dynamic memory pool +* +* SYNOPSIS +* +* #include "dmp.h" +* void dmp_delete_pool(DMP *pool); +* +* DESCRIPTION +* +* The routine dmp_delete_pool deletes the specified dynamic memory +* pool freeing all the memory allocated to this object. */ + +void dmp_delete_pool(DMP *pool) +{ while (pool->block != NULL) + { void *block = pool->block; + pool->block = *(void **)block; + tfree(block); + } + tfree(pool); + return; +} + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/dmp.h b/test/monniaux/glpk-4.65/src/misc/dmp.h new file mode 100644 index 00000000..85fe7176 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/dmp.h @@ -0,0 +1,63 @@ +/* dmp.h (dynamic memory pool) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2000-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#ifndef DMP_H +#define DMP_H + +#include "stdc.h" + +typedef struct DMP DMP; + +#define dmp_debug _glp_dmp_debug +extern int dmp_debug; +/* debug mode flag */ + +#define dmp_create_pool _glp_dmp_create_pool +DMP *dmp_create_pool(void); +/* create dynamic memory pool */ + +#define dmp_talloc(pool, type) \ + ((type *)dmp_get_atom(pool, sizeof(type))) + +#define dmp_get_atom _glp_dmp_get_atom +void *dmp_get_atom(DMP *pool, int size); +/* get free atom from dynamic memory pool */ + +#define dmp_tfree(pool, atom) \ + dmp_free_atom(pool, atom, sizeof(*(atom))) + +#define dmp_free_atom _glp_dmp_free_atom +void dmp_free_atom(DMP *pool, void *atom, int size); +/* return atom to dynamic memory pool */ + +#define dmp_in_use _glp_dmp_in_use +size_t dmp_in_use(DMP *pool); +/* determine how many atoms are still in use */ + +#define dmp_delete_pool _glp_dmp_delete_pool +void dmp_delete_pool(DMP *pool); +/* delete dynamic memory pool */ + +#endif + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/ffalg.c b/test/monniaux/glpk-4.65/src/misc/ffalg.c new file mode 100644 index 00000000..4ea2913d --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/ffalg.c @@ -0,0 +1,221 @@ +/* ffalg.c (Ford-Fulkerson algorithm) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2009-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#include "env.h" +#include "ffalg.h" + +/*********************************************************************** +* NAME +* +* ffalg - Ford-Fulkerson algorithm +* +* SYNOPSIS +* +* #include "ffalg.h" +* void ffalg(int nv, int na, const int tail[], const int head[], +* int s, int t, const int cap[], int x[], char cut[]); +* +* DESCRIPTION +* +* The routine ffalg implements the Ford-Fulkerson algorithm to find a +* maximal flow in the specified flow network. +* +* INPUT PARAMETERS +* +* nv is the number of nodes, nv >= 2. +* +* na is the number of arcs, na >= 0. +* +* tail[a], a = 1,...,na, is the index of tail node of arc a. +* +* head[a], a = 1,...,na, is the index of head node of arc a. +* +* s is the source node index, 1 <= s <= nv. +* +* t is the sink node index, 1 <= t <= nv, t != s. +* +* cap[a], a = 1,...,na, is the capacity of arc a, cap[a] >= 0. +* +* NOTE: Multiple arcs are allowed, but self-loops are not allowed. +* +* OUTPUT PARAMETERS +* +* x[a], a = 1,...,na, is optimal value of the flow through arc a. +* +* cut[i], i = 1,...,nv, is 1 if node i is labelled, and 0 otherwise. +* The set of arcs, whose one endpoint is labelled and other is not, +* defines the minimal cut corresponding to the maximal flow found. +* If the parameter cut is NULL, the cut information are not stored. +* +* REFERENCES +* +* L.R.Ford, Jr., and D.R.Fulkerson, "Flows in Networks," The RAND +* Corp., Report R-375-PR (August 1962), Chap. I "Static Maximal Flow," +* pp.30-33. */ + +void ffalg(int nv, int na, const int tail[], const int head[], + int s, int t, const int cap[], int x[], char cut[]) +{ int a, delta, i, j, k, pos1, pos2, temp, + *ptr, *arc, *link, *list; + /* sanity checks */ + xassert(nv >= 2); + xassert(na >= 0); + xassert(1 <= s && s <= nv); + xassert(1 <= t && t <= nv); + xassert(s != t); + for (a = 1; a <= na; a++) + { i = tail[a], j = head[a]; + xassert(1 <= i && i <= nv); + xassert(1 <= j && j <= nv); + xassert(i != j); + xassert(cap[a] >= 0); + } + /* allocate working arrays */ + ptr = xcalloc(1+nv+1, sizeof(int)); + arc = xcalloc(1+na+na, sizeof(int)); + link = xcalloc(1+nv, sizeof(int)); + list = xcalloc(1+nv, sizeof(int)); + /* ptr[i] := (degree of node i) */ + for (i = 1; i <= nv; i++) + ptr[i] = 0; + for (a = 1; a <= na; a++) + { ptr[tail[a]]++; + ptr[head[a]]++; + } + /* initialize arc pointers */ + ptr[1]++; + for (i = 1; i < nv; i++) + ptr[i+1] += ptr[i]; + ptr[nv+1] = ptr[nv]; + /* build arc lists */ + for (a = 1; a <= na; a++) + { arc[--ptr[tail[a]]] = a; + arc[--ptr[head[a]]] = a; + } + xassert(ptr[1] == 1); + xassert(ptr[nv+1] == na+na+1); + /* now the indices of arcs incident to node i are stored in + * locations arc[ptr[i]], arc[ptr[i]+1], ..., arc[ptr[i+1]-1] */ + /* initialize arc flows */ + for (a = 1; a <= na; a++) + x[a] = 0; +loop: /* main loop starts here */ + /* build augmenting tree rooted at s */ + /* link[i] = 0 means that node i is not labelled yet; + * link[i] = a means that arc a immediately precedes node i */ + /* initially node s is labelled as the root */ + for (i = 1; i <= nv; i++) + link[i] = 0; + link[s] = -1, list[1] = s, pos1 = pos2 = 1; + /* breadth first search */ + while (pos1 <= pos2) + { /* dequeue node i */ + i = list[pos1++]; + /* consider all arcs incident to node i */ + for (k = ptr[i]; k < ptr[i+1]; k++) + { a = arc[k]; + if (tail[a] == i) + { /* a = i->j is a forward arc from s to t */ + j = head[a]; + /* if node j has been labelled, skip the arc */ + if (link[j] != 0) continue; + /* if the arc does not allow increasing the flow through + * it, skip the arc */ + if (x[a] == cap[a]) continue; + } + else if (head[a] == i) + { /* a = i<-j is a backward arc from s to t */ + j = tail[a]; + /* if node j has been labelled, skip the arc */ + if (link[j] != 0) continue; + /* if the arc does not allow decreasing the flow through + * it, skip the arc */ + if (x[a] == 0) continue; + } + else + xassert(a != a); + /* label node j and enqueue it */ + link[j] = a, list[++pos2] = j; + /* check for breakthrough */ + if (j == t) goto brkt; + } + } + /* NONBREAKTHROUGH */ + /* no augmenting path exists; current flow is maximal */ + /* store minimal cut information, if necessary */ + if (cut != NULL) + { for (i = 1; i <= nv; i++) + cut[i] = (char)(link[i] != 0); + } + goto done; +brkt: /* BREAKTHROUGH */ + /* walk through arcs of the augmenting path (s, ..., t) found in + * the reverse order and determine maximal change of the flow */ + delta = 0; + for (j = t; j != s; j = i) + { /* arc a immediately precedes node j in the path */ + a = link[j]; + if (head[a] == j) + { /* a = i->j is a forward arc of the cycle */ + i = tail[a]; + /* x[a] may be increased until its upper bound */ + temp = cap[a] - x[a]; + } + else if (tail[a] == j) + { /* a = i<-j is a backward arc of the cycle */ + i = head[a]; + /* x[a] may be decreased until its lower bound */ + temp = x[a]; + } + else + xassert(a != a); + if (delta == 0 || delta > temp) delta = temp; + } + xassert(delta > 0); + /* increase the flow along the path */ + for (j = t; j != s; j = i) + { /* arc a immediately precedes node j in the path */ + a = link[j]; + if (head[a] == j) + { /* a = i->j is a forward arc of the cycle */ + i = tail[a]; + x[a] += delta; + } + else if (tail[a] == j) + { /* a = i<-j is a backward arc of the cycle */ + i = head[a]; + x[a] -= delta; + } + else + xassert(a != a); + } + goto loop; +done: /* free working arrays */ + xfree(ptr); + xfree(arc); + xfree(link); + xfree(list); + return; +} + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/ffalg.h b/test/monniaux/glpk-4.65/src/misc/ffalg.h new file mode 100644 index 00000000..7016f8fa --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/ffalg.h @@ -0,0 +1,34 @@ +/* ffalg.h (Ford-Fulkerson algorithm) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2009-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#ifndef FFALG_H +#define FFALG_H + +#define ffalg _glp_ffalg +void ffalg(int nv, int na, const int tail[], const int head[], + int s, int t, const int cap[], int x[], char cut[]); +/* Ford-Fulkerson algorithm */ + +#endif + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/fp2rat.c b/test/monniaux/glpk-4.65/src/misc/fp2rat.c new file mode 100644 index 00000000..4699bbd1 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/fp2rat.c @@ -0,0 +1,164 @@ +/* fp2rat.c (convert floating-point number to rational number) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2000-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#include "env.h" +#include "misc.h" + +/*********************************************************************** +* NAME +* +* fp2rat - convert floating-point number to rational number +* +* SYNOPSIS +* +* #include "misc.h" +* int fp2rat(double x, double eps, double *p, double *q); +* +* DESCRIPTION +* +* Given a floating-point number 0 <= x < 1 the routine fp2rat finds +* its "best" rational approximation p / q, where p >= 0 and q > 0 are +* integer numbers, such that |x - p / q| <= eps. +* +* RETURNS +* +* The routine fp2rat returns the number of iterations used to achieve +* the specified precision eps. +* +* EXAMPLES +* +* For x = sqrt(2) - 1 = 0.414213562373095 and eps = 1e-6 the routine +* gives p = 408 and q = 985, where 408 / 985 = 0.414213197969543. +* +* BACKGROUND +* +* It is well known that every positive real number x can be expressed +* as the following continued fraction: +* +* x = b[0] + a[1] +* ------------------------ +* b[1] + a[2] +* ----------------- +* b[2] + a[3] +* ---------- +* b[3] + ... +* +* where: +* +* a[k] = 1, k = 0, 1, 2, ... +* +* b[k] = floor(x[k]), k = 0, 1, 2, ... +* +* x[0] = x, +* +* x[k] = 1 / frac(x[k-1]), k = 1, 2, 3, ... +* +* To find the "best" rational approximation of x the routine computes +* partial fractions f[k] by dropping after k terms as follows: +* +* f[k] = A[k] / B[k], +* +* where: +* +* A[-1] = 1, A[0] = b[0], B[-1] = 0, B[0] = 1, +* +* A[k] = b[k] * A[k-1] + a[k] * A[k-2], +* +* B[k] = b[k] * B[k-1] + a[k] * B[k-2]. +* +* Once the condition +* +* |x - f[k]| <= eps +* +* has been satisfied, the routine reports p = A[k] and q = B[k] as the +* final answer. +* +* In the table below here is some statistics obtained for one million +* random numbers uniformly distributed in the range [0, 1). +* +* eps max p mean p max q mean q max k mean k +* ------------------------------------------------------------- +* 1e-1 8 1.6 9 3.2 3 1.4 +* 1e-2 98 6.2 99 12.4 5 2.4 +* 1e-3 997 20.7 998 41.5 8 3.4 +* 1e-4 9959 66.6 9960 133.5 10 4.4 +* 1e-5 97403 211.7 97404 424.2 13 5.3 +* 1e-6 479669 669.9 479670 1342.9 15 6.3 +* 1e-7 1579030 2127.3 3962146 4257.8 16 7.3 +* 1e-8 26188823 6749.4 26188824 13503.4 19 8.2 +* +* REFERENCES +* +* W. B. Jones and W. J. Thron, "Continued Fractions: Analytic Theory +* and Applications," Encyclopedia on Mathematics and Its Applications, +* Addison-Wesley, 1980. */ + +int fp2rat(double x, double eps, double *p, double *q) +{ int k; + double xk, Akm1, Ak, Bkm1, Bk, ak, bk, fk, temp; + xassert(0.0 <= x && x < 1.0); + for (k = 0; ; k++) + { xassert(k <= 100); + if (k == 0) + { /* x[0] = x */ + xk = x; + /* A[-1] = 1 */ + Akm1 = 1.0; + /* A[0] = b[0] = floor(x[0]) = 0 */ + Ak = 0.0; + /* B[-1] = 0 */ + Bkm1 = 0.0; + /* B[0] = 1 */ + Bk = 1.0; + } + else + { /* x[k] = 1 / frac(x[k-1]) */ + temp = xk - floor(xk); + xassert(temp != 0.0); + xk = 1.0 / temp; + /* a[k] = 1 */ + ak = 1.0; + /* b[k] = floor(x[k]) */ + bk = floor(xk); + /* A[k] = b[k] * A[k-1] + a[k] * A[k-2] */ + temp = bk * Ak + ak * Akm1; + Akm1 = Ak, Ak = temp; + /* B[k] = b[k] * B[k-1] + a[k] * B[k-2] */ + temp = bk * Bk + ak * Bkm1; + Bkm1 = Bk, Bk = temp; + } + /* f[k] = A[k] / B[k] */ + fk = Ak / Bk; +#if 0 + print("%.*g / %.*g = %.*g", + DBL_DIG, Ak, DBL_DIG, Bk, DBL_DIG, fk); +#endif + if (fabs(x - fk) <= eps) + break; + } + *p = Ak; + *q = Bk; + return k; +} + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/fvs.c b/test/monniaux/glpk-4.65/src/misc/fvs.c new file mode 100644 index 00000000..916a1bf9 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/fvs.c @@ -0,0 +1,137 @@ +/* fvs.c (sparse vector in FVS format) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2016 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#include "env.h" +#include "fvs.h" + +void fvs_alloc_vec(FVS *x, int n) +{ /* allocate sparse vector */ + int j; + xassert(n >= 0); + x->n = n; + x->nnz = 0; + x->ind = talloc(1+n, int); + x->vec = talloc(1+n, double); + for (j = 1; j <= n; j++) + x->vec[j] = 0.0; + return; +} + +void fvs_check_vec(const FVS *x) +{ /* check sparse vector */ + /* NOTE: for testing/debugging only */ + int n = x->n; + int nnz = x->nnz; + int *ind = x->ind; + double *vec = x->vec; + char *map; + int j, k; + xassert(n >= 0); + xassert(0 <= nnz && nnz <= n); + map = talloc(1+n, char); + for (j = 1; j <= n; j++) + map[j] = (vec[j] != 0.0); + for (k = 1; k <= nnz; k++) + { j = ind[k]; + xassert(1 <= j && j <= n); + xassert(map[j]); + map[j] = 0; + } + for (j = 1; j <= n; j++) + xassert(!map[j]); + tfree(map); + return; +} + +void fvs_gather_vec(FVS *x, double eps) +{ /* gather sparse vector */ + int n = x->n; + int *ind = x->ind; + double *vec = x->vec; + int j, nnz = 0; + for (j = n; j >= 1; j--) + { if (-eps < vec[j] && vec[j] < +eps) + vec[j] = 0.0; + else + ind[++nnz] = j; + } + x->nnz = nnz; + return; +} + +void fvs_clear_vec(FVS *x) +{ /* clear sparse vector */ + int *ind = x->ind; + double *vec = x->vec; + int k; + for (k = x->nnz; k >= 1; k--) + vec[ind[k]] = 0.0; + x->nnz = 0; + return; +} + +void fvs_copy_vec(FVS *x, const FVS *y) +{ /* copy sparse vector */ + int *x_ind = x->ind; + double *x_vec = x->vec; + int *y_ind = y->ind; + double *y_vec = y->vec; + int j, k; + xassert(x != y); + xassert(x->n == y->n); + fvs_clear_vec(x); + for (k = x->nnz = y->nnz; k >= 1; k--) + { j = x_ind[k] = y_ind[k]; + x_vec[j] = y_vec[j]; + } + return; +} + +void fvs_adjust_vec(FVS *x, double eps) +{ /* replace tiny vector elements by exact zeros */ + int nnz = x->nnz; + int *ind = x->ind; + double *vec = x->vec; + int j, k, cnt = 0; + for (k = 1; k <= nnz; k++) + { j = ind[k]; + if (-eps < vec[j] && vec[j] < +eps) + vec[j] = 0.0; + else + ind[++cnt] = j; + } + x->nnz = cnt; + return; +} + +void fvs_free_vec(FVS *x) +{ /* deallocate sparse vector */ + tfree(x->ind); + tfree(x->vec); + x->n = x->nnz = -1; + x->ind = NULL; + x->vec = NULL; + return; +} + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/fvs.h b/test/monniaux/glpk-4.65/src/misc/fvs.h new file mode 100644 index 00000000..abfed8cc --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/fvs.h @@ -0,0 +1,76 @@ +/* fvs.h (sparse vector in FVS format) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2016 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#ifndef FVS_H +#define FVS_H + +typedef struct FVS FVS; + +struct FVS +{ /* sparse vector in FVS (Full Vector Storage) format */ + int n; + /* vector dimension (total number of elements) */ + int nnz; + /* number of non-zero elements, 0 <= nnz <= n */ + int *ind; /* int ind[1+n]; */ + /* ind[0] is not used; + * ind[k] = j, 1 <= k <= nnz, means that vec[j] != 0 + * non-zero indices in the array ind are stored in arbitrary + * order; if vec[j] = 0, its index j SHOULD NOT be presented in + * the array ind */ + double *vec; /* double vec[1+n]; */ + /* vec[0] is not used; + * vec[j], 1 <= j <= n, is a numeric value of j-th element */ +}; + +#define fvs_alloc_vec _glp_fvs_alloc_vec +void fvs_alloc_vec(FVS *x, int n); +/* allocate sparse vector */ + +#define fvs_check_vec _glp_fvs_check_vec +void fvs_check_vec(const FVS *x); +/* check sparse vector */ + +#define fvs_gather_vec _glp_fvs_gather_vec +void fvs_gather_vec(FVS *x, double eps); +/* gather sparse vector */ + +#define fvs_clear_vec _glp_fvs_clear_vec +void fvs_clear_vec(FVS *x); +/* clear sparse vector */ + +#define fvs_copy_vec _glp_fvs_copy_vec +void fvs_copy_vec(FVS *x, const FVS *y); +/* copy sparse vector */ + +#define fvs_adjust_vec _glp_fvs_adjust_vec +void fvs_adjust_vec(FVS *x, double eps); +/* replace tiny vector elements by exact zeros */ + +#define fvs_free_vec _glp_fvs_free_vec +void fvs_free_vec(FVS *x); +/* deallocate sparse vector */ + +#endif + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/gcd.c b/test/monniaux/glpk-4.65/src/misc/gcd.c new file mode 100644 index 00000000..95c48cc0 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/gcd.c @@ -0,0 +1,102 @@ +/* gcd.c (greatest common divisor) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2000-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#include "env.h" +#include "misc.h" + +/*********************************************************************** +* NAME +* +* gcd - find greatest common divisor of two integers +* +* SYNOPSIS +* +* #include "misc.h" +* int gcd(int x, int y); +* +* RETURNS +* +* The routine gcd returns gcd(x, y), the greatest common divisor of +* the two positive integers given. +* +* ALGORITHM +* +* The routine gcd is based on Euclid's algorithm. +* +* REFERENCES +* +* Don Knuth, The Art of Computer Programming, Vol.2: Seminumerical +* Algorithms, 3rd Edition, Addison-Wesley, 1997. Section 4.5.2: The +* Greatest Common Divisor, pp. 333-56. */ + +int gcd(int x, int y) +{ int r; + xassert(x > 0 && y > 0); + while (y > 0) + r = x % y, x = y, y = r; + return x; +} + +/*********************************************************************** +* NAME +* +* gcdn - find greatest common divisor of n integers +* +* SYNOPSIS +* +* #include "misc.h" +* int gcdn(int n, int x[]); +* +* RETURNS +* +* The routine gcdn returns gcd(x[1], x[2], ..., x[n]), the greatest +* common divisor of n positive integers given, n > 0. +* +* BACKGROUND +* +* The routine gcdn is based on the following identity: +* +* gcd(x, y, z) = gcd(gcd(x, y), z). +* +* REFERENCES +* +* Don Knuth, The Art of Computer Programming, Vol.2: Seminumerical +* Algorithms, 3rd Edition, Addison-Wesley, 1997. Section 4.5.2: The +* Greatest Common Divisor, pp. 333-56. */ + +int gcdn(int n, int x[]) +{ int d, j; + xassert(n > 0); + for (j = 1; j <= n; j++) + { xassert(x[j] > 0); + if (j == 1) + d = x[1]; + else + d = gcd(d, x[j]); + if (d == 1) + break; + } + return d; +} + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/jd.c b/test/monniaux/glpk-4.65/src/misc/jd.c new file mode 100644 index 00000000..c9d63171 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/jd.c @@ -0,0 +1,152 @@ +/* jd.c (conversions between calendar date and Julian day number) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2000-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#include +#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 +#include +#include + +int main(void) +{ int jbeg, jend, j, d, m, y; + jbeg = jday(1, 1, 1); + jend = jday(31, 12, 4000); + for (j = jbeg; j <= jend; j++) + { assert(jdate(j, &d, &m, &y) == 0); + assert(jday(d, m, y) == j); + } + printf("Routines jday and jdate work correctly.\n"); + return 0; +} +#endif + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/jd.h b/test/monniaux/glpk-4.65/src/misc/jd.h new file mode 100644 index 00000000..009d2daa --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/jd.h @@ -0,0 +1,32 @@ +/* jd.h (conversions between calendar date and Julian day number) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2000-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#define jday _glp_jday +int jday(int d, int m, int y); +/* convert calendar date to Julian day number */ + +#define jdate _glp_jdate +int jdate(int j, int *d, int *m, int *y); +/* convert Julian day number to calendar date */ + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/keller.c b/test/monniaux/glpk-4.65/src/misc/keller.c new file mode 100644 index 00000000..d64d3c1e --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/keller.c @@ -0,0 +1,235 @@ +/* keller.c (cover edges by cliques, Kellerman's heuristic) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2009-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#include "glpk.h" +#include "env.h" +#include "keller.h" + +/*********************************************************************** +* NAME +* +* kellerman - cover edges by cliques with Kellerman's heuristic +* +* SYNOPSIS +* +* #include "keller.h" +* int kellerman(int n, int (*func)(void *info, int i, int ind[]), +* void *info, glp_graph *H); +* +* DESCRIPTION +* +* The routine kellerman implements Kellerman's heuristic algorithm +* to find a minimal set of cliques which cover all edges of specified +* graph G = (V, E). +* +* The parameter n specifies the number of vertices |V|, n >= 0. +* +* Formal routine func specifies the set of edges E in the following +* way. Running the routine kellerman calls the routine func and passes +* to it parameter i, which is the number of some vertex, 1 <= i <= n. +* In response the routine func should store numbers of all vertices +* adjacent to vertex i to locations ind[1], ind[2], ..., ind[len] and +* return the value of len, which is the number of adjacent vertices, +* 0 <= len <= n. Self-loops are allowed, but ignored. Multiple edges +* are not allowed. +* +* The parameter info is a transit pointer (magic cookie) passed to the +* formal routine func as its first parameter. +* +* The result provided by the routine kellerman is the bipartite graph +* H = (V union C, F), which defines the covering found. (The program +* object of type glp_graph specified by the parameter H should be +* previously created with the routine glp_create_graph. On entry the +* routine kellerman erases the content of this object with the routine +* glp_erase_graph.) Vertices of first part V correspond to vertices of +* the graph G and have the same ordinal numbers 1, 2, ..., n. Vertices +* of second part C correspond to cliques and have ordinal numbers +* n+1, n+2, ..., n+k, where k is the total number of cliques in the +* edge covering found. Every edge f in F in the program object H is +* represented as arc f = (i->j), where i in V and j in C, which means +* that vertex i of the graph G is in clique C[j], 1 <= j <= k. (Thus, +* if two vertices of the graph G are in the same clique, these vertices +* are adjacent in G, and corresponding edge is covered by that clique.) +* +* RETURNS +* +* The routine Kellerman returns k, the total number of cliques in the +* edge covering found. +* +* REFERENCE +* +* For more details see: glpk/doc/notes/keller.pdf (in Russian). */ + +struct set +{ /* set of vertices */ + int size; + /* size (cardinality) of the set, 0 <= card <= n */ + int *list; /* int list[1+n]; */ + /* the set contains vertices list[1,...,size] */ + int *pos; /* int pos[1+n]; */ + /* pos[i] > 0 means that vertex i is in the set and + * list[pos[i]] = i; pos[i] = 0 means that vertex i is not in + * the set */ +}; + +int kellerman(int n, int (*func)(void *info, int i, int ind[]), + void *info, void /* glp_graph */ *H_) +{ glp_graph *H = H_; + struct set W_, *W = &W_, V_, *V = &V_; + glp_arc *a; + int i, j, k, m, t, len, card, best; + xassert(n >= 0); + /* H := (V, 0; 0), where V is the set of vertices of graph G */ + glp_erase_graph(H, H->v_size, H->a_size); + glp_add_vertices(H, n); + /* W := 0 */ + W->size = 0; + W->list = xcalloc(1+n, sizeof(int)); + W->pos = xcalloc(1+n, sizeof(int)); + memset(&W->pos[1], 0, sizeof(int) * n); + /* V := 0 */ + V->size = 0; + V->list = xcalloc(1+n, sizeof(int)); + V->pos = xcalloc(1+n, sizeof(int)); + memset(&V->pos[1], 0, sizeof(int) * n); + /* main loop */ + for (i = 1; i <= n; i++) + { /* W must be empty */ + xassert(W->size == 0); + /* W := { j : i > j and (i,j) in E } */ + len = func(info, i, W->list); + xassert(0 <= len && len <= n); + for (t = 1; t <= len; t++) + { j = W->list[t]; + xassert(1 <= j && j <= n); + if (j >= i) continue; + xassert(W->pos[j] == 0); + W->list[++W->size] = j, W->pos[j] = W->size; + } + /* on i-th iteration we need to cover edges (i,j) for all + * j in W */ + /* if W is empty, it is a special case */ + if (W->size == 0) + { /* set k := k + 1 and create new clique C[k] = { i } */ + k = glp_add_vertices(H, 1) - n; + glp_add_arc(H, i, n + k); + continue; + } + /* try to include vertex i into existing cliques */ + /* V must be empty */ + xassert(V->size == 0); + /* k is the number of cliques found so far */ + k = H->nv - n; + for (m = 1; m <= k; m++) + { /* do while V != W; since here V is within W, we can use + * equivalent condition: do while |V| < |W| */ + if (V->size == W->size) break; + /* check if C[m] is within W */ + for (a = H->v[n + m]->in; a != NULL; a = a->h_next) + { j = a->tail->i; + if (W->pos[j] == 0) break; + } + if (a != NULL) continue; + /* C[m] is within W, expand clique C[m] with vertex i */ + /* C[m] := C[m] union {i} */ + glp_add_arc(H, i, n + m); + /* V is a set of vertices whose incident edges are already + * covered by existing cliques */ + /* V := V union C[m] */ + for (a = H->v[n + m]->in; a != NULL; a = a->h_next) + { j = a->tail->i; + if (V->pos[j] == 0) + V->list[++V->size] = j, V->pos[j] = V->size; + } + } + /* remove from set W the vertices whose incident edges are + * already covered by existing cliques */ + /* W := W \ V, V := 0 */ + for (t = 1; t <= V->size; t++) + { j = V->list[t], V->pos[j] = 0; + if (W->pos[j] != 0) + { /* remove vertex j from W */ + if (W->pos[j] != W->size) + { int jj = W->list[W->size]; + W->list[W->pos[j]] = jj; + W->pos[jj] = W->pos[j]; + } + W->size--, W->pos[j] = 0; + } + } + V->size = 0; + /* now set W contains only vertices whose incident edges are + * still not covered by existing cliques; create new cliques + * to cover remaining edges until set W becomes empty */ + while (W->size > 0) + { /* find clique C[m], 1 <= m <= k, which shares maximal + * number of vertices with W; to break ties choose clique + * having smallest number m */ + m = 0, best = -1; + k = H->nv - n; + for (t = 1; t <= k; t++) + { /* compute cardinality of intersection of W and C[t] */ + card = 0; + for (a = H->v[n + t]->in; a != NULL; a = a->h_next) + { j = a->tail->i; + if (W->pos[j] != 0) card++; + } + if (best < card) + m = t, best = card; + } + xassert(m > 0); + /* set k := k + 1 and create new clique: + * C[k] := (W intersect C[m]) union { i }, which covers all + * edges incident to vertices from (W intersect C[m]) */ + k = glp_add_vertices(H, 1) - n; + for (a = H->v[n + m]->in; a != NULL; a = a->h_next) + { j = a->tail->i; + if (W->pos[j] != 0) + { /* vertex j is in both W and C[m]; include it in new + * clique C[k] */ + glp_add_arc(H, j, n + k); + /* remove vertex j from W, since edge (i,j) will be + * covered by new clique C[k] */ + if (W->pos[j] != W->size) + { int jj = W->list[W->size]; + W->list[W->pos[j]] = jj; + W->pos[jj] = W->pos[j]; + } + W->size--, W->pos[j] = 0; + } + } + /* include vertex i to new clique C[k] to cover edges (i,j) + * incident to all vertices j just removed from W */ + glp_add_arc(H, i, n + k); + } + } + /* free working arrays */ + xfree(W->list); + xfree(W->pos); + xfree(V->list); + xfree(V->pos); + /* return the number of cliques in the edge covering found */ + return H->nv - n; +} + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/keller.h b/test/monniaux/glpk-4.65/src/misc/keller.h new file mode 100644 index 00000000..d7a5b343 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/keller.h @@ -0,0 +1,34 @@ +/* keller.h (cover edges by cliques, Kellerman's heuristic) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2009-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#ifndef KELLER_H +#define KELLER_H + +#define kellerman _glp_kellerman +int kellerman(int n, int (*func)(void *info, int i, int ind[]), + void *info, void /* glp_graph */ *H); +/* cover edges by cliques with Kellerman's heuristic */ + +#endif + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/ks.c b/test/monniaux/glpk-4.65/src/misc/ks.c new file mode 100644 index 00000000..0720cc90 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/ks.c @@ -0,0 +1,466 @@ +/* ks.c (0-1 knapsack problem) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2017-2018 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#include "env.h" +#include "ks.h" +#include "mt1.h" + +/*********************************************************************** +* 0-1 knapsack problem has the following formulation: +* +* maximize z = sum{j in 1..n} c[j]x[j] (1) +* +* s.t. sum{j in 1..n} a[j]x[j] <= b (2) +* +* x[j] in {0, 1} for all j in 1..n (3) +* +* In general case it is assumed that the instance is non-normalized, +* i.e. parameters a, b, and c may have any sign. +***********************************************************************/ + +/*********************************************************************** +* ks_enum - solve 0-1 knapsack problem by complete enumeration +* +* This routine finds optimal solution to 0-1 knapsack problem (1)-(3) +* by complete enumeration. It is intended mainly for testing purposes. +* +* The instance to be solved is specified by parameters n, a, b, and c. +* Note that these parameters can have any sign, i.e. normalization is +* not needed. +* +* On exit the routine stores the optimal point found in locations +* x[1], ..., x[n] and returns the optimal objective value. However, if +* the instance is infeasible, the routine returns INT_MIN. +* +* Since the complete enumeration is inefficient, this routine can be +* used only for small instances (n <= 20-30). */ + +#define N_MAX 40 + +int ks_enum(int n, const int a[/*1+n*/], int b, const int c[/*1+n*/], + char x[/*1+n*/]) +{ int j, s, z, z_best; + char x_best[1+N_MAX]; + xassert(0 <= n && n <= N_MAX); + /* initialization */ + memset(&x[1], 0, n * sizeof(char)); + z_best = INT_MIN; +loop: /* compute constraint and objective at current x */ + s = z = 0; + for (j = 1; j <= n; j++) + { if (x[j]) + s += a[j], z += c[j]; + } + /* check constraint violation */ + if (s > b) + goto next; + /* check objective function */ + if (z_best < z) + { /* better solution has been found */ + memcpy(&x_best[1], &x[1], n * sizeof(char)); + z_best = z; + } +next: /* generate next x */ + for (j = 1; j <= n; j++) + { if (!x[j]) + { x[j] = 1; + goto loop; + } + x[j] = 0; + } + /* report best (optimal) solution */ + memcpy(&x[1], &x_best[1], n * sizeof(char)); + return z_best; +} + +/*********************************************************************** +* reduce - prepare reduced instance of 0-1 knapsack +* +* Given original instance of 0-1 knapsack (1)-(3) specified by the +* parameters n, a, b, and c this routine transforms it to equivalent +* reduced instance in the same format. The reduced instance is +* normalized, i.e. the following additional conditions are met: +* +* n >= 2 (4) +* +* 1 <= a[j] <= b for all j in 1..n (5) +* +* sum{j in 1..n} a[j] >= b+1 (6) +* +* c[j] >= 1 for all j in 1..n (7) +* +* The routine creates the structure ks and stores there parameters n, +* a, b, and c of the reduced instance as well as template of solution +* to original instance. +* +* Normally the routine returns a pointer to the structure ks created. +* However, if the original instance is infeasible, the routine returns +* a null pointer. */ + +struct ks +{ int orig_n; + /* original problem dimension */ + int n; + /* reduced problem dimension */ + int *a; /* int a[1+orig_n]; */ + /* a{j in 1..n} are constraint coefficients (2) */ + int b; + /* b is constraint right-hand side (2) */ + int *c; /* int c[1+orig_n]; */ + /* c{j in 1..n} are objective coefficients (1) */ + int c0; + /* c0 is objective constant term */ + char *x; /* char x[1+orig_n]; */ + /* x{j in 1..orig_n} is solution template to original instance: + * x[j] = 0 x[j] is fixed at 0 + * x[j] = 1 x[j] is fixed at 1 + * x[j] = 0x10 x[j] = x[j'] + * x[j] = 0x11 x[j] = 1 - x[j'] + * where x[j'] is corresponding solution to reduced instance */ +}; + +static void free_ks(struct ks *ks); + +static struct ks *reduce(const int n, const int a[/*1+n*/], int b, + const int c[/*1+n*/]) +{ struct ks *ks; + int j, s; + xassert(n >= 0); + /* initially reduced instance is the same as original one */ + ks = talloc(1, struct ks); + ks->orig_n = n; + ks->n = 0; + ks->a = talloc(1+n, int); + memcpy(&ks->a[1], &a[1], n * sizeof(int)); + ks->b = b; + ks->c = talloc(1+n, int); + memcpy(&ks->c[1], &c[1], n * sizeof(int)); + ks->c0 = 0; + ks->x = talloc(1+n, char); + /* make all a[j] non-negative */ + for (j = 1; j <= n; j++) + { if (a[j] >= 0) + { /* keep original x[j] */ + ks->x[j] = 0x10; + } + else /* a[j] < 0 */ + { /* substitute x[j] = 1 - x'[j] */ + ks->x[j] = 0x11; + /* ... + a[j]x[j] + ... <= b + * ... + a[j](1 - x'[j]) + ... <= b + * ... - a[j]x'[j] + ... <= b - a[j] */ + ks->a[j] = - ks->a[j]; + ks->b += ks->a[j]; + /* z = ... + c[j]x[j] + ... + c0 = + * = ... + c[j](1 - x'[j]) + ... + c0 = + * = ... - c[j]x'[j] + ... + (c0 + c[j]) */ + ks->c0 += ks->c[j]; + ks->c[j] = - ks->c[j]; + } + } + /* now a[j] >= 0 for all j in 1..n */ + if (ks->b < 0) + { /* instance is infeasible */ + free_ks(ks); + return NULL; + } + /* build reduced instance */ + for (j = 1; j <= n; j++) + { if (ks->a[j] == 0) + { if (ks->c[j] <= 0) + { /* fix x[j] at 0 */ + ks->x[j] ^= 0x10; + } + else + { /* fix x[j] at 1 */ + ks->x[j] ^= 0x11; + ks->c0 += ks->c[j]; + } + } + else if (ks->a[j] > ks->b || ks->c[j] <= 0) + { /* fix x[j] at 0 */ + ks->x[j] ^= 0x10; + } + else + { /* include x[j] in reduced instance */ + ks->n++; + ks->a[ks->n] = ks->a[j]; + ks->c[ks->n] = ks->c[j]; + } + } + /* now conditions (5) and (7) are met */ + /* check condition (6) */ + s = 0; + for (j = 1; j <= ks->n; j++) + { xassert(1 <= ks->a[j] && ks->a[j] <= ks->b); + xassert(ks->c[j] >= 1); + s += ks->a[j]; + } + if (s <= ks->b) + { /* sum{j in 1..n} a[j] <= b */ + /* fix all remaining x[j] at 1 to obtain trivial solution */ + for (j = 1; j <= n; j++) + { if (ks->x[j] & 0x10) + ks->x[j] ^= 0x11; + } + for (j = 1; j <= ks->n; j++) + ks->c0 += ks->c[j]; + /* reduced instance is empty */ + ks->n = 0; + } + /* here n = 0 or n >= 2 due to condition (6) */ + xassert(ks->n == 0 || ks->n >= 2); + return ks; +} + +/*********************************************************************** +* restore - restore solution to original 0-1 knapsack instance +* +* Given optimal solution x{j in 1..ks->n} to the reduced 0-1 knapsack +* instance (previously prepared by the routine reduce) this routine +* constructs optimal solution to the original instance and stores it +* in the array ks->x{j in 1..ks->orig_n}. +* +* On exit the routine returns optimal objective value for the original +* instance. +* +* NOTE: This operation should be performed only once. */ + +static int restore(struct ks *ks, char x[]) +{ int j, k, z; + z = ks->c0; + for (j = 1, k = 0; j <= ks->orig_n; j++) + { if (ks->x[j] & 0x10) + { k++; + xassert(k <= ks->n); + xassert(x[k] == 0 || x[k] == 1); + if (ks->x[j] & 1) + ks->x[j] = 1 - x[k]; + else + ks->x[j] = x[k]; + if (x[k]) + z += ks->c[k]; + } + } + xassert(k == ks->n); + return z; +} + +/*********************************************************************** +* free_ks - deallocate structure ks +* +* This routine frees memory previously allocated to the structure ks +* and all its components. */ + +static void free_ks(struct ks *ks) +{ xassert(ks != NULL); + tfree(ks->a); + tfree(ks->c); + tfree(ks->x); + tfree(ks); +} + +/*********************************************************************** +* ks_mt1 - solve 0-1 knapsack problem with Martello & Toth algorithm +* +* This routine finds optimal solution to 0-1 knapsack problem (1)-(3) +* with Martello & Toth algorithm MT1. +* +* The instance to be solved is specified by parameters n, a, b, and c. +* Note that these parameters can have any sign, i.e. normalization is +* not needed. +* +* On exit the routine stores the optimal point found in locations +* x[1], ..., x[n] and returns the optimal objective value. However, if +* the instance is infeasible, the routine returns INT_MIN. +* +* REFERENCES +* +* S.Martello, P.Toth. Knapsack Problems: Algorithms and Computer Imp- +* lementations. John Wiley & Sons, 1990. */ + +struct mt +{ int j; + float r; /* r[j] = c[j] / a[j] */ +}; + +static int CDECL fcmp(const void *p1, const void *p2) +{ if (((struct mt *)p1)->r > ((struct mt *)p2)->r) + return -1; + else if (((struct mt *)p1)->r < ((struct mt *)p2)->r) + return +1; + else + return 0; +} + +static int mt1a(int n, const int a[], int b, const int c[], char x[]) +{ /* interface routine to MT1 */ + struct mt *mt; + int j, z, *p, *w, *x1, *xx, *min, *psign, *wsign, *zsign; + xassert(n >= 2); + /* allocate working arrays */ + mt = talloc(1+n, struct mt); + p = talloc(1+n+1, int); + w = talloc(1+n+1, int); + x1 = talloc(1+n+1, int); + xx = talloc(1+n+1, int); + min = talloc(1+n+1, int); + psign = talloc(1+n+1, int); + wsign = talloc(1+n+1, int); + zsign = talloc(1+n+1, int); + /* reorder items to provide c[j] / a[j] >= a[j+1] / a[j+1] */ + for (j = 1; j <= n; j++) + { mt[j].j = j; + mt[j].r = (float)c[j] / (float)a[j]; + } + qsort(&mt[1], n, sizeof(struct mt), fcmp); + /* load instance parameters */ + for (j = 1; j <= n; j++) + { p[j] = c[mt[j].j]; + w[j] = a[mt[j].j]; + } + /* find optimal solution */ + z = mt1(n, p, w, b, x1, 1, xx, min, psign, wsign, zsign); + xassert(z >= 0); + /* store optimal point found */ + for (j = 1; j <= n; j++) + { xassert(x1[j] == 0 || x1[j] == 1); + x[mt[j].j] = x1[j]; + } + /* free working arrays */ + tfree(mt); + tfree(p); + tfree(w); + tfree(x1); + tfree(xx); + tfree(min); + tfree(psign); + tfree(wsign); + tfree(zsign); + return z; +} + +int ks_mt1(int n, const int a[/*1+n*/], int b, const int c[/*1+n*/], + char x[/*1+n*/]) +{ struct ks *ks; + int j, s1, s2, z; + xassert(n >= 0); + /* prepare reduced instance */ + ks = reduce(n, a, b, c); + if (ks == NULL) + { /* original instance is infeasible */ + return INT_MIN; + } + /* find optimal solution to reduced instance */ + if (ks->n > 0) + mt1a(ks->n, ks->a, ks->b, ks->c, x); + /* restore solution to original instance */ + z = restore(ks, x); + memcpy(&x[1], &ks->x[1], n * sizeof(char)); + free_ks(ks); + /* check solution found */ + s1 = s2 = 0; + for (j = 1; j <= n; j++) + { xassert(x[j] == 0 || x[j] == 1); + if (x[j]) + s1 += a[j], s2 += c[j]; + } + xassert(s1 <= b); + xassert(s2 == z); + return z; +} + +/*********************************************************************** +* ks_greedy - solve 0-1 knapsack problem with greedy heuristic +* +* This routine finds (sub)optimal solution to 0-1 knapsack problem +* (1)-(3) with greedy heuristic. +* +* The instance to be solved is specified by parameters n, a, b, and c. +* Note that these parameters can have any sign, i.e. normalization is +* not needed. +* +* On exit the routine stores the optimal point found in locations +* x[1], ..., x[n] and returns the optimal objective value. However, if +* the instance is infeasible, the routine returns INT_MIN. */ + +static int greedy(int n, const int a[], int b, const int c[], char x[]) +{ /* core routine for normalized 0-1 knapsack instance */ + struct mt *mt; + int j, s, z; + xassert(n >= 2); + /* reorder items to provide c[j] / a[j] >= a[j+1] / a[j+1] */ + mt = talloc(1+n, struct mt); + for (j = 1; j <= n; j++) + { mt[j].j = j; + mt[j].r = (float)c[j] / (float)a[j]; + } + qsort(&mt[1], n, sizeof(struct mt), fcmp); + /* take items starting from most valuable ones until the knapsack + * is full */ + s = z = 0; + for (j = 1; j <= n; j++) + { if (s + a[mt[j].j] > b) + break; + x[mt[j].j] = 1; + s += a[mt[j].j]; + z += c[mt[j].j]; + } + /* don't take remaining items */ + for (j = j; j <= n; j++) + x[mt[j].j] = 0; + tfree(mt); + return z; +} + +int ks_greedy(int n, const int a[/*1+n*/], int b, const int c[/*1+n*/], + char x[/*1+n*/]) +{ struct ks *ks; + int j, s1, s2, z; + xassert(n >= 0); + /* prepare reduced instance */ + ks = reduce(n, a, b, c); + if (ks == NULL) + { /* original instance is infeasible */ + return INT_MIN; + } + /* find suboptimal solution to reduced instance */ + if (ks->n > 0) + greedy(ks->n, ks->a, ks->b, ks->c, x); + /* restore solution to original instance */ + z = restore(ks, x); + memcpy(&x[1], &ks->x[1], n * sizeof(char)); + free_ks(ks); + /* check solution found */ + s1 = s2 = 0; + for (j = 1; j <= n; j++) + { xassert(x[j] == 0 || x[j] == 1); + if (x[j]) + s1 += a[j], s2 += c[j]; + } + xassert(s1 <= b); + xassert(s2 == z); + return z; +} + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/ks.h b/test/monniaux/glpk-4.65/src/misc/ks.h new file mode 100644 index 00000000..d607dc44 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/ks.h @@ -0,0 +1,44 @@ +/* ks.h (0-1 knapsack problem) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2017-2018 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#ifndef KS_H +#define KS_H + +#define ks_enum _glp_ks_enum +int ks_enum(int n, const int a[/*1+n*/], int b, const int c[/*1+n*/], + char x[/*1+n*/]); +/* solve 0-1 knapsack problem by complete enumeration */ + +#define ks_mt1 _glp_ks_mt1 +int ks_mt1(int n, const int a[/*1+n*/], int b, const int c[/*1+n*/], + char x[/*1+n*/]); +/* solve 0-1 knapsack problem with Martello & Toth algorithm */ + +#define ks_greedy _glp_ks_greedy +int ks_greedy(int n, const int a[/*1+n*/], int b, const int c[/*1+n*/], + char x[/*1+n*/]); +/* solve 0-1 knapsack problem with greedy heuristic */ + +#endif + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/mc13d.c b/test/monniaux/glpk-4.65/src/misc/mc13d.c new file mode 100644 index 00000000..d8bab398 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/mc13d.c @@ -0,0 +1,314 @@ +/* mc13d.c (permutations to block triangular form) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* This code is the result of translation of the Fortran subroutines +* MC13D and MC13E associated with the following paper: +* +* I.S.Duff, J.K.Reid, Algorithm 529: Permutations to block triangular +* form, ACM Trans. on Math. Softw. 4 (1978), 189-192. +* +* Use of ACM Algorithms is subject to the ACM Software Copyright and +* License Agreement. See . +* +* The translation was made by Andrew Makhorin . +* +* 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 . +***********************************************************************/ + +#include "mc13d.h" + +/*********************************************************************** +* NAME +* +* mc13d - permutations to block triangular form +* +* SYNOPSIS +* +* #include "mc13d.h" +* int mc13d(int n, const int icn[], const int ip[], const int lenr[], +* int ior[], int ib[], int lowl[], int numb[], int prev[]); +* +* DESCRIPTION +* +* Given the column numbers of the nonzeros in each row of the sparse +* matrix, the routine mc13d finds a symmetric permutation that makes +* the matrix block lower triangular. +* +* INPUT PARAMETERS +* +* n order of the matrix. +* +* icn array containing the column indices of the non-zeros. Those +* belonging to a single row must be contiguous but the ordering +* of column indices within each row is unimportant and wasted +* space between rows is permitted. +* +* ip ip[i], i = 1,2,...,n, is the position in array icn of the +* first column index of a non-zero in row i. +* +* lenr lenr[i], i = 1,2,...,n, is the number of non-zeros in row i. +* +* OUTPUT PARAMETERS +* +* ior ior[i], i = 1,2,...,n, gives the position on the original +* ordering of the row or column which is in position i in the +* permuted form. +* +* ib ib[i], i = 1,2,...,num, is the row number in the permuted +* matrix of the beginning of block i, 1 <= num <= n. +* +* WORKING ARRAYS +* +* arp working array of length [1+n], where arp[0] is not used. +* arp[i] is one less than the number of unsearched edges leaving +* node i. At the end of the algorithm it is set to a permutation +* which puts the matrix in block lower triangular form. +* +* ib working array of length [1+n], where ib[0] is not used. +* ib[i] is the position in the ordering of the start of the ith +* block. ib[n+1-i] holds the node number of the ith node on the +* stack. +* +* lowl working array of length [1+n], where lowl[0] is not used. +* lowl[i] is the smallest stack position of any node to which a +* path from node i has been found. It is set to n+1 when node i +* is removed from the stack. +* +* numb working array of length [1+n], where numb[0] is not used. +* numb[i] is the position of node i in the stack if it is on it, +* is the permuted order of node i for those nodes whose final +* position has been found and is otherwise zero. +* +* prev working array of length [1+n], where prev[0] is not used. +* prev[i] is the node at the end of the path when node i was +* placed on the stack. +* +* RETURNS +* +* The routine mc13d returns num, the number of blocks found. */ + +int mc13d(int n, const int icn[], const int ip[], const int lenr[], + int ior[], int ib[], int lowl[], int numb[], int prev[]) +{ int *arp = ior; + int dummy, i, i1, i2, icnt, ii, isn, ist, ist1, iv, iw, j, lcnt, + nnm1, num, stp; + /* icnt is the number of nodes whose positions in final ordering + * have been found. */ + icnt = 0; + /* num is the number of blocks that have been found. */ + num = 0; + nnm1 = n + n - 1; + /* Initialization of arrays. */ + for (j = 1; j <= n; j++) + { numb[j] = 0; + arp[j] = lenr[j] - 1; + } + for (isn = 1; isn <= n; isn++) + { /* Look for a starting node. */ + if (numb[isn] != 0) continue; + iv = isn; + /* ist is the number of nodes on the stack ... it is the stack + * pointer. */ + ist = 1; + /* Put node iv at beginning of stack. */ + lowl[iv] = numb[iv] = 1; + ib[n] = iv; + /* The body of this loop puts a new node on the stack or + * backtracks. */ + for (dummy = 1; dummy <= nnm1; dummy++) + { i1 = arp[iv]; + /* Have all edges leaving node iv been searched? */ + if (i1 >= 0) + { i2 = ip[iv] + lenr[iv] - 1; + i1 = i2 - i1; + /* Look at edges leaving node iv until one enters a new + * node or all edges are exhausted. */ + for (ii = i1; ii <= i2; ii++) + { iw = icn[ii]; + /* Has node iw been on stack already? */ + if (numb[iw] == 0) goto L70; + /* Update value of lowl[iv] if necessary. */ + if (lowl[iw] < lowl[iv]) lowl[iv] = lowl[iw]; + } + /* There are no more edges leaving node iv. */ + arp[iv] = -1; + } + /* Is node iv the root of a block? */ + if (lowl[iv] < numb[iv]) goto L60; + /* Order nodes in a block. */ + num++; + ist1 = n + 1 - ist; + lcnt = icnt + 1; + /* Peel block off the top of the stack starting at the top + * and working down to the root of the block. */ + for (stp = ist1; stp <= n; stp++) + { iw = ib[stp]; + lowl[iw] = n + 1; + numb[iw] = ++icnt; + if (iw == iv) break; + } + ist = n - stp; + ib[num] = lcnt; + /* Are there any nodes left on the stack? */ + if (ist != 0) goto L60; + /* Have all the nodes been ordered? */ + if (icnt < n) break; + goto L100; +L60: /* Backtrack to previous node on path. */ + iw = iv; + iv = prev[iv]; + /* Update value of lowl[iv] if necessary. */ + if (lowl[iw] < lowl[iv]) lowl[iv] = lowl[iw]; + continue; +L70: /* Put new node on the stack. */ + arp[iv] = i2 - ii - 1; + prev[iw] = iv; + iv = iw; + lowl[iv] = numb[iv] = ++ist; + ib[n+1-ist] = iv; + } + } +L100: /* Put permutation in the required form. */ + for (i = 1; i <= n; i++) + arp[numb[i]] = i; + return num; +} + +/**********************************************************************/ + +#ifdef GLP_TEST +#include "env.h" + +void test(int n, int ipp); + +int main(void) +{ /* test program for routine mc13d */ + test( 1, 0); + test( 2, 1); + test( 2, 2); + test( 3, 3); + test( 4, 4); + test( 5, 10); + test(10, 10); + test(10, 20); + test(20, 20); + test(20, 50); + test(50, 50); + test(50, 200); + return 0; +} + +void fa01bs(int max, int *nrand); + +void setup(int n, char a[1+50][1+50], int ip[], int icn[], int lenr[]); + +void test(int n, int ipp) +{ int ip[1+50], icn[1+1000], ior[1+50], ib[1+51], iw[1+150], + lenr[1+50]; + char a[1+50][1+50], hold[1+100]; + int i, ii, iblock, ij, index, j, jblock, jj, k9, num; + xprintf("\n\n\nMatrix is of order %d and has %d off-diagonal non-" + "zeros\n", n, ipp); + for (j = 1; j <= n; j++) + { for (i = 1; i <= n; i++) + a[i][j] = 0; + a[j][j] = 1; + } + for (k9 = 1; k9 <= ipp; k9++) + { /* these statements should be replaced by calls to your + * favorite random number generator to place two pseudo-random + * numbers between 1 and n in the variables i and j */ + for (;;) + { fa01bs(n, &i); + fa01bs(n, &j); + if (!a[i][j]) break; + } + a[i][j] = 1; + } + /* setup converts matrix a[i,j] to required sparsity-oriented + * storage format */ + setup(n, a, ip, icn, lenr); + num = mc13d(n, icn, ip, lenr, ior, ib, &iw[0], &iw[n], &iw[n+n]); + /* output reordered matrix with blocking to improve clarity */ + xprintf("\nThe reordered matrix which has %d block%s is of the fo" + "rm\n", num, num == 1 ? "" : "s"); + ib[num+1] = n + 1; + index = 100; + iblock = 1; + for (i = 1; i <= n; i++) + { for (ij = 1; ij <= index; ij++) + hold[ij] = ' '; + if (i == ib[iblock]) + { xprintf("\n"); + iblock++; + } + jblock = 1; + index = 0; + for (j = 1; j <= n; j++) + { if (j == ib[jblock]) + { hold[++index] = ' '; + jblock++; + } + ii = ior[i]; + jj = ior[j]; + hold[++index] = (char)(a[ii][jj] ? 'X' : '0'); + } + xprintf("%.*s\n", index, &hold[1]); + } + xprintf("\nThe starting point for each block is given by\n"); + for (i = 1; i <= num; i++) + { if ((i - 1) % 12 == 0) xprintf("\n"); + xprintf(" %4d", ib[i]); + } + xprintf("\n"); + return; +} + +void setup(int n, char a[1+50][1+50], int ip[], int icn[], int lenr[]) +{ int i, j, ind; + for (i = 1; i <= n; i++) + lenr[i] = 0; + ind = 1; + for (i = 1; i <= n; i++) + { ip[i] = ind; + for (j = 1; j <= n; j++) + { if (a[i][j]) + { lenr[i]++; + icn[ind++] = j; + } + } + } + return; +} + +double g = 1431655765.0; + +double fa01as(int i) +{ /* random number generator */ + g = fmod(g * 9228907.0, 4294967296.0); + if (i >= 0) + return g / 4294967296.0; + else + return 2.0 * g / 4294967296.0 - 1.0; +} + +void fa01bs(int max, int *nrand) +{ *nrand = (int)(fa01as(1) * (double)max) + 1; + return; +} +#endif + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/mc13d.h b/test/monniaux/glpk-4.65/src/misc/mc13d.h new file mode 100644 index 00000000..bdd57a19 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/mc13d.h @@ -0,0 +1,34 @@ +/* mc13d.h */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2009-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#ifndef MC13D_H +#define MC13D_H + +#define mc13d _glp_mc13d +int mc13d(int n, const int icn[], const int ip[], const int lenr[], + int ior[], int ib[], int lowl[], int numb[], int prev[]); +/* permutations to block triangular form */ + +#endif + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/mc21a.c b/test/monniaux/glpk-4.65/src/misc/mc21a.c new file mode 100644 index 00000000..700d0f4e --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/mc21a.c @@ -0,0 +1,301 @@ +/* mc21a.c (permutations for zero-free diagonal) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* This code is the result of translation of the Fortran subroutines +* MC21A and MC21B associated with the following paper: +* +* I.S.Duff, Algorithm 575: Permutations for zero-free diagonal, ACM +* Trans. on Math. Softw. 7 (1981), 387-390. +* +* Use of ACM Algorithms is subject to the ACM Software Copyright and +* License Agreement. See . +* +* The translation was made by Andrew Makhorin . +* +* 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 . +***********************************************************************/ + +#include "mc21a.h" + +/*********************************************************************** +* NAME +* +* mc21a - permutations for zero-free diagonal +* +* SYNOPSIS +* +* #include "mc21a.h" +* int mc21a(int n, const int icn[], const int ip[], const int lenr[], +* int iperm[], int pr[], int arp[], int cv[], int out[]); +* +* DESCRIPTION +* +* Given the pattern of nonzeros of a sparse matrix, the routine mc21a +* attempts to find a permutation of its rows that makes the matrix have +* no zeros on its diagonal. +* +* INPUT PARAMETERS +* +* n order of matrix. +* +* icn array containing the column indices of the non-zeros. Those +* belonging to a single row must be contiguous but the ordering +* of column indices within each row is unimportant and wasted +* space between rows is permitted. +* +* ip ip[i], i = 1,2,...,n, is the position in array icn of the +* first column index of a non-zero in row i. +* +* lenr lenr[i], i = 1,2,...,n, is the number of non-zeros in row i. +* +* OUTPUT PARAMETER +* +* iperm contains permutation to make diagonal have the smallest +* number of zeros on it. Elements (iperm[i], i), i = 1,2,...,n, +* are non-zero at the end of the algorithm unless the matrix is +* structurally singular. In this case, (iperm[i], i) will be +* zero for n - numnz entries. +* +* WORKING ARRAYS +* +* pr working array of length [1+n], where pr[0] is not used. +* pr[i] is the previous row to i in the depth first search. +* +* arp working array of length [1+n], where arp[0] is not used. +* arp[i] is one less than the number of non-zeros in row i which +* have not been scanned when looking for a cheap assignment. +* +* cv working array of length [1+n], where cv[0] is not used. +* cv[i] is the most recent row extension at which column i was +* visited. +* +* out working array of length [1+n], where out[0] is not used. +* out[i] is one less than the number of non-zeros in row i +* which have not been scanned during one pass through the main +* loop. +* +* RETURNS +* +* The routine mc21a returns numnz, the number of non-zeros on diagonal +* of permuted matrix. */ + +int mc21a(int n, const int icn[], const int ip[], const int lenr[], + int iperm[], int pr[], int arp[], int cv[], int out[]) +{ int i, ii, in1, in2, j, j1, jord, k, kk, numnz; + /* Initialization of arrays. */ + for (i = 1; i <= n; i++) + { arp[i] = lenr[i] - 1; + cv[i] = iperm[i] = 0; + } + numnz = 0; + /* Main loop. */ + /* Each pass round this loop either results in a new assignment + * or gives a row with no assignment. */ + for (jord = 1; jord <= n; jord++) + { j = jord; + pr[j] = -1; + for (k = 1; k <= jord; k++) + { /* Look for a cheap assignment. */ + in1 = arp[j]; + if (in1 >= 0) + { in2 = ip[j] + lenr[j] - 1; + in1 = in2 - in1; + for (ii = in1; ii <= in2; ii++) + { i = icn[ii]; + if (iperm[i] == 0) goto L110; + } + /* No cheap assignment in row. */ + arp[j] = -1; + } + /* Begin looking for assignment chain starting with row j.*/ + out[j] = lenr[j] - 1; + /* Inner loop. Extends chain by one or backtracks. */ + for (kk = 1; kk <= jord; kk++) + { in1 = out[j]; + if (in1 >= 0) + { in2 = ip[j] + lenr[j] - 1; + in1 = in2 - in1; + /* Forward scan. */ + for (ii = in1; ii <= in2; ii++) + { i = icn[ii]; + if (cv[i] != jord) + { /* Column i has not yet been accessed during + * this pass. */ + j1 = j; + j = iperm[i]; + cv[i] = jord; + pr[j] = j1; + out[j1] = in2 - ii - 1; + goto L100; + } + } + } + /* Backtracking step. */ + j = pr[j]; + if (j == -1) goto L130; + } +L100: ; + } +L110: /* New assignment is made. */ + iperm[i] = j; + arp[j] = in2 - ii - 1; + numnz++; + for (k = 1; k <= jord; k++) + { j = pr[j]; + if (j == -1) break; + ii = ip[j] + lenr[j] - out[j] - 2; + i = icn[ii]; + iperm[i] = j; + } +L130: ; + } + /* If matrix is structurally singular, we now complete the + * permutation iperm. */ + if (numnz < n) + { for (i = 1; i <= n; i++) + arp[i] = 0; + k = 0; + for (i = 1; i <= n; i++) + { if (iperm[i] == 0) + out[++k] = i; + else + arp[iperm[i]] = i; + } + k = 0; + for (i = 1; i <= n; i++) + { if (arp[i] == 0) + iperm[out[++k]] = i; + } + } + return numnz; +} + +/**********************************************************************/ + +#ifdef GLP_TEST +#include "env.h" + +int sing; + +void ranmat(int m, int n, int icn[], int iptr[], int nnnp1, int *knum, + int iw[]); + +void fa01bs(int max, int *nrand); + +int main(void) +{ /* test program for the routine mc21a */ + /* these runs on random matrices cause all possible statements in + * mc21a to be executed */ + int i, iold, j, j1, j2, jj, knum, l, licn, n, nov4, num, numnz; + int ip[1+21], icn[1+1000], iperm[1+20], lenr[1+20], iw1[1+80]; + licn = 1000; + /* run on random matrices of orders 1 through 20 */ + for (n = 1; n <= 20; n++) + { nov4 = n / 4; + if (nov4 < 1) nov4 = 1; +L10: fa01bs(nov4, &l); + knum = l * n; + /* knum is requested number of non-zeros in random matrix */ + if (knum > licn) goto L10; + /* if sing is false, matrix is guaranteed structurally + * non-singular */ + sing = ((n / 2) * 2 == n); + /* call to subroutine to generate random matrix */ + ranmat(n, n, icn, ip, n+1, &knum, iw1); + /* knum is now actual number of non-zeros in random matrix */ + if (knum > licn) goto L10; + xprintf("n = %2d; nz = %4d; sing = %d\n", n, knum, sing); + /* set up array of row lengths */ + for (i = 1; i <= n; i++) + lenr[i] = ip[i+1] - ip[i]; + /* call to mc21a */ + numnz = mc21a(n, icn, ip, lenr, iperm, &iw1[0], &iw1[n], + &iw1[n+n], &iw1[n+n+n]); + /* testing to see if there are numnz non-zeros on the diagonal + * of the permuted matrix. */ + num = 0; + for (i = 1; i <= n; i++) + { iold = iperm[i]; + j1 = ip[iold]; + j2 = j1 + lenr[iold] - 1; + if (j2 < j1) continue; + for (jj = j1; jj <= j2; jj++) + { j = icn[jj]; + if (j == i) + { num++; + break; + } + } + } + if (num != numnz) + xprintf("Failure in mc21a, numnz = %d instead of %d\n", + numnz, num); + } + return 0; +} + +void ranmat(int m, int n, int icn[], int iptr[], int nnnp1, int *knum, + int iw[]) +{ /* subroutine to generate random matrix */ + int i, ii, inum, j, lrow, matnum; + inum = (*knum / n) * 2; + if (inum > n-1) inum = n-1; + matnum = 1; + /* each pass through this loop generates a row of the matrix */ + for (j = 1; j <= m; j++) + { iptr[j] = matnum; + if (!(sing || j > n)) + icn[matnum++] = j; + if (n == 1) continue; + for (i = 1; i <= n; i++) iw[i] = 0; + if (!sing) iw[j] = 1; + fa01bs(inum, &lrow); + lrow--; + if (lrow == 0) continue; + /* lrow off-diagonal non-zeros in row j of the matrix */ + for (ii = 1; ii <= lrow; ii++) + { for (;;) + { fa01bs(n, &i); + if (iw[i] != 1) break; + } + iw[i] = 1; + icn[matnum++] = i; + } + } + for (i = m+1; i <= nnnp1; i++) + iptr[i] = matnum; + *knum = matnum - 1; + return; +} + +double g = 1431655765.0; + +double fa01as(int i) +{ /* random number generator */ + g = fmod(g * 9228907.0, 4294967296.0); + if (i >= 0) + return g / 4294967296.0; + else + return 2.0 * g / 4294967296.0 - 1.0; +} + +void fa01bs(int max, int *nrand) +{ *nrand = (int)(fa01as(1) * (double)max) + 1; + return; +} +#endif + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/mc21a.h b/test/monniaux/glpk-4.65/src/misc/mc21a.h new file mode 100644 index 00000000..755f28b2 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/mc21a.h @@ -0,0 +1,34 @@ +/* mc21a.h (permutations for zero-free diagonal) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2009-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#ifndef MC21A_H +#define MC21A_H + +#define mc21a _glp_mc21a +int mc21a(int n, const int icn[], const int ip[], const int lenr[], + int iperm[], int pr[], int arp[], int cv[], int out[]); +/* permutations for zero-free diagonal */ + +#endif + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/misc.h b/test/monniaux/glpk-4.65/src/misc/misc.h new file mode 100644 index 00000000..1ba1dc50 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/misc.h @@ -0,0 +1,61 @@ +/* misc.h (miscellaneous routines) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2000-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#ifndef MISC_H +#define MISC_H + +#define str2int _glp_str2int +int str2int(const char *str, int *val); +/* convert character string to value of int type */ + +#define str2num _glp_str2num +int str2num(const char *str, double *val); +/* convert character string to value of double type */ + +#define strspx _glp_strspx +char *strspx(char *str); +/* remove all spaces from character string */ + +#define strtrim _glp_strtrim +char *strtrim(char *str); +/* remove trailing spaces from character string */ + +#define gcd _glp_gcd +int gcd(int x, int y); +/* find greatest common divisor of two integers */ + +#define gcdn _glp_gcdn +int gcdn(int n, int x[]); +/* find greatest common divisor of n integers */ + +#define round2n _glp_round2n +double round2n(double x); +/* round floating-point number to nearest power of two */ + +#define fp2rat _glp_fp2rat +int fp2rat(double x, double eps, double *p, double *q); +/* convert floating-point number to rational number */ + +#endif + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/mt1.c b/test/monniaux/glpk-4.65/src/misc/mt1.c new file mode 100644 index 00000000..63a0f80e --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/mt1.c @@ -0,0 +1,1110 @@ +/* mt1.c (0-1 knapsack problem; Martello & Toth algorithm) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* THIS CODE IS THE RESULT OF TRANSLATION OF THE FORTRAN SUBROUTINES +* MT1 FROM THE BOOK: +* +* SILVANO MARTELLO, PAOLO TOTH. KNAPSACK PROBLEMS: ALGORITHMS AND +* COMPUTER IMPLEMENTATIONS. JOHN WILEY & SONS, 1990. +* +* THE TRANSLATION HAS BEEN DONE WITH THE PERMISSION OF THE AUTHORS OF +* THE ORIGINAL FORTRAN SUBROUTINES: SILVANO MARTELLO AND PAOLO TOTH. +* +* The translation was made by Andrew Makhorin . +* +* 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 . +***********************************************************************/ + +#line 1 "" +/* -- translated by f2c (version 20100827). + You must link the resulting object file with libf2c: + on Microsoft Windows system, link with libf2c.lib; + on Linux or Unix systems, link with .../path/to/libf2c.a -lm + or, if you install libf2c.a in a standard place, with -lf2c -lm + -- in that order, at the end of the command line, as in + cc *.o -lf2c -lm + Source for libf2c is in /netlib/f2c/libf2c.zip, e.g., + + http://www.netlib.org/f2c/libf2c.zip +*/ + +#if 0 /* by mao */ +#include "f2c.h" +#else +#include "env.h" +#include "mt1.h" + +typedef int integer; +typedef float real; +#endif + +#line 1 "" +/*< SUBROUTINE MT1(N,P,W,C,Z,X,JDIM,JCK,XX,MIN,PSIGN,WSIGN,ZSIGN) >*/ +#if 1 /* by mao */ +static int chmt1_(int *, int *, int *, int *, int *, int *); + +static +#endif +/* Subroutine */ int mt1_(integer *n, integer *p, integer *w, integer *c__, + integer *z__, integer *x, integer *jdim, integer *jck, integer *xx, + integer *min__, integer *psign, integer *wsign, integer *zsign) +{ + /* System generated locals */ + integer i__1; + + /* Local variables */ + static real a, b; + static integer j, r__, t, j1, n1, ch, ii, jj, kk, in, ll, ip, nn, iu, ii1, + chs, lim, lim1, diff, lold, mink; + extern /* Subroutine */ int chmt1_(integer *, integer *, integer *, + integer *, integer *, integer *); + static integer profit; + + +/* THIS SUBROUTINE SOLVES THE 0-1 SINGLE KNAPSACK PROBLEM */ + +/* MAXIMIZE Z = P(1)*X(1) + ... + P(N)*X(N) */ + +/* SUBJECT TO: W(1)*X(1) + ... + W(N)*X(N) .LE. C , */ +/* X(J) = 0 OR 1 FOR J=1,...,N. */ + +/* THE PROGRAM IS INCLUDED IN THE VOLUME */ +/* S. MARTELLO, P. TOTH, "KNAPSACK PROBLEMS: ALGORITHMS */ +/* AND COMPUTER IMPLEMENTATIONS", JOHN WILEY, 1990 */ +/* AND IMPLEMENTS THE BRANCH-AND-BOUND ALGORITHM DESCRIBED IN */ +/* SECTION 2.5.2 . */ +/* THE PROGRAM DERIVES FROM AN EARLIER CODE PRESENTED IN */ +/* S. MARTELLO, P. TOTH, "ALGORITHM FOR THE SOLUTION OF THE 0-1 SINGLE */ +/* KNAPSACK PROBLEM", COMPUTING, 1978. */ + +/* THE INPUT PROBLEM MUST SATISFY THE CONDITIONS */ + +/* 1) 2 .LE. N .LE. JDIM - 1 ; */ +/* 2) P(J), W(J), C POSITIVE INTEGERS; */ +/* 3) MAX (W(J)) .LE. C ; */ +/* 4) W(1) + ... + W(N) .GT. C ; */ +/* 5) P(J)/W(J) .GE. P(J+1)/W(J+1) FOR J=1,...,N-1. */ + +/* MT1 CALLS 1 PROCEDURE: CHMT1. */ + +/* THE PROGRAM IS COMPLETELY SELF-CONTAINED AND COMMUNICATION TO IT IS */ +/* ACHIEVED SOLELY THROUGH THE PARAMETER LIST OF MT1. */ +/* NO MACHINE-DEPENDENT CONSTANT IS USED. */ +/* THE PROGRAM IS WRITTEN IN 1967 AMERICAN NATIONAL STANDARD FORTRAN */ +/* AND IS ACCEPTED BY THE PFORT VERIFIER (PFORT IS THE PORTABLE */ +/* SUBSET OF ANSI DEFINED BY THE ASSOCIATION FOR COMPUTING MACHINERY). */ +/* THE PROGRAM HAS BEEN TESTED ON A DIGITAL VAX 11/780 AND AN H.P. */ +/* 9000/840. */ + +/* MT1 NEEDS 8 ARRAYS ( P , W , X , XX , MIN , PSIGN , WSIGN */ +/* AND ZSIGN ) OF LENGTH AT LEAST N + 1 . */ + +/* MEANING OF THE INPUT PARAMETERS: */ +/* N = NUMBER OF ITEMS; */ +/* P(J) = PROFIT OF ITEM J (J=1,...,N); */ +/* W(J) = WEIGHT OF ITEM J (J=1,...,N); */ +/* C = CAPACITY OF THE KNAPSACK; */ +/* JDIM = DIMENSION OF THE 8 ARRAYS; */ +/* JCK = 1 IF CHECK ON THE INPUT DATA IS DESIRED, */ +/* = 0 OTHERWISE. */ + +/* MEANING OF THE OUTPUT PARAMETERS: */ +/* Z = VALUE OF THE OPTIMAL SOLUTION IF Z .GT. 0 , */ +/* = ERROR IN THE INPUT DATA (WHEN JCK=1) IF Z .LT. 0 : CONDI- */ +/* TION - Z IS VIOLATED; */ +/* X(J) = 1 IF ITEM J IS IN THE OPTIMAL SOLUTION, */ +/* = 0 OTHERWISE. */ + +/* ARRAYS XX, MIN, PSIGN, WSIGN AND ZSIGN ARE DUMMY. */ + +/* ALL THE PARAMETERS ARE INTEGER. ON RETURN OF MT1 ALL THE INPUT */ +/* PARAMETERS ARE UNCHANGED. */ + +/*< INTEGER P(JDIM),W(JDIM),X(JDIM),C,Z >*/ +/*< INTEGER XX(JDIM),MIN(JDIM),PSIGN(JDIM),WSIGN(JDIM),ZSIGN(JDIM) >*/ +/*< INTEGER CH,CHS,DIFF,PROFIT,R,T >*/ +/*< Z = 0 >*/ +#line 65 "" + /* Parameter adjustments */ +#line 65 "" + --zsign; +#line 65 "" + --wsign; +#line 65 "" + --psign; +#line 65 "" + --min__; +#line 65 "" + --xx; +#line 65 "" + --x; +#line 65 "" + --w; +#line 65 "" + --p; +#line 65 "" + +#line 65 "" + /* Function Body */ +#line 65 "" + *z__ = 0; +/*< IF ( JCK .EQ. 1 ) CALL CHMT1(N,P,W,C,Z,JDIM) >*/ +#line 66 "" + if (*jck == 1) { +#line 66 "" + chmt1_(n, &p[1], &w[1], c__, z__, jdim); +#line 66 "" + } +/*< IF ( Z .LT. 0 ) RETURN >*/ +#line 67 "" + if (*z__ < 0) { +#line 67 "" + return 0; +#line 67 "" + } +/* INITIALIZE. */ +/*< CH = C >*/ +#line 69 "" + ch = *c__; +/*< IP = 0 >*/ +#line 70 "" + ip = 0; +/*< CHS = CH >*/ +#line 71 "" + chs = ch; +/*< DO 10 LL=1,N >*/ +#line 72 "" + i__1 = *n; +#line 72 "" + for (ll = 1; ll <= i__1; ++ll) { +/*< IF ( W(LL) .GT. CHS ) GO TO 20 >*/ +#line 73 "" + if (w[ll] > chs) { +#line 73 "" + goto L20; +#line 73 "" + } +/*< IP = IP + P(LL) >*/ +#line 74 "" + ip += p[ll]; +/*< CHS = CHS - W(LL) >*/ +#line 75 "" + chs -= w[ll]; +/*< 10 CONTINUE >*/ +#line 76 "" +/* L10: */ +#line 76 "" + } +/*< 20 LL = LL - 1 >*/ +#line 77 "" +L20: +#line 77 "" + --ll; +/*< IF ( CHS .EQ. 0 ) GO TO 50 >*/ +#line 78 "" + if (chs == 0) { +#line 78 "" + goto L50; +#line 78 "" + } +/*< P(N+1) = 0 >*/ +#line 79 "" + p[*n + 1] = 0; +/*< W(N+1) = CH + 1 >*/ +#line 80 "" + w[*n + 1] = ch + 1; +/*< LIM = IP + CHS*P(LL+2)/W(LL+2) >*/ +#line 81 "" + lim = ip + chs * p[ll + 2] / w[ll + 2]; +/*< A = W(LL+1) - CHS >*/ +#line 82 "" + a = (real) (w[ll + 1] - chs); +/*< B = IP + P(LL+1) >*/ +#line 83 "" + b = (real) (ip + p[ll + 1]); +/*< LIM1 = B - A*FLOAT(P(LL))/FLOAT(W(LL)) >*/ +#line 84 "" + lim1 = b - a * (real) p[ll] / (real) w[ll]; +/*< IF ( LIM1 .GT. LIM ) LIM = LIM1 >*/ +#line 85 "" + if (lim1 > lim) { +#line 85 "" + lim = lim1; +#line 85 "" + } +/*< MINK = CH + 1 >*/ +#line 86 "" + mink = ch + 1; +/*< MIN(N) = MINK >*/ +#line 87 "" + min__[*n] = mink; +/*< DO 30 J=2,N >*/ +#line 88 "" + i__1 = *n; +#line 88 "" + for (j = 2; j <= i__1; ++j) { +/*< KK = N + 2 - J >*/ +#line 89 "" + kk = *n + 2 - j; +/*< IF ( W(KK) .LT. MINK ) MINK = W(KK) >*/ +#line 90 "" + if (w[kk] < mink) { +#line 90 "" + mink = w[kk]; +#line 90 "" + } +/*< MIN(KK-1) = MINK >*/ +#line 91 "" + min__[kk - 1] = mink; +/*< 30 CONTINUE >*/ +#line 92 "" +/* L30: */ +#line 92 "" + } +/*< DO 40 J=1,N >*/ +#line 93 "" + i__1 = *n; +#line 93 "" + for (j = 1; j <= i__1; ++j) { +/*< XX(J) = 0 >*/ +#line 94 "" + xx[j] = 0; +/*< 40 CONTINUE >*/ +#line 95 "" +/* L40: */ +#line 95 "" + } +/*< Z = 0 >*/ +#line 96 "" + *z__ = 0; +/*< PROFIT = 0 >*/ +#line 97 "" + profit = 0; +/*< LOLD = N >*/ +#line 98 "" + lold = *n; +/*< II = 1 >*/ +#line 99 "" + ii = 1; +/*< GO TO 170 >*/ +#line 100 "" + goto L170; +/*< 50 Z = IP >*/ +#line 101 "" +L50: +#line 101 "" + *z__ = ip; +/*< DO 60 J=1,LL >*/ +#line 102 "" + i__1 = ll; +#line 102 "" + for (j = 1; j <= i__1; ++j) { +/*< X(J) = 1 >*/ +#line 103 "" + x[j] = 1; +/*< 60 CONTINUE >*/ +#line 104 "" +/* L60: */ +#line 104 "" + } +/*< NN = LL + 1 >*/ +#line 105 "" + nn = ll + 1; +/*< DO 70 J=NN,N >*/ +#line 106 "" + i__1 = *n; +#line 106 "" + for (j = nn; j <= i__1; ++j) { +/*< X(J) = 0 >*/ +#line 107 "" + x[j] = 0; +/*< 70 CONTINUE >*/ +#line 108 "" +/* L70: */ +#line 108 "" + } +/*< RETURN >*/ +#line 109 "" + return 0; +/* TRY TO INSERT THE II-TH ITEM INTO THE CURRENT SOLUTION. */ +/*< 80 IF ( W(II) .LE. CH ) GO TO 90 >*/ +#line 111 "" +L80: +#line 111 "" + if (w[ii] <= ch) { +#line 111 "" + goto L90; +#line 111 "" + } +/*< II1 = II + 1 >*/ +#line 112 "" + ii1 = ii + 1; +/*< IF ( Z .GE. CH*P(II1)/W(II1) + PROFIT ) GO TO 280 >*/ +#line 113 "" + if (*z__ >= ch * p[ii1] / w[ii1] + profit) { +#line 113 "" + goto L280; +#line 113 "" + } +/*< II = II1 >*/ +#line 114 "" + ii = ii1; +/*< GO TO 80 >*/ +#line 115 "" + goto L80; +/* BUILD A NEW CURRENT SOLUTION. */ +/*< 90 IP = PSIGN(II) >*/ +#line 117 "" +L90: +#line 117 "" + ip = psign[ii]; +/*< CHS = CH - WSIGN(II) >*/ +#line 118 "" + chs = ch - wsign[ii]; +/*< IN = ZSIGN(II) >*/ +#line 119 "" + in = zsign[ii]; +/*< DO 100 LL=IN,N >*/ +#line 120 "" + i__1 = *n; +#line 120 "" + for (ll = in; ll <= i__1; ++ll) { +/*< IF ( W(LL) .GT. CHS ) GO TO 160 >*/ +#line 121 "" + if (w[ll] > chs) { +#line 121 "" + goto L160; +#line 121 "" + } +/*< IP = IP + P(LL) >*/ +#line 122 "" + ip += p[ll]; +/*< CHS = CHS - W(LL) >*/ +#line 123 "" + chs -= w[ll]; +/*< 100 CONTINUE >*/ +#line 124 "" +/* L100: */ +#line 124 "" + } +/*< LL = N >*/ +#line 125 "" + ll = *n; +/*< 110 IF ( Z .GE. IP + PROFIT ) GO TO 280 >*/ +#line 126 "" +L110: +#line 126 "" + if (*z__ >= ip + profit) { +#line 126 "" + goto L280; +#line 126 "" + } +/*< Z = IP + PROFIT >*/ +#line 127 "" + *z__ = ip + profit; +/*< NN = II - 1 >*/ +#line 128 "" + nn = ii - 1; +/*< DO 120 J=1,NN >*/ +#line 129 "" + i__1 = nn; +#line 129 "" + for (j = 1; j <= i__1; ++j) { +/*< X(J) = XX(J) >*/ +#line 130 "" + x[j] = xx[j]; +/*< 120 CONTINUE >*/ +#line 131 "" +/* L120: */ +#line 131 "" + } +/*< DO 130 J=II,LL >*/ +#line 132 "" + i__1 = ll; +#line 132 "" + for (j = ii; j <= i__1; ++j) { +/*< X(J) = 1 >*/ +#line 133 "" + x[j] = 1; +/*< 130 CONTINUE >*/ +#line 134 "" +/* L130: */ +#line 134 "" + } +/*< IF ( LL .EQ. N ) GO TO 150 >*/ +#line 135 "" + if (ll == *n) { +#line 135 "" + goto L150; +#line 135 "" + } +/*< NN = LL + 1 >*/ +#line 136 "" + nn = ll + 1; +/*< DO 140 J=NN,N >*/ +#line 137 "" + i__1 = *n; +#line 137 "" + for (j = nn; j <= i__1; ++j) { +/*< X(J) = 0 >*/ +#line 138 "" + x[j] = 0; +/*< 140 CONTINUE >*/ +#line 139 "" +/* L140: */ +#line 139 "" + } +/*< 150 IF ( Z .NE. LIM ) GO TO 280 >*/ +#line 140 "" +L150: +#line 140 "" + if (*z__ != lim) { +#line 140 "" + goto L280; +#line 140 "" + } +/*< RETURN >*/ +#line 141 "" + return 0; +/*< 160 IU = CHS*P(LL)/W(LL) >*/ +#line 142 "" +L160: +#line 142 "" + iu = chs * p[ll] / w[ll]; +/*< LL = LL - 1 >*/ +#line 143 "" + --ll; +/*< IF ( IU .EQ. 0 ) GO TO 110 >*/ +#line 144 "" + if (iu == 0) { +#line 144 "" + goto L110; +#line 144 "" + } +/*< IF ( Z .GE. PROFIT + IP + IU ) GO TO 280 >*/ +#line 145 "" + if (*z__ >= profit + ip + iu) { +#line 145 "" + goto L280; +#line 145 "" + } +/* SAVE THE CURRENT SOLUTION. */ +/*< 170 WSIGN(II) = CH - CHS >*/ +#line 147 "" +L170: +#line 147 "" + wsign[ii] = ch - chs; +/*< PSIGN(II) = IP >*/ +#line 148 "" + psign[ii] = ip; +/*< ZSIGN(II) = LL + 1 >*/ +#line 149 "" + zsign[ii] = ll + 1; +/*< XX(II) = 1 >*/ +#line 150 "" + xx[ii] = 1; +/*< NN = LL - 1 >*/ +#line 151 "" + nn = ll - 1; +/*< IF ( NN .LT. II) GO TO 190 >*/ +#line 152 "" + if (nn < ii) { +#line 152 "" + goto L190; +#line 152 "" + } +/*< DO 180 J=II,NN >*/ +#line 153 "" + i__1 = nn; +#line 153 "" + for (j = ii; j <= i__1; ++j) { +/*< WSIGN(J+1) = WSIGN(J) - W(J) >*/ +#line 154 "" + wsign[j + 1] = wsign[j] - w[j]; +/*< PSIGN(J+1) = PSIGN(J) - P(J) >*/ +#line 155 "" + psign[j + 1] = psign[j] - p[j]; +/*< ZSIGN(J+1) = LL + 1 >*/ +#line 156 "" + zsign[j + 1] = ll + 1; +/*< XX(J+1) = 1 >*/ +#line 157 "" + xx[j + 1] = 1; +/*< 180 CONTINUE >*/ +#line 158 "" +/* L180: */ +#line 158 "" + } +/*< 190 J1 = LL + 1 >*/ +#line 159 "" +L190: +#line 159 "" + j1 = ll + 1; +/*< DO 200 J=J1,LOLD >*/ +#line 160 "" + i__1 = lold; +#line 160 "" + for (j = j1; j <= i__1; ++j) { +/*< WSIGN(J) = 0 >*/ +#line 161 "" + wsign[j] = 0; +/*< PSIGN(J) = 0 >*/ +#line 162 "" + psign[j] = 0; +/*< ZSIGN(J) = J >*/ +#line 163 "" + zsign[j] = j; +/*< 200 CONTINUE >*/ +#line 164 "" +/* L200: */ +#line 164 "" + } +/*< LOLD = LL >*/ +#line 165 "" + lold = ll; +/*< CH = CHS >*/ +#line 166 "" + ch = chs; +/*< PROFIT = PROFIT + IP >*/ +#line 167 "" + profit += ip; +/*< IF ( LL - (N - 2) ) 240, 220, 210 >*/ +#line 168 "" + if ((i__1 = ll - (*n - 2)) < 0) { +#line 168 "" + goto L240; +#line 168 "" + } else if (i__1 == 0) { +#line 168 "" + goto L220; +#line 168 "" + } else { +#line 168 "" + goto L210; +#line 168 "" + } +/*< 210 II = N >*/ +#line 169 "" +L210: +#line 169 "" + ii = *n; +/*< GO TO 250 >*/ +#line 170 "" + goto L250; +/*< 220 IF ( CH .LT. W(N) ) GO TO 230 >*/ +#line 171 "" +L220: +#line 171 "" + if (ch < w[*n]) { +#line 171 "" + goto L230; +#line 171 "" + } +/*< CH = CH - W(N) >*/ +#line 172 "" + ch -= w[*n]; +/*< PROFIT = PROFIT + P(N) >*/ +#line 173 "" + profit += p[*n]; +/*< XX(N) = 1 >*/ +#line 174 "" + xx[*n] = 1; +/*< 230 II = N - 1 >*/ +#line 175 "" +L230: +#line 175 "" + ii = *n - 1; +/*< GO TO 250 >*/ +#line 176 "" + goto L250; +/*< 240 II = LL + 2 >*/ +#line 177 "" +L240: +#line 177 "" + ii = ll + 2; +/*< IF ( CH .GE. MIN(II-1) ) GO TO 80 >*/ +#line 178 "" + if (ch >= min__[ii - 1]) { +#line 178 "" + goto L80; +#line 178 "" + } +/* SAVE THE CURRENT OPTIMAL SOLUTION. */ +/*< 250 IF ( Z .GE. PROFIT ) GO TO 270 >*/ +#line 180 "" +L250: +#line 180 "" + if (*z__ >= profit) { +#line 180 "" + goto L270; +#line 180 "" + } +/*< Z = PROFIT >*/ +#line 181 "" + *z__ = profit; +/*< DO 260 J=1,N >*/ +#line 182 "" + i__1 = *n; +#line 182 "" + for (j = 1; j <= i__1; ++j) { +/*< X(J) = XX(J) >*/ +#line 183 "" + x[j] = xx[j]; +/*< 260 CONTINUE >*/ +#line 184 "" +/* L260: */ +#line 184 "" + } +/*< IF ( Z .EQ. LIM ) RETURN >*/ +#line 185 "" + if (*z__ == lim) { +#line 185 "" + return 0; +#line 185 "" + } +/*< 270 IF ( XX(N) .EQ. 0 ) GO TO 280 >*/ +#line 186 "" +L270: +#line 186 "" + if (xx[*n] == 0) { +#line 186 "" + goto L280; +#line 186 "" + } +/*< XX(N) = 0 >*/ +#line 187 "" + xx[*n] = 0; +/*< CH = CH + W(N) >*/ +#line 188 "" + ch += w[*n]; +/*< PROFIT = PROFIT - P(N) >*/ +#line 189 "" + profit -= p[*n]; +/* BACKTRACK. */ +/*< 280 NN = II - 1 >*/ +#line 191 "" +L280: +#line 191 "" + nn = ii - 1; +/*< IF ( NN .EQ. 0 ) RETURN >*/ +#line 192 "" + if (nn == 0) { +#line 192 "" + return 0; +#line 192 "" + } +/*< DO 290 J=1,NN >*/ +#line 193 "" + i__1 = nn; +#line 193 "" + for (j = 1; j <= i__1; ++j) { +/*< KK = II - J >*/ +#line 194 "" + kk = ii - j; +/*< IF ( XX(KK) .EQ. 1 ) GO TO 300 >*/ +#line 195 "" + if (xx[kk] == 1) { +#line 195 "" + goto L300; +#line 195 "" + } +/*< 290 CONTINUE >*/ +#line 196 "" +/* L290: */ +#line 196 "" + } +/*< RETURN >*/ +#line 197 "" + return 0; +/*< 300 R = CH >*/ +#line 198 "" +L300: +#line 198 "" + r__ = ch; +/*< CH = CH + W(KK) >*/ +#line 199 "" + ch += w[kk]; +/*< PROFIT = PROFIT - P(KK) >*/ +#line 200 "" + profit -= p[kk]; +/*< XX(KK) = 0 >*/ +#line 201 "" + xx[kk] = 0; +/*< IF ( R .LT. MIN(KK) ) GO TO 310 >*/ +#line 202 "" + if (r__ < min__[kk]) { +#line 202 "" + goto L310; +#line 202 "" + } +/*< II = KK + 1 >*/ +#line 203 "" + ii = kk + 1; +/*< GO TO 80 >*/ +#line 204 "" + goto L80; +/*< 310 NN = KK + 1 >*/ +#line 205 "" +L310: +#line 205 "" + nn = kk + 1; +/*< II = KK >*/ +#line 206 "" + ii = kk; +/* TRY TO SUBSTITUTE THE NN-TH ITEM FOR THE KK-TH. */ +/*< 320 IF ( Z .GE. PROFIT + CH*P(NN)/W(NN) ) GO TO 280 >*/ +#line 208 "" +L320: +#line 208 "" + if (*z__ >= profit + ch * p[nn] / w[nn]) { +#line 208 "" + goto L280; +#line 208 "" + } +/*< DIFF = W(NN) - W(KK) >*/ +#line 209 "" + diff = w[nn] - w[kk]; +/*< IF ( DIFF ) 370, 330, 340 >*/ +#line 210 "" + if (diff < 0) { +#line 210 "" + goto L370; +#line 210 "" + } else if (diff == 0) { +#line 210 "" + goto L330; +#line 210 "" + } else { +#line 210 "" + goto L340; +#line 210 "" + } +/*< 330 NN = NN + 1 >*/ +#line 211 "" +L330: +#line 211 "" + ++nn; +/*< GO TO 320 >*/ +#line 212 "" + goto L320; +/*< 340 IF ( DIFF .GT. R ) GO TO 330 >*/ +#line 213 "" +L340: +#line 213 "" + if (diff > r__) { +#line 213 "" + goto L330; +#line 213 "" + } +/*< IF ( Z .GE. PROFIT + P(NN) ) GO TO 330 >*/ +#line 214 "" + if (*z__ >= profit + p[nn]) { +#line 214 "" + goto L330; +#line 214 "" + } +/*< Z = PROFIT + P(NN) >*/ +#line 215 "" + *z__ = profit + p[nn]; +/*< DO 350 J=1,KK >*/ +#line 216 "" + i__1 = kk; +#line 216 "" + for (j = 1; j <= i__1; ++j) { +/*< X(J) = XX(J) >*/ +#line 217 "" + x[j] = xx[j]; +/*< 350 CONTINUE >*/ +#line 218 "" +/* L350: */ +#line 218 "" + } +/*< JJ = KK + 1 >*/ +#line 219 "" + jj = kk + 1; +/*< DO 360 J=JJ,N >*/ +#line 220 "" + i__1 = *n; +#line 220 "" + for (j = jj; j <= i__1; ++j) { +/*< X(J) = 0 >*/ +#line 221 "" + x[j] = 0; +/*< 360 CONTINUE >*/ +#line 222 "" +/* L360: */ +#line 222 "" + } +/*< X(NN) = 1 >*/ +#line 223 "" + x[nn] = 1; +/*< IF ( Z .EQ. LIM ) RETURN >*/ +#line 224 "" + if (*z__ == lim) { +#line 224 "" + return 0; +#line 224 "" + } +/*< R = R - DIFF >*/ +#line 225 "" + r__ -= diff; +/*< KK = NN >*/ +#line 226 "" + kk = nn; +/*< NN = NN + 1 >*/ +#line 227 "" + ++nn; +/*< GO TO 320 >*/ +#line 228 "" + goto L320; +/*< 370 T = R - DIFF >*/ +#line 229 "" +L370: +#line 229 "" + t = r__ - diff; +/*< IF ( T .LT. MIN(NN) ) GO TO 330 >*/ +#line 230 "" + if (t < min__[nn]) { +#line 230 "" + goto L330; +#line 230 "" + } +/*< IF ( Z .GE. PROFIT + P(NN) + T*P(NN+1)/W(NN+1)) GO TO 280 >*/ +#line 231 "" + if (*z__ >= profit + p[nn] + t * p[nn + 1] / w[nn + 1]) { +#line 231 "" + goto L280; +#line 231 "" + } +/*< CH = CH - W(NN) >*/ +#line 232 "" + ch -= w[nn]; +/*< PROFIT = PROFIT + P(NN) >*/ +#line 233 "" + profit += p[nn]; +/*< XX(NN) = 1 >*/ +#line 234 "" + xx[nn] = 1; +/*< II = NN + 1 >*/ +#line 235 "" + ii = nn + 1; +/*< WSIGN(NN) = W(NN) >*/ +#line 236 "" + wsign[nn] = w[nn]; +/*< PSIGN(NN) = P(NN) >*/ +#line 237 "" + psign[nn] = p[nn]; +/*< ZSIGN(NN) = II >*/ +#line 238 "" + zsign[nn] = ii; +/*< N1 = NN + 1 >*/ +#line 239 "" + n1 = nn + 1; +/*< DO 380 J=N1,LOLD >*/ +#line 240 "" + i__1 = lold; +#line 240 "" + for (j = n1; j <= i__1; ++j) { +/*< WSIGN(J) = 0 >*/ +#line 241 "" + wsign[j] = 0; +/*< PSIGN(J) = 0 >*/ +#line 242 "" + psign[j] = 0; +/*< ZSIGN(J) = J >*/ +#line 243 "" + zsign[j] = j; +/*< 380 CONTINUE >*/ +#line 244 "" +/* L380: */ +#line 244 "" + } +/*< LOLD = NN >*/ +#line 245 "" + lold = nn; +/*< GO TO 80 >*/ +#line 246 "" + goto L80; +/*< END >*/ +} /* mt1_ */ + +/*< SUBROUTINE CHMT1(N,P,W,C,Z,JDIM) >*/ +#if 1 /* by mao */ +static +#endif +/* Subroutine */ int chmt1_(integer *n, integer *p, integer *w, integer *c__, + integer *z__, integer *jdim) +{ + /* System generated locals */ + integer i__1; + + /* Local variables */ + static integer j; + static real r__, rr; + static integer jsw; + + +/* CHECK THE INPUT DATA. */ + +/*< INTEGER P(JDIM),W(JDIM),C,Z >*/ +/*< IF ( N .GE. 2 .AND. N .LE. JDIM - 1 ) GO TO 10 >*/ +#line 253 "" + /* Parameter adjustments */ +#line 253 "" + --w; +#line 253 "" + --p; +#line 253 "" + +#line 253 "" + /* Function Body */ +#line 253 "" + if (*n >= 2 && *n <= *jdim - 1) { +#line 253 "" + goto L10; +#line 253 "" + } +/*< Z = - 1 >*/ +#line 254 "" + *z__ = -1; +/*< RETURN >*/ +#line 255 "" + return 0; +/*< 10 IF ( C .GT. 0 ) GO TO 30 >*/ +#line 256 "" +L10: +#line 256 "" + if (*c__ > 0) { +#line 256 "" + goto L30; +#line 256 "" + } +/*< 20 Z = - 2 >*/ +#line 257 "" +L20: +#line 257 "" + *z__ = -2; +/*< RETURN >*/ +#line 258 "" + return 0; +/*< 30 JSW = 0 >*/ +#line 259 "" +L30: +#line 259 "" + jsw = 0; +/*< RR = FLOAT(P(1))/FLOAT(W(1)) >*/ +#line 260 "" + rr = (real) p[1] / (real) w[1]; +/*< DO 50 J=1,N >*/ +#line 261 "" + i__1 = *n; +#line 261 "" + for (j = 1; j <= i__1; ++j) { +/*< R = RR >*/ +#line 262 "" + r__ = rr; +/*< IF ( P(J) .LE. 0 ) GO TO 20 >*/ +#line 263 "" + if (p[j] <= 0) { +#line 263 "" + goto L20; +#line 263 "" + } +/*< IF ( W(J) .LE. 0 ) GO TO 20 >*/ +#line 264 "" + if (w[j] <= 0) { +#line 264 "" + goto L20; +#line 264 "" + } +/*< JSW = JSW + W(J) >*/ +#line 265 "" + jsw += w[j]; +/*< IF ( W(J) .LE. C ) GO TO 40 >*/ +#line 266 "" + if (w[j] <= *c__) { +#line 266 "" + goto L40; +#line 266 "" + } +/*< Z = - 3 >*/ +#line 267 "" + *z__ = -3; +/*< RETURN >*/ +#line 268 "" + return 0; +/*< 40 RR = FLOAT(P(J))/FLOAT(W(J)) >*/ +#line 269 "" +L40: +#line 269 "" + rr = (real) p[j] / (real) w[j]; +/*< IF ( RR .LE. R ) GO TO 50 >*/ +#line 270 "" + if (rr <= r__) { +#line 270 "" + goto L50; +#line 270 "" + } +/*< Z = - 5 >*/ +#line 271 "" + *z__ = -5; +/*< RETURN >*/ +#line 272 "" + return 0; +/*< 50 CONTINUE >*/ +#line 273 "" +L50: +#line 273 "" + ; +#line 273 "" + } +/*< IF ( JSW .GT. C ) RETURN >*/ +#line 274 "" + if (jsw > *c__) { +#line 274 "" + return 0; +#line 274 "" + } +/*< Z = - 4 >*/ +#line 275 "" + *z__ = -4; +/*< RETURN >*/ +#line 276 "" + return 0; +/*< END >*/ +} /* chmt1_ */ + +#if 1 /* by mao */ +int mt1(int n, int p[], int w[], int c, int x[], int jck, int xx[], + int min[], int psign[], int wsign[], int zsign[]) +{ /* solve 0-1 knapsack problem */ + int z, jdim = n+1, j, s1, s2; + mt1_(&n, &p[1], &w[1], &c, &z, &x[1], &jdim, &jck, &xx[1], + &min[1], &psign[1], &wsign[1], &zsign[1]); + /* check solution found */ + s1 = s2 = 0; + for (j = 1; j <= n; j++) + { xassert(x[j] == 0 || x[j] == 1); + if (x[j]) + s1 += p[j], s2 += w[j]; + } + xassert(s1 == z); + xassert(s2 <= c); + return z; +} +#endif + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/mt1.f b/test/monniaux/glpk-4.65/src/misc/mt1.f new file mode 100644 index 00000000..82cc4a1b --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/mt1.f @@ -0,0 +1,277 @@ + SUBROUTINE MT1(N,P,W,C,Z,X,JDIM,JCK,XX,MIN,PSIGN,WSIGN,ZSIGN) +C +C THIS SUBROUTINE SOLVES THE 0-1 SINGLE KNAPSACK PROBLEM +C +C MAXIMIZE Z = P(1)*X(1) + ... + P(N)*X(N) +C +C SUBJECT TO: W(1)*X(1) + ... + W(N)*X(N) .LE. C , +C X(J) = 0 OR 1 FOR J=1,...,N. +C +C THE PROGRAM IS INCLUDED IN THE VOLUME +C S. MARTELLO, P. TOTH, "KNAPSACK PROBLEMS: ALGORITHMS +C AND COMPUTER IMPLEMENTATIONS", JOHN WILEY, 1990 +C AND IMPLEMENTS THE BRANCH-AND-BOUND ALGORITHM DESCRIBED IN +C SECTION 2.5.2 . +C THE PROGRAM DERIVES FROM AN EARLIER CODE PRESENTED IN +C S. MARTELLO, P. TOTH, "ALGORITHM FOR THE SOLUTION OF THE 0-1 SINGLE +C KNAPSACK PROBLEM", COMPUTING, 1978. +C +C THE INPUT PROBLEM MUST SATISFY THE CONDITIONS +C +C 1) 2 .LE. N .LE. JDIM - 1 ; +C 2) P(J), W(J), C POSITIVE INTEGERS; +C 3) MAX (W(J)) .LE. C ; +C 4) W(1) + ... + W(N) .GT. C ; +C 5) P(J)/W(J) .GE. P(J+1)/W(J+1) FOR J=1,...,N-1. +C +C MT1 CALLS 1 PROCEDURE: CHMT1. +C +C THE PROGRAM IS COMPLETELY SELF-CONTAINED AND COMMUNICATION TO IT IS +C ACHIEVED SOLELY THROUGH THE PARAMETER LIST OF MT1. +C NO MACHINE-DEPENDENT CONSTANT IS USED. +C THE PROGRAM IS WRITTEN IN 1967 AMERICAN NATIONAL STANDARD FORTRAN +C AND IS ACCEPTED BY THE PFORT VERIFIER (PFORT IS THE PORTABLE +C SUBSET OF ANSI DEFINED BY THE ASSOCIATION FOR COMPUTING MACHINERY). +C THE PROGRAM HAS BEEN TESTED ON A DIGITAL VAX 11/780 AND AN H.P. +C 9000/840. +C +C MT1 NEEDS 8 ARRAYS ( P , W , X , XX , MIN , PSIGN , WSIGN +C AND ZSIGN ) OF LENGTH AT LEAST N + 1 . +C +C MEANING OF THE INPUT PARAMETERS: +C N = NUMBER OF ITEMS; +C P(J) = PROFIT OF ITEM J (J=1,...,N); +C W(J) = WEIGHT OF ITEM J (J=1,...,N); +C C = CAPACITY OF THE KNAPSACK; +C JDIM = DIMENSION OF THE 8 ARRAYS; +C JCK = 1 IF CHECK ON THE INPUT DATA IS DESIRED, +C = 0 OTHERWISE. +C +C MEANING OF THE OUTPUT PARAMETERS: +C Z = VALUE OF THE OPTIMAL SOLUTION IF Z .GT. 0 , +C = ERROR IN THE INPUT DATA (WHEN JCK=1) IF Z .LT. 0 : CONDI- +C TION - Z IS VIOLATED; +C X(J) = 1 IF ITEM J IS IN THE OPTIMAL SOLUTION, +C = 0 OTHERWISE. +C +C ARRAYS XX, MIN, PSIGN, WSIGN AND ZSIGN ARE DUMMY. +C +C ALL THE PARAMETERS ARE INTEGER. ON RETURN OF MT1 ALL THE INPUT +C PARAMETERS ARE UNCHANGED. +C + INTEGER P(JDIM),W(JDIM),X(JDIM),C,Z + INTEGER XX(JDIM),MIN(JDIM),PSIGN(JDIM),WSIGN(JDIM),ZSIGN(JDIM) + INTEGER CH,CHS,DIFF,PROFIT,R,T + Z = 0 + IF ( JCK .EQ. 1 ) CALL CHMT1(N,P,W,C,Z,JDIM) + IF ( Z .LT. 0 ) RETURN +C INITIALIZE. + CH = C + IP = 0 + CHS = CH + DO 10 LL=1,N + IF ( W(LL) .GT. CHS ) GO TO 20 + IP = IP + P(LL) + CHS = CHS - W(LL) + 10 CONTINUE + 20 LL = LL - 1 + IF ( CHS .EQ. 0 ) GO TO 50 + P(N+1) = 0 + W(N+1) = CH + 1 + LIM = IP + CHS*P(LL+2)/W(LL+2) + A = W(LL+1) - CHS + B = IP + P(LL+1) + LIM1 = B - A*FLOAT(P(LL))/FLOAT(W(LL)) + IF ( LIM1 .GT. LIM ) LIM = LIM1 + MINK = CH + 1 + MIN(N) = MINK + DO 30 J=2,N + KK = N + 2 - J + IF ( W(KK) .LT. MINK ) MINK = W(KK) + MIN(KK-1) = MINK + 30 CONTINUE + DO 40 J=1,N + XX(J) = 0 + 40 CONTINUE + Z = 0 + PROFIT = 0 + LOLD = N + II = 1 + GO TO 170 + 50 Z = IP + DO 60 J=1,LL + X(J) = 1 + 60 CONTINUE + NN = LL + 1 + DO 70 J=NN,N + X(J) = 0 + 70 CONTINUE + RETURN +C TRY TO INSERT THE II-TH ITEM INTO THE CURRENT SOLUTION. + 80 IF ( W(II) .LE. CH ) GO TO 90 + II1 = II + 1 + IF ( Z .GE. CH*P(II1)/W(II1) + PROFIT ) GO TO 280 + II = II1 + GO TO 80 +C BUILD A NEW CURRENT SOLUTION. + 90 IP = PSIGN(II) + CHS = CH - WSIGN(II) + IN = ZSIGN(II) + DO 100 LL=IN,N + IF ( W(LL) .GT. CHS ) GO TO 160 + IP = IP + P(LL) + CHS = CHS - W(LL) + 100 CONTINUE + LL = N + 110 IF ( Z .GE. IP + PROFIT ) GO TO 280 + Z = IP + PROFIT + NN = II - 1 + DO 120 J=1,NN + X(J) = XX(J) + 120 CONTINUE + DO 130 J=II,LL + X(J) = 1 + 130 CONTINUE + IF ( LL .EQ. N ) GO TO 150 + NN = LL + 1 + DO 140 J=NN,N + X(J) = 0 + 140 CONTINUE + 150 IF ( Z .NE. LIM ) GO TO 280 + RETURN + 160 IU = CHS*P(LL)/W(LL) + LL = LL - 1 + IF ( IU .EQ. 0 ) GO TO 110 + IF ( Z .GE. PROFIT + IP + IU ) GO TO 280 +C SAVE THE CURRENT SOLUTION. + 170 WSIGN(II) = CH - CHS + PSIGN(II) = IP + ZSIGN(II) = LL + 1 + XX(II) = 1 + NN = LL - 1 + IF ( NN .LT. II) GO TO 190 + DO 180 J=II,NN + WSIGN(J+1) = WSIGN(J) - W(J) + PSIGN(J+1) = PSIGN(J) - P(J) + ZSIGN(J+1) = LL + 1 + XX(J+1) = 1 + 180 CONTINUE + 190 J1 = LL + 1 + DO 200 J=J1,LOLD + WSIGN(J) = 0 + PSIGN(J) = 0 + ZSIGN(J) = J + 200 CONTINUE + LOLD = LL + CH = CHS + PROFIT = PROFIT + IP + IF ( LL - (N - 2) ) 240, 220, 210 + 210 II = N + GO TO 250 + 220 IF ( CH .LT. W(N) ) GO TO 230 + CH = CH - W(N) + PROFIT = PROFIT + P(N) + XX(N) = 1 + 230 II = N - 1 + GO TO 250 + 240 II = LL + 2 + IF ( CH .GE. MIN(II-1) ) GO TO 80 +C SAVE THE CURRENT OPTIMAL SOLUTION. + 250 IF ( Z .GE. PROFIT ) GO TO 270 + Z = PROFIT + DO 260 J=1,N + X(J) = XX(J) + 260 CONTINUE + IF ( Z .EQ. LIM ) RETURN + 270 IF ( XX(N) .EQ. 0 ) GO TO 280 + XX(N) = 0 + CH = CH + W(N) + PROFIT = PROFIT - P(N) +C BACKTRACK. + 280 NN = II - 1 + IF ( NN .EQ. 0 ) RETURN + DO 290 J=1,NN + KK = II - J + IF ( XX(KK) .EQ. 1 ) GO TO 300 + 290 CONTINUE + RETURN + 300 R = CH + CH = CH + W(KK) + PROFIT = PROFIT - P(KK) + XX(KK) = 0 + IF ( R .LT. MIN(KK) ) GO TO 310 + II = KK + 1 + GO TO 80 + 310 NN = KK + 1 + II = KK +C TRY TO SUBSTITUTE THE NN-TH ITEM FOR THE KK-TH. + 320 IF ( Z .GE. PROFIT + CH*P(NN)/W(NN) ) GO TO 280 + DIFF = W(NN) - W(KK) + IF ( DIFF ) 370, 330, 340 + 330 NN = NN + 1 + GO TO 320 + 340 IF ( DIFF .GT. R ) GO TO 330 + IF ( Z .GE. PROFIT + P(NN) ) GO TO 330 + Z = PROFIT + P(NN) + DO 350 J=1,KK + X(J) = XX(J) + 350 CONTINUE + JJ = KK + 1 + DO 360 J=JJ,N + X(J) = 0 + 360 CONTINUE + X(NN) = 1 + IF ( Z .EQ. LIM ) RETURN + R = R - DIFF + KK = NN + NN = NN + 1 + GO TO 320 + 370 T = R - DIFF + IF ( T .LT. MIN(NN) ) GO TO 330 + IF ( Z .GE. PROFIT + P(NN) + T*P(NN+1)/W(NN+1)) GO TO 280 + CH = CH - W(NN) + PROFIT = PROFIT + P(NN) + XX(NN) = 1 + II = NN + 1 + WSIGN(NN) = W(NN) + PSIGN(NN) = P(NN) + ZSIGN(NN) = II + N1 = NN + 1 + DO 380 J=N1,LOLD + WSIGN(J) = 0 + PSIGN(J) = 0 + ZSIGN(J) = J + 380 CONTINUE + LOLD = NN + GO TO 80 + END + SUBROUTINE CHMT1(N,P,W,C,Z,JDIM) +C +C CHECK THE INPUT DATA. +C + INTEGER P(JDIM),W(JDIM),C,Z + IF ( N .GE. 2 .AND. N .LE. JDIM - 1 ) GO TO 10 + Z = - 1 + RETURN + 10 IF ( C .GT. 0 ) GO TO 30 + 20 Z = - 2 + RETURN + 30 JSW = 0 + RR = FLOAT(P(1))/FLOAT(W(1)) + DO 50 J=1,N + R = RR + IF ( P(J) .LE. 0 ) GO TO 20 + IF ( W(J) .LE. 0 ) GO TO 20 + JSW = JSW + W(J) + IF ( W(J) .LE. C ) GO TO 40 + Z = - 3 + RETURN + 40 RR = FLOAT(P(J))/FLOAT(W(J)) + IF ( RR .LE. R ) GO TO 50 + Z = - 5 + RETURN + 50 CONTINUE + IF ( JSW .GT. C ) RETURN + Z = - 4 + RETURN + END diff --git a/test/monniaux/glpk-4.65/src/misc/mt1.h b/test/monniaux/glpk-4.65/src/misc/mt1.h new file mode 100644 index 00000000..cceebba9 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/mt1.h @@ -0,0 +1,34 @@ +/* mt1.h (0-1 knapsack problem; Martello & Toth algorithm) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2017-2018 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#ifndef MT1_H +#define MT1_H + +#define mt1 _glp_mt1 +int mt1(int n, int p[], int w[], int c, int x[], int jck, int xx[], + int min[], int psign[], int wsign[], int zsign[]); +/* solve 0-1 single knapsack problem */ + +#endif + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/mygmp.c b/test/monniaux/glpk-4.65/src/misc/mygmp.c new file mode 100644 index 00000000..89d053ae --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/mygmp.c @@ -0,0 +1,1162 @@ +/* mygmp.c (integer and rational arithmetic) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2008-2015 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#include "mygmp.h" + +#ifdef HAVE_GMP /* use GNU MP library */ + +/* nothing is needed */ + +#else /* use GLPK MP module */ + +#include "bignum.h" +#include "dmp.h" +#include "env.h" + +#define gmp_pool env->gmp_pool +#define gmp_size env->gmp_size +#define gmp_work env->gmp_work + +void *gmp_get_atom(int size) +{ ENV *env = get_env_ptr(); + if (gmp_pool == NULL) + gmp_pool = dmp_create_pool(); + return dmp_get_atom(gmp_pool, size); +} + +void gmp_free_atom(void *ptr, int size) +{ ENV *env = get_env_ptr(); + xassert(gmp_pool != NULL); + dmp_free_atom(gmp_pool, ptr, size); + return; +} + +int gmp_pool_count(void) +{ ENV *env = get_env_ptr(); + if (gmp_pool == NULL) + return 0; + else + return dmp_in_use(gmp_pool); +} + +unsigned short *gmp_get_work(int size) +{ ENV *env = get_env_ptr(); + xassert(size > 0); + if (gmp_size < size) + { if (gmp_size == 0) + { xassert(gmp_work == NULL); + gmp_size = 100; + } + else + { xassert(gmp_work != NULL); + xfree(gmp_work); + } + while (gmp_size < size) + gmp_size += gmp_size; + gmp_work = xcalloc(gmp_size, sizeof(unsigned short)); + } + return gmp_work; +} + +void gmp_free_mem(void) +{ ENV *env = get_env_ptr(); + if (gmp_pool != NULL) + dmp_delete_pool(gmp_pool); + if (gmp_work != NULL) + xfree(gmp_work); + gmp_pool = NULL; + gmp_size = 0; + gmp_work = NULL; + return; +} + +/*--------------------------------------------------------------------*/ + +mpz_t _mpz_init(void) +{ /* initialize x and set its value to 0 */ + mpz_t x; + x = gmp_get_atom(sizeof(struct mpz)); + x->val = 0; + x->ptr = NULL; + return x; +} + +void mpz_clear(mpz_t x) +{ /* free the space occupied by x */ + mpz_set_si(x, 0); + xassert(x->ptr == NULL); + /* free the number descriptor */ + gmp_free_atom(x, sizeof(struct mpz)); + return; +} + +void mpz_set(mpz_t z, mpz_t x) +{ /* set the value of z from x */ + struct mpz_seg *e, *ee, *es; + if (z != x) + { mpz_set_si(z, 0); + z->val = x->val; + xassert(z->ptr == NULL); + for (e = x->ptr, es = NULL; e != NULL; e = e->next) + { ee = gmp_get_atom(sizeof(struct mpz_seg)); + memcpy(ee->d, e->d, 12); + ee->next = NULL; + if (z->ptr == NULL) + z->ptr = ee; + else + es->next = ee; + es = ee; + } + } + return; +} + +void mpz_set_si(mpz_t x, int val) +{ /* set the value of x to val */ + struct mpz_seg *e; + /* free existing segments, if any */ + while (x->ptr != NULL) + { e = x->ptr; + x->ptr = e->next; + gmp_free_atom(e, sizeof(struct mpz_seg)); + } + /* assign new value */ + if (val == 0x80000000) + { /* long format is needed */ + x->val = -1; + x->ptr = e = gmp_get_atom(sizeof(struct mpz_seg)); + memset(e->d, 0, 12); + e->d[1] = 0x8000; + e->next = NULL; + } + else + { /* short format is enough */ + x->val = val; + } + return; +} + +double mpz_get_d(mpz_t x) +{ /* convert x to a double, truncating if necessary */ + struct mpz_seg *e; + int j; + double val, deg; + if (x->ptr == NULL) + val = (double)x->val; + else + { xassert(x->val != 0); + val = 0.0; + deg = 1.0; + for (e = x->ptr; e != NULL; e = e->next) + { for (j = 0; j <= 5; j++) + { val += deg * (double)((int)e->d[j]); + deg *= 65536.0; + } + } + if (x->val < 0) + val = - val; + } + return val; +} + +double mpz_get_d_2exp(int *exp, mpz_t x) +{ /* convert x to a double, truncating if necessary (i.e. rounding + * towards zero), and returning the exponent separately; + * the return value is in the range 0.5 <= |d| < 1 and the + * exponent is stored to *exp; d*2^exp is the (truncated) x value; + * if x is zero, the return is 0.0 and 0 is stored to *exp; + * this is similar to the standard C frexp function */ + struct mpz_seg *e; + int j, n, n1; + double val; + if (x->ptr == NULL) + val = (double)x->val, n = 0; + else + { xassert(x->val != 0); + val = 0.0, n = 0; + for (e = x->ptr; e != NULL; e = e->next) + { for (j = 0; j <= 5; j++) + { val += (double)((int)e->d[j]); + val /= 65536.0, n += 16; + } + } + if (x->val < 0) + val = - val; + } + val = frexp(val, &n1); + *exp = n + n1; + return val; +} + +void mpz_swap(mpz_t x, mpz_t y) +{ /* swap the values x and y efficiently */ + int val; + void *ptr; + val = x->val, ptr = x->ptr; + x->val = y->val, x->ptr = y->ptr; + y->val = val, y->ptr = ptr; + return; +} + +static void normalize(mpz_t x) +{ /* normalize integer x that includes removing non-significant + * (leading) zeros and converting to short format, if possible */ + struct mpz_seg *es, *e; + /* if the integer is in short format, it remains unchanged */ + if (x->ptr == NULL) + { xassert(x->val != 0x80000000); + goto done; + } + xassert(x->val == +1 || x->val == -1); + /* find the last (most significant) non-zero segment */ + es = NULL; + for (e = x->ptr; e != NULL; e = e->next) + { if (e->d[0] || e->d[1] || e->d[2] || + e->d[3] || e->d[4] || e->d[5]) + es = e; + } + /* if all segments contain zeros, the integer is zero */ + if (es == NULL) + { mpz_set_si(x, 0); + goto done; + } + /* remove non-significant (leading) zero segments */ + while (es->next != NULL) + { e = es->next; + es->next = e->next; + gmp_free_atom(e, sizeof(struct mpz_seg)); + } + /* convert the integer to short format, if possible */ + e = x->ptr; + if (e->next == NULL && e->d[1] <= 0x7FFF && + !e->d[2] && !e->d[3] && !e->d[4] && !e->d[5]) + { int val; + val = (int)e->d[0] + ((int)e->d[1] << 16); + if (x->val < 0) + val = - val; + mpz_set_si(x, val); + } +done: return; +} + +void mpz_add(mpz_t z, mpz_t x, mpz_t y) +{ /* set z to x + y */ + static struct mpz_seg zero = { { 0, 0, 0, 0, 0, 0 }, NULL }; + struct mpz_seg dumx, dumy, *ex, *ey, *ez, *es, *ee; + int k, sx, sy, sz; + unsigned int t; + /* if [x] = 0 then [z] = [y] */ + if (x->val == 0) + { xassert(x->ptr == NULL); + mpz_set(z, y); + goto done; + } + /* if [y] = 0 then [z] = [x] */ + if (y->val == 0) + { xassert(y->ptr == NULL); + mpz_set(z, x); + goto done; + } + /* special case when both [x] and [y] are in short format */ + if (x->ptr == NULL && y->ptr == NULL) + { int xval = x->val, yval = y->val, zval = x->val + y->val; + xassert(xval != 0x80000000 && yval != 0x80000000); + if (!(xval > 0 && yval > 0 && zval <= 0 || + xval < 0 && yval < 0 && zval >= 0)) + { mpz_set_si(z, zval); + goto done; + } + } + /* convert [x] to long format, if necessary */ + if (x->ptr == NULL) + { xassert(x->val != 0x80000000); + if (x->val >= 0) + { sx = +1; + t = (unsigned int)(+ x->val); + } + else + { sx = -1; + t = (unsigned int)(- x->val); + } + ex = &dumx; + ex->d[0] = (unsigned short)t; + ex->d[1] = (unsigned short)(t >> 16); + ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0; + ex->next = NULL; + } + else + { sx = x->val; + xassert(sx == +1 || sx == -1); + ex = x->ptr; + } + /* convert [y] to long format, if necessary */ + if (y->ptr == NULL) + { xassert(y->val != 0x80000000); + if (y->val >= 0) + { sy = +1; + t = (unsigned int)(+ y->val); + } + else + { sy = -1; + t = (unsigned int)(- y->val); + } + ey = &dumy; + ey->d[0] = (unsigned short)t; + ey->d[1] = (unsigned short)(t >> 16); + ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0; + ey->next = NULL; + } + else + { sy = y->val; + xassert(sy == +1 || sy == -1); + ey = y->ptr; + } + /* main fragment */ + sz = sx; + ez = es = NULL; + if (sx > 0 && sy > 0 || sx < 0 && sy < 0) + { /* [x] and [y] have identical signs -- addition */ + t = 0; + for (; ex || ey; ex = ex->next, ey = ey->next) + { if (ex == NULL) + ex = &zero; + if (ey == NULL) + ey = &zero; + ee = gmp_get_atom(sizeof(struct mpz_seg)); + for (k = 0; k <= 5; k++) + { t += (unsigned int)ex->d[k]; + t += (unsigned int)ey->d[k]; + ee->d[k] = (unsigned short)t; + t >>= 16; + } + ee->next = NULL; + if (ez == NULL) + ez = ee; + else + es->next = ee; + es = ee; + } + if (t) + { /* overflow -- one extra digit is needed */ + ee = gmp_get_atom(sizeof(struct mpz_seg)); + ee->d[0] = 1; + ee->d[1] = ee->d[2] = ee->d[3] = ee->d[4] = ee->d[5] = 0; + ee->next = NULL; + xassert(es != NULL); + es->next = ee; + } + } + else + { /* [x] and [y] have different signs -- subtraction */ + t = 1; + for (; ex || ey; ex = ex->next, ey = ey->next) + { if (ex == NULL) + ex = &zero; + if (ey == NULL) + ey = &zero; + ee = gmp_get_atom(sizeof(struct mpz_seg)); + for (k = 0; k <= 5; k++) + { t += (unsigned int)ex->d[k]; + t += (0xFFFF - (unsigned int)ey->d[k]); + ee->d[k] = (unsigned short)t; + t >>= 16; + } + ee->next = NULL; + if (ez == NULL) + ez = ee; + else + es->next = ee; + es = ee; + } + if (!t) + { /* |[x]| < |[y]| -- result in complement coding */ + sz = - sz; + t = 1; + for (ee = ez; ee != NULL; ee = ee->next) + { for (k = 0; k <= 5; k++) + { t += (0xFFFF - (unsigned int)ee->d[k]); + ee->d[k] = (unsigned short)t; + t >>= 16; + } + } + } + } + /* contruct and normalize result */ + mpz_set_si(z, 0); + z->val = sz; + z->ptr = ez; + normalize(z); +done: return; +} + +void mpz_sub(mpz_t z, mpz_t x, mpz_t y) +{ /* set z to x - y */ + if (x == y) + mpz_set_si(z, 0); + else + { y->val = - y->val; + mpz_add(z, x, y); + if (y != z) + y->val = - y->val; + } + return; +} + +void mpz_mul(mpz_t z, mpz_t x, mpz_t y) +{ /* set z to x * y */ + struct mpz_seg dumx, dumy, *ex, *ey, *es, *e; + int sx, sy, k, nx, ny, n; + unsigned int t; + unsigned short *work, *wx, *wy; + /* if [x] = 0 then [z] = 0 */ + if (x->val == 0) + { xassert(x->ptr == NULL); + mpz_set_si(z, 0); + goto done; + } + /* if [y] = 0 then [z] = 0 */ + if (y->val == 0) + { xassert(y->ptr == NULL); + mpz_set_si(z, 0); + goto done; + } + /* special case when both [x] and [y] are in short format */ + if (x->ptr == NULL && y->ptr == NULL) + { int xval = x->val, yval = y->val, sz = +1; + xassert(xval != 0x80000000 && yval != 0x80000000); + if (xval < 0) + xval = - xval, sz = - sz; + if (yval < 0) + yval = - yval, sz = - sz; + if (xval <= 0x7FFFFFFF / yval) + { mpz_set_si(z, sz * (xval * yval)); + goto done; + } + } + /* convert [x] to long format, if necessary */ + if (x->ptr == NULL) + { xassert(x->val != 0x80000000); + if (x->val >= 0) + { sx = +1; + t = (unsigned int)(+ x->val); + } + else + { sx = -1; + t = (unsigned int)(- x->val); + } + ex = &dumx; + ex->d[0] = (unsigned short)t; + ex->d[1] = (unsigned short)(t >> 16); + ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0; + ex->next = NULL; + } + else + { sx = x->val; + xassert(sx == +1 || sx == -1); + ex = x->ptr; + } + /* convert [y] to long format, if necessary */ + if (y->ptr == NULL) + { xassert(y->val != 0x80000000); + if (y->val >= 0) + { sy = +1; + t = (unsigned int)(+ y->val); + } + else + { sy = -1; + t = (unsigned int)(- y->val); + } + ey = &dumy; + ey->d[0] = (unsigned short)t; + ey->d[1] = (unsigned short)(t >> 16); + ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0; + ey->next = NULL; + } + else + { sy = y->val; + xassert(sy == +1 || sy == -1); + ey = y->ptr; + } + /* determine the number of digits of [x] */ + nx = n = 0; + for (e = ex; e != NULL; e = e->next) + { for (k = 0; k <= 5; k++) + { n++; + if (e->d[k]) + nx = n; + } + } + xassert(nx > 0); + /* determine the number of digits of [y] */ + ny = n = 0; + for (e = ey; e != NULL; e = e->next) + { for (k = 0; k <= 5; k++) + { n++; + if (e->d[k]) + ny = n; + } + } + xassert(ny > 0); + /* we need working array containing at least nx+ny+ny places */ + work = gmp_get_work(nx+ny+ny); + /* load digits of [x] */ + wx = &work[0]; + for (n = 0; n < nx; n++) + wx[ny+n] = 0; + for (n = 0, e = ex; e != NULL; e = e->next) + { for (k = 0; k <= 5; k++, n++) + { if (e->d[k]) + wx[ny+n] = e->d[k]; + } + } + /* load digits of [y] */ + wy = &work[nx+ny]; + for (n = 0; n < ny; n++) wy[n] = 0; + for (n = 0, e = ey; e != NULL; e = e->next) + { for (k = 0; k <= 5; k++, n++) + { if (e->d[k]) + wy[n] = e->d[k]; + } + } + /* compute [x] * [y] */ + bigmul(nx, ny, wx, wy); + /* construct and normalize result */ + mpz_set_si(z, 0); + z->val = sx * sy; + es = NULL; + k = 6; + for (n = 0; n < nx+ny; n++) + { if (k > 5) + { e = gmp_get_atom(sizeof(struct mpz_seg)); + e->d[0] = e->d[1] = e->d[2] = 0; + e->d[3] = e->d[4] = e->d[5] = 0; + e->next = NULL; + if (z->ptr == NULL) + z->ptr = e; + else + es->next = e; + es = e; + k = 0; + } + es->d[k++] = wx[n]; + } + normalize(z); +done: return; +} + +void mpz_neg(mpz_t z, mpz_t x) +{ /* set z to 0 - x */ + mpz_set(z, x); + z->val = - z->val; + return; +} + +void mpz_abs(mpz_t z, mpz_t x) +{ /* set z to the absolute value of x */ + mpz_set(z, x); + if (z->val < 0) + z->val = - z->val; + return; +} + +void mpz_div(mpz_t q, mpz_t r, mpz_t x, mpz_t y) +{ /* divide x by y, forming quotient q and/or remainder r + * if q = NULL then quotient is not stored; if r = NULL then + * remainder is not stored + * the sign of quotient is determined as in algebra while the + * sign of remainder is the same as the sign of dividend: + * +26 : +7 = +3, remainder is +5 + * -26 : +7 = -3, remainder is -5 + * +26 : -7 = -3, remainder is +5 + * -26 : -7 = +3, remainder is -5 */ + struct mpz_seg dumx, dumy, *ex, *ey, *es, *e; + int sx, sy, k, nx, ny, n; + unsigned int t; + unsigned short *work, *wx, *wy; + /* divide by zero is not allowed */ + if (y->val == 0) + { xassert(y->ptr == NULL); + xerror("mpz_div: divide by zero not allowed\n"); + } + /* if [x] = 0 then [q] = [r] = 0 */ + if (x->val == 0) + { xassert(x->ptr == NULL); + if (q != NULL) + mpz_set_si(q, 0); + if (r != NULL) + mpz_set_si(r, 0); + goto done; + } + /* special case when both [x] and [y] are in short format */ + if (x->ptr == NULL && y->ptr == NULL) + { int xval = x->val, yval = y->val; + xassert(xval != 0x80000000 && yval != 0x80000000); + /* FIXME: use div function */ + if (q != NULL) + mpz_set_si(q, xval / yval); + if (r != NULL) + mpz_set_si(r, xval % yval); + goto done; + } + /* convert [x] to long format, if necessary */ + if (x->ptr == NULL) + { xassert(x->val != 0x80000000); + if (x->val >= 0) + { sx = +1; + t = (unsigned int)(+ x->val); + } + else + { sx = -1; + t = (unsigned int)(- x->val); + } + ex = &dumx; + ex->d[0] = (unsigned short)t; + ex->d[1] = (unsigned short)(t >> 16); + ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0; + ex->next = NULL; + } + else + { sx = x->val; + xassert(sx == +1 || sx == -1); + ex = x->ptr; + } + /* convert [y] to long format, if necessary */ + if (y->ptr == NULL) + { xassert(y->val != 0x80000000); + if (y->val >= 0) + { sy = +1; + t = (unsigned int)(+ y->val); + } + else + { sy = -1; + t = (unsigned int)(- y->val); + } + ey = &dumy; + ey->d[0] = (unsigned short)t; + ey->d[1] = (unsigned short)(t >> 16); + ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0; + ey->next = NULL; + } + else + { sy = y->val; + xassert(sy == +1 || sy == -1); + ey = y->ptr; + } + /* determine the number of digits of [x] */ + nx = n = 0; + for (e = ex; e != NULL; e = e->next) + { for (k = 0; k <= 5; k++) + { n++; + if (e->d[k]) + nx = n; + } + } + xassert(nx > 0); + /* determine the number of digits of [y] */ + ny = n = 0; + for (e = ey; e != NULL; e = e->next) + { for (k = 0; k <= 5; k++) + { n++; + if (e->d[k]) + ny = n; + } + } + xassert(ny > 0); + /* if nx < ny then [q] = 0 and [r] = [x] */ + if (nx < ny) + { if (r != NULL) + mpz_set(r, x); + if (q != NULL) + mpz_set_si(q, 0); + goto done; + } + /* we need working array containing at least nx+ny+1 places */ + work = gmp_get_work(nx+ny+1); + /* load digits of [x] */ + wx = &work[0]; + for (n = 0; n < nx; n++) + wx[n] = 0; + for (n = 0, e = ex; e != NULL; e = e->next) + { for (k = 0; k <= 5; k++, n++) + if (e->d[k]) wx[n] = e->d[k]; + } + /* load digits of [y] */ + wy = &work[nx+1]; + for (n = 0; n < ny; n++) + wy[n] = 0; + for (n = 0, e = ey; e != NULL; e = e->next) + { for (k = 0; k <= 5; k++, n++) + if (e->d[k]) wy[n] = e->d[k]; + } + /* compute quotient and remainder */ + xassert(wy[ny-1] != 0); + bigdiv(nx-ny, ny, wx, wy); + /* construct and normalize quotient */ + if (q != NULL) + { mpz_set_si(q, 0); + q->val = sx * sy; + es = NULL; + k = 6; + for (n = ny; n <= nx; n++) + { if (k > 5) + { e = gmp_get_atom(sizeof(struct mpz_seg)); + e->d[0] = e->d[1] = e->d[2] = 0; + e->d[3] = e->d[4] = e->d[5] = 0; + e->next = NULL; + if (q->ptr == NULL) + q->ptr = e; + else + es->next = e; + es = e; + k = 0; + } + es->d[k++] = wx[n]; + } + normalize(q); + } + /* construct and normalize remainder */ + if (r != NULL) + { mpz_set_si(r, 0); + r->val = sx; + es = NULL; + k = 6; + for (n = 0; n < ny; n++) + { if (k > 5) + { e = gmp_get_atom(sizeof(struct mpz_seg)); + e->d[0] = e->d[1] = e->d[2] = 0; + e->d[3] = e->d[4] = e->d[5] = 0; + e->next = NULL; + if (r->ptr == NULL) + r->ptr = e; + else + es->next = e; + es = e; + k = 0; + } + es->d[k++] = wx[n]; + } + normalize(r); + } +done: return; +} + +void mpz_gcd(mpz_t z, mpz_t x, mpz_t y) +{ /* set z to the greatest common divisor of x and y */ + /* in case of arbitrary integers GCD(x, y) = GCD(|x|, |y|), and, + * in particular, GCD(0, 0) = 0 */ + mpz_t u, v, r; + mpz_init(u); + mpz_init(v); + mpz_init(r); + mpz_abs(u, x); + mpz_abs(v, y); + while (mpz_sgn(v)) + { mpz_div(NULL, r, u, v); + mpz_set(u, v); + mpz_set(v, r); + } + mpz_set(z, u); + mpz_clear(u); + mpz_clear(v); + mpz_clear(r); + return; +} + +int mpz_cmp(mpz_t x, mpz_t y) +{ /* compare x and y; return a positive value if x > y, zero if + * x = y, or a nefative value if x < y */ + static struct mpz_seg zero = { { 0, 0, 0, 0, 0, 0 }, NULL }; + struct mpz_seg dumx, dumy, *ex, *ey; + int cc, sx, sy, k; + unsigned int t; + if (x == y) + { cc = 0; + goto done; + } + /* special case when both [x] and [y] are in short format */ + if (x->ptr == NULL && y->ptr == NULL) + { int xval = x->val, yval = y->val; + xassert(xval != 0x80000000 && yval != 0x80000000); + cc = (xval > yval ? +1 : xval < yval ? -1 : 0); + goto done; + } + /* special case when [x] and [y] have different signs */ + if (x->val > 0 && y->val <= 0 || x->val == 0 && y->val < 0) + { cc = +1; + goto done; + } + if (x->val < 0 && y->val >= 0 || x->val == 0 && y->val > 0) + { cc = -1; + goto done; + } + /* convert [x] to long format, if necessary */ + if (x->ptr == NULL) + { xassert(x->val != 0x80000000); + if (x->val >= 0) + { sx = +1; + t = (unsigned int)(+ x->val); + } + else + { sx = -1; + t = (unsigned int)(- x->val); + } + ex = &dumx; + ex->d[0] = (unsigned short)t; + ex->d[1] = (unsigned short)(t >> 16); + ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0; + ex->next = NULL; + } + else + { sx = x->val; + xassert(sx == +1 || sx == -1); + ex = x->ptr; + } + /* convert [y] to long format, if necessary */ + if (y->ptr == NULL) + { xassert(y->val != 0x80000000); + if (y->val >= 0) + { sy = +1; + t = (unsigned int)(+ y->val); + } + else + { sy = -1; + t = (unsigned int)(- y->val); + } + ey = &dumy; + ey->d[0] = (unsigned short)t; + ey->d[1] = (unsigned short)(t >> 16); + ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0; + ey->next = NULL; + } + else + { sy = y->val; + xassert(sy == +1 || sy == -1); + ey = y->ptr; + } + /* main fragment */ + xassert(sx > 0 && sy > 0 || sx < 0 && sy < 0); + cc = 0; + for (; ex || ey; ex = ex->next, ey = ey->next) + { if (ex == NULL) + ex = &zero; + if (ey == NULL) + ey = &zero; + for (k = 0; k <= 5; k++) + { if (ex->d[k] > ey->d[k]) + cc = +1; + if (ex->d[k] < ey->d[k]) + cc = -1; + } + } + if (sx < 0) cc = - cc; +done: return cc; +} + +int mpz_sgn(mpz_t x) +{ /* return +1 if x > 0, 0 if x = 0, and -1 if x < 0 */ + int s; + s = (x->val > 0 ? +1 : x->val < 0 ? -1 : 0); + return s; +} + +int mpz_out_str(void *_fp, int base, mpz_t x) +{ /* output x on stream fp, as a string in given base; the base + * may vary from 2 to 36; + * return the number of bytes written, or if an error occurred, + * return 0 */ + FILE *fp = _fp; + mpz_t b, y, r; + int n, j, nwr = 0; + unsigned char *d; + static char *set = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + if (!(2 <= base && base <= 36)) + xerror("mpz_out_str: base = %d; invalid base\n", base); + mpz_init(b); + mpz_set_si(b, base); + mpz_init(y); + mpz_init(r); + /* determine the number of digits */ + mpz_abs(y, x); + for (n = 0; mpz_sgn(y) != 0; n++) + mpz_div(y, NULL, y, b); + if (n == 0) n = 1; + /* compute the digits */ + d = xmalloc(n); + mpz_abs(y, x); + for (j = 0; j < n; j++) + { mpz_div(y, r, y, b); + xassert(0 <= r->val && r->val < base && r->ptr == NULL); + d[j] = (unsigned char)r->val; + } + /* output the integer to the stream */ + if (fp == NULL) + fp = stdout; + if (mpz_sgn(x) < 0) + fputc('-', fp), nwr++; + for (j = n-1; j >= 0; j--) + fputc(set[d[j]], fp), nwr++; + if (ferror(fp)) + nwr = 0; + mpz_clear(b); + mpz_clear(y); + mpz_clear(r); + xfree(d); + return nwr; +} + +/*--------------------------------------------------------------------*/ + +mpq_t _mpq_init(void) +{ /* initialize x, and set its value to 0/1 */ + mpq_t x; + x = gmp_get_atom(sizeof(struct mpq)); + x->p.val = 0; + x->p.ptr = NULL; + x->q.val = 1; + x->q.ptr = NULL; + return x; +} + +void mpq_clear(mpq_t x) +{ /* free the space occupied by x */ + mpz_set_si(&x->p, 0); + xassert(x->p.ptr == NULL); + mpz_set_si(&x->q, 0); + xassert(x->q.ptr == NULL); + /* free the number descriptor */ + gmp_free_atom(x, sizeof(struct mpq)); + return; +} + +void mpq_canonicalize(mpq_t x) +{ /* remove any factors that are common to the numerator and + * denominator of x, and make the denominator positive */ + mpz_t f; + xassert(x->q.val != 0); + if (x->q.val < 0) + { mpz_neg(&x->p, &x->p); + mpz_neg(&x->q, &x->q); + } + mpz_init(f); + mpz_gcd(f, &x->p, &x->q); + if (!(f->val == 1 && f->ptr == NULL)) + { mpz_div(&x->p, NULL, &x->p, f); + mpz_div(&x->q, NULL, &x->q, f); + } + mpz_clear(f); + return; +} + +void mpq_set(mpq_t z, mpq_t x) +{ /* set the value of z from x */ + if (z != x) + { mpz_set(&z->p, &x->p); + mpz_set(&z->q, &x->q); + } + return; +} + +void mpq_set_si(mpq_t x, int p, unsigned int q) +{ /* set the value of x to p/q */ + if (q == 0) + xerror("mpq_set_si: zero denominator not allowed\n"); + mpz_set_si(&x->p, p); + xassert(q <= 0x7FFFFFFF); + mpz_set_si(&x->q, q); + return; +} + +double mpq_get_d(mpq_t x) +{ /* convert x to a double, truncating if necessary */ + int np, nq; + double p, q; + p = mpz_get_d_2exp(&np, &x->p); + q = mpz_get_d_2exp(&nq, &x->q); + return ldexp(p / q, np - nq); +} + +void mpq_set_d(mpq_t x, double val) +{ /* set x to val; there is no rounding, the conversion is exact */ + int s, n, d, j; + double f; + mpz_t temp; + xassert(-DBL_MAX <= val && val <= +DBL_MAX); + mpq_set_si(x, 0, 1); + if (val > 0.0) + s = +1; + else if (val < 0.0) + s = -1; + else + goto done; + f = frexp(fabs(val), &n); + /* |val| = f * 2^n, where 0.5 <= f < 1.0 */ + mpz_init(temp); + while (f != 0.0) + { f *= 16.0, n -= 4; + d = (int)f; + xassert(0 <= d && d <= 15); + f -= (double)d; + /* x := 16 * x + d */ + mpz_set_si(temp, 16); + mpz_mul(&x->p, &x->p, temp); + mpz_set_si(temp, d); + mpz_add(&x->p, &x->p, temp); + } + mpz_clear(temp); + /* x := x * 2^n */ + if (n > 0) + { for (j = 1; j <= n; j++) + mpz_add(&x->p, &x->p, &x->p); + } + else if (n < 0) + { for (j = 1; j <= -n; j++) + mpz_add(&x->q, &x->q, &x->q); + mpq_canonicalize(x); + } + if (s < 0) + mpq_neg(x, x); +done: return; +} + +void mpq_add(mpq_t z, mpq_t x, mpq_t y) +{ /* set z to x + y */ + mpz_t p, q; + mpz_init(p); + mpz_init(q); + mpz_mul(p, &x->p, &y->q); + mpz_mul(q, &x->q, &y->p); + mpz_add(p, p, q); + mpz_mul(q, &x->q, &y->q); + mpz_set(&z->p, p); + mpz_set(&z->q, q); + mpz_clear(p); + mpz_clear(q); + mpq_canonicalize(z); + return; +} + +void mpq_sub(mpq_t z, mpq_t x, mpq_t y) +{ /* set z to x - y */ + mpz_t p, q; + mpz_init(p); + mpz_init(q); + mpz_mul(p, &x->p, &y->q); + mpz_mul(q, &x->q, &y->p); + mpz_sub(p, p, q); + mpz_mul(q, &x->q, &y->q); + mpz_set(&z->p, p); + mpz_set(&z->q, q); + mpz_clear(p); + mpz_clear(q); + mpq_canonicalize(z); + return; +} + +void mpq_mul(mpq_t z, mpq_t x, mpq_t y) +{ /* set z to x * y */ + mpz_mul(&z->p, &x->p, &y->p); + mpz_mul(&z->q, &x->q, &y->q); + mpq_canonicalize(z); + return; +} + +void mpq_div(mpq_t z, mpq_t x, mpq_t y) +{ /* set z to x / y */ + mpz_t p, q; + if (mpq_sgn(y) == 0) + xerror("mpq_div: zero divisor not allowed\n"); + mpz_init(p); + mpz_init(q); + mpz_mul(p, &x->p, &y->q); + mpz_mul(q, &x->q, &y->p); + mpz_set(&z->p, p); + mpz_set(&z->q, q); + mpz_clear(p); + mpz_clear(q); + mpq_canonicalize(z); + return; +} + +void mpq_neg(mpq_t z, mpq_t x) +{ /* set z to 0 - x */ + mpq_set(z, x); + mpz_neg(&z->p, &z->p); + return; +} + +void mpq_abs(mpq_t z, mpq_t x) +{ /* set z to the absolute value of x */ + mpq_set(z, x); + mpz_abs(&z->p, &z->p); + xassert(mpz_sgn(&x->q) > 0); + return; +} + +int mpq_cmp(mpq_t x, mpq_t y) +{ /* compare x and y; return a positive value if x > y, zero if + * x = y, or a negative value if x < y */ + mpq_t temp; + int s; + mpq_init(temp); + mpq_sub(temp, x, y); + s = mpq_sgn(temp); + mpq_clear(temp); + return s; +} + +int mpq_sgn(mpq_t x) +{ /* return +1 if x > 0, 0 if x = 0, and -1 if x < 0 */ + int s; + s = mpz_sgn(&x->p); + xassert(mpz_sgn(&x->q) > 0); + return s; +} + +int mpq_out_str(void *_fp, int base, mpq_t x) +{ /* output x on stream fp, as a string in given base; the base + * may vary from 2 to 36; output is in the form 'num/den' or if + * the denominator is 1 then just 'num'; + * if the parameter fp is a null pointer, stdout is assumed; + * return the number of bytes written, or if an error occurred, + * return 0 */ + FILE *fp = _fp; + int nwr; + if (!(2 <= base && base <= 36)) + xerror("mpq_out_str: base = %d; invalid base\n", base); + if (fp == NULL) + fp = stdout; + nwr = mpz_out_str(fp, base, &x->p); + if (x->q.val == 1 && x->q.ptr == NULL) + ; + else + { fputc('/', fp), nwr++; + nwr += mpz_out_str(fp, base, &x->q); + } + if (ferror(fp)) + nwr = 0; + return nwr; +} + +#endif + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/mygmp.h b/test/monniaux/glpk-4.65/src/misc/mygmp.h new file mode 100644 index 00000000..31d2024d --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/mygmp.h @@ -0,0 +1,254 @@ +/* mygmp.h (integer and rational arithmetic) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2008-2015 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#ifndef MYGMP_H +#define MYGMP_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_GMP /* use GNU MP library */ + +#include + +#define gmp_pool_count() 0 + +#define gmp_free_mem() ((void)0) + +#else /* use GLPK MP module */ + +/*********************************************************************** +* INTEGER NUMBERS +* --------------- +* Depending on its magnitude an integer number of arbitrary precision +* is represented either in short format or in long format. +* +* Short format corresponds to the int type and allows representing +* integer numbers in the range [-(2^31-1), +(2^31-1)]. Note that for +* the most negative number of int type the short format is not used. +* +* In long format integer numbers are represented using the positional +* system with the base (radix) 2^16 = 65536: +* +* x = (-1)^s sum{j in 0..n-1} d[j] * 65536^j, +* +* where x is the integer to be represented, s is its sign (+1 or -1), +* d[j] are its digits (0 <= d[j] <= 65535). +* +* RATIONAL NUMBERS +* ---------------- +* A rational number is represented as an irreducible fraction: +* +* p / q, +* +* where p (numerator) and q (denominator) are integer numbers (q > 0) +* having no common divisors. */ + +struct mpz +{ /* integer number */ + int val; + /* if ptr is a null pointer, the number is in short format, and + val is its value; otherwise, the number is in long format, and + val is its sign (+1 or -1) */ + struct mpz_seg *ptr; + /* pointer to the linked list of the number segments ordered in + ascending of powers of the base */ +}; + +struct mpz_seg +{ /* integer number segment */ + unsigned short d[6]; + /* six digits of the number ordered in ascending of powers of the + base */ + struct mpz_seg *next; + /* pointer to the next number segment */ +}; + +struct mpq +{ /* rational number (p / q) */ + struct mpz p; + /* numerator */ + struct mpz q; + /* denominator */ +}; + +typedef struct mpz *mpz_t; +typedef struct mpq *mpq_t; + +#define gmp_get_atom _glp_gmp_get_atom +void *gmp_get_atom(int size); + +#define gmp_free_atom _glp_gmp_free_atom +void gmp_free_atom(void *ptr, int size); + +#define gmp_pool_count _glp_gmp_pool_count +int gmp_pool_count(void); + +#define gmp_get_work _glp_gmp_get_work +unsigned short *gmp_get_work(int size); + +#define gmp_free_mem _glp_gmp_free_mem +void gmp_free_mem(void); + +#define mpz_init(x) (void)((x) = _mpz_init()) + +#define _mpz_init _glp_mpz_init +mpz_t _mpz_init(void); +/* initialize x and set its value to 0 */ + +#define mpz_clear _glp_mpz_clear +void mpz_clear(mpz_t x); +/* free the space occupied by x */ + +#define mpz_set _glp_mpz_set +void mpz_set(mpz_t z, mpz_t x); +/* set the value of z from x */ + +#define mpz_set_si _glp_mpz_set_si +void mpz_set_si(mpz_t x, int val); +/* set the value of x to val */ + +#define mpz_get_d _glp_mpz_get_d +double mpz_get_d(mpz_t x); +/* convert x to a double, truncating if necessary */ + +#define mpz_get_d_2exp _glp_mpz_get_d_2exp +double mpz_get_d_2exp(int *exp, mpz_t x); +/* convert x to a double, returning the exponent separately */ + +#define mpz_swap _glp_mpz_swap +void mpz_swap(mpz_t x, mpz_t y); +/* swap the values x and y efficiently */ + +#define mpz_add _glp_mpz_add +void mpz_add(mpz_t, mpz_t, mpz_t); +/* set z to x + y */ + +#define mpz_sub _glp_mpz_sub +void mpz_sub(mpz_t, mpz_t, mpz_t); +/* set z to x - y */ + +#define mpz_mul _glp_mpz_mul +void mpz_mul(mpz_t, mpz_t, mpz_t); +/* set z to x * y */ + +#define mpz_neg _glp_mpz_neg +void mpz_neg(mpz_t z, mpz_t x); +/* set z to 0 - x */ + +#define mpz_abs _glp_mpz_abs +void mpz_abs(mpz_t z, mpz_t x); +/* set z to the absolute value of x */ + +#define mpz_div _glp_mpz_div +void mpz_div(mpz_t q, mpz_t r, mpz_t x, mpz_t y); +/* divide x by y, forming quotient q and/or remainder r */ + +#define mpz_gcd _glp_mpz_gcd +void mpz_gcd(mpz_t z, mpz_t x, mpz_t y); +/* set z to the greatest common divisor of x and y */ + +#define mpz_cmp _glp_mpz_cmp +int mpz_cmp(mpz_t x, mpz_t y); +/* compare x and y */ + +#define mpz_sgn _glp_mpz_sgn +int mpz_sgn(mpz_t x); +/* return +1 if x > 0, 0 if x = 0, and -1 if x < 0 */ + +#define mpz_out_str _glp_mpz_out_str +int mpz_out_str(void *fp, int base, mpz_t x); +/* output x on stream fp, as a string in given base */ + +#define mpq_init(x) (void)((x) = _mpq_init()) + +#define _mpq_init _glp_mpq_init +mpq_t _mpq_init(void); +/* initialize x, and set its value to 0/1 */ + +#define mpq_clear _glp_mpq_clear +void mpq_clear(mpq_t x); +/* free the space occupied by x */ + +#define mpq_canonicalize _glp_mpq_canonicalize +void mpq_canonicalize(mpq_t x); +/* canonicalize x */ + +#define mpq_set _glp_mpq_set +void mpq_set(mpq_t z, mpq_t x); +/* set the value of z from x */ + +#define mpq_set_si _glp_mpq_set_si +void mpq_set_si(mpq_t x, int p, unsigned int q); +/* set the value of x to p/q */ + +#define mpq_get_d _glp_mpq_get_d +double mpq_get_d(mpq_t x); +/* convert x to a double, truncating if necessary */ + +#define mpq_set_d _glp_mpq_set_d +void mpq_set_d(mpq_t x, double val); +/* set x to val; there is no rounding, the conversion is exact */ + +#define mpq_add _glp_mpq_add +void mpq_add(mpq_t z, mpq_t x, mpq_t y); +/* set z to x + y */ + +#define mpq_sub _glp_mpq_sub +void mpq_sub(mpq_t z, mpq_t x, mpq_t y); +/* set z to x - y */ + +#define mpq_mul _glp_mpq_mul +void mpq_mul(mpq_t z, mpq_t x, mpq_t y); +/* set z to x * y */ + +#define mpq_div _glp_mpq_div +void mpq_div(mpq_t z, mpq_t x, mpq_t y); +/* set z to x / y */ + +#define mpq_neg _glp_mpq_neg +void mpq_neg(mpq_t z, mpq_t x); +/* set z to 0 - x */ + +#define mpq_abs _glp_mpq_abs +void mpq_abs(mpq_t z, mpq_t x); +/* set z to the absolute value of x */ + +#define mpq_cmp _glp_mpq_cmp +int mpq_cmp(mpq_t x, mpq_t y); +/* compare x and y */ + +#define mpq_sgn _glp_mpq_sgn +int mpq_sgn(mpq_t x); +/* return +1 if x > 0, 0 if x = 0, and -1 if x < 0 */ + +#define mpq_out_str _glp_mpq_out_str +int mpq_out_str(void *fp, int base, mpq_t x); +/* output x on stream fp, as a string in given base */ + +#endif + +#endif + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/okalg.c b/test/monniaux/glpk-4.65/src/misc/okalg.c new file mode 100644 index 00000000..8eecd6df --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/okalg.c @@ -0,0 +1,382 @@ +/* okalg.c (out-of-kilter algorithm) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2009-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#include "env.h" +#include "okalg.h" + +/*********************************************************************** +* NAME +* +* okalg - out-of-kilter algorithm +* +* SYNOPSIS +* +* #include "okalg.h" +* int okalg(int nv, int na, const int tail[], const int head[], +* const int low[], const int cap[], const int cost[], int x[], +* int pi[]); +* +* DESCRIPTION +* +* The routine okalg implements the out-of-kilter algorithm to find a +* minimal-cost circulation in the specified flow network. +* +* INPUT PARAMETERS +* +* nv is the number of nodes, nv >= 0. +* +* na is the number of arcs, na >= 0. +* +* tail[a], a = 1,...,na, is the index of tail node of arc a. +* +* head[a], a = 1,...,na, is the index of head node of arc a. +* +* low[a], a = 1,...,na, is an lower bound to the flow through arc a. +* +* cap[a], a = 1,...,na, is an upper bound to the flow through arc a, +* which is the capacity of the arc. +* +* cost[a], a = 1,...,na, is a per-unit cost of the flow through arc a. +* +* NOTES +* +* 1. Multiple arcs are allowed, but self-loops are not allowed. +* +* 2. It is required that 0 <= low[a] <= cap[a] for all arcs. +* +* 3. Arc costs may have any sign. +* +* OUTPUT PARAMETERS +* +* x[a], a = 1,...,na, is optimal value of the flow through arc a. +* +* pi[i], i = 1,...,nv, is Lagrange multiplier for flow conservation +* equality constraint corresponding to node i (the node potential). +* +* RETURNS +* +* 0 optimal circulation found; +* +* 1 there is no feasible circulation; +* +* 2 integer overflow occured; +* +* 3 optimality test failed (logic error). +* +* REFERENCES +* +* L.R.Ford, Jr., and D.R.Fulkerson, "Flows in Networks," The RAND +* Corp., Report R-375-PR (August 1962), Chap. III "Minimal Cost Flow +* Problems," pp.113-26. */ + +static int overflow(int u, int v) +{ /* check for integer overflow on computing u + v */ + if (u > 0 && v > 0 && u + v < 0) return 1; + if (u < 0 && v < 0 && u + v > 0) return 1; + return 0; +} + +int okalg(int nv, int na, const int tail[], const int head[], + const int low[], const int cap[], const int cost[], int x[], + int pi[]) +{ int a, aok, delta, i, j, k, lambda, pos1, pos2, s, t, temp, ret, + *ptr, *arc, *link, *list; + /* sanity checks */ + xassert(nv >= 0); + xassert(na >= 0); + for (a = 1; a <= na; a++) + { i = tail[a], j = head[a]; + xassert(1 <= i && i <= nv); + xassert(1 <= j && j <= nv); + xassert(i != j); + xassert(0 <= low[a] && low[a] <= cap[a]); + } + /* allocate working arrays */ + ptr = xcalloc(1+nv+1, sizeof(int)); + arc = xcalloc(1+na+na, sizeof(int)); + link = xcalloc(1+nv, sizeof(int)); + list = xcalloc(1+nv, sizeof(int)); + /* ptr[i] := (degree of node i) */ + for (i = 1; i <= nv; i++) + ptr[i] = 0; + for (a = 1; a <= na; a++) + { ptr[tail[a]]++; + ptr[head[a]]++; + } + /* initialize arc pointers */ + ptr[1]++; + for (i = 1; i < nv; i++) + ptr[i+1] += ptr[i]; + ptr[nv+1] = ptr[nv]; + /* build arc lists */ + for (a = 1; a <= na; a++) + { arc[--ptr[tail[a]]] = a; + arc[--ptr[head[a]]] = a; + } + xassert(ptr[1] == 1); + xassert(ptr[nv+1] == na+na+1); + /* now the indices of arcs incident to node i are stored in + * locations arc[ptr[i]], arc[ptr[i]+1], ..., arc[ptr[i+1]-1] */ + /* initialize arc flows and node potentials */ + for (a = 1; a <= na; a++) + x[a] = 0; + for (i = 1; i <= nv; i++) + pi[i] = 0; +loop: /* main loop starts here */ + /* find out-of-kilter arc */ + aok = 0; + for (a = 1; a <= na; a++) + { i = tail[a], j = head[a]; + if (overflow(cost[a], pi[i] - pi[j])) + { ret = 2; + goto done; + } + lambda = cost[a] + (pi[i] - pi[j]); + if (x[a] < low[a] || (lambda < 0 && x[a] < cap[a])) + { /* arc a = i->j is out of kilter, and we need to increase + * the flow through this arc */ + aok = a, s = j, t = i; + break; + } + if (x[a] > cap[a] || (lambda > 0 && x[a] > low[a])) + { /* arc a = i->j is out of kilter, and we need to decrease + * the flow through this arc */ + aok = a, s = i, t = j; + break; + } + } + if (aok == 0) + { /* all arcs are in kilter */ + /* check for feasibility */ + for (a = 1; a <= na; a++) + { if (!(low[a] <= x[a] && x[a] <= cap[a])) + { ret = 3; + goto done; + } + } + for (i = 1; i <= nv; i++) + { temp = 0; + for (k = ptr[i]; k < ptr[i+1]; k++) + { a = arc[k]; + if (tail[a] == i) + { /* a is outgoing arc */ + temp += x[a]; + } + else if (head[a] == i) + { /* a is incoming arc */ + temp -= x[a]; + } + else + xassert(a != a); + } + if (temp != 0) + { ret = 3; + goto done; + } + } + /* check for optimality */ + for (a = 1; a <= na; a++) + { i = tail[a], j = head[a]; + lambda = cost[a] + (pi[i] - pi[j]); + if ((lambda > 0 && x[a] != low[a]) || + (lambda < 0 && x[a] != cap[a])) + { ret = 3; + goto done; + } + } + /* current circulation is optimal */ + ret = 0; + goto done; + } + /* now we need to find a cycle (t, a, s, ..., t), which allows + * increasing the flow along it, where a is the out-of-kilter arc + * just found */ + /* link[i] = 0 means that node i is not labelled yet; + * link[i] = a means that arc a immediately precedes node i */ + /* initially only node s is labelled */ + for (i = 1; i <= nv; i++) + link[i] = 0; + link[s] = aok, list[1] = s, pos1 = pos2 = 1; + /* breadth first search */ + while (pos1 <= pos2) + { /* dequeue node i */ + i = list[pos1++]; + /* consider all arcs incident to node i */ + for (k = ptr[i]; k < ptr[i+1]; k++) + { a = arc[k]; + if (tail[a] == i) + { /* a = i->j is a forward arc from s to t */ + j = head[a]; + /* if node j has been labelled, skip the arc */ + if (link[j] != 0) continue; + /* if the arc does not allow increasing the flow through + * it, skip the arc */ + if (x[a] >= cap[a]) continue; + if (overflow(cost[a], pi[i] - pi[j])) + { ret = 2; + goto done; + } + lambda = cost[a] + (pi[i] - pi[j]); + if (lambda > 0 && x[a] >= low[a]) continue; + } + else if (head[a] == i) + { /* a = i<-j is a backward arc from s to t */ + j = tail[a]; + /* if node j has been labelled, skip the arc */ + if (link[j] != 0) continue; + /* if the arc does not allow decreasing the flow through + * it, skip the arc */ + if (x[a] <= low[a]) continue; + if (overflow(cost[a], pi[j] - pi[i])) + { ret = 2; + goto done; + } + lambda = cost[a] + (pi[j] - pi[i]); + if (lambda < 0 && x[a] <= cap[a]) continue; + } + else + xassert(a != a); + /* label node j and enqueue it */ + link[j] = a, list[++pos2] = j; + /* check for breakthrough */ + if (j == t) goto brkt; + } + } + /* NONBREAKTHROUGH */ + /* consider all arcs, whose one endpoint is labelled and other is + * not, and determine maximal change of node potentials */ + delta = 0; + for (a = 1; a <= na; a++) + { i = tail[a], j = head[a]; + if (link[i] != 0 && link[j] == 0) + { /* a = i->j, where node i is labelled, node j is not */ + if (overflow(cost[a], pi[i] - pi[j])) + { ret = 2; + goto done; + } + lambda = cost[a] + (pi[i] - pi[j]); + if (x[a] <= cap[a] && lambda > 0) + if (delta == 0 || delta > + lambda) delta = + lambda; + } + else if (link[i] == 0 && link[j] != 0) + { /* a = j<-i, where node j is labelled, node i is not */ + if (overflow(cost[a], pi[i] - pi[j])) + { ret = 2; + goto done; + } + lambda = cost[a] + (pi[i] - pi[j]); + if (x[a] >= low[a] && lambda < 0) + if (delta == 0 || delta > - lambda) delta = - lambda; + } + } + if (delta == 0) + { /* there is no feasible circulation */ + ret = 1; + goto done; + } + /* increase potentials of all unlabelled nodes */ + for (i = 1; i <= nv; i++) + { if (link[i] == 0) + { if (overflow(pi[i], delta)) + { ret = 2; + goto done; + } + pi[i] += delta; + } + } + goto loop; +brkt: /* BREAKTHROUGH */ + /* walk through arcs of the cycle (t, a, s, ..., t) found in the + * reverse order and determine maximal change of the flow */ + delta = 0; + for (j = t;; j = i) + { /* arc a immediately precedes node j in the cycle */ + a = link[j]; + if (head[a] == j) + { /* a = i->j is a forward arc of the cycle */ + i = tail[a]; + lambda = cost[a] + (pi[i] - pi[j]); + if (lambda > 0 && x[a] < low[a]) + { /* x[a] may be increased until its lower bound */ + temp = low[a] - x[a]; + } + else if (lambda <= 0 && x[a] < cap[a]) + { /* x[a] may be increased until its upper bound */ + temp = cap[a] - x[a]; + } + else + xassert(a != a); + } + else if (tail[a] == j) + { /* a = i<-j is a backward arc of the cycle */ + i = head[a]; + lambda = cost[a] + (pi[j] - pi[i]); + if (lambda < 0 && x[a] > cap[a]) + { /* x[a] may be decreased until its upper bound */ + temp = x[a] - cap[a]; + } + else if (lambda >= 0 && x[a] > low[a]) + { /* x[a] may be decreased until its lower bound */ + temp = x[a] - low[a]; + } + else + xassert(a != a); + } + else + xassert(a != a); + if (delta == 0 || delta > temp) delta = temp; + /* check for end of the cycle */ + if (i == t) break; + } + xassert(delta > 0); + /* increase the flow along the cycle */ + for (j = t;; j = i) + { /* arc a immediately precedes node j in the cycle */ + a = link[j]; + if (head[a] == j) + { /* a = i->j is a forward arc of the cycle */ + i = tail[a]; + /* overflow cannot occur */ + x[a] += delta; + } + else if (tail[a] == j) + { /* a = i<-j is a backward arc of the cycle */ + i = head[a]; + /* overflow cannot occur */ + x[a] -= delta; + } + else + xassert(a != a); + /* check for end of the cycle */ + if (i == t) break; + } + goto loop; +done: /* free working arrays */ + xfree(ptr); + xfree(arc); + xfree(link); + xfree(list); + return ret; +} + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/okalg.h b/test/monniaux/glpk-4.65/src/misc/okalg.h new file mode 100644 index 00000000..2f2d9740 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/okalg.h @@ -0,0 +1,35 @@ +/* okalg.h (out-of-kilter algorithm) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2009-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#ifndef OKALG_H +#define OKALG_H + +#define okalg _glp_okalg +int okalg(int nv, int na, const int tail[], const int head[], + const int low[], const int cap[], const int cost[], int x[], + int pi[]); +/* out-of-kilter algorithm */ + +#endif + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/qmd.c b/test/monniaux/glpk-4.65/src/misc/qmd.c new file mode 100644 index 00000000..a3397dcf --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/qmd.c @@ -0,0 +1,584 @@ +/* qmd.c (quotient minimum degree algorithm) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* THIS CODE IS THE RESULT OF TRANSLATION OF THE FORTRAN SUBROUTINES +* GENQMD, QMDRCH, QMDQT, QMDUPD, AND QMDMRG FROM THE BOOK: +* +* ALAN GEORGE, JOSEPH W-H LIU. COMPUTER SOLUTION OF LARGE SPARSE +* POSITIVE DEFINITE SYSTEMS. PRENTICE-HALL, 1981. +* +* THE TRANSLATION HAS BEEN DONE WITH THE PERMISSION OF THE AUTHORS +* OF THE ORIGINAL FORTRAN SUBROUTINES: ALAN GEORGE AND JOSEPH LIU, +* UNIVERSITY OF WATERLOO, WATERLOO, ONTARIO, CANADA. +* +* The translation was made by Andrew Makhorin . +* +* 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 . +***********************************************************************/ + +#include "qmd.h" + +/*********************************************************************** +* NAME +* +* genqmd - GENeral Quotient Minimum Degree algorithm +* +* SYNOPSIS +* +* #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); +* +* PURPOSE +* +* This routine implements the minimum degree algorithm. It makes use +* of the implicit representation of the elimination graph by quotient +* graphs, and the notion of indistinguishable nodes. +* +* CAUTION +* +* The adjancy vector adjncy will be destroyed. +* +* INPUT PARAMETERS +* +* neqns - number of equations; +* (xadj, adjncy) - +* the adjancy structure. +* +* OUTPUT PARAMETERS +* +* perm - the minimum degree ordering; +* invp - the inverse of perm. +* +* WORKING PARAMETERS +* +* deg - the degree vector. deg[i] is negative means node i has been +* numbered; +* marker - a marker vector, where marker[i] is negative means node i +* has been merged with another nodeand thus can be ignored; +* rchset - vector used for the reachable set; +* nbrhd - vector used for neighborhood set; +* qsize - vector used to store the size of indistinguishable +* supernodes; +* qlink - vector used to store indistinguishable nodes, i, qlink[i], +* qlink[qlink[i]], ... are the members of the supernode +* represented by i. +* +* PROGRAM SUBROUTINES +* +* qmdrch, qmdqt, qmdupd. +***********************************************************************/ + +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) +{ int inode, ip, irch, j, mindeg, ndeg, nhdsze, node, np, num, + nump1, nxnode, rchsze, search, thresh; +# define neqns (*_neqns) +# define nofsub (*_nofsub) + /* Initialize degree vector and other working variables. */ + mindeg = neqns; + nofsub = 0; + for (node = 1; node <= neqns; node++) + { perm[node] = node; + invp[node] = node; + marker[node] = 0; + qsize[node] = 1; + qlink[node] = 0; + ndeg = xadj[node+1] - xadj[node]; + deg[node] = ndeg; + if (ndeg < mindeg) mindeg = ndeg; + } + num = 0; + /* Perform threshold search to get a node of min degree. + * Variable search point to where search should start. */ +s200: search = 1; + thresh = mindeg; + mindeg = neqns; +s300: nump1 = num + 1; + if (nump1 > search) search = nump1; + for (j = search; j <= neqns; j++) + { node = perm[j]; + if (marker[node] >= 0) + { ndeg = deg[node]; + if (ndeg <= thresh) goto s500; + if (ndeg < mindeg) mindeg = ndeg; + } + } + goto s200; + /* Node has minimum degree. Find its reachable sets by calling + * qmdrch. */ +s500: search = j; + nofsub += deg[node]; + marker[node] = 1; + qmdrch(&node, xadj, adjncy, deg, marker, &rchsze, rchset, &nhdsze, + nbrhd); + /* Eliminate all nodes indistinguishable from node. They are given + * by node, qlink[node], ... . */ + nxnode = node; +s600: num++; + np = invp[nxnode]; + ip = perm[num]; + perm[np] = ip; + invp[ip] = np; + perm[num] = nxnode; + invp[nxnode] = num; + deg[nxnode] = -1; + nxnode = qlink[nxnode]; + if (nxnode > 0) goto s600; + if (rchsze > 0) + { /* Update the degrees of the nodes in the reachable set and + * identify indistinguishable nodes. */ + qmdupd(xadj, adjncy, &rchsze, rchset, deg, qsize, qlink, + marker, &rchset[rchsze+1], &nbrhd[nhdsze+1]); + /* Reset marker value of nodes in reach set. Update threshold + * value for cyclic search. Also call qmdqt to form new + * quotient graph. */ + marker[node] = 0; + for (irch = 1; irch <= rchsze; irch++) + { inode = rchset[irch]; + if (marker[inode] >= 0) + { marker[inode] = 0; + ndeg = deg[inode]; + if (ndeg < mindeg) mindeg = ndeg; + if (ndeg <= thresh) + { mindeg = thresh; + thresh = ndeg; + search = invp[inode]; + } + } + } + if (nhdsze > 0) + qmdqt(&node, xadj, adjncy, marker, &rchsze, rchset, nbrhd); + } + if (num < neqns) goto s300; + return; +# undef neqns +# undef nofsub +} + +/*********************************************************************** +* NAME +* +* qmdrch - Quotient MD ReaCHable set +* +* SYNOPSIS +* +* #include "qmd.h" +* void qmdrch(int *root, int xadj[], int adjncy[], int deg[], +* int marker[], int *rchsze, int rchset[], int *nhdsze, +* int nbrhd[]); +* +* PURPOSE +* +* This subroutine determines the reachable set of a node through a +* given subset. The adjancy structure is assumed to be stored in a +* quotient graph format. +* +* INPUT PARAMETERS +* +* root - the given node not in the subset; +* (xadj, adjncy) - +* the adjancy structure pair; +* deg - the degree vector. deg[i] < 0 means the node belongs to the +* given subset. +* +* OUTPUT PARAMETERS +* +* (rchsze, rchset) - +* the reachable set; +* (nhdsze, nbrhd) - +* the neighborhood set. +* +* UPDATED PARAMETERS +* +* marker - the marker vector for reach and nbrhd sets. > 0 means the +* node is in reach set. < 0 means the node has been merged +* with others in the quotient or it is in nbrhd set. +***********************************************************************/ + +void qmdrch(int *_root, int xadj[], int adjncy[], int deg[], + int marker[], int *_rchsze, int rchset[], int *_nhdsze, + int nbrhd[]) +{ int i, istop, istrt, j, jstop, jstrt, nabor, node; +# define root (*_root) +# define rchsze (*_rchsze) +# define nhdsze (*_nhdsze) + /* Loop through the neighbors of root in the quotient graph. */ + nhdsze = 0; + rchsze = 0; + istrt = xadj[root]; + istop = xadj[root+1] - 1; + if (istop < istrt) return; + for (i = istrt; i <= istop; i++) + { nabor = adjncy[i]; + if (nabor == 0) return; + if (marker[nabor] == 0) + { if (deg[nabor] >= 0) + { /* Include nabor into the reachable set. */ + rchsze++; + rchset[rchsze] = nabor; + marker[nabor] = 1; + goto s600; + } + /* nabor has been eliminated. Find nodes reachable from + * it. */ + marker[nabor] = -1; + nhdsze++; + nbrhd[nhdsze] = nabor; +s300: jstrt = xadj[nabor]; + jstop = xadj[nabor+1] - 1; + for (j = jstrt; j <= jstop; j++) + { node = adjncy[j]; + nabor = - node; + if (node < 0) goto s300; + if (node == 0) goto s600; + if (marker[node] == 0) + { rchsze++; + rchset[rchsze] = node; + marker[node] = 1; + } + } + } +s600: ; + } + return; +# undef root +# undef rchsze +# undef nhdsze +} + +/*********************************************************************** +* NAME +* +* qmdqt - Quotient MD Quotient graph Transformation +* +* SYNOPSIS +* +* #include "qmd.h" +* void qmdqt(int *root, int xadj[], int adjncy[], int marker[], +* int *rchsze, int rchset[], int nbrhd[]); +* +* PURPOSE +* +* This subroutine performs the quotient graph transformation after a +* node has been eliminated. +* +* INPUT PARAMETERS +* +* root - the node just eliminated. It becomes the representative of +* the new supernode; +* (xadj, adjncy) - +* the adjancy structure; +* (rchsze, rchset) - +* the reachable set of root in the old quotient graph; +* nbrhd - the neighborhood set which will be merged with root to form +* the new supernode; +* marker - the marker vector. +* +* UPDATED PARAMETERS +* +* adjncy - becomes the adjncy of the quotient graph. +***********************************************************************/ + +void qmdqt(int *_root, int xadj[], int adjncy[], int marker[], + int *_rchsze, int rchset[], int nbrhd[]) +{ int inhd, irch, j, jstop, jstrt, link, nabor, node; +# define root (*_root) +# define rchsze (*_rchsze) + irch = 0; + inhd = 0; + node = root; +s100: jstrt = xadj[node]; + jstop = xadj[node+1] - 2; + if (jstop >= jstrt) + { /* Place reach nodes into the adjacent list of node. */ + for (j = jstrt; j <= jstop; j++) + { irch++; + adjncy[j] = rchset[irch]; + if (irch >= rchsze) goto s400; + } + } + /* Link to other space provided by the nbrhd set. */ + link = adjncy[jstop+1]; + node = - link; + if (link >= 0) + { inhd++; + node = nbrhd[inhd]; + adjncy[jstop+1] = - node; + } + goto s100; + /* All reachable nodes have been saved. End the adjacent list. + * Add root to the neighborhood list of each node in the reach + * set. */ +s400: adjncy[j+1] = 0; + for (irch = 1; irch <= rchsze; irch++) + { node = rchset[irch]; + if (marker[node] >= 0) + { jstrt = xadj[node]; + jstop = xadj[node+1] - 1; + for (j = jstrt; j <= jstop; j++) + { nabor = adjncy[j]; + if (marker[nabor] < 0) + { adjncy[j] = root; + goto s600; + } + } + } +s600: ; + } + return; +# undef root +# undef rchsze +} + +/*********************************************************************** +* NAME +* +* qmdupd - Quotient MD UPDate +* +* SYNOPSIS +* +* #include "qmd.h" +* void qmdupd(int xadj[], int adjncy[], int *nlist, int list[], +* int deg[], int qsize[], int qlink[], int marker[], int rchset[], +* int nbrhd[]); +* +* PURPOSE +* +* This routine performs degree update for a set of nodes in the minimum +* degree algorithm. +* +* INPUT PARAMETERS +* +* (xadj, adjncy) - +* the adjancy structure; +* (nlist, list) - +* the list of nodes whose degree has to be updated. +* +* UPDATED PARAMETERS +* +* deg - the degree vector; +* qsize - size of indistinguishable supernodes; +* qlink - linked list for indistinguishable nodes; +* marker - used to mark those nodes in reach/nbrhd sets. +* +* WORKING PARAMETERS +* +* rchset - the reachable set; +* nbrhd - the neighborhood set. +* +* PROGRAM SUBROUTINES +* +* qmdmrg. +***********************************************************************/ + +void qmdupd(int xadj[], int adjncy[], int *_nlist, int list[], + int deg[], int qsize[], int qlink[], int marker[], int rchset[], + int nbrhd[]) +{ int deg0, deg1, il, inhd, inode, irch, j, jstop, jstrt, mark, + nabor, nhdsze, node, rchsze; +# define nlist (*_nlist) + /* Find all eliminated supernodes that are adjacent to some nodes + * in the given list. Put them into (nhdsze, nbrhd). deg0 contains + * the number of nodes in the list. */ + if (nlist <= 0) return; + deg0 = 0; + nhdsze = 0; + for (il = 1; il <= nlist; il++) + { node = list[il]; + deg0 += qsize[node]; + jstrt = xadj[node]; + jstop = xadj[node+1] - 1; + for (j = jstrt; j <= jstop; j++) + { nabor = adjncy[j]; + if (marker[nabor] == 0 && deg[nabor] < 0) + { marker[nabor] = -1; + nhdsze++; + nbrhd[nhdsze] = nabor; + } + } + } + /* Merge indistinguishable nodes in the list by calling the + * subroutine qmdmrg. */ + if (nhdsze > 0) + qmdmrg(xadj, adjncy, deg, qsize, qlink, marker, °0, &nhdsze, + nbrhd, rchset, &nbrhd[nhdsze+1]); + /* Find the new degrees of the nodes that have not been merged. */ + for (il = 1; il <= nlist; il++) + { node = list[il]; + mark = marker[node]; + if (mark == 0 || mark == 1) + { marker[node] = 2; + qmdrch(&node, xadj, adjncy, deg, marker, &rchsze, rchset, + &nhdsze, nbrhd); + deg1 = deg0; + if (rchsze > 0) + { for (irch = 1; irch <= rchsze; irch++) + { inode = rchset[irch]; + deg1 += qsize[inode]; + marker[inode] = 0; + } + } + deg[node] = deg1 - 1; + if (nhdsze > 0) + { for (inhd = 1; inhd <= nhdsze; inhd++) + { inode = nbrhd[inhd]; + marker[inode] = 0; + } + } + } + } + return; +# undef nlist +} + +/*********************************************************************** +* NAME +* +* qmdmrg - Quotient MD MeRGe +* +* SYNOPSIS +* +* #include "qmd.h" +* void qmdmrg(int xadj[], int adjncy[], int deg[], int qsize[], +* int qlink[], int marker[], int *deg0, int *nhdsze, int nbrhd[], +* int rchset[], int ovrlp[]); +* +* PURPOSE +* +* This routine merges indistinguishable nodes in the minimum degree +* ordering algorithm. It also computes the new degrees of these new +* supernodes. +* +* INPUT PARAMETERS +* +* (xadj, adjncy) - +* the adjancy structure; +* deg0 - the number of nodes in the given set; +* (nhdsze, nbrhd) - +* the set of eliminated supernodes adjacent to some nodes in +* the set. +* +* UPDATED PARAMETERS +* +* deg - the degree vector; +* qsize - size of indistinguishable nodes; +* qlink - linked list for indistinguishable nodes; +* marker - the given set is given by those nodes with marker value set +* to 1. Those nodes with degree updated will have marker value +* set to 2. +* +* WORKING PARAMETERS +* +* rchset - the reachable set; +* ovrlp - temp vector to store the intersection of two reachable sets. +***********************************************************************/ + +void qmdmrg(int xadj[], int adjncy[], int deg[], int qsize[], + int qlink[], int marker[], int *_deg0, int *_nhdsze, int nbrhd[], + int rchset[], int ovrlp[]) +{ int deg1, head, inhd, iov, irch, j, jstop, jstrt, link, lnode, + mark, mrgsze, nabor, node, novrlp, rchsze, root; +# define deg0 (*_deg0) +# define nhdsze (*_nhdsze) + /* Initialization. */ + if (nhdsze <= 0) return; + for (inhd = 1; inhd <= nhdsze; inhd++) + { root = nbrhd[inhd]; + marker[root] = 0; + } + /* Loop through each eliminated supernode in the set + * (nhdsze, nbrhd). */ + for (inhd = 1; inhd <= nhdsze; inhd++) + { root = nbrhd[inhd]; + marker[root] = -1; + rchsze = 0; + novrlp = 0; + deg1 = 0; +s200: jstrt = xadj[root]; + jstop = xadj[root+1] - 1; + /* Determine the reachable set and its intersection with the + * input reachable set. */ + for (j = jstrt; j <= jstop; j++) + { nabor = adjncy[j]; + root = - nabor; + if (nabor < 0) goto s200; + if (nabor == 0) break; + mark = marker[nabor]; + if (mark == 0) + { rchsze++; + rchset[rchsze] = nabor; + deg1 += qsize[nabor]; + marker[nabor] = 1; + } + else if (mark == 1) + { novrlp++; + ovrlp[novrlp] = nabor; + marker[nabor] = 2; + } + } + /* From the overlapped set, determine the nodes that can be + * merged together. */ + head = 0; + mrgsze = 0; + for (iov = 1; iov <= novrlp; iov++) + { node = ovrlp[iov]; + jstrt = xadj[node]; + jstop = xadj[node+1] - 1; + for (j = jstrt; j <= jstop; j++) + { nabor = adjncy[j]; + if (marker[nabor] == 0) + { marker[node] = 1; + goto s1100; + } + } + /* Node belongs to the new merged supernode. Update the + * vectors qlink and qsize. */ + mrgsze += qsize[node]; + marker[node] = -1; + lnode = node; +s900: link = qlink[lnode]; + if (link > 0) + { lnode = link; + goto s900; + } + qlink[lnode] = head; + head = node; +s1100: ; + } + if (head > 0) + { qsize[head] = mrgsze; + deg[head] = deg0 + deg1 - 1; + marker[head] = 2; + } + /* Reset marker values. */ + root = nbrhd[inhd]; + marker[root] = 0; + if (rchsze > 0) + { for (irch = 1; irch <= rchsze; irch++) + { node = rchset[irch]; + marker[node] = 0; + } + } + } + return; +# undef deg0 +# undef nhdsze +} + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/qmd.h b/test/monniaux/glpk-4.65/src/misc/qmd.h new file mode 100644 index 00000000..e55d50f5 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/qmd.h @@ -0,0 +1,58 @@ +/* qmd.h (quotient minimum degree algorithm) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2001-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#ifndef QMD_H +#define QMD_H + +#define genqmd _glp_genqmd +void genqmd(int *neqns, int xadj[], int adjncy[], int perm[], + int invp[], int deg[], int marker[], int rchset[], int nbrhd[], + int qsize[], int qlink[], int *nofsub); +/* GENeral Quotient Minimum Degree algorithm */ + +#define qmdrch _glp_qmdrch +void qmdrch(int *root, int xadj[], int adjncy[], int deg[], + int marker[], int *rchsze, int rchset[], int *nhdsze, + int nbrhd[]); +/* Quotient MD ReaCHable set */ + +#define qmdqt _glp_qmdqt +void qmdqt(int *root, int xadj[], int adjncy[], int marker[], + int *rchsze, int rchset[], int nbrhd[]); +/* Quotient MD Quotient graph Transformation */ + +#define qmdupd _glp_qmdupd +void qmdupd(int xadj[], int adjncy[], int *nlist, int list[], + int deg[], int qsize[], int qlink[], int marker[], int rchset[], + int nbrhd[]); +/* Quotient MD UPDate */ + +#define qmdmrg _glp_qmdmrg +void qmdmrg(int xadj[], int adjncy[], int deg[], int qsize[], + int qlink[], int marker[], int *deg0, int *nhdsze, int nbrhd[], + int rchset[], int ovrlp[]); +/* Quotient MD MeRGe */ + +#endif + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/relax4.c b/test/monniaux/glpk-4.65/src/misc/relax4.c new file mode 100644 index 00000000..f0a47d6d --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/relax4.c @@ -0,0 +1,2850 @@ +/* relax4.c (relaxation method of Bertsekas and Tseng) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* THIS CODE IS THE RESULT OF TRANSLATION OF THE FORTRAN CODE RELAX4. +* +* THE TRANSLATION HAS BEEN DONE WITH THE PERMISSION OF THE AUTHOR OF +* THE ORIGINAL FORTRAN CODE PROF. DIMITRI P. BERTSEKAS, MASSACHUSETTS +* INSTITUTE OF TECHNOLOGY, CAMBRIDGE, MASSACHUSETTS, USA. +* +* The translation was made by Andrew Makhorin . +* +* 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 . +***********************************************************************/ + +#include "relax4.h" + +/*********************************************************************** +* WARNING +* +* A serious bug was *tentatively* fixed in this code (see #if/#endif +* marked by 'mao'). +* +* This bug is inherited from the original Fortran version of the +* RELAX-IV code. Unfortunately, the code is very intricate, so this +* bug is still under investigation. Thanks to Sylvain Fournier for bug +* report. +* +* RELAX-IV bug details +* -------------------- +* In the original RELAX-IV code there are four similar fragments in +* subroutines ascnt1 and ascnt2 like this: +* +* C +* C DECREASE THE PRICES OF THE SCANNED NODES BY DELPRC. +* C ADJUST FLOW TO MAINTAIN COMPLEMENTARY SLACKNESS WITH +* C THE PRICES. +* C +* NB = 0 +* DO 6 I=1,NSAVE +* . . . +* IF (RC(ARC).EQ.0) THEN +* DELX=DELX+U(ARC) +* NB = NB + 1 +* PRDCSR(NB) = ARC +* END IF +* . . . +* +* On some instances the variable NB becomes greater than N (the number +* of nodes) that leads to indexing error, because the array PRDCSR is +* declared as array of N elements (more precisely, as array of MAXNN +* elements, however, NB becomes even much greater than MAXNN). +***********************************************************************/ + +#define false 0 +#define true 1 + +/*********************************************************************** +* NAME +* +* RELAX-IV (version of October 1994) +* +* PURPOSE +* +* This routine implements the relaxation method of Bertsekas and Tseng +* (see [1], [2]) for linear cost ordinary network flow problems. +* +* [1] Bertsekas, D. P., "A Unified Framework for Primal-Dual Methods" +* Mathematical Programming, Vol. 32, 1985, pp. 125-145. +* [2] Bertsekas, D. P., and Tseng, P., "Relaxation Methods for +* Minimum Cost" Operations Research, Vol. 26, 1988, pp. 93-114. +* +* The relaxation method is also described in the books: +* +* [3] Bertsekas, D. P., "Linear Network Optimization: Algorithms and +* Codes" MIT Press, 1991. +* [4] Bertsekas, D. P. and Tsitsiklis, J. N., "Parallel and Distributed +* Computation: Numerical Methods", Prentice-Hall, 1989. +* [5] Bertsekas, D. P., "Network Optimization: Continuous and Discrete +* Models", Athena Scientific, 1998. +* +* RELEASE NOTE +* +* This version of relaxation code has option for a special crash +* procedure for the initial price-flow pair. This is recommended for +* difficult problems where the default initialization results in long +* running times. crash = 1 corresponds to an auction/shortest path +* method +* +* These initializations are recommended in the absence of any prior +* information on a favorable initial flow-price vector pair that +* satisfies complementary slackness. +* +* The relaxation portion of the code differs from the code RELAXT-III +* and other earlier relaxation codes in that it maintains the set of +* nodes with nonzero deficit in a fifo queue. Like its predecessor +* RELAXT-III, this code maintains a linked list of balanced (i.e., of +* zero reduced cost) arcs so to reduce the work in labeling and +* scanning. Unlike RELAXT-III, it does not use selectively shortest +* path iterations for initialization. +* +* SOURCE +* +* The original Fortran code was written by Dimitri P. Bertsekas and +* Paul Tseng, with a contribution by Jonathan Eckstein in the phase II +* initialization. The original Fortran routine AUCTION was written by +* Dimitri P. Bertsekas and is based on the method described in the +* paper: +* +* [6] Bertsekas, D. P., "An Auction/Sequential Shortest Path Algorithm +* for the Minimum Cost Flow Problem", LIDS Report P-2146, MIT, +* Nov. 1992. +* +* For inquiries about the original Fortran code, please contact: +* +* Dimitri P. Bertsekas +* Laboratory for information and decision systems +* Massachusetts Institute of Technology +* Cambridge, MA 02139 +* (617) 253-7267, dimitrib@mit.edu +* +* This code is the result of translation of the original Fortran code. +* The translation was made by Andrew Makhorin . +* +* USER GUIDELINES +* +* This routine is in the public domain to be used only for research +* purposes. It cannot be used as part of a commercial product, or to +* satisfy in any part commercial delivery requirements to government +* or industry, without prior agreement with the authors. Users are +* requested to acknowledge the authorship of the code, and the +* relaxation method. +* +* No modification should be made to this code other than the minimal +* necessary to make it compatible with specific platforms. +* +* INPUT PARAMETERS (see notes 1, 2, 4) +* +* n = number of nodes +* na = number of arcs +* large = a very large integer to represent infinity +* (see note 3) +* repeat = true if initialization is to be skipped +* (false otherwise) +* crash = 0 if default initialization is used +* 1 if auction initialization is used +* startn[j] = starting node for arc j, j = 1,...,na +* endn[j] = ending node for arc j, j = 1,...,na +* fou[i] = first arc out of node i, i = 1,...,n +* nxtou[j] = next arc out of the starting node of arc j, j = 1,...,na +* fin[i] = first arc into node i, i = 1,...,n +* nxtin[j] = next arc into the ending node of arc j, j = 1,...,na +* +* UPDATED PARAMETERS (see notes 1, 3, 4) +* +* rc[j] = reduced cost of arc j, j = 1,...,na +* u[j] = capacity of arc j on input +* and (capacity of arc j) - x[j] on output, j = 1,...,na +* dfct[i] = demand at node i on input +* and zero on output, i = 1,...,n +* +* OUTPUT PARAMETERS (see notes 1, 3, 4) +* +* x[j] = flow on arc j, j = 1,...,na +* nmultinode = number of multinode relaxation iterations in RELAX4 +* iter = number of relaxation iterations in RELAX4 +* num_augm = number of flow augmentation steps in RELAX4 +* num_ascnt = number of multinode ascent steps in RELAX4 +* nsp = number of auction/shortest path iterations +* +* WORKING PARAMETERS (see notes 1, 4, 5) +* +* label[1+n], prdcsr[1+n], save[1+na], tfstou[1+n], tnxtou[1+na], +* tfstin[1+n], tnxtin[1+na], nxtqueue[1+n], scan[1+n], mark[1+n], +* extend_arc[1+n], sb_level[1+n], sb_arc[1+n] +* +* RETURNS +* +* 0 = normal return +* 1,...,8 = problem is found to be infeasible +* +* NOTE 1 +* +* To run in limited memory systems, declare the arrays startn, endn, +* nxtin, nxtou, fin, fou, label, prdcsr, save, tfstou, tnxtou, tfstin, +* tnxtin, ddpos, ddneg, nxtqueue as short instead. +* +* NOTE 2 +* +* This routine makes no effort to initialize with a favorable x from +* amongst those flow vectors that satisfy complementary slackness with +* the initial reduced cost vector rc. If a favorable x is known, then +* it can be passed, together with the corresponding arrays u and dfct, +* to this routine directly. This, however, requires that the capacity +* tightening portion and the flow initialization portion of this +* routine (up to line labeled 90) be skipped. +* +* NOTE 3 +* +* All problem data should be less than large in magnitude, and large +* should be less than, say, 1/4 the largest int of the machine used. +* This will guard primarily against overflow in uncapacitated problems +* where the arc capacities are taken finite but very large. Note, +* however, that as in all codes operating with integers, overflow may +* occur if some of the problem data takes very large values. +* +* NOTE 4 +* +* [This note being specific to Fortran was removed.-A.M.] +* +* NOTE 5 +* +* ddpos and ddneg are arrays that give the directional derivatives for +* all positive and negative single-node price changes. These are used +* only in phase II of the initialization procedure, before the linked +* list of balanced arcs comes to play. Therefore, to reduce storage, +* they are equivalence to tfstou and tfstin, which are of the same size +* (number of nodes) and are used only after the tree comes into use. */ + +static void ascnt1(struct relax4_csa *csa, int dm, int *delx, + int *nlabel, int *feasbl, int *svitch, int nscan, int curnode, + int *prevnode); + +static void ascnt2(struct relax4_csa *csa, int dm, int *delx, + int *nlabel, int *feasbl, int *svitch, int nscan, int curnode, + int *prevnode); + +static int auction(struct relax4_csa *csa); + +int relax4(struct relax4_csa *csa) +{ /* input parameters */ + int n = csa->n; + int na = csa->na; + int large = csa->large; + int repeat = csa->repeat; + int crash = csa->crash; + int *startn = csa->startn; + int *endn = csa->endn; + int *fou = csa->fou; + int *nxtou = csa->nxtou; + int *fin = csa->fin; + int *nxtin = csa->nxtin; + /* updated parameters */ + int *rc = csa->rc; + int *u = csa->u; + int *dfct = csa->dfct; + /* output parameters */ + int *x = csa->x; +# define nmultinode (csa->nmultinode) +# define iter (csa->iter) +# define num_augm (csa->num_augm) +# define num_ascnt (csa->num_ascnt) +# define nsp (csa->nsp) + /* working parameters */ + int *label = csa->label; + int *prdcsr = csa->prdcsr; + int *save = csa->save; + int *tfstou = csa->tfstou; + int *tnxtou = csa->tnxtou; + int *tfstin = csa->tfstin; + int *tnxtin = csa->tnxtin; + int *nxtqueue = csa->nxtqueue; + char *scan = csa->scan; + char *mark = csa->mark; + int *ddpos = tfstou; + int *ddneg = tfstin; + /* local variables */ + int arc, augnod, capin, capout, defcit, delprc, delx, dm, dp, + dx, feasbl, i, ib, indef, j, lastqueue, maxcap, narc, nb, + nlabel, node, node2, node_def, naugnod, nscan, num_passes, + numnz, numnz_new, numpasses, nxtarc, nxtbrk, nxtnode, passes, + pchange, posit, prevnode, prvarc, quit, rdcost, scapin, + scapou, svitch, t, t1, t2, tmparc, tp, trc, ts; + /*--------------------------------------------------------------*/ + /* Initialization phase I */ + /* In this phase, we reduce the arc capacities by as much as + * possible without changing the problem; then we set the initial + * flow array x, together with the corresponding arrays u and + * dfct. */ + /* This phase and phase II (from here up to line labeled 90) can + * be skipped (by setting repeat to true) if the calling program + * places in common user-chosen values for the arc flows, the + * residual arc capacities, and the nodal deficits. When this is + * done, it is critical that the flow and the reduced cost for + * each arc satisfy complementary slackness and the dfct array + * properly correspond to the initial arc/flows. */ + if (repeat) + goto L90; + for (node = 1; node <= n; node++) + { node_def = dfct[node]; + ddpos[node] = node_def; + ddneg[node] = -node_def; + maxcap = 0; + scapou = 0; + for (arc = fou[node]; arc > 0; arc = nxtou[arc]) + { if (scapou <= large - u[arc]) + scapou += u[arc]; + else + goto L10; + } + if (scapou <= large - node_def) + capout = scapou + node_def; + else + goto L10; + if (capout < 0) + { /* problem is infeasible */ + /* exogenous flow into node exceeds out capacity */ + return 1; + } + scapin = 0; + for (arc = fin[node]; arc > 0; arc = nxtin[arc]) + { if (u[arc] > capout) + u[arc] = capout; + if (maxcap < u[arc]) + maxcap = u[arc]; + if (scapin <= large - u[arc]) + scapin += u[arc]; + else + goto L10; + } + if (scapin <= large + node_def) + capin = scapin - node_def; + else + goto L10; + if (capin < 0) + { /* problem is infeasible */ + /* exogenous flow out of node exceeds in capacity */ + return 2; + } + for (arc = fou[node]; arc > 0; arc = nxtou[arc]) + { if (u[arc] > capin) + u[arc] = capin; + } +L10: ; + } + /*--------------------------------------------------------------*/ + /* Initialization phase II */ + /* In this phase, we initialize the prices and flows by either + * calling the routine auction or by performing only single node + * (coordinate) relaxation iterations. */ + if (crash == 1) + { nsp = 0; + if (auction(csa) != 0) + { /* problem is found to be infeasible */ + return 3; + } + goto L70; + } + /* Initialize the arc flows to satisfy complementary slackness + * with the prices. u[arc] is the residual capacity of arc, and + * x[arc] is the flow. These two always add up to the total + * capacity for arc. Also compute the directional derivatives for + * each coordinate and compute the actual deficits. */ + for (arc = 1; arc <= na; arc++) + { x[arc] = 0; + if (rc[arc] <= 0) + { t = u[arc]; + t1 = startn[arc]; + t2 = endn[arc]; + ddpos[t1] += t; + ddneg[t2] += t; + if (rc[arc] < 0) + { x[arc] = t; + u[arc] = 0; + dfct[t1] += t; + dfct[t2] -= t; + ddneg[t1] -= t; + ddpos[t2] -= t; + } + } + } + /* Make 2 or 3 passes through all nodes, performing only single + * node relaxation iterations. The number of passes depends on the + * density of the network. */ + if (na > n * 10) + numpasses = 2; + else + numpasses = 3; + for (passes = 1; passes <= numpasses; passes++) + for (node = 1; node <= n; node++) + { if (dfct[node] == 0) + continue; + if (ddpos[node] <= 0) + { /* Compute delprc, the stepsize to the next breakpoint in + * the dual cost as the price of node is increased. + * [Since the reduced cost of all outgoing (resp., incoming) + * arcs will decrease (resp., increase) as the price of node + * is increased, the next breakpoint is the minimum of the + * positive reduced cost on outgoing arcs and of the + * negative reduced cost on incoming arcs.] */ + delprc = large; + for (arc = fou[node]; arc > 0; arc = nxtou[arc]) + { trc = rc[arc]; + if ((trc > 0) && (trc < delprc)) + delprc = trc; + } + for (arc = fin[node]; arc > 0; arc = nxtin[arc]) + { trc = rc[arc]; + if ((trc < 0) && (trc > -delprc)) + delprc = -trc; + } + /* If no breakpoint is left and dual ascent is still + * possible, the problem is infeasible. */ + if (delprc >= large) + { if (ddpos[node] == 0) + continue; + return 4; + } + /* delprc is the stepsize to next breakpoint. Increase + * price of node by delprc and compute the stepsize to the + * next breakpoint in the dual cost. */ +L53: nxtbrk = large; + /* Look at all arcs out of node. */ + for (arc = fou[node]; arc > 0; arc = nxtou[arc]) + { trc = rc[arc]; + if (trc == 0) + { t1 = endn[arc]; + t = u[arc]; + if (t > 0) + { dfct[node] += t; + dfct[t1] -= t; + x[arc] = t; + u[arc] = 0; + } + else + t = x[arc]; + ddneg[node] -= t; + ddpos[t1] -= t; + } + /* Decrease the reduced costs on all outgoing arcs. */ + trc -= delprc; + if ((trc > 0) && (trc < nxtbrk)) + nxtbrk = trc; + else if (trc == 0) + { /* Arc goes from inactive to balanced. Update the rate + * of dual ascent at node and at its neighbor. */ + ddpos[node] += u[arc]; + ddneg[endn[arc]] += u[arc]; + } + rc[arc] = trc; + } + /* Look at all arcs into node. */ + for (arc = fin[node]; arc > 0; arc = nxtin[arc]) + { trc = rc[arc]; + if (trc == 0) + { t1 = startn[arc]; + t = x[arc]; + if (t > 0) + { dfct[node] += t; + dfct[t1] -= t; + u[arc] = t; + x[arc] = 0; + } + else + t = u[arc]; + ddpos[t1] -= t; + ddneg[node] -= t; + } + /* Increase the reduced cost on all incoming arcs. */ + trc += delprc; + if ((trc < 0) && (trc > -nxtbrk)) + nxtbrk = -trc; + else if (trc == 0) + { /* Arc goes from active to balanced. Update the rate + * of dual ascent at node and at its neighbor. */ + ddneg[startn[arc]] += x[arc]; + ddpos[node] += x[arc]; + } + rc[arc] = trc; + } + /* If price of node can be increased further without + * decreasing the dual cost (even the dual cost doesn't + * increase), return to increase the price further. */ + if ((ddpos[node] <= 0) && (nxtbrk < large)) + { delprc = nxtbrk; + goto L53; + } + } + else if (ddneg[node] <= 0) + { /* Compute delprc, the stepsize to the next breakpoint in + * the dual cost as the price of node is decreased. + * [Since the reduced cost of all outgoing (resp., incoming) + * arcs will increase (resp., decrease) as the price of node + * is decreased, the next breakpoint is the minimum of the + * negative reduced cost on outgoing arcs and of the + * positive reduced cost on incoming arcs.] */ + delprc = large; + for (arc = fou[node]; arc > 0; arc = nxtou[arc]) + { trc = rc[arc]; + if ((trc < 0) && (trc > -delprc)) + delprc = -trc; + } + for (arc = fin[node]; arc > 0; arc = nxtin[arc]) + { trc = rc[arc]; + if ((trc > 0) && (trc < delprc)) + delprc = trc; + } + /* If no breakpoint is left and dual ascent is still + * possible, the problem is infeasible. */ + if (delprc == large) + { if (ddneg[node] == 0) + continue; + return 5; + } + /* delprc is the stepsize to next breakpoint. Decrease + * price of node by delprc and compute the stepsize to the + * next breakpoint in the dual cost. */ +L63: nxtbrk = large; + /* Look at all arcs out of node. */ + for (arc = fou[node]; arc > 0; arc = nxtou[arc]) + { trc = rc[arc]; + if (trc == 0) + { t1 = endn[arc]; + t = x[arc]; + if (t > 0) + { dfct[node] -= t; + dfct[t1] += t; + u[arc] = t; + x[arc] = 0; + } + else + t = u[arc]; + ddpos[node] -= t; + ddneg[t1] -= t; + } + /* Increase the reduced cost on all outgoing arcs. */ + trc += delprc; + if ((trc < 0) && (trc > -nxtbrk)) + nxtbrk = -trc; + else if (trc == 0) + { /* Arc goes from active to balanced. Update the rate + * of dual ascent at node and at its neighbor. */ + ddneg[node] += x[arc]; + ddpos[endn[arc]] += x[arc]; + } + rc[arc] = trc; + } + /* Look at all arcs into node. */ + for (arc = fin[node]; arc > 0; arc = nxtin[arc]) + { trc = rc[arc]; + if (trc == 0) + { t1 = startn[arc]; + t = u[arc]; + if (t > 0) + { dfct[node] -= t; + dfct[t1] += t; + x[arc] = t; + u[arc] = 0; + } + else + t = x[arc]; + ddneg[t1] -= t; + ddpos[node] -= t; + } + /* Decrease the reduced cost on all incoming arcs. */ + trc -= delprc; + if ((trc > 0) && (trc < nxtbrk)) + nxtbrk = trc; + else if (trc == 0) + { /* Arc goes from inactive to balanced. Update the rate + * of dual ascent at node and at its neighbor. */ + ddpos[startn[arc]] += u[arc]; + ddneg[node] += u[arc]; + } + rc[arc] = trc; + } + /* If price of node can be decreased further without + * decreasing the dual cost (even the dual cost doesn't + * increase), return to decrease the price further. */ + if ((ddneg[node] <= 0) && (nxtbrk < large)) + { delprc = nxtbrk; + goto L63; + } + } + } + /*--------------------------------------------------------------*/ +L70: /* Initialize tree data structure. */ + for (i = 1; i <= n; i++) + tfstou[i] = tfstin[i] = 0; + for (i = 1; i <= na; i++) + { tnxtin[i] = tnxtou[i] = -1; + if (rc[i] == 0) + { tnxtou[i] = tfstou[startn[i]]; + tfstou[startn[i]] = i; + tnxtin[i] = tfstin[endn[i]]; + tfstin[endn[i]] = i; + } + } +L90: /* Initialize other variables. */ + feasbl = true; + iter = 0; + nmultinode = 0; + num_augm = 0; + num_ascnt = 0; + num_passes = 0; + numnz = n; + numnz_new = 0; + svitch = false; + for (i = 1; i <= n; i++) + mark[i] = scan[i] = false; + nlabel = 0; + /* RELAX4 uses an adaptive strategy to decide whether to continue + * the scanning process after a multinode price change. + * The threshold parameter tp and ts that control this strategy + * are set in the next two lines. */ + tp = 10; + ts = n / 15; + /* Initialize the queue of nodes with nonzero deficit. */ + for (node = 1; node <= n - 1; node++) + nxtqueue[node] = node + 1; + nxtqueue[n] = 1; + node = lastqueue = n; + /*--------------------------------------------------------------*/ + /* Start the relaxation algorithm. */ +L100: /* Code for advancing the queue of nonzero deficit nodes. */ + prevnode = node; + node = nxtqueue[node]; + defcit = dfct[node]; + if (node == lastqueue) + { numnz = numnz_new; + numnz_new = 0; + lastqueue = prevnode; + num_passes++; + } + /* Code for deleting a node from the queue. */ + if (defcit == 0) + { nxtnode = nxtqueue[node]; + if (node == nxtnode) + return 0; + else + { nxtqueue[prevnode] = nxtnode; + nxtqueue[node] = 0; + node = nxtnode; + goto L100; + } + } + else + posit = (defcit > 0); + iter++; + numnz_new++; + if (posit) + { /* Attempt a single node iteration from node with positive + * deficit. */ + pchange = false; + indef = defcit; + delx = 0; + nb = 0; + /* Check outgoing (probably) balanced arcs from node. */ + for (arc = tfstou[node]; arc > 0; arc = tnxtou[arc]) + { if ((rc[arc] == 0) && (x[arc] > 0)) + { delx += x[arc]; + nb++; + save[nb] = arc; + } + } + /* Check incoming arcs. */ + for (arc = tfstin[node]; arc > 0; arc = tnxtin[arc]) + { if ((rc[arc] == 0) && (u[arc] > 0)) + { delx += u[arc]; + nb++; + save[nb] = -arc; + } + } + /* End of initial node scan. */ +L4018: /* If no price change is possible, exit. */ + if (delx > defcit) + { quit = (defcit < indef); + goto L4016; + } + /* RELAX4 searches along the ascent direction for the best + * price by checking the slope of the dual cost at successive + * break points. First, we compute the distance to the next + * break point. */ + delprc = large; + for (arc = fou[node]; arc > 0; arc = nxtou[arc]) + { rdcost = rc[arc]; + if ((rdcost < 0) && (rdcost > -delprc)) + delprc = -rdcost; + } + for (arc = fin[node]; arc > 0; arc = nxtin[arc]) + { rdcost = rc[arc]; + if ((rdcost > 0) && (rdcost < delprc)) + delprc = rdcost; + } + /* Check if problem is infeasible. */ + if ((delx < defcit) && (delprc == large)) + { /* The dual cost can be decreased without bound. */ + return 6; + } + /* Skip flow adjustment if there is no flow to modify. */ + if (delx == 0) + goto L4014; + /* Adjust the flow on the balanced arcs incident to node to + * maintain complementary slackness after the price change. */ + for (j = 1; j <= nb; j++) + { arc = save[j]; + if (arc > 0) + { node2 = endn[arc]; + t1 = x[arc]; + dfct[node2] += t1; + if (nxtqueue[node2] == 0) + { nxtqueue[prevnode] = node2; + nxtqueue[node2] = node; + prevnode = node2; + } + u[arc] += t1; + x[arc] = 0; + } + else + { narc = -arc; + node2 = startn[narc]; + t1 = u[narc]; + dfct[node2] += t1; + if (nxtqueue[node2] == 0) + { nxtqueue[prevnode] = node2; + nxtqueue[node2] = node; + prevnode = node2; + } + x[narc] += t1; + u[narc] = 0; + } + } + defcit -= delx; +L4014: if (delprc == large) + { quit = true; + goto L4019; + } + /* Node corresponds to a dual ascent direction. Decrease the + * price of node by delprc and compute the stepsize to the next + * breakpoint in the dual cost. */ + nb = 0; + pchange = true; + dp = delprc; + delprc = large; + delx = 0; + for (arc = fou[node]; arc > 0; arc = nxtou[arc]) + { rdcost = rc[arc] + dp; + rc[arc] = rdcost; + if (rdcost == 0) + { nb++; + save[nb] = arc; + delx += x[arc]; + } + if ((rdcost < 0) && (rdcost > -delprc)) + delprc = -rdcost; + } + for (arc = fin[node]; arc > 0; arc = nxtin[arc]) + { rdcost = rc[arc] - dp; + rc[arc] = rdcost; + if (rdcost == 0) + { nb++; + save[nb] = -arc; + delx += u[arc]; + } + if ((rdcost > 0) && (rdcost < delprc)) + delprc = rdcost; + } + /* Return to check if another price change is possible. */ + goto L4018; +L4016: /* Perform flow augmentation at node. */ + for (j = 1; j <= nb; j++) + { arc = save[j]; + if (arc > 0) + { /* arc is an outgoing arc from node. */ + node2 = endn[arc]; + t1 = dfct[node2]; + if (t1 < 0) + { /* Decrease the total deficit by decreasing flow of + * arc. */ + quit = true; + t2 = x[arc]; + dx = defcit; + if (dx > -t1) dx = -t1; + if (dx > t2) dx = t2; + defcit -= dx; + dfct[node2] = t1 + dx; + if (nxtqueue[node2] == 0) + { nxtqueue[prevnode] = node2; + nxtqueue[node2] = node; + prevnode = node2; + } + x[arc] = t2 - dx; + u[arc] += dx; + if (defcit == 0) + break; + } + } + else + { /* -arc is an incoming arc to node. */ + narc = -arc; + node2 = startn[narc]; + t1 = dfct[node2]; + if (t1 < 0) + { /* Decrease the total deficit by increasing flow of + * -arc. */ + quit = true; + t2 = u[narc]; + dx = defcit; + if (dx > -t1) dx = -t1; + if (dx > t2) dx = t2; + defcit -= dx; + dfct[node2] = t1 + dx; + if (nxtqueue[node2] == 0) + { nxtqueue[prevnode] = node2; + nxtqueue[node2] = node; + prevnode = node2; + } + x[narc] += dx; + u[narc] = t2 - dx; + if (defcit == 0) + break; + } + } + } +L4019: dfct[node] = defcit; + /* Reconstruct the linked list of balance arcs incident to this + * node. For each adjacent node, we add any newly balanced arcs + * to the list, but do not bother removing formerly balanced + * ones (they will be removed the next time each adjacent node + * is scanned). */ + if (pchange) + { arc = tfstou[node]; + tfstou[node] = 0; + while (arc > 0) + { nxtarc = tnxtou[arc]; + tnxtou[arc] = -1; + arc = nxtarc; + } + arc = tfstin[node]; + tfstin[node] = 0; + while (arc > 0) + { nxtarc = tnxtin[arc]; + tnxtin[arc] = -1; + arc = nxtarc; + } + /* Now add the currently balanced arcs to the list for this + * node (which is now empty), and the appropriate adjacent + * ones. */ + for (j = 1; j <= nb; j++) + { arc = save[j]; + if (arc < 0) + arc = -arc; + if (tnxtou[arc] < 0) + { tnxtou[arc] = tfstou[startn[arc]]; + tfstou[startn[arc]] = arc; + } + if (tnxtin[arc] < 0) + { tnxtin[arc] = tfstin[endn[arc]]; + tfstin[endn[arc]] = arc; + } + } + } + /* End of single node iteration for positive deficit node. */ + } + else + { /* Attempt a single node iteration from node with negative + * deficit. */ + pchange = false; + defcit = -defcit; + indef = defcit; + delx = 0; + nb = 0; + for (arc = tfstin[node]; arc > 0; arc = tnxtin[arc]) + { if ((rc[arc] == 0) && (x[arc] > 0)) + { delx += x[arc]; + nb++; + save[nb] = arc; + } + } + for (arc = tfstou[node]; arc > 0; arc = tnxtou[arc]) + { if ((rc[arc] == 0) && (u[arc] > 0)) + { delx += u[arc]; + nb++; + save[nb] = -arc; + } + } +L4028: if (delx >= defcit) + { quit = (defcit < indef); + goto L4026; + } + /* Compute distance to next breakpoint. */ + delprc = large; + for (arc = fin[node]; arc > 0; arc = nxtin[arc]) + { rdcost = rc[arc]; + if ((rdcost < 0) && (rdcost > -delprc)) + delprc = -rdcost; + } + for (arc = fou[node]; arc > 0; arc = nxtou[arc]) + { rdcost = rc[arc]; + if ((rdcost > 0) && (rdcost < delprc)) + delprc = rdcost; + } + /* Check if problem is infeasible. */ + if ((delx < defcit) && (delprc == large)) + return 7; + if (delx == 0) + goto L4024; + /* Flow augmentation is possible. */ + for (j = 1; j <= nb; j++) + { arc = save[j]; + if (arc > 0) + { node2 = startn[arc]; + t1 = x[arc]; + dfct[node2] -= t1; + if (nxtqueue[node2] == 0) + { nxtqueue[prevnode] = node2; + nxtqueue[node2] = node; + prevnode = node2; + } + u[arc] += t1; + x[arc] = 0; + } + else + { narc = -arc; + node2 = endn[narc]; + t1 = u[narc]; + dfct[node2] -= t1; + if (nxtqueue[node2] == 0) + { nxtqueue[prevnode] = node2; + nxtqueue[node2] = node; + prevnode = node2; + } + x[narc] += t1; + u[narc] = 0; + } + } + defcit -= delx; +L4024: if (delprc == large) + { quit = true; + goto L4029; + } + /* Price increase at node is possible. */ + nb = 0; + pchange = true; + dp = delprc; + delprc = large; + delx = 0; + for (arc = fin[node]; arc > 0; arc = nxtin[arc]) + { rdcost = rc[arc] + dp; + rc[arc] = rdcost; + if (rdcost == 0) + { nb++; + save[nb] = arc; + delx += x[arc]; + } + if ((rdcost < 0) && (rdcost > -delprc)) + delprc = -rdcost; + } + for (arc = fou[node]; arc > 0; arc = nxtou[arc]) + { rdcost = rc[arc] - dp; + rc[arc] = rdcost; + if (rdcost == 0) + { nb++; + save[nb] = -arc; + delx += u[arc]; + } + if ((rdcost > 0) && (rdcost < delprc)) + delprc = rdcost; + } + goto L4028; +L4026: /* Perform flow augmentation at node. */ + for (j = 1; j <= nb; j++) + { arc = save[j]; + if (arc > 0) + { /* arc is an incoming arc to node. */ + node2 = startn[arc]; + t1 = dfct[node2]; + if (t1 > 0) + { quit = true; + t2 = x[arc]; + dx = defcit; + if (dx > t1) dx = t1; + if (dx > t2) dx = t2; + defcit -= dx; + dfct[node2] = t1 - dx; + if (nxtqueue[node2] == 0) + { nxtqueue[prevnode] = node2; + nxtqueue[node2] = node; + prevnode = node2; + } + x[arc] = t2 - dx; + u[arc] += dx; + if (defcit == 0) + break; + } + } + else + { /* -arc is an outgoing arc from node. */ + narc = -arc; + node2 = endn[narc]; + t1 = dfct[node2]; + if (t1 > 0) + { quit = true; + t2 = u[narc]; + dx = defcit; + if (dx > t1) dx = t1; + if (dx > t2) dx = t2; + defcit -= dx; + dfct[node2] = t1 - dx; + if (nxtqueue[node2] == 0) + { nxtqueue[prevnode] = node2; + nxtqueue[node2] = node; + prevnode = node2; + } + x[narc] += dx; + u[narc] = t2 - dx; + if (defcit == 0) + break; + } + } + } +L4029: dfct[node] = -defcit; + /* Reconstruct the list of balanced arcs incident to node. */ + if (pchange) + { arc = tfstou[node]; + tfstou[node] = 0; + while (arc > 0) + { nxtarc = tnxtou[arc]; + tnxtou[arc] = -1; + arc = nxtarc; + } + arc = tfstin[node]; + tfstin[node] = 0; + while (arc > 0) + { nxtarc = tnxtin[arc]; + tnxtin[arc] = -1; + arc = nxtarc; + } + /* Now add the currently balanced arcs to the list for this + * node (which is now empty), and the appropriate adjacent + * ones. */ + for (j = 1; j <= nb; j++) + { arc = save[j]; + if (arc <= 0) + arc = -arc; + if (tnxtou[arc] < 0) + { tnxtou[arc] = tfstou[startn[arc]]; + tfstou[startn[arc]] = arc; + } + if (tnxtin[arc] < 0) + { tnxtin[arc] = tfstin[endn[arc]]; + tfstin[endn[arc]] = arc; + } + } + } + /* End of single node iteration for a negative deficit node. */ + } + if (quit || (num_passes <= 3)) + goto L100; + /* Do a multinode iteration from node. */ + nmultinode++; + /* If number of nonzero deficit nodes is small, continue labeling + * until a flow augmentation is done. */ + svitch = (numnz < tp); + /* Unmark nodes labeled earlier. */ + for (j = 1; j <= nlabel; j++) + { node2 = label[j]; + mark[node2] = scan[node2] = false; + } + /* Initialize labeling. */ + nlabel = 1; + label[1] = node; + mark[node] = true; + prdcsr[node] = 0; + /* Scan starting node. */ + scan[node] = true; + nscan = 1; + dm = dfct[node]; + delx = 0; + for (j = 1; j <= nb; j++) + { arc = save[j]; + if (arc > 0) + { if (posit) + node2 = endn[arc]; + else + node2 = startn[arc]; + if (!mark[node2]) + { nlabel++; + label[nlabel] = node2; + prdcsr[node2] = arc; + mark[node2] = true; + delx += x[arc]; + } + } + else + { narc = -arc; + if (posit) + node2 = startn[narc]; + else + node2 = endn[narc]; + if (!mark[node2]) + { nlabel++; + label[nlabel] = node2; + prdcsr[node2] = arc; + mark[node2] = true; + delx += u[narc]; + } + } + } +L4120:/* Start scanning a labeled but unscanned node. */ + nscan++; + /* Check to see if switch needs to be set to true so to continue + * scanning even after a price change. */ + svitch = svitch || ((nscan > ts) && (numnz < ts)); + /* Scanning will continue until either an overestimate of the + * residual capacity across the cut corresponding to the scanned + * set of nodes (called delx) exceeds the absolute value of the + * total deficit of the scanned nodes (called dm), or else an + * augmenting path is found. Arcs that are in the tree but are not + * balanced are removed as part of the scanning process. */ + i = label[nscan]; + scan[i] = true; + naugnod = 0; + if (posit) + { /* Scanning node i in case of positive deficit. */ + prvarc = 0; + arc = tfstou[i]; + while (arc > 0) + { /* arc is an outgoing arc from node. */ + if (rc[arc] == 0) + { if (x[arc] > 0) + { node2 = endn[arc]; + if (!mark[node2]) + { /* node2 is not labeled, so add node2 to the + labeled set. */ + prdcsr[node2] = arc; + if (dfct[node2] < 0) + { naugnod++; + save[naugnod] = node2; + } + nlabel++; + label[nlabel] = node2; + mark[node2] = true; + delx += x[arc]; + } + } + prvarc = arc; + arc = tnxtou[arc]; + } + else + { tmparc = arc; + arc = tnxtou[arc]; + tnxtou[tmparc] = -1; + if (prvarc == 0) + tfstou[i] = arc; + else + tnxtou[prvarc] = arc; + } + } + prvarc = 0; + arc = tfstin[i]; + while (arc > 0) + { /* arc is an incoming arc into node. */ + if (rc[arc] == 0) + { if (u[arc] > 0) + { node2 = startn[arc]; + if (!mark[node2]) + { /* node2 is not labeled, so add node2 to the + * labeled set. */ + prdcsr[node2] = -arc; + if (dfct[node2] < 0) + { naugnod++; + save[naugnod] = node2; + } + nlabel++; + label[nlabel] = node2; + mark[node2] = true; + delx += u[arc]; + } + } + prvarc = arc; + arc = tnxtin[arc]; + } + else + { tmparc = arc; + arc = tnxtin[arc]; + tnxtin[tmparc] = -1; + if (prvarc == 0) + tfstin[i] = arc; + else + tnxtin[prvarc] = arc; + } + } + /* Correct the residual capacity of the scanned node cut. */ + arc = prdcsr[i]; + if (arc > 0) + delx -= x[arc]; + else + delx -= u[-arc]; + /* End of scanning of node i for positive deficit case. */ + } + else + { /* Scanning node i for negative deficit case. */ + prvarc = 0; + arc = tfstin[i]; + while (arc > 0) + { if (rc[arc] == 0) + { if (x[arc] > 0) + { node2 = startn[arc]; + if (!mark[node2]) + { prdcsr[node2] = arc; + if (dfct[node2] > 0) + { naugnod++; + save[naugnod] = node2; + } + nlabel++; + label[nlabel] = node2; + mark[node2] = true; + delx += x[arc]; + } + } + prvarc = arc; + arc = tnxtin[arc]; + } + else + { tmparc = arc; + arc = tnxtin[arc]; + tnxtin[tmparc] = -1; + if (prvarc == 0) + tfstin[i] = arc; + else + tnxtin[prvarc] = arc; + } + } + prvarc = 0; + arc = tfstou[i]; + while (arc > 0) + { if (rc[arc] == 0) + { if (u[arc] > 0) + { node2 = endn[arc]; + if (!mark[node2]) + { prdcsr[node2] = -arc; + if (dfct[node2] > 0) + { naugnod++; + save[naugnod] = node2; + } + nlabel++; + label[nlabel] = node2; + mark[node2] = true; + delx += u[arc]; + } + } + prvarc = arc; + arc = tnxtou[arc]; + } + else + { tmparc = arc; + arc = tnxtou[arc]; + tnxtou[tmparc] = -1; + if (prvarc == 0) + tfstou[i] = arc; + else + tnxtou[prvarc] = arc; + } + } + arc = prdcsr[i]; + if (arc > 0) + delx -= x[arc]; + else + delx -= u[-arc]; + } + /* Add deficit of node scanned to dm. */ + dm += dfct[i]; + /* Check if the set of scanned nodes correspond to a dual ascent + * direction; if yes, perform a price adjustment step, otherwise + * continue labeling. */ + if (nscan < nlabel) + { if (svitch) + goto L4210; + if ((delx >= dm) && (delx >= -dm)) + goto L4210; + } + /* Try a price change. + * [Note that since delx - abs(dm) is an overestimate of ascent + * slope, we may occasionally try a direction that is not an + * ascent direction. In this case the ascnt routines return with + * quit = false, so we continue labeling nodes.] */ + if (posit) + { ascnt1(csa, dm, &delx, &nlabel, &feasbl, &svitch, nscan, node, + &prevnode); + num_ascnt++; + } + else + { ascnt2(csa, dm, &delx, &nlabel, &feasbl, &svitch, nscan, node, + &prevnode); + num_ascnt++; + } + if (!feasbl) + return 8; + if (!svitch) + goto L100; + /* Store those newly labeled nodes to which flow augmentation is + * possible. */ + naugnod = 0; + for (j = nscan + 1; j <= nlabel; j++) + { node2 = label[j]; + if (posit && (dfct[node2] < 0)) + { naugnod++; + save[naugnod] = node2; + } + else if ((!posit) && (dfct[node2] > 0)) + { naugnod++; + save[naugnod] = node2; + } + } +L4210:/* Check if flow augmentation is possible. If not, return to scan + * another node. */ + if (naugnod == 0) + goto L4120; + for (j = 1; j <= naugnod; j++) + { num_augm++; + augnod = save[j]; + if (posit) + { /* Do the augmentation from node with positive deficit. */ + dx = -dfct[augnod]; + ib = augnod; + while (ib != node) + { arc = prdcsr[ib]; + if (arc > 0) + { if (dx > x[arc]) dx = x[arc]; + ib = startn[arc]; + } + else + { if (dx > u[-arc]) dx = u[-arc]; + ib = endn[-arc]; + } + } + if (dx > dfct[node]) dx = dfct[node]; + if (dx > 0) + { /* Increase (decrease) the flow of all forward (backward) + * arcs in the flow augmenting path. Adjust node deficit + * accordingly. */ + if (nxtqueue[augnod] == 0) + { nxtqueue[prevnode] = augnod; + nxtqueue[augnod] = node; + prevnode = augnod; + } + dfct[augnod] += dx; + dfct[node] -= dx; + ib = augnod; + while (ib != node) + { arc = prdcsr[ib]; + if (arc > 0) + { x[arc] -= dx; + u[arc] += dx; + ib = startn[arc]; + } + else + { narc = -arc; + x[narc] += dx; + u[narc] -= dx; + ib = endn[narc]; + } + } + } + } + else + { /* Do the augmentation from node with negative deficit. */ + dx = dfct[augnod]; + ib = augnod; + while (ib != node) + { arc = prdcsr[ib]; + if (arc > 0) + { if (dx > x[arc]) dx = x[arc]; + ib = endn[arc]; + } + else + { if (dx > u[-arc]) dx = u[-arc]; + ib = startn[-arc]; + } + } + if (dx > -dfct[node]) dx = -dfct[node]; + if (dx > 0) + { /* Update the flow and deficits. */ + if (nxtqueue[augnod] == 0) + { nxtqueue[prevnode] = augnod; + nxtqueue[augnod] = node; + prevnode = augnod; + } + dfct[augnod] -= dx; + dfct[node] += dx; + ib = augnod; + while (ib != node) + { arc = prdcsr[ib]; + if (arc > 0) + { x[arc] -= dx; + u[arc] += dx; + ib = endn[arc]; + } + else + { narc = -arc; + x[narc] += dx; + u[narc] -= dx; + ib = startn[narc]; + } + } + } + } + if (dfct[node] == 0) + goto L100; + if (dfct[augnod] != 0) + svitch = false; + } + /* If node still has nonzero deficit and all newly labeled nodes + * have same sign for their deficit as node, we can continue + * labeling. In this case, continue labeling only when flow + * augmentation is done relatively infrequently. */ + if (svitch && (iter > 8 * num_augm)) + goto L4120; + /* Return to do another relaxation iteration. */ + goto L100; +# undef nmultinode +# undef iter +# undef num_augm +# undef num_ascnt +# undef nsp +} + +/*********************************************************************** +* NAME +* +* relax4_inidat - construct linked lists for network topology +* +* PURPOSE +* +* This routine constructs two linked lists for the network topology: +* one list (given by fou, nxtou) for the outgoing arcs of nodes and +* one list (given by fin, nxtin) for the incoming arcs of nodes. These +* two lists are required by RELAX4. +* +* INPUT PARAMETERS +* +* n = number of nodes +* na = number of arcs +* startn[j] = starting node for arc j, j = 1,...,na +* endn[j] = ending node for arc j, j = 1,...,na +* +* OUTPUT PARAMETERS +* +* fou[i] = first arc out of node i, i = 1,...,n +* nxtou[j] = next arc out of the starting node of arc j, j = 1,...,na +* fin[i] = first arc into node i, i = 1,...,n +* nxtin[j] = next arc into the ending node of arc j, j = 1,...,na +* +* WORKING PARAMETERS +* +* tempin[1+n], tempou[1+n] */ + +void relax4_inidat(struct relax4_csa *csa) +{ /* input parameters */ + int n = csa->n; + int na = csa->na; + int *startn = csa->startn; + int *endn = csa->endn; + /* output parameters */ + int *fou = csa->fou; + int *nxtou = csa->nxtou; + int *fin = csa->fin; + int *nxtin = csa->nxtin; + /* working parameters */ + int *tempin = csa->label; + int *tempou = csa->prdcsr; + /* local variables */ + int i, i1, i2; + for (i = 1; i <= n; i++) + { fin[i] = fou[i] = 0; + tempin[i] = tempou[i] = 0; + } + for (i = 1; i <= na; i++) + { nxtin[i] = nxtou[i] = 0; + i1 = startn[i]; + i2 = endn[i]; + if (fou[i1] != 0) + nxtou[tempou[i1]] = i; + else + fou[i1] = i; + tempou[i1] = i; + if (fin[i2] != 0) + nxtin[tempin[i2]] = i; + else + fin[i2] = i; + tempin[i2] = i; + } + return; +} + +/*********************************************************************** +* NAME +* +* ascnt1 - multi-node price adjustment for positive deficit case +* +* PURPOSE +* +* This subroutine performs the multi-node price adjustment step for +* the case where the scanned nodes have positive deficit. It first +* checks if decreasing the price of the scanned nodes increases the +* dual cost. If yes, then it decreases the price of all scanned nodes. +* There are two possibilities for price decrease: if switch = true, +* then the set of scanned nodes corresponds to an elementary direction +* of maximal rate of ascent, in which case the price of all scanned +* nodes are decreased until the next breakpoint in the dual cost is +* encountered. At this point, some arc becomes balanced and more +* node(s) are added to the labeled set and the subroutine is exited. +* If switch = false, then the price of all scanned nodes are decreased +* until the rate of ascent becomes negative (this corresponds to the +* price adjustment step in which both the line search and the +* degenerate ascent iteration are implemented). +* +* INPUT PARAMETERS +* +* dm = total deficit of scanned nodes +* switch = true if labeling is to continue after price change +* nscan = number of scanned nodes +* curnode = most recently scanned node +* n = number of nodes +* na = number of arcs +* large = a very large integer to represent infinity (see note 3) +* startn[i] = starting node for the i-th arc, i = 1,...,na +* endn[i] = ending node for the i-th arc, i = 1,...,na +* fou[i] = first arc leaving i-th node, i = 1,...,n +* nxtou[i] = next arc leaving the starting node of j-th arc, +* i = 1,...,na +* fin[i] = first arc entering i-th node, i = 1,...,n +* nxtin[i] = next arc entering the ending node of j-th arc, +* i = 1,...,na +* +* UPDATED PARAMETERS +* +* delx = a lower estimate of the total flow on balanced arcs in +* the scanned-nodes cut +* nlabel = number of labeled nodes +* feasbl = false if problem is found to be infeasible +* prevnode = the node before curnode in queue +* rc[j] = reduced cost of arc j, j = 1,...,na +* u[j] = residual capacity of arc j, j = 1,...,na +* x[j] = flow on arc j, j = 1,...,na +* dfct[i] = deficit at node i, i = 1,...,n +* label[k] = k-th node labeled, k = 1,...,nlabel +* prdcsr[i] = predecessor of node i in tree of labeled nodes (0 if i +* is unlabeled), i = 1,...,n +* tfstou[i] = first balanced arc out of node i, i = 1,...,n +* tnxtou[j] = next balanced arc out of the starting node of arc j, +* j = 1,...,na +* tfstin[i] = first balanced arc into node i, i = 1,...,n +* tnxtin[j] = next balanced arc into the ending node of arc j, +* j = 1,...,na +* nxtqueue[i] = node following node i in the fifo queue (0 if node is +* not in the queue), i = 1,...,n +* scan[i] = true if node i is scanned, i = 1,...,n +* mark[i] = true if node i is labeled, i = 1,...,n +* +* WORKING PARAMETERS +* +* save[1+na] */ + +static void ascnt1(struct relax4_csa *csa, int dm, int *delx, + int *nlabel, int *feasbl, int *svitch, int nscan, int curnode, + int *prevnode) +{ /* input parameters */ + int n = csa->n; + /* int na = csa->na; */ + int large = csa->large; + int *startn = csa->startn; + int *endn = csa->endn; + int *fou = csa->fou; + int *nxtou = csa->nxtou; + int *fin = csa->fin; + int *nxtin = csa->nxtin; + /* updated parameters */ +# define delx (*delx) +# define nlabel (*nlabel) +# define feasbl (*feasbl) +# define svitch (*svitch) +# define prevnode (*prevnode) + int *rc = csa->rc; + int *u = csa->u; + int *x = csa->x; + int *dfct = csa->dfct; + int *label = csa->label; + int *prdcsr = csa->prdcsr; + int *tfstou = csa->tfstou; + int *tnxtou = csa->tnxtou; + int *tfstin = csa->tfstin; + int *tnxtin = csa->tnxtin; + int *nxtqueue = csa->nxtqueue; + char *scan = csa->scan; + char *mark = csa->mark; + int *save = csa->save; + /* local variables */ + int arc, delprc, dlx, i, j, nb, node, node2, nsave, rdcost, t1, + t2, t3; + /* Store the arcs between the set of scanned nodes and its + * complement in save and compute delprc, the stepsize to the next + * breakpoint in the dual cost in the direction of decreasing + * prices of the scanned nodes. + * [The arcs are stored into save by looking at the arcs incident + * to either the set of scanned nodes or its complement, depending + * on whether nscan > n/2 or not. This improves the efficiency of + * storing.] */ + delprc = large; + dlx = 0; + nsave = 0; + if (nscan <= n / 2) + { for (i = 1; i <= nscan; i++) + { node = label[i]; + for (arc = fou[node]; arc > 0; arc = nxtou[arc]) + { /* arc points from scanned node to an unscanned node. */ + node2 = endn[arc]; + if (!scan[node2]) + { nsave++; + save[nsave] = arc; + rdcost = rc[arc]; + if ((rdcost == 0) && (prdcsr[node2] != arc)) + dlx += x[arc]; + if ((rdcost < 0) && (rdcost > -delprc)) + delprc = -rdcost; + } + } + for (arc = fin[node]; arc > 0; arc = nxtin[arc]) + { /* arc points from unscanned node to scanned node. */ + node2 = startn[arc]; + if (!scan[node2]) + { nsave++; + save[nsave] = -arc; + rdcost = rc[arc]; + if ((rdcost == 0) && (prdcsr[node2] != -arc)) + dlx += u[arc]; + if ((rdcost > 0) && (rdcost < delprc)) + delprc = rdcost; + } + } + } + } + else + { for (node = 1; node <= n; node++) + { if (scan[node]) + continue; + for (arc = fin[node]; arc > 0; arc = nxtin[arc]) + { node2 = startn[arc]; + if (scan[node2]) + { nsave++; + save[nsave] = arc; + rdcost = rc[arc]; + if ((rdcost == 0) && (prdcsr[node] != arc)) + dlx += x[arc]; + if ((rdcost < 0) && (rdcost > -delprc)) + delprc = -rdcost; + } + } + for (arc = fou[node]; arc > 0; arc = nxtou[arc]) + { node2 = endn[arc]; + if (scan[node2]) + { nsave++; + save[nsave] = -arc; + rdcost = rc[arc]; + if ((rdcost == 0) && (prdcsr[node] != -arc)) + dlx += u[arc]; + if ((rdcost > 0) && (rdcost < delprc)) + delprc = rdcost; + } + } + } + } + /* Check if the set of scanned nodes truly corresponds to a dual + * ascent direction. [Here delx + dlx is the exact sum of the flow + * on arcs from the scanned set to the unscanned set plus the + * (capacity - flow) on arcs from the unscanned set to the scanned + * set.] If this were not the case, set switch to true and exit + * subroutine. */ + if ((!svitch) && (delx + dlx >= dm)) + { svitch = true; + return; + } + delx += dlx; +L4: /* Check that the problem is feasible. */ + if (delprc == large) + { /* We can increase the dual cost without bound, so the primal + * problem is infeasible. */ + feasbl = false; + return; + } + /* Decrease the prices of the scanned nodes, add more nodes to + * the labeled set and check if a newly labeled node has negative + * deficit. */ + if (svitch) + { for (i = 1; i <= nsave; i++) + { arc = save[i]; + if (arc > 0) + { rc[arc] += delprc; + if (rc[arc] == 0) + { node2 = endn[arc]; + if (tnxtou[arc] < 0) + { tnxtou[arc] = tfstou[startn[arc]]; + tfstou[startn[arc]] = arc; + } + if (tnxtin[arc] < 0) + { tnxtin[arc] = tfstin[node2]; + tfstin[node2] = arc; + } + if (!mark[node2]) + { prdcsr[node2] = arc; + nlabel++; + label[nlabel] = node2; + mark[node2] = true; + } + } + } + else + { arc = -arc; + rc[arc] -= delprc; + if (rc[arc] == 0) + { node2 = startn[arc]; + if (tnxtou[arc] < 0) + { tnxtou[arc] = tfstou[node2]; + tfstou[node2] = arc; + } + if (tnxtin[arc] < 0) + { tnxtin[arc] = tfstin[endn[arc]]; + tfstin[endn[arc]] = arc; + } + if (!mark[node2]) + { prdcsr[node2] = -arc; + nlabel++; + label[nlabel] = node2; + mark[node2] = true; + } + } + } + } + return; + } + else + { /* Decrease the prices of the scanned nodes by delprc. Adjust + * flow to maintain complementary slackness with the prices. */ + nb = 0; + for (i = 1; i <= nsave; i++) + { arc = save[i]; + if (arc > 0) + { t1 = rc[arc]; + if (t1 == 0) + { t2 = x[arc]; + t3 = startn[arc]; + dfct[t3] -= t2; + if (nxtqueue[t3] == 0) + { nxtqueue[prevnode] = t3; + nxtqueue[t3] = curnode; + prevnode = t3; + } + t3 = endn[arc]; + dfct[t3] += t2; + if (nxtqueue[t3] == 0) + { nxtqueue[prevnode] = t3; + nxtqueue[t3] = curnode; + prevnode = t3; + } + u[arc] += t2; + x[arc] = 0; + } + rc[arc] = t1 + delprc; +#if 0 /* by mao; 26/IV-2013 */ + if (rc[arc] == 0) +#else + if (rc[arc] == 0 && nb < n) +#endif + { delx += x[arc]; + nb++; + prdcsr[nb] = arc; + } + } + else + { arc = -arc; + t1 = rc[arc]; + if (t1 == 0) + { t2 = u[arc]; + t3 = startn[arc]; + dfct[t3] += t2; + if (nxtqueue[t3] == 0) + { nxtqueue[prevnode] = t3; + nxtqueue[t3] = curnode; + prevnode = t3; + } + t3 = endn[arc]; + dfct[t3] -= t2; + if (nxtqueue[t3] == 0) + { nxtqueue[prevnode] = t3; + nxtqueue[t3] = curnode; + prevnode = t3; + } + x[arc] += t2; + u[arc] = 0; + } + rc[arc] = t1 - delprc; +#if 0 /* by mao; 26/IV-2013 */ + if (rc[arc] == 0) +#else + if (rc[arc] == 0 && nb < n) +#endif + { delx += u[arc]; + nb++; + prdcsr[nb] = arc; + } + } + } + } + if (delx <= dm) + { /* The set of scanned nodes still corresponds to a dual + * (possibly degenerate) ascent direction. Compute the stepsize + * delprc to the next breakpoint in the dual cost. */ + delprc = large; + for (i = 1; i <= nsave; i++) + { arc = save[i]; + if (arc > 0) + { rdcost = rc[arc]; + if ((rdcost < 0) && (rdcost > -delprc)) + delprc = -rdcost; + } + else + { arc = -arc; + rdcost = rc[arc]; + if ((rdcost > 0) && (rdcost < delprc)) + delprc = rdcost; + } + } + if ((delprc != large) || (delx < dm)) + goto L4; + } + /* Add new balanced arcs to the superset of balanced arcs. */ + for (i = 1; i <= nb; i++) + { arc = prdcsr[i]; + if (tnxtin[arc] == -1) + { j = endn[arc]; + tnxtin[arc] = tfstin[j]; + tfstin[j] = arc; + } + if (tnxtou[arc] == -1) + { j = startn[arc]; + tnxtou[arc] = tfstou[j]; + tfstou[j] = arc; + } + } + return; +# undef delx +# undef nlabel +# undef feasbl +# undef svitch +# undef prevnode +} + +/*********************************************************************** +* NAME +* +* ascnt2 - multi-node price adjustment for negative deficit case +* +* PURPOSE +* +* This routine is analogous to ascnt1 but for the case where the +* scanned nodes have negative deficit. */ + +static void ascnt2(struct relax4_csa *csa, int dm, int *delx, + int *nlabel, int *feasbl, int *svitch, int nscan, int curnode, + int *prevnode) +{ /* input parameters */ + int n = csa->n; + /* int na = csa->na; */ + int large = csa->large; + int *startn = csa->startn; + int *endn = csa->endn; + int *fou = csa->fou; + int *nxtou = csa->nxtou; + int *fin = csa->fin; + int *nxtin = csa->nxtin; + /* updated parameters */ +# define delx (*delx) +# define nlabel (*nlabel) +# define feasbl (*feasbl) +# define svitch (*svitch) +# define prevnode (*prevnode) + int *rc = csa->rc; + int *u = csa->u; + int *x = csa->x; + int *dfct = csa->dfct; + int *label = csa->label; + int *prdcsr = csa->prdcsr; + int *tfstou = csa->tfstou; + int *tnxtou = csa->tnxtou; + int *tfstin = csa->tfstin; + int *tnxtin = csa->tnxtin; + int *nxtqueue = csa->nxtqueue; + char *scan = csa->scan; + char *mark = csa->mark; + int *save = csa->save; + /* local variables */ + int arc, delprc, dlx, i, j, nb, node, node2, nsave, rdcost, t1, + t2, t3; + /* Store the arcs between the set of scanned nodes and its + * complement in save and compute delprc, the stepsize to the next + * breakpoint in the dual cost in the direction of increasing + * prices of the scanned nodes. */ + delprc = large; + dlx = 0; + nsave = 0; + if (nscan <= n / 2) + { for (i = 1; i <= nscan; i++) + { node = label[i]; + for (arc = fin[node]; arc > 0; arc = nxtin[arc]) + { node2 = startn[arc]; + if (!scan[node2]) + { nsave++; + save[nsave] = arc; + rdcost = rc[arc]; + if ((rdcost == 0) && (prdcsr[node2] != arc)) + dlx += x[arc]; + if ((rdcost < 0) && (rdcost > -delprc)) + delprc = -rdcost; + } + } + for (arc = fou[node]; arc > 0; arc = nxtou[arc]) + { node2 = endn[arc]; + if (!scan[node2]) + { nsave++; + save[nsave] = -arc; + rdcost = rc[arc]; + if ((rdcost == 0) && (prdcsr[node2] != -arc)) + dlx += u[arc]; + if ((rdcost > 0) && (rdcost < delprc)) + delprc = rdcost; + } + } + } + } + else + { for (node = 1; node <= n; node++) + { if (scan[node]) + continue; + for (arc = fou[node]; arc > 0; arc = nxtou[arc]) + { node2 = endn[arc]; + if (scan[node2]) + { nsave++; + save[nsave] = arc; + rdcost = rc[arc]; + if ((rdcost == 0) && (prdcsr[node] != arc)) + dlx += x[arc]; + if ((rdcost < 0) && (rdcost > -delprc)) + delprc = -rdcost; + } + } + for (arc = fin[node]; arc > 0; arc = nxtin[arc]) + { node2 = startn[arc]; + if (scan[node2]) + { nsave++; + save[nsave] = -arc; + rdcost = rc[arc]; + if ((rdcost == 0) && (prdcsr[node] != -arc)) + dlx += u[arc]; + if ((rdcost > 0) && (rdcost < delprc)) + delprc = rdcost; + } + } + } + } + if ((!svitch) && (delx + dlx >= -dm)) + { svitch = true; + return; + } + delx += dlx; + /* Check that the problem is feasible. */ +L4: if (delprc == large) + { feasbl = false; + return; + } + /* Increase the prices of the scanned nodes, add more nodes to + * the labeled set and check if a newly labeled node has positive + * deficit. */ + if (svitch) + { for (i = 1; i <= nsave; i++) + { arc = save[i]; + if (arc > 0) + { rc[arc] += delprc; + if (rc[arc] == 0) + { node2 = startn[arc]; + if (tnxtou[arc] < 0) + { tnxtou[arc] = tfstou[node2]; + tfstou[node2] = arc; + } + if (tnxtin[arc] < 0) + { tnxtin[arc] = tfstin[endn[arc]]; + tfstin[endn[arc]] = arc; + } + if (!mark[node2]) + { prdcsr[node2] = arc; + nlabel++; + label[nlabel] = node2; + mark[node2] = true; + } + } + } + else + { arc = -arc; + rc[arc] -= delprc; + if (rc[arc] == 0) + { node2 = endn[arc]; + if (tnxtou[arc] < 0) + { tnxtou[arc] = tfstou[startn[arc]]; + tfstou[startn[arc]] = arc; + } + if (tnxtin[arc] < 0) + { tnxtin[arc] = tfstin[node2]; + tfstin[node2] = arc; + } + if (!mark[node2]) + { prdcsr[node2] = -arc; + nlabel++; + label[nlabel] = node2; + mark[node2] = true; + } + } + } + } + return; + } + else + { nb = 0; + for (i = 1; i <= nsave; i++) + { arc = save[i]; + if (arc > 0) + { t1 = rc[arc]; + if (t1 == 0) + { t2 = x[arc]; + t3 = startn[arc]; + dfct[t3] -= t2; + if (nxtqueue[t3] == 0) + { nxtqueue[prevnode] = t3; + nxtqueue[t3] = curnode; + prevnode = t3; + } + t3 = endn[arc]; + dfct[t3] += t2; + if (nxtqueue[t3] == 0) + { nxtqueue[prevnode] = t3; + nxtqueue[t3] = curnode; + prevnode = t3; + } + u[arc] += t2; + x[arc] = 0; + } + rc[arc] = t1 + delprc; +#if 0 /* by mao; 26/IV-2013 */ + if (rc[arc] == 0) +#else + if (rc[arc] == 0 && nb < n) +#endif + { delx += x[arc]; + nb++; + prdcsr[nb] = arc; + } + } + else + { arc = -arc; + t1 = rc[arc]; + if (t1 == 0) + { t2 = u[arc]; + t3 = startn[arc]; + dfct[t3] += t2; + if (nxtqueue[t3] == 0) + { nxtqueue[prevnode] = t3; + nxtqueue[t3] = curnode; + prevnode = t3; + } + t3 = endn[arc]; + dfct[t3] -= t2; + if (nxtqueue[t3] == 0) + { nxtqueue[prevnode] = t3; + nxtqueue[t3] = curnode; + prevnode = t3; + } + x[arc] += t2; + u[arc] = 0; + } + rc[arc] = t1 - delprc; +#if 0 /* by mao; 26/IV-2013 */ + if (rc[arc] == 0) +#else + if (rc[arc] == 0 && nb < n) +#endif + { delx += u[arc]; + nb++; + prdcsr[nb] = arc; + } + } + } + } + if (delx <= -dm) + { delprc = large; + for (i = 1; i <= nsave; i++) + { arc = save[i]; + if (arc > 0) + { rdcost = rc[arc]; + if ((rdcost < 0) && (rdcost > -delprc)) + delprc = -rdcost; + } + else + { arc = -arc; + rdcost = rc[arc]; + if ((rdcost > 0) && (rdcost < delprc)) + delprc = rdcost; + } + } + if ((delprc != large) || (delx < -dm)) + goto L4; + } + /* Add new balanced arcs to the superset of balanced arcs. */ + for (i = 1; i <= nb; i++) + { arc = prdcsr[i]; + if (tnxtin[arc] == -1) + { j = endn[arc]; + tnxtin[arc] = tfstin[j]; + tfstin[j] = arc; + } + if (tnxtou[arc] == -1) + { j = startn[arc]; + tnxtou[arc] = tfstou[j]; + tfstou[j] = arc; + } + } + return; +# undef delx +# undef nlabel +# undef feasbl +# undef svitch +# undef prevnode +} + +/*********************************************************************** +* NAME +* +* auction - compute good initial flow and prices +* +* PURPOSE +* +* This subroutine uses a version of the auction algorithm for min +* cost network flow to compute a good initial flow and prices for the +* problem. +* +* INPUT PARAMETERS +* +* n = number of nodes +* na = number of arcs +* large = a very large integer to represent infinity (see note 3) +* startn[i] = starting node for the i-th arc, i = 1,...,na +* endn[i] = ending node for the i-th arc, i = 1,...,na +* fou[i] = first arc leaving i-th node, i = 1,...,n +* nxtou[i] = next arc leaving the starting node of j-th arc, +* i = 1,...,na +* fin[i] = first arc entering i-th node, i = 1,...,n +* nxtin[i] = next arc entering the ending node of j-th arc, +* i = 1,...,na +* +* UPDATED PARAMETERS +* +* rc[j] = reduced cost of arc j, j = 1,...,na +* u[j] = residual capacity of arc j, j = 1,...,na +* x[j] = flow on arc j, j = 1,...,na +* dfct[i] = deficit at node i, i = 1,...,n +* +* OUTPUT PARAMETERS +* +* nsp = number of auction/shortest path iterations +* +* WORKING PARAMETERS +* +* p[1+n], prdcsr[1+n], save[1+na], fpushf[1+n], nxtpushf[1+na], +* fpushb[1+n], nxtpushb[1+na], nxtqueue[1+n], extend_arc[1+n], +* sb_level[1+n], sb_arc[1+n], path_id[1+n] +* +* RETURNS +* +* 0 = normal return +* 1 = problem is found to be infeasible */ + +static int auction(struct relax4_csa *csa) +{ /* input parameters */ + int n = csa->n; + int na = csa->na; + int large = csa->large; + int *startn = csa->startn; + int *endn = csa->endn; + int *fou = csa->fou; + int *nxtou = csa->nxtou; + int *fin = csa->fin; + int *nxtin = csa->nxtin; + /* updated parameters */ +# define crash (csa->crash) + int *rc = csa->rc; + int *u = csa->u; + int *x = csa->x; + int *dfct = csa->dfct; + /* output parameters */ +# define nsp (csa->nsp) + /* working parameters */ + int *p = csa->label; + int *prdcsr = csa->prdcsr; + int *save = csa->save; + int *fpushf = csa->tfstou; + int *nxtpushf = csa->tnxtou; + int *fpushb = csa->tfstin; + int *nxtpushb = csa->tnxtin; + int *nxtqueue = csa->nxtqueue; + int *extend_arc = csa->extend_arc; + int *sb_level = csa->sb_level; + int *sb_arc = csa->sb_arc; + char *path_id = csa->mark; + /* local variables */ + int arc, bstlevel, end, eps, extarc, factor, flow, i, incr, + last, lastqueue, maxcost, mincost, nas, naug, new_level, node, + nolist, num_passes, nxtnode, pass, pend, pr_term, prd, + prevarc, prevlevel, prevnode, pstart, pterm, rdcost, red_cost, + resid, root, secarc, seclevel, start, term, thresh_dfct; + /* start initialization using auction */ + naug = 0; + pass = 0; + thresh_dfct = 0; + /* factor determines by how much epsilon is reduced at each + * minimization */ + factor = 3; + /* num_passes determines how many auction scaling phases are + * performed */ + num_passes = 1; + /* set arc flows to satisfy cs and calculate maxcost and + * mincost */ + maxcost = -large; + mincost = large; + for (arc = 1; arc <= na; arc++) + { start = startn[arc]; + end = endn[arc]; + rdcost = rc[arc]; + if (maxcost < rdcost) + maxcost = rdcost; + if (mincost > rdcost) + mincost = rdcost; + if (rdcost < 0) + { dfct[start] += u[arc]; + dfct[end] -= u[arc]; + x[arc] = u[arc]; + u[arc] = 0; + } + else + x[arc] = 0; + } + /* set initial epsilon */ + if ((maxcost - mincost) >= 8) + eps = (maxcost - mincost) / 8; + else + eps = 1; + /* set initial prices to zero */ + for (node = 1; node <= n; node++) + p[node] = 0; + /* Initialization using auction/shortest paths. */ +L100: /* Start of the first scaling phase. */ + pass++; + if ((pass == num_passes) || (eps == 1)) + crash = 0; + nolist = 0; + /* construct list of positive surplus nodes and queue of negative + * surplus nodes */ + for (node = 1; node <= n; node++) + { prdcsr[node] = 0; + path_id[node] = false; + extend_arc[node] = 0; + sb_level[node] = -large; + nxtqueue[node] = node + 1; + if (dfct[node] > 0) + { nolist++; + save[nolist] = node; + } + } + nxtqueue[n] = 1; + root = 1; + prevnode = lastqueue = n; + /* initialization with down iterations for negative surplus + * nodes */ + for (i = 1; i <= nolist; i++) + { node = save[i]; + nsp++; + /* build the list of arcs w/ room for pushing flow and find + * proper price for down iteration */ + bstlevel = -large; + fpushf[node] = 0; + for (arc = fou[node]; arc > 0; arc = nxtou[arc]) + { if (u[arc] > 0) + { if (fpushf[node] == 0) + { fpushf[node] = arc; + nxtpushf[arc] = 0; + last = arc; + } + else + { nxtpushf[last] = arc; + nxtpushf[arc] = 0; + last = arc; + } + } + if (x[arc] > 0) + { new_level = p[endn[arc]] + rc[arc]; + if (new_level > bstlevel) + { bstlevel = new_level; + extarc = arc; + } + } + } + fpushb[node] = 0; + for (arc = fin[node]; arc > 0; arc = nxtin[arc]) + { if (x[arc] > 0) + { if (fpushb[node] == 0) + { fpushb[node] = arc; + nxtpushb[arc] = 0; + last = arc; + } + else + { nxtpushb[last] = arc; + nxtpushb[arc] = 0; + last = arc; + } + } + if (u[arc] > 0) + { new_level = p[startn[arc]] - rc[arc]; + if (new_level > bstlevel) + { bstlevel = new_level; + extarc = -arc; + } + } + } + extend_arc[node] = extarc; + p[node] = bstlevel - eps; + } +L200: /* Start the augmentation cycles of the new scaling phase. */ + if (dfct[root] >= thresh_dfct) + goto L3000; + term = root; + path_id[root] = true; +L500: /* Main forward algorithm with root as origin. */ + /* start of a new forward iteration */ + pterm = p[term]; + extarc = extend_arc[term]; + if (extarc == 0) + { /* build the list of arcs w/ room for pushing flow */ + fpushf[term] = 0; + for (arc = fou[term]; arc > 0; arc = nxtou[arc]) + { if (u[arc] > 0) + { if (fpushf[term] == 0) + { fpushf[term] = arc; + nxtpushf[arc] = 0; + last = arc; + } + else + { nxtpushf[last] = arc; + nxtpushf[arc] = 0; + last = arc; + } + } + } + fpushb[term] = 0; + for (arc = fin[term]; arc > 0; arc = nxtin[arc]) + { if (x[arc] > 0) + { if (fpushb[term] == 0) + { fpushb[term] = arc; + nxtpushb[arc] = 0; + last = arc; + } + else + { nxtpushb[last] = arc; + nxtpushb[arc] = 0; + last = arc; + } + } + } + goto L600; + } + /* speculative path extension attempt */ + /* note: arc > 0 means that arc is oriented from the root to the + * destinations + * arc < 0 means that arc is oriented from the destinations to the + * root + * extarc = 0 or prdarc = 0, means the extension arc or the + * predecessor arc, respectively, has not been established */ + if (extarc > 0) + { if (u[extarc] == 0) + { seclevel = sb_level[term]; + goto L580; + } + end = endn[extarc]; + bstlevel = p[end] + rc[extarc]; + if (pterm >= bstlevel) + { if (path_id[end]) + goto L1200; + term = end; + prdcsr[term] = extarc; + path_id[term] = true; + /* if negative surplus node is found, do an augmentation */ + if (dfct[term] > 0) + goto L2000; + /* return for another iteration */ + goto L500; + } + } + else + { extarc = -extarc; + if (x[extarc] == 0) + { seclevel = sb_level[term]; + goto L580; + } + start = startn[extarc]; + bstlevel = p[start] - rc[extarc]; + if (pterm >= bstlevel) + { if (path_id[start]) + goto L1200; + term = start; + prdcsr[term] = -extarc; + path_id[term] = true; + /* if negative surplus node is found, do an augmentation */ + if (dfct[term] > 0) + goto L2000; + /* return for another iteration */ + goto L500; + } + } +L550: /* second best logic test applied to save a full node scan + * if old best level continues to be best go for another + * contraction */ + seclevel = sb_level[term]; + if (bstlevel <= seclevel) + goto L800; +L580: /* if second best can be used do either a contraction or start + * over with a speculative extension */ + if (seclevel > -large) + { extarc = sb_arc[term]; + if (extarc > 0) + { if (u[extarc] == 0) + goto L600; + bstlevel = p[endn[extarc]] + rc[extarc]; + } + else + { if (x[-extarc] == 0) + goto L600; + bstlevel = p[startn[-extarc]] - rc[-extarc]; + } + if (bstlevel == seclevel) + { sb_level[term] = -large; + extend_arc[term] = extarc; + goto L800; + } + } +L600: /* extension/contraction attempt was unsuccessful, so scan + * terminal node */ + nsp++; + bstlevel = seclevel = large; + for (arc = fpushf[term]; arc > 0; arc = nxtpushf[arc]) + { new_level = p[endn[arc]] + rc[arc]; + if (new_level < seclevel) + { if (new_level < bstlevel) + { seclevel = bstlevel; + bstlevel = new_level; + secarc = extarc; + extarc = arc; + } + else + { seclevel = new_level; + secarc = arc; + } + } + } + for (arc = fpushb[term]; arc > 0; arc = nxtpushb[arc]) + { new_level = p[startn[arc]] - rc[arc]; + if (new_level < seclevel) + { if (new_level < bstlevel) + { seclevel = bstlevel; + bstlevel = new_level; + secarc = extarc; + extarc = -arc; + } + else + { seclevel = new_level; + secarc = -arc; + } + } + } + sb_level[term] = seclevel; + sb_arc[term] = secarc; + extend_arc[term] = extarc; +L800: /* End of node scan. */ + /* if the terminal node is the root, adjust its price and change + * root */ + if (term == root) + { p[term] = bstlevel + eps; + if (p[term] >= large) + { /* no path to the destination */ + /* problem is found to be infeasible */ + return 1; + } + path_id[root] = false; + prevnode = root; + root = nxtqueue[root]; + goto L200; + } + /* check whether extension or contraction */ + prd = prdcsr[term]; + if (prd > 0) + { pr_term = startn[prd]; + prevlevel = p[pr_term] - rc[prd]; + } + else + { pr_term = endn[-prd]; + prevlevel = p[pr_term] + rc[-prd]; + } + if (prevlevel > bstlevel) + { /* path extension */ + if (prevlevel >= bstlevel + eps) + p[term] = bstlevel + eps; + else + p[term] = prevlevel; + if (extarc > 0) + { end = endn[extarc]; + if (path_id[end]) + goto L1200; + term = end; + } + else + { start = startn[-extarc]; + if (path_id[start]) + goto L1200; + term = start; + } + prdcsr[term] = extarc; + path_id[term] = true; + /* if negative surplus node is found, do an augmentation */ + if (dfct[term] > 0) + goto L2000; + /* return for another iteration */ + goto L500; + } + else + { /* path contraction */ + p[term] = bstlevel + eps; + path_id[term] = false; + term = pr_term; + if (pr_term != root) + { if (bstlevel <= pterm + eps) + goto L2000; + } + pterm = p[term]; + extarc = prd; + if (prd > 0) + bstlevel += eps + rc[prd]; + else + bstlevel += eps - rc[-prd]; + /* do a second best test and if that fails, do a full node + * scan */ + goto L550; + } +L1200:/* A cycle is about to form; do a retreat sequence. */ + node = term; +L1600:if (node != root) + { path_id[node] = false; + prd = prdcsr[node]; + if (prd > 0) + { pr_term = startn[prd]; + if (p[pr_term] == p[node] + rc[prd] + eps) + { node = pr_term; + goto L1600; + } + } + else + { pr_term = endn[-prd]; + if (p[pr_term] == p[node] - rc[-prd] + eps) + { node = pr_term; + goto L1600; + } + } + /* do a full scan and price rise at pr_term */ + nsp++; + bstlevel = seclevel = large; + for (arc = fpushf[pr_term]; arc > 0; arc = nxtpushf[arc]) + { new_level = p[endn[arc]] + rc[arc]; + if (new_level < seclevel) + { if (new_level < bstlevel) + { seclevel = bstlevel; + bstlevel = new_level; + secarc = extarc; + extarc = arc; + } + else + { seclevel = new_level; + secarc = arc; + } + } + } + for (arc = fpushb[pr_term]; arc > 0; arc = nxtpushb[arc]) + { new_level = p[startn[arc]] - rc[arc]; + if (new_level < seclevel) + { if (new_level < bstlevel) + { seclevel = bstlevel; + bstlevel = new_level; + secarc = extarc; + extarc = -arc; + } + else + { seclevel = new_level; + secarc = -arc; + } + } + } + sb_level[pr_term] = seclevel; + sb_arc[pr_term] = secarc; + extend_arc[pr_term] = extarc; + p[pr_term] = bstlevel + eps; + if (pr_term == root) + { prevnode = root; + path_id[root] = false; + root = nxtqueue[root]; + goto L200; + } + path_id[pr_term] = false; + prd = prdcsr[pr_term]; + if (prd > 0) + term = startn[prd]; + else + term = endn[-prd]; + if (term == root) + { prevnode = root; + path_id[root] = false; + root = nxtqueue[root]; + goto L200; + } + else + goto L2000; + } +L2000:/* End of auction/shortest path routine. */ + /* do augmentation from root and correct the push lists */ + incr = -dfct[root]; + for (node = root;;) + { extarc = extend_arc[node]; + path_id[node] = false; + if (extarc > 0) + { node = endn[extarc]; + if (incr > u[extarc]) + incr = u[extarc]; + } + else + { node = startn[-extarc]; + if (incr > x[-extarc]) + incr = x[-extarc]; + } + if (node == term) + break; + } + path_id[term] = false; + if (dfct[term] > 0) + { if (incr > dfct[term]) + incr = dfct[term]; + } + for (node = root;;) + { extarc = extend_arc[node]; + if (extarc > 0) + { end = endn[extarc]; + /* add arc to the reduced graph */ + if (x[extarc] == 0) + { nxtpushb[extarc] = fpushb[end]; + fpushb[end] = extarc; + new_level = p[node] - rc[extarc]; + if (sb_level[end] > new_level) + { sb_level[end] = new_level; + sb_arc[end] = -extarc; + } + } + x[extarc] += incr; + u[extarc] -= incr; + /* remove arc from the reduced graph */ + if (u[extarc] == 0) + { nas++; + arc = fpushf[node]; + if (arc == extarc) + fpushf[node] = nxtpushf[arc]; + else + { prevarc = arc; + arc = nxtpushf[arc]; + while (arc > 0) + { if (arc == extarc) + { nxtpushf[prevarc] = nxtpushf[arc]; + break; + } + prevarc = arc; + arc = nxtpushf[arc]; + } + } + } + node = end; + } + else + { extarc = -extarc; + start = startn[extarc]; + /* add arc to the reduced graph */ + if (u[extarc] == 0) + { nxtpushf[extarc] = fpushf[start]; + fpushf[start] = extarc; + new_level = p[node] + rc[extarc]; + if (sb_level[start] > new_level) + { sb_level[start] = new_level; + sb_arc[start] = extarc; + } + } + u[extarc] += incr; + x[extarc] -= incr; + /* remove arc from the reduced graph */ + if (x[extarc] == 0) + { nas++; + arc = fpushb[node]; + if (arc == extarc) + fpushb[node] = nxtpushb[arc]; + else + { prevarc = arc; + arc = nxtpushb[arc]; + while (arc > 0) + { if (arc == extarc) + { nxtpushb[prevarc] = nxtpushb[arc]; + break; + } + prevarc = arc; + arc = nxtpushb[arc]; + } + } + } + node = start; + } + if (node == term) + break; + } + dfct[term] -= incr; + dfct[root] += incr; + /* insert term in the queue if it has a large enough surplus */ + if (dfct[term] < thresh_dfct) + { if (nxtqueue[term] == 0) + { nxtnode = nxtqueue[root]; + if ((p[term] >= p[nxtnode]) && (root != nxtnode)) + { nxtqueue[root] = term; + nxtqueue[term] = nxtnode; + } + else + { nxtqueue[prevnode] = term; + nxtqueue[term] = root; + prevnode = term; + } + } + } + /* if root has a large enough surplus, keep it in the queue and + * return for another iteration */ + if (dfct[root] < thresh_dfct) + { prevnode = root; + root = nxtqueue[root]; + goto L200; + } +L3000:/* end of augmentation cycle */ + /* Check for termination of scaling phase. If scaling phase is not + * finished, advance the queue and return to take another node. */ + nxtnode = nxtqueue[root]; + if (root != nxtnode) + { nxtqueue[root] = 0; + nxtqueue[prevnode] = nxtnode; + root = nxtnode; + goto L200; + } + /* End of subproblem (scaling phase). */ + /* Reduce epsilon. */ + eps /= factor; + if (eps < 1) eps = 1; + thresh_dfct /= factor; + if (eps == 1) thresh_dfct = 0; + /* if another auction scaling phase remains, reset the flows & + * the push lists; else reset arc flows to satisfy cs and compute + * reduced costs */ + if (crash == 1) + { for (arc = 1; arc <= na; arc++) + { start = startn[arc]; + end = endn[arc]; + pstart = p[start]; + pend = p[end]; + if (pstart > pend + eps + rc[arc]) + { resid = u[arc]; + if (resid > 0) + { dfct[start] += resid; + dfct[end] -= resid; + x[arc] += resid; + u[arc] = 0; + } + } + else if (pstart < pend - eps + rc[arc]) + { flow = x[arc]; + if (flow > 0) + { dfct[start] -= flow; + dfct[end] += flow; + x[arc] = 0; + u[arc] += flow; + } + } + } + /* return for another phase */ + goto L100; + } + else + { crash = 1; + for (arc = 1; arc <= na; arc++) + { start = startn[arc]; + end = endn[arc]; + red_cost = rc[arc] + p[end] - p[start]; + if (red_cost < 0) + { resid = u[arc]; + if (resid > 0) + { dfct[start] += resid; + dfct[end] -= resid; + x[arc] += resid; + u[arc] = 0; + } + } + else if (red_cost > 0) + { flow = x[arc]; + if (flow > 0) + { dfct[start] -= flow; + dfct[end] += flow; + x[arc] = 0; + u[arc] += flow; + } + } + rc[arc] = red_cost; + } + } + return 0; +# undef crash +# undef nsp +} + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/relax4.h b/test/monniaux/glpk-4.65/src/misc/relax4.h new file mode 100644 index 00000000..f48b8508 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/relax4.h @@ -0,0 +1,102 @@ +/* relax4.h */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2012-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#ifndef RELAX4_H +#define RELAX4_H + +struct relax4_csa +{ /* common storage area */ + /* input parameters --------------------------------------------*/ + int n; + /* number of nodes */ + int na; + /* number of arcs */ + int large; + /* very large int to represent infinity */ + int repeat; + /* true if initialization is to be skipped (false otherwise) */ + int crash; + /* 0 if default initialization is used + * 1 if auction initialization is used */ + int *startn; /* int startn[1+na]; */ + /* startn[j] = starting node for arc j, j = 1,...,na */ + int *endn; /* int endn[1+na] */ + /* endn[j] = ending node for arc j, j = 1,...,na */ + int *fou; /* int fou[1+n]; */ + /* fou[i] = first arc out of node i, i = 1,...,n */ + int *nxtou; /* int nxtou[1+na]; */ + /* nxtou[j] = next arc out of the starting node of arc j, + * j = 1,...,na */ + int *fin; /* int fin[1+n]; */ + /* fin[i] = first arc into node i, i = 1,...,n */ + int *nxtin; /* int nxtin[1+na]; */ + /* nxtin[j] = next arc into the ending node of arc j, + * j = 1,...,na */ + /* updated parameters ------------------------------------------*/ + int *rc; /* int rc[1+na]; */ + /* rc[j] = reduced cost of arc j, j = 1,...,na */ + int *u; /* int u[1+na]; */ + /* u[j] = capacity of arc j on input + * and (capacity of arc j) - x(j) on output, j = 1,...,na */ + int *dfct; /* int dfct[1+n]; */ + /* dfct[i] = demand at node i on input + * and zero on output, i = 1,...,n */ + /* output parameters -------------------------------------------*/ + int *x; /* int x[1+na]; */ + /* x[j] = flow on arc j, j = 1,...,na */ + int nmultinode; + /* number of multinode relaxation iterations in RELAX4 */ + int iter; + /* number of relaxation iterations in RELAX4 */ + int num_augm; + /* number of flow augmentation steps in RELAX4 */ + int num_ascnt; + /* number of multinode ascent steps in RELAX4 */ + int nsp; + /* number of auction/shortest path iterations */ + /* working parameters ------------------------------------------*/ + int *label; /* int label, tempin, p[1+n]; */ + int *prdcsr; /* int prdcsr, tempou, price[1+n]; */ + int *save; /* int save[1+na]; */ + int *tfstou; /* int tfstou, fpushf[1+n]; */ + int *tnxtou; /* int tnxtou, nxtpushf[1+na]; */ + int *tfstin; /* int tfstin, fpushb[1+n]; */ + int *tnxtin; /* int tnxtin, nxtpushb[1+na]; */ + int *nxtqueue; /* int nxtqueue[1+n]; */ + char *scan; /* bool scan[1+n]; */ + char *mark; /* bool mark, path_id[1+n]; */ + /* working parameters used by routine auction only -------------*/ + int *extend_arc; /* int extend_arc[1+n]; */ + int *sb_level; /* int sb_level[1+n]; */ + int *sb_arc; /* int sb_arc[1+n]; */ +}; + +#define relax4 _glp_relax4 +int relax4(struct relax4_csa *csa); + +#define relax4_inidat _glp_relax4_inidat +void relax4_inidat(struct relax4_csa *csa); + +#endif + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/rng.c b/test/monniaux/glpk-4.65/src/misc/rng.c new file mode 100644 index 00000000..e0acb53a --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/rng.c @@ -0,0 +1,227 @@ +/* rng.c (pseudo-random number generator) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* This code is a modified version of the module GB_FLIP, a portable +* pseudo-random number generator. The original version of GB_FLIP is +* a part of The Stanford GraphBase developed by Donald E. Knuth (see +* http://www-cs-staff.stanford.edu/~knuth/sgb.html). +* +* Note that all changes concern only external names, so this modified +* version produces exactly the same results as the original version. +* +* Changes were made by Andrew Makhorin . +* +* 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 . +***********************************************************************/ + +#include "env.h" +#include "rng.h" + +#if 0 +int A[56] = { -1 }; +#else +#define A (rand->A) +#endif +/* pseudo-random values */ + +#if 0 +int *fptr = A; +#else +#define fptr (rand->fptr) +#endif +/* the next A value to be exported */ + +#define mod_diff(x, y) (((x) - (y)) & 0x7FFFFFFF) +/* difference modulo 2^31 */ + +static int flip_cycle(RNG *rand) +{ /* this is an auxiliary routine to do 55 more steps of the basic + * recurrence, at high speed, and to reset fptr */ + int *ii, *jj; + for (ii = &A[1], jj = &A[32]; jj <= &A[55]; ii++, jj++) + *ii = mod_diff(*ii, *jj); + for (jj = &A[1]; ii <= &A[55]; ii++, jj++) + *ii = mod_diff(*ii, *jj); + fptr = &A[54]; + return A[55]; +} + +/*********************************************************************** +* NAME +* +* rng_create_rand - create pseudo-random number generator +* +* SYNOPSIS +* +* #include "rng.h" +* RNG *rng_create_rand(void); +* +* DESCRIPTION +* +* The routine rng_create_rand creates and initializes a pseudo-random +* number generator. +* +* RETURNS +* +* The routine returns a pointer to the generator created. */ + +RNG *rng_create_rand(void) +{ RNG *rand; + int i; + rand = talloc(1, RNG); + A[0] = -1; + for (i = 1; i <= 55; i++) A[i] = 0; + fptr = A; + rng_init_rand(rand, 1); + return rand; +} + +/*********************************************************************** +* NAME +* +* rng_init_rand - initialize pseudo-random number generator +* +* SYNOPSIS +* +* #include "rng.h" +* void rng_init_rand(RNG *rand, int seed); +* +* DESCRIPTION +* +* The routine rng_init_rand initializes the pseudo-random number +* generator. The parameter seed may be any integer number. Note that +* on creating the generator this routine is called with the parameter +* seed equal to 1. */ + +void rng_init_rand(RNG *rand, int seed) +{ int i; + int prev = seed, next = 1; + seed = prev = mod_diff(prev, 0); + A[55] = prev; + for (i = 21; i; i = (i + 21) % 55) + { A[i] = next; + next = mod_diff(prev, next); + if (seed & 1) + seed = 0x40000000 + (seed >> 1); + else + seed >>= 1; + next = mod_diff(next, seed); + prev = A[i]; + } + flip_cycle(rand); + flip_cycle(rand); + flip_cycle(rand); + flip_cycle(rand); + flip_cycle(rand); + return; +} + +/*********************************************************************** +* NAME +* +* rng_next_rand - obtain pseudo-random integer in the range [0, 2^31-1] +* +* SYNOPSIS +* +* #include "rng.h" +* int rng_next_rand(RNG *rand); +* +* RETURNS +* +* The routine rng_next_rand returns a next pseudo-random integer which +* is uniformly distributed between 0 and 2^31-1, inclusive. The period +* length of the generated numbers is 2^85 - 2^30. The low order bits of +* the generated numbers are just as random as the high-order bits. */ + +int rng_next_rand(RNG *rand) +{ return + *fptr >= 0 ? *fptr-- : flip_cycle(rand); +} + +/*********************************************************************** +* NAME +* +* rng_unif_rand - obtain pseudo-random integer in the range [0, m-1] +* +* SYNOPSIS +* +* #include "rng.h" +* int rng_unif_rand(RNG *rand, int m); +* +* RETURNS +* +* The routine rng_unif_rand returns a next pseudo-random integer which +* is uniformly distributed between 0 and m-1, inclusive, where m is any +* positive integer less than 2^31. */ + +#define two_to_the_31 ((unsigned int)0x80000000) + +int rng_unif_rand(RNG *rand, int m) +{ unsigned int t = two_to_the_31 - (two_to_the_31 % m); + int r; + xassert(m > 0); + do { r = rng_next_rand(rand); } while (t <= (unsigned int)r); + return r % m; +} + +/*********************************************************************** +* NAME +* +* rng_delete_rand - delete pseudo-random number generator +* +* SYNOPSIS +* +* #include "rng.h" +* void rng_delete_rand(RNG *rand); +* +* DESCRIPTION +* +* The routine rng_delete_rand frees all the memory allocated to the +* specified pseudo-random number generator. */ + +void rng_delete_rand(RNG *rand) +{ tfree(rand); + return; +} + +/**********************************************************************/ + +#ifdef GLP_TEST +/* To be sure that this modified version produces the same results as + * the original version, run this validation program. */ + +int main(void) +{ RNG *rand; + int j; + rand = rng_create_rand(); + rng_init_rand(rand, -314159); + if (rng_next_rand(rand) != 119318998) + { fprintf(stderr, "Failure on the first try!\n"); + return -1; + } + for (j = 1; j <= 133; j++) rng_next_rand(rand); + if (rng_unif_rand(rand, 0x55555555) != 748103812) + { fprintf(stderr, "Failure on the second try!\n"); + return -2; + } + fprintf(stderr, "OK, the random-number generator routines seem to" + " work!\n"); + rng_delete_rand(rand); + return 0; +} +#endif + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/rng.h b/test/monniaux/glpk-4.65/src/misc/rng.h new file mode 100644 index 00000000..49725e05 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/rng.h @@ -0,0 +1,67 @@ +/* rng.h (pseudo-random number generator) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2003-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#ifndef RNG_H +#define RNG_H + +typedef struct RNG RNG; + +struct RNG +{ /* Knuth's portable pseudo-random number generator */ + int A[56]; + /* pseudo-random values */ + int *fptr; + /* the next A value to be exported */ +}; + +#define rng_create_rand _glp_rng_create_rand +RNG *rng_create_rand(void); +/* create pseudo-random number generator */ + +#define rng_init_rand _glp_rng_init_rand +void rng_init_rand(RNG *rand, int seed); +/* initialize pseudo-random number generator */ + +#define rng_next_rand _glp_rng_next_rand +int rng_next_rand(RNG *rand); +/* obtain pseudo-random integer in the range [0, 2^31-1] */ + +#define rng_unif_rand _glp_rng_unif_rand +int rng_unif_rand(RNG *rand, int m); +/* obtain pseudo-random integer in the range [0, m-1] */ + +#define rng_delete_rand _glp_rng_delete_rand +void rng_delete_rand(RNG *rand); +/* delete pseudo-random number generator */ + +#define rng_unif_01 _glp_rng_unif_01 +double rng_unif_01(RNG *rand); +/* obtain pseudo-random number in the range [0, 1] */ + +#define rng_uniform _glp_rng_uniform +double rng_uniform(RNG *rand, double a, double b); +/* obtain pseudo-random number in the range [a, b] */ + +#endif + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/rng1.c b/test/monniaux/glpk-4.65/src/misc/rng1.c new file mode 100644 index 00000000..b89f676f --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/rng1.c @@ -0,0 +1,73 @@ +/* rng1.c (pseudo-random number generator) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2003-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#include "env.h" +#include "rng.h" + +/*********************************************************************** +* NAME +* +* rng_unif_01 - obtain pseudo-random number in the range [0, 1] +* +* SYNOPSIS +* +* #include "rng.h" +* double rng_unif_01(RNG *rand); +* +* RETURNS +* +* The routine rng_unif_01 returns a next pseudo-random number which is +* uniformly distributed in the range [0, 1]. */ + +double rng_unif_01(RNG *rand) +{ double x; + x = (double)rng_next_rand(rand) / 2147483647.0; + xassert(0.0 <= x && x <= 1.0); + return x; +} + +/*********************************************************************** +* NAME +* +* rng_uniform - obtain pseudo-random number in the range [a, b] +* +* SYNOPSIS +* +* #include "rng.h" +* double rng_uniform(RNG *rand, double a, double b); +* +* RETURNS +* +* The routine rng_uniform returns a next pseudo-random number which is +* uniformly distributed in the range [a, b]. */ + +double rng_uniform(RNG *rand, double a, double b) +{ double x; + xassert(a < b); + x = rng_unif_01(rand); + x = a * (1.0 - x) + b * x; + xassert(a <= x && x <= b); + return x; +} + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/round2n.c b/test/monniaux/glpk-4.65/src/misc/round2n.c new file mode 100644 index 00000000..8a94c616 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/round2n.c @@ -0,0 +1,64 @@ +/* round2n.c (round floating-point number to nearest power of two) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2000-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#include "env.h" +#include "misc.h" + +/*********************************************************************** +* NAME +* +* round2n - round floating-point number to nearest power of two +* +* SYNOPSIS +* +* #include "misc.h" +* double round2n(double x); +* +* RETURNS +* +* Given a positive floating-point value x the routine round2n returns +* 2^n such that |x - 2^n| is minimal. +* +* EXAMPLES +* +* round2n(10.1) = 2^3 = 8 +* round2n(15.3) = 2^4 = 16 +* round2n(0.01) = 2^(-7) = 0.0078125 +* +* BACKGROUND +* +* Let x = f * 2^e, where 0.5 <= f < 1 is a normalized fractional part, +* e is an integer exponent. Then, obviously, 0.5 * 2^e <= x < 2^e, so +* if x - 0.5 * 2^e <= 2^e - x, we choose 0.5 * 2^e = 2^(e-1), and 2^e +* otherwise. The latter condition can be written as 2 * x <= 1.5 * 2^e +* or 2 * f * 2^e <= 1.5 * 2^e or, finally, f <= 0.75. */ + +double round2n(double x) +{ int e; + double f; + xassert(x > 0.0); + f = frexp(x, &e); + return ldexp(1.0, f <= 0.75 ? e-1 : e); +} + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/str2int.c b/test/monniaux/glpk-4.65/src/misc/str2int.c new file mode 100644 index 00000000..cbd6e953 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/str2int.c @@ -0,0 +1,92 @@ +/* str2int.c (convert string to int) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2000-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#include "misc.h" +#include "stdc.h" + +/*********************************************************************** +* NAME +* +* str2int - convert character string to value of int type +* +* SYNOPSIS +* +* #include "misc.h" +* int str2int(const char *str, int *val); +* +* DESCRIPTION +* +* The routine str2int converts the character string str to a value of +* integer type and stores the value into location, which the parameter +* val points to (in the case of error content of this location is not +* changed). +* +* RETURNS +* +* The routine returns one of the following error codes: +* +* 0 - no error; +* 1 - value out of range; +* 2 - character string is syntactically incorrect. */ + +int str2int(const char *str, int *val_) +{ int d, k, s, val = 0; + /* scan optional sign */ + if (str[0] == '+') + s = +1, k = 1; + else if (str[0] == '-') + s = -1, k = 1; + else + s = +1, k = 0; + /* check for the first digit */ + if (!isdigit((unsigned char)str[k])) + return 2; + /* scan digits */ + while (isdigit((unsigned char)str[k])) + { d = str[k++] - '0'; + if (s > 0) + { if (val > INT_MAX / 10) + return 1; + val *= 10; + if (val > INT_MAX - d) + return 1; + val += d; + } + else /* s < 0 */ + { if (val < INT_MIN / 10) + return 1; + val *= 10; + if (val < INT_MIN + d) + return 1; + val -= d; + } + } + /* check for terminator */ + if (str[k] != '\0') + return 2; + /* conversion has been done */ + *val_ = val; + return 0; +} + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/str2num.c b/test/monniaux/glpk-4.65/src/misc/str2num.c new file mode 100644 index 00000000..26c2f68f --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/str2num.c @@ -0,0 +1,110 @@ +/* str2num.c (convert string to double) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2000-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#include "misc.h" +#include "stdc.h" + +/*********************************************************************** +* NAME +* +* str2num - convert character string to value of double type +* +* SYNOPSIS +* +* #include "misc.h" +* int str2num(const char *str, double *val); +* +* DESCRIPTION +* +* The routine str2num converts the character string str to a value of +* double type and stores the value into location, which the parameter +* val points to (in the case of error content of this location is not +* changed). +* +* RETURNS +* +* The routine returns one of the following error codes: +* +* 0 - no error; +* 1 - value out of range; +* 2 - character string is syntactically incorrect. */ + +int str2num(const char *str, double *val_) +{ int k; + double val; + /* scan optional sign */ + k = (str[0] == '+' || str[0] == '-' ? 1 : 0); + /* check for decimal point */ + if (str[k] == '.') + { k++; + /* a digit should follow it */ + if (!isdigit((unsigned char)str[k])) + return 2; + k++; + goto frac; + } + /* integer part should start with a digit */ + if (!isdigit((unsigned char)str[k])) + return 2; + /* scan integer part */ + while (isdigit((unsigned char)str[k])) + k++; + /* check for decimal point */ + if (str[k] == '.') k++; +frac: /* scan optional fraction part */ + while (isdigit((unsigned char)str[k])) + k++; + /* check for decimal exponent */ + if (str[k] == 'E' || str[k] == 'e') + { k++; + /* scan optional sign */ + if (str[k] == '+' || str[k] == '-') + k++; + /* a digit should follow E, E+ or E- */ + if (!isdigit((unsigned char)str[k])) + return 2; + } + /* scan optional exponent part */ + while (isdigit((unsigned char)str[k])) + k++; + /* check for terminator */ + if (str[k] != '\0') + return 2; + /* perform conversion */ + { char *endptr; + val = strtod(str, &endptr); + if (*endptr != '\0') + return 2; + } + /* check for overflow */ + if (!(-DBL_MAX <= val && val <= +DBL_MAX)) + return 1; + /* check for underflow */ + if (-DBL_MIN < val && val < +DBL_MIN) + val = 0.0; + /* conversion has been done */ + *val_ = val; + return 0; +} + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/strspx.c b/test/monniaux/glpk-4.65/src/misc/strspx.c new file mode 100644 index 00000000..fe8a2a10 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/strspx.c @@ -0,0 +1,60 @@ +/* strspx.c (remove all spaces from string) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2000-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#include "misc.h" + +/*********************************************************************** +* NAME +* +* strspx - remove all spaces from character string +* +* SYNOPSIS +* +* #include "misc.h" +* char *strspx(char *str); +* +* DESCRIPTION +* +* The routine strspx removes all spaces from the character string str. +* +* RETURNS +* +* The routine returns a pointer to the character string. +* +* EXAMPLES +* +* strspx(" Errare humanum est ") => "Errarehumanumest" +* +* strspx(" ") => "" */ + +char *strspx(char *str) +{ char *s, *t; + for (s = t = str; *s; s++) + { if (*s != ' ') + *t++ = *s; + } + *t = '\0'; + return str; +} + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/strtrim.c b/test/monniaux/glpk-4.65/src/misc/strtrim.c new file mode 100644 index 00000000..9992c4b0 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/strtrim.c @@ -0,0 +1,62 @@ +/* strtrim.c (remove trailing spaces from string) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2000-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#include "misc.h" +#include "stdc.h" + +/*********************************************************************** +* NAME +* +* strtrim - remove trailing spaces from character string +* +* SYNOPSIS +* +* #include "misc.h" +* char *strtrim(char *str); +* +* DESCRIPTION +* +* The routine strtrim removes trailing spaces from the character +* string str. +* +* RETURNS +* +* The routine returns a pointer to the character string. +* +* EXAMPLES +* +* strtrim("Errare humanum est ") => "Errare humanum est" +* +* strtrim(" ") => "" */ + +char *strtrim(char *str) +{ char *t; + for (t = strrchr(str, '\0') - 1; t >= str; t--) + { if (*t != ' ') + break; + *t = '\0'; + } + return str; +} + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/triang.c b/test/monniaux/glpk-4.65/src/misc/triang.c new file mode 100644 index 00000000..99ba4d60 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/triang.c @@ -0,0 +1,311 @@ +/* triang.c (find maximal triangular part of rectangular matrix) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2012-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#include "env.h" +#include "triang.h" + +/*********************************************************************** +* triang - find maximal triangular part of rectangular matrix +* +* Given a mxn sparse matrix A this routine finds permutation matrices +* P and Q such that matrix A' = P * A * Q has the following structure: +* +* 1 s n +* 1 * . . . . . x x x x x +* * * . . . . x x x x x +* * * * . . . x x x x x +* * * * * . . x x x x x +* * * * * * . x x x x x +* s * * * * * * x x x x x +* x x x x x x x x x x x +* x x x x x x x x x x x +* m x x x x x x x x x x x +* +* where '*' are elements of the triangular part, '.' are structural +* zeros, 'x' are other elements. +* +* The formal routine mat specifies the original matrix A in both row- +* and column-wise format. If the routine mat is called with k = +i, +* 1 <= i <= m, it should store column indices and values of non-zero +* elements of i-th row of A in locations ind[1], ..., ind[len] and +* val[1], ..., val[len], resp., where len is the returned number of +* non-zeros in the row, 0 <= len <= n. Similarly, if the routine mat +* is called with k = -j, 1 <= j <= n, it should store row indices and +* values of non-zero elements of j-th column of A and return len, the +* number of non-zeros in the column, 0 <= len <= m. Should note that +* duplicate indices are not allowed. +* +* The parameter info is a transit pointer passed to the routine mat. +* +* The parameter tol is a tolerance. The routine triang guarantees that +* each diagonal element in the triangular part of matrix A' is not +* less in magnitude than tol * max, where max is the maximal magnitude +* of elements in corresponding column. +* +* On exit the routine triang stores information on the triangular part +* found in the arrays rn and cn. Elements rn[1], ..., rn[s] specify +* row numbers and elements cn[1], ..., cn[s] specify column numbers +* of the original matrix A, which correspond to rows/columns 1, ..., s +* of matrix A', where s is the size of the triangular part returned by +* the routine, 0 <= s <= min(m, n). The order of rows and columns that +* are not included in the triangular part remains unspecified. +* +* ALGORITHM +* +* The routine triang uses a simple greedy heuristic. +* +* At some step the matrix A' = P * A * Q has the following structure: +* +* 1 n +* 1 * . . . . . . . x x x +* * * . . . . . . x x x +* * * * . . . . . x x x +* * * * * . . . . x x x +* x x x x # # # # x x x +* x x x x # # # # x x x +* x x x x # # # # x x x +* x x x x # # # # x x x +* m x x x x # # # # x x x +* +* where '#' are elements of active submatrix. Initially P = Q = I, so +* the active submatrix is the original matrix A = A'. +* +* If some row has exactly one non-zero in the active submatrix (row +* singleton), the routine includes this row and corresponding column +* in the triangular part, and removes the column from the active +* submatrix. Otherwise, the routine simply removes a column having +* maximal number of non-zeros from the active submatrix in the hope +* that new row singleton(s) will appear. +* +* COMPLEXITY +* +* The time complexity of the routine triang is O(nnz), where nnz is +* number of non-zeros in the original matrix A. */ + +int triang(int m, int n, int (*mat)(void *info, int k, int ind[], + double val[]), void *info, double tol, int rn[], int cn[]) +{ int head, i, j, jj, k, kk, ks, len, len2, next_j, ns, size; + int *cind, *rind, *cnt, *ptr, *list, *prev, *next; + double *cval, *rval, *big; + char *flag; + /* allocate working arrays */ + cind = talloc(1+m, int); + cval = talloc(1+m, double); + rind = talloc(1+n, int); + rval = talloc(1+n, double); + cnt = ptr = talloc(1+m, int); + list = talloc(1+n, int); + prev = talloc(1+n, int); + next = talloc(1+n, int); + big = talloc(1+n, double); + flag = talloc(1+n, char); + /*--------------------------------------------------------------*/ + /* build linked lists of columns having equal lengths */ + /*--------------------------------------------------------------*/ + /* ptr[len], 0 <= len <= m, is number of first column of length + * len; + * next[j], 1 <= j <= n, is number of next column having the same + * length as column j; + * big[j], 1 <= j <= n, is maximal magnitude of elements in j-th + * column */ + for (len = 0; len <= m; len++) + ptr[len] = 0; + for (j = 1; j <= n; j++) + { /* get j-th column */ + len = mat(info, -j, cind, cval); + xassert(0 <= len && len <= m); + /* add this column to beginning of list ptr[len] */ + next[j] = ptr[len]; + ptr[len] = j; + /* determine maximal magnitude of elements in this column */ + big[j] = 0.0; + for (k = 1; k <= len; k++) + { if (big[j] < fabs(cval[k])) + big[j] = fabs(cval[k]); + } + } + /*--------------------------------------------------------------*/ + /* build doubly linked list of columns ordered by decreasing */ + /* column lengths */ + /*--------------------------------------------------------------*/ + /* head is number of first column in the list; + * prev[j], 1 <= j <= n, is number of column that precedes j-th + * column in the list; + * next[j], 1 <= j <= n, is number of column that follows j-th + * column in the list */ + head = 0; + for (len = 0; len <= m; len++) + { /* walk thru list of columns of length len */ + for (j = ptr[len]; j != 0; j = next_j) + { next_j = next[j]; + /* add j-th column to beginning of the column list */ + prev[j] = 0; + next[j] = head; + if (head != 0) + prev[head] = j; + head = j; + } + } + /*--------------------------------------------------------------*/ + /* build initial singleton list */ + /*--------------------------------------------------------------*/ + /* there are used two list of columns: + * 1) doubly linked list of active columns, in which all columns + * are ordered by decreasing column lengths; + * 2) singleton list; an active column is included in this list + * if it has at least one row singleton in active submatrix */ + /* flag[j], 1 <= j <= n, is a flag of j-th column: + * 0 j-th column is inactive; + * 1 j-th column is active; + * 2 j-th column is active and has row singleton(s) */ + /* initially all columns are active */ + for (j = 1; j <= n; j++) + flag[j] = 1; + /* initialize row counts and build initial singleton list */ + /* cnt[i], 1 <= i <= m, is number of non-zeros, which i-th row + * has in active submatrix; + * ns is size of singleton list; + * list[1], ..., list[ns] are numbers of active columns included + * in the singleton list */ + ns = 0; + for (i = 1; i <= m; i++) + { /* get i-th row */ + len = cnt[i] = mat(info, +i, rind, rval); + xassert(0 <= len && len <= n); + if (len == 1) + { /* a[i,j] is row singleton */ + j = rind[1]; + xassert(1 <= j && j <= n); + if (flag[j] != 2) + { /* include j-th column in singleton list */ + flag[j] = 2; + list[++ns] = j; + } + } + } + /*--------------------------------------------------------------*/ + /* main loop */ + /*--------------------------------------------------------------*/ + size = 0; /* size of triangular part */ + /* loop until active column list is non-empty, i.e. until the + * active submatrix has at least one column */ + while (head != 0) + { if (ns == 0) + { /* singleton list is empty */ + /* remove from the active submatrix a column of maximal + * length in the hope that some row singletons appear */ + j = head; + len = mat(info, -j, cind, cval); + xassert(0 <= len && len <= m); + goto drop; + } + /* take column j from the singleton list */ + j = list[ns--]; + xassert(flag[j] == 2); + /* j-th column has at least one row singleton in the active + * submatrix; choose one having maximal magnitude */ + len = mat(info, -j, cind, cval); + xassert(0 <= len && len <= m); + kk = 0; + for (k = 1; k <= len; k++) + { i = cind[k]; + xassert(1 <= i && i <= m); + if (cnt[i] == 1) + { /* a[i,j] is row singleton */ + if (kk == 0 || fabs(cval[kk]) < fabs(cval[k])) + kk = k; + } + } + xassert(kk > 0); + /* check magnitude of the row singleton chosen */ + if (fabs(cval[kk]) < tol * big[j]) + { /* all row singletons are too small in magnitude; drop j-th + * column */ + goto drop; + } + /* row singleton a[i,j] is ok; add i-th row and j-th column to + * the triangular part */ + size++; + rn[size] = cind[kk]; + cn[size] = j; +drop: /* remove j-th column from the active submatrix */ + xassert(flag[j]); + flag[j] = 0; + if (prev[j] == 0) + head = next[j]; + else + next[prev[j]] = next[j]; + if (next[j] == 0) + ; + else + prev[next[j]] = prev[j]; + /* decrease row counts */ + for (k = 1; k <= len; k++) + { i = cind[k]; + xassert(1 <= i && i <= m); + xassert(cnt[i] > 0); + cnt[i]--; + if (cnt[i] == 1) + { /* new singleton appeared in i-th row; determine number + * of corresponding column (it is the only active column + * in this row) */ + len2 = mat(info, +i, rind, rval); + xassert(0 <= len2 && len2 <= n); + ks = 0; + for (kk = 1; kk <= len2; kk++) + { jj = rind[kk]; + xassert(1 <= jj && jj <= n); + if (flag[jj]) + { xassert(ks == 0); + ks = kk; + } + } + xassert(ks > 0); + /* a[i,jj] is new row singleton */ + jj = rind[ks]; + if (flag[jj] != 2) + { /* include jj-th column in the singleton list */ + flag[jj] = 2; + list[++ns] = jj; + } + } + } + } + /* now all row counts should be zero */ + for (i = 1; i <= m; i++) + xassert(cnt[i] == 0); + /* deallocate working arrays */ + tfree(cind); + tfree(cval); + tfree(rind); + tfree(rval); + tfree(ptr); + tfree(list); + tfree(prev); + tfree(next); + tfree(big); + tfree(flag); + return size; +} + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/triang.h b/test/monniaux/glpk-4.65/src/misc/triang.h new file mode 100644 index 00000000..1e50d44d --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/triang.h @@ -0,0 +1,34 @@ +/* triang.h (find maximal triangular part of rectangular matrix) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2012-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#ifndef TRIANG_H +#define TRIANG_H + +#define triang _glp_triang +int triang(int m, int n, int (*mat)(void *info, int k, int ind[], + double val[]), void *info, double tol, int rn[], int cn[]); +/* find maximal triangular part of rectangular matrix */ + +#endif + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/wclique.c b/test/monniaux/glpk-4.65/src/misc/wclique.c new file mode 100644 index 00000000..5daa69cf --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/wclique.c @@ -0,0 +1,242 @@ +/* wclique.c (maximum weight clique, Ostergard's algorithm) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Two subroutines sub() and wclique() below are intended to find a +* maximum weight clique in a given undirected graph. These subroutines +* are slightly modified version of the program WCLIQUE developed by +* Patric Ostergard 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 . +* +* 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 . +***********************************************************************/ + +#include "env.h" +#include "wclique.h" + +/*********************************************************************** +* NAME +* +* wclique - find maximum weight clique with Ostergard's algorithm +* +* SYNOPSIS +* +* #include "wclique.h" +* int wclique(int n, const int w[], const unsigned char a[], +* int ind[]); +* +* DESCRIPTION +* +* The routine wclique finds a maximum weight clique in an undirected +* graph with Ostergard's algorithm. +* +* INPUT PARAMETERS +* +* n is the number of vertices, n > 0. +* +* w[i], i = 1,...,n, is a weight of vertex i. +* +* a[*] is the strict (without main diagonal) lower triangle of the +* graph adjacency matrix in packed format. +* +* OUTPUT PARAMETER +* +* ind[k], k = 1,...,size, is the number of a vertex included in the +* clique found, 1 <= ind[k] <= n, where size is the number of vertices +* in the clique returned on exit. +* +* RETURNS +* +* The routine returns the clique size, i.e. the number of vertices in +* the clique. */ + +struct csa +{ /* common storage area */ + int n; + /* number of vertices */ + const int *wt; /* int wt[0:n-1]; */ + /* weights */ + const unsigned char *a; + /* adjacency matrix (packed lower triangle without main diag.) */ + int record; + /* weight of best clique */ + int rec_level; + /* number of vertices in best clique */ + int *rec; /* int rec[0:n-1]; */ + /* best clique so far */ + int *clique; /* int clique[0:n-1]; */ + /* table for pruning */ + int *set; /* int set[0:n-1]; */ + /* current clique */ +}; + +#define n (csa->n) +#define wt (csa->wt) +#define a (csa->a) +#define record (csa->record) +#define rec_level (csa->rec_level) +#define rec (csa->rec) +#define clique (csa->clique) +#define set (csa->set) + +#if 0 +static int is_edge(struct csa *csa, int i, int j) +{ /* if there is arc (i,j), the routine returns true; otherwise + * false; 0 <= i, j < n */ + int k; + xassert(0 <= i && i < n); + xassert(0 <= j && j < n); + if (i == j) return 0; + if (i < j) k = i, i = j, j = k; + k = (i * (i - 1)) / 2 + j; + return a[k / CHAR_BIT] & + (unsigned char)(1 << ((CHAR_BIT - 1) - k % CHAR_BIT)); +} +#else +#define is_edge(csa, i, j) ((i) == (j) ? 0 : \ + (i) > (j) ? is_edge1(i, j) : is_edge1(j, i)) +#define is_edge1(i, j) is_edge2(((i) * ((i) - 1)) / 2 + (j)) +#define is_edge2(k) (a[(k) / CHAR_BIT] & \ + (unsigned char)(1 << ((CHAR_BIT - 1) - (k) % CHAR_BIT))) +#endif + +static void sub(struct csa *csa, int ct, int table[], int level, + int weight, int l_weight) +{ int i, j, k, curr_weight, left_weight, *p1, *p2, *newtable; + newtable = xcalloc(n, sizeof(int)); + if (ct <= 0) + { /* 0 or 1 elements left; include these */ + if (ct == 0) + { set[level++] = table[0]; + weight += l_weight; + } + if (weight > record) + { record = weight; + rec_level = level; + for (i = 0; i < level; i++) rec[i] = set[i]; + } + goto done; + } + for (i = ct; i >= 0; i--) + { if ((level == 0) && (i < ct)) goto done; + k = table[i]; + if ((level > 0) && (clique[k] <= (record - weight))) + goto done; /* prune */ + set[level] = k; + curr_weight = weight + wt[k]; + l_weight -= wt[k]; + if (l_weight <= (record - curr_weight)) + goto done; /* prune */ + p1 = newtable; + p2 = table; + left_weight = 0; + while (p2 < table + i) + { j = *p2++; + if (is_edge(csa, j, k)) + { *p1++ = j; + left_weight += wt[j]; + } + } + if (left_weight <= (record - curr_weight)) continue; + sub(csa, p1 - newtable - 1, newtable, level + 1, curr_weight, + left_weight); + } +done: xfree(newtable); + return; +} + +int wclique(int n_, const int w[], const unsigned char a_[], int ind[]) +{ struct csa csa_, *csa = &csa_; + int i, j, p, max_wt, max_nwt, wth, *used, *nwt, *pos; + double timer; + n = n_; + xassert(n > 0); + wt = &w[1]; + a = a_; + record = 0; + rec_level = 0; + rec = &ind[1]; + clique = xcalloc(n, sizeof(int)); + set = xcalloc(n, sizeof(int)); + used = xcalloc(n, sizeof(int)); + nwt = xcalloc(n, sizeof(int)); + pos = xcalloc(n, sizeof(int)); + /* start timer */ + timer = xtime(); + /* order vertices */ + for (i = 0; i < n; i++) + { nwt[i] = 0; + for (j = 0; j < n; j++) + if (is_edge(csa, i, j)) nwt[i] += wt[j]; + } + for (i = 0; i < n; i++) + used[i] = 0; + for (i = n-1; i >= 0; i--) + { max_wt = -1; + max_nwt = -1; + for (j = 0; j < n; j++) + { if ((!used[j]) && ((wt[j] > max_wt) || (wt[j] == max_wt + && nwt[j] > max_nwt))) + { max_wt = wt[j]; + max_nwt = nwt[j]; + p = j; + } + } + pos[i] = p; + used[p] = 1; + for (j = 0; j < n; j++) + if ((!used[j]) && (j != p) && (is_edge(csa, p, j))) + nwt[j] -= wt[p]; + } + /* main routine */ + wth = 0; + for (i = 0; i < n; i++) + { wth += wt[pos[i]]; + sub(csa, i, pos, 0, 0, wth); + clique[pos[i]] = record; + if (xdifftime(xtime(), timer) >= 5.0 - 0.001) + { /* print current record and reset timer */ + xprintf("level = %d (%d); best = %d\n", i+1, n, record); + timer = xtime(); + } + } + xfree(clique); + xfree(set); + xfree(used); + xfree(nwt); + xfree(pos); + /* return the solution found */ + for (i = 1; i <= rec_level; i++) ind[i]++; + return rec_level; +} + +#undef n +#undef wt +#undef a +#undef record +#undef rec_level +#undef rec +#undef clique +#undef set + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/wclique.h b/test/monniaux/glpk-4.65/src/misc/wclique.h new file mode 100644 index 00000000..d52dc805 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/wclique.h @@ -0,0 +1,33 @@ +/* wclique.h (maximum weight clique, Ostergard's algorithm) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2009-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#ifndef WCLIQUE_H +#define WCLIQUE_H + +#define wclique _glp_wclique +int wclique(int n, const int w[], const unsigned char a[], int ind[]); +/* find maximum weight clique with Ostergard's algorithm */ + +#endif + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/wclique1.c b/test/monniaux/glpk-4.65/src/misc/wclique1.c new file mode 100644 index 00000000..a3d89542 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/wclique1.c @@ -0,0 +1,317 @@ +/* wclique1.c (maximum weight clique, greedy heuristic) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2012-2018 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#include "env.h" +#include "wclique1.h" + +/*********************************************************************** +* NAME +* +* wclique1 - find maximum weight clique with greedy heuristic +* +* SYNOPSIS +* +* #include "wclique1.h" +* int wclique1(int n, const double w[], +* int (*func)(void *info, int i, int ind[]), void *info, int c[]); +* +* DESCRIPTION +* +* The routine wclique1 implements a sequential greedy heuristic to +* find maximum weight clique in a given (undirected) graph G = (V, E). +* +* The parameter n specifies the number of vertices |V| in the graph, +* n >= 0. +* +* The array w specifies vertex weights in locations w[i], i = 1,...,n. +* All weights must be non-negative. +* +* The formal routine func specifies the graph. For a given vertex i, +* 1 <= i <= n, it stores indices of all vertices adjacent to vertex i +* in locations ind[1], ..., ind[deg], where deg is the degree of +* vertex i, 0 <= deg < n, returned on exit. Note that self-loops and +* multiple edges are not allowed. +* +* The parameter info is a cookie passed to the routine func. +* +* On exit the routine wclique1 stores vertex indices included in +* the clique found to locations c[1], ..., c[size], where size is the +* clique size returned by the routine, 0 <= size <= n. +* +* RETURNS +* +* The routine wclique1 returns the size of the clique found. */ + +struct vertex { int i; double cw; }; + +static int CDECL fcmp(const void *xx, const void *yy) +{ const struct vertex *x = xx, *y = yy; + if (x->cw > y->cw) return -1; + if (x->cw < y->cw) return +1; + return 0; +} + +int wclique1(int n, const double w[], + int (*func)(void *info, int i, int ind[]), void *info, int c[]) +{ struct vertex *v_list; + int deg, c_size, d_size, i, j, k, kk, l, *ind, *c_list, *d_list, + size = 0; + double c_wght, d_wght, *sw, best = 0.0; + char *d_flag, *skip; + /* perform sanity checks */ + xassert(n >= 0); + for (i = 1; i <= n; i++) + xassert(w[i] >= 0.0); + /* if the graph is empty, nothing to do */ + if (n == 0) goto done; + /* allocate working arrays */ + ind = xcalloc(1+n, sizeof(int)); + v_list = xcalloc(1+n, sizeof(struct vertex)); + c_list = xcalloc(1+n, sizeof(int)); + d_list = xcalloc(1+n, sizeof(int)); + d_flag = xcalloc(1+n, sizeof(char)); + skip = xcalloc(1+n, sizeof(char)); + sw = xcalloc(1+n, sizeof(double)); + /* build the vertex list */ + for (i = 1; i <= n; i++) + { v_list[i].i = i; + /* compute the cumulative weight of each vertex i, which is + * cw[i] = w[i] + sum{j : (i,j) in E} w[j] */ + v_list[i].cw = w[i]; + deg = func(info, i, ind); + xassert(0 <= deg && deg < n); + for (k = 1; k <= deg; k++) + { j = ind[k]; + xassert(1 <= j && j <= n && j != i); + v_list[i].cw += w[j]; + } + } + /* sort the vertex list to access vertices in descending order of + * cumulative weights */ + qsort(&v_list[1], n, sizeof(struct vertex), fcmp); + /* initially all vertices are unmarked */ + memset(&skip[1], 0, sizeof(char) * n); + /* clear flags of all vertices */ + memset(&d_flag[1], 0, sizeof(char) * n); + /* look through all vertices of the graph */ + for (l = 1; l <= n; l++) + { /* take vertex i */ + i = v_list[l].i; + /* if this vertex was already included in one of previosuly + * constructed cliques, skip it */ + if (skip[i]) continue; + /* use vertex i as the initial clique vertex */ + c_size = 1; /* size of current clique */ + c_list[1] = i; /* list of vertices in current clique */ + c_wght = w[i]; /* weight of current clique */ + /* determine the candidate set D = { j : (i,j) in E } */ + d_size = func(info, i, d_list); + xassert(0 <= d_size && d_size < n); + d_wght = 0.0; /* weight of set D */ + for (k = 1; k <= d_size; k++) + { j = d_list[k]; + xassert(1 <= j && j <= n && j != i); + xassert(!d_flag[j]); + d_flag[j] = 1; + d_wght += w[j]; + } + /* check an upper bound to the final clique weight */ + if (c_wght + d_wght < best + 1e-5 * (1.0 + fabs(best))) + { /* skip constructing the current clique */ + goto next; + } + /* compute the summary weight of each vertex i in D, which is + * sw[i] = w[i] + sum{j in D and (i,j) in E} w[j] */ + for (k = 1; k <= d_size; k++) + { i = d_list[k]; + sw[i] = w[i]; + /* consider vertices adjacent to vertex i */ + deg = func(info, i, ind); + xassert(0 <= deg && deg < n); + for (kk = 1; kk <= deg; kk++) + { j = ind[kk]; + xassert(1 <= j && j <= n && j != i); + if (d_flag[j]) sw[i] += w[j]; + } + } + /* grow the current clique by adding vertices from D */ + while (d_size > 0) + { /* check an upper bound to the final clique weight */ + if (c_wght + d_wght < best + 1e-5 * (1.0 + fabs(best))) + { /* skip constructing the current clique */ + goto next; + } + /* choose vertex i in D having maximal summary weight */ + i = d_list[1]; + for (k = 2; k <= d_size; k++) + { j = d_list[k]; + if (sw[i] < sw[j]) i = j; + } + /* include vertex i in the current clique */ + c_size++; + c_list[c_size] = i; + c_wght += w[i]; + /* remove all vertices not adjacent to vertex i, including + * vertex i itself, from the candidate set D */ + deg = func(info, i, ind); + xassert(0 <= deg && deg < n); + for (k = 1; k <= deg; k++) + { j = ind[k]; + xassert(1 <= j && j <= n && j != i); + /* vertex j is adjacent to vertex i */ + if (d_flag[j]) + { xassert(d_flag[j] == 1); + /* mark vertex j to keep it in D */ + d_flag[j] = 2; + } + } + kk = d_size, d_size = 0; + for (k = 1; k <= kk; k++) + { j = d_list[k]; + if (d_flag[j] == 1) + { /* remove vertex j from D */ + d_flag[j] = 0; + d_wght -= w[j]; + } + else if (d_flag[j] == 2) + { /* keep vertex j in D */ + d_list[++d_size] = j; + d_flag[j] = 1; + } + else + xassert(d_flag != d_flag); + } + } + /* the current clique has been completely constructed */ + if (best < c_wght) + { best = c_wght; + size = c_size; + xassert(1 <= size && size <= n); + memcpy(&c[1], &c_list[1], size * sizeof(int)); + } +next: /* mark the current clique vertices in order not to use them + * as initial vertices anymore */ + for (k = 1; k <= c_size; k++) + skip[c_list[k]] = 1; + /* set D can be non-empty, so clean up vertex flags */ + for (k = 1; k <= d_size; k++) + d_flag[d_list[k]] = 0; + } + /* free working arrays */ + xfree(ind); + xfree(v_list); + xfree(c_list); + xfree(d_list); + xfree(d_flag); + xfree(skip); + xfree(sw); +done: /* return to the calling program */ + return size; +} + +/**********************************************************************/ + +#ifdef GLP_TEST +#include "glpk.h" +#include "rng.h" + +typedef struct { double w; } v_data; + +#define weight(v) (((v_data *)((v)->data))->w) + +glp_graph *G; + +char *flag; + +int func(void *info, int i, int ind[]) +{ glp_arc *e; + int j, k, deg = 0; + xassert(info == NULL); + xassert(1 <= i && i <= G->nv); + /* look through incoming arcs */ + for (e = G->v[i]->in; e != NULL; e = e->h_next) + { j = e->tail->i; /* j->i */ + if (j != i && !flag[j]) ind[++deg] = j, flag[j] = 1; + } + /* look through outgoing arcs */ + for (e = G->v[i]->out; e != NULL; e = e->t_next) + { j = e->head->i; /* i->j */ + if (j != i && !flag[j]) ind[++deg] = j, flag[j] = 1; + } + /* clear the flag array */ + xassert(deg < G->nv); + for (k = 1; k <= deg; k++) flag[ind[k]] = 0; + return deg; +} + +int main(int argc, char *argv[]) +{ RNG *rand; + int i, k, kk, size, *c, *ind, deg; + double *w, sum, t; + /* read graph in DIMACS format */ + G = glp_create_graph(sizeof(v_data), 0); + xassert(argc == 2); + xassert(glp_read_ccdata(G, offsetof(v_data, w), argv[1]) == 0); + /* print the number of connected components */ + xprintf("nc = %d\n", glp_weak_comp(G, -1)); + /* assign random weights unformly distributed in [1,100] */ + w = xcalloc(1+G->nv, sizeof(double)); + rand = rng_create_rand(); + for (i = 1; i <= G->nv; i++) +#if 0 + w[i] = weight(G->v[i]) = 1.0; +#else + w[i] = weight(G->v[i]) = rng_unif_rand(rand, 100) + 1; +#endif + /* write graph in DIMACS format */ + xassert(glp_write_ccdata(G, offsetof(v_data, w), "graph") == 0); + /* find maximum weight clique */ + c = xcalloc(1+G->nv, sizeof(int)); + flag = xcalloc(1+G->nv, sizeof(char)); + memset(&flag[1], 0, G->nv); + t = xtime(); + size = wclique1(G->nv, w, func, NULL, c); + xprintf("Time used: %.1f s\n", xdifftime(xtime(), t)); + /* check the clique found */ + ind = xcalloc(1+G->nv, sizeof(int)); + for (k = 1; k <= size; k++) + { i = c[k]; + deg = func(NULL, i, ind); + for (kk = 1; kk <= size; kk++) + flag[c[kk]] = 1; + flag[i] = 0; + for (kk = 1; kk <= deg; kk++) + flag[ind[kk]] = 0; + for (kk = 1; kk <= size; kk++) + xassert(flag[c[kk]] == 0); + } + /* compute the clique weight */ + sum = 0.0; + for (i = 1; i <= size; i++) + sum += w[c[i]]; + xprintf("size = %d; sum = %g\n", size, sum); + return 0; +} +#endif + +/* eof */ diff --git a/test/monniaux/glpk-4.65/src/misc/wclique1.h b/test/monniaux/glpk-4.65/src/misc/wclique1.h new file mode 100644 index 00000000..588f3257 --- /dev/null +++ b/test/monniaux/glpk-4.65/src/misc/wclique1.h @@ -0,0 +1,34 @@ +/* wclique1.h (maximum weight clique, greedy heuristic) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* +* Copyright (C) 2012-2013 Andrew Makhorin, Department for Applied +* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights +* reserved. E-mail: . +* +* 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 . +***********************************************************************/ + +#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 */ -- cgit