diff options
| author | Pasha <pasha@member.fsf.org> | 2023-01-27 00:54:07 +0000 | 
|---|---|---|
| committer | Pasha <pasha@member.fsf.org> | 2023-01-27 00:54:07 +0000 | 
| commit | ef800d4ffafdbde7d7a172ad73bd984b1695c138 (patch) | |
| tree | 920cc189130f1e98f252283fce94851443641a6d /glpk-5.0/src/api | |
| parent | ec4ae3c2b5cb0e83fb667f14f832ea94f68ef075 (diff) | |
| download | oneapi-master.tar.gz oneapi-master.tar.bz2  | |
Diffstat (limited to 'glpk-5.0/src/api')
55 files changed, 13138 insertions, 0 deletions
diff --git a/glpk-5.0/src/api/advbas.c b/glpk-5.0/src/api/advbas.c new file mode 100644 index 0000000..1aa76d0 --- /dev/null +++ b/glpk-5.0/src/api/advbas.c @@ -0,0 +1,153 @@ +/* advbas.c (construct advanced initial LP basis) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2008-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" +#include "triang.h" + +/*********************************************************************** +*  NAME +* +*  glp_adv_basis - construct advanced initial LP basis +* +*  SYNOPSIS +* +*  void glp_adv_basis(glp_prob *P, int flags); +* +*  DESCRIPTION +* +*  The routine glp_adv_basis constructs an advanced initial LP basis +*  for the specified problem object. +* +*  The parameter flag is reserved for use in the future and should be +*  specified as zero. +* +*  NOTE +* +*  The routine glp_adv_basis should be called after the constraint +*  matrix has been scaled (if scaling is used). */ + +static int mat(void *info, int k, int ind[], double val[]) +{     glp_prob *P = info; +      int m = P->m; +      int n = P->n; +      GLPROW **row = P->row; +      GLPCOL **col = P->col; +      GLPAIJ *aij; +      int i, j, len; +      if (k > 0) +      {  /* retrieve scaled row of constraint matrix */ +         i = +k; +         xassert(1 <= i && i <= m); +         len = 0; +         if (row[i]->type == GLP_FX) +         {  for (aij = row[i]->ptr; aij != NULL; aij = aij->r_next) +            {  j = aij->col->j; +               if (col[j]->type != GLP_FX) +               {  len++; +                  ind[len] = j; +                  val[len] = aij->row->rii * aij->val * aij->col->sjj; +               } +            } +         } +      } +      else +      {  /* retrieve scaled column of constraint matrix */ +         j = -k; +         xassert(1 <= j && j <= n); +         len = 0; +         if (col[j]->type != GLP_FX) +         {  for (aij = col[j]->ptr; aij != NULL; aij = aij->c_next) +            {  i = aij->row->i; +               if (row[i]->type == GLP_FX) +               {  len++; +                  ind[len] = i; +                  val[len] = aij->row->rii * aij->val * aij->col->sjj; +               } +            } +         } +      } +      return len; +} + +void glp_adv_basis(glp_prob *P, int flags) +{     int i, j, k, m, n, min_mn, size, *rn, *cn; +      char *flag; +      if (flags != 0) +         xerror("glp_adv_basis: flags = %d; invalid flags\n", flags); +      m = P->m; /* number of rows */ +      n = P->n; /* number of columns */ +      if (m == 0 || n == 0) +      {  /* trivial case */ +         glp_std_basis(P); +         goto done; +      } +      xprintf("Constructing initial basis...\n"); +      /* allocate working arrays */ +      min_mn = (m < n ? m : n); +      rn = talloc(1+min_mn, int); +      cn = talloc(1+min_mn, int); +      flag = talloc(1+m, char); +      /* make the basis empty */ +      for (i = 1; i <= m; i++) +      {  flag[i] = 0; +         glp_set_row_stat(P, i, GLP_NS); +      } +      for (j = 1; j <= n; j++) +         glp_set_col_stat(P, j, GLP_NS); +      /* find maximal triangular part of the constraint matrix; +         to prevent including non-fixed rows and fixed columns in the +         triangular part, such rows and columns are temporarily made +         empty by the routine mat */ +#if 1 /* FIXME: tolerance */ +      size = triang(m, n, mat, P, 0.001, rn, cn); +#endif +      xassert(0 <= size && size <= min_mn); +      /* include in the basis non-fixed structural variables, whose +         columns constitute the triangular part */ +      for (k = 1; k <= size; k++) +      {  i = rn[k]; +         xassert(1 <= i && i <= m); +         flag[i] = 1; +         j = cn[k]; +         xassert(1 <= j && j <= n); +         glp_set_col_stat(P, j, GLP_BS); +      } +      /* include in the basis appropriate auxiliary variables, whose +         unity columns preserve triangular form of the basis matrix */ +      for (i = 1; i <= m; i++) +      {  if (flag[i] == 0) +         {  glp_set_row_stat(P, i, GLP_BS); +            if (P->row[i]->type != GLP_FX) +               size++; +         } +      } +      /* size of triangular part = (number of rows) - (number of basic +         fixed auxiliary variables) */ +      xprintf("Size of triangular part is %d\n", size); +      /* deallocate working arrays */ +      tfree(rn); +      tfree(cn); +      tfree(flag); +done: return; +} + +/* eof */ diff --git a/glpk-5.0/src/api/asnhall.c b/glpk-5.0/src/api/asnhall.c new file mode 100644 index 0000000..38ac287 --- /dev/null +++ b/glpk-5.0/src/api/asnhall.c @@ -0,0 +1,161 @@ +/* asnhall.c (find bipartite matching of maximum cardinality) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" +#include "mc21a.h" + +/*********************************************************************** +*  NAME +* +*  glp_asnprob_hall - find bipartite matching of maximum cardinality +* +*  SYNOPSIS +* +*  int glp_asnprob_hall(glp_graph *G, int v_set, int a_x); +* +*  DESCRIPTION +* +*  The routine glp_asnprob_hall finds a matching of maximal cardinality +*  in the specified bipartite graph G. It uses a version of the Fortran +*  routine MC21A developed by I.S.Duff [1], which implements Hall's +*  algorithm [2]. +* +*  RETURNS +* +*  The routine glp_asnprob_hall returns the cardinality of the matching +*  found. However, if the specified graph is incorrect (as detected by +*  the routine glp_check_asnprob), the routine returns negative value. +* +*  REFERENCES +* +*  1. I.S.Duff, Algorithm 575: Permutations for zero-free diagonal, ACM +*     Trans. on Math. Softw. 7 (1981), 387-390. +* +*  2. M.Hall, "An Algorithm for distinct representatives," Amer. Math. +*     Monthly 63 (1956), 716-717. */ + +int glp_asnprob_hall(glp_graph *G, int v_set, int a_x) +{     glp_vertex *v; +      glp_arc *a; +      int card, i, k, loc, n, n1, n2, xij; +      int *num, *icn, *ip, *lenr, *iperm, *pr, *arp, *cv, *out; +      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int)) +         xerror("glp_asnprob_hall: v_set = %d; invalid offset\n", +            v_set); +      if (a_x >= 0 && a_x > G->a_size - (int)sizeof(int)) +         xerror("glp_asnprob_hall: a_x = %d; invalid offset\n", a_x); +      if (glp_check_asnprob(G, v_set)) +         return -1; +      /* determine the number of vertices in sets R and S and renumber +         vertices in S which correspond to columns of the matrix; skip +         all isolated vertices */ +      num = xcalloc(1+G->nv, sizeof(int)); +      n1 = n2 = 0; +      for (i = 1; i <= G->nv; i++) +      {  v = G->v[i]; +         if (v->in == NULL && v->out != NULL) +            n1++, num[i] = 0; /* vertex in R */ +         else if (v->in != NULL && v->out == NULL) +            n2++, num[i] = n2; /* vertex in S */ +         else +         {  xassert(v->in == NULL && v->out == NULL); +            num[i] = -1; /* isolated vertex */ +         } +      } +      /* the matrix must be square, thus, if it has more columns than +         rows, extra rows will be just empty, and vice versa */ +      n = (n1 >= n2 ? n1 : n2); +      /* allocate working arrays */ +      icn = xcalloc(1+G->na, sizeof(int)); +      ip = xcalloc(1+n, sizeof(int)); +      lenr = xcalloc(1+n, sizeof(int)); +      iperm = xcalloc(1+n, sizeof(int)); +      pr = xcalloc(1+n, sizeof(int)); +      arp = xcalloc(1+n, sizeof(int)); +      cv = xcalloc(1+n, sizeof(int)); +      out = xcalloc(1+n, sizeof(int)); +      /* build the adjacency matrix of the bipartite graph in row-wise +         format (rows are vertices in R, columns are vertices in S) */ +      k = 0, loc = 1; +      for (i = 1; i <= G->nv; i++) +      {  if (num[i] != 0) continue; +         /* vertex i in R */ +         ip[++k] = loc; +         v = G->v[i]; +         for (a = v->out; a != NULL; a = a->t_next) +         {  xassert(num[a->head->i] != 0); +            icn[loc++] = num[a->head->i]; +         } +         lenr[k] = loc - ip[k]; +      } +      xassert(loc-1 == G->na); +      /* make all extra rows empty (all extra columns are empty due to +         the row-wise format used) */ +      for (k++; k <= n; k++) +         ip[k] = loc, lenr[k] = 0; +      /* find a row permutation that maximizes the number of non-zeros +         on the main diagonal */ +      card = mc21a(n, icn, ip, lenr, iperm, pr, arp, cv, out); +#if 1 /* 18/II-2010 */ +      /* FIXED: if card = n, arp remains clobbered on exit */ +      for (i = 1; i <= n; i++) +         arp[i] = 0; +      for (i = 1; i <= card; i++) +      {  k = iperm[i]; +         xassert(1 <= k && k <= n); +         xassert(arp[k] == 0); +         arp[k] = i; +      } +#endif +      /* store solution, if necessary */ +      if (a_x < 0) goto skip; +      k = 0; +      for (i = 1; i <= G->nv; i++) +      {  if (num[i] != 0) continue; +         /* vertex i in R */ +         k++; +         v = G->v[i]; +         for (a = v->out; a != NULL; a = a->t_next) +         {  /* arp[k] is the number of matched column or zero */ +            if (arp[k] == num[a->head->i]) +            {  xassert(arp[k] != 0); +               xij = 1; +            } +            else +               xij = 0; +            memcpy((char *)a->data + a_x, &xij, sizeof(int)); +         } +      } +skip: /* free working arrays */ +      xfree(num); +      xfree(icn); +      xfree(ip); +      xfree(lenr); +      xfree(iperm); +      xfree(pr); +      xfree(arp); +      xfree(cv); +      xfree(out); +      return card; +} + +/* eof */ diff --git a/glpk-5.0/src/api/asnlp.c b/glpk-5.0/src/api/asnlp.c new file mode 100644 index 0000000..b7bac6c --- /dev/null +++ b/glpk-5.0/src/api/asnlp.c @@ -0,0 +1,102 @@ +/* asnlp.c (convert assignment problem to LP) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" + +/*********************************************************************** +*  NAME +* +*  glp_asnprob_lp - convert assignment problem to LP +* +*  SYNOPSIS +* +*  int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G, int names, +*     int v_set, int a_cost); +* +*  DESCRIPTION +* +*  The routine glp_asnprob_lp builds an LP problem, which corresponds +*  to the assignment problem on the specified graph G. +* +*  RETURNS +* +*  If the LP problem has been successfully built, the routine returns +*  zero, otherwise, non-zero. */ + +int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G, int names, +      int v_set, int a_cost) +{     glp_vertex *v; +      glp_arc *a; +      int i, j, ret, ind[1+2]; +      double cost, val[1+2]; +      if (!(form == GLP_ASN_MIN || form == GLP_ASN_MAX || +            form == GLP_ASN_MMP)) +         xerror("glp_asnprob_lp: form = %d; invalid parameter\n", +            form); +      if (!(names == GLP_ON || names == GLP_OFF)) +         xerror("glp_asnprob_lp: names = %d; invalid parameter\n", +            names); +      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int)) +         xerror("glp_asnprob_lp: v_set = %d; invalid offset\n", +            v_set); +      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) +         xerror("glp_asnprob_lp: a_cost = %d; invalid offset\n", +            a_cost); +      ret = glp_check_asnprob(G, v_set); +      if (ret != 0) goto done; +      glp_erase_prob(P); +      if (names) glp_set_prob_name(P, G->name); +      glp_set_obj_dir(P, form == GLP_ASN_MIN ? GLP_MIN : GLP_MAX); +      if (G->nv > 0) glp_add_rows(P, G->nv); +      for (i = 1; i <= G->nv; i++) +      {  v = G->v[i]; +         if (names) glp_set_row_name(P, i, v->name); +         glp_set_row_bnds(P, i, form == GLP_ASN_MMP ? GLP_UP : GLP_FX, +            1.0, 1.0); +      } +      if (G->na > 0) glp_add_cols(P, G->na); +      for (i = 1, j = 0; i <= G->nv; i++) +      {  v = G->v[i]; +         for (a = v->out; a != NULL; a = a->t_next) +         {  j++; +            if (names) +            {  char name[50+1]; +               sprintf(name, "x[%d,%d]", a->tail->i, a->head->i); +               xassert(strlen(name) < sizeof(name)); +               glp_set_col_name(P, j, name); +            } +            ind[1] = a->tail->i, val[1] = +1.0; +            ind[2] = a->head->i, val[2] = +1.0; +            glp_set_mat_col(P, j, 2, ind, val); +            glp_set_col_bnds(P, j, GLP_DB, 0.0, 1.0); +            if (a_cost >= 0) +               memcpy(&cost, (char *)a->data + a_cost, sizeof(double)); +            else +               cost = 1.0; +            glp_set_obj_coef(P, j, cost); +         } +      } +      xassert(j == G->na); +done: return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/asnokalg.c b/glpk-5.0/src/api/asnokalg.c new file mode 100644 index 0000000..54236e7 --- /dev/null +++ b/glpk-5.0/src/api/asnokalg.c @@ -0,0 +1,152 @@ +/* asnokalg.c (solve assignment problem with out-of-kilter alg.) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" +#include "okalg.h" + +int glp_asnprob_okalg(int form, glp_graph *G, int v_set, int a_cost, +      double *sol, int a_x) +{     /* solve assignment problem with out-of-kilter algorithm */ +      glp_vertex *v; +      glp_arc *a; +      int nv, na, i, k, *tail, *head, *low, *cap, *cost, *x, *pi, ret; +      double temp; +      if (!(form == GLP_ASN_MIN || form == GLP_ASN_MAX || +            form == GLP_ASN_MMP)) +         xerror("glp_asnprob_okalg: form = %d; invalid parameter\n", +            form); +      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int)) +         xerror("glp_asnprob_okalg: v_set = %d; invalid offset\n", +            v_set); +      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) +         xerror("glp_asnprob_okalg: a_cost = %d; invalid offset\n", +            a_cost); +      if (a_x >= 0 && a_x > G->a_size - (int)sizeof(int)) +         xerror("glp_asnprob_okalg: a_x = %d; invalid offset\n", a_x); +      if (glp_check_asnprob(G, v_set)) +         return GLP_EDATA; +      /* nv is the total number of nodes in the resulting network */ +      nv = G->nv + 1; +      /* na is the total number of arcs in the resulting network */ +      na = G->na + G->nv; +      /* allocate working arrays */ +      tail = xcalloc(1+na, sizeof(int)); +      head = xcalloc(1+na, sizeof(int)); +      low = xcalloc(1+na, sizeof(int)); +      cap = xcalloc(1+na, sizeof(int)); +      cost = xcalloc(1+na, sizeof(int)); +      x = xcalloc(1+na, sizeof(int)); +      pi = xcalloc(1+nv, sizeof(int)); +      /* construct the resulting network */ +      k = 0; +      /* (original arcs) */ +      for (i = 1; i <= G->nv; i++) +      {  v = G->v[i]; +         for (a = v->out; a != NULL; a = a->t_next) +         {  k++; +            tail[k] = a->tail->i; +            head[k] = a->head->i; +            low[k] = 0; +            cap[k] = 1; +            if (a_cost >= 0) +               memcpy(&temp, (char *)a->data + a_cost, sizeof(double)); +            else +               temp = 1.0; +            if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp))) +            {  ret = GLP_EDATA; +               goto done; +            } +            cost[k] = (int)temp; +            if (form != GLP_ASN_MIN) cost[k] = - cost[k]; +         } +      } +      /* (artificial arcs) */ +      for (i = 1; i <= G->nv; i++) +      {  v = G->v[i]; +         k++; +         if (v->out == NULL) +            tail[k] = i, head[k] = nv; +         else if (v->in == NULL) +            tail[k] = nv, head[k] = i; +         else +            xassert(v != v); +         low[k] = (form == GLP_ASN_MMP ? 0 : 1); +         cap[k] = 1; +         cost[k] = 0; +      } +      xassert(k == na); +      /* find minimal-cost circulation in the resulting network */ +      ret = okalg(nv, na, tail, head, low, cap, cost, x, pi); +      switch (ret) +      {  case 0: +            /* optimal circulation found */ +            ret = 0; +            break; +         case 1: +            /* no feasible circulation exists */ +            ret = GLP_ENOPFS; +            break; +         case 2: +            /* integer overflow occured */ +            ret = GLP_ERANGE; +            goto done; +         case 3: +            /* optimality test failed (logic error) */ +            ret = GLP_EFAIL; +            goto done; +         default: +            xassert(ret != ret); +      } +      /* store solution components */ +      /* (objective function = the total cost) */ +      if (sol != NULL) +      {  temp = 0.0; +         for (k = 1; k <= na; k++) +            temp += (double)cost[k] * (double)x[k]; +         if (form != GLP_ASN_MIN) temp = - temp; +         *sol = temp; +      } +      /* (arc flows) */ +      if (a_x >= 0) +      {  k = 0; +         for (i = 1; i <= G->nv; i++) +         {  v = G->v[i]; +            for (a = v->out; a != NULL; a = a->t_next) +            {  k++; +               if (ret == 0) +                  xassert(x[k] == 0 || x[k] == 1); +               memcpy((char *)a->data + a_x, &x[k], sizeof(int)); +            } +         } +      } +done: /* free working arrays */ +      xfree(tail); +      xfree(head); +      xfree(low); +      xfree(cap); +      xfree(cost); +      xfree(x); +      xfree(pi); +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/ckasn.c b/glpk-5.0/src/api/ckasn.c new file mode 100644 index 0000000..0cb9e0d --- /dev/null +++ b/glpk-5.0/src/api/ckasn.c @@ -0,0 +1,76 @@ +/* ckasn.c (check correctness of assignment problem data) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" + +/*********************************************************************** +*  NAME +* +*  glp_check_asnprob - check correctness of assignment problem data +* +*  SYNOPSIS +* +*  int glp_check_asnprob(glp_graph *G, int v_set); +* +*  RETURNS +* +*  If the specified assignment problem data are correct, the routine +*  glp_check_asnprob returns zero, otherwise, non-zero. */ + +int glp_check_asnprob(glp_graph *G, int v_set) +{     glp_vertex *v; +      int i, k, ret = 0; +      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int)) +         xerror("glp_check_asnprob: v_set = %d; invalid offset\n", +            v_set); +      for (i = 1; i <= G->nv; i++) +      {  v = G->v[i]; +         if (v_set >= 0) +         {  memcpy(&k, (char *)v->data + v_set, sizeof(int)); +            if (k == 0) +            {  if (v->in != NULL) +               {  ret = 1; +                  break; +               } +            } +            else if (k == 1) +            {  if (v->out != NULL) +               {  ret = 2; +                  break; +               } +            } +            else +            {  ret = 3; +               break; +            } +         } +         else +         {  if (v->in != NULL && v->out != NULL) +            {  ret = 4; +               break; +            } +         } +      } +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/ckcnf.c b/glpk-5.0/src/api/ckcnf.c new file mode 100644 index 0000000..26decce --- /dev/null +++ b/glpk-5.0/src/api/ckcnf.c @@ -0,0 +1,80 @@ +/* ckcnf.c (check for CNF-SAT problem instance) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2010-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +int glp_check_cnfsat(glp_prob *P) +{     /* check for CNF-SAT problem instance */ +      int m = P->m; +      int n = P->n; +      GLPROW *row; +      GLPCOL *col; +      GLPAIJ *aij; +      int i, j, neg; +#if 0 /* 04/IV-2016 */ +      if (P == NULL || P->magic != GLP_PROB_MAGIC) +         xerror("glp_check_cnfsat: P = %p; invalid problem object\n", +            P); +#endif +      /* check columns */ +      for (j = 1; j <= n; j++) +      {  col = P->col[j]; +         /* the variable should be binary */ +         if (!(col->kind == GLP_IV && col->type == GLP_DB && +               col->lb == 0.0 && col->ub == 1.0)) +            return 1; +      } +      /* objective function should be zero */ +      if (P->c0 != 0.0) +         return 2; +      for (j = 1; j <= n; j++) +      {  col = P->col[j]; +         if (col->coef != 0.0) +            return 3; +      } +      /* check rows */ +      for (i = 1; i <= m; i++) +      {  row = P->row[i]; +         /* the row should be of ">=" type */ +         if (row->type != GLP_LO) +            return 4; +         /* check constraint coefficients */ +         neg = 0; +         for (aij = row->ptr; aij != NULL; aij = aij->r_next) +         {  /* the constraint coefficient should be +1 or -1 */ +            if (aij->val == +1.0) +               ; +            else if (aij->val == -1.0) +               neg++; +            else +               return 5; +         } +         /* the right-hand side should be (1 - neg), where neg is the +            number of negative constraint coefficients in the row */ +         if (row->lb != (double)(1 - neg)) +            return 6; +      } +      /* congratulations; this is CNF-SAT */ +      return 0; +} + +/* eof */ diff --git a/glpk-5.0/src/api/cplex.c b/glpk-5.0/src/api/cplex.c new file mode 100644 index 0000000..45ecaa2 --- /dev/null +++ b/glpk-5.0/src/api/cplex.c @@ -0,0 +1,1281 @@ +/* cplex.c (CPLEX LP format routines) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2018 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "misc.h" +#include "prob.h" + +#define xfprintf glp_format + +/*********************************************************************** +*  NAME +* +*  glp_init_cpxcp - initialize CPLEX LP format control parameters +* +*  SYNOPSIS +* +*  void glp_init_cpxcp(glp_cpxcp *parm): +* +*  The routine glp_init_cpxcp initializes control parameters used by +*  the CPLEX LP input/output routines glp_read_lp and glp_write_lp with +*  default values. +* +*  Default values of the control parameters are stored in the glp_cpxcp +*  structure, which the parameter parm points to. */ + +void glp_init_cpxcp(glp_cpxcp *parm) +{     xassert(parm != NULL); +      return; +} + +static void check_parm(const char *func, const glp_cpxcp *parm) +{     /* check control parameters */ +      xassert(func != NULL); +      xassert(parm != NULL); +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_read_lp - read problem data in CPLEX LP format +* +*  SYNOPSIS +* +*  int glp_read_lp(glp_prob *P, const glp_cpxcp *parm, const char +*     *fname); +* +*  DESCRIPTION +* +*  The routine glp_read_lp reads problem data in CPLEX LP format from +*  a text file. +* +*  The parameter parm is a pointer to the structure glp_cpxcp, which +*  specifies control parameters used by the routine. If parm is NULL, +*  the routine uses default settings. +* +*  The character string fname specifies a name of the text file to be +*  read. +* +*  Note that before reading data the current content of the problem +*  object is completely erased with the routine glp_erase_prob. +* +*  RETURNS +* +*  If the operation was successful, the routine glp_read_lp returns +*  zero. Otherwise, it prints an error message and returns non-zero. */ + +struct csa +{     /* common storage area */ +      glp_prob *P; +      /* LP/MIP problem object */ +      const glp_cpxcp *parm; +      /* pointer to control parameters */ +      const char *fname; +      /* name of input CPLEX LP file */ +      glp_file *fp; +      /* stream assigned to input CPLEX LP file */ +      jmp_buf jump; +      /* label for go to in case of error */ +      int count; +      /* line count */ +      int c; +      /* current character or EOF */ +      int token; +      /* current token: */ +#define T_EOF        0x00  /* end of file */ +#define T_MINIMIZE   0x01  /* keyword 'minimize' */ +#define T_MAXIMIZE   0x02  /* keyword 'maximize' */ +#define T_SUBJECT_TO 0x03  /* keyword 'subject to' */ +#define T_BOUNDS     0x04  /* keyword 'bounds' */ +#define T_GENERAL    0x05  /* keyword 'general' */ +#define T_INTEGER    0x06  /* keyword 'integer' */ +#define T_BINARY     0x07  /* keyword 'binary' */ +#define T_END        0x08  /* keyword 'end' */ +#define T_NAME       0x09  /* symbolic name */ +#define T_NUMBER     0x0A  /* numeric constant */ +#define T_PLUS       0x0B  /* delimiter '+' */ +#define T_MINUS      0x0C  /* delimiter '-' */ +#define T_COLON      0x0D  /* delimiter ':' */ +#define T_LE         0x0E  /* delimiter '<=' */ +#define T_GE         0x0F  /* delimiter '>=' */ +#define T_EQ         0x10  /* delimiter '=' */ +      char image[255+1]; +      /* image of current token */ +      int imlen; +      /* length of token image */ +      double value; +      /* value of numeric constant */ +      int n_max; +      /* length of the following five arrays (enlarged automatically, +         if necessary) */ +      int *ind; /* int ind[1+n_max]; */ +      double *val; /* double val[1+n_max]; */ +      char *flag; /* char flag[1+n_max]; */ +      /* working arrays used to construct linear forms */ +      double *lb; /* double lb[1+n_max]; */ +      double *ub; /* double ub[1+n_max]; */ +      /* lower and upper bounds of variables (columns) */ +#if 1 /* 27/VII-2013 */ +      int lb_warn, ub_warn; +      /* warning 'lower/upper bound redefined' already issued */ +#endif +}; + +#define CHAR_SET "!\"#$%&()/,.;?@_`'{}|~" +/* characters that may appear in symbolic names */ + +static void error(struct csa *csa, const char *fmt, ...) +{     /* print error message and terminate processing */ +      va_list arg; +      xprintf("%s:%d: ", csa->fname, csa->count); +      va_start(arg, fmt); +      xvprintf(fmt, arg); +      va_end(arg); +      longjmp(csa->jump, 1); +      /* no return */ +} + +static void warning(struct csa *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); +      return; +} + +static void read_char(struct csa *csa) +{     /* read next character from input file */ +      int c; +      xassert(csa->c != EOF); +      if (csa->c == '\n') csa->count++; +      c = glp_getc(csa->fp); +      if (c < 0) +      {  if (glp_ioerr(csa->fp)) +            error(csa, "read error - %s\n", get_err_msg()); +         else if (csa->c == '\n') +         {  csa->count--; +            c = EOF; +         } +         else +         {  warning(csa, "missing final end of line\n"); +            c = '\n'; +         } +      } +      else if (c == '\n') +         ; +      else if (isspace(c)) +         c = ' '; +      else if (iscntrl(c)) +         error(csa, "invalid control character 0x%02X\n", c); +      csa->c = c; +      return; +} + +static void add_char(struct csa *csa) +{     /* append current character to current token */ +      if (csa->imlen == sizeof(csa->image)-1) +         error(csa, "token '%.15s...' too long\n", csa->image); +      csa->image[csa->imlen++] = (char)csa->c; +      csa->image[csa->imlen] = '\0'; +      read_char(csa); +      return; +} + +static int the_same(char *s1, char *s2) +{     /* compare two character strings ignoring case sensitivity */ +      for (; *s1 != '\0'; s1++, s2++) +      {  if (tolower((unsigned char)*s1) != tolower((unsigned char)*s2)) +            return 0; +      } +      return 1; +} + +static void scan_token(struct csa *csa) +{     /* scan next token */ +      int flag; +      csa->token = -1; +      csa->image[0] = '\0'; +      csa->imlen = 0; +      csa->value = 0.0; +loop: flag = 0; +      /* skip non-significant characters */ +      while (csa->c == ' ') read_char(csa); +      /* recognize and scan current token */ +      if (csa->c == EOF) +         csa->token = T_EOF; +      else if (csa->c == '\n') +      {  read_char(csa); +         /* if the next character is letter, it may begin a keyword */ +         if (isalpha(csa->c)) +         {  flag = 1; +            goto name; +         } +         goto loop; +      } +      else if (csa->c == '\\') +      {  /* comment; ignore everything until end-of-line */ +         while (csa->c != '\n') read_char(csa); +         goto loop; +      } +      else if (isalpha(csa->c) || csa->c != '.' && strchr(CHAR_SET, +         csa->c) != NULL) +name: {  /* symbolic name */ +         csa->token = T_NAME; +         while (isalnum(csa->c) || strchr(CHAR_SET, csa->c) != NULL) +            add_char(csa); +         if (flag) +         {  /* check for keyword */ +            if (the_same(csa->image, "minimize")) +               csa->token = T_MINIMIZE; +            else if (the_same(csa->image, "minimum")) +               csa->token = T_MINIMIZE; +            else if (the_same(csa->image, "min")) +               csa->token = T_MINIMIZE; +            else if (the_same(csa->image, "maximize")) +               csa->token = T_MAXIMIZE; +            else if (the_same(csa->image, "maximum")) +               csa->token = T_MAXIMIZE; +            else if (the_same(csa->image, "max")) +               csa->token = T_MAXIMIZE; +            else if (the_same(csa->image, "subject")) +            {  if (csa->c == ' ') +               {  read_char(csa); +                  if (tolower(csa->c) == 't') +                  {  csa->token = T_SUBJECT_TO; +                     csa->image[csa->imlen++] = ' '; +                     csa->image[csa->imlen] = '\0'; +                     add_char(csa); +                     if (tolower(csa->c) != 'o') +                        error(csa, "keyword 'subject to' incomplete\n"); +                     add_char(csa); +                     if (isalpha(csa->c)) +                        error(csa, "keyword '%s%c...' not recognized\n", +                           csa->image, csa->c); +                  } +               } +            } +            else if (the_same(csa->image, "such")) +            {  if (csa->c == ' ') +               {  read_char(csa); +                  if (tolower(csa->c) == 't') +                  {  csa->token = T_SUBJECT_TO; +                     csa->image[csa->imlen++] = ' '; +                     csa->image[csa->imlen] = '\0'; +                     add_char(csa); +                     if (tolower(csa->c) != 'h') +err:                    error(csa, "keyword 'such that' incomplete\n"); +                     add_char(csa); +                     if (tolower(csa->c) != 'a') goto err; +                     add_char(csa); +                     if (tolower(csa->c) != 't') goto err; +                     add_char(csa); +                     if (isalpha(csa->c)) +                        error(csa, "keyword '%s%c...' not recognized\n", +                           csa->image, csa->c); +                  } +               } +            } +            else if (the_same(csa->image, "st")) +               csa->token = T_SUBJECT_TO; +            else if (the_same(csa->image, "s.t.")) +               csa->token = T_SUBJECT_TO; +            else if (the_same(csa->image, "st.")) +               csa->token = T_SUBJECT_TO; +            else if (the_same(csa->image, "bounds")) +               csa->token = T_BOUNDS; +            else if (the_same(csa->image, "bound")) +               csa->token = T_BOUNDS; +            else if (the_same(csa->image, "general")) +               csa->token = T_GENERAL; +            else if (the_same(csa->image, "generals")) +               csa->token = T_GENERAL; +            else if (the_same(csa->image, "gen")) +               csa->token = T_GENERAL; +            else if (the_same(csa->image, "integer")) +               csa->token = T_INTEGER; +            else if (the_same(csa->image, "integers")) +               csa->token = T_INTEGER; +            else if (the_same(csa->image, "int")) +              csa->token = T_INTEGER; +            else if (the_same(csa->image, "binary")) +               csa->token = T_BINARY; +            else if (the_same(csa->image, "binaries")) +               csa->token = T_BINARY; +            else if (the_same(csa->image, "bin")) +               csa->token = T_BINARY; +            else if (the_same(csa->image, "end")) +               csa->token = T_END; +         } +      } +      else if (isdigit(csa->c) || csa->c == '.') +      {  /* numeric constant */ +         csa->token = T_NUMBER; +         /* scan integer part */ +         while (isdigit(csa->c)) add_char(csa); +         /* scan optional fractional part (it is mandatory, if there is +            no integer part) */ +         if (csa->c == '.') +         {  add_char(csa); +            if (csa->imlen == 1 && !isdigit(csa->c)) +               error(csa, "invalid use of decimal point\n"); +            while (isdigit(csa->c)) add_char(csa); +         } +         /* scan optional decimal exponent */ +         if (csa->c == 'e' || csa->c == 'E') +         {  add_char(csa); +            if (csa->c == '+' || csa->c == '-') add_char(csa); +            if (!isdigit(csa->c)) +               error(csa, "numeric constant '%s' incomplete\n", +                  csa->image); +            while (isdigit(csa->c)) add_char(csa); +         } +         /* convert the numeric constant to floating-point */ +         if (str2num(csa->image, &csa->value)) +            error(csa, "numeric constant '%s' out of range\n", +               csa->image); +      } +      else if (csa->c == '+') +         csa->token = T_PLUS, add_char(csa); +      else if (csa->c == '-') +         csa->token = T_MINUS, add_char(csa); +      else if (csa->c == ':') +         csa->token = T_COLON, add_char(csa); +      else if (csa->c == '<') +      {  csa->token = T_LE, add_char(csa); +         if (csa->c == '=') add_char(csa); +      } +      else if (csa->c == '>') +      {  csa->token = T_GE, add_char(csa); +         if (csa->c == '=') add_char(csa); +      } +      else if (csa->c == '=') +      {  csa->token = T_EQ, add_char(csa); +         if (csa->c == '<') +            csa->token = T_LE, add_char(csa); +         else if (csa->c == '>') +            csa->token = T_GE, add_char(csa); +      } +      else +         error(csa, "character '%c' not recognized\n", csa->c); +      /* skip non-significant characters */ +      while (csa->c == ' ') read_char(csa); +      return; +} + +static int find_col(struct csa *csa, char *name) +{     /* find column by its symbolic name */ +      int j; +      j = glp_find_col(csa->P, name); +      if (j == 0) +      {  /* not found; create new column */ +         j = glp_add_cols(csa->P, 1); +         glp_set_col_name(csa->P, j, name); +         /* enlarge working arrays, if necessary */ +         if (csa->n_max < j) +         {  int n_max = csa->n_max; +            int *ind = csa->ind; +            double *val = csa->val; +            char *flag = csa->flag; +            double *lb = csa->lb; +            double *ub = csa->ub; +            csa->n_max += csa->n_max; +            csa->ind = xcalloc(1+csa->n_max, sizeof(int)); +            memcpy(&csa->ind[1], &ind[1], n_max * sizeof(int)); +            xfree(ind); +            csa->val = xcalloc(1+csa->n_max, sizeof(double)); +            memcpy(&csa->val[1], &val[1], n_max * sizeof(double)); +            xfree(val); +            csa->flag = xcalloc(1+csa->n_max, sizeof(char)); +            memset(&csa->flag[1], 0, csa->n_max * sizeof(char)); +            memcpy(&csa->flag[1], &flag[1], n_max * sizeof(char)); +            xfree(flag); +            csa->lb = xcalloc(1+csa->n_max, sizeof(double)); +            memcpy(&csa->lb[1], &lb[1], n_max * sizeof(double)); +            xfree(lb); +            csa->ub = xcalloc(1+csa->n_max, sizeof(double)); +            memcpy(&csa->ub[1], &ub[1], n_max * sizeof(double)); +            xfree(ub); +         } +         csa->lb[j] = +DBL_MAX, csa->ub[j] = -DBL_MAX; +      } +      return j; +} + +/*********************************************************************** +*  parse_linear_form - parse linear form +* +*  This routine parses the linear form using the following syntax: +* +*  <variable> ::= <symbolic name> +*  <coefficient> ::= <numeric constant> +*  <term> ::= <variable> | <numeric constant> <variable> +*  <linear form> ::= <term> | + <term> | - <term> | +*     <linear form> + <term> | <linear form> - <term> +* +*  The routine returns the number of terms in the linear form. */ + +static int parse_linear_form(struct csa *csa) +{     int j, k, len = 0, newlen; +      double s, coef; +loop: /* parse an optional sign */ +      if (csa->token == T_PLUS) +         s = +1.0, scan_token(csa); +      else if (csa->token == T_MINUS) +         s = -1.0, scan_token(csa); +      else +         s = +1.0; +      /* parse an optional coefficient */ +      if (csa->token == T_NUMBER) +         coef = csa->value, scan_token(csa); +      else +         coef = 1.0; +      /* parse a variable name */ +      if (csa->token != T_NAME) +         error(csa, "missing variable name\n"); +      /* find the corresponding column */ +      j = find_col(csa, csa->image); +      /* check if the variable is already used in the linear form */ +      if (csa->flag[j]) +         error(csa, "multiple use of variable '%s' not allowed\n", +            csa->image); +      /* add new term to the linear form */ +      len++, csa->ind[len] = j, csa->val[len] = s * coef; +      /* and mark that the variable is used in the linear form */ +      csa->flag[j] = 1; +      scan_token(csa); +      /* if the next token is a sign, there is another term */ +      if (csa->token == T_PLUS || csa->token == T_MINUS) goto loop; +      /* clear marks of the variables used in the linear form */ +      for (k = 1; k <= len; k++) csa->flag[csa->ind[k]] = 0; +      /* remove zero coefficients */ +      newlen = 0; +      for (k = 1; k <= len; k++) +      {  if (csa->val[k] != 0.0) +         {  newlen++; +            csa->ind[newlen] = csa->ind[k]; +            csa->val[newlen] = csa->val[k]; +         } +      } +      return newlen; +} + +/*********************************************************************** +*  parse_objective - parse objective function +* +*  This routine parses definition of the objective function using the +*  following syntax: +* +*  <obj sense> ::= minimize | minimum | min | maximize | maximum | max +*  <obj name> ::= <empty> | <symbolic name> : +*  <obj function> ::= <obj sense> <obj name> <linear form> */ + +static void parse_objective(struct csa *csa) +{     /* parse objective sense */ +      int k, len; +      /* parse the keyword 'minimize' or 'maximize' */ +      if (csa->token == T_MINIMIZE) +         glp_set_obj_dir(csa->P, GLP_MIN); +      else if (csa->token == T_MAXIMIZE) +         glp_set_obj_dir(csa->P, GLP_MAX); +      else +         xassert(csa != csa); +      scan_token(csa); +      /* parse objective name */ +      if (csa->token == T_NAME && csa->c == ':') +      {  /* objective name is followed by a colon */ +         glp_set_obj_name(csa->P, csa->image); +         scan_token(csa); +         xassert(csa->token == T_COLON); +         scan_token(csa); +      } +      else +      {  /* objective name is not specified; use default */ +         glp_set_obj_name(csa->P, "obj"); +      } +      /* parse linear form */ +      len = parse_linear_form(csa); +      for (k = 1; k <= len; k++) +         glp_set_obj_coef(csa->P, csa->ind[k], csa->val[k]); +      return; +} + +/*********************************************************************** +*  parse_constraints - parse constraints section +* +*  This routine parses the constraints section using the following +*  syntax: +* +*  <row name> ::= <empty> | <symbolic name> : +*  <row sense> ::= < | <= | =< | > | >= | => | = +*  <right-hand side> ::= <numeric constant> | + <numeric constant> | +*     - <numeric constant> +*  <constraint> ::= <row name> <linear form> <row sense> +*     <right-hand side> +*  <subject to> ::= subject to | such that | st | s.t. | st. +*  <constraints section> ::= <subject to> <constraint> | +*     <constraints section> <constraint> */ + +static void parse_constraints(struct csa *csa) +{     int i, len, type; +      double s; +      /* parse the keyword 'subject to' */ +      xassert(csa->token == T_SUBJECT_TO); +      scan_token(csa); +loop: /* create new row (constraint) */ +      i = glp_add_rows(csa->P, 1); +      /* parse row name */ +      if (csa->token == T_NAME && csa->c == ':') +      {  /* row name is followed by a colon */ +         if (glp_find_row(csa->P, csa->image) != 0) +            error(csa, "constraint '%s' multiply defined\n", +               csa->image); +         glp_set_row_name(csa->P, i, csa->image); +         scan_token(csa); +         xassert(csa->token == T_COLON); +         scan_token(csa); +      } +      else +      {  /* row name is not specified; use default */ +         char name[50]; +         sprintf(name, "r.%d", csa->count); +         glp_set_row_name(csa->P, i, name); +      } +      /* parse linear form */ +      len = parse_linear_form(csa); +      glp_set_mat_row(csa->P, i, len, csa->ind, csa->val); +      /* parse constraint sense */ +      if (csa->token == T_LE) +         type = GLP_UP, scan_token(csa); +      else if (csa->token == T_GE) +         type = GLP_LO, scan_token(csa); +      else if (csa->token == T_EQ) +         type = GLP_FX, scan_token(csa); +      else +         error(csa, "missing constraint sense\n"); +      /* parse right-hand side */ +      if (csa->token == T_PLUS) +         s = +1.0, scan_token(csa); +      else if (csa->token == T_MINUS) +         s = -1.0, scan_token(csa); +      else +         s = +1.0; +      if (csa->token != T_NUMBER) +         error(csa, "missing right-hand side\n"); +      glp_set_row_bnds(csa->P, i, type, s * csa->value, s * csa->value); +      /* the rest of the current line must be empty */ +      if (!(csa->c == '\n' || csa->c == EOF)) +         error(csa, "invalid symbol(s) beyond right-hand side\n"); +      scan_token(csa); +      /* if the next token is a sign, numeric constant, or a symbolic +         name, here is another constraint */ +      if (csa->token == T_PLUS || csa->token == T_MINUS || +          csa->token == T_NUMBER || csa->token == T_NAME) goto loop; +      return; +} + +static void set_lower_bound(struct csa *csa, int j, double lb) +{     /* set lower bound of j-th variable */ +      if (csa->lb[j] != +DBL_MAX && !csa->lb_warn) +      {  warning(csa, "lower bound of variable '%s' redefined\n", +            glp_get_col_name(csa->P, j)); +         csa->lb_warn = 1; +      } +      csa->lb[j] = lb; +      return; +} + +static void set_upper_bound(struct csa *csa, int j, double ub) +{     /* set upper bound of j-th variable */ +      if (csa->ub[j] != -DBL_MAX && !csa->ub_warn) +      {  warning(csa, "upper bound of variable '%s' redefined\n", +            glp_get_col_name(csa->P, j)); +         csa->ub_warn = 1; +      } +      csa->ub[j] = ub; +      return; +} + +/*********************************************************************** +*  parse_bounds - parse bounds section +* +*  This routine parses the bounds section using the following syntax: +* +*  <variable> ::= <symbolic name> +*  <infinity> ::= infinity | inf +*  <bound> ::= <numeric constant> | + <numeric constant> | +*     - <numeric constant> | + <infinity> | - <infinity> +*  <lt> ::= < | <= | =< +*  <gt> ::= > | >= | => +*  <bound definition> ::= <bound> <lt> <variable> <lt> <bound> | +*     <bound> <lt> <variable> | <variable> <lt> <bound> | +*     <variable> <gt> <bound> | <variable> = <bound> | <variable> free +*  <bounds> ::= bounds | bound +*  <bounds section> ::= <bounds> | +*     <bounds section> <bound definition> */ + +static void parse_bounds(struct csa *csa) +{     int j, lb_flag; +      double lb, s; +      /* parse the keyword 'bounds' */ +      xassert(csa->token == T_BOUNDS); +      scan_token(csa); +loop: /* bound definition can start with a sign, numeric constant, or +         a symbolic name */ +      if (!(csa->token == T_PLUS || csa->token == T_MINUS || +            csa->token == T_NUMBER || csa->token == T_NAME)) goto done; +      /* parse bound definition */ +      if (csa->token == T_PLUS || csa->token == T_MINUS) +      {  /* parse signed lower bound */ +         lb_flag = 1; +         s = (csa->token == T_PLUS ? +1.0 : -1.0); +         scan_token(csa); +         if (csa->token == T_NUMBER) +            lb = s * csa->value, scan_token(csa); +         else if (the_same(csa->image, "infinity") || +                  the_same(csa->image, "inf")) +         {  if (s > 0.0) +               error(csa, "invalid use of '+inf' as lower bound\n"); +            lb = -DBL_MAX, scan_token(csa); +         } +         else +            error(csa, "missing lower bound\n"); +      } +      else if (csa->token == T_NUMBER) +      {  /* parse unsigned lower bound */ +         lb_flag = 1; +         lb = csa->value, scan_token(csa); +      } +      else +      {  /* lower bound is not specified */ +         lb_flag = 0; +      } +      /* parse the token that should follow the lower bound */ +      if (lb_flag) +      {  if (csa->token != T_LE) +            error(csa, "missing '<', '<=', or '=<' after lower bound\n") +               ; +         scan_token(csa); +      } +      /* parse variable name */ +      if (csa->token != T_NAME) +         error(csa, "missing variable name\n"); +      j = find_col(csa, csa->image); +      /* set lower bound */ +      if (lb_flag) set_lower_bound(csa, j, lb); +      scan_token(csa); +      /* parse the context that follows the variable name */ +      if (csa->token == T_LE) +      {  /* parse upper bound */ +         scan_token(csa); +         if (csa->token == T_PLUS || csa->token == T_MINUS) +         {  /* parse signed upper bound */ +            s = (csa->token == T_PLUS ? +1.0 : -1.0); +            scan_token(csa); +            if (csa->token == T_NUMBER) +            {  set_upper_bound(csa, j, s * csa->value); +               scan_token(csa); +            } +            else if (the_same(csa->image, "infinity") || +                     the_same(csa->image, "inf")) +            {  if (s < 0.0) +                  error(csa, "invalid use of '-inf' as upper bound\n"); +               set_upper_bound(csa, j, +DBL_MAX); +               scan_token(csa); +            } +            else +               error(csa, "missing upper bound\n"); +         } +         else if (csa->token == T_NUMBER) +         {  /* parse unsigned upper bound */ +            set_upper_bound(csa, j, csa->value); +            scan_token(csa); +         } +         else +            error(csa, "missing upper bound\n"); +      } +      else if (csa->token == T_GE) +      {  /* parse lower bound */ +         if (lb_flag) +         {  /* the context '... <= x >= ...' is invalid */ +            error(csa, "invalid bound definition\n"); +         } +         scan_token(csa); +         if (csa->token == T_PLUS || csa->token == T_MINUS) +         {  /* parse signed lower bound */ +            s = (csa->token == T_PLUS ? +1.0 : -1.0); +            scan_token(csa); +            if (csa->token == T_NUMBER) +            {  set_lower_bound(csa, j, s * csa->value); +               scan_token(csa); +            } +            else if (the_same(csa->image, "infinity") || +                     the_same(csa->image, "inf") == 0) +            {  if (s > 0.0) +                  error(csa, "invalid use of '+inf' as lower bound\n"); +               set_lower_bound(csa, j, -DBL_MAX); +               scan_token(csa); +            } +            else +               error(csa, "missing lower bound\n"); +         } +         else if (csa->token == T_NUMBER) +         {  /* parse unsigned lower bound */ +            set_lower_bound(csa, j, csa->value); +            scan_token(csa); +         } +         else +            error(csa, "missing lower bound\n"); +      } +      else if (csa->token == T_EQ) +      {  /* parse fixed value */ +         if (lb_flag) +         {  /* the context '... <= x = ...' is invalid */ +            error(csa, "invalid bound definition\n"); +         } +         scan_token(csa); +         if (csa->token == T_PLUS || csa->token == T_MINUS) +         {  /* parse signed fixed value */ +            s = (csa->token == T_PLUS ? +1.0 : -1.0); +            scan_token(csa); +            if (csa->token == T_NUMBER) +            {  set_lower_bound(csa, j, s * csa->value); +               set_upper_bound(csa, j, s * csa->value); +               scan_token(csa); +            } +            else +               error(csa, "missing fixed value\n"); +         } +         else if (csa->token == T_NUMBER) +         {  /* parse unsigned fixed value */ +            set_lower_bound(csa, j, csa->value); +            set_upper_bound(csa, j, csa->value); +            scan_token(csa); +         } +         else +            error(csa, "missing fixed value\n"); +      } +      else if (the_same(csa->image, "free")) +      {  /* parse the keyword 'free' */ +         if (lb_flag) +         {  /* the context '... <= x free ...' is invalid */ +            error(csa, "invalid bound definition\n"); +         } +         set_lower_bound(csa, j, -DBL_MAX); +         set_upper_bound(csa, j, +DBL_MAX); +         scan_token(csa); +      } +      else if (!lb_flag) +      {  /* neither lower nor upper bounds are specified */ +         error(csa, "invalid bound definition\n"); +      } +      goto loop; +done: return; +} + +/*********************************************************************** +*  parse_integer - parse general, integer, or binary section +* +*  <variable> ::= <symbolic name> +*  <general> ::= general | generals | gen +*  <integer> ::= integer | integers | int +*  <binary> ::= binary | binaries | bin +*  <section head> ::= <general> <integer> <binary> +*  <additional section> ::= <section head> | +*     <additional section> <variable> */ + +static void parse_integer(struct csa *csa) +{     int j, binary; +      /* parse the keyword 'general', 'integer', or 'binary' */ +      if (csa->token == T_GENERAL) +         binary = 0, scan_token(csa); +      else if (csa->token == T_INTEGER) +         binary = 0, scan_token(csa); +      else if (csa->token == T_BINARY) +         binary = 1, scan_token(csa); +      else +         xassert(csa != csa); +      /* parse list of variables (may be empty) */ +      while (csa->token == T_NAME) +      {  /* find the corresponding column */ +         j = find_col(csa, csa->image); +         /* change kind of the variable */ +         glp_set_col_kind(csa->P, j, GLP_IV); +         /* set bounds for the binary variable */ +         if (binary) +#if 0 /* 07/VIII-2013 */ +         {  set_lower_bound(csa, j, 0.0); +            set_upper_bound(csa, j, 1.0); +         } +#else +         {  set_lower_bound(csa, j, +               csa->lb[j] == +DBL_MAX ? 0.0 : csa->lb[j]); +            set_upper_bound(csa, j, +               csa->ub[j] == -DBL_MAX ? 1.0 : csa->ub[j]); +         } +#endif +         scan_token(csa); +      } +      return; +} + +int glp_read_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname) +{     /* read problem data in CPLEX LP format */ +      glp_cpxcp _parm; +      struct csa _csa, *csa = &_csa; +      int ret; +      xprintf("Reading problem data from '%s'...\n", fname); +      if (parm == NULL) +         glp_init_cpxcp(&_parm), parm = &_parm; +      /* check control parameters */ +      check_parm("glp_read_lp", parm); +      /* initialize common storage area */ +      csa->P = P; +      csa->parm = parm; +      csa->fname = fname; +      csa->fp = NULL; +      if (setjmp(csa->jump)) +      {  ret = 1; +         goto done; +      } +      csa->count = 0; +      csa->c = '\n'; +      csa->token = T_EOF; +      csa->image[0] = '\0'; +      csa->imlen = 0; +      csa->value = 0.0; +      csa->n_max = 100; +      csa->ind = xcalloc(1+csa->n_max, sizeof(int)); +      csa->val = xcalloc(1+csa->n_max, sizeof(double)); +      csa->flag = xcalloc(1+csa->n_max, sizeof(char)); +      memset(&csa->flag[1], 0, csa->n_max * sizeof(char)); +      csa->lb = xcalloc(1+csa->n_max, sizeof(double)); +      csa->ub = xcalloc(1+csa->n_max, sizeof(double)); +#if 1 /* 27/VII-2013 */ +      csa->lb_warn = csa->ub_warn = 0; +#endif +      /* erase problem object */ +      glp_erase_prob(P); +      glp_create_index(P); +      /* open input CPLEX LP file */ +      csa->fp = glp_open(fname, "r"); +      if (csa->fp == NULL) +      {  xprintf("Unable to open '%s' - %s\n", fname, get_err_msg()); +         ret = 1; +         goto done; +      } +      /* scan very first token */ +      scan_token(csa); +      /* parse definition of the objective function */ +      if (!(csa->token == T_MINIMIZE || csa->token == T_MAXIMIZE)) +         error(csa, "'minimize' or 'maximize' keyword missing\n"); +      parse_objective(csa); +      /* parse constraints section */ +      if (csa->token != T_SUBJECT_TO) +         error(csa, "constraints section missing\n"); +      parse_constraints(csa); +      /* parse optional bounds section */ +      if (csa->token == T_BOUNDS) parse_bounds(csa); +      /* parse optional general, integer, and binary sections */ +      while (csa->token == T_GENERAL || +             csa->token == T_INTEGER || +             csa->token == T_BINARY) parse_integer(csa); +      /* check for the keyword 'end' */ +      if (csa->token == T_END) +         scan_token(csa); +      else if (csa->token == T_EOF) +         warning(csa, "keyword 'end' missing\n"); +      else +         error(csa, "symbol '%s' in wrong position\n", csa->image); +      /* nothing must follow the keyword 'end' (except comments) */ +      if (csa->token != T_EOF) +         error(csa, "extra symbol(s) detected beyond 'end'\n"); +      /* set bounds of variables */ +      {  int j, type; +         double lb, ub; +         for (j = 1; j <= P->n; j++) +         {  lb = csa->lb[j]; +            ub = csa->ub[j]; +            if (lb == +DBL_MAX) lb = 0.0;      /* default lb */ +            if (ub == -DBL_MAX) ub = +DBL_MAX; /* default ub */ +            if (lb == -DBL_MAX && ub == +DBL_MAX) +               type = GLP_FR; +            else if (ub == +DBL_MAX) +               type = GLP_LO; +            else if (lb == -DBL_MAX) +               type = GLP_UP; +            else if (lb != ub) +               type = GLP_DB; +            else +               type = GLP_FX; +            glp_set_col_bnds(csa->P, j, type, lb, ub); +         } +      } +      /* print some statistics */ +      xprintf("%d row%s, %d column%s, %d non-zero%s\n", +         P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s", +         P->nnz, P->nnz == 1 ? "" : "s"); +      if (glp_get_num_int(P) > 0) +      {  int ni = glp_get_num_int(P); +         int nb = glp_get_num_bin(P); +         if (ni == 1) +         {  if (nb == 0) +               xprintf("One variable is integer\n"); +            else +               xprintf("One variable is binary\n"); +         } +         else +         {  xprintf("%d integer variables, ", ni); +            if (nb == 0) +               xprintf("none"); +            else if (nb == 1) +               xprintf("one"); +            else if (nb == ni) +               xprintf("all"); +            else +               xprintf("%d", nb); +            xprintf(" of which %s binary\n", nb == 1 ? "is" : "are"); +         } +      } +      xprintf("%d lines were read\n", csa->count); +      /* problem data has been successfully read */ +      glp_delete_index(P); +      glp_sort_matrix(P); +      ret = 0; +done: if (csa->fp != NULL) glp_close(csa->fp); +      xfree(csa->ind); +      xfree(csa->val); +      xfree(csa->flag); +      xfree(csa->lb); +      xfree(csa->ub); +      if (ret != 0) glp_erase_prob(P); +      return ret; +} + +/*********************************************************************** +*  NAME +* +*  glp_write_lp - write problem data in CPLEX LP format +* +*  SYNOPSIS +* +*  int glp_write_lp(glp_prob *P, const glp_cpxcp *parm, const char +*     *fname); +* +*  DESCRIPTION +* +*  The routine glp_write_lp writes problem data in CPLEX LP format to +*  a text file. +* +*  The parameter parm is a pointer to the structure glp_cpxcp, which +*  specifies control parameters used by the routine. If parm is NULL, +*  the routine uses default settings. +* +*  The character string fname specifies a name of the text file to be +*  written. +* +*  RETURNS +* +*  If the operation was successful, the routine glp_write_lp returns +*  zero. Otherwise, it prints an error message and returns non-zero. */ + +#define csa csa1 + +struct csa +{     /* common storage area */ +      glp_prob *P; +      /* pointer to problem object */ +      const glp_cpxcp *parm; +      /* pointer to control parameters */ +}; + +static int check_name(char *name) +{     /* check if specified name is valid for CPLEX LP format */ +      if (*name == '.') return 1; +      if (isdigit((unsigned char)*name)) return 1; +      for (; *name; name++) +      {  if (!isalnum((unsigned char)*name) && +             strchr(CHAR_SET, (unsigned char)*name) == NULL) return 1; +      } +      return 0; /* name is ok */ +} + +static void adjust_name(char *name) +{     /* attempt to adjust specified name to make it valid for CPLEX LP +         format */ +      for (; *name; name++) +      {  if (*name == ' ') +            *name = '_'; +         else if (*name == '-') +            *name = '~'; +         else if (*name == '[') +            *name = '('; +         else if (*name == ']') +            *name = ')'; +      } +      return; +} + +static char *row_name(struct csa *csa, int i, char rname[255+1]) +{     /* construct symbolic name of i-th row (constraint) */ +      const char *name; +      if (i == 0) +         name = glp_get_obj_name(csa->P); +      else +         name = glp_get_row_name(csa->P, i); +      if (name == NULL) goto fake; +      strcpy(rname, name); +      adjust_name(rname); +      if (check_name(rname)) goto fake; +      return rname; +fake: if (i == 0) +         strcpy(rname, "obj"); +      else +         sprintf(rname, "r_%d", i); +      return rname; +} + +static char *col_name(struct csa *csa, int j, char cname[255+1]) +{     /* construct symbolic name of j-th column (variable) */ +      const char *name; +      name = glp_get_col_name(csa->P, j); +      if (name == NULL) goto fake; +      strcpy(cname, name); +      adjust_name(cname); +      if (check_name(cname)) goto fake; +      return cname; +#if 0 /* 18/I-2018 */ +fake: sprintf(cname, "x_%d", j); +#else +fake: /* construct fake name depending on column's attributes */ +      {  GLPCOL *col = csa->P->col[j]; +         if (col->type == GLP_FX) +         {  /* fixed column */ +            sprintf(cname, "s_%d", j); +         } +         else if (col->kind == GLP_CV) +         {  /* continuous variable */ +            sprintf(cname, "x_%d", j); +         } +         else if (!(col->lb == 0 && col->ub == 1)) +         {  /* general (non-binary) integer variable */ +            sprintf(cname, "y_%d", j); +         } +         else +         {  /* binary variable */ +            sprintf(cname, "z_%d", j); +         } +      } +#endif +      return cname; +} + +int glp_write_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname) +{     /* write problem data in CPLEX LP format */ +      glp_cpxcp _parm; +      struct csa _csa, *csa = &_csa; +      glp_file *fp; +      GLPROW *row; +      GLPCOL *col; +      GLPAIJ *aij; +      int i, j, len, flag, count, ret; +      char line[1000+1], term[500+1], name[255+1]; +      xprintf("Writing problem data to '%s'...\n", fname); +      if (parm == NULL) +         glp_init_cpxcp(&_parm), parm = &_parm; +      /* check control parameters */ +      check_parm("glp_write_lp", parm); +      /* initialize common storage area */ +      csa->P = P; +      csa->parm = parm; +      /* create output CPLEX LP file */ +      fp = glp_open(fname, "w"), count = 0; +      if (fp == NULL) +      {  xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); +         ret = 1; +         goto done; +      } +      /* write problem name */ +      xfprintf(fp, "\\* Problem: %s *\\\n", +         P->name == NULL ? "Unknown" : P->name), count++; +      xfprintf(fp, "\n"), count++; +      /* the problem should contain at least one row and one column */ +      if (!(P->m > 0 && P->n > 0)) +      {  xprintf("Warning: problem has no rows/columns\n"); +         xfprintf(fp, "\\* WARNING: PROBLEM HAS NO ROWS/COLUMNS *\\\n"), +            count++; +         xfprintf(fp, "\n"), count++; +         goto skip; +      } +      /* write the objective function definition */ +      if (P->dir == GLP_MIN) +         xfprintf(fp, "Minimize\n"), count++; +      else if (P->dir == GLP_MAX) +         xfprintf(fp, "Maximize\n"), count++; +      else +         xassert(P != P); +      row_name(csa, 0, name); +      sprintf(line, " %s:", name); +      len = 0; +      for (j = 1; j <= P->n; j++) +      {  col = P->col[j]; +         if (col->coef != 0.0 || col->ptr == NULL) +         {  len++; +            col_name(csa, j, name); +            if (col->coef == 0.0) +               sprintf(term, " + 0 %s", name); /* empty column */ +            else if (col->coef == +1.0) +               sprintf(term, " + %s", name); +            else if (col->coef == -1.0) +               sprintf(term, " - %s", name); +            else if (col->coef > 0.0) +               sprintf(term, " + %.*g %s", DBL_DIG, +col->coef, name); +            else +               sprintf(term, " - %.*g %s", DBL_DIG, -col->coef, name); +            if (strlen(line) + strlen(term) > 72) +               xfprintf(fp, "%s\n", line), line[0] = '\0', count++; +            strcat(line, term); +         } +      } +      if (len == 0) +      {  /* empty objective */ +         sprintf(term, " 0 %s", col_name(csa, 1, name)); +         strcat(line, term); +      } +      xfprintf(fp, "%s\n", line), count++; +      if (P->c0 != 0.0) +         xfprintf(fp, "\\* constant term = %.*g *\\\n", DBL_DIG, P->c0), +            count++; +      xfprintf(fp, "\n"), count++; +      /* write the constraints section */ +      xfprintf(fp, "Subject To\n"), count++; +      for (i = 1; i <= P->m; i++) +      {  row = P->row[i]; +         if (row->type == GLP_FR) continue; /* skip free row */ +         row_name(csa, i, name); +         sprintf(line, " %s:", name); +         /* linear form */ +         for (aij = row->ptr; aij != NULL; aij = aij->r_next) +         {  col_name(csa, aij->col->j, name); +            if (aij->val == +1.0) +               sprintf(term, " + %s", name); +            else if (aij->val == -1.0) +               sprintf(term, " - %s", name); +            else if (aij->val > 0.0) +               sprintf(term, " + %.*g %s", DBL_DIG, +aij->val, name); +            else +               sprintf(term, " - %.*g %s", DBL_DIG, -aij->val, name); +            if (strlen(line) + strlen(term) > 72) +               xfprintf(fp, "%s\n", line), line[0] = '\0', count++; +            strcat(line, term); +         } +         if (row->type == GLP_DB) +         {  /* double-bounded (ranged) constraint */ +            sprintf(term, " - ~r_%d", i); +            if (strlen(line) + strlen(term) > 72) +               xfprintf(fp, "%s\n", line), line[0] = '\0', count++; +            strcat(line, term); +         } +         else if (row->ptr == NULL) +         {  /* empty constraint */ +            sprintf(term, " 0 %s", col_name(csa, 1, name)); +            strcat(line, term); +         } +         /* right hand-side */ +         if (row->type == GLP_LO) +            sprintf(term, " >= %.*g", DBL_DIG, row->lb); +         else if (row->type == GLP_UP) +            sprintf(term, " <= %.*g", DBL_DIG, row->ub); +         else if (row->type == GLP_DB || row->type == GLP_FX) +            sprintf(term, " = %.*g", DBL_DIG, row->lb); +         else +            xassert(row != row); +         if (strlen(line) + strlen(term) > 72) +            xfprintf(fp, "%s\n", line), line[0] = '\0', count++; +         strcat(line, term); +         xfprintf(fp, "%s\n", line), count++; +      } +      xfprintf(fp, "\n"), count++; +      /* write the bounds section */ +      flag = 0; +      for (i = 1; i <= P->m; i++) +      {  row = P->row[i]; +         if (row->type != GLP_DB) continue; +         if (!flag) +            xfprintf(fp, "Bounds\n"), flag = 1, count++; +         xfprintf(fp, " 0 <= ~r_%d <= %.*g\n", +            i, DBL_DIG, row->ub - row->lb), count++; +      } +      for (j = 1; j <= P->n; j++) +      {  col = P->col[j]; +         if (col->type == GLP_LO && col->lb == 0.0) continue; +         if (!flag) +            xfprintf(fp, "Bounds\n"), flag = 1, count++; +         col_name(csa, j, name); +         if (col->type == GLP_FR) +            xfprintf(fp, " %s free\n", name), count++; +         else if (col->type == GLP_LO) +            xfprintf(fp, " %s >= %.*g\n", +               name, DBL_DIG, col->lb), count++; +         else if (col->type == GLP_UP) +            xfprintf(fp, " -Inf <= %s <= %.*g\n", +               name, DBL_DIG, col->ub), count++; +         else if (col->type == GLP_DB) +            xfprintf(fp, " %.*g <= %s <= %.*g\n", +               DBL_DIG, col->lb, name, DBL_DIG, col->ub), count++; +         else if (col->type == GLP_FX) +            xfprintf(fp, " %s = %.*g\n", +               name, DBL_DIG, col->lb), count++; +         else +            xassert(col != col); +      } +      if (flag) xfprintf(fp, "\n"), count++; +      /* write the integer section */ +      flag = 0; +      for (j = 1; j <= P->n; j++) +      {  col = P->col[j]; +         if (col->kind == GLP_CV) continue; +         xassert(col->kind == GLP_IV); +         if (!flag) +            xfprintf(fp, "Generals\n"), flag = 1, count++; +         xfprintf(fp, " %s\n", col_name(csa, j, name)), count++; +      } +      if (flag) xfprintf(fp, "\n"), count++; +skip: /* write the end keyword */ +      xfprintf(fp, "End\n"), count++; +#if 0 /* FIXME */ +      xfflush(fp); +#endif +      if (glp_ioerr(fp)) +      {  xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); +         ret = 1; +         goto done; +      } +      /* problem data has been successfully written */ +      xprintf("%d lines were written\n", count); +      ret = 0; +done: if (fp != NULL) glp_close(fp); +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/cpp.c b/glpk-5.0/src/api/cpp.c new file mode 100644 index 0000000..5473bf3 --- /dev/null +++ b/glpk-5.0/src/api/cpp.c @@ -0,0 +1,183 @@ +/* cpp.c (solve critical path problem) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2010-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" + +/*********************************************************************** +*  NAME +* +*  glp_cpp - solve critical path problem +* +*  SYNOPSIS +* +*  double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls); +* +*  DESCRIPTION +* +*  The routine glp_cpp solves the critical path problem represented in +*  the form of the project network. +* +*  The parameter G is a pointer to the graph object, which specifies +*  the project network. This graph must be acyclic. Multiple arcs are +*  allowed being considered as single arcs. +* +*  The parameter v_t specifies an offset of the field of type double +*  in the vertex data block, which contains time t[i] >= 0 needed to +*  perform corresponding job j. If v_t < 0, it is assumed that t[i] = 1 +*  for all jobs. +* +*  The parameter v_es specifies an offset of the field of type double +*  in the vertex data block, to which the routine stores earliest start +*  time for corresponding job. If v_es < 0, this time is not stored. +* +*  The parameter v_ls specifies an offset of the field of type double +*  in the vertex data block, to which the routine stores latest start +*  time for corresponding job. If v_ls < 0, this time is not stored. +* +*  RETURNS +* +*  The routine glp_cpp returns the minimal project duration, that is, +*  minimal time needed to perform all jobs in the project. */ + +static void sorting(glp_graph *G, int list[]); + +double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls) +{     glp_vertex *v; +      glp_arc *a; +      int i, j, k, nv, *list; +      double temp, total, *t, *es, *ls; +      if (v_t >= 0 && v_t > G->v_size - (int)sizeof(double)) +         xerror("glp_cpp: v_t = %d; invalid offset\n", v_t); +      if (v_es >= 0 && v_es > G->v_size - (int)sizeof(double)) +         xerror("glp_cpp: v_es = %d; invalid offset\n", v_es); +      if (v_ls >= 0 && v_ls > G->v_size - (int)sizeof(double)) +         xerror("glp_cpp: v_ls = %d; invalid offset\n", v_ls); +      nv = G->nv; +      if (nv == 0) +      {  total = 0.0; +         goto done; +      } +      /* allocate working arrays */ +      t = xcalloc(1+nv, sizeof(double)); +      es = xcalloc(1+nv, sizeof(double)); +      ls = xcalloc(1+nv, sizeof(double)); +      list = xcalloc(1+nv, sizeof(int)); +      /* retrieve job times */ +      for (i = 1; i <= nv; i++) +      {  v = G->v[i]; +         if (v_t >= 0) +         {  memcpy(&t[i], (char *)v->data + v_t, sizeof(double)); +            if (t[i] < 0.0) +               xerror("glp_cpp: t[%d] = %g; invalid time\n", i, t[i]); +         } +         else +            t[i] = 1.0; +      } +      /* perform topological sorting to determine the list of nodes +         (jobs) such that if list[k] = i and list[kk] = j and there +         exists arc (i->j), then k < kk */ +      sorting(G, list); +      /* FORWARD PASS */ +      /* determine earliest start times */ +      for (k = 1; k <= nv; k++) +      {  j = list[k]; +         es[j] = 0.0; +         for (a = G->v[j]->in; a != NULL; a = a->h_next) +         {  i = a->tail->i; +            /* there exists arc (i->j) in the project network */ +            temp = es[i] + t[i]; +            if (es[j] < temp) es[j] = temp; +         } +      } +      /* determine the minimal project duration */ +      total = 0.0; +      for (i = 1; i <= nv; i++) +      {  temp = es[i] + t[i]; +         if (total < temp) total = temp; +      } +      /* BACKWARD PASS */ +      /* determine latest start times */ +      for (k = nv; k >= 1; k--) +      {  i = list[k]; +         ls[i] = total - t[i]; +         for (a = G->v[i]->out; a != NULL; a = a->t_next) +         {  j = a->head->i; +            /* there exists arc (i->j) in the project network */ +            temp = ls[j] - t[i]; +            if (ls[i] > temp) ls[i] = temp; +         } +         /* avoid possible round-off errors */ +         if (ls[i] < es[i]) ls[i] = es[i]; +      } +      /* store results, if necessary */ +      if (v_es >= 0) +      {  for (i = 1; i <= nv; i++) +         {  v = G->v[i]; +            memcpy((char *)v->data + v_es, &es[i], sizeof(double)); +         } +      } +      if (v_ls >= 0) +      {  for (i = 1; i <= nv; i++) +         {  v = G->v[i]; +            memcpy((char *)v->data + v_ls, &ls[i], sizeof(double)); +         } +      } +      /* free working arrays */ +      xfree(t); +      xfree(es); +      xfree(ls); +      xfree(list); +done: return total; +} + +static void sorting(glp_graph *G, int list[]) +{     /* perform topological sorting to determine the list of nodes +         (jobs) such that if list[k] = i and list[kk] = j and there +         exists arc (i->j), then k < kk */ +      int i, k, nv, v_size, *num; +      void **save; +      nv = G->nv; +      v_size = G->v_size; +      save = xcalloc(1+nv, sizeof(void *)); +      num = xcalloc(1+nv, sizeof(int)); +      G->v_size = sizeof(int); +      for (i = 1; i <= nv; i++) +      {  save[i] = G->v[i]->data; +         G->v[i]->data = &num[i]; +         list[i] = 0; +      } +      if (glp_top_sort(G, 0) != 0) +         xerror("glp_cpp: project network is not acyclic\n"); +      G->v_size = v_size; +      for (i = 1; i <= nv; i++) +      {  G->v[i]->data = save[i]; +         k = num[i]; +         xassert(1 <= k && k <= nv); +         xassert(list[k] == 0); +         list[k] = i; +      } +      xfree(save); +      xfree(num); +      return; +} + +/* eof */ diff --git a/glpk-5.0/src/api/cpxbas.c b/glpk-5.0/src/api/cpxbas.c new file mode 100644 index 0000000..38ba3e4 --- /dev/null +++ b/glpk-5.0/src/api/cpxbas.c @@ -0,0 +1,267 @@ +/* cpxbas.c (construct Bixby's initial LP basis) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2008-2018 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +struct var +{     /* structural variable */ +      int j; +      /* ordinal number */ +      double q; +      /* penalty value */ +}; + +static int CDECL fcmp(const void *ptr1, const void *ptr2) +{     /* this routine is passed to the qsort() function */ +      struct var *col1 = (void *)ptr1, *col2 = (void *)ptr2; +      if (col1->q < col2->q) return -1; +      if (col1->q > col2->q) return +1; +      return 0; +} + +static int get_column(glp_prob *lp, int j, int ind[], double val[]) +{     /* Bixby's algorithm assumes that the constraint matrix is scaled +         such that the maximum absolute value in every non-zero row and +         column is 1 */ +      int k, len; +      double big; +      len = glp_get_mat_col(lp, j, ind, val); +      big = 0.0; +      for (k = 1; k <= len; k++) +         if (big < fabs(val[k])) big = fabs(val[k]); +      if (big == 0.0) big = 1.0; +      for (k = 1; k <= len; k++) val[k] /= big; +      return len; +} + +static void cpx_basis(glp_prob *lp) +{     /* main routine */ +      struct var *C, *C2, *C3, *C4; +      int m, n, i, j, jk, k, l, ll, t, n2, n3, n4, type, len, *I, *r, +         *ind; +      double alpha, gamma, cmax, temp, *v, *val; +      xprintf("Constructing initial basis...\n"); +      /* determine the number of rows and columns */ +      m = glp_get_num_rows(lp); +      n = glp_get_num_cols(lp); +      /* allocate working arrays */ +      C = xcalloc(1+n, sizeof(struct var)); +      I = xcalloc(1+m, sizeof(int)); +      r = xcalloc(1+m, sizeof(int)); +      v = xcalloc(1+m, sizeof(double)); +      ind = xcalloc(1+m, sizeof(int)); +      val = xcalloc(1+m, sizeof(double)); +      /* make all auxiliary variables non-basic */ +      for (i = 1; i <= m; i++) +      {  if (glp_get_row_type(lp, i) != GLP_DB) +            glp_set_row_stat(lp, i, GLP_NS); +         else if (fabs(glp_get_row_lb(lp, i)) <= +                  fabs(glp_get_row_ub(lp, i))) +            glp_set_row_stat(lp, i, GLP_NL); +         else +            glp_set_row_stat(lp, i, GLP_NU); +      } +      /* make all structural variables non-basic */ +      for (j = 1; j <= n; j++) +      {  if (glp_get_col_type(lp, j) != GLP_DB) +            glp_set_col_stat(lp, j, GLP_NS); +         else if (fabs(glp_get_col_lb(lp, j)) <= +                  fabs(glp_get_col_ub(lp, j))) +            glp_set_col_stat(lp, j, GLP_NL); +         else +            glp_set_col_stat(lp, j, GLP_NU); +      } +      /* C2 is a set of free structural variables */ +      n2 = 0, C2 = C + 0; +      for (j = 1; j <= n; j++) +      {  type = glp_get_col_type(lp, j); +         if (type == GLP_FR) +         {  n2++; +            C2[n2].j = j; +            C2[n2].q = 0.0; +         } +      } +      /* C3 is a set of structural variables having excatly one (lower +         or upper) bound */ +      n3 = 0, C3 = C2 + n2; +      for (j = 1; j <= n; j++) +      {  type = glp_get_col_type(lp, j); +         if (type == GLP_LO) +         {  n3++; +            C3[n3].j = j; +            C3[n3].q = + glp_get_col_lb(lp, j); +         } +         else if (type == GLP_UP) +         {  n3++; +            C3[n3].j = j; +            C3[n3].q = - glp_get_col_ub(lp, j); +         } +      } +      /* C4 is a set of structural variables having both (lower and +         upper) bounds */ +      n4 = 0, C4 = C3 + n3; +      for (j = 1; j <= n; j++) +      {  type = glp_get_col_type(lp, j); +         if (type == GLP_DB) +         {  n4++; +            C4[n4].j = j; +            C4[n4].q = glp_get_col_lb(lp, j) - glp_get_col_ub(lp, j); +         } +      } +      /* compute gamma = max{|c[j]|: 1 <= j <= n} */ +      gamma = 0.0; +      for (j = 1; j <= n; j++) +      {  temp = fabs(glp_get_obj_coef(lp, j)); +         if (gamma < temp) gamma = temp; +      } +      /* compute cmax */ +      cmax = (gamma == 0.0 ? 1.0 : 1000.0 * gamma); +      /* compute final penalty for all structural variables within sets +         C2, C3, and C4 */ +      switch (glp_get_obj_dir(lp)) +      {  case GLP_MIN: temp = +1.0; break; +         case GLP_MAX: temp = -1.0; break; +         default: xassert(lp != lp); +      } +      for (k = 1; k <= n2+n3+n4; k++) +      {  j = C[k].j; +         C[k].q += (temp * glp_get_obj_coef(lp, j)) / cmax; +      } +      /* sort structural variables within C2, C3, and C4 in ascending +         order of penalty value */ +      qsort(C2+1, n2, sizeof(struct var), fcmp); +      for (k = 1; k < n2; k++) xassert(C2[k].q <= C2[k+1].q); +      qsort(C3+1, n3, sizeof(struct var), fcmp); +      for (k = 1; k < n3; k++) xassert(C3[k].q <= C3[k+1].q); +      qsort(C4+1, n4, sizeof(struct var), fcmp); +      for (k = 1; k < n4; k++) xassert(C4[k].q <= C4[k+1].q); +      /*** STEP 1 ***/ +      for (i = 1; i <= m; i++) +      {  type = glp_get_row_type(lp, i); +         if (type != GLP_FX) +         {  /* row i is either free or inequality constraint */ +            glp_set_row_stat(lp, i, GLP_BS); +            I[i] = 1; +            r[i] = 1; +         } +         else +         {  /* row i is equality constraint */ +            I[i] = 0; +            r[i] = 0; +         } +         v[i] = +DBL_MAX; +      } +      /*** STEP 2 ***/ +      for (k = 1; k <= n2+n3+n4; k++) +      {  jk = C[k].j; +         len = get_column(lp, jk, ind, val); +         /* let alpha = max{|A[l,jk]|: r[l] = 0} and let l' be such +            that alpha = |A[l',jk]| */ +         alpha = 0.0, ll = 0; +         for (t = 1; t <= len; t++) +         {  l = ind[t]; +            if (r[l] == 0 && alpha < fabs(val[t])) +               alpha = fabs(val[t]), ll = l; +         } +         if (alpha >= 0.99) +         {  /* B := B union {jk} */ +            glp_set_col_stat(lp, jk, GLP_BS); +            I[ll] = 1; +            v[ll] = alpha; +            /* r[l] := r[l] + 1 for all l such that |A[l,jk]| != 0 */ +            for (t = 1; t <= len; t++) +            {  l = ind[t]; +               if (val[t] != 0.0) r[l]++; +            } +            /* continue to the next k */ +            continue; +         } +         /* if |A[l,jk]| > 0.01 * v[l] for some l, continue to the +            next k */ +         for (t = 1; t <= len; t++) +         {  l = ind[t]; +            if (fabs(val[t]) > 0.01 * v[l]) break; +         } +         if (t <= len) continue; +         /* otherwise, let alpha = max{|A[l,jk]|: I[l] = 0} and let l' +            be such that alpha = |A[l',jk]| */ +         alpha = 0.0, ll = 0; +         for (t = 1; t <= len; t++) +         {  l = ind[t]; +            if (I[l] == 0 && alpha < fabs(val[t])) +               alpha = fabs(val[t]), ll = l; +         } +         /* if alpha = 0, continue to the next k */ +         if (alpha == 0.0) continue; +         /* B := B union {jk} */ +         glp_set_col_stat(lp, jk, GLP_BS); +         I[ll] = 1; +         v[ll] = alpha; +         /* r[l] := r[l] + 1 for all l such that |A[l,jk]| != 0 */ +         for (t = 1; t <= len; t++) +         {  l = ind[t]; +            if (val[t] != 0.0) r[l]++; +         } +      } +      /*** STEP 3 ***/ +      /* add an artificial variable (auxiliary variable for equality +         constraint) to cover each remaining uncovered row */ +      for (i = 1; i <= m; i++) +         if (I[i] == 0) glp_set_row_stat(lp, i, GLP_BS); +      /* free working arrays */ +      xfree(C); +      xfree(I); +      xfree(r); +      xfree(v); +      xfree(ind); +      xfree(val); +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_cpx_basis - construct Bixby's initial LP basis +* +*  SYNOPSIS +* +*  void glp_cpx_basis(glp_prob *lp); +* +*  DESCRIPTION +* +*  The routine glp_cpx_basis constructs an advanced initial basis for +*  the specified problem object. +* +*  The routine is based on Bixby's algorithm described in the paper: +* +*  Robert E. Bixby. Implementing the Simplex Method: The Initial Basis. +*  ORSA Journal on Computing, Vol. 4, No. 3, 1992, pp. 267-84. */ + +void glp_cpx_basis(glp_prob *lp) +{     if (lp->m == 0 || lp->n == 0) +         glp_std_basis(lp); +      else +         cpx_basis(lp); +      return; +} + +/* eof */ diff --git a/glpk-5.0/src/api/graph.c b/glpk-5.0/src/api/graph.c new file mode 100644 index 0000000..a522282 --- /dev/null +++ b/glpk-5.0/src/api/graph.c @@ -0,0 +1,502 @@ +/* graph.c (basic graph routines) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "avl.h" +#include "dmp.h" +#include "env.h" +#include "glpk.h" + +/* CAUTION: DO NOT CHANGE THE LIMITS BELOW */ + +#define NV_MAX 100000000 /* = 100*10^6 */ +/* maximal number of vertices in the graph */ + +#define NA_MAX 500000000 /* = 500*10^6 */ +/* maximal number of arcs in the graph */ + +/*********************************************************************** +*  NAME +* +*  glp_create_graph - create graph +* +*  SYNOPSIS +* +*  glp_graph *glp_create_graph(int v_size, int a_size); +* +*  DESCRIPTION +* +*  The routine creates a new graph, which initially is empty, i.e. has +*  no vertices and arcs. +* +*  The parameter v_size specifies the size of data associated with each +*  vertex of the graph (0 to 256 bytes). +* +*  The parameter a_size specifies the size of data associated with each +*  arc of the graph (0 to 256 bytes). +* +*  RETURNS +* +*  The routine returns a pointer to the graph created. */ + +static void create_graph(glp_graph *G, int v_size, int a_size) +{     G->pool = dmp_create_pool(); +      G->name = NULL; +      G->nv_max = 50; +      G->nv = G->na = 0; +      G->v = xcalloc(1+G->nv_max, sizeof(glp_vertex *)); +      G->index = NULL; +      G->v_size = v_size; +      G->a_size = a_size; +      return; +} + +glp_graph *glp_create_graph(int v_size, int a_size) +{     glp_graph *G; +      if (!(0 <= v_size && v_size <= 256)) +         xerror("glp_create_graph: v_size = %d; invalid size of vertex " +            "data\n", v_size); +      if (!(0 <= a_size && a_size <= 256)) +         xerror("glp_create_graph: a_size = %d; invalid size of arc dat" +            "a\n", a_size); +      G = xmalloc(sizeof(glp_graph)); +      create_graph(G, v_size, a_size); +      return G; +} + +/*********************************************************************** +*  NAME +* +*  glp_set_graph_name - assign (change) graph name +* +*  SYNOPSIS +* +*  void glp_set_graph_name(glp_graph *G, const char *name); +* +*  DESCRIPTION +* +*  The routine glp_set_graph_name assigns a symbolic name specified by +*  the character string name (1 to 255 chars) to the graph. +* +*  If the parameter name is NULL or an empty string, the routine erases +*  the existing symbolic name of the graph. */ + +void glp_set_graph_name(glp_graph *G, const char *name) +{     if (G->name != NULL) +      {  dmp_free_atom(G->pool, G->name, strlen(G->name)+1); +         G->name = NULL; +      } +      if (!(name == NULL || name[0] == '\0')) +      {  int j; +         for (j = 0; name[j] != '\0'; j++) +         {  if (j == 256) +               xerror("glp_set_graph_name: graph name too long\n"); +            if (iscntrl((unsigned char)name[j])) +               xerror("glp_set_graph_name: graph name contains invalid " +                  "character(s)\n"); +         } +         G->name = dmp_get_atom(G->pool, strlen(name)+1); +         strcpy(G->name, name); +      } +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_add_vertices - add new vertices to graph +* +*  SYNOPSIS +* +*  int glp_add_vertices(glp_graph *G, int nadd); +* +*  DESCRIPTION +* +*  The routine glp_add_vertices adds nadd vertices to the specified +*  graph. New vertices are always added to the end of the vertex list, +*  so ordinal numbers of existing vertices remain unchanged. +* +*  Being added each new vertex is isolated (has no incident arcs). +* +*  RETURNS +* +*  The routine glp_add_vertices returns an ordinal number of the first +*  new vertex added to the graph. */ + +int glp_add_vertices(glp_graph *G, int nadd) +{     int i, nv_new; +      if (nadd < 1) +         xerror("glp_add_vertices: nadd = %d; invalid number of vertice" +            "s\n", nadd); +      if (nadd > NV_MAX - G->nv) +         xerror("glp_add_vertices: nadd = %d; too many vertices\n", +            nadd); +      /* determine new number of vertices */ +      nv_new = G->nv + nadd; +      /* increase the room, if necessary */ +      if (G->nv_max < nv_new) +      {  glp_vertex **save = G->v; +         while (G->nv_max < nv_new) +         {  G->nv_max += G->nv_max; +            xassert(G->nv_max > 0); +         } +         G->v = xcalloc(1+G->nv_max, sizeof(glp_vertex *)); +         memcpy(&G->v[1], &save[1], G->nv * sizeof(glp_vertex *)); +         xfree(save); +      } +      /* add new vertices to the end of the vertex list */ +      for (i = G->nv+1; i <= nv_new; i++) +      {  glp_vertex *v; +         G->v[i] = v = dmp_get_atom(G->pool, sizeof(glp_vertex)); +         v->i = i; +         v->name = NULL; +         v->entry = NULL; +         if (G->v_size == 0) +            v->data = NULL; +         else +         {  v->data = dmp_get_atom(G->pool, G->v_size); +            memset(v->data, 0, G->v_size); +         } +         v->temp = NULL; +         v->in = v->out = NULL; +      } +      /* set new number of vertices */ +      G->nv = nv_new; +      /* return the ordinal number of the first vertex added */ +      return nv_new - nadd + 1; +} + +/**********************************************************************/ + +void glp_set_vertex_name(glp_graph *G, int i, const char *name) +{     /* assign (change) vertex name */ +      glp_vertex *v; +      if (!(1 <= i && i <= G->nv)) +         xerror("glp_set_vertex_name: i = %d; vertex number out of rang" +            "e\n", i); +      v = G->v[i]; +      if (v->name != NULL) +      {  if (v->entry != NULL) +         {  xassert(G->index != NULL); +            avl_delete_node(G->index, v->entry); +            v->entry = NULL; +         } +         dmp_free_atom(G->pool, v->name, strlen(v->name)+1); +         v->name = NULL; +      } +      if (!(name == NULL || name[0] == '\0')) +      {  int k; +         for (k = 0; name[k] != '\0'; k++) +         {  if (k == 256) +               xerror("glp_set_vertex_name: i = %d; vertex name too lon" +                  "g\n", i); +            if (iscntrl((unsigned char)name[k])) +               xerror("glp_set_vertex_name: i = %d; vertex name contain" +                  "s invalid character(s)\n", i); +         } +         v->name = dmp_get_atom(G->pool, strlen(name)+1); +         strcpy(v->name, name); +         if (G->index != NULL) +         {  xassert(v->entry == NULL); +            v->entry = avl_insert_node(G->index, v->name); +            avl_set_node_link(v->entry, v); +         } +      } +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_add_arc - add new arc to graph +* +*  SYNOPSIS +* +*  glp_arc *glp_add_arc(glp_graph *G, int i, int j); +* +*  DESCRIPTION +* +*  The routine glp_add_arc adds a new arc to the specified graph. +* +*  The parameters i and j specify the ordinal numbers of, resp., tail +*  and head vertices of the arc. Note that self-loops and multiple arcs +*  are allowed. +* +*  RETURNS +* +*  The routine glp_add_arc returns a pointer to the arc added. */ + +glp_arc *glp_add_arc(glp_graph *G, int i, int j) +{     glp_arc *a; +      if (!(1 <= i && i <= G->nv)) +         xerror("glp_add_arc: i = %d; tail vertex number out of range\n" +            , i); +      if (!(1 <= j && j <= G->nv)) +         xerror("glp_add_arc: j = %d; head vertex number out of range\n" +            , j); +      if (G->na == NA_MAX) +         xerror("glp_add_arc: too many arcs\n"); +      a = dmp_get_atom(G->pool, sizeof(glp_arc)); +      a->tail = G->v[i]; +      a->head = G->v[j]; +      if (G->a_size == 0) +         a->data = NULL; +      else +      {  a->data = dmp_get_atom(G->pool, G->a_size); +         memset(a->data, 0, G->a_size); +      } +      a->temp = NULL; +      a->t_prev = NULL; +      a->t_next = G->v[i]->out; +      if (a->t_next != NULL) a->t_next->t_prev = a; +      a->h_prev = NULL; +      a->h_next = G->v[j]->in; +      if (a->h_next != NULL) a->h_next->h_prev = a; +      G->v[i]->out = G->v[j]->in = a; +      G->na++; +      return a; +} + +/*********************************************************************** +*  NAME +* +*  glp_del_vertices - delete vertices from graph +* +*  SYNOPSIS +* +*  void glp_del_vertices(glp_graph *G, int ndel, const int num[]); +* +*  DESCRIPTION +* +*  The routine glp_del_vertices deletes vertices along with all +*  incident arcs from the specified graph. Ordinal numbers of vertices +*  to be deleted should be placed in locations num[1], ..., num[ndel], +*  ndel > 0. +* +*  Note that deleting vertices involves changing ordinal numbers of +*  other vertices remaining in the graph. New ordinal numbers of the +*  remaining vertices are assigned under the assumption that the +*  original order of vertices is not changed. */ + +void glp_del_vertices(glp_graph *G, int ndel, const int num[]) +{     glp_vertex *v; +      int i, k, nv_new; +      /* scan the list of vertices to be deleted */ +      if (!(1 <= ndel && ndel <= G->nv)) +         xerror("glp_del_vertices: ndel = %d; invalid number of vertice" +            "s\n", ndel); +      for (k = 1; k <= ndel; k++) +      {  /* take the number of vertex to be deleted */ +         i = num[k]; +         /* obtain pointer to i-th vertex */ +         if (!(1 <= i && i <= G->nv)) +            xerror("glp_del_vertices: num[%d] = %d; vertex number out o" +               "f range\n", k, i); +         v = G->v[i]; +         /* check that the vertex is not marked yet */ +         if (v->i == 0) +            xerror("glp_del_vertices: num[%d] = %d; duplicate vertex nu" +               "mbers not allowed\n", k, i); +         /* erase symbolic name assigned to the vertex */ +         glp_set_vertex_name(G, i, NULL); +         xassert(v->name == NULL); +         xassert(v->entry == NULL); +         /* free vertex data, if allocated */ +         if (v->data != NULL) +            dmp_free_atom(G->pool, v->data, G->v_size); +         /* delete all incoming arcs */ +         while (v->in != NULL) +            glp_del_arc(G, v->in); +         /* delete all outgoing arcs */ +         while (v->out != NULL) +            glp_del_arc(G, v->out); +         /* mark the vertex to be deleted */ +         v->i = 0; +      } +      /* delete all marked vertices from the vertex list */ +      nv_new = 0; +      for (i = 1; i <= G->nv; i++) +      {  /* obtain pointer to i-th vertex */ +         v = G->v[i]; +         /* check if the vertex is marked */ +         if (v->i == 0) +         {  /* it is marked, delete it */ +            dmp_free_atom(G->pool, v, sizeof(glp_vertex)); +         } +         else +         {  /* it is not marked, keep it */ +            v->i = ++nv_new; +            G->v[v->i] = v; +         } +      } +      /* set new number of vertices in the graph */ +      G->nv = nv_new; +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_del_arc - delete arc from graph +* +*  SYNOPSIS +* +*  void glp_del_arc(glp_graph *G, glp_arc *a); +* +*  DESCRIPTION +* +*  The routine glp_del_arc deletes an arc from the specified graph. +*  The arc to be deleted must exist. */ + +void glp_del_arc(glp_graph *G, glp_arc *a) +{     /* some sanity checks */ +      xassert(G->na > 0); +      xassert(1 <= a->tail->i && a->tail->i <= G->nv); +      xassert(a->tail == G->v[a->tail->i]); +      xassert(1 <= a->head->i && a->head->i <= G->nv); +      xassert(a->head == G->v[a->head->i]); +      /* remove the arc from the list of incoming arcs */ +      if (a->h_prev == NULL) +         a->head->in = a->h_next; +      else +         a->h_prev->h_next = a->h_next; +      if (a->h_next == NULL) +         ; +      else +         a->h_next->h_prev = a->h_prev; +      /* remove the arc from the list of outgoing arcs */ +      if (a->t_prev == NULL) +         a->tail->out = a->t_next; +      else +         a->t_prev->t_next = a->t_next; +      if (a->t_next == NULL) +         ; +      else +         a->t_next->t_prev = a->t_prev; +      /* free arc data, if allocated */ +      if (a->data != NULL) +         dmp_free_atom(G->pool, a->data, G->a_size); +      /* delete the arc from the graph */ +      dmp_free_atom(G->pool, a, sizeof(glp_arc)); +      G->na--; +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_erase_graph - erase graph content +* +*  SYNOPSIS +* +*  void glp_erase_graph(glp_graph *G, int v_size, int a_size); +* +*  DESCRIPTION +* +*  The routine glp_erase_graph erases the content of the specified +*  graph. The effect of this operation is the same as if the graph +*  would be deleted with the routine glp_delete_graph and then created +*  anew with the routine glp_create_graph, with exception that the +*  handle (pointer) to the graph remains valid. */ + +static void delete_graph(glp_graph *G) +{     dmp_delete_pool(G->pool); +      xfree(G->v); +      if (G->index != NULL) avl_delete_tree(G->index); +      return; +} + +void glp_erase_graph(glp_graph *G, int v_size, int a_size) +{     if (!(0 <= v_size && v_size <= 256)) +         xerror("glp_erase_graph: v_size = %d; invalid size of vertex d" +            "ata\n", v_size); +      if (!(0 <= a_size && a_size <= 256)) +         xerror("glp_erase_graph: a_size = %d; invalid size of arc data" +            "\n", a_size); +      delete_graph(G); +      create_graph(G, v_size, a_size); +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_delete_graph - delete graph +* +*  SYNOPSIS +* +*  void glp_delete_graph(glp_graph *G); +* +*  DESCRIPTION +* +*  The routine glp_delete_graph deletes the specified graph and frees +*  all the memory allocated to this program object. */ + +void glp_delete_graph(glp_graph *G) +{     delete_graph(G); +      xfree(G); +      return; +} + +/**********************************************************************/ + +void glp_create_v_index(glp_graph *G) +{     /* create vertex name index */ +      glp_vertex *v; +      int i; +      if (G->index == NULL) +      {  G->index = avl_create_tree(avl_strcmp, NULL); +         for (i = 1; i <= G->nv; i++) +         {  v = G->v[i]; +            xassert(v->entry == NULL); +            if (v->name != NULL) +            {  v->entry = avl_insert_node(G->index, v->name); +               avl_set_node_link(v->entry, v); +            } +         } +      } +      return; +} + +int glp_find_vertex(glp_graph *G, const char *name) +{     /* find vertex by its name */ +      AVLNODE *node; +      int i = 0; +      if (G->index == NULL) +         xerror("glp_find_vertex: vertex name index does not exist\n"); +      if (!(name == NULL || name[0] == '\0' || strlen(name) > 255)) +      {  node = avl_find_node(G->index, name); +         if (node != NULL) +            i = ((glp_vertex *)avl_get_node_link(node))->i; +      } +      return i; +} + +void glp_delete_v_index(glp_graph *G) +{     /* delete vertex name index */ +      int i; +      if (G->index != NULL) +      {  avl_delete_tree(G->index), G->index = NULL; +         for (i = 1; i <= G->nv; i++) G->v[i]->entry = NULL; +      } +      return; +} + +/* eof */ diff --git a/glpk-5.0/src/api/gridgen.c b/glpk-5.0/src/api/gridgen.c new file mode 100644 index 0000000..9df454b --- /dev/null +++ b/glpk-5.0/src/api/gridgen.c @@ -0,0 +1,20 @@ +/* gridgen.c */ + +#include "env.h" +#include "glpk.h" + +int glp_gridgen(glp_graph *G_, int v_rhs_, int a_cap_, int a_cost_, +      const int parm[1+14]) +{     static const char func[] = "glp_gridgen"; +      xassert(G_ == G_); +      xassert(v_rhs_ == v_rhs_); +      xassert(a_cap_ == a_cap_); +      xassert(a_cost_ == a_cost_); +      xassert(parm == parm); +      xerror("%s: sorry, this routine is temporarily disabled due to li" +         "censing problems\n", func); +      abort(); +      return -1; +} + +/* eof */ diff --git a/glpk-5.0/src/api/intfeas1.c b/glpk-5.0/src/api/intfeas1.c new file mode 100644 index 0000000..d500251 --- /dev/null +++ b/glpk-5.0/src/api/intfeas1.c @@ -0,0 +1,265 @@ +/* intfeas1.c (solve integer feasibility problem) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2011-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "npp.h" + +int glp_intfeas1(glp_prob *P, int use_bound, int obj_bound) +{     /* solve integer feasibility problem */ +      NPP *npp = NULL; +      glp_prob *mip = NULL; +      int *obj_ind = NULL; +      double *obj_val = NULL; +      int obj_row = 0; +      int i, j, k, obj_len, temp, ret; +#if 0 /* 04/IV-2016 */ +      /* check the problem object */ +      if (P == NULL || P->magic != GLP_PROB_MAGIC) +         xerror("glp_intfeas1: P = %p; invalid problem object\n", +            P); +#endif +      if (P->tree != NULL) +         xerror("glp_intfeas1: operation not allowed\n"); +      /* integer solution is currently undefined */ +      P->mip_stat = GLP_UNDEF; +      P->mip_obj = 0.0; +      /* check columns (variables) */ +      for (j = 1; j <= P->n; j++) +      {  GLPCOL *col = P->col[j]; +#if 0 /* binarization is not yet implemented */ +         if (!(col->kind == GLP_IV || col->type == GLP_FX)) +         {  xprintf("glp_intfeas1: column %d: non-integer non-fixed var" +               "iable not allowed\n", j); +#else +         if (!((col->kind == GLP_IV && col->lb == 0.0 && col->ub == 1.0) +            || col->type == GLP_FX)) +         {  xprintf("glp_intfeas1: column %d: non-binary non-fixed vari" +               "able not allowed\n", j); +#endif +            ret = GLP_EDATA; +            goto done; +         } +         temp = (int)col->lb; +         if ((double)temp != col->lb) +         {  if (col->type == GLP_FX) +               xprintf("glp_intfeas1: column %d: fixed value %g is non-" +                  "integer or out of range\n", j, col->lb); +            else +               xprintf("glp_intfeas1: column %d: lower bound %g is non-" +                  "integer or out of range\n", j, col->lb); +            ret = GLP_EDATA; +            goto done; +         } +         temp = (int)col->ub; +         if ((double)temp != col->ub) +         {  xprintf("glp_intfeas1: column %d: upper bound %g is non-int" +               "eger or out of range\n", j, col->ub); +            ret = GLP_EDATA; +            goto done; +         } +         if (col->type == GLP_DB && col->lb > col->ub) +         {  xprintf("glp_intfeas1: column %d: lower bound %g is greater" +               " than upper bound %g\n", j, col->lb, col->ub); +            ret = GLP_EBOUND; +            goto done; +         } +      } +      /* check rows (constraints) */ +      for (i = 1; i <= P->m; i++) +      {  GLPROW *row = P->row[i]; +         GLPAIJ *aij; +         for (aij = row->ptr; aij != NULL; aij = aij->r_next) +         {  temp = (int)aij->val; +            if ((double)temp != aij->val) +            {  xprintf("glp_intfeas1: row = %d, column %d: constraint c" +                  "oefficient %g is non-integer or out of range\n", +                  i, aij->col->j, aij->val); +               ret = GLP_EDATA; +               goto done; +            } +         } +         temp = (int)row->lb; +         if ((double)temp != row->lb) +         {  if (row->type == GLP_FX) +               xprintf("glp_intfeas1: row = %d: fixed value %g is non-i" +                  "nteger or out of range\n", i, row->lb); +            else +               xprintf("glp_intfeas1: row = %d: lower bound %g is non-i" +                  "nteger or out of range\n", i, row->lb); +            ret = GLP_EDATA; +            goto done; +         } +         temp = (int)row->ub; +         if ((double)temp != row->ub) +         {  xprintf("glp_intfeas1: row = %d: upper bound %g is non-inte" +               "ger or out of range\n", i, row->ub); +            ret = GLP_EDATA; +            goto done; +         } +         if (row->type == GLP_DB && row->lb > row->ub) +         {  xprintf("glp_intfeas1: row %d: lower bound %g is greater th" +               "an upper bound %g\n", i, row->lb, row->ub); +            ret = GLP_EBOUND; +            goto done; +         } +      } +      /* check the objective function */ +#if 1 /* 08/I-2017 by cmatraki & mao */ +      if (!use_bound) +      {  /* skip check if no obj. bound is specified */ +         goto skip; +      } +#endif +      temp = (int)P->c0; +      if ((double)temp != P->c0) +      {  xprintf("glp_intfeas1: objective constant term %g is non-integ" +            "er or out of range\n", P->c0); +         ret = GLP_EDATA; +         goto done; +      } +      for (j = 1; j <= P->n; j++) +      {  temp = (int)P->col[j]->coef; +         if ((double)temp != P->col[j]->coef) +         {  xprintf("glp_intfeas1: column %d: objective coefficient is " +               "non-integer or out of range\n", j, P->col[j]->coef); +            ret = GLP_EDATA; +            goto done; +         } +      } +#if 1 /* 08/I-2017 by cmatraki & mao */ +skip: ; +#endif +      /* save the objective function and set it to zero */ +      obj_ind = xcalloc(1+P->n, sizeof(int)); +      obj_val = xcalloc(1+P->n, sizeof(double)); +      obj_len = 0; +      obj_ind[0] = 0; +      obj_val[0] = P->c0; +      P->c0 = 0.0; +      for (j = 1; j <= P->n; j++) +      {  if (P->col[j]->coef != 0.0) +         {  obj_len++; +            obj_ind[obj_len] = j; +            obj_val[obj_len] = P->col[j]->coef; +            P->col[j]->coef = 0.0; +         } +      } +      /* add inequality to bound the objective function, if required */ +      if (!use_bound) +         xprintf("Will search for ANY feasible solution\n"); +      else +      {  xprintf("Will search only for solution not worse than %d\n", +            obj_bound); +         obj_row = glp_add_rows(P, 1); +         glp_set_mat_row(P, obj_row, obj_len, obj_ind, obj_val); +         if (P->dir == GLP_MIN) +            glp_set_row_bnds(P, obj_row, +               GLP_UP, 0.0, (double)obj_bound - obj_val[0]); +         else if (P->dir == GLP_MAX) +            glp_set_row_bnds(P, obj_row, +               GLP_LO, (double)obj_bound - obj_val[0], 0.0); +         else +            xassert(P != P); +      } +      /* create preprocessor workspace */ +      xprintf("Translating to CNF-SAT...\n"); +      xprintf("Original problem has %d row%s, %d column%s, and %d non-z" +         "ero%s\n", P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : +         "s", P->nnz, P->nnz == 1 ? "" : "s"); +      npp = npp_create_wksp(); +      /* load the original problem into the preprocessor workspace */ +      npp_load_prob(npp, P, GLP_OFF, GLP_MIP, GLP_OFF); +      /* perform translation to SAT-CNF problem instance */ +      ret = npp_sat_encode_prob(npp); +      if (ret == 0) +         ; +      else if (ret == GLP_ENOPFS) +         xprintf("PROBLEM HAS NO INTEGER FEASIBLE SOLUTION\n"); +      else if (ret == GLP_ERANGE) +         xprintf("glp_intfeas1: translation to SAT-CNF failed because o" +            "f integer overflow\n"); +      else +         xassert(ret != ret); +      if (ret != 0) +         goto done; +      /* build SAT-CNF problem instance and try to solve it */ +      mip = glp_create_prob(); +      npp_build_prob(npp, mip); +      ret = glp_minisat1(mip); +      /* only integer feasible solution can be postprocessed */ +      if (!(mip->mip_stat == GLP_OPT || mip->mip_stat == GLP_FEAS)) +      {  P->mip_stat = mip->mip_stat; +         goto done; +      } +      /* postprocess the solution found */ +      npp_postprocess(npp, mip); +      /* the transformed problem is no longer needed */ +      glp_delete_prob(mip), mip = NULL; +      /* store solution to the original problem object */ +      npp_unload_sol(npp, P); +      /* change the solution status to 'integer feasible' */ +      P->mip_stat = GLP_FEAS; +      /* check integer feasibility */ +      for (i = 1; i <= P->m; i++) +      {  GLPROW *row; +         GLPAIJ *aij; +         double sum; +         row = P->row[i]; +         sum = 0.0; +         for (aij = row->ptr; aij != NULL; aij = aij->r_next) +            sum += aij->val * aij->col->mipx; +         xassert(sum == row->mipx); +         if (row->type == GLP_LO || row->type == GLP_DB || +             row->type == GLP_FX) +            xassert(sum >= row->lb); +         if (row->type == GLP_UP || row->type == GLP_DB || +             row->type == GLP_FX) +            xassert(sum <= row->ub); +      } +      /* compute value of the original objective function */ +      P->mip_obj = obj_val[0]; +      for (k = 1; k <= obj_len; k++) +         P->mip_obj += obj_val[k] * P->col[obj_ind[k]]->mipx; +      xprintf("Objective value = %17.9e\n", P->mip_obj); +done: /* delete the transformed problem, if it exists */ +      if (mip != NULL) +         glp_delete_prob(mip); +      /* delete the preprocessor workspace, if it exists */ +      if (npp != NULL) +         npp_delete_wksp(npp); +      /* remove inequality used to bound the objective function */ +      if (obj_row > 0) +      {  int ind[1+1]; +         ind[1] = obj_row; +         glp_del_rows(P, 1, ind); +      } +      /* restore the original objective function */ +      if (obj_ind != NULL) +      {  P->c0 = obj_val[0]; +         for (k = 1; k <= obj_len; k++) +            P->col[obj_ind[k]]->coef = obj_val[k]; +         xfree(obj_ind); +         xfree(obj_val); +      } +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/maxffalg.c b/glpk-5.0/src/api/maxffalg.c new file mode 100644 index 0000000..5b66a6c --- /dev/null +++ b/glpk-5.0/src/api/maxffalg.c @@ -0,0 +1,128 @@ +/* maxffalg.c (find maximal flow with Ford-Fulkerson algorithm) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "ffalg.h" +#include "glpk.h" + +int glp_maxflow_ffalg(glp_graph *G, int s, int t, int a_cap, +      double *sol, int a_x, int v_cut) +{     /* find maximal flow with Ford-Fulkerson algorithm */ +      glp_vertex *v; +      glp_arc *a; +      int nv, na, i, k, flag, *tail, *head, *cap, *x, ret; +      char *cut; +      double temp; +      if (!(1 <= s && s <= G->nv)) +         xerror("glp_maxflow_ffalg: s = %d; source node number out of r" +            "ange\n", s); +      if (!(1 <= t && t <= G->nv)) +         xerror("glp_maxflow_ffalg: t = %d: sink node number out of ran" +            "ge\n", t); +      if (s == t) +         xerror("glp_maxflow_ffalg: s = t = %d; source and sink nodes m" +            "ust be distinct\n", s); +      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) +         xerror("glp_maxflow_ffalg: a_cap = %d; invalid offset\n", +            a_cap); +      if (v_cut >= 0 && v_cut > G->v_size - (int)sizeof(int)) +         xerror("glp_maxflow_ffalg: v_cut = %d; invalid offset\n", +            v_cut); +      /* allocate working arrays */ +      nv = G->nv; +      na = G->na; +      tail = xcalloc(1+na, sizeof(int)); +      head = xcalloc(1+na, sizeof(int)); +      cap = xcalloc(1+na, sizeof(int)); +      x = xcalloc(1+na, sizeof(int)); +      if (v_cut < 0) +         cut = NULL; +      else +         cut = xcalloc(1+nv, sizeof(char)); +      /* copy the flow network */ +      k = 0; +      for (i = 1; i <= G->nv; i++) +      {  v = G->v[i]; +         for (a = v->out; a != NULL; a = a->t_next) +         {  k++; +            tail[k] = a->tail->i; +            head[k] = a->head->i; +            if (tail[k] == head[k]) +            {  ret = GLP_EDATA; +               goto done; +            } +            if (a_cap >= 0) +               memcpy(&temp, (char *)a->data + a_cap, sizeof(double)); +            else +               temp = 1.0; +            if (!(0.0 <= temp && temp <= (double)INT_MAX && +                  temp == floor(temp))) +            {  ret = GLP_EDATA; +               goto done; +            } +            cap[k] = (int)temp; +         } +      } +      xassert(k == na); +      /* find maximal flow in the flow network */ +      ffalg(nv, na, tail, head, s, t, cap, x, cut); +      ret = 0; +      /* store solution components */ +      /* (objective function = total flow through the network) */ +      if (sol != NULL) +      {  temp = 0.0; +         for (k = 1; k <= na; k++) +         {  if (tail[k] == s) +               temp += (double)x[k]; +            else if (head[k] == s) +               temp -= (double)x[k]; +         } +         *sol = temp; +      } +      /* (arc flows) */ +      if (a_x >= 0) +      {  k = 0; +         for (i = 1; i <= G->nv; i++) +         {  v = G->v[i]; +            for (a = v->out; a != NULL; a = a->t_next) +            {  temp = (double)x[++k]; +               memcpy((char *)a->data + a_x, &temp, sizeof(double)); +            } +         } +      } +      /* (node flags) */ +      if (v_cut >= 0) +      {  for (i = 1; i <= G->nv; i++) +         {  v = G->v[i]; +            flag = cut[i]; +            memcpy((char *)v->data + v_cut, &flag, sizeof(int)); +         } +      } +done: /* free working arrays */ +      xfree(tail); +      xfree(head); +      xfree(cap); +      xfree(x); +      if (cut != NULL) xfree(cut); +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/maxflp.c b/glpk-5.0/src/api/maxflp.c new file mode 100644 index 0000000..fba9c1f --- /dev/null +++ b/glpk-5.0/src/api/maxflp.c @@ -0,0 +1,112 @@ +/* maxflp.c (convert maximum flow problem to LP) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" + +/*********************************************************************** +*  NAME +* +*  glp_maxflow_lp - convert maximum flow problem to LP +* +*  SYNOPSIS +* +*  void glp_maxflow_lp(glp_prob *lp, glp_graph *G, int names, int s, +*     int t, int a_cap); +* +*  DESCRIPTION +* +*  The routine glp_maxflow_lp builds an LP problem, which corresponds +*  to the maximum flow problem on the specified network G. */ + +void glp_maxflow_lp(glp_prob *lp, glp_graph *G, int names, int s, +      int t, int a_cap) +{     glp_vertex *v; +      glp_arc *a; +      int i, j, type, ind[1+2]; +      double cap, val[1+2]; +      if (!(names == GLP_ON || names == GLP_OFF)) +         xerror("glp_maxflow_lp: names = %d; invalid parameter\n", +            names); +      if (!(1 <= s && s <= G->nv)) +         xerror("glp_maxflow_lp: s = %d; source node number out of rang" +            "e\n", s); +      if (!(1 <= t && t <= G->nv)) +         xerror("glp_maxflow_lp: t = %d: sink node number out of range " +            "\n", t); +      if (s == t) +         xerror("glp_maxflow_lp: s = t = %d; source and sink nodes must" +            " be distinct\n", s); +      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) +         xerror("glp_maxflow_lp: a_cap = %d; invalid offset\n", a_cap); +      glp_erase_prob(lp); +      if (names) glp_set_prob_name(lp, G->name); +      glp_set_obj_dir(lp, GLP_MAX); +      glp_add_rows(lp, G->nv); +      for (i = 1; i <= G->nv; i++) +      {  v = G->v[i]; +         if (names) glp_set_row_name(lp, i, v->name); +         if (i == s) +            type = GLP_LO; +         else if (i == t) +            type = GLP_UP; +         else +            type = GLP_FX; +         glp_set_row_bnds(lp, i, type, 0.0, 0.0); +      } +      if (G->na > 0) glp_add_cols(lp, G->na); +      for (i = 1, j = 0; i <= G->nv; i++) +      {  v = G->v[i]; +         for (a = v->out; a != NULL; a = a->t_next) +         {  j++; +            if (names) +            {  char name[50+1]; +               sprintf(name, "x[%d,%d]", a->tail->i, a->head->i); +               xassert(strlen(name) < sizeof(name)); +               glp_set_col_name(lp, j, name); +            } +            if (a->tail->i != a->head->i) +            {  ind[1] = a->tail->i, val[1] = +1.0; +               ind[2] = a->head->i, val[2] = -1.0; +               glp_set_mat_col(lp, j, 2, ind, val); +            } +            if (a_cap >= 0) +               memcpy(&cap, (char *)a->data + a_cap, sizeof(double)); +            else +               cap = 1.0; +            if (cap == DBL_MAX) +               type = GLP_LO; +            else if (cap != 0.0) +               type = GLP_DB; +            else +               type = GLP_FX; +            glp_set_col_bnds(lp, j, type, 0.0, cap); +            if (a->tail->i == s) +               glp_set_obj_coef(lp, j, +1.0); +            else if (a->head->i == s) +               glp_set_obj_coef(lp, j, -1.0); +         } +      } +      xassert(j == G->na); +      return; +} + +/* eof */ diff --git a/glpk-5.0/src/api/mcflp.c b/glpk-5.0/src/api/mcflp.c new file mode 100644 index 0000000..e4ef0b6 --- /dev/null +++ b/glpk-5.0/src/api/mcflp.c @@ -0,0 +1,112 @@ +/* mcflp.c (convert minimum cost flow problem to LP) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" + +/*********************************************************************** +*  NAME +* +*  glp_mincost_lp - convert minimum cost flow problem to LP +* +*  SYNOPSIS +* +*  void glp_mincost_lp(glp_prob *lp, glp_graph *G, int names, +*     int v_rhs, int a_low, int a_cap, int a_cost); +* +*  DESCRIPTION +* +*  The routine glp_mincost_lp builds an LP problem, which corresponds +*  to the minimum cost flow problem on the specified network G. */ + +void glp_mincost_lp(glp_prob *lp, glp_graph *G, int names, int v_rhs, +      int a_low, int a_cap, int a_cost) +{     glp_vertex *v; +      glp_arc *a; +      int i, j, type, ind[1+2]; +      double rhs, low, cap, cost, val[1+2]; +      if (!(names == GLP_ON || names == GLP_OFF)) +         xerror("glp_mincost_lp: names = %d; invalid parameter\n", +            names); +      if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double)) +         xerror("glp_mincost_lp: v_rhs = %d; invalid offset\n", v_rhs); +      if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double)) +         xerror("glp_mincost_lp: a_low = %d; invalid offset\n", a_low); +      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) +         xerror("glp_mincost_lp: a_cap = %d; invalid offset\n", a_cap); +      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) +         xerror("glp_mincost_lp: a_cost = %d; invalid offset\n", a_cost) +            ; +      glp_erase_prob(lp); +      if (names) glp_set_prob_name(lp, G->name); +      if (G->nv > 0) glp_add_rows(lp, G->nv); +      for (i = 1; i <= G->nv; i++) +      {  v = G->v[i]; +         if (names) glp_set_row_name(lp, i, v->name); +         if (v_rhs >= 0) +            memcpy(&rhs, (char *)v->data + v_rhs, sizeof(double)); +         else +            rhs = 0.0; +         glp_set_row_bnds(lp, i, GLP_FX, rhs, rhs); +      } +      if (G->na > 0) glp_add_cols(lp, G->na); +      for (i = 1, j = 0; i <= G->nv; i++) +      {  v = G->v[i]; +         for (a = v->out; a != NULL; a = a->t_next) +         {  j++; +            if (names) +            {  char name[50+1]; +               sprintf(name, "x[%d,%d]", a->tail->i, a->head->i); +               xassert(strlen(name) < sizeof(name)); +               glp_set_col_name(lp, j, name); +            } +            if (a->tail->i != a->head->i) +            {  ind[1] = a->tail->i, val[1] = +1.0; +               ind[2] = a->head->i, val[2] = -1.0; +               glp_set_mat_col(lp, j, 2, ind, val); +            } +            if (a_low >= 0) +               memcpy(&low, (char *)a->data + a_low, sizeof(double)); +            else +               low = 0.0; +            if (a_cap >= 0) +               memcpy(&cap, (char *)a->data + a_cap, sizeof(double)); +            else +               cap = 1.0; +            if (cap == DBL_MAX) +               type = GLP_LO; +            else if (low != cap) +               type = GLP_DB; +            else +               type = GLP_FX; +            glp_set_col_bnds(lp, j, type, low, cap); +            if (a_cost >= 0) +               memcpy(&cost, (char *)a->data + a_cost, sizeof(double)); +            else +               cost = 0.0; +            glp_set_obj_coef(lp, j, cost); +         } +      } +      xassert(j == G->na); +      return; +} + +/* eof */ diff --git a/glpk-5.0/src/api/mcfokalg.c b/glpk-5.0/src/api/mcfokalg.c new file mode 100644 index 0000000..c2d2794 --- /dev/null +++ b/glpk-5.0/src/api/mcfokalg.c @@ -0,0 +1,219 @@ +/* mcfokalg.c (find minimum-cost flow with out-of-kilter algorithm) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" +#include "okalg.h" + +int glp_mincost_okalg(glp_graph *G, int v_rhs, int a_low, int a_cap, +      int a_cost, double *sol, int a_x, int v_pi) +{     /* find minimum-cost flow with out-of-kilter algorithm */ +      glp_vertex *v; +      glp_arc *a; +      int nv, na, i, k, s, t, *tail, *head, *low, *cap, *cost, *x, *pi, +         ret; +      double sum, temp; +      if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double)) +         xerror("glp_mincost_okalg: v_rhs = %d; invalid offset\n", +            v_rhs); +      if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double)) +         xerror("glp_mincost_okalg: a_low = %d; invalid offset\n", +            a_low); +      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) +         xerror("glp_mincost_okalg: a_cap = %d; invalid offset\n", +            a_cap); +      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) +         xerror("glp_mincost_okalg: a_cost = %d; invalid offset\n", +            a_cost); +      if (a_x >= 0 && a_x > G->a_size - (int)sizeof(double)) +         xerror("glp_mincost_okalg: a_x = %d; invalid offset\n", a_x); +      if (v_pi >= 0 && v_pi > G->v_size - (int)sizeof(double)) +         xerror("glp_mincost_okalg: v_pi = %d; invalid offset\n", v_pi); +      /* s is artificial source node */ +      s = G->nv + 1; +      /* t is artificial sink node */ +      t = s + 1; +      /* nv is the total number of nodes in the resulting network */ +      nv = t; +      /* na is the total number of arcs in the resulting network */ +      na = G->na + 1; +      for (i = 1; i <= G->nv; i++) +      {  v = G->v[i]; +         if (v_rhs >= 0) +            memcpy(&temp, (char *)v->data + v_rhs, sizeof(double)); +         else +            temp = 0.0; +         if (temp != 0.0) na++; +      } +      /* allocate working arrays */ +      tail = xcalloc(1+na, sizeof(int)); +      head = xcalloc(1+na, sizeof(int)); +      low = xcalloc(1+na, sizeof(int)); +      cap = xcalloc(1+na, sizeof(int)); +      cost = xcalloc(1+na, sizeof(int)); +      x = xcalloc(1+na, sizeof(int)); +      pi = xcalloc(1+nv, sizeof(int)); +      /* construct the resulting network */ +      k = 0; +      /* (original arcs) */ +      for (i = 1; i <= G->nv; i++) +      {  v = G->v[i]; +         for (a = v->out; a != NULL; a = a->t_next) +         {  k++; +            tail[k] = a->tail->i; +            head[k] = a->head->i; +            if (tail[k] == head[k]) +            {  ret = GLP_EDATA; +               goto done; +            } +            if (a_low >= 0) +               memcpy(&temp, (char *)a->data + a_low, sizeof(double)); +            else +               temp = 0.0; +            if (!(0.0 <= temp && temp <= (double)INT_MAX && +                  temp == floor(temp))) +            {  ret = GLP_EDATA; +               goto done; +            } +            low[k] = (int)temp; +            if (a_cap >= 0) +               memcpy(&temp, (char *)a->data + a_cap, sizeof(double)); +            else +               temp = 1.0; +            if (!((double)low[k] <= temp && temp <= (double)INT_MAX && +                  temp == floor(temp))) +            {  ret = GLP_EDATA; +               goto done; +            } +            cap[k] = (int)temp; +            if (a_cost >= 0) +               memcpy(&temp, (char *)a->data + a_cost, sizeof(double)); +            else +               temp = 0.0; +            if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp))) +            {  ret = GLP_EDATA; +               goto done; +            } +            cost[k] = (int)temp; +         } +      } +      /* (artificial arcs) */ +      sum = 0.0; +      for (i = 1; i <= G->nv; i++) +      {  v = G->v[i]; +         if (v_rhs >= 0) +            memcpy(&temp, (char *)v->data + v_rhs, sizeof(double)); +         else +            temp = 0.0; +         if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp))) +         {  ret = GLP_EDATA; +            goto done; +         } +         if (temp > 0.0) +         {  /* artificial arc from s to original source i */ +            k++; +            tail[k] = s; +            head[k] = i; +            low[k] = cap[k] = (int)(+temp); /* supply */ +            cost[k] = 0; +            sum += (double)temp; +         } +         else if (temp < 0.0) +         {  /* artificial arc from original sink i to t */ +            k++; +            tail[k] = i; +            head[k] = t; +            low[k] = cap[k] = (int)(-temp); /* demand */ +            cost[k] = 0; +         } +      } +      /* (feedback arc from t to s) */ +      k++; +      xassert(k == na); +      tail[k] = t; +      head[k] = s; +      if (sum > (double)INT_MAX) +      {  ret = GLP_EDATA; +         goto done; +      } +      low[k] = cap[k] = (int)sum; /* total supply/demand */ +      cost[k] = 0; +      /* find minimal-cost circulation in the resulting network */ +      ret = okalg(nv, na, tail, head, low, cap, cost, x, pi); +      switch (ret) +      {  case 0: +            /* optimal circulation found */ +            ret = 0; +            break; +         case 1: +            /* no feasible circulation exists */ +            ret = GLP_ENOPFS; +            break; +         case 2: +            /* integer overflow occured */ +            ret = GLP_ERANGE; +            goto done; +         case 3: +            /* optimality test failed (logic error) */ +            ret = GLP_EFAIL; +            goto done; +         default: +            xassert(ret != ret); +      } +      /* store solution components */ +      /* (objective function = the total cost) */ +      if (sol != NULL) +      {  temp = 0.0; +         for (k = 1; k <= na; k++) +            temp += (double)cost[k] * (double)x[k]; +         *sol = temp; +      } +      /* (arc flows) */ +      if (a_x >= 0) +      {  k = 0; +         for (i = 1; i <= G->nv; i++) +         {  v = G->v[i]; +            for (a = v->out; a != NULL; a = a->t_next) +            {  temp = (double)x[++k]; +               memcpy((char *)a->data + a_x, &temp, sizeof(double)); +            } +         } +      } +      /* (node potentials = Lagrange multipliers) */ +      if (v_pi >= 0) +      {  for (i = 1; i <= G->nv; i++) +         {  v = G->v[i]; +            temp = - (double)pi[i]; +            memcpy((char *)v->data + v_pi, &temp, sizeof(double)); +         } +      } +done: /* free working arrays */ +      xfree(tail); +      xfree(head); +      xfree(low); +      xfree(cap); +      xfree(cost); +      xfree(x); +      xfree(pi); +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/mcfrelax.c b/glpk-5.0/src/api/mcfrelax.c new file mode 100644 index 0000000..74c2826 --- /dev/null +++ b/glpk-5.0/src/api/mcfrelax.c @@ -0,0 +1,249 @@ +/* mcfrelax.c (find minimum-cost flow with RELAX-IV) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2013-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" +#include "relax4.h" + +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 glp_mincost_relax4(glp_graph *G, int v_rhs, int a_low, int a_cap, +      int a_cost, int crash, double *sol, int a_x, int a_rc) +{     /* find minimum-cost flow with Bertsekas-Tseng relaxation method +         (RELAX-IV) */ +      glp_vertex *v; +      glp_arc *a; +      struct relax4_csa csa; +      int i, k, large, n, na, ret; +      double cap, cost, low, rc, rhs, sum, x; +      if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double)) +         xerror("glp_mincost_relax4: v_rhs = %d; invalid offset\n", +            v_rhs); +      if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double)) +         xerror("glp_mincost_relax4: a_low = %d; invalid offset\n", +            a_low); +      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) +         xerror("glp_mincost_relax4: a_cap = %d; invalid offset\n", +            a_cap); +      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) +         xerror("glp_mincost_relax4: a_cost = %d; invalid offset\n", +            a_cost); +      if (a_x >= 0 && a_x > G->a_size - (int)sizeof(double)) +         xerror("glp_mincost_relax4: a_x = %d; invalid offset\n", +            a_x); +      if (a_rc >= 0 && a_rc > G->a_size - (int)sizeof(double)) +         xerror("glp_mincost_relax4: a_rc = %d; invalid offset\n", +            a_rc); +      csa.n = n = G->nv; /* number of nodes */ +      csa.na = na = G->na; /* number of arcs */ +      csa.large = large = INT_MAX / 4; +      csa.repeat = 0; +      csa.crash = crash; +      /* allocate working arrays */ +      csa.startn = xcalloc(1+na, sizeof(int)); +      csa.endn = xcalloc(1+na, sizeof(int)); +      csa.fou = xcalloc(1+n, sizeof(int)); +      csa.nxtou = xcalloc(1+na, sizeof(int)); +      csa.fin = xcalloc(1+n, sizeof(int)); +      csa.nxtin = xcalloc(1+na, sizeof(int)); +      csa.rc = xcalloc(1+na, sizeof(int)); +      csa.u = xcalloc(1+na, sizeof(int)); +      csa.dfct = xcalloc(1+n, sizeof(int)); +      csa.x = xcalloc(1+na, sizeof(int)); +      csa.label = xcalloc(1+n, sizeof(int)); +      csa.prdcsr = xcalloc(1+n, sizeof(int)); +      csa.save = xcalloc(1+na, sizeof(int)); +      csa.tfstou = xcalloc(1+n, sizeof(int)); +      csa.tnxtou = xcalloc(1+na, sizeof(int)); +      csa.tfstin = xcalloc(1+n, sizeof(int)); +      csa.tnxtin = xcalloc(1+na, sizeof(int)); +      csa.nxtqueue = xcalloc(1+n, sizeof(int)); +      csa.scan = xcalloc(1+n, sizeof(char)); +      csa.mark = xcalloc(1+n, sizeof(char)); +      if (crash) +      {  csa.extend_arc = xcalloc(1+n, sizeof(int)); +         csa.sb_level = xcalloc(1+n, sizeof(int)); +         csa.sb_arc = xcalloc(1+n, sizeof(int)); +      } +      else +      {  csa.extend_arc = NULL; +         csa.sb_level = NULL; +         csa.sb_arc = NULL; +      } +      /* scan nodes */ +      for (i = 1; i <= n; i++) +      {  v = G->v[i]; +         /* get supply at i-th node */ +         if (v_rhs >= 0) +            memcpy(&rhs, (char *)v->data + v_rhs, sizeof(double)); +         else +            rhs = 0.0; +         if (!(fabs(rhs) <= (double)large && rhs == floor(rhs))) +         {  ret = GLP_EDATA; +            goto done; +         } +         /* set demand at i-th node */ +         csa.dfct[i] = -(int)rhs; +      } +      /* scan arcs */ +      k = 0; +      for (i = 1; i <= n; i++) +      {  v = G->v[i]; +         for (a = v->out; a != NULL; a = a->t_next) +         {  k++; +            /* set endpoints of k-th arc */ +            if (a->tail->i == a->head->i) +            {  /* self-loops not allowed */ +               ret = GLP_EDATA; +               goto done; +            } +            csa.startn[k] = a->tail->i; +            csa.endn[k] = a->head->i; +            /* set per-unit cost for k-th arc flow */ +            if (a_cost >= 0) +               memcpy(&cost, (char *)a->data + a_cost, sizeof(double)); +            else +               cost = 0.0; +            if (!(fabs(cost) <= (double)large && cost == floor(cost))) +            {  ret = GLP_EDATA; +               goto done; +            } +            csa.rc[k] = (int)cost; +            /* get lower bound for k-th arc flow */ +            if (a_low >= 0) +               memcpy(&low, (char *)a->data + a_low, sizeof(double)); +            else +               low = 0.0; +            if (!(0.0 <= low && low <= (double)large && +                  low == floor(low))) +            {  ret = GLP_EDATA; +               goto done; +            } +            /* get upper bound for k-th arc flow */ +            if (a_cap >= 0) +               memcpy(&cap, (char *)a->data + a_cap, sizeof(double)); +            else +               cap = 1.0; +            if (!(low <= cap && cap <= (double)large && +                  cap == floor(cap))) +            {  ret = GLP_EDATA; +               goto done; +            } +            /* substitute x = x' + low, where 0 <= x' <= cap - low */ +            csa.u[k] = (int)(cap - low); +            /* correct demands at endpoints of k-th arc */ +            if (overflow(csa.dfct[a->tail->i], +low)) +            {  ret = GLP_ERANGE; +               goto done; +            } +#if 0 /* 29/IX-2017 */ +            csa.dfct[a->tail->i] += low; +#else +            csa.dfct[a->tail->i] += (int)low; +#endif +            if (overflow(csa.dfct[a->head->i], -low)) +            {  ret = GLP_ERANGE; +               goto done; +            } +#if 0 /* 29/IX-2017 */ +            csa.dfct[a->head->i] -= low; +#else +            csa.dfct[a->head->i] -= (int)low; +#endif +         } +      } +      /* construct linked list for network topology */ +      relax4_inidat(&csa); +      /* find minimum-cost flow */ +      ret = relax4(&csa); +      if (ret != 0) +      {  /* problem is found to be infeasible */ +         xassert(1 <= ret && ret <= 8); +         ret = GLP_ENOPFS; +         goto done; +      } +      /* store solution */ +      sum = 0.0; +      k = 0; +      for (i = 1; i <= n; i++) +      {  v = G->v[i]; +         for (a = v->out; a != NULL; a = a->t_next) +         {  k++; +            /* get lower bound for k-th arc flow */ +            if (a_low >= 0) +               memcpy(&low, (char *)a->data + a_low, sizeof(double)); +            else +               low = 0.0; +            /* store original flow x = x' + low thru k-th arc */ +            x = (double)csa.x[k] + low; +            if (a_x >= 0) +               memcpy((char *)a->data + a_x, &x, sizeof(double)); +            /* store reduced cost for k-th arc flow */ +            rc = (double)csa.rc[k]; +            if (a_rc >= 0) +               memcpy((char *)a->data + a_rc, &rc, sizeof(double)); +            /* get per-unit cost for k-th arc flow */ +            if (a_cost >= 0) +               memcpy(&cost, (char *)a->data + a_cost, sizeof(double)); +            else +               cost = 0.0; +            /* compute the total cost */ +            sum += cost * x; +         } +      } +      /* store the total cost */ +      if (sol != NULL) +         *sol = sum; +done: /* free working arrays */ +      xfree(csa.startn); +      xfree(csa.endn); +      xfree(csa.fou); +      xfree(csa.nxtou); +      xfree(csa.fin); +      xfree(csa.nxtin); +      xfree(csa.rc); +      xfree(csa.u); +      xfree(csa.dfct); +      xfree(csa.x); +      xfree(csa.label); +      xfree(csa.prdcsr); +      xfree(csa.save); +      xfree(csa.tfstou); +      xfree(csa.tnxtou); +      xfree(csa.tfstin); +      xfree(csa.tnxtin); +      xfree(csa.nxtqueue); +      xfree(csa.scan); +      xfree(csa.mark); +      if (crash) +      {  xfree(csa.extend_arc); +         xfree(csa.sb_level); +         xfree(csa.sb_arc); +      } +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/minisat1.c b/glpk-5.0/src/api/minisat1.c new file mode 100644 index 0000000..6015760 --- /dev/null +++ b/glpk-5.0/src/api/minisat1.c @@ -0,0 +1,159 @@ +/* minisat1.c (driver to MiniSat solver) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2011-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "minisat.h" +#include "prob.h" + +int glp_minisat1(glp_prob *P) +{     /* solve CNF-SAT problem with MiniSat solver */ +      solver *s; +      GLPAIJ *aij; +      int i, j, len, ret, *ind; +      double sum; +#if 0 /* 04/IV-2016 */ +      /* check problem object */ +      if (P == NULL || P->magic != GLP_PROB_MAGIC) +         xerror("glp_minisat1: P = %p; invalid problem object\n", +            P); +#endif +      if (P->tree != NULL) +         xerror("glp_minisat1: operation not allowed\n"); +      /* integer solution is currently undefined */ +      P->mip_stat = GLP_UNDEF; +      P->mip_obj = 0.0; +      /* check that problem object encodes CNF-SAT instance */ +      if (glp_check_cnfsat(P) != 0) +      {  xprintf("glp_minisat1: problem object does not encode CNF-SAT " +            "instance\n"); +         ret = GLP_EDATA; +         goto done; +      } +#if 0 /* 08/I-2017 by cmatraki */ +#if 1 /* 07/XI-2015 */ +      if (sizeof(void *) != sizeof(int)) +      {  xprintf("glp_minisat1: sorry, MiniSat solver is not supported " +            "on 64-bit platforms\n"); +         ret = GLP_EFAIL; +         goto done; +      } +#endif +#else +      if (sizeof(void *) != sizeof(size_t)) +      {  xprintf("glp_minisat1: sorry, MiniSat solver is not supported " +            "on this platform\n"); +         ret = GLP_EFAIL; +         goto done; +      } +#endif +      /* solve CNF-SAT problem */ +      xprintf("Solving CNF-SAT problem...\n"); +      xprintf("Instance has %d variable%s, %d clause%s, and %d literal%" +         "s\n", P->n, P->n == 1 ? "" : "s", P->m, P->m == 1 ? "" : "s", +         P->nnz, P->nnz == 1 ? "" : "s"); +      /* if CNF-SAT has no clauses, it is satisfiable */ +      if (P->m == 0) +      {  P->mip_stat = GLP_OPT; +         for (j = 1; j <= P->n; j++) +            P->col[j]->mipx = 0.0; +         goto fini; +      } +      /* if CNF-SAT has an empty clause, it is unsatisfiable */ +      for (i = 1; i <= P->m; i++) +      {  if (P->row[i]->ptr == NULL) +         {  P->mip_stat = GLP_NOFEAS; +            goto fini; +         } +      } +      /* prepare input data for the solver */ +      s = solver_new(); +      solver_setnvars(s, P->n); +      ind = xcalloc(1+P->n, sizeof(int)); +      for (i = 1; i <= P->m; i++) +      {  len = 0; +         for (aij = P->row[i]->ptr; aij != NULL; aij = aij->r_next) +         {  ind[++len] = toLit(aij->col->j-1); +            if (aij->val < 0.0) +               ind[len] = lit_neg(ind[len]); +         } +         xassert(len > 0); +#if 0 /* 08/I-2017 by cmatraki */ +         xassert(solver_addclause(s, &ind[1], &ind[1+len])); +#else +         if (!solver_addclause(s, &ind[1], &ind[1+len])) +         {  /* found trivial conflict */ +            xfree(ind); +            solver_delete(s); +            P->mip_stat = GLP_NOFEAS; +            goto fini; +         } +#endif +      } +      xfree(ind); +      /* call the solver */ +      s->verbosity = 1; +      if (solver_solve(s, 0, 0)) +      {  /* instance is reported as satisfiable */ +         P->mip_stat = GLP_OPT; +         /* copy solution to the problem object */ +         xassert(s->model.size == P->n); +         for (j = 1; j <= P->n; j++) +         {  P->col[j]->mipx = +               s->model.ptr[j-1] == l_True ? 1.0 : 0.0; +         } +         /* compute row values */ +         for (i = 1; i <= P->m; i++) +         {  sum = 0; +            for (aij = P->row[i]->ptr; aij != NULL; aij = aij->r_next) +               sum += aij->val * aij->col->mipx; +            P->row[i]->mipx = sum; +         } +         /* check integer feasibility */ +         for (i = 1; i <= P->m; i++) +         {  if (P->row[i]->mipx < P->row[i]->lb) +            {  /* solution is wrong */ +               P->mip_stat = GLP_UNDEF; +               break; +            } +         } +      } +      else +      {  /* instance is reported as unsatisfiable */ +         P->mip_stat = GLP_NOFEAS; +      } +      solver_delete(s); +fini: /* report the instance status */ +      if (P->mip_stat == GLP_OPT) +      {  xprintf("SATISFIABLE\n"); +         ret = 0; +      } +      else if (P->mip_stat == GLP_NOFEAS) +      {  xprintf("UNSATISFIABLE\n"); +         ret = 0; +      } +      else +      {  xprintf("glp_minisat1: solver failed\n"); +         ret = GLP_EFAIL; +      } +done: return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/mpl.c b/glpk-5.0/src/api/mpl.c new file mode 100644 index 0000000..6dd886c --- /dev/null +++ b/glpk-5.0/src/api/mpl.c @@ -0,0 +1,267 @@ +/* mpl.c (processing model in GNU MathProg language) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2008-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "mpl.h" +#include "prob.h" + +glp_tran *glp_mpl_alloc_wksp(void) +{     /* allocate the MathProg translator workspace */ +      glp_tran *tran; +      tran = mpl_initialize(); +      return tran; +} + +void glp_mpl_init_rand(glp_tran *tran, int seed) +{     /* initialize pseudo-random number generator */ +      if (tran->phase != 0) +         xerror("glp_mpl_init_rand: invalid call sequence\n"); +      rng_init_rand(tran->rand, seed); +      return; +} + +int glp_mpl_read_model(glp_tran *tran, const char *fname, int skip) +{     /* read and translate model section */ +      int ret; +      if (tran->phase != 0) +         xerror("glp_mpl_read_model: invalid call sequence\n"); +      ret = mpl_read_model(tran, (char *)fname, skip); +      if (ret == 1 || ret == 2) +         ret = 0; +      else if (ret == 4) +         ret = 1; +      else +         xassert(ret != ret); +      return ret; +} + +int glp_mpl_read_data(glp_tran *tran, const char *fname) +{     /* read and translate data section */ +      int ret; +      if (!(tran->phase == 1 || tran->phase == 2)) +         xerror("glp_mpl_read_data: invalid call sequence\n"); +      ret = mpl_read_data(tran, (char *)fname); +      if (ret == 2) +         ret = 0; +      else if (ret == 4) +         ret = 1; +      else +         xassert(ret != ret); +      return ret; +} + +int glp_mpl_generate(glp_tran *tran, const char *fname) +{     /* generate the model */ +      int ret; +      if (!(tran->phase == 1 || tran->phase == 2)) +         xerror("glp_mpl_generate: invalid call sequence\n"); +      ret = mpl_generate(tran, (char *)fname); +      if (ret == 3) +         ret = 0; +      else if (ret == 4) +         ret = 1; +      return ret; +} + +void glp_mpl_build_prob(glp_tran *tran, glp_prob *prob) +{     /* build LP/MIP problem instance from the model */ +      int m, n, i, j, t, kind, type, len, *ind; +      double lb, ub, *val; +      if (tran->phase != 3) +         xerror("glp_mpl_build_prob: invalid call sequence\n"); +      /* erase the problem object */ +      glp_erase_prob(prob); +      /* set problem name */ +      glp_set_prob_name(prob, mpl_get_prob_name(tran)); +      /* build rows (constraints) */ +      m = mpl_get_num_rows(tran); +      if (m > 0) +         glp_add_rows(prob, m); +      for (i = 1; i <= m; i++) +      {  /* set row name */ +         glp_set_row_name(prob, i, mpl_get_row_name(tran, i)); +         /* set row bounds */ +         type = mpl_get_row_bnds(tran, i, &lb, &ub); +         switch (type) +         {  case MPL_FR: type = GLP_FR; break; +            case MPL_LO: type = GLP_LO; break; +            case MPL_UP: type = GLP_UP; break; +            case MPL_DB: type = GLP_DB; break; +            case MPL_FX: type = GLP_FX; break; +            default: xassert(type != type); +         } +         if (type == GLP_DB && fabs(lb - ub) < 1e-9 * (1.0 + fabs(lb))) +         {  type = GLP_FX; +            if (fabs(lb) <= fabs(ub)) ub = lb; else lb = ub; +         } +         glp_set_row_bnds(prob, i, type, lb, ub); +         /* warn about non-zero constant term */ +         if (mpl_get_row_c0(tran, i) != 0.0) +            xprintf("glp_mpl_build_prob: row %s; constant term %.12g ig" +               "nored\n", +               mpl_get_row_name(tran, i), mpl_get_row_c0(tran, i)); +      } +      /* build columns (variables) */ +      n = mpl_get_num_cols(tran); +      if (n > 0) +         glp_add_cols(prob, n); +      for (j = 1; j <= n; j++) +      {  /* set column name */ +         glp_set_col_name(prob, j, mpl_get_col_name(tran, j)); +         /* set column kind */ +         kind = mpl_get_col_kind(tran, j); +         switch (kind) +         {  case MPL_NUM: +               break; +            case MPL_INT: +            case MPL_BIN: +               glp_set_col_kind(prob, j, GLP_IV); +               break; +            default: +               xassert(kind != kind); +         } +         /* set column bounds */ +         type = mpl_get_col_bnds(tran, j, &lb, &ub); +         switch (type) +         {  case MPL_FR: type = GLP_FR; break; +            case MPL_LO: type = GLP_LO; break; +            case MPL_UP: type = GLP_UP; break; +            case MPL_DB: type = GLP_DB; break; +            case MPL_FX: type = GLP_FX; break; +            default: xassert(type != type); +         } +         if (kind == MPL_BIN) +         {  if (type == GLP_FR || type == GLP_UP || lb < 0.0) lb = 0.0; +            if (type == GLP_FR || type == GLP_LO || ub > 1.0) ub = 1.0; +            type = GLP_DB; +         } +         if (type == GLP_DB && fabs(lb - ub) < 1e-9 * (1.0 + fabs(lb))) +         {  type = GLP_FX; +            if (fabs(lb) <= fabs(ub)) ub = lb; else lb = ub; +         } +         glp_set_col_bnds(prob, j, type, lb, ub); +      } +      /* load the constraint matrix */ +      ind = xcalloc(1+n, sizeof(int)); +      val = xcalloc(1+n, sizeof(double)); +      for (i = 1; i <= m; i++) +      {  len = mpl_get_mat_row(tran, i, ind, val); +         glp_set_mat_row(prob, i, len, ind, val); +      } +      /* build objective function (the first objective is used) */ +      for (i = 1; i <= m; i++) +      {  kind = mpl_get_row_kind(tran, i); +         if (kind == MPL_MIN || kind == MPL_MAX) +         {  /* set objective name */ +            glp_set_obj_name(prob, mpl_get_row_name(tran, i)); +            /* set optimization direction */ +            glp_set_obj_dir(prob, kind == MPL_MIN ? GLP_MIN : GLP_MAX); +            /* set constant term */ +            glp_set_obj_coef(prob, 0, mpl_get_row_c0(tran, i)); +            /* set objective coefficients */ +            len = mpl_get_mat_row(tran, i, ind, val); +            for (t = 1; t <= len; t++) +               glp_set_obj_coef(prob, ind[t], val[t]); +            break; +         } +      } +      /* free working arrays */ +      xfree(ind); +      xfree(val); +      return; +} + +int glp_mpl_postsolve(glp_tran *tran, glp_prob *prob, int sol) +{     /* postsolve the model */ +      int i, j, m, n, stat, ret; +      double prim, dual; +      if (!(tran->phase == 3 && !tran->flag_p)) +         xerror("glp_mpl_postsolve: invalid call sequence\n"); +      if (!(sol == GLP_SOL || sol == GLP_IPT || sol == GLP_MIP)) +         xerror("glp_mpl_postsolve: sol = %d; invalid parameter\n", +            sol); +      m = mpl_get_num_rows(tran); +      n = mpl_get_num_cols(tran); +      if (!(m == glp_get_num_rows(prob) && +            n == glp_get_num_cols(prob))) +         xerror("glp_mpl_postsolve: wrong problem object\n"); +      if (!mpl_has_solve_stmt(tran)) +      {  ret = 0; +         goto done; +      } +      for (i = 1; i <= m; i++) +      {  if (sol == GLP_SOL) +         {  stat = glp_get_row_stat(prob, i); +            prim = glp_get_row_prim(prob, i); +            dual = glp_get_row_dual(prob, i); +         } +         else if (sol == GLP_IPT) +         {  stat = 0; +            prim = glp_ipt_row_prim(prob, i); +            dual = glp_ipt_row_dual(prob, i); +         } +         else if (sol == GLP_MIP) +         {  stat = 0; +            prim = glp_mip_row_val(prob, i); +            dual = 0.0; +         } +         else +            xassert(sol != sol); +         if (fabs(prim) < 1e-9) prim = 0.0; +         if (fabs(dual) < 1e-9) dual = 0.0; +         mpl_put_row_soln(tran, i, stat, prim, dual); +      } +      for (j = 1; j <= n; j++) +      {  if (sol == GLP_SOL) +         {  stat = glp_get_col_stat(prob, j); +            prim = glp_get_col_prim(prob, j); +            dual = glp_get_col_dual(prob, j); +         } +         else if (sol == GLP_IPT) +         {  stat = 0; +            prim = glp_ipt_col_prim(prob, j); +            dual = glp_ipt_col_dual(prob, j); +         } +         else if (sol == GLP_MIP) +         {  stat = 0; +            prim = glp_mip_col_val(prob, j); +            dual = 0.0; +         } +         else +            xassert(sol != sol); +         if (fabs(prim) < 1e-9) prim = 0.0; +         if (fabs(dual) < 1e-9) dual = 0.0; +         mpl_put_col_soln(tran, j, stat, prim, dual); +      } +      ret = mpl_postsolve(tran); +      if (ret == 3) +         ret = 0; +      else if (ret == 4) +         ret = 1; +done: return ret; +} + +void glp_mpl_free_wksp(glp_tran *tran) +{     /* free the MathProg translator workspace */ +      mpl_terminate(tran); +      return; +} + +/* eof */ diff --git a/glpk-5.0/src/api/mps.c b/glpk-5.0/src/api/mps.c new file mode 100644 index 0000000..c17d8d9 --- /dev/null +++ b/glpk-5.0/src/api/mps.c @@ -0,0 +1,1450 @@ +/* mps.c (MPS format routines) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2008-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "misc.h" +#include "prob.h" + +#define xfprintf glp_format + +/*********************************************************************** +*  NAME +* +*  glp_init_mpscp - initialize MPS format control parameters +* +*  SYNOPSIS +* +*  void glp_init_mpscp(glp_mpscp *parm); +* +*  DESCRIPTION +* +*  The routine glp_init_mpscp initializes control parameters, which are +*  used by the MPS input/output routines glp_read_mps and glp_write_mps, +*  with default values. +* +*  Default values of the control parameters are stored in the glp_mpscp +*  structure, which the parameter parm points to. */ + +void glp_init_mpscp(glp_mpscp *parm) +{     parm->blank = '\0'; +      parm->obj_name = NULL; +      parm->tol_mps = 1e-12; +      return; +} + +static void check_parm(const char *func, const glp_mpscp *parm) +{     /* check control parameters */ +      if (!(0x00 <= parm->blank && parm->blank <= 0xFF) || +          !(parm->blank == '\0' || isprint(parm->blank))) +         xerror("%s: blank = 0x%02X; invalid parameter\n", +            func, parm->blank); +      if (!(parm->obj_name == NULL || strlen(parm->obj_name) <= 255)) +         xerror("%s: obj_name = \"%.12s...\"; parameter too long\n", +            func, parm->obj_name); +      if (!(0.0 <= parm->tol_mps && parm->tol_mps < 1.0)) +         xerror("%s: tol_mps = %g; invalid parameter\n", +            func, parm->tol_mps); +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_read_mps - read problem data in MPS format +* +*  SYNOPSIS +* +*  int glp_read_mps(glp_prob *P, int fmt, const glp_mpscp *parm, +*     const char *fname); +* +*  DESCRIPTION +* +*  The routine glp_read_mps reads problem data in MPS format from a +*  text file. +* +*  The parameter fmt specifies the version of MPS format: +* +*  GLP_MPS_DECK - fixed (ancient) MPS format; +*  GLP_MPS_FILE - free (modern) MPS format. +* +*  The parameter parm is a pointer to the structure glp_mpscp, which +*  specifies control parameters used by the routine. If parm is NULL, +*  the routine uses default settings. +* +*  The character string fname specifies a name of the text file to be +*  read. +* +*  Note that before reading data the current content of the problem +*  object is completely erased with the routine glp_erase_prob. +* +*  RETURNS +* +*  If the operation was successful, the routine glp_read_mps returns +*  zero. Otherwise, it prints an error message and returns non-zero. */ + +struct csa +{     /* common storage area */ +      glp_prob *P; +      /* pointer to problem object */ +      int deck; +      /* MPS format (0 - free, 1 - fixed) */ +      const glp_mpscp *parm; +      /* pointer to control parameters */ +      const char *fname; +      /* name of input MPS file */ +      glp_file *fp; +      /* stream assigned to input MPS file */ +      jmp_buf jump; +      /* label for go to in case of error */ +      int recno; +      /* current record (card) number */ +      int recpos; +      /* current record (card) position */ +      int c; +      /* current character */ +      int fldno; +      /* current field number */ +      char field[255+1]; +      /* current field content */ +      int w80; +      /* warning 'record must not be longer than 80 chars' issued */ +      int wef; +      /* warning 'extra fields detected beyond field 6' issued */ +      int obj_row; +      /* objective row number */ +      void *work1, *work2, *work3; +      /* working arrays */ +}; + +static void error(struct csa *csa, const char *fmt, ...) +{     /* print error message and terminate processing */ +      va_list arg; +      xprintf("%s:%d: ", csa->fname, csa->recno); +      va_start(arg, fmt); +      xvprintf(fmt, arg); +      va_end(arg); +      longjmp(csa->jump, 1); +      /* no return */ +} + +static void warning(struct csa *csa, const char *fmt, ...) +{     /* print warning message and continue processing */ +      va_list arg; +      xprintf("%s:%d: warning: ", csa->fname, csa->recno); +      va_start(arg, fmt); +      xvprintf(fmt, arg); +      va_end(arg); +      return; +} + +static void read_char(struct csa *csa) +{     /* read next character */ +      int c; +      if (csa->c == '\n') +         csa->recno++, csa->recpos = 0; +      csa->recpos++; +read: c = glp_getc(csa->fp); +      if (c < 0) +      {  if (glp_ioerr(csa->fp)) +            error(csa, "read error - %s\n", get_err_msg()); +         else if (csa->c == '\n') +            error(csa, "unexpected end of file\n"); +         else +         {  warning(csa, "missing final end of line\n"); +            c = '\n'; +         } +      } +      else if (c == '\n') +         ; +      else if (csa->c == '\r') +      {  c = '\r'; +         goto badc; +      } +      else if (csa->deck && c == '\r') +      {  csa->c = '\r'; +         goto read; +      } +      else if (c == ' ') +         ; +      else if (isspace(c)) +      {  if (csa->deck) +badc:       error(csa, "in fixed MPS format white-space character 0x%02" +               "X is not allowed\n", c); +         c = ' '; +      } +      else if (iscntrl(c)) +         error(csa, "invalid control character 0x%02X\n", c); +      if (csa->deck && csa->recpos == 81 && c != '\n' && csa->w80 < 1) +      {  warning(csa, "in fixed MPS format record must not be longer th" +            "an 80 characters\n"); +         csa->w80++; +      } +      csa->c = c; +      return; +} + +static int indicator(struct csa *csa, int name) +{     /* skip comment records and read possible indicator record */ +      int ret; +      /* reset current field number */ +      csa->fldno = 0; +loop: /* read the very first character of the next record */ +      xassert(csa->c == '\n'); +      read_char(csa); +      if (csa->c == ' ' || csa->c == '\n') +      {  /* data record */ +         ret = 0; +      } +      else if (csa->c == '*') +      {  /* comment record */ +         while (csa->c != '\n') +            read_char(csa); +         goto loop; +      } +      else +      {  /* indicator record */ +         int len = 0; +         while (csa->c != ' ' && csa->c != '\n' && len < 12) +         {  csa->field[len++] = (char)csa->c; +            read_char(csa); +         } +         csa->field[len] = '\0'; +         if (!(strcmp(csa->field, "NAME")    == 0 || +               strcmp(csa->field, "ROWS")    == 0 || +               strcmp(csa->field, "COLUMNS") == 0 || +               strcmp(csa->field, "RHS")     == 0 || +               strcmp(csa->field, "RANGES")  == 0 || +               strcmp(csa->field, "BOUNDS")  == 0 || +               strcmp(csa->field, "ENDATA")  == 0)) +            error(csa, "invalid indicator record\n"); +         if (!name) +         {  while (csa->c != '\n') +               read_char(csa); +         } +         ret = 1; +      } +      return ret; +} + +static void read_field(struct csa *csa) +{     /* read next field of the current data record */ +      csa->fldno++; +      if (csa->deck) +      {  /* fixed MPS format */ +         int beg, end, pos; +         /* determine predefined field positions */ +         if (csa->fldno == 1) +            beg = 2, end = 3; +         else if (csa->fldno == 2) +            beg = 5, end = 12; +         else if (csa->fldno == 3) +            beg = 15, end = 22; +         else if (csa->fldno == 4) +            beg = 25, end = 36; +         else if (csa->fldno == 5) +            beg = 40, end = 47; +         else if (csa->fldno == 6) +            beg = 50, end = 61; +         else +            xassert(csa != csa); +         /* skip blanks preceding the current field */ +         if (csa->c != '\n') +         {  pos = csa->recpos; +            while (csa->recpos < beg) +            {  if (csa->c == ' ') +                  ; +               else if (csa->c == '\n') +                  break; +               else +                  error(csa, "in fixed MPS format positions %d-%d must " +                     "be blank\n", pos, beg-1); +               read_char(csa); +            } +         } +         /* skip possible comment beginning in the field 3 or 5 */ +         if ((csa->fldno == 3 || csa->fldno == 5) && csa->c == '$') +         {  while (csa->c != '\n') +               read_char(csa); +         } +         /* read the current field */ +         for (pos = beg; pos <= end; pos++) +         {  if (csa->c == '\n') break; +            csa->field[pos-beg] = (char)csa->c; +            read_char(csa); +         } +         csa->field[pos-beg] = '\0'; +         strtrim(csa->field); +         /* skip blanks following the last field */ +         if (csa->fldno == 6 && csa->c != '\n') +         {  while (csa->recpos <= 72) +            {  if (csa->c == ' ') +                  ; +               else if (csa->c == '\n') +                  break; +               else +                  error(csa, "in fixed MPS format positions 62-72 must " +                     "be blank\n"); +               read_char(csa); +            } +            while (csa->c != '\n') +               read_char(csa); +         } +      } +      else +      {  /* free MPS format */ +         int len; +         /* skip blanks preceding the current field */ +         while (csa->c == ' ') +            read_char(csa); +         /* skip possible comment */ +         if (csa->c == '$') +         {  while (csa->c != '\n') +               read_char(csa); +         } +         /* read the current field */ +         len = 0; +         while (!(csa->c == ' ' || csa->c == '\n')) +         {  if (len == 255) +               error(csa, "length of field %d exceeds 255 characters\n", +                  csa->fldno++); +            csa->field[len++] = (char)csa->c; +            read_char(csa); +         } +         csa->field[len] = '\0'; +         /* skip anything following the last field (any extra fields +            are considered to be comments) */ +         if (csa->fldno == 6) +         {  while (csa->c == ' ') +               read_char(csa); +            if (csa->c != '$' && csa->c != '\n' && csa->wef < 1) +            {  warning(csa, "some extra field(s) detected beyond field " +                  "6; field(s) ignored\n"); +               csa->wef++; +            } +            while (csa->c != '\n') +               read_char(csa); +         } +      } +      return; +} + +static void patch_name(struct csa *csa, char *name) +{     /* process embedded blanks in symbolic name */ +      int blank = csa->parm->blank; +      if (blank == '\0') +      {  /* remove emedded blanks */ +         strspx(name); +      } +      else +      {  /* replace embedded blanks by specified character */ +         for (; *name != '\0'; name++) +            if (*name == ' ') *name = (char)blank; +      } +      return; +} + +static double read_number(struct csa *csa) +{     /* read next field and convert it to floating-point number */ +      double x; +      char *s; +      /* read next field */ +      read_field(csa); +      xassert(csa->fldno == 4 || csa->fldno == 6); +      if (csa->field[0] == '\0') +         error(csa, "missing numeric value in field %d\n", csa->fldno); +      /* skip initial spaces of the field */ +      for (s = csa->field; *s == ' '; s++); +      /* perform conversion */ +      if (str2num(s, &x) != 0) +         error(csa, "cannot convert '%s' to floating-point number\n", +            s); +      return x; +} + +static void skip_field(struct csa *csa) +{     /* read and skip next field (assumed to be blank) */ +      read_field(csa); +      if (csa->field[0] != '\0') +         error(csa, "field %d must be blank\n", csa->fldno); +      return; +} + +static void read_name(struct csa *csa) +{     /* read NAME indicator record */ +      if (!(indicator(csa, 1) && strcmp(csa->field, "NAME") == 0)) +         error(csa, "missing NAME indicator record\n"); +      /* this indicator record looks like a data record; simulate that +         fields 1 and 2 were read */ +      csa->fldno = 2; +      /* field 3: model name */ +      read_field(csa), patch_name(csa, csa->field); +      if (csa->field[0] == '\0') +         warning(csa, "missing model name in field 3\n"); +      else +         glp_set_prob_name(csa->P, csa->field); +      /* skip anything following field 3 */ +      while (csa->c != '\n') +         read_char(csa); +      return; +} + +static void read_rows(struct csa *csa) +{     /* read ROWS section */ +      int i, type; +loop: if (indicator(csa, 0)) goto done; +      /* field 1: row type */ +      read_field(csa), strspx(csa->field); +      if (strcmp(csa->field, "N") == 0) +         type = GLP_FR; +      else if (strcmp(csa->field, "G") == 0) +         type = GLP_LO; +      else if (strcmp(csa->field, "L") == 0) +         type = GLP_UP; +      else if (strcmp(csa->field, "E") == 0) +         type = GLP_FX; +      else if (csa->field[0] == '\0') +         error(csa, "missing row type in field 1\n"); +      else +         error(csa, "invalid row type in field 1\n"); +      /* field 2: row name */ +      read_field(csa), patch_name(csa, csa->field); +      if (csa->field[0] == '\0') +         error(csa, "missing row name in field 2\n"); +      if (glp_find_row(csa->P, csa->field) != 0) +         error(csa, "row '%s' multiply specified\n", csa->field); +      i = glp_add_rows(csa->P, 1); +      glp_set_row_name(csa->P, i, csa->field); +      glp_set_row_bnds(csa->P, i, type, 0.0, 0.0); +      /* fields 3, 4, 5, and 6 must be blank */ +      skip_field(csa); +      skip_field(csa); +      skip_field(csa); +      skip_field(csa); +      goto loop; +done: return; +} + +static void read_columns(struct csa *csa) +{     /* read COLUMNS section */ +      int i, j, f, len, kind = GLP_CV, *ind; +      double aij, *val; +      char name[255+1], *flag; +      /* allocate working arrays */ +      csa->work1 = ind = xcalloc(1+csa->P->m, sizeof(int)); +      csa->work2 = val = xcalloc(1+csa->P->m, sizeof(double)); +      csa->work3 = flag = xcalloc(1+csa->P->m, sizeof(char)); +      memset(&flag[1], 0, csa->P->m); +      /* no current column exists */ +      j = 0, len = 0; +loop: if (indicator(csa, 0)) goto done; +      /* field 1 must be blank */ +      if (csa->deck) +      {  read_field(csa); +         if (csa->field[0] != '\0') +            error(csa, "field 1 must be blank\n"); +      } +      else +         csa->fldno++; +      /* field 2: column or kind name */ +      read_field(csa), patch_name(csa, csa->field); +      strcpy(name, csa->field); +      /* field 3: row name or keyword 'MARKER' */ +      read_field(csa), patch_name(csa, csa->field); +      if (strcmp(csa->field, "'MARKER'") == 0) +      {  /* process kind data record */ +         /* field 4 must be blank */ +         if (csa->deck) +         {  read_field(csa); +            if (csa->field[0] != '\0') +               error(csa, "field 4 must be blank\n"); +         } +         else +            csa->fldno++; +         /* field 5: keyword 'INTORG' or 'INTEND' */ +         read_field(csa), patch_name(csa, csa->field); +         if (strcmp(csa->field, "'INTORG'") == 0) +            kind = GLP_IV; +         else if (strcmp(csa->field, "'INTEND'") == 0) +            kind = GLP_CV; +         else if (csa->field[0] == '\0') +            error(csa, "missing keyword in field 5\n"); +         else +            error(csa, "invalid keyword in field 5\n"); +         /* field 6 must be blank */ +         skip_field(csa); +         goto loop; +      } +      /* process column name specified in field 2 */ +      if (name[0] == '\0') +      {  /* the same column as in previous data record */ +         if (j == 0) +            error(csa, "missing column name in field 2\n"); +      } +      else if (j != 0 && strcmp(name, csa->P->col[j]->name) == 0) +      {  /* the same column as in previous data record */ +         xassert(j != 0); +      } +      else +      {  /* store the current column */ +         if (j != 0) +         {  glp_set_mat_col(csa->P, j, len, ind, val); +            while (len > 0) flag[ind[len--]] = 0; +         } +         /* create new column */ +         if (glp_find_col(csa->P, name) != 0) +            error(csa, "column '%s' multiply specified\n", name); +         j = glp_add_cols(csa->P, 1); +         glp_set_col_name(csa->P, j, name); +         glp_set_col_kind(csa->P, j, kind); +         if (kind == GLP_CV) +            glp_set_col_bnds(csa->P, j, GLP_LO, 0.0, 0.0); +         else if (kind == GLP_IV) +            glp_set_col_bnds(csa->P, j, GLP_DB, 0.0, 1.0); +         else +            xassert(kind != kind); +      } +      /* process fields 3-4 and 5-6 */ +      for (f = 3; f <= 5; f += 2) +      {  /* field 3 or 5: row name */ +         if (f == 3) +         {  if (csa->field[0] == '\0') +               error(csa, "missing row name in field 3\n"); +         } +         else +         {  read_field(csa), patch_name(csa, csa->field); +            if (csa->field[0] == '\0') +            {  /* if field 5 is blank, field 6 also must be blank */ +               skip_field(csa); +               continue; +            } +         } +         i = glp_find_row(csa->P, csa->field); +         if (i == 0) +            error(csa, "row '%s' not found\n", csa->field); +         if (flag[i]) +            error(csa, "duplicate coefficient in row '%s'\n", +               csa->field); +         /* field 4 or 6: coefficient value */ +         aij = read_number(csa); +         if (fabs(aij) < csa->parm->tol_mps) aij = 0.0; +         len++, ind[len] = i, val[len] = aij, flag[i] = 1; +      } +      goto loop; +done: /* store the last column */ +      if (j != 0) +         glp_set_mat_col(csa->P, j, len, ind, val); +      /* free working arrays */ +      xfree(ind); +      xfree(val); +      xfree(flag); +      csa->work1 = csa->work2 = csa->work3 = NULL; +      return; +} + +static void read_rhs(struct csa *csa) +{     /* read RHS section */ +      int i, f, v, type; +      double rhs; +      char name[255+1], *flag; +      /* allocate working array */ +      csa->work3 = flag = xcalloc(1+csa->P->m, sizeof(char)); +      memset(&flag[1], 0, csa->P->m); +      /* no current RHS vector exists */ +      v = 0; +loop: if (indicator(csa, 0)) goto done; +      /* field 1 must be blank */ +      if (csa->deck) +      {  read_field(csa); +         if (csa->field[0] != '\0') +            error(csa, "field 1 must be blank\n"); +      } +      else +         csa->fldno++; +      /* field 2: RHS vector name */ +      read_field(csa), patch_name(csa, csa->field); +      if (csa->field[0] == '\0') +      {  /* the same RHS vector as in previous data record */ +         if (v == 0) +         {  warning(csa, "missing RHS vector name in field 2\n"); +            goto blnk; +         } +      } +      else if (v != 0 && strcmp(csa->field, name) == 0) +      {  /* the same RHS vector as in previous data record */ +         xassert(v != 0); +      } +      else +blnk: {  /* new RHS vector */ +         if (v != 0) +            error(csa, "multiple RHS vectors not supported\n"); +         v++; +         strcpy(name, csa->field); +      } +      /* process fields 3-4 and 5-6 */ +      for (f = 3; f <= 5; f += 2) +      {  /* field 3 or 5: row name */ +         read_field(csa), patch_name(csa, csa->field); +         if (csa->field[0] == '\0') +         {  if (f == 3) +               error(csa, "missing row name in field 3\n"); +            else +            {  /* if field 5 is blank, field 6 also must be blank */ +               skip_field(csa); +               continue; +            } +         } +         i = glp_find_row(csa->P, csa->field); +         if (i == 0) +            error(csa, "row '%s' not found\n", csa->field); +         if (flag[i]) +            error(csa, "duplicate right-hand side for row '%s'\n", +               csa->field); +         /* field 4 or 6: right-hand side value */ +         rhs = read_number(csa); +         if (fabs(rhs) < csa->parm->tol_mps) rhs = 0.0; +         type = csa->P->row[i]->type; +         if (type == GLP_FR) +         {  if (i == csa->obj_row) +               glp_set_obj_coef(csa->P, 0, rhs); +            else if (rhs != 0.0) +               warning(csa, "non-zero right-hand side for free row '%s'" +                  " ignored\n", csa->P->row[i]->name); +         } +         else +            glp_set_row_bnds(csa->P, i, type, rhs, rhs); +         flag[i] = 1; +      } +      goto loop; +done: /* free working array */ +      xfree(flag); +      csa->work3 = NULL; +      return; +} + +static void read_ranges(struct csa *csa) +{     /* read RANGES section */ +      int i, f, v, type; +      double rhs, rng; +      char name[255+1], *flag; +      /* allocate working array */ +      csa->work3 = flag = xcalloc(1+csa->P->m, sizeof(char)); +      memset(&flag[1], 0, csa->P->m); +      /* no current RANGES vector exists */ +      v = 0; +loop: if (indicator(csa, 0)) goto done; +      /* field 1 must be blank */ +      if (csa->deck) +      {  read_field(csa); +         if (csa->field[0] != '\0') +            error(csa, "field 1 must be blank\n"); +      } +      else +         csa->fldno++; +      /* field 2: RANGES vector name */ +      read_field(csa), patch_name(csa, csa->field); +      if (csa->field[0] == '\0') +      {  /* the same RANGES vector as in previous data record */ +         if (v == 0) +         {  warning(csa, "missing RANGES vector name in field 2\n"); +            goto blnk; +         } +      } +      else if (v != 0 && strcmp(csa->field, name) == 0) +      {  /* the same RANGES vector as in previous data record */ +         xassert(v != 0); +      } +      else +blnk: {  /* new RANGES vector */ +         if (v != 0) +            error(csa, "multiple RANGES vectors not supported\n"); +         v++; +         strcpy(name, csa->field); +      } +      /* process fields 3-4 and 5-6 */ +      for (f = 3; f <= 5; f += 2) +      {  /* field 3 or 5: row name */ +         read_field(csa), patch_name(csa, csa->field); +         if (csa->field[0] == '\0') +         {  if (f == 3) +               error(csa, "missing row name in field 3\n"); +            else +            {  /* if field 5 is blank, field 6 also must be blank */ +               skip_field(csa); +               continue; +            } +         } +         i = glp_find_row(csa->P, csa->field); +         if (i == 0) +            error(csa, "row '%s' not found\n", csa->field); +         if (flag[i]) +            error(csa, "duplicate range for row '%s'\n", csa->field); +         /* field 4 or 6: range value */ +         rng = read_number(csa); +         if (fabs(rng) < csa->parm->tol_mps) rng = 0.0; +         type = csa->P->row[i]->type; +         if (type == GLP_FR) +            warning(csa, "range for free row '%s' ignored\n", +               csa->P->row[i]->name); +         else if (type == GLP_LO) +         {  rhs = csa->P->row[i]->lb; +#if 0 /* 26/V-2017 by cmatraki */ +            glp_set_row_bnds(csa->P, i, rhs == 0.0 ? GLP_FX : GLP_DB, +#else +            glp_set_row_bnds(csa->P, i, rng == 0.0 ? GLP_FX : GLP_DB, +#endif +               rhs, rhs + fabs(rng)); +         } +         else if (type == GLP_UP) +         {  rhs = csa->P->row[i]->ub; +#if 0 /* 26/V-2017 by cmatraki */ +            glp_set_row_bnds(csa->P, i, rhs == 0.0 ? GLP_FX : GLP_DB, +#else +            glp_set_row_bnds(csa->P, i, rng == 0.0 ? GLP_FX : GLP_DB, +#endif +               rhs - fabs(rng), rhs); +         } +         else if (type == GLP_FX) +         {  rhs = csa->P->row[i]->lb; +            if (rng > 0.0) +               glp_set_row_bnds(csa->P, i, GLP_DB, rhs, rhs + rng); +            else if (rng < 0.0) +               glp_set_row_bnds(csa->P, i, GLP_DB, rhs + rng, rhs); +         } +         else +            xassert(type != type); +         flag[i] = 1; +      } +      goto loop; +done: /* free working array */ +      xfree(flag); +      csa->work3 = NULL; +      return; +} + +static void read_bounds(struct csa *csa) +{     /* read BOUNDS section */ +      GLPCOL *col; +      int j, v, mask, data; +      double bnd, lb, ub; +      char type[2+1], name[255+1], *flag; +      /* allocate working array */ +      csa->work3 = flag = xcalloc(1+csa->P->n, sizeof(char)); +      memset(&flag[1], 0, csa->P->n); +      /* no current BOUNDS vector exists */ +      v = 0; +loop: if (indicator(csa, 0)) goto done; +      /* field 1: bound type */ +      read_field(csa); +      if (strcmp(csa->field, "LO") == 0) +         mask = 0x01, data = 1; +      else if (strcmp(csa->field, "UP") == 0) +         mask = 0x10, data = 1; +      else if (strcmp(csa->field, "FX") == 0) +         mask = 0x11, data = 1; +      else if (strcmp(csa->field, "FR") == 0) +         mask = 0x11, data = 0; +      else if (strcmp(csa->field, "MI") == 0) +         mask = 0x01, data = 0; +      else if (strcmp(csa->field, "PL") == 0) +         mask = 0x10, data = 0; +      else if (strcmp(csa->field, "LI") == 0) +         mask = 0x01, data = 1; +      else if (strcmp(csa->field, "UI") == 0) +         mask = 0x10, data = 1; +      else if (strcmp(csa->field, "BV") == 0) +         mask = 0x11, data = 0; +      else if (csa->field[0] == '\0') +         error(csa, "missing bound type in field 1\n"); +      else +         error(csa, "invalid bound type in field 1\n"); +      strcpy(type, csa->field); +      /* field 2: BOUNDS vector name */ +      read_field(csa), patch_name(csa, csa->field); +      if (csa->field[0] == '\0') +      {  /* the same BOUNDS vector as in previous data record */ +         if (v == 0) +         {  warning(csa, "missing BOUNDS vector name in field 2\n"); +            goto blnk; +         } +      } +      else if (v != 0 && strcmp(csa->field, name) == 0) +      {  /* the same BOUNDS vector as in previous data record */ +         xassert(v != 0); +      } +      else +blnk: {  /* new BOUNDS vector */ +         if (v != 0) +            error(csa, "multiple BOUNDS vectors not supported\n"); +         v++; +         strcpy(name, csa->field); +      } +      /* field 3: column name */ +      read_field(csa), patch_name(csa, csa->field); +      if (csa->field[0] == '\0') +         error(csa, "missing column name in field 3\n"); +      j = glp_find_col(csa->P, csa->field); +      if (j == 0) +         error(csa, "column '%s' not found\n", csa->field); +      if ((flag[j] & mask) == 0x01) +         error(csa, "duplicate lower bound for column '%s'\n", +            csa->field); +      if ((flag[j] & mask) == 0x10) +         error(csa, "duplicate upper bound for column '%s'\n", +            csa->field); +      xassert((flag[j] & mask) == 0x00); +      /* field 4: bound value */ +      if (data) +      {  bnd = read_number(csa); +         if (fabs(bnd) < csa->parm->tol_mps) bnd = 0.0; +      } +      else +         read_field(csa), bnd = 0.0; +      /* get current column bounds */ +      col = csa->P->col[j]; +      if (col->type == GLP_FR) +         lb = -DBL_MAX, ub = +DBL_MAX; +      else if (col->type == GLP_LO) +         lb = col->lb, ub = +DBL_MAX; +      else if (col->type == GLP_UP) +         lb = -DBL_MAX, ub = col->ub; +      else if (col->type == GLP_DB) +         lb = col->lb, ub = col->ub; +      else if (col->type == GLP_FX) +         lb = ub = col->lb; +      else +         xassert(col != col); +      /* change column bounds */ +      if (strcmp(type, "LO") == 0) +         lb = bnd; +      else if (strcmp(type, "UP") == 0) +         ub = bnd; +      else if (strcmp(type, "FX") == 0) +         lb = ub = bnd; +      else if (strcmp(type, "FR") == 0) +         lb = -DBL_MAX, ub = +DBL_MAX; +      else if (strcmp(type, "MI") == 0) +         lb = -DBL_MAX; +      else if (strcmp(type, "PL") == 0) +         ub = +DBL_MAX; +      else if (strcmp(type, "LI") == 0) +      {  glp_set_col_kind(csa->P, j, GLP_IV); +         lb = ceil(bnd); +#if 1 /* 16/VII-2013 */ +         /* if column upper bound has not been explicitly specified, +            take it as +inf */ +         if (!(flag[j] & 0x10)) +            ub = +DBL_MAX; +#endif +      } +      else if (strcmp(type, "UI") == 0) +      {  glp_set_col_kind(csa->P, j, GLP_IV); +         ub = floor(bnd); +      } +      else if (strcmp(type, "BV") == 0) +      {  glp_set_col_kind(csa->P, j, GLP_IV); +         lb = 0.0, ub = 1.0; +      } +      else +         xassert(type != type); +      /* set new column bounds */ +      if (lb == -DBL_MAX && ub == +DBL_MAX) +         glp_set_col_bnds(csa->P, j, GLP_FR, lb, ub); +      else if (ub == +DBL_MAX) +         glp_set_col_bnds(csa->P, j, GLP_LO, lb, ub); +      else if (lb == -DBL_MAX) +         glp_set_col_bnds(csa->P, j, GLP_UP, lb, ub); +      else if (lb != ub) +         glp_set_col_bnds(csa->P, j, GLP_DB, lb, ub); +      else +         glp_set_col_bnds(csa->P, j, GLP_FX, lb, ub); +      flag[j] |= (char)mask; +      /* fields 5 and 6 must be blank */ +      skip_field(csa); +      skip_field(csa); +      goto loop; +done: /* free working array */ +      xfree(flag); +      csa->work3 = NULL; +      return; +} + +int glp_read_mps(glp_prob *P, int fmt, const glp_mpscp *parm, +      const char *fname) +{     /* read problem data in MPS format */ +      glp_mpscp _parm; +      struct csa _csa, *csa = &_csa; +      int ret; +      xprintf("Reading problem data from '%s'...\n", fname); +      if (!(fmt == GLP_MPS_DECK || fmt == GLP_MPS_FILE)) +         xerror("glp_read_mps: fmt = %d; invalid parameter\n", fmt); +      if (parm == NULL) +         glp_init_mpscp(&_parm), parm = &_parm; +      /* check control parameters */ +      check_parm("glp_read_mps", parm); +      /* initialize common storage area */ +      csa->P = P; +      csa->deck = (fmt == GLP_MPS_DECK); +      csa->parm = parm; +      csa->fname = fname; +      csa->fp = NULL; +      if (setjmp(csa->jump)) +      {  ret = 1; +         goto done; +      } +      csa->recno = csa->recpos = 0; +      csa->c = '\n'; +      csa->fldno = 0; +      csa->field[0] = '\0'; +      csa->w80 = csa->wef = 0; +      csa->obj_row = 0; +      csa->work1 = csa->work2 = csa->work3 = NULL; +      /* erase problem object */ +      glp_erase_prob(P); +      glp_create_index(P); +      /* open input MPS file */ +      csa->fp = glp_open(fname, "r"); +      if (csa->fp == NULL) +      {  xprintf("Unable to open '%s' - %s\n", fname, get_err_msg()); +         ret = 1; +         goto done; +      } +      /* read NAME indicator record */ +      read_name(csa); +      if (P->name != NULL) +         xprintf("Problem: %s\n", P->name); +      /* read ROWS section */ +      if (!(indicator(csa, 0) && strcmp(csa->field, "ROWS") == 0)) +         error(csa, "missing ROWS indicator record\n"); +      read_rows(csa); +      /* determine objective row */ +      if (parm->obj_name == NULL || parm->obj_name[0] == '\0') +      {  /* use the first row of N type */ +         int i; +         for (i = 1; i <= P->m; i++) +         {  if (P->row[i]->type == GLP_FR) +            {  csa->obj_row = i; +               break; +            } +         } +         if (csa->obj_row == 0) +            warning(csa, "unable to determine objective row\n"); +      } +      else +      {  /* use a row with specified name */ +         int i; +         for (i = 1; i <= P->m; i++) +         {  xassert(P->row[i]->name != NULL); +            if (strcmp(parm->obj_name, P->row[i]->name) == 0) +            {  csa->obj_row = i; +               break; +            } +         } +         if (csa->obj_row == 0) +            error(csa, "objective row '%s' not found\n", +               parm->obj_name); +      } +      if (csa->obj_row != 0) +      {  glp_set_obj_name(P, P->row[csa->obj_row]->name); +         xprintf("Objective: %s\n", P->obj); +      } +      /* read COLUMNS section */ +      if (strcmp(csa->field, "COLUMNS") != 0) +         error(csa, "missing COLUMNS indicator record\n"); +      read_columns(csa); +      /* set objective coefficients */ +      if (csa->obj_row != 0) +      {  GLPAIJ *aij; +         for (aij = P->row[csa->obj_row]->ptr; aij != NULL; aij = +            aij->r_next) glp_set_obj_coef(P, aij->col->j, aij->val); +      } +      /* read optional RHS section */ +      if (strcmp(csa->field, "RHS") == 0) +         read_rhs(csa); +      /* read optional RANGES section */ +      if (strcmp(csa->field, "RANGES") == 0) +         read_ranges(csa); +      /* read optional BOUNDS section */ +      if (strcmp(csa->field, "BOUNDS") == 0) +         read_bounds(csa); +      /* read ENDATA indicator record */ +      if (strcmp(csa->field, "ENDATA") != 0) +         error(csa, "invalid use of %s indicator record\n", +            csa->field); +      /* print some statistics */ +      xprintf("%d row%s, %d column%s, %d non-zero%s\n", +         P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s", +         P->nnz, P->nnz == 1 ? "" : "s"); +      if (glp_get_num_int(P) > 0) +      {  int ni = glp_get_num_int(P); +         int nb = glp_get_num_bin(P); +         if (ni == 1) +         {  if (nb == 0) +               xprintf("One variable is integer\n"); +            else +               xprintf("One variable is binary\n"); +         } +         else +         {  xprintf("%d integer variables, ", ni); +            if (nb == 0) +               xprintf("none"); +            else if (nb == 1) +               xprintf("one"); +            else if (nb == ni) +               xprintf("all"); +            else +               xprintf("%d", nb); +            xprintf(" of which %s binary\n", nb == 1 ? "is" : "are"); +         } +      } +      xprintf("%d records were read\n", csa->recno); +#if 1 /* 31/III-2016 */ +      /* free (unbounded) row(s) in MPS file are intended to specify +       * objective function(s), so all such rows can be removed */ +#if 1 /* 08/VIII-2013 */ +      /* remove free rows */ +      {  int i, nrs, *num; +         num = talloc(1+P->m, int); +         nrs = 0; +         for (i = 1; i <= P->m; i++) +         {  if (P->row[i]->type == GLP_FR) +               num[++nrs] = i; +         } +         if (nrs > 0) +         {  glp_del_rows(P, nrs, num); +            if (nrs == 1) +               xprintf("One free row was removed\n"); +            else +               xprintf("%d free rows were removed\n", nrs); +         } +         tfree(num); +      } +#endif +#else +      /* if objective function row is free, remove it */ +      if (csa->obj_row != 0 && P->row[csa->obj_row]->type == GLP_FR) +      {  int num[1+1]; +         num[1] = csa->obj_row; +         glp_del_rows(P, 1, num); +         xprintf("Free objective row was removed\n"); +      } +#endif +      /* problem data has been successfully read */ +      glp_delete_index(P); +      glp_sort_matrix(P); +      ret = 0; +done: if (csa->fp != NULL) glp_close(csa->fp); +      if (csa->work1 != NULL) xfree(csa->work1); +      if (csa->work2 != NULL) xfree(csa->work2); +      if (csa->work3 != NULL) xfree(csa->work3); +      if (ret != 0) glp_erase_prob(P); +      return ret; +} + +/*********************************************************************** +*  NAME +* +*  glp_write_mps - write problem data in MPS format +* +*  SYNOPSIS +* +*  int glp_write_mps(glp_prob *P, int fmt, const glp_mpscp *parm, +*     const char *fname); +* +*  DESCRIPTION +* +*  The routine glp_write_mps writes problem data in MPS format to a +*  text file. +* +*  The parameter fmt specifies the version of MPS format: +* +*  GLP_MPS_DECK - fixed (ancient) MPS format; +*  GLP_MPS_FILE - free (modern) MPS format. +* +*  The parameter parm is a pointer to the structure glp_mpscp, which +*  specifies control parameters used by the routine. If parm is NULL, +*  the routine uses default settings. +* +*  The character string fname specifies a name of the text file to be +*  written. +* +*  RETURNS +* +*  If the operation was successful, the routine glp_read_mps returns +*  zero. Otherwise, it prints an error message and returns non-zero. */ + +#define csa csa1 + +struct csa +{     /* common storage area */ +      glp_prob *P; +      /* pointer to problem object */ +      int deck; +      /* MPS format (0 - free, 1 - fixed) */ +      const glp_mpscp *parm; +      /* pointer to control parameters */ +      char field[255+1]; +      /* field buffer */ +}; + +static char *mps_name(struct csa *csa) +{     /* make problem name */ +      char *f; +      if (csa->P->name == NULL) +         csa->field[0] = '\0'; +      else if (csa->deck) +      {  strncpy(csa->field, csa->P->name, 8); +         csa->field[8] = '\0'; +      } +      else +         strcpy(csa->field, csa->P->name); +      for (f = csa->field; *f != '\0'; f++) +         if (*f == ' ') *f = '_'; +      return csa->field; +} + +static char *row_name(struct csa *csa, int i) +{     /* make i-th row name */ +      char *f; +      xassert(0 <= i && i <= csa->P->m); +      if (i == 0 || csa->P->row[i]->name == NULL || +          csa->deck && strlen(csa->P->row[i]->name) > 8) +         sprintf(csa->field, "R%07d", i); +      else +      {  strcpy(csa->field, csa->P->row[i]->name); +         for (f = csa->field; *f != '\0'; f++) +            if (*f == ' ') *f = '_'; +      } +      return csa->field; +} + +static char *col_name(struct csa *csa, int j) +{     /* make j-th column name */ +      char *f; +      xassert(1 <= j && j <= csa->P->n); +      if (csa->P->col[j]->name == NULL || +          csa->deck && strlen(csa->P->col[j]->name) > 8) +         sprintf(csa->field, "C%07d", j); +      else +      {  strcpy(csa->field, csa->P->col[j]->name); +         for (f = csa->field; *f != '\0'; f++) +            if (*f == ' ') *f = '_'; +      } +      return csa->field; +} + +static char *mps_numb(struct csa *csa, double val) +{     /* format floating-point number */ +      int dig; +      char *exp; +      for (dig = 12; dig >= 6; dig--) +      {  if (val != 0.0 && fabs(val) < 0.002) +            sprintf(csa->field, "%.*E", dig-1, val); +         else +            sprintf(csa->field, "%.*G", dig, val); +         exp = strchr(csa->field, 'E'); +         if (exp != NULL) +            sprintf(exp+1, "%d", atoi(exp+1)); +         if (strlen(csa->field) <= 12) break; +      } +      xassert(strlen(csa->field) <= 12); +      return csa->field; +} + +int glp_write_mps(glp_prob *P, int fmt, const glp_mpscp *parm, +      const char *fname) +{     /* write problem data in MPS format */ +      glp_mpscp _parm; +      struct csa _csa, *csa = &_csa; +      glp_file *fp; +      int out_obj, one_col = 0, empty = 0; +      int i, j, recno, marker, count, gap, ret; +      xprintf("Writing problem data to '%s'...\n", fname); +      if (!(fmt == GLP_MPS_DECK || fmt == GLP_MPS_FILE)) +         xerror("glp_write_mps: fmt = %d; invalid parameter\n", fmt); +      if (parm == NULL) +         glp_init_mpscp(&_parm), parm = &_parm; +      /* check control parameters */ +      check_parm("glp_write_mps", parm); +      /* initialize common storage area */ +      csa->P = P; +      csa->deck = (fmt == GLP_MPS_DECK); +      csa->parm = parm; +      /* create output MPS file */ +      fp = glp_open(fname, "w"), recno = 0; +      if (fp == NULL) +      {  xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); +         ret = 1; +         goto done; +      } +      /* write comment records */ +      xfprintf(fp, "* %-*s%s\n", P->name == NULL ? 1 : 12, "Problem:", +         P->name == NULL ? "" : P->name), recno++; +      xfprintf(fp, "* %-12s%s\n", "Class:", glp_get_num_int(P) == 0 ? +         "LP" : "MIP"), recno++; +      xfprintf(fp, "* %-12s%d\n", "Rows:", P->m), recno++; +      if (glp_get_num_int(P) == 0) +         xfprintf(fp, "* %-12s%d\n", "Columns:", P->n), recno++; +      else +         xfprintf(fp, "* %-12s%d (%d integer, %d binary)\n", +            "Columns:", P->n, glp_get_num_int(P), glp_get_num_bin(P)), +            recno++; +      xfprintf(fp, "* %-12s%d\n", "Non-zeros:", P->nnz), recno++; +      xfprintf(fp, "* %-12s%s\n", "Format:", csa->deck ? "Fixed MPS" : +         "Free MPS"), recno++; +      xfprintf(fp, "*\n", recno++); +      /* write NAME indicator record */ +      xfprintf(fp, "NAME%*s%s\n", +         P->name == NULL ? 0 : csa->deck ? 10 : 1, "", mps_name(csa)), +         recno++; +#if 1 +      /* determine whether to write the objective row */ +      out_obj = 1; +      for (i = 1; i <= P->m; i++) +      {  if (P->row[i]->type == GLP_FR) +         {  out_obj = 0; +            break; +         } +      } +#endif +      /* write ROWS section */ +      xfprintf(fp, "ROWS\n"), recno++; +      for (i = (out_obj ? 0 : 1); i <= P->m; i++) +      {  int type; +         type = (i == 0 ? GLP_FR : P->row[i]->type); +         if (type == GLP_FR) +            type = 'N'; +         else if (type == GLP_LO) +            type = 'G'; +         else if (type == GLP_UP) +            type = 'L'; +         else if (type == GLP_DB || type == GLP_FX) +            type = 'E'; +         else +            xassert(type != type); +         xfprintf(fp, " %c%*s%s\n", type, csa->deck ? 2 : 1, "", +            row_name(csa, i)), recno++; +      } +      /* write COLUMNS section */ +      xfprintf(fp, "COLUMNS\n"), recno++; +      marker = 0; +      for (j = 1; j <= P->n; j++) +      {  GLPAIJ cj, *aij; +         int kind; +         kind = P->col[j]->kind; +         if (kind == GLP_CV) +         {  if (marker % 2 == 1) +            {  /* close current integer block */ +               marker++; +               xfprintf(fp, "%*sM%07d%*s'MARKER'%*s'INTEND'\n", +                  csa->deck ? 4 : 1, "", marker, csa->deck ? 2 : 1, "", +                  csa->deck ? 17 : 1, ""), recno++; +            } +         } +         else if (kind == GLP_IV) +         {  if (marker % 2 == 0) +            {  /* open new integer block */ +               marker++; +               xfprintf(fp, "%*sM%07d%*s'MARKER'%*s'INTORG'\n", +                  csa->deck ? 4 : 1, "", marker, csa->deck ? 2 : 1, "", +                  csa->deck ? 17 : 1, ""), recno++; +            } +         } +         else +            xassert(kind != kind); +         if (out_obj && P->col[j]->coef != 0.0) +         {  /* make fake objective coefficient */ +            aij = &cj; +            aij->row = NULL; +            aij->val = P->col[j]->coef; +            aij->c_next = P->col[j]->ptr; +         } +         else +            aij = P->col[j]->ptr; +#if 1 /* FIXME */ +         if (aij == NULL) +         {  /* empty column */ +            empty++; +            xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "", +               csa->deck ? 8 : 1, col_name(csa, j)); +            /* we need a row */ +            xassert(P->m > 0); +            xfprintf(fp, "%*s%-*s", +               csa->deck ? 2 : 1, "", csa->deck ? 8 : 1, +               row_name(csa, 1)); +            xfprintf(fp, "%*s0%*s$ empty column\n", +               csa->deck ? 13 : 1, "", csa->deck ? 3 : 1, ""), recno++; +         } +#endif +         count = 0; +         for (aij = aij; aij != NULL; aij = aij->c_next) +         {  if (one_col || count % 2 == 0) +               xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "", +                  csa->deck ? 8 : 1, col_name(csa, j)); +            gap = (one_col || count % 2 == 0 ? 2 : 3); +            xfprintf(fp, "%*s%-*s", +               csa->deck ? gap : 1, "", csa->deck ? 8 : 1, +               row_name(csa, aij->row == NULL ? 0 : aij->row->i)); +            xfprintf(fp, "%*s%*s", +               csa->deck ? 2 : 1, "", csa->deck ? 12 : 1, +               mps_numb(csa, aij->val)), count++; +            if (one_col || count % 2 == 0) +               xfprintf(fp, "\n"), recno++; +         } +         if (!(one_col || count % 2 == 0)) +            xfprintf(fp, "\n"), recno++; +      } +      if (marker % 2 == 1) +      {  /* close last integer block */ +         marker++; +         xfprintf(fp, "%*sM%07d%*s'MARKER'%*s'INTEND'\n", +            csa->deck ? 4 : 1, "", marker, csa->deck ? 2 : 1, "", +            csa->deck ? 17 : 1, ""), recno++; +      } +#if 1 +      if (empty > 0) +         xprintf("Warning: problem has %d empty column(s)\n", empty); +#endif +      /* write RHS section */ +      xfprintf(fp, "RHS\n"), recno++; +      count = 0; +      for (i = (out_obj ? 0 : 1); i <= P->m; i++) +      {  int type; +         double rhs; +         if (i == 0) +            rhs = P->c0; +         else +         {  type = P->row[i]->type; +            if (type == GLP_FR) +               rhs = 0.0; +            else if (type == GLP_LO) +               rhs = P->row[i]->lb; +            else if (type == GLP_UP) +               rhs = P->row[i]->ub; +            else if (type == GLP_DB || type == GLP_FX) +               rhs = P->row[i]->lb; +            else +               xassert(type != type); +         } +         if (rhs != 0.0) +         {  if (one_col || count % 2 == 0) +               xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "", +                  csa->deck ? 8 : 1, "RHS1"); +            gap = (one_col || count % 2 == 0 ? 2 : 3); +            xfprintf(fp, "%*s%-*s", +               csa->deck ? gap : 1, "", csa->deck ? 8 : 1, +               row_name(csa, i)); +            xfprintf(fp, "%*s%*s", +               csa->deck ? 2 : 1, "", csa->deck ? 12 : 1, +               mps_numb(csa, rhs)), count++; +            if (one_col || count % 2 == 0) +               xfprintf(fp, "\n"), recno++; +         } +      } +      if (!(one_col || count % 2 == 0)) +         xfprintf(fp, "\n"), recno++; +      /* write RANGES section */ +      for (i = P->m; i >= 1; i--) +         if (P->row[i]->type == GLP_DB) break; +      if (i == 0) goto bnds; +      xfprintf(fp, "RANGES\n"), recno++; +      count = 0; +      for (i = 1; i <= P->m; i++) +      {  if (P->row[i]->type == GLP_DB) +         {  if (one_col || count % 2 == 0) +               xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "", +                  csa->deck ? 8 : 1, "RNG1"); +            gap = (one_col || count % 2 == 0 ? 2 : 3); +            xfprintf(fp, "%*s%-*s", +               csa->deck ? gap : 1, "", csa->deck ? 8 : 1, +               row_name(csa, i)); +            xfprintf(fp, "%*s%*s", +               csa->deck ? 2 : 1, "", csa->deck ? 12 : 1, +               mps_numb(csa, P->row[i]->ub - P->row[i]->lb)), count++; +            if (one_col || count % 2 == 0) +               xfprintf(fp, "\n"), recno++; +         } +      } +      if (!(one_col || count % 2 == 0)) +         xfprintf(fp, "\n"), recno++; +bnds: /* write BOUNDS section */ +      for (j = P->n; j >= 1; j--) +         if (!(P->col[j]->kind == GLP_CV && +               P->col[j]->type == GLP_LO && P->col[j]->lb == 0.0)) +            break; +      if (j == 0) goto endt; +      xfprintf(fp, "BOUNDS\n"), recno++; +      for (j = 1; j <= P->n; j++) +      {  int type, data[2]; +         double bnd[2]; +         char *spec[2]; +         spec[0] = spec[1] = NULL; +         type = P->col[j]->type; +         if (type == GLP_FR) +            spec[0] = "FR", data[0] = 0; +         else if (type == GLP_LO) +         {  if (P->col[j]->lb != 0.0) +               spec[0] = "LO", data[0] = 1, bnd[0] = P->col[j]->lb; +            if (P->col[j]->kind == GLP_IV) +               spec[1] = "PL", data[1] = 0; +         } +         else if (type == GLP_UP) +         {  spec[0] = "MI", data[0] = 0; +            spec[1] = "UP", data[1] = 1, bnd[1] = P->col[j]->ub; +         } +         else if (type == GLP_DB) +         {  if (P->col[j]->lb != 0.0) +               spec[0] = "LO", data[0] = 1, bnd[0] = P->col[j]->lb; +            spec[1] = "UP", data[1] = 1, bnd[1] = P->col[j]->ub; +         } +         else if (type == GLP_FX) +            spec[0] = "FX", data[0] = 1, bnd[0] = P->col[j]->lb; +         else +            xassert(type != type); +         for (i = 0; i <= 1; i++) +         {  if (spec[i] != NULL) +            {  xfprintf(fp, " %s %-*s%*s%-*s", spec[i], +                  csa->deck ? 8 : 1, "BND1", csa->deck ? 2 : 1, "", +                  csa->deck ? 8 : 1, col_name(csa, j)); +               if (data[i]) +                  xfprintf(fp, "%*s%*s", csa->deck ? 2 : 1, "", +                     csa->deck ? 12 : 1, mps_numb(csa, bnd[i])); +               xfprintf(fp, "\n"), recno++; +            } +         } +      } +endt: /* write ENDATA indicator record */ +      xfprintf(fp, "ENDATA\n"), recno++; +#if 0 /* FIXME */ +      xfflush(fp); +#endif +      if (glp_ioerr(fp)) +      {  xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); +         ret = 1; +         goto done; +      } +      /* problem data has been successfully written */ +      xprintf("%d records were written\n", recno); +      ret = 0; +done: if (fp != NULL) glp_close(fp); +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/netgen.c b/glpk-5.0/src/api/netgen.c new file mode 100644 index 0000000..ec556ad --- /dev/null +++ b/glpk-5.0/src/api/netgen.c @@ -0,0 +1,20 @@ +/* netgen.c */ + +#include "env.h" +#include "glpk.h" + +int glp_netgen(glp_graph *G_, int v_rhs_, int a_cap_, int a_cost_, +      const int parm[1+15]) +{     static const char func[] = "glp_netgen"; +      xassert(G_ == G_); +      xassert(v_rhs_ == v_rhs_); +      xassert(a_cap_ == a_cap_); +      xassert(a_cost_ == a_cost_); +      xassert(parm == parm); +      xerror("%s: sorry, this routine is temporarily disabled due to li" +         "censing problems\n", func); +      abort(); +      return -1; +} + +/* eof */ diff --git a/glpk-5.0/src/api/npp.c b/glpk-5.0/src/api/npp.c new file mode 100644 index 0000000..ec7be18 --- /dev/null +++ b/glpk-5.0/src/api/npp.c @@ -0,0 +1,141 @@ +/* npp.c (LP/MIP preprocessing) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2017 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "npp.h" + +glp_prep *glp_npp_alloc_wksp(void) +{     /* allocate the preprocessor workspace */ +      glp_prep *prep; +      prep = npp_create_wksp(); +      return prep; +} + +void glp_npp_load_prob(glp_prep *prep, glp_prob *P, int sol, int names) +{     /* load original problem instance */ +      if (prep->sol != 0) +         xerror("glp_npp_load_prob: invalid call sequence (original ins" +            "tance already loaded)\n"); +      if (!(sol == GLP_SOL || sol == GLP_IPT || sol == GLP_MIP)) +         xerror("glp_npp_load_prob: sol = %d; invalid parameter\n", +            sol); +      if (!(names == GLP_ON || names == GLP_OFF)) +         xerror("glp_npp_load_prob: names = %d; invalid parameter\n", +            names); +      npp_load_prob(prep, P, names, sol, GLP_OFF); +      return; +} + +int glp_npp_preprocess1(glp_prep *prep, int hard) +{     /* perform basic LP/MIP preprocessing */ +      if (prep->sol == 0) +         xerror("glp_npp_preprocess1: invalid call sequence (original i" +            "nstance not loaded yet)\n"); +      if (prep->pool == NULL) +         xerror("glp_npp_preprocess1: invalid call sequence (preprocess" +            "ing already finished)\n"); +      if (!(hard == GLP_ON || hard == GLP_OFF)) +         xerror("glp_npp_preprocess1: hard = %d; invalid parameter\n", +            hard); +      return npp_process_prob(prep, hard); +} + +void glp_npp_build_prob(glp_prep *prep, glp_prob *Q) +{     /* build resultant problem instance */ +      if (prep->sol == 0) +         xerror("glp_npp_build_prob: invalid call sequence (original in" +            "stance not loaded yet)\n"); +      if (prep->pool == NULL) +         xerror("glp_npp_build_prob: invalid call sequence (resultant i" +            "nstance already built)\n"); +      npp_build_prob(prep, Q); +      return; +} + +void glp_npp_postprocess(glp_prep *prep, glp_prob *Q) +{     /* postprocess solution to resultant problem */ +      if (prep->pool != NULL) +         xerror("glp_npp_postprocess: invalid call sequence (resultant " +            "instance not built yet)\n"); +      if (!(prep->m == Q->m && prep->n == Q->n && prep->nnz == Q->nnz)) +         xerror("glp_npp_postprocess: resultant instance mismatch\n"); +      switch (prep->sol) +      {  case GLP_SOL: +            if (glp_get_status(Q) != GLP_OPT) +               xerror("glp_npp_postprocess: unable to recover non-optim" +                  "al basic solution\n"); +            break; +         case GLP_IPT: +            if (glp_ipt_status(Q) != GLP_OPT) +               xerror("glp_npp_postprocess: unable to recover non-optim" +                  "al interior-point solution\n"); +            break; +         case GLP_MIP: +            if (!(glp_mip_status(Q) == GLP_OPT || glp_mip_status(Q) == +               GLP_FEAS)) +               xerror("glp_npp_postprocess: unable to recover integer n" +                  "on-feasible solution\n"); +            break; +         default: +            xassert(prep != prep); +      } +      npp_postprocess(prep, Q); +      return; +} + +void glp_npp_obtain_sol(glp_prep *prep, glp_prob *P) +{     /* obtain solution to original problem */ +      if (prep->pool != NULL) +         xerror("glp_npp_obtain_sol: invalid call sequence (resultant i" +            "nstance not built yet)\n"); +      switch (prep->sol) +      {  case GLP_SOL: +            if (prep->p_stat == 0 || prep->d_stat == 0) +               xerror("glp_npp_obtain_sol: invalid call sequence (basic" +                  " solution not provided yet)\n"); +            break; +         case GLP_IPT: +            if (prep->t_stat == 0) +               xerror("glp_npp_obtain_sol: invalid call sequence (inter" +                  "ior-point solution not provided yet)\n"); +            break; +         case GLP_MIP: +            if (prep->i_stat == 0) +               xerror("glp_npp_obtain_sol: invalid call sequence (MIP s" +                  "olution not provided yet)\n"); +            break; +         default: +            xassert(prep != prep); +      } +      if (!(prep->orig_dir == P->dir && prep->orig_m == P->m && +            prep->orig_n == P->n && prep->orig_nnz == P->nnz)) +         xerror("glp_npp_obtain_sol: original instance mismatch\n"); +      npp_unload_sol(prep, P); +      return; +} + +void glp_npp_free_wksp(glp_prep *prep) +{     /* free the preprocessor workspace */ +      npp_delete_wksp(prep); +      return; +} + +/* eof */ diff --git a/glpk-5.0/src/api/pript.c b/glpk-5.0/src/api/pript.c new file mode 100644 index 0000000..968236b --- /dev/null +++ b/glpk-5.0/src/api/pript.c @@ -0,0 +1,184 @@ +/* pript.c (write interior-point solution in printable format) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +#define xfprintf glp_format + +int glp_print_ipt(glp_prob *P, const char *fname) +{     /* write interior-point solution in printable format */ +      glp_file *fp; +      GLPROW *row; +      GLPCOL *col; +      int i, j, t, ae_ind, re_ind, ret; +      double ae_max, re_max; +      xprintf("Writing interior-point solution to '%s'...\n", fname); +      fp = glp_open(fname, "w"); +      if (fp == NULL) +      {  xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); +         ret = 1; +         goto done; +      } +      xfprintf(fp, "%-12s%s\n", "Problem:", +         P->name == NULL ? "" : P->name); +      xfprintf(fp, "%-12s%d\n", "Rows:", P->m); +      xfprintf(fp, "%-12s%d\n", "Columns:", P->n); +      xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz); +      t = glp_ipt_status(P); +      xfprintf(fp, "%-12s%s\n", "Status:", +         t == GLP_OPT    ? "OPTIMAL" : +         t == GLP_UNDEF  ? "UNDEFINED" : +         t == GLP_INFEAS ? "INFEASIBLE (INTERMEDIATE)" : +         t == GLP_NOFEAS ? "INFEASIBLE (FINAL)" : "???"); +      xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:", +         P->obj == NULL ? "" : P->obj, +         P->obj == NULL ? "" : " = ", P->ipt_obj, +         P->dir == GLP_MIN ? "MINimum" : +         P->dir == GLP_MAX ? "MAXimum" : "???"); +      xfprintf(fp, "\n"); +      xfprintf(fp, "   No.   Row name        Activity     Lower bound  " +         " Upper bound    Marginal\n"); +      xfprintf(fp, "------ ------------    ------------- ------------- " +         "------------- -------------\n"); +      for (i = 1; i <= P->m; i++) +      {  row = P->row[i]; +         xfprintf(fp, "%6d ", i); +         if (row->name == NULL || strlen(row->name) <= 12) +            xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name); +         else +            xfprintf(fp, "%s\n%20s", row->name, ""); +         xfprintf(fp, "%3s", ""); +         xfprintf(fp, "%13.6g ", +            fabs(row->pval) <= 1e-9 ? 0.0 : row->pval); +         if (row->type == GLP_LO || row->type == GLP_DB || +             row->type == GLP_FX) +            xfprintf(fp, "%13.6g ", row->lb); +         else +            xfprintf(fp, "%13s ", ""); +         if (row->type == GLP_UP || row->type == GLP_DB) +            xfprintf(fp, "%13.6g ", row->ub); +         else +            xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : ""); +         if (fabs(row->dval) <= 1e-9) +            xfprintf(fp, "%13s", "< eps"); +         else +            xfprintf(fp, "%13.6g ", row->dval); +         xfprintf(fp, "\n"); +      } +      xfprintf(fp, "\n"); +      xfprintf(fp, "   No. Column name       Activity     Lower bound  " +         " Upper bound    Marginal\n"); +      xfprintf(fp, "------ ------------    ------------- ------------- " +         "------------- -------------\n"); +      for (j = 1; j <= P->n; j++) +      {  col = P->col[j]; +         xfprintf(fp, "%6d ", j); +         if (col->name == NULL || strlen(col->name) <= 12) +            xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name); +         else +            xfprintf(fp, "%s\n%20s", col->name, ""); +         xfprintf(fp, "%3s", ""); +         xfprintf(fp, "%13.6g ", +            fabs(col->pval) <= 1e-9 ? 0.0 : col->pval); +         if (col->type == GLP_LO || col->type == GLP_DB || +             col->type == GLP_FX) +            xfprintf(fp, "%13.6g ", col->lb); +         else +            xfprintf(fp, "%13s ", ""); +         if (col->type == GLP_UP || col->type == GLP_DB) +            xfprintf(fp, "%13.6g ", col->ub); +         else +            xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : ""); +         if (fabs(col->dval) <= 1e-9) +            xfprintf(fp, "%13s", "< eps"); +         else +            xfprintf(fp, "%13.6g ", col->dval); +         xfprintf(fp, "\n"); +      } +      xfprintf(fp, "\n"); +      xfprintf(fp, "Karush-Kuhn-Tucker optimality conditions:\n"); +      xfprintf(fp, "\n"); +      glp_check_kkt(P, GLP_IPT, GLP_KKT_PE, &ae_max, &ae_ind, &re_max, +         &re_ind); +      xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n", +         ae_max, ae_ind); +      xfprintf(fp, "        max.rel.err = %.2e on row %d\n", +         re_max, re_ind); +      xfprintf(fp, "%8s%s\n", "", +         re_max <= 1e-9 ? "High quality" : +         re_max <= 1e-6 ? "Medium quality" : +         re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS WRONG"); +      xfprintf(fp, "\n"); +      glp_check_kkt(P, GLP_IPT, GLP_KKT_PB, &ae_max, &ae_ind, &re_max, +         &re_ind); +      xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n", +            ae_max, ae_ind <= P->m ? "row" : "column", +            ae_ind <= P->m ? ae_ind : ae_ind - P->m); +      xfprintf(fp, "        max.rel.err = %.2e on %s %d\n", +            re_max, re_ind <= P->m ? "row" : "column", +            re_ind <= P->m ? re_ind : re_ind - P->m); +      xfprintf(fp, "%8s%s\n", "", +         re_max <= 1e-9 ? "High quality" : +         re_max <= 1e-6 ? "Medium quality" : +         re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS INFEASIBL" +            "E"); +      xfprintf(fp, "\n"); +      glp_check_kkt(P, GLP_IPT, GLP_KKT_DE, &ae_max, &ae_ind, &re_max, +         &re_ind); +      xfprintf(fp, "KKT.DE: max.abs.err = %.2e on column %d\n", +         ae_max, ae_ind == 0 ? 0 : ae_ind - P->m); +      xfprintf(fp, "        max.rel.err = %.2e on column %d\n", +         re_max, re_ind == 0 ? 0 : re_ind - P->m); +      xfprintf(fp, "%8s%s\n", "", +         re_max <= 1e-9 ? "High quality" : +         re_max <= 1e-6 ? "Medium quality" : +         re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS WRONG"); +      xfprintf(fp, "\n"); +      glp_check_kkt(P, GLP_IPT, GLP_KKT_DB, &ae_max, &ae_ind, &re_max, +         &re_ind); +      xfprintf(fp, "KKT.DB: max.abs.err = %.2e on %s %d\n", +            ae_max, ae_ind <= P->m ? "row" : "column", +            ae_ind <= P->m ? ae_ind : ae_ind - P->m); +      xfprintf(fp, "        max.rel.err = %.2e on %s %d\n", +            re_max, re_ind <= P->m ? "row" : "column", +            re_ind <= P->m ? re_ind : re_ind - P->m); +      xfprintf(fp, "%8s%s\n", "", +         re_max <= 1e-9 ? "High quality" : +         re_max <= 1e-6 ? "Medium quality" : +         re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS INFEASIBLE") +            ; +      xfprintf(fp, "\n"); +      xfprintf(fp, "End of output\n"); +#if 0 /* FIXME */ +      xfflush(fp); +#endif +      if (glp_ioerr(fp)) +      {  xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); +         ret = 1; +         goto done; +      } +      ret = 0; +done: if (fp != NULL) glp_close(fp); +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/prmip.c b/glpk-5.0/src/api/prmip.c new file mode 100644 index 0000000..81d52c8 --- /dev/null +++ b/glpk-5.0/src/api/prmip.c @@ -0,0 +1,153 @@ +/* prmip.c (write MIP solution in printable format) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +#define xfprintf glp_format + +int glp_print_mip(glp_prob *P, const char *fname) +{     /* write MIP solution in printable format */ +      glp_file *fp; +      GLPROW *row; +      GLPCOL *col; +      int i, j, t, ae_ind, re_ind, ret; +      double ae_max, re_max; +      xprintf("Writing MIP solution to '%s'...\n", fname); +      fp = glp_open(fname, "w"); +      if (fp == NULL) +      {  xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); +         ret = 1; +         goto done; +      } +      xfprintf(fp, "%-12s%s\n", "Problem:", +         P->name == NULL ? "" : P->name); +      xfprintf(fp, "%-12s%d\n", "Rows:", P->m); +      xfprintf(fp, "%-12s%d (%d integer, %d binary)\n", "Columns:", +         P->n, glp_get_num_int(P), glp_get_num_bin(P)); +      xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz); +      t = glp_mip_status(P); +      xfprintf(fp, "%-12s%s\n", "Status:", +         t == GLP_OPT    ? "INTEGER OPTIMAL" : +         t == GLP_FEAS   ? "INTEGER NON-OPTIMAL" : +         t == GLP_NOFEAS ? "INTEGER EMPTY" : +         t == GLP_UNDEF  ? "INTEGER UNDEFINED" : "???"); +      xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:", +         P->obj == NULL ? "" : P->obj, +         P->obj == NULL ? "" : " = ", P->mip_obj, +         P->dir == GLP_MIN ? "MINimum" : +         P->dir == GLP_MAX ? "MAXimum" : "???"); +      xfprintf(fp, "\n"); +      xfprintf(fp, "   No.   Row name        Activity     Lower bound  " +         " Upper bound\n"); +      xfprintf(fp, "------ ------------    ------------- ------------- " +         "-------------\n"); +      for (i = 1; i <= P->m; i++) +      {  row = P->row[i]; +         xfprintf(fp, "%6d ", i); +         if (row->name == NULL || strlen(row->name) <= 12) +            xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name); +         else +            xfprintf(fp, "%s\n%20s", row->name, ""); +         xfprintf(fp, "%3s", ""); +         xfprintf(fp, "%13.6g ", +            fabs(row->mipx) <= 1e-9 ? 0.0 : row->mipx); +         if (row->type == GLP_LO || row->type == GLP_DB || +             row->type == GLP_FX) +            xfprintf(fp, "%13.6g ", row->lb); +         else +            xfprintf(fp, "%13s ", ""); +         if (row->type == GLP_UP || row->type == GLP_DB) +            xfprintf(fp, "%13.6g ", row->ub); +         else +            xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : ""); +         xfprintf(fp, "\n"); +      } +      xfprintf(fp, "\n"); +      xfprintf(fp, "   No. Column name       Activity     Lower bound  " +         " Upper bound\n"); +      xfprintf(fp, "------ ------------    ------------- ------------- " +         "-------------\n"); +      for (j = 1; j <= P->n; j++) +      {  col = P->col[j]; +         xfprintf(fp, "%6d ", j); +         if (col->name == NULL || strlen(col->name) <= 12) +            xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name); +         else +            xfprintf(fp, "%s\n%20s", col->name, ""); +         xfprintf(fp, "%s  ", +            col->kind == GLP_CV ? " " : +            col->kind == GLP_IV ? "*" : "?"); +         xfprintf(fp, "%13.6g ", +            fabs(col->mipx) <= 1e-9 ? 0.0 : col->mipx); +         if (col->type == GLP_LO || col->type == GLP_DB || +             col->type == GLP_FX) +            xfprintf(fp, "%13.6g ", col->lb); +         else +            xfprintf(fp, "%13s ", ""); +         if (col->type == GLP_UP || col->type == GLP_DB) +            xfprintf(fp, "%13.6g ", col->ub); +         else +            xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : ""); +         xfprintf(fp, "\n"); +      } +      xfprintf(fp, "\n"); +      xfprintf(fp, "Integer feasibility conditions:\n"); +      xfprintf(fp, "\n"); +      glp_check_kkt(P, GLP_MIP, GLP_KKT_PE, &ae_max, &ae_ind, &re_max, +         &re_ind); +      xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n", +         ae_max, ae_ind); +      xfprintf(fp, "        max.rel.err = %.2e on row %d\n", +         re_max, re_ind); +      xfprintf(fp, "%8s%s\n", "", +         re_max <= 1e-9 ? "High quality" : +         re_max <= 1e-6 ? "Medium quality" : +         re_max <= 1e-3 ? "Low quality" : "SOLUTION IS WRONG"); +      xfprintf(fp, "\n"); +      glp_check_kkt(P, GLP_MIP, GLP_KKT_PB, &ae_max, &ae_ind, &re_max, +         &re_ind); +      xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n", +            ae_max, ae_ind <= P->m ? "row" : "column", +            ae_ind <= P->m ? ae_ind : ae_ind - P->m); +      xfprintf(fp, "        max.rel.err = %.2e on %s %d\n", +            re_max, re_ind <= P->m ? "row" : "column", +            re_ind <= P->m ? re_ind : re_ind - P->m); +      xfprintf(fp, "%8s%s\n", "", +         re_max <= 1e-9 ? "High quality" : +         re_max <= 1e-6 ? "Medium quality" : +         re_max <= 1e-3 ? "Low quality" : "SOLUTION IS INFEASIBLE"); +      xfprintf(fp, "\n"); +      xfprintf(fp, "End of output\n"); +#if 0 /* FIXME */ +      xfflush(fp); +#endif +      if (glp_ioerr(fp)) +      {  xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); +         ret = 1; +         goto done; +      } +      ret = 0; +done: if (fp != NULL) glp_close(fp); +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/prob.h b/glpk-5.0/src/api/prob.h new file mode 100644 index 0000000..9a20fd9 --- /dev/null +++ b/glpk-5.0/src/api/prob.h @@ -0,0 +1,284 @@ +/* prob.h (LP/MIP problem object) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2000-2013 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#ifndef PROB_H +#define PROB_H + +#include "avl.h" +#include "bfd.h" +#include "dmp.h" +#if 1 /* 28/III-2016 */ +#define GLP_UNDOC 1 +#endif +#include "glpk.h" + +typedef struct GLPROW GLPROW; +typedef struct GLPCOL GLPCOL; +typedef struct GLPAIJ GLPAIJ; + +#if 0 /* 04/IV-2016 */ +#define GLP_PROB_MAGIC 0xD7D9D6C2 +#endif + +struct glp_prob +{     /* LP/MIP problem object */ +#if 0 /* 04/IV-2016 */ +      unsigned magic; +      /* magic value used for debugging */ +#endif +      DMP *pool; +      /* memory pool to store problem object components */ +      glp_tree *tree; +      /* pointer to the search tree; set by the MIP solver when this +         object is used in the tree as a core MIP object */ +#if 0 /* 08/III-2014 */ +      void *parms; +      /* reserved for backward compatibility */ +#endif +      /*--------------------------------------------------------------*/ +      /* LP/MIP data */ +      char *name; +      /* problem name (1 to 255 chars); NULL means no name is assigned +         to the problem */ +      char *obj; +      /* objective function name (1 to 255 chars); NULL means no name +         is assigned to the objective function */ +      int dir; +      /* optimization direction flag (objective "sense"): +         GLP_MIN - minimization +         GLP_MAX - maximization */ +      double c0; +      /* constant term of the objective function ("shift") */ +      int m_max; +      /* length of the array of rows (enlarged automatically) */ +      int n_max; +      /* length of the array of columns (enlarged automatically) */ +      int m; +      /* number of rows, 0 <= m <= m_max */ +      int n; +      /* number of columns, 0 <= n <= n_max */ +      int nnz; +      /* number of non-zero constraint coefficients, nnz >= 0 */ +      GLPROW **row; /* GLPROW *row[1+m_max]; */ +      /* row[i], 1 <= i <= m, is a pointer to i-th row */ +      GLPCOL **col; /* GLPCOL *col[1+n_max]; */ +      /* col[j], 1 <= j <= n, is a pointer to j-th column */ +      AVL *r_tree; +      /* row index to find rows by their names; NULL means this index +         does not exist */ +      AVL *c_tree; +      /* column index to find columns by their names; NULL means this +         index does not exist */ +      /*--------------------------------------------------------------*/ +      /* basis factorization (LP) */ +      int valid; +      /* the factorization is valid only if this flag is set */ +      int *head; /* int head[1+m_max]; */ +      /* basis header (valid only if the factorization is valid); +         head[i] = k is the ordinal number of auxiliary (1 <= k <= m) +         or structural (m+1 <= k <= m+n) variable which corresponds to +         i-th basic variable xB[i], 1 <= i <= m */ +#if 0 /* 08/III-2014 */ +      glp_bfcp *bfcp; +      /* basis factorization control parameters; may be NULL */ +#endif +      BFD *bfd; /* BFD bfd[1:m,1:m]; */ +      /* basis factorization driver; may be NULL */ +      /*--------------------------------------------------------------*/ +      /* basic solution (LP) */ +      int pbs_stat; +      /* primal basic solution status: +         GLP_UNDEF  - primal solution is undefined +         GLP_FEAS   - primal solution is feasible +         GLP_INFEAS - primal solution is infeasible +         GLP_NOFEAS - no primal feasible solution exists */ +      int dbs_stat; +      /* dual basic solution status: +         GLP_UNDEF  - dual solution is undefined +         GLP_FEAS   - dual solution is feasible +         GLP_INFEAS - dual solution is infeasible +         GLP_NOFEAS - no dual feasible solution exists */ +      double obj_val; +      /* objective function value */ +      int it_cnt; +      /* simplex method iteration count; increases by one on performing +         one simplex iteration */ +      int some; +      /* ordinal number of some auxiliary or structural variable having +         certain property, 0 <= some <= m+n */ +      /*--------------------------------------------------------------*/ +      /* interior-point solution (LP) */ +      int ipt_stat; +      /* interior-point solution status: +         GLP_UNDEF  - interior solution is undefined +         GLP_OPT    - interior solution is optimal +         GLP_INFEAS - interior solution is infeasible +         GLP_NOFEAS - no feasible solution exists */ +      double ipt_obj; +      /* objective function value */ +      /*--------------------------------------------------------------*/ +      /* integer solution (MIP) */ +      int mip_stat; +      /* integer solution status: +         GLP_UNDEF  - integer solution is undefined +         GLP_OPT    - integer solution is optimal +         GLP_FEAS   - integer solution is feasible +         GLP_NOFEAS - no integer solution exists */ +      double mip_obj; +      /* objective function value */ +}; + +struct GLPROW +{     /* LP/MIP row (auxiliary variable) */ +      int i; +      /* ordinal number (1 to m) assigned to this row */ +      char *name; +      /* row name (1 to 255 chars); NULL means no name is assigned to +         this row */ +      AVLNODE *node; +      /* pointer to corresponding node in the row index; NULL means +         that either the row index does not exist or this row has no +         name assigned */ +#if 1 /* 20/IX-2008 */ +      int level; +      unsigned char origin; +      unsigned char klass; +#endif +      int type; +      /* type of the auxiliary variable: +         GLP_FR - free variable +         GLP_LO - variable with lower bound +         GLP_UP - variable with upper bound +         GLP_DB - double-bounded variable +         GLP_FX - fixed variable */ +      double lb; /* non-scaled */ +      /* lower bound; if the row has no lower bound, lb is zero */ +      double ub; /* non-scaled */ +      /* upper bound; if the row has no upper bound, ub is zero */ +      /* if the row type is GLP_FX, ub is equal to lb */ +      GLPAIJ *ptr; /* non-scaled */ +      /* pointer to doubly linked list of constraint coefficients which +         are placed in this row */ +      double rii; +      /* diagonal element r[i,i] of scaling matrix R for this row; +         if the scaling is not used, r[i,i] is 1 */ +      int stat; +      /* status of the auxiliary variable: +         GLP_BS - basic variable +         GLP_NL - non-basic variable on lower bound +         GLP_NU - non-basic variable on upper bound +         GLP_NF - non-basic free variable +         GLP_NS - non-basic fixed variable */ +      int bind; +      /* if the auxiliary variable is basic, head[bind] refers to this +         row, otherwise, bind is 0; this attribute is valid only if the +         basis factorization is valid */ +      double prim; /* non-scaled */ +      /* primal value of the auxiliary variable in basic solution */ +      double dual; /* non-scaled */ +      /* dual value of the auxiliary variable in basic solution */ +      double pval; /* non-scaled */ +      /* primal value of the auxiliary variable in interior solution */ +      double dval; /* non-scaled */ +      /* dual value of the auxiliary variable in interior solution */ +      double mipx; /* non-scaled */ +      /* primal value of the auxiliary variable in integer solution */ +}; + +struct GLPCOL +{     /* LP/MIP column (structural variable) */ +      int j; +      /* ordinal number (1 to n) assigned to this column */ +      char *name; +      /* column name (1 to 255 chars); NULL means no name is assigned +         to this column */ +      AVLNODE *node; +      /* pointer to corresponding node in the column index; NULL means +         that either the column index does not exist or the column has +         no name assigned */ +      int kind; +      /* kind of the structural variable: +         GLP_CV - continuous variable +         GLP_IV - integer or binary variable */ +      int type; +      /* type of the structural variable: +         GLP_FR - free variable +         GLP_LO - variable with lower bound +         GLP_UP - variable with upper bound +         GLP_DB - double-bounded variable +         GLP_FX - fixed variable */ +      double lb; /* non-scaled */ +      /* lower bound; if the column has no lower bound, lb is zero */ +      double ub; /* non-scaled */ +      /* upper bound; if the column has no upper bound, ub is zero */ +      /* if the column type is GLP_FX, ub is equal to lb */ +      double coef; /* non-scaled */ +      /* objective coefficient at the structural variable */ +      GLPAIJ *ptr; /* non-scaled */ +      /* pointer to doubly linked list of constraint coefficients which +         are placed in this column */ +      double sjj; +      /* diagonal element s[j,j] of scaling matrix S for this column; +         if the scaling is not used, s[j,j] is 1 */ +      int stat; +      /* status of the structural variable: +         GLP_BS - basic variable +         GLP_NL - non-basic variable on lower bound +         GLP_NU - non-basic variable on upper bound +         GLP_NF - non-basic free variable +         GLP_NS - non-basic fixed variable */ +      int bind; +      /* if the structural variable is basic, head[bind] refers to +         this column; otherwise, bind is 0; this attribute is valid only +         if the basis factorization is valid */ +      double prim; /* non-scaled */ +      /* primal value of the structural variable in basic solution */ +      double dual; /* non-scaled */ +      /* dual value of the structural variable in basic solution */ +      double pval; /* non-scaled */ +      /* primal value of the structural variable in interior solution */ +      double dval; /* non-scaled */ +      /* dual value of the structural variable in interior solution */ +      double mipx; /* non-scaled */ +      /* primal value of the structural variable in integer solution */ +}; + +struct GLPAIJ +{     /* constraint coefficient a[i,j] */ +      GLPROW *row; +      /* pointer to row, where this coefficient is placed */ +      GLPCOL *col; +      /* pointer to column, where this coefficient is placed */ +      double val; +      /* numeric (non-zero) value of this coefficient */ +      GLPAIJ *r_prev; +      /* pointer to previous coefficient in the same row */ +      GLPAIJ *r_next; +      /* pointer to next coefficient in the same row */ +      GLPAIJ *c_prev; +      /* pointer to previous coefficient in the same column */ +      GLPAIJ *c_next; +      /* pointer to next coefficient in the same column */ +}; + +#endif + +/* eof */ diff --git a/glpk-5.0/src/api/prob1.c b/glpk-5.0/src/api/prob1.c new file mode 100644 index 0000000..5fe1ab7 --- /dev/null +++ b/glpk-5.0/src/api/prob1.c @@ -0,0 +1,1586 @@ +/* prob1.c (problem creating and modifying routines) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2000-2018 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "ios.h" + +/* CAUTION: DO NOT CHANGE THE LIMITS BELOW */ + +#define M_MAX 100000000 /* = 100*10^6 */ +/* maximal number of rows in the problem object */ + +#define N_MAX 100000000 /* = 100*10^6 */ +/* maximal number of columns in the problem object */ + +#define NNZ_MAX 500000000 /* = 500*10^6 */ +/* maximal number of constraint coefficients in the problem object */ + +/*********************************************************************** +*  NAME +* +*  glp_create_prob - create problem object +* +*  SYNOPSIS +* +*  glp_prob *glp_create_prob(void); +* +*  DESCRIPTION +* +*  The routine glp_create_prob creates a new problem object, which is +*  initially "empty", i.e. has no rows and columns. +* +*  RETURNS +* +*  The routine returns a pointer to the object created, which should be +*  used in any subsequent operations on this object. */ + +static void create_prob(glp_prob *lp) +#if 0 /* 04/IV-2016 */ +{     lp->magic = GLP_PROB_MAGIC; +#else +{ +#endif +      lp->pool = dmp_create_pool(); +#if 0 /* 08/III-2014 */ +#if 0 /* 17/XI-2009 */ +      lp->cps = xmalloc(sizeof(struct LPXCPS)); +      lpx_reset_parms(lp); +#else +      lp->parms = NULL; +#endif +#endif +      lp->tree = NULL; +#if 0 +      lp->lwa = 0; +      lp->cwa = NULL; +#endif +      /* LP/MIP data */ +      lp->name = NULL; +      lp->obj = NULL; +      lp->dir = GLP_MIN; +      lp->c0 = 0.0; +      lp->m_max = 100; +      lp->n_max = 200; +      lp->m = lp->n = 0; +      lp->nnz = 0; +      lp->row = xcalloc(1+lp->m_max, sizeof(GLPROW *)); +      lp->col = xcalloc(1+lp->n_max, sizeof(GLPCOL *)); +      lp->r_tree = lp->c_tree = NULL; +      /* basis factorization */ +      lp->valid = 0; +      lp->head = xcalloc(1+lp->m_max, sizeof(int)); +#if 0 /* 08/III-2014 */ +      lp->bfcp = NULL; +#endif +      lp->bfd = NULL; +      /* basic solution (LP) */ +      lp->pbs_stat = lp->dbs_stat = GLP_UNDEF; +      lp->obj_val = 0.0; +      lp->it_cnt = 0; +      lp->some = 0; +      /* interior-point solution (LP) */ +      lp->ipt_stat = GLP_UNDEF; +      lp->ipt_obj = 0.0; +      /* integer solution (MIP) */ +      lp->mip_stat = GLP_UNDEF; +      lp->mip_obj = 0.0; +      return; +} + +glp_prob *glp_create_prob(void) +{     glp_prob *lp; +      lp = xmalloc(sizeof(glp_prob)); +      create_prob(lp); +      return lp; +} + +/*********************************************************************** +*  NAME +* +*  glp_set_prob_name - assign (change) problem name +* +*  SYNOPSIS +* +*  void glp_set_prob_name(glp_prob *lp, const char *name); +* +*  DESCRIPTION +* +*  The routine glp_set_prob_name assigns a given symbolic name (1 up to +*  255 characters) to the specified problem object. +* +*  If the parameter name is NULL or empty string, the routine erases an +*  existing symbolic name of the problem object. */ + +void glp_set_prob_name(glp_prob *lp, const char *name) +{     glp_tree *tree = lp->tree; +      if (tree != NULL && tree->reason != 0) +         xerror("glp_set_prob_name: operation not allowed\n"); +      if (lp->name != NULL) +      {  dmp_free_atom(lp->pool, lp->name, strlen(lp->name)+1); +         lp->name = NULL; +      } +      if (!(name == NULL || name[0] == '\0')) +      {  int k; +         for (k = 0; name[k] != '\0'; k++) +         {  if (k == 256) +               xerror("glp_set_prob_name: problem name too long\n"); +            if (iscntrl((unsigned char)name[k])) +               xerror("glp_set_prob_name: problem name contains invalid" +                  " character(s)\n"); +         } +         lp->name = dmp_get_atom(lp->pool, strlen(name)+1); +         strcpy(lp->name, name); +      } +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_set_obj_name - assign (change) objective function name +* +*  SYNOPSIS +* +*  void glp_set_obj_name(glp_prob *lp, const char *name); +* +*  DESCRIPTION +* +*  The routine glp_set_obj_name assigns a given symbolic name (1 up to +*  255 characters) to the objective function of the specified problem +*  object. +* +*  If the parameter name is NULL or empty string, the routine erases an +*  existing name of the objective function. */ + +void glp_set_obj_name(glp_prob *lp, const char *name) +{     glp_tree *tree = lp->tree; +      if (tree != NULL && tree->reason != 0) +         xerror("glp_set_obj_name: operation not allowed\n"); +     if (lp->obj != NULL) +      {  dmp_free_atom(lp->pool, lp->obj, strlen(lp->obj)+1); +         lp->obj = NULL; +      } +      if (!(name == NULL || name[0] == '\0')) +      {  int k; +         for (k = 0; name[k] != '\0'; k++) +         {  if (k == 256) +               xerror("glp_set_obj_name: objective name too long\n"); +            if (iscntrl((unsigned char)name[k])) +               xerror("glp_set_obj_name: objective name contains invali" +                  "d character(s)\n"); +         } +         lp->obj = dmp_get_atom(lp->pool, strlen(name)+1); +         strcpy(lp->obj, name); +      } +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_set_obj_dir - set (change) optimization direction flag +* +*  SYNOPSIS +* +*  void glp_set_obj_dir(glp_prob *lp, int dir); +* +*  DESCRIPTION +* +*  The routine glp_set_obj_dir sets (changes) optimization direction +*  flag (i.e. "sense" of the objective function) as specified by the +*  parameter dir: +* +*  GLP_MIN - minimization; +*  GLP_MAX - maximization. */ + +void glp_set_obj_dir(glp_prob *lp, int dir) +{     glp_tree *tree = lp->tree; +      if (tree != NULL && tree->reason != 0) +         xerror("glp_set_obj_dir: operation not allowed\n"); +     if (!(dir == GLP_MIN || dir == GLP_MAX)) +         xerror("glp_set_obj_dir: dir = %d; invalid direction flag\n", +            dir); +      lp->dir = dir; +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_add_rows - add new rows to problem object +* +*  SYNOPSIS +* +*  int glp_add_rows(glp_prob *lp, int nrs); +* +*  DESCRIPTION +* +*  The routine glp_add_rows adds nrs rows (constraints) to the specified +*  problem object. New rows are always added to the end of the row list, +*  so the ordinal numbers of existing rows remain unchanged. +* +*  Being added each new row is initially free (unbounded) and has empty +*  list of the constraint coefficients. +* +*  RETURNS +* +*  The routine glp_add_rows returns the ordinal number of the first new +*  row added to the problem object. */ + +int glp_add_rows(glp_prob *lp, int nrs) +{     glp_tree *tree = lp->tree; +      GLPROW *row; +      int m_new, i; +      /* determine new number of rows */ +      if (nrs < 1) +         xerror("glp_add_rows: nrs = %d; invalid number of rows\n", +            nrs); +      if (nrs > M_MAX - lp->m) +         xerror("glp_add_rows: nrs = %d; too many rows\n", nrs); +      m_new = lp->m + nrs; +      /* increase the room, if necessary */ +      if (lp->m_max < m_new) +      {  GLPROW **save = lp->row; +         while (lp->m_max < m_new) +         {  lp->m_max += lp->m_max; +            xassert(lp->m_max > 0); +         } +         lp->row = xcalloc(1+lp->m_max, sizeof(GLPROW *)); +         memcpy(&lp->row[1], &save[1], lp->m * sizeof(GLPROW *)); +         xfree(save); +         /* do not forget about the basis header */ +         xfree(lp->head); +         lp->head = xcalloc(1+lp->m_max, sizeof(int)); +      } +      /* add new rows to the end of the row list */ +      for (i = lp->m+1; i <= m_new; i++) +      {  /* create row descriptor */ +         lp->row[i] = row = dmp_get_atom(lp->pool, sizeof(GLPROW)); +         row->i = i; +         row->name = NULL; +         row->node = NULL; +#if 1 /* 20/IX-2008 */ +         row->level = 0; +         row->origin = 0; +         row->klass = 0; +         if (tree != NULL) +         {  switch (tree->reason) +            {  case 0: +                  break; +               case GLP_IROWGEN: +                  xassert(tree->curr != NULL); +                  row->level = tree->curr->level; +                  row->origin = GLP_RF_LAZY; +                  break; +               case GLP_ICUTGEN: +                  xassert(tree->curr != NULL); +                  row->level = tree->curr->level; +                  row->origin = GLP_RF_CUT; +                  break; +               default: +                  xassert(tree != tree); +            } +         } +#endif +         row->type = GLP_FR; +         row->lb = row->ub = 0.0; +         row->ptr = NULL; +         row->rii = 1.0; +         row->stat = GLP_BS; +#if 0 +         row->bind = -1; +#else +         row->bind = 0; +#endif +         row->prim = row->dual = 0.0; +         row->pval = row->dval = 0.0; +         row->mipx = 0.0; +      } +      /* set new number of rows */ +      lp->m = m_new; +      /* invalidate the basis factorization */ +      lp->valid = 0; +#if 1 +      if (tree != NULL && tree->reason != 0) tree->reopt = 1; +#endif +      /* return the ordinal number of the first row added */ +      return m_new - nrs + 1; +} + +/*********************************************************************** +*  NAME +* +*  glp_add_cols - add new columns to problem object +* +*  SYNOPSIS +* +*  int glp_add_cols(glp_prob *lp, int ncs); +* +*  DESCRIPTION +* +*  The routine glp_add_cols adds ncs columns (structural variables) to +*  the specified problem object. New columns are always added to the end +*  of the column list, so the ordinal numbers of existing columns remain +*  unchanged. +* +*  Being added each new column is initially fixed at zero and has empty +*  list of the constraint coefficients. +* +*  RETURNS +* +*  The routine glp_add_cols returns the ordinal number of the first new +*  column added to the problem object. */ + +int glp_add_cols(glp_prob *lp, int ncs) +{     glp_tree *tree = lp->tree; +      GLPCOL *col; +      int n_new, j; +      if (tree != NULL && tree->reason != 0) +         xerror("glp_add_cols: operation not allowed\n"); +      /* determine new number of columns */ +      if (ncs < 1) +         xerror("glp_add_cols: ncs = %d; invalid number of columns\n", +            ncs); +      if (ncs > N_MAX - lp->n) +         xerror("glp_add_cols: ncs = %d; too many columns\n", ncs); +      n_new = lp->n + ncs; +      /* increase the room, if necessary */ +      if (lp->n_max < n_new) +      {  GLPCOL **save = lp->col; +         while (lp->n_max < n_new) +         {  lp->n_max += lp->n_max; +            xassert(lp->n_max > 0); +         } +         lp->col = xcalloc(1+lp->n_max, sizeof(GLPCOL *)); +         memcpy(&lp->col[1], &save[1], lp->n * sizeof(GLPCOL *)); +         xfree(save); +      } +      /* add new columns to the end of the column list */ +      for (j = lp->n+1; j <= n_new; j++) +      {  /* create column descriptor */ +         lp->col[j] = col = dmp_get_atom(lp->pool, sizeof(GLPCOL)); +         col->j = j; +         col->name = NULL; +         col->node = NULL; +         col->kind = GLP_CV; +         col->type = GLP_FX; +         col->lb = col->ub = 0.0; +         col->coef = 0.0; +         col->ptr = NULL; +         col->sjj = 1.0; +         col->stat = GLP_NS; +#if 0 +         col->bind = -1; +#else +         col->bind = 0; /* the basis may remain valid */ +#endif +         col->prim = col->dual = 0.0; +         col->pval = col->dval = 0.0; +         col->mipx = 0.0; +      } +      /* set new number of columns */ +      lp->n = n_new; +      /* return the ordinal number of the first column added */ +      return n_new - ncs + 1; +} + +/*********************************************************************** +*  NAME +* +*  glp_set_row_name - assign (change) row name +* +*  SYNOPSIS +* +*  void glp_set_row_name(glp_prob *lp, int i, const char *name); +* +*  DESCRIPTION +* +*  The routine glp_set_row_name assigns a given symbolic name (1 up to +*  255 characters) to i-th row (auxiliary variable) of the specified +*  problem object. +* +*  If the parameter name is NULL or empty string, the routine erases an +*  existing name of i-th row. */ + +void glp_set_row_name(glp_prob *lp, int i, const char *name) +{     glp_tree *tree = lp->tree; +      GLPROW *row; +      if (!(1 <= i && i <= lp->m)) +         xerror("glp_set_row_name: i = %d; row number out of range\n", +            i); +      row = lp->row[i]; +      if (tree != NULL && tree->reason != 0) +      {  xassert(tree->curr != NULL); +         xassert(row->level == tree->curr->level); +      } +      if (row->name != NULL) +      {  if (row->node != NULL) +         {  xassert(lp->r_tree != NULL); +            avl_delete_node(lp->r_tree, row->node); +            row->node = NULL; +         } +         dmp_free_atom(lp->pool, row->name, strlen(row->name)+1); +         row->name = NULL; +      } +      if (!(name == NULL || name[0] == '\0')) +      {  int k; +         for (k = 0; name[k] != '\0'; k++) +         {  if (k == 256) +               xerror("glp_set_row_name: i = %d; row name too long\n", +                  i); +            if (iscntrl((unsigned char)name[k])) +               xerror("glp_set_row_name: i = %d: row name contains inva" +                  "lid character(s)\n", i); +         } +         row->name = dmp_get_atom(lp->pool, strlen(name)+1); +         strcpy(row->name, name); +         if (lp->r_tree != NULL) +         {  xassert(row->node == NULL); +            row->node = avl_insert_node(lp->r_tree, row->name); +            avl_set_node_link(row->node, row); +         } +      } +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_set_col_name - assign (change) column name +* +*  SYNOPSIS +* +*  void glp_set_col_name(glp_prob *lp, int j, const char *name); +* +*  DESCRIPTION +* +*  The routine glp_set_col_name assigns a given symbolic name (1 up to +*  255 characters) to j-th column (structural variable) of the specified +*  problem object. +* +*  If the parameter name is NULL or empty string, the routine erases an +*  existing name of j-th column. */ + +void glp_set_col_name(glp_prob *lp, int j, const char *name) +{     glp_tree *tree = lp->tree; +      GLPCOL *col; +      if (tree != NULL && tree->reason != 0) +         xerror("glp_set_col_name: operation not allowed\n"); +      if (!(1 <= j && j <= lp->n)) +         xerror("glp_set_col_name: j = %d; column number out of range\n" +            , j); +      col = lp->col[j]; +      if (col->name != NULL) +      {  if (col->node != NULL) +         {  xassert(lp->c_tree != NULL); +            avl_delete_node(lp->c_tree, col->node); +            col->node = NULL; +         } +         dmp_free_atom(lp->pool, col->name, strlen(col->name)+1); +         col->name = NULL; +      } +      if (!(name == NULL || name[0] == '\0')) +      {  int k; +         for (k = 0; name[k] != '\0'; k++) +         {  if (k == 256) +               xerror("glp_set_col_name: j = %d; column name too long\n" +                  , j); +            if (iscntrl((unsigned char)name[k])) +               xerror("glp_set_col_name: j = %d: column name contains i" +                  "nvalid character(s)\n", j); +         } +         col->name = dmp_get_atom(lp->pool, strlen(name)+1); +         strcpy(col->name, name); +         if (lp->c_tree != NULL && col->name != NULL) +         {  xassert(col->node == NULL); +            col->node = avl_insert_node(lp->c_tree, col->name); +            avl_set_node_link(col->node, col); +         } +      } +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_set_row_bnds - set (change) row bounds +* +*  SYNOPSIS +* +*  void glp_set_row_bnds(glp_prob *lp, int i, int type, double lb, +*     double ub); +* +*  DESCRIPTION +* +*  The routine glp_set_row_bnds sets (changes) the type and bounds of +*  i-th row (auxiliary variable) of the specified problem object. +* +*  Parameters type, lb, and ub specify the type, lower bound, and upper +*  bound, respectively, as follows: +* +*     Type           Bounds        Comments +*     ------------------------------------------------------ +*     GLP_FR   -inf <  x <  +inf   Free variable +*     GLP_LO     lb <= x <  +inf   Variable with lower bound +*     GLP_UP   -inf <  x <=  ub    Variable with upper bound +*     GLP_DB     lb <= x <=  ub    Double-bounded variable +*     GLP_FX           x  =  lb    Fixed variable +* +*  where x is the auxiliary variable associated with i-th row. +* +*  If the row has no lower bound, the parameter lb is ignored. If the +*  row has no upper bound, the parameter ub is ignored. If the row is +*  an equality constraint (i.e. the corresponding auxiliary variable is +*  of fixed type), only the parameter lb is used while the parameter ub +*  is ignored. */ + +void glp_set_row_bnds(glp_prob *lp, int i, int type, double lb, +      double ub) +{     GLPROW *row; +      if (!(1 <= i && i <= lp->m)) +         xerror("glp_set_row_bnds: i = %d; row number out of range\n", +            i); +      row = lp->row[i]; +      row->type = type; +      switch (type) +      {  case GLP_FR: +            row->lb = row->ub = 0.0; +            if (row->stat != GLP_BS) row->stat = GLP_NF; +            break; +         case GLP_LO: +            row->lb = lb, row->ub = 0.0; +            if (row->stat != GLP_BS) row->stat = GLP_NL; +            break; +         case GLP_UP: +            row->lb = 0.0, row->ub = ub; +            if (row->stat != GLP_BS) row->stat = GLP_NU; +            break; +         case GLP_DB: +            row->lb = lb, row->ub = ub; +            if (!(row->stat == GLP_BS || +                  row->stat == GLP_NL || row->stat == GLP_NU)) +               row->stat = (fabs(lb) <= fabs(ub) ? GLP_NL : GLP_NU); +            break; +         case GLP_FX: +            row->lb = row->ub = lb; +            if (row->stat != GLP_BS) row->stat = GLP_NS; +            break; +         default: +            xerror("glp_set_row_bnds: i = %d; type = %d; invalid row ty" +               "pe\n", i, type); +      } +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_set_col_bnds - set (change) column bounds +* +*  SYNOPSIS +* +*  void glp_set_col_bnds(glp_prob *lp, int j, int type, double lb, +*     double ub); +* +*  DESCRIPTION +* +*  The routine glp_set_col_bnds sets (changes) the type and bounds of +*  j-th column (structural variable) of the specified problem object. +* +*  Parameters type, lb, and ub specify the type, lower bound, and upper +*  bound, respectively, as follows: +* +*     Type           Bounds        Comments +*     ------------------------------------------------------ +*     GLP_FR   -inf <  x <  +inf   Free variable +*     GLP_LO     lb <= x <  +inf   Variable with lower bound +*     GLP_UP   -inf <  x <=  ub    Variable with upper bound +*     GLP_DB     lb <= x <=  ub    Double-bounded variable +*     GLP_FX           x  =  lb    Fixed variable +* +*  where x is the structural variable associated with j-th column. +* +*  If the column has no lower bound, the parameter lb is ignored. If the +*  column has no upper bound, the parameter ub is ignored. If the column +*  is of fixed type, only the parameter lb is used while the parameter +*  ub is ignored. */ + +void glp_set_col_bnds(glp_prob *lp, int j, int type, double lb, +      double ub) +{     GLPCOL *col; +      if (!(1 <= j && j <= lp->n)) +         xerror("glp_set_col_bnds: j = %d; column number out of range\n" +            , j); +      col = lp->col[j]; +      col->type = type; +      switch (type) +      {  case GLP_FR: +            col->lb = col->ub = 0.0; +            if (col->stat != GLP_BS) col->stat = GLP_NF; +            break; +         case GLP_LO: +            col->lb = lb, col->ub = 0.0; +            if (col->stat != GLP_BS) col->stat = GLP_NL; +            break; +         case GLP_UP: +            col->lb = 0.0, col->ub = ub; +            if (col->stat != GLP_BS) col->stat = GLP_NU; +            break; +         case GLP_DB: +            col->lb = lb, col->ub = ub; +            if (!(col->stat == GLP_BS || +                  col->stat == GLP_NL || col->stat == GLP_NU)) +               col->stat = (fabs(lb) <= fabs(ub) ? GLP_NL : GLP_NU); +            break; +         case GLP_FX: +            col->lb = col->ub = lb; +            if (col->stat != GLP_BS) col->stat = GLP_NS; +            break; +         default: +            xerror("glp_set_col_bnds: j = %d; type = %d; invalid column" +               " type\n", j, type); +      } +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_set_obj_coef - set (change) obj. coefficient or constant term +* +*  SYNOPSIS +* +*  void glp_set_obj_coef(glp_prob *lp, int j, double coef); +* +*  DESCRIPTION +* +*  The routine glp_set_obj_coef sets (changes) objective coefficient at +*  j-th column (structural variable) of the specified problem object. +* +*  If the parameter j is 0, the routine sets (changes) the constant term +*  ("shift") of the objective function. */ + +void glp_set_obj_coef(glp_prob *lp, int j, double coef) +{     glp_tree *tree = lp->tree; +      if (tree != NULL && tree->reason != 0) +         xerror("glp_set_obj_coef: operation not allowed\n"); +      if (!(0 <= j && j <= lp->n)) +         xerror("glp_set_obj_coef: j = %d; column number out of range\n" +            , j); +      if (j == 0) +         lp->c0 = coef; +      else +         lp->col[j]->coef = coef; +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_set_mat_row - set (replace) row of the constraint matrix +* +*  SYNOPSIS +* +*  void glp_set_mat_row(glp_prob *lp, int i, int len, const int ind[], +*     const double val[]); +* +*  DESCRIPTION +* +*  The routine glp_set_mat_row stores (replaces) the contents of i-th +*  row of the constraint matrix of the specified problem object. +* +*  Column indices and numeric values of new row elements must be placed +*  in locations ind[1], ..., ind[len] and val[1], ..., val[len], where +*  0 <= len <= n is the new length of i-th row, n is the current number +*  of columns in the problem object. Elements with identical column +*  indices are not allowed. Zero elements are allowed, but they are not +*  stored in the constraint matrix. +* +*  If the parameter len is zero, the parameters ind and/or val can be +*  specified as NULL. */ + +void glp_set_mat_row(glp_prob *lp, int i, int len, const int ind[], +      const double val[]) +{     glp_tree *tree = lp->tree; +      GLPROW *row; +      GLPCOL *col; +      GLPAIJ *aij, *next; +      int j, k; +      /* obtain pointer to i-th row */ +      if (!(1 <= i && i <= lp->m)) +         xerror("glp_set_mat_row: i = %d; row number out of range\n", +            i); +      row = lp->row[i]; +      if (tree != NULL && tree->reason != 0) +      {  xassert(tree->curr != NULL); +         xassert(row->level == tree->curr->level); +      } +      /* remove all existing elements from i-th row */ +      while (row->ptr != NULL) +      {  /* take next element in the row */ +         aij = row->ptr; +         /* remove the element from the row list */ +         row->ptr = aij->r_next; +         /* obtain pointer to corresponding column */ +         col = aij->col; +         /* remove the element from the column list */ +         if (aij->c_prev == NULL) +            col->ptr = aij->c_next; +         else +            aij->c_prev->c_next = aij->c_next; +         if (aij->c_next == NULL) +            ; +         else +            aij->c_next->c_prev = aij->c_prev; +         /* return the element to the memory pool */ +         dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--; +         /* if the corresponding column is basic, invalidate the basis +            factorization */ +         if (col->stat == GLP_BS) lp->valid = 0; +      } +      /* store new contents of i-th row */ +      if (!(0 <= len && len <= lp->n)) +         xerror("glp_set_mat_row: i = %d; len = %d; invalid row length " +            "\n", i, len); +      if (len > NNZ_MAX - lp->nnz) +         xerror("glp_set_mat_row: i = %d; len = %d; too many constraint" +            " coefficients\n", i, len); +      for (k = 1; k <= len; k++) +      {  /* take number j of corresponding column */ +         j = ind[k]; +         /* obtain pointer to j-th column */ +         if (!(1 <= j && j <= lp->n)) +            xerror("glp_set_mat_row: i = %d; ind[%d] = %d; column index" +               " out of range\n", i, k, j); +         col = lp->col[j]; +         /* if there is element with the same column index, it can only +            be found in the beginning of j-th column list */ +         if (col->ptr != NULL && col->ptr->row->i == i) +            xerror("glp_set_mat_row: i = %d; ind[%d] = %d; duplicate co" +               "lumn indices not allowed\n", i, k, j); +         /* create new element */ +         aij = dmp_get_atom(lp->pool, sizeof(GLPAIJ)), lp->nnz++; +         aij->row = row; +         aij->col = col; +         aij->val = val[k]; +         /* add the new element to the beginning of i-th row and j-th +            column lists */ +         aij->r_prev = NULL; +         aij->r_next = row->ptr; +         aij->c_prev = NULL; +         aij->c_next = col->ptr; +         if (aij->r_next != NULL) aij->r_next->r_prev = aij; +         if (aij->c_next != NULL) aij->c_next->c_prev = aij; +         row->ptr = col->ptr = aij; +         /* if the corresponding column is basic, invalidate the basis +            factorization */ +         if (col->stat == GLP_BS && aij->val != 0.0) lp->valid = 0; +      } +      /* remove zero elements from i-th row */ +      for (aij = row->ptr; aij != NULL; aij = next) +      {  next = aij->r_next; +         if (aij->val == 0.0) +         {  /* remove the element from the row list */ +            if (aij->r_prev == NULL) +               row->ptr = next; +            else +               aij->r_prev->r_next = next; +            if (next == NULL) +               ; +            else +               next->r_prev = aij->r_prev; +            /* remove the element from the column list */ +            xassert(aij->c_prev == NULL); +            aij->col->ptr = aij->c_next; +            if (aij->c_next != NULL) aij->c_next->c_prev = NULL; +            /* return the element to the memory pool */ +            dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--; +         } +      } +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_set_mat_col - set (replace) column of the constraint matrix +* +*  SYNOPSIS +* +*  void glp_set_mat_col(glp_prob *lp, int j, int len, const int ind[], +*     const double val[]); +* +*  DESCRIPTION +* +*  The routine glp_set_mat_col stores (replaces) the contents of j-th +*  column of the constraint matrix of the specified problem object. +* +*  Row indices and numeric values of new column elements must be placed +*  in locations ind[1], ..., ind[len] and val[1], ..., val[len], where +*  0 <= len <= m is the new length of j-th column, m is the current +*  number of rows in the problem object. Elements with identical column +*  indices are not allowed. Zero elements are allowed, but they are not +*  stored in the constraint matrix. +* +*  If the parameter len is zero, the parameters ind and/or val can be +*  specified as NULL. */ + +void glp_set_mat_col(glp_prob *lp, int j, int len, const int ind[], +      const double val[]) +{     glp_tree *tree = lp->tree; +      GLPROW *row; +      GLPCOL *col; +      GLPAIJ *aij, *next; +      int i, k; +      if (tree != NULL && tree->reason != 0) +         xerror("glp_set_mat_col: operation not allowed\n"); +      /* obtain pointer to j-th column */ +      if (!(1 <= j && j <= lp->n)) +         xerror("glp_set_mat_col: j = %d; column number out of range\n", +            j); +      col = lp->col[j]; +      /* remove all existing elements from j-th column */ +      while (col->ptr != NULL) +      {  /* take next element in the column */ +         aij = col->ptr; +         /* remove the element from the column list */ +         col->ptr = aij->c_next; +         /* obtain pointer to corresponding row */ +         row = aij->row; +         /* remove the element from the row list */ +         if (aij->r_prev == NULL) +            row->ptr = aij->r_next; +         else +            aij->r_prev->r_next = aij->r_next; +         if (aij->r_next == NULL) +            ; +         else +            aij->r_next->r_prev = aij->r_prev; +         /* return the element to the memory pool */ +         dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--; +      } +      /* store new contents of j-th column */ +      if (!(0 <= len && len <= lp->m)) +         xerror("glp_set_mat_col: j = %d; len = %d; invalid column leng" +            "th\n", j, len); +      if (len > NNZ_MAX - lp->nnz) +         xerror("glp_set_mat_col: j = %d; len = %d; too many constraint" +            " coefficients\n", j, len); +      for (k = 1; k <= len; k++) +      {  /* take number i of corresponding row */ +         i = ind[k]; +         /* obtain pointer to i-th row */ +         if (!(1 <= i && i <= lp->m)) +            xerror("glp_set_mat_col: j = %d; ind[%d] = %d; row index ou" +               "t of range\n", j, k, i); +         row = lp->row[i]; +         /* if there is element with the same row index, it can only be +            found in the beginning of i-th row list */ +         if (row->ptr != NULL && row->ptr->col->j == j) +            xerror("glp_set_mat_col: j = %d; ind[%d] = %d; duplicate ro" +               "w indices not allowed\n", j, k, i); +         /* create new element */ +         aij = dmp_get_atom(lp->pool, sizeof(GLPAIJ)), lp->nnz++; +         aij->row = row; +         aij->col = col; +         aij->val = val[k]; +         /* add the new element to the beginning of i-th row and j-th +            column lists */ +         aij->r_prev = NULL; +         aij->r_next = row->ptr; +         aij->c_prev = NULL; +         aij->c_next = col->ptr; +         if (aij->r_next != NULL) aij->r_next->r_prev = aij; +         if (aij->c_next != NULL) aij->c_next->c_prev = aij; +         row->ptr = col->ptr = aij; +      } +      /* remove zero elements from j-th column */ +      for (aij = col->ptr; aij != NULL; aij = next) +      {  next = aij->c_next; +         if (aij->val == 0.0) +         {  /* remove the element from the row list */ +            xassert(aij->r_prev == NULL); +            aij->row->ptr = aij->r_next; +            if (aij->r_next != NULL) aij->r_next->r_prev = NULL; +            /* remove the element from the column list */ +            if (aij->c_prev == NULL) +               col->ptr = next; +            else +               aij->c_prev->c_next = next; +            if (next == NULL) +               ; +            else +               next->c_prev = aij->c_prev; +            /* return the element to the memory pool */ +            dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--; +         } +      } +      /* if j-th column is basic, invalidate the basis factorization */ +      if (col->stat == GLP_BS) lp->valid = 0; +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_load_matrix - load (replace) the whole constraint matrix +* +*  SYNOPSIS +* +*  void glp_load_matrix(glp_prob *lp, int ne, const int ia[], +*     const int ja[], const double ar[]); +* +*  DESCRIPTION +* +*  The routine glp_load_matrix loads the constraint matrix passed in +*  the arrays ia, ja, and ar into the specified problem object. Before +*  loading the current contents of the constraint matrix is destroyed. +* +*  Constraint coefficients (elements of the constraint matrix) must be +*  specified as triplets (ia[k], ja[k], ar[k]) for k = 1, ..., ne, +*  where ia[k] is the row index, ja[k] is the column index, ar[k] is a +*  numeric value of corresponding constraint coefficient. The parameter +*  ne specifies the total number of (non-zero) elements in the matrix +*  to be loaded. Coefficients with identical indices are not allowed. +*  Zero coefficients are allowed, however, they are not stored in the +*  constraint matrix. +* +*  If the parameter ne is zero, the parameters ia, ja, and ar can be +*  specified as NULL. */ + +void glp_load_matrix(glp_prob *lp, int ne, const int ia[], +      const int ja[], const double ar[]) +{     glp_tree *tree = lp->tree; +      GLPROW *row; +      GLPCOL *col; +      GLPAIJ *aij, *next; +      int i, j, k; +      if (tree != NULL && tree->reason != 0) +         xerror("glp_load_matrix: operation not allowed\n"); +      /* clear the constraint matrix */ +      for (i = 1; i <= lp->m; i++) +      {  row = lp->row[i]; +         while (row->ptr != NULL) +         {  aij = row->ptr; +            row->ptr = aij->r_next; +            dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--; +         } +      } +      xassert(lp->nnz == 0); +      for (j = 1; j <= lp->n; j++) lp->col[j]->ptr = NULL; +      /* load the new contents of the constraint matrix and build its +         row lists */ +      if (ne < 0) +         xerror("glp_load_matrix: ne = %d; invalid number of constraint" +            " coefficients\n", ne); +      if (ne > NNZ_MAX) +         xerror("glp_load_matrix: ne = %d; too many constraint coeffici" +            "ents\n", ne); +      for (k = 1; k <= ne; k++) +      {  /* take indices of new element */ +         i = ia[k], j = ja[k]; +         /* obtain pointer to i-th row */ +         if (!(1 <= i && i <= lp->m)) +            xerror("glp_load_matrix: ia[%d] = %d; row index out of rang" +               "e\n", k, i); +         row = lp->row[i]; +         /* obtain pointer to j-th column */ +         if (!(1 <= j && j <= lp->n)) +            xerror("glp_load_matrix: ja[%d] = %d; column index out of r" +               "ange\n", k, j); +         col = lp->col[j]; +         /* create new element */ +         aij = dmp_get_atom(lp->pool, sizeof(GLPAIJ)), lp->nnz++; +         aij->row = row; +         aij->col = col; +         aij->val = ar[k]; +         /* add the new element to the beginning of i-th row list */ +         aij->r_prev = NULL; +         aij->r_next = row->ptr; +         if (aij->r_next != NULL) aij->r_next->r_prev = aij; +         row->ptr = aij; +      } +      xassert(lp->nnz == ne); +      /* build column lists of the constraint matrix and check elements +         with identical indices */ +      for (i = 1; i <= lp->m; i++) +      {  for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next) +         {  /* obtain pointer to corresponding column */ +            col = aij->col; +            /* if there is element with identical indices, it can only +               be found in the beginning of j-th column list */ +            if (col->ptr != NULL && col->ptr->row->i == i) +            {  for (k = 1; k <= ne; k++) +                  if (ia[k] == i && ja[k] == col->j) break; +               xerror("glp_load_mat: ia[%d] = %d; ja[%d] = %d; duplicat" +                  "e indices not allowed\n", k, i, k, col->j); +            } +            /* add the element to the beginning of j-th column list */ +            aij->c_prev = NULL; +            aij->c_next = col->ptr; +            if (aij->c_next != NULL) aij->c_next->c_prev = aij; +            col->ptr = aij; +         } +      } +      /* remove zero elements from the constraint matrix */ +      for (i = 1; i <= lp->m; i++) +      {  row = lp->row[i]; +         for (aij = row->ptr; aij != NULL; aij = next) +         {  next = aij->r_next; +            if (aij->val == 0.0) +            {  /* remove the element from the row list */ +               if (aij->r_prev == NULL) +                  row->ptr = next; +               else +                  aij->r_prev->r_next = next; +               if (next == NULL) +                  ; +               else +                  next->r_prev = aij->r_prev; +               /* remove the element from the column list */ +               if (aij->c_prev == NULL) +                  aij->col->ptr = aij->c_next; +               else +                  aij->c_prev->c_next = aij->c_next; +               if (aij->c_next == NULL) +                  ; +               else +                  aij->c_next->c_prev = aij->c_prev; +               /* return the element to the memory pool */ +               dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--; +            } +         } +      } +      /* invalidate the basis factorization */ +      lp->valid = 0; +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_check_dup - check for duplicate elements in sparse matrix +* +*  SYNOPSIS +* +*  int glp_check_dup(int m, int n, int ne, const int ia[], +*     const int ja[]); +* +*  DESCRIPTION +* +*  The routine glp_check_dup checks for duplicate elements (that is, +*  elements with identical indices) in a sparse matrix specified in the +*  coordinate format. +* +*  The parameters m and n specifies, respectively, the number of rows +*  and columns in the matrix, m >= 0, n >= 0. +* +*  The parameter ne specifies the number of (structurally) non-zero +*  elements in the matrix, ne >= 0. +* +*  Elements of the matrix are specified as doublets (ia[k],ja[k]) for +*  k = 1,...,ne, where ia[k] is a row index, ja[k] is a column index. +* +*  The routine glp_check_dup can be used prior to a call to the routine +*  glp_load_matrix to check that the constraint matrix to be loaded has +*  no duplicate elements. +* +*  RETURNS +* +*  The routine glp_check_dup returns one of the following values: +* +*   0 - the matrix has no duplicate elements; +* +*  -k - indices ia[k] or/and ja[k] are out of range; +* +*  +k - element (ia[k],ja[k]) is duplicate. */ + +int glp_check_dup(int m, int n, int ne, const int ia[], const int ja[]) +{     int i, j, k, *ptr, *next, ret; +      char *flag; +      if (m < 0) +         xerror("glp_check_dup: m = %d; invalid parameter\n"); +      if (n < 0) +         xerror("glp_check_dup: n = %d; invalid parameter\n"); +      if (ne < 0) +         xerror("glp_check_dup: ne = %d; invalid parameter\n"); +      if (ne > 0 && ia == NULL) +         xerror("glp_check_dup: ia = %p; invalid parameter\n", ia); +      if (ne > 0 && ja == NULL) +         xerror("glp_check_dup: ja = %p; invalid parameter\n", ja); +      for (k = 1; k <= ne; k++) +      {  i = ia[k], j = ja[k]; +         if (!(1 <= i && i <= m && 1 <= j && j <= n)) +         {  ret = -k; +            goto done; +         } +      } +      if (m == 0 || n == 0) +      {  ret = 0; +         goto done; +      } +      /* allocate working arrays */ +      ptr = xcalloc(1+m, sizeof(int)); +      next = xcalloc(1+ne, sizeof(int)); +      flag = xcalloc(1+n, sizeof(char)); +      /* build row lists */ +      for (i = 1; i <= m; i++) +         ptr[i] = 0; +      for (k = 1; k <= ne; k++) +      {  i = ia[k]; +         next[k] = ptr[i]; +         ptr[i] = k; +      } +      /* clear column flags */ +      for (j = 1; j <= n; j++) +         flag[j] = 0; +      /* check for duplicate elements */ +      for (i = 1; i <= m; i++) +      {  for (k = ptr[i]; k != 0; k = next[k]) +         {  j = ja[k]; +            if (flag[j]) +            {  /* find first element (i,j) */ +               for (k = 1; k <= ne; k++) +                  if (ia[k] == i && ja[k] == j) break; +               xassert(k <= ne); +               /* find next (duplicate) element (i,j) */ +               for (k++; k <= ne; k++) +                  if (ia[k] == i && ja[k] == j) break; +               xassert(k <= ne); +               ret = +k; +               goto skip; +            } +            flag[j] = 1; +         } +         /* clear column flags */ +         for (k = ptr[i]; k != 0; k = next[k]) +            flag[ja[k]] = 0; +      } +      /* no duplicate element found */ +      ret = 0; +skip: /* free working arrays */ +      xfree(ptr); +      xfree(next); +      xfree(flag); +done: return ret; +} + +/*********************************************************************** +*  NAME +* +*  glp_sort_matrix - sort elements of the constraint matrix +* +*  SYNOPSIS +* +*  void glp_sort_matrix(glp_prob *P); +* +*  DESCRIPTION +* +*  The routine glp_sort_matrix sorts elements of the constraint matrix +*  rebuilding its row and column linked lists. On exit from the routine +*  the constraint matrix is not changed, however, elements in the row +*  linked lists become ordered by ascending column indices, and the +*  elements in the column linked lists become ordered by ascending row +*  indices. */ + +void glp_sort_matrix(glp_prob *P) +{     GLPAIJ *aij; +      int i, j; +#if 0 /* 04/IV-2016 */ +      if (P == NULL || P->magic != GLP_PROB_MAGIC) +         xerror("glp_sort_matrix: P = %p; invalid problem object\n", +            P); +#endif +      /* rebuild row linked lists */ +      for (i = P->m; i >= 1; i--) +         P->row[i]->ptr = NULL; +      for (j = P->n; j >= 1; j--) +      {  for (aij = P->col[j]->ptr; aij != NULL; aij = aij->c_next) +         {  i = aij->row->i; +            aij->r_prev = NULL; +            aij->r_next = P->row[i]->ptr; +            if (aij->r_next != NULL) aij->r_next->r_prev = aij; +            P->row[i]->ptr = aij; +         } +      } +      /* rebuild column linked lists */ +      for (j = P->n; j >= 1; j--) +         P->col[j]->ptr = NULL; +      for (i = P->m; i >= 1; i--) +      {  for (aij = P->row[i]->ptr; aij != NULL; aij = aij->r_next) +         {  j = aij->col->j; +            aij->c_prev = NULL; +            aij->c_next = P->col[j]->ptr; +            if (aij->c_next != NULL) aij->c_next->c_prev = aij; +            P->col[j]->ptr = aij; +         } +      } +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_del_rows - delete rows from problem object +* +*  SYNOPSIS +* +*  void glp_del_rows(glp_prob *lp, int nrs, const int num[]); +* +*  DESCRIPTION +* +*  The routine glp_del_rows deletes rows from the specified problem +*  object. Ordinal numbers of rows to be deleted should be placed in +*  locations num[1], ..., num[nrs], where nrs > 0. +* +*  Note that deleting rows involves changing ordinal numbers of other +*  rows remaining in the problem object. New ordinal numbers of the +*  remaining rows are assigned under the assumption that the original +*  order of rows is not changed. */ + +void glp_del_rows(glp_prob *lp, int nrs, const int num[]) +{     glp_tree *tree = lp->tree; +      GLPROW *row; +      int i, k, m_new; +      /* mark rows to be deleted */ +      if (!(1 <= nrs && nrs <= lp->m)) +         xerror("glp_del_rows: nrs = %d; invalid number of rows\n", +            nrs); +      for (k = 1; k <= nrs; k++) +      {  /* take the number of row to be deleted */ +         i = num[k]; +         /* obtain pointer to i-th row */ +         if (!(1 <= i && i <= lp->m)) +            xerror("glp_del_rows: num[%d] = %d; row number out of range" +               "\n", k, i); +         row = lp->row[i]; +         if (tree != NULL && tree->reason != 0) +         {  if (!(tree->reason == GLP_IROWGEN || +                  tree->reason == GLP_ICUTGEN)) +               xerror("glp_del_rows: operation not allowed\n"); +            xassert(tree->curr != NULL); +            if (row->level != tree->curr->level) +               xerror("glp_del_rows: num[%d] = %d; invalid attempt to d" +                  "elete row created not in current subproblem\n", k,i); +            if (row->stat != GLP_BS) +               xerror("glp_del_rows: num[%d] = %d; invalid attempt to d" +                  "elete active row (constraint)\n", k, i); +            tree->reinv = 1; +         } +         /* check that the row is not marked yet */ +         if (row->i == 0) +            xerror("glp_del_rows: num[%d] = %d; duplicate row numbers n" +               "ot allowed\n", k, i); +         /* erase symbolic name assigned to the row */ +         glp_set_row_name(lp, i, NULL); +         xassert(row->node == NULL); +         /* erase corresponding row of the constraint matrix */ +         glp_set_mat_row(lp, i, 0, NULL, NULL); +         xassert(row->ptr == NULL); +         /* mark the row to be deleted */ +         row->i = 0; +      } +      /* delete all marked rows from the row list */ +      m_new = 0; +      for (i = 1; i <= lp->m; i++) +      {  /* obtain pointer to i-th row */ +         row = lp->row[i]; +         /* check if the row is marked */ +         if (row->i == 0) +         {  /* it is marked, delete it */ +            dmp_free_atom(lp->pool, row, sizeof(GLPROW)); +         } +         else +         {  /* it is not marked; keep it */ +            row->i = ++m_new; +            lp->row[row->i] = row; +         } +      } +      /* set new number of rows */ +      lp->m = m_new; +      /* invalidate the basis factorization */ +      lp->valid = 0; +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_del_cols - delete columns from problem object +* +*  SYNOPSIS +* +*  void glp_del_cols(glp_prob *lp, int ncs, const int num[]); +* +*  DESCRIPTION +* +*  The routine glp_del_cols deletes columns from the specified problem +*  object. Ordinal numbers of columns to be deleted should be placed in +*  locations num[1], ..., num[ncs], where ncs > 0. +* +*  Note that deleting columns involves changing ordinal numbers of +*  other columns remaining in the problem object. New ordinal numbers +*  of the remaining columns are assigned under the assumption that the +*  original order of columns is not changed. */ + +void glp_del_cols(glp_prob *lp, int ncs, const int num[]) +{     glp_tree *tree = lp->tree; +      GLPCOL *col; +      int j, k, n_new; +      if (tree != NULL && tree->reason != 0) +         xerror("glp_del_cols: operation not allowed\n"); +      /* mark columns to be deleted */ +      if (!(1 <= ncs && ncs <= lp->n)) +         xerror("glp_del_cols: ncs = %d; invalid number of columns\n", +            ncs); +      for (k = 1; k <= ncs; k++) +      {  /* take the number of column to be deleted */ +         j = num[k]; +         /* obtain pointer to j-th column */ +         if (!(1 <= j && j <= lp->n)) +            xerror("glp_del_cols: num[%d] = %d; column number out of ra" +               "nge", k, j); +         col = lp->col[j]; +         /* check that the column is not marked yet */ +         if (col->j == 0) +            xerror("glp_del_cols: num[%d] = %d; duplicate column number" +               "s not allowed\n", k, j); +         /* erase symbolic name assigned to the column */ +         glp_set_col_name(lp, j, NULL); +         xassert(col->node == NULL); +         /* erase corresponding column of the constraint matrix */ +         glp_set_mat_col(lp, j, 0, NULL, NULL); +         xassert(col->ptr == NULL); +         /* mark the column to be deleted */ +         col->j = 0; +         /* if it is basic, invalidate the basis factorization */ +         if (col->stat == GLP_BS) lp->valid = 0; +      } +      /* delete all marked columns from the column list */ +      n_new = 0; +      for (j = 1; j <= lp->n; j++) +      {  /* obtain pointer to j-th column */ +         col = lp->col[j]; +         /* check if the column is marked */ +         if (col->j == 0) +         {  /* it is marked; delete it */ +            dmp_free_atom(lp->pool, col, sizeof(GLPCOL)); +         } +         else +         {  /* it is not marked; keep it */ +            col->j = ++n_new; +            lp->col[col->j] = col; +         } +      } +      /* set new number of columns */ +      lp->n = n_new; +      /* if the basis header is still valid, adjust it */ +      if (lp->valid) +      {  int m = lp->m; +         int *head = lp->head; +         for (j = 1; j <= n_new; j++) +         {  k = lp->col[j]->bind; +            if (k != 0) +            {  xassert(1 <= k && k <= m); +               head[k] = m + j; +            } +         } +      } +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_copy_prob - copy problem object content +* +*  SYNOPSIS +* +*  void glp_copy_prob(glp_prob *dest, glp_prob *prob, int names); +* +*  DESCRIPTION +* +*  The routine glp_copy_prob copies the content of the problem object +*  prob to the problem object dest. +* +*  The parameter names is a flag. If it is non-zero, the routine also +*  copies all symbolic names; otherwise, if it is zero, symbolic names +*  are not copied. */ + +void glp_copy_prob(glp_prob *dest, glp_prob *prob, int names) +{     glp_tree *tree = dest->tree; +      glp_bfcp bfcp; +      int i, j, len, *ind; +      double *val; +      if (tree != NULL && tree->reason != 0) +         xerror("glp_copy_prob: operation not allowed\n"); +      if (dest == prob) +         xerror("glp_copy_prob: copying problem object to itself not al" +            "lowed\n"); +      if (!(names == GLP_ON || names == GLP_OFF)) +         xerror("glp_copy_prob: names = %d; invalid parameter\n", +            names); +      glp_erase_prob(dest); +      if (names && prob->name != NULL) +         glp_set_prob_name(dest, prob->name); +      if (names && prob->obj != NULL) +         glp_set_obj_name(dest, prob->obj); +      dest->dir = prob->dir; +      dest->c0 = prob->c0; +      if (prob->m > 0) +         glp_add_rows(dest, prob->m); +      if (prob->n > 0) +         glp_add_cols(dest, prob->n); +      glp_get_bfcp(prob, &bfcp); +      glp_set_bfcp(dest, &bfcp); +      dest->pbs_stat = prob->pbs_stat; +      dest->dbs_stat = prob->dbs_stat; +      dest->obj_val = prob->obj_val; +      dest->some = prob->some; +      dest->ipt_stat = prob->ipt_stat; +      dest->ipt_obj = prob->ipt_obj; +      dest->mip_stat = prob->mip_stat; +      dest->mip_obj = prob->mip_obj; +      for (i = 1; i <= prob->m; i++) +      {  GLPROW *to = dest->row[i]; +         GLPROW *from = prob->row[i]; +         if (names && from->name != NULL) +            glp_set_row_name(dest, i, from->name); +         to->type = from->type; +         to->lb = from->lb; +         to->ub = from->ub; +         to->rii = from->rii; +         to->stat = from->stat; +         to->prim = from->prim; +         to->dual = from->dual; +         to->pval = from->pval; +         to->dval = from->dval; +         to->mipx = from->mipx; +      } +      ind = xcalloc(1+prob->m, sizeof(int)); +      val = xcalloc(1+prob->m, sizeof(double)); +      for (j = 1; j <= prob->n; j++) +      {  GLPCOL *to = dest->col[j]; +         GLPCOL *from = prob->col[j]; +         if (names && from->name != NULL) +            glp_set_col_name(dest, j, from->name); +         to->kind = from->kind; +         to->type = from->type; +         to->lb = from->lb; +         to->ub = from->ub; +         to->coef = from->coef; +         len = glp_get_mat_col(prob, j, ind, val); +         glp_set_mat_col(dest, j, len, ind, val); +         to->sjj = from->sjj; +         to->stat = from->stat; +         to->prim = from->prim; +         to->dual = from->dual; +         to->pval = from->pval; +         to->dval = from->dval; +         to->mipx = from->mipx; +      } +      xfree(ind); +      xfree(val); +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_erase_prob - erase problem object content +* +*  SYNOPSIS +* +*  void glp_erase_prob(glp_prob *lp); +* +*  DESCRIPTION +* +*  The routine glp_erase_prob erases the content of the specified +*  problem object. The effect of this operation is the same as if the +*  problem object would be deleted with the routine glp_delete_prob and +*  then created anew with the routine glp_create_prob, with exception +*  that the handle (pointer) to the problem object remains valid. */ + +static void delete_prob(glp_prob *lp); + +void glp_erase_prob(glp_prob *lp) +{     glp_tree *tree = lp->tree; +      if (tree != NULL && tree->reason != 0) +         xerror("glp_erase_prob: operation not allowed\n"); +      delete_prob(lp); +      create_prob(lp); +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_delete_prob - delete problem object +* +*  SYNOPSIS +* +*  void glp_delete_prob(glp_prob *lp); +* +*  DESCRIPTION +* +*  The routine glp_delete_prob deletes the specified problem object and +*  frees all the memory allocated to it. */ + +static void delete_prob(glp_prob *lp) +#if 0 /* 04/IV-2016 */ +{     lp->magic = 0x3F3F3F3F; +#else +{ +#endif +      dmp_delete_pool(lp->pool); +#if 0 /* 08/III-2014 */ +#if 0 /* 17/XI-2009 */ +      xfree(lp->cps); +#else +      if (lp->parms != NULL) xfree(lp->parms); +#endif +#endif +      xassert(lp->tree == NULL); +#if 0 +      if (lp->cwa != NULL) xfree(lp->cwa); +#endif +      xfree(lp->row); +      xfree(lp->col); +      if (lp->r_tree != NULL) avl_delete_tree(lp->r_tree); +      if (lp->c_tree != NULL) avl_delete_tree(lp->c_tree); +      xfree(lp->head); +#if 0 /* 08/III-2014 */ +      if (lp->bfcp != NULL) xfree(lp->bfcp); +#endif +      if (lp->bfd != NULL) bfd_delete_it(lp->bfd); +      return; +} + +void glp_delete_prob(glp_prob *lp) +{     glp_tree *tree = lp->tree; +      if (tree != NULL && tree->reason != 0) +         xerror("glp_delete_prob: operation not allowed\n"); +      delete_prob(lp); +      xfree(lp); +      return; +} + +/* eof */ diff --git a/glpk-5.0/src/api/prob2.c b/glpk-5.0/src/api/prob2.c new file mode 100644 index 0000000..f54a803 --- /dev/null +++ b/glpk-5.0/src/api/prob2.c @@ -0,0 +1,489 @@ +/* prob2.c (problem retrieving routines) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2000-2013 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +/*********************************************************************** +*  NAME +* +*  glp_get_prob_name - retrieve problem name +* +*  SYNOPSIS +* +*  const char *glp_get_prob_name(glp_prob *lp); +* +*  RETURNS +* +*  The routine glp_get_prob_name returns a pointer to an internal +*  buffer, which contains symbolic name of the problem. However, if the +*  problem has no assigned name, the routine returns NULL. */ + +const char *glp_get_prob_name(glp_prob *lp) +{     char *name; +      name = lp->name; +      return name; +} + +/*********************************************************************** +*  NAME +* +*  glp_get_obj_name - retrieve objective function name +* +*  SYNOPSIS +* +*  const char *glp_get_obj_name(glp_prob *lp); +* +*  RETURNS +* +*  The routine glp_get_obj_name returns a pointer to an internal +*  buffer, which contains a symbolic name of the objective function. +*  However, if the objective function has no assigned name, the routine +*  returns NULL. */ + +const char *glp_get_obj_name(glp_prob *lp) +{     char *name; +      name = lp->obj; +      return name; +} + +/*********************************************************************** +*  NAME +* +*  glp_get_obj_dir - retrieve optimization direction flag +* +*  SYNOPSIS +* +*  int glp_get_obj_dir(glp_prob *lp); +* +*  RETURNS +* +*  The routine glp_get_obj_dir returns the optimization direction flag +*  (i.e. "sense" of the objective function): +* +*  GLP_MIN - minimization; +*  GLP_MAX - maximization. */ + +int glp_get_obj_dir(glp_prob *lp) +{     int dir = lp->dir; +      return dir; +} + +/*********************************************************************** +*  NAME +* +*  glp_get_num_rows - retrieve number of rows +* +*  SYNOPSIS +* +*  int glp_get_num_rows(glp_prob *lp); +* +*  RETURNS +* +*  The routine glp_get_num_rows returns the current number of rows in +*  the specified problem object. */ + +int glp_get_num_rows(glp_prob *lp) +{     int m = lp->m; +      return m; +} + +/*********************************************************************** +*  NAME +* +*  glp_get_num_cols - retrieve number of columns +* +*  SYNOPSIS +* +*  int glp_get_num_cols(glp_prob *lp); +* +*  RETURNS +* +*  The routine glp_get_num_cols returns the current number of columns +*  in the specified problem object. */ + +int glp_get_num_cols(glp_prob *lp) +{     int n = lp->n; +      return n; +} + +/*********************************************************************** +*  NAME +* +*  glp_get_row_name - retrieve row name +* +*  SYNOPSIS +* +*  const char *glp_get_row_name(glp_prob *lp, int i); +* +*  RETURNS +* +*  The routine glp_get_row_name returns a pointer to an internal +*  buffer, which contains symbolic name of i-th row. However, if i-th +*  row has no assigned name, the routine returns NULL. */ + +const char *glp_get_row_name(glp_prob *lp, int i) +{     char *name; +      if (!(1 <= i && i <= lp->m)) +         xerror("glp_get_row_name: i = %d; row number out of range\n", +            i); +      name = lp->row[i]->name; +      return name; +} + +/*********************************************************************** +*  NAME +* +*  glp_get_col_name - retrieve column name +* +*  SYNOPSIS +* +*  const char *glp_get_col_name(glp_prob *lp, int j); +* +*  RETURNS +* +*  The routine glp_get_col_name returns a pointer to an internal +*  buffer, which contains symbolic name of j-th column. However, if j-th +*  column has no assigned name, the routine returns NULL. */ + +const char *glp_get_col_name(glp_prob *lp, int j) +{     char *name; +      if (!(1 <= j && j <= lp->n)) +         xerror("glp_get_col_name: j = %d; column number out of range\n" +            , j); +      name = lp->col[j]->name; +      return name; +} + +/*********************************************************************** +*  NAME +* +*  glp_get_row_type - retrieve row type +* +*  SYNOPSIS +* +*  int glp_get_row_type(glp_prob *lp, int i); +* +*  RETURNS +* +*  The routine glp_get_row_type returns the type of i-th row, i.e. the +*  type of corresponding auxiliary variable, as follows: +* +*  GLP_FR - free (unbounded) variable; +*  GLP_LO - variable with lower bound; +*  GLP_UP - variable with upper bound; +*  GLP_DB - double-bounded variable; +*  GLP_FX - fixed variable. */ + +int glp_get_row_type(glp_prob *lp, int i) +{     if (!(1 <= i && i <= lp->m)) +         xerror("glp_get_row_type: i = %d; row number out of range\n", +            i); +      return lp->row[i]->type; +} + +/*********************************************************************** +*  NAME +* +*  glp_get_row_lb - retrieve row lower bound +* +*  SYNOPSIS +* +*  double glp_get_row_lb(glp_prob *lp, int i); +* +*  RETURNS +* +*  The routine glp_get_row_lb returns the lower bound of i-th row, i.e. +*  the lower bound of corresponding auxiliary variable. However, if the +*  row has no lower bound, the routine returns -DBL_MAX. */ + +double glp_get_row_lb(glp_prob *lp, int i) +{     double lb; +      if (!(1 <= i && i <= lp->m)) +         xerror("glp_get_row_lb: i = %d; row number out of range\n", i); +      switch (lp->row[i]->type) +      {  case GLP_FR: +         case GLP_UP: +            lb = -DBL_MAX; break; +         case GLP_LO: +         case GLP_DB: +         case GLP_FX: +            lb = lp->row[i]->lb; break; +         default: +            xassert(lp != lp); +      } +      return lb; +} + +/*********************************************************************** +*  NAME +* +*  glp_get_row_ub - retrieve row upper bound +* +*  SYNOPSIS +* +*  double glp_get_row_ub(glp_prob *lp, int i); +* +*  RETURNS +* +*  The routine glp_get_row_ub returns the upper bound of i-th row, i.e. +*  the upper bound of corresponding auxiliary variable. However, if the +*  row has no upper bound, the routine returns +DBL_MAX. */ + +double glp_get_row_ub(glp_prob *lp, int i) +{     double ub; +      if (!(1 <= i && i <= lp->m)) +         xerror("glp_get_row_ub: i = %d; row number out of range\n", i); +      switch (lp->row[i]->type) +      {  case GLP_FR: +         case GLP_LO: +            ub = +DBL_MAX; break; +         case GLP_UP: +         case GLP_DB: +         case GLP_FX: +            ub = lp->row[i]->ub; break; +         default: +            xassert(lp != lp); +      } +      return ub; +} + +/*********************************************************************** +*  NAME +* +*  glp_get_col_type - retrieve column type +* +*  SYNOPSIS +* +*  int glp_get_col_type(glp_prob *lp, int j); +* +*  RETURNS +* +*  The routine glp_get_col_type returns the type of j-th column, i.e. +*  the type of corresponding structural variable, as follows: +* +*  GLP_FR - free (unbounded) variable; +*  GLP_LO - variable with lower bound; +*  GLP_UP - variable with upper bound; +*  GLP_DB - double-bounded variable; +*  GLP_FX - fixed variable. */ + +int glp_get_col_type(glp_prob *lp, int j) +{     if (!(1 <= j && j <= lp->n)) +         xerror("glp_get_col_type: j = %d; column number out of range\n" +            , j); +      return lp->col[j]->type; +} + +/*********************************************************************** +*  NAME +* +*  glp_get_col_lb - retrieve column lower bound +* +*  SYNOPSIS +* +*  double glp_get_col_lb(glp_prob *lp, int j); +* +*  RETURNS +* +*  The routine glp_get_col_lb returns the lower bound of j-th column, +*  i.e. the lower bound of corresponding structural variable. However, +*  if the column has no lower bound, the routine returns -DBL_MAX. */ + +double glp_get_col_lb(glp_prob *lp, int j) +{     double lb; +      if (!(1 <= j && j <= lp->n)) +         xerror("glp_get_col_lb: j = %d; column number out of range\n", +            j); +      switch (lp->col[j]->type) +      {  case GLP_FR: +         case GLP_UP: +            lb = -DBL_MAX; break; +         case GLP_LO: +         case GLP_DB: +         case GLP_FX: +            lb = lp->col[j]->lb; break; +         default: +            xassert(lp != lp); +      } +      return lb; +} + +/*********************************************************************** +*  NAME +* +*  glp_get_col_ub - retrieve column upper bound +* +*  SYNOPSIS +* +*  double glp_get_col_ub(glp_prob *lp, int j); +* +*  RETURNS +* +*  The routine glp_get_col_ub returns the upper bound of j-th column, +*  i.e. the upper bound of corresponding structural variable. However, +*  if the column has no upper bound, the routine returns +DBL_MAX. */ + +double glp_get_col_ub(glp_prob *lp, int j) +{     double ub; +      if (!(1 <= j && j <= lp->n)) +         xerror("glp_get_col_ub: j = %d; column number out of range\n", +            j); +      switch (lp->col[j]->type) +      {  case GLP_FR: +         case GLP_LO: +            ub = +DBL_MAX; break; +         case GLP_UP: +         case GLP_DB: +         case GLP_FX: +            ub = lp->col[j]->ub; break; +         default: +            xassert(lp != lp); +      } +      return ub; +} + +/*********************************************************************** +*  NAME +* +*  glp_get_obj_coef - retrieve obj. coefficient or constant term +* +*  SYNOPSIS +* +*  double glp_get_obj_coef(glp_prob *lp, int j); +* +*  RETURNS +* +*  The routine glp_get_obj_coef returns the objective coefficient at +*  j-th structural variable (column) of the specified problem object. +* +*  If the parameter j is zero, the routine returns the constant term +*  ("shift") of the objective function. */ + +double glp_get_obj_coef(glp_prob *lp, int j) +{     if (!(0 <= j && j <= lp->n)) +         xerror("glp_get_obj_coef: j = %d; column number out of range\n" +            , j); +      return j == 0 ? lp->c0 : lp->col[j]->coef; +} + +/*********************************************************************** +*  NAME +* +*  glp_get_num_nz - retrieve number of constraint coefficients +* +*  SYNOPSIS +* +*  int glp_get_num_nz(glp_prob *lp); +* +*  RETURNS +* +*  The routine glp_get_num_nz returns the number of (non-zero) elements +*  in the constraint matrix of the specified problem object. */ + +int glp_get_num_nz(glp_prob *lp) +{     int nnz = lp->nnz; +      return nnz; +} + +/*********************************************************************** +*  NAME +* +*  glp_get_mat_row - retrieve row of the constraint matrix +* +*  SYNOPSIS +* +*  int glp_get_mat_row(glp_prob *lp, int i, int ind[], double val[]); +* +*  DESCRIPTION +* +*  The routine glp_get_mat_row scans (non-zero) elements of i-th row +*  of the constraint matrix of the specified problem object and stores +*  their column indices and numeric values to locations ind[1], ..., +*  ind[len] and val[1], ..., val[len], respectively, where 0 <= len <= n +*  is the number of elements in i-th row, n is the number of columns. +* +*  The parameter ind and/or val can be specified as NULL, in which case +*  corresponding information is not stored. +* +*  RETURNS +* +*  The routine glp_get_mat_row returns the length len, i.e. the number +*  of (non-zero) elements in i-th row. */ + +int glp_get_mat_row(glp_prob *lp, int i, int ind[], double val[]) +{     GLPAIJ *aij; +      int len; +      if (!(1 <= i && i <= lp->m)) +         xerror("glp_get_mat_row: i = %d; row number out of range\n", +            i); +      len = 0; +      for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next) +      {  len++; +         if (ind != NULL) ind[len] = aij->col->j; +         if (val != NULL) val[len] = aij->val; +      } +      xassert(len <= lp->n); +      return len; +} + +/*********************************************************************** +*  NAME +* +*  glp_get_mat_col - retrieve column of the constraint matrix +* +*  SYNOPSIS +* +*  int glp_get_mat_col(glp_prob *lp, int j, int ind[], double val[]); +* +*  DESCRIPTION +* +*  The routine glp_get_mat_col scans (non-zero) elements of j-th column +*  of the constraint matrix of the specified problem object and stores +*  their row indices and numeric values to locations ind[1], ..., +*  ind[len] and val[1], ..., val[len], respectively, where 0 <= len <= m +*  is the number of elements in j-th column, m is the number of rows. +* +*  The parameter ind or/and val can be specified as NULL, in which case +*  corresponding information is not stored. +* +*  RETURNS +* +*  The routine glp_get_mat_col returns the length len, i.e. the number +*  of (non-zero) elements in j-th column. */ + +int glp_get_mat_col(glp_prob *lp, int j, int ind[], double val[]) +{     GLPAIJ *aij; +      int len; +      if (!(1 <= j && j <= lp->n)) +         xerror("glp_get_mat_col: j = %d; column number out of range\n", +            j); +      len = 0; +      for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next) +      {  len++; +         if (ind != NULL) ind[len] = aij->row->i; +         if (val != NULL) val[len] = aij->val; +      } +      xassert(len <= lp->m); +      return len; +} + +/* eof */ diff --git a/glpk-5.0/src/api/prob3.c b/glpk-5.0/src/api/prob3.c new file mode 100644 index 0000000..16fc852 --- /dev/null +++ b/glpk-5.0/src/api/prob3.c @@ -0,0 +1,164 @@ +/* prob3.c (problem row/column searching routines) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2000-2013 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +/*********************************************************************** +*  NAME +* +*  glp_create_index - create the name index +* +*  SYNOPSIS +* +*  void glp_create_index(glp_prob *lp); +* +*  DESCRIPTION +* +*  The routine glp_create_index creates the name index for the +*  specified problem object. The name index is an auxiliary data +*  structure, which is intended to quickly (i.e. for logarithmic time) +*  find rows and columns by their names. +* +*  This routine can be called at any time. If the name index already +*  exists, the routine does nothing. */ + +void glp_create_index(glp_prob *lp) +{     GLPROW *row; +      GLPCOL *col; +      int i, j; +      /* create row name index */ +      if (lp->r_tree == NULL) +      {  lp->r_tree = avl_create_tree(avl_strcmp, NULL); +         for (i = 1; i <= lp->m; i++) +         {  row = lp->row[i]; +            xassert(row->node == NULL); +            if (row->name != NULL) +            {  row->node = avl_insert_node(lp->r_tree, row->name); +               avl_set_node_link(row->node, row); +            } +         } +      } +      /* create column name index */ +      if (lp->c_tree == NULL) +      {  lp->c_tree = avl_create_tree(avl_strcmp, NULL); +         for (j = 1; j <= lp->n; j++) +         {  col = lp->col[j]; +            xassert(col->node == NULL); +            if (col->name != NULL) +            {  col->node = avl_insert_node(lp->c_tree, col->name); +               avl_set_node_link(col->node, col); +            } +         } +      } +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_find_row - find row by its name +* +*  SYNOPSIS +* +*  int glp_find_row(glp_prob *lp, const char *name); +* +*  RETURNS +* +*  The routine glp_find_row returns the ordinal number of a row, +*  which is assigned (by the routine glp_set_row_name) the specified +*  symbolic name. If no such row exists, the routine returns 0. */ + +int glp_find_row(glp_prob *lp, const char *name) +{     AVLNODE *node; +      int i = 0; +      if (lp->r_tree == NULL) +         xerror("glp_find_row: row name index does not exist\n"); +      if (!(name == NULL || name[0] == '\0' || strlen(name) > 255)) +      {  node = avl_find_node(lp->r_tree, name); +         if (node != NULL) +            i = ((GLPROW *)avl_get_node_link(node))->i; +      } +      return i; +} + +/*********************************************************************** +*  NAME +* +*  glp_find_col - find column by its name +* +*  SYNOPSIS +* +*  int glp_find_col(glp_prob *lp, const char *name); +* +*  RETURNS +* +*  The routine glp_find_col returns the ordinal number of a column, +*  which is assigned (by the routine glp_set_col_name) the specified +*  symbolic name. If no such column exists, the routine returns 0. */ + +int glp_find_col(glp_prob *lp, const char *name) +{     AVLNODE *node; +      int j = 0; +      if (lp->c_tree == NULL) +         xerror("glp_find_col: column name index does not exist\n"); +      if (!(name == NULL || name[0] == '\0' || strlen(name) > 255)) +      {  node = avl_find_node(lp->c_tree, name); +         if (node != NULL) +            j = ((GLPCOL *)avl_get_node_link(node))->j; +      } +      return j; +} + +/*********************************************************************** +*  NAME +* +*  glp_delete_index - delete the name index +* +*  SYNOPSIS +* +*  void glp_delete_index(glp_prob *lp); +* +*  DESCRIPTION +* +*  The routine glp_delete_index deletes the name index previously +*  created by the routine glp_create_index and frees the memory +*  allocated to this auxiliary data structure. +* +*  This routine can be called at any time. If the name index does not +*  exist, the routine does nothing. */ + +void glp_delete_index(glp_prob *lp) +{     int i, j; +      /* delete row name index */ +      if (lp->r_tree != NULL) +      {  for (i = 1; i <= lp->m; i++) lp->row[i]->node = NULL; +         avl_delete_tree(lp->r_tree), lp->r_tree = NULL; +      } +      /* delete column name index */ +      if (lp->c_tree != NULL) +      {  for (j = 1; j <= lp->n; j++) lp->col[j]->node = NULL; +         avl_delete_tree(lp->c_tree), lp->c_tree = NULL; +      } +      return; +} + +/* eof */ diff --git a/glpk-5.0/src/api/prob4.c b/glpk-5.0/src/api/prob4.c new file mode 100644 index 0000000..6a45161 --- /dev/null +++ b/glpk-5.0/src/api/prob4.c @@ -0,0 +1,154 @@ +/* prob4.c (problem scaling routines) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2000-2013 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +/*********************************************************************** +*  NAME +* +*  glp_set_rii - set (change) row scale factor +* +*  SYNOPSIS +* +*  void glp_set_rii(glp_prob *lp, int i, double rii); +* +*  DESCRIPTION +* +*  The routine glp_set_rii sets (changes) the scale factor r[i,i] for +*  i-th row of the specified problem object. */ + +void glp_set_rii(glp_prob *lp, int i, double rii) +{     if (!(1 <= i && i <= lp->m)) +         xerror("glp_set_rii: i = %d; row number out of range\n", i); +      if (rii <= 0.0) +         xerror("glp_set_rii: i = %d; rii = %g; invalid scale factor\n", +            i, rii); +      if (lp->valid && lp->row[i]->rii != rii) +      {  GLPAIJ *aij; +         for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next) +         {  if (aij->col->stat == GLP_BS) +            {  /* invalidate the basis factorization */ +               lp->valid = 0; +               break; +            } +         } +      } +      lp->row[i]->rii = rii; +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_set sjj - set (change) column scale factor +* +*  SYNOPSIS +* +*  void glp_set_sjj(glp_prob *lp, int j, double sjj); +* +*  DESCRIPTION +* +*  The routine glp_set_sjj sets (changes) the scale factor s[j,j] for +*  j-th column of the specified problem object. */ + +void glp_set_sjj(glp_prob *lp, int j, double sjj) +{     if (!(1 <= j && j <= lp->n)) +         xerror("glp_set_sjj: j = %d; column number out of range\n", j); +      if (sjj <= 0.0) +         xerror("glp_set_sjj: j = %d; sjj = %g; invalid scale factor\n", +            j, sjj); +      if (lp->valid && lp->col[j]->sjj != sjj && lp->col[j]->stat == +         GLP_BS) +      {  /* invalidate the basis factorization */ +         lp->valid = 0; +      } +      lp->col[j]->sjj = sjj; +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_get_rii - retrieve row scale factor +* +*  SYNOPSIS +* +*  double glp_get_rii(glp_prob *lp, int i); +* +*  RETURNS +* +*  The routine glp_get_rii returns current scale factor r[i,i] for i-th +*  row of the specified problem object. */ + +double glp_get_rii(glp_prob *lp, int i) +{     if (!(1 <= i && i <= lp->m)) +         xerror("glp_get_rii: i = %d; row number out of range\n", i); +      return lp->row[i]->rii; +} + +/*********************************************************************** +*  NAME +* +*  glp_get_sjj - retrieve column scale factor +* +*  SYNOPSIS +* +*  double glp_get_sjj(glp_prob *lp, int j); +* +*  RETURNS +* +*  The routine glp_get_sjj returns current scale factor s[j,j] for j-th +*  column of the specified problem object. */ + +double glp_get_sjj(glp_prob *lp, int j) +{     if (!(1 <= j && j <= lp->n)) +         xerror("glp_get_sjj: j = %d; column number out of range\n", j); +      return lp->col[j]->sjj; +} + +/*********************************************************************** +*  NAME +* +*  glp_unscale_prob - unscale problem data +* +*  SYNOPSIS +* +*  void glp_unscale_prob(glp_prob *lp); +* +*  DESCRIPTION +* +*  The routine glp_unscale_prob performs unscaling of problem data for +*  the specified problem object. +* +*  "Unscaling" means replacing the current scaling matrices R and S by +*  unity matrices that cancels the scaling effect. */ + +void glp_unscale_prob(glp_prob *lp) +{     int m = glp_get_num_rows(lp); +      int n = glp_get_num_cols(lp); +      int i, j; +      for (i = 1; i <= m; i++) glp_set_rii(lp, i, 1.0); +      for (j = 1; j <= n; j++) glp_set_sjj(lp, j, 1.0); +      return; +} + +/* eof */ diff --git a/glpk-5.0/src/api/prob5.c b/glpk-5.0/src/api/prob5.c new file mode 100644 index 0000000..c15d048 --- /dev/null +++ b/glpk-5.0/src/api/prob5.c @@ -0,0 +1,166 @@ +/* prob5.c (LP problem basis constructing routines) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2000-2013 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +/*********************************************************************** +*  NAME +* +*  glp_set_row_stat - set (change) row status +* +*  SYNOPSIS +* +*  void glp_set_row_stat(glp_prob *lp, int i, int stat); +* +*  DESCRIPTION +* +*  The routine glp_set_row_stat sets (changes) status of the auxiliary +*  variable associated with i-th row. +* +*  The new status of the auxiliary variable should be specified by the +*  parameter stat as follows: +* +*  GLP_BS - basic variable; +*  GLP_NL - non-basic variable; +*  GLP_NU - non-basic variable on its upper bound; if the variable is +*           not double-bounded, this means the same as GLP_NL (only in +*           case of this routine); +*  GLP_NF - the same as GLP_NL (only in case of this routine); +*  GLP_NS - the same as GLP_NL (only in case of this routine). */ + +void glp_set_row_stat(glp_prob *lp, int i, int stat) +{     GLPROW *row; +      if (!(1 <= i && i <= lp->m)) +         xerror("glp_set_row_stat: i = %d; row number out of range\n", +            i); +      if (!(stat == GLP_BS || stat == GLP_NL || stat == GLP_NU || +            stat == GLP_NF || stat == GLP_NS)) +         xerror("glp_set_row_stat: i = %d; stat = %d; invalid status\n", +            i, stat); +      row = lp->row[i]; +      if (stat != GLP_BS) +      {  switch (row->type) +         {  case GLP_FR: stat = GLP_NF; break; +            case GLP_LO: stat = GLP_NL; break; +            case GLP_UP: stat = GLP_NU; break; +            case GLP_DB: if (stat != GLP_NU) stat = GLP_NL; break; +            case GLP_FX: stat = GLP_NS; break; +            default: xassert(row != row); +         } +      } +      if (row->stat == GLP_BS && stat != GLP_BS || +          row->stat != GLP_BS && stat == GLP_BS) +      {  /* invalidate the basis factorization */ +         lp->valid = 0; +      } +      row->stat = stat; +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_set_col_stat - set (change) column status +* +*  SYNOPSIS +* +*  void glp_set_col_stat(glp_prob *lp, int j, int stat); +* +*  DESCRIPTION +* +*  The routine glp_set_col_stat sets (changes) status of the structural +*  variable associated with j-th column. +* +*  The new status of the structural variable should be specified by the +*  parameter stat as follows: +* +*  GLP_BS - basic variable; +*  GLP_NL - non-basic variable; +*  GLP_NU - non-basic variable on its upper bound; if the variable is +*           not double-bounded, this means the same as GLP_NL (only in +*           case of this routine); +*  GLP_NF - the same as GLP_NL (only in case of this routine); +*  GLP_NS - the same as GLP_NL (only in case of this routine). */ + +void glp_set_col_stat(glp_prob *lp, int j, int stat) +{     GLPCOL *col; +      if (!(1 <= j && j <= lp->n)) +         xerror("glp_set_col_stat: j = %d; column number out of range\n" +            , j); +      if (!(stat == GLP_BS || stat == GLP_NL || stat == GLP_NU || +            stat == GLP_NF || stat == GLP_NS)) +         xerror("glp_set_col_stat: j = %d; stat = %d; invalid status\n", +            j, stat); +      col = lp->col[j]; +      if (stat != GLP_BS) +      {  switch (col->type) +         {  case GLP_FR: stat = GLP_NF; break; +            case GLP_LO: stat = GLP_NL; break; +            case GLP_UP: stat = GLP_NU; break; +            case GLP_DB: if (stat != GLP_NU) stat = GLP_NL; break; +            case GLP_FX: stat = GLP_NS; break; +            default: xassert(col != col); +         } +      } +      if (col->stat == GLP_BS && stat != GLP_BS || +          col->stat != GLP_BS && stat == GLP_BS) +      {  /* invalidate the basis factorization */ +         lp->valid = 0; +      } +      col->stat = stat; +      return; +} + +/*********************************************************************** +*  NAME +* +*  glp_std_basis - construct standard initial LP basis +* +*  SYNOPSIS +* +*  void glp_std_basis(glp_prob *lp); +* +*  DESCRIPTION +* +*  The routine glp_std_basis builds the "standard" (trivial) initial +*  basis for the specified problem object. +* +*  In the "standard" basis all auxiliary variables are basic, and all +*  structural variables are non-basic. */ + +void glp_std_basis(glp_prob *lp) +{     int i, j; +      /* make all auxiliary variables basic */ +      for (i = 1; i <= lp->m; i++) +         glp_set_row_stat(lp, i, GLP_BS); +      /* make all structural variables non-basic */ +      for (j = 1; j <= lp->n; j++) +      {  GLPCOL *col = lp->col[j]; +         if (col->type == GLP_DB && fabs(col->lb) > fabs(col->ub)) +            glp_set_col_stat(lp, j, GLP_NU); +         else +            glp_set_col_stat(lp, j, GLP_NL); +      } +      return; +} + +/* eof */ diff --git a/glpk-5.0/src/api/prrngs.c b/glpk-5.0/src/api/prrngs.c new file mode 100644 index 0000000..962614a --- /dev/null +++ b/glpk-5.0/src/api/prrngs.c @@ -0,0 +1,300 @@ +/* prrngs.c (print sensitivity analysis report) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +#define xfprintf glp_format + +static char *format(char buf[13+1], double x) +{     /* format floating-point number in MPS/360-like style */ +      if (x == -DBL_MAX) +         strcpy(buf, "         -Inf"); +      else if (x == +DBL_MAX) +         strcpy(buf, "         +Inf"); +      else if (fabs(x) <= 999999.99998) +      {  sprintf(buf, "%13.5f", x); +#if 1 +         if (strcmp(buf, "      0.00000") == 0 || +             strcmp(buf, "     -0.00000") == 0) +            strcpy(buf, "       .     "); +         else if (memcmp(buf, "      0.", 8) == 0) +            memcpy(buf, "       .", 8); +         else if (memcmp(buf, "     -0.", 8) == 0) +            memcpy(buf, "      -.", 8); +#endif +      } +      else +         sprintf(buf, "%13.6g", x); +      return buf; +} + +int glp_print_ranges(glp_prob *P, int len, const int list[], +      int flags, const char *fname) +{     /* print sensitivity analysis report */ +      glp_file *fp = NULL; +      GLPROW *row; +      GLPCOL *col; +      int m, n, pass, k, t, numb, type, stat, var1, var2, count, page, +         ret; +      double lb, ub, slack, coef, prim, dual, value1, value2, coef1, +         coef2, obj1, obj2; +      const char *name, *limit; +      char buf[13+1]; +      /* sanity checks */ +#if 0 /* 04/IV-2016 */ +      if (P == NULL || P->magic != GLP_PROB_MAGIC) +         xerror("glp_print_ranges: P = %p; invalid problem object\n", +            P); +#endif +      m = P->m, n = P->n; +      if (len < 0) +         xerror("glp_print_ranges: len = %d; invalid list length\n", +            len); +      if (len > 0) +      {  if (list == NULL) +            xerror("glp_print_ranges: list = %p: invalid parameter\n", +               list); +         for (t = 1; t <= len; t++) +         {  k = list[t]; +            if (!(1 <= k && k <= m+n)) +               xerror("glp_print_ranges: list[%d] = %d; row/column numb" +                  "er out of range\n", t, k); +         } +      } +      if (flags != 0) +         xerror("glp_print_ranges: flags = %d; invalid parameter\n", +            flags); +      if (fname == NULL) +         xerror("glp_print_ranges: fname = %p; invalid parameter\n", +            fname); +      if (glp_get_status(P) != GLP_OPT) +      {  xprintf("glp_print_ranges: optimal basic solution required\n"); +         ret = 1; +         goto done; +      } +      if (!glp_bf_exists(P)) +      {  xprintf("glp_print_ranges: basis factorization required\n"); +         ret = 2; +         goto done; +      } +      /* start reporting */ +      xprintf("Write sensitivity analysis report to '%s'...\n", fname); +      fp = glp_open(fname, "w"); +      if (fp == NULL) +      {  xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); +         ret = 3; +         goto done; +      } +      page = count = 0; +      for (pass = 1; pass <= 2; pass++) +      for (t = 1; t <= (len == 0 ? m+n : len); t++) +      {  if (t == 1) count = 0; +         k = (len == 0 ? t : list[t]); +         if (pass == 1 && k > m || pass == 2 && k <= m) +            continue; +         if (count == 0) +         {  xfprintf(fp, "GLPK %-4s - SENSITIVITY ANALYSIS REPORT%73sPa" +               "ge%4d\n", glp_version(), "", ++page); +            xfprintf(fp, "\n"); +            xfprintf(fp, "%-12s%s\n", "Problem:", +               P->name == NULL ? "" : P->name); +            xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:", +               P->obj == NULL ? "" : P->obj, +               P->obj == NULL ? "" : " = ", P->obj_val, +               P->dir == GLP_MIN ? "MINimum" : +               P->dir == GLP_MAX ? "MAXimum" : "???"); +            xfprintf(fp, "\n"); +            xfprintf(fp, "%6s %-12s %2s %13s %13s %13s  %13s %13s %13s " +               "%s\n", "No.", pass == 1 ? "Row name" : "Column name", +               "St", "Activity", pass == 1 ? "Slack" : "Obj coef", +               "Lower bound", "Activity", "Obj coef", "Obj value at", +               "Limiting"); +            xfprintf(fp, "%6s %-12s %2s %13s %13s %13s  %13s %13s %13s " +               "%s\n", "", "", "", "", "Marginal", "Upper bound", +               "range", "range", "break point", "variable"); +            xfprintf(fp, "------ ------------ -- ------------- --------" +               "----- -------------  ------------- ------------- ------" +               "------- ------------\n"); +         } +         if (pass == 1) +         {  numb = k; +            xassert(1 <= numb && numb <= m); +            row = P->row[numb]; +            name = row->name; +            type = row->type; +            lb = glp_get_row_lb(P, numb); +            ub = glp_get_row_ub(P, numb); +            coef = 0.0; +            stat = row->stat; +            prim = row->prim; +            if (type == GLP_FR) +               slack = - prim; +            else if (type == GLP_LO) +               slack = lb - prim; +            else if (type == GLP_UP || type == GLP_DB || type == GLP_FX) +               slack = ub - prim; +            dual = row->dual; +         } +         else +         {  numb = k - m; +            xassert(1 <= numb && numb <= n); +            col = P->col[numb]; +            name = col->name; +            lb = glp_get_col_lb(P, numb); +            ub = glp_get_col_ub(P, numb); +            coef = col->coef; +            stat = col->stat; +            prim = col->prim; +            slack = 0.0; +            dual = col->dual; +         } +         if (stat != GLP_BS) +         {  glp_analyze_bound(P, k, &value1, &var1, &value2, &var2); +            if (stat == GLP_NF) +               coef1 = coef2 = coef; +            else if (stat == GLP_NS) +               coef1 = -DBL_MAX, coef2 = +DBL_MAX; +            else if (stat == GLP_NL && P->dir == GLP_MIN || +                     stat == GLP_NU && P->dir == GLP_MAX) +               coef1 = coef - dual, coef2 = +DBL_MAX; +            else +               coef1 = -DBL_MAX, coef2 = coef - dual; +            if (value1 == -DBL_MAX) +            {  if (dual < -1e-9) +                  obj1 = +DBL_MAX; +               else if (dual > +1e-9) +                  obj1 = -DBL_MAX; +               else +                  obj1 = P->obj_val; +            } +            else +               obj1 = P->obj_val + dual * (value1 - prim); +            if (value2 == +DBL_MAX) +            {  if (dual < -1e-9) +                  obj2 = -DBL_MAX; +               else if (dual > +1e-9) +                  obj2 = +DBL_MAX; +               else +                  obj2 = P->obj_val; +            } +            else +               obj2 = P->obj_val + dual * (value2 - prim); +         } +         else +         {  glp_analyze_coef(P, k, &coef1, &var1, &value1, &coef2, +               &var2, &value2); +            if (coef1 == -DBL_MAX) +            {  if (prim < -1e-9) +                  obj1 = +DBL_MAX; +               else if (prim > +1e-9) +                  obj1 = -DBL_MAX; +               else +                  obj1 = P->obj_val; +            } +            else +               obj1 = P->obj_val + (coef1 - coef) * prim; +            if (coef2 == +DBL_MAX) +            {  if (prim < -1e-9) +                  obj2 = -DBL_MAX; +               else if (prim > +1e-9) +                  obj2 = +DBL_MAX; +               else +                  obj2 = P->obj_val; +            } +            else +               obj2 = P->obj_val + (coef2 - coef) * prim; +         } +         /*** first line ***/ +         /* row/column number */ +         xfprintf(fp, "%6d", numb); +         /* row/column name */ +         xfprintf(fp, " %-12.12s", name == NULL ? "" : name); +         if (name != NULL && strlen(name) > 12) +            xfprintf(fp, "%s\n%6s %12s", name+12, "", ""); +         /* row/column status */ +         xfprintf(fp, " %2s", +            stat == GLP_BS ? "BS" : stat == GLP_NL ? "NL" : +            stat == GLP_NU ? "NU" : stat == GLP_NF ? "NF" : +            stat == GLP_NS ? "NS" : "??"); +         /* row/column activity */ +         xfprintf(fp, " %s", format(buf, prim)); +         /* row slack, column objective coefficient */ +         xfprintf(fp, " %s", format(buf, k <= m ? slack : coef)); +         /* row/column lower bound */ +         xfprintf(fp, " %s", format(buf, lb)); +         /* row/column activity range */ +         xfprintf(fp, "  %s", format(buf, value1)); +         /* row/column objective coefficient range */ +         xfprintf(fp, " %s", format(buf, coef1)); +         /* objective value at break point */ +         xfprintf(fp, " %s", format(buf, obj1)); +         /* limiting variable name */ +         if (var1 != 0) +         {  if (var1 <= m) +               limit = glp_get_row_name(P, var1); +            else +               limit = glp_get_col_name(P, var1 - m); +            if (limit != NULL) +               xfprintf(fp, " %s", limit); +         } +         xfprintf(fp, "\n"); +         /*** second line ***/ +         xfprintf(fp, "%6s %-12s %2s %13s", "", "", "", ""); +         /* row/column reduced cost */ +         xfprintf(fp, " %s", format(buf, dual)); +         /* row/column upper bound */ +         xfprintf(fp, " %s", format(buf, ub)); +         /* row/column activity range */ +         xfprintf(fp, "  %s", format(buf, value2)); +         /* row/column objective coefficient range */ +         xfprintf(fp, " %s", format(buf, coef2)); +         /* objective value at break point */ +         xfprintf(fp, " %s", format(buf, obj2)); +         /* limiting variable name */ +         if (var2 != 0) +         {  if (var2 <= m) +               limit = glp_get_row_name(P, var2); +            else +               limit = glp_get_col_name(P, var2 - m); +            if (limit != NULL) +               xfprintf(fp, " %s", limit); +         } +         xfprintf(fp, "\n"); +         xfprintf(fp, "\n"); +         /* print 10 items per page */ +         count = (count + 1) % 10; +      } +      xfprintf(fp, "End of report\n"); +#if 0 /* FIXME */ +      xfflush(fp); +#endif +      if (glp_ioerr(fp)) +      {  xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); +         ret = 4; +         goto done; +      } +      ret = 0; +done: if (fp != NULL) glp_close(fp); +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/prsol.c b/glpk-5.0/src/api/prsol.c new file mode 100644 index 0000000..4ba6730 --- /dev/null +++ b/glpk-5.0/src/api/prsol.c @@ -0,0 +1,200 @@ +/* prsol.c (write basic solution in printable format) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +#define xfprintf glp_format + +int glp_print_sol(glp_prob *P, const char *fname) +{     /* write basic solution in printable format */ +      glp_file *fp; +      GLPROW *row; +      GLPCOL *col; +      int i, j, t, ae_ind, re_ind, ret; +      double ae_max, re_max; +      xprintf("Writing basic solution to '%s'...\n", fname); +      fp = glp_open(fname, "w"); +      if (fp == NULL) +      {  xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); +         ret = 1; +         goto done; +      } +      xfprintf(fp, "%-12s%s\n", "Problem:", +         P->name == NULL ? "" : P->name); +      xfprintf(fp, "%-12s%d\n", "Rows:", P->m); +      xfprintf(fp, "%-12s%d\n", "Columns:", P->n); +      xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz); +      t = glp_get_status(P); +      xfprintf(fp, "%-12s%s\n", "Status:", +         t == GLP_OPT    ? "OPTIMAL" : +         t == GLP_FEAS   ? "FEASIBLE" : +         t == GLP_INFEAS ? "INFEASIBLE (INTERMEDIATE)" : +         t == GLP_NOFEAS ? "INFEASIBLE (FINAL)" : +         t == GLP_UNBND  ? "UNBOUNDED" : +         t == GLP_UNDEF  ? "UNDEFINED" : "???"); +      xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:", +         P->obj == NULL ? "" : P->obj, +         P->obj == NULL ? "" : " = ", P->obj_val, +         P->dir == GLP_MIN ? "MINimum" : +         P->dir == GLP_MAX ? "MAXimum" : "???"); +      xfprintf(fp, "\n"); +      xfprintf(fp, "   No.   Row name   St   Activity     Lower bound  " +         " Upper bound    Marginal\n"); +      xfprintf(fp, "------ ------------ -- ------------- ------------- " +         "------------- -------------\n"); +      for (i = 1; i <= P->m; i++) +      {  row = P->row[i]; +         xfprintf(fp, "%6d ", i); +         if (row->name == NULL || strlen(row->name) <= 12) +            xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name); +         else +            xfprintf(fp, "%s\n%20s", row->name, ""); +         xfprintf(fp, "%s ", +            row->stat == GLP_BS ? "B " : +            row->stat == GLP_NL ? "NL" : +            row->stat == GLP_NU ? "NU" : +            row->stat == GLP_NF ? "NF" : +            row->stat == GLP_NS ? "NS" : "??"); +         xfprintf(fp, "%13.6g ", +            fabs(row->prim) <= 1e-9 ? 0.0 : row->prim); +         if (row->type == GLP_LO || row->type == GLP_DB || +             row->type == GLP_FX) +            xfprintf(fp, "%13.6g ", row->lb); +         else +            xfprintf(fp, "%13s ", ""); +         if (row->type == GLP_UP || row->type == GLP_DB) +            xfprintf(fp, "%13.6g ", row->ub); +         else +            xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : ""); +         if (row->stat != GLP_BS) +         {  if (fabs(row->dual) <= 1e-9) +               xfprintf(fp, "%13s", "< eps"); +            else +               xfprintf(fp, "%13.6g ", row->dual); +         } +         xfprintf(fp, "\n"); +      } +      xfprintf(fp, "\n"); +      xfprintf(fp, "   No. Column name  St   Activity     Lower bound  " +         " Upper bound    Marginal\n"); +      xfprintf(fp, "------ ------------ -- ------------- ------------- " +         "------------- -------------\n"); +      for (j = 1; j <= P->n; j++) +      {  col = P->col[j]; +         xfprintf(fp, "%6d ", j); +         if (col->name == NULL || strlen(col->name) <= 12) +            xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name); +         else +            xfprintf(fp, "%s\n%20s", col->name, ""); +         xfprintf(fp, "%s ", +            col->stat == GLP_BS ? "B " : +            col->stat == GLP_NL ? "NL" : +            col->stat == GLP_NU ? "NU" : +            col->stat == GLP_NF ? "NF" : +            col->stat == GLP_NS ? "NS" : "??"); +         xfprintf(fp, "%13.6g ", +            fabs(col->prim) <= 1e-9 ? 0.0 : col->prim); +         if (col->type == GLP_LO || col->type == GLP_DB || +             col->type == GLP_FX) +            xfprintf(fp, "%13.6g ", col->lb); +         else +            xfprintf(fp, "%13s ", ""); +         if (col->type == GLP_UP || col->type == GLP_DB) +            xfprintf(fp, "%13.6g ", col->ub); +         else +            xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : ""); +         if (col->stat != GLP_BS) +         {  if (fabs(col->dual) <= 1e-9) +               xfprintf(fp, "%13s", "< eps"); +            else +               xfprintf(fp, "%13.6g ", col->dual); +         } +         xfprintf(fp, "\n"); +      } +      xfprintf(fp, "\n"); +      xfprintf(fp, "Karush-Kuhn-Tucker optimality conditions:\n"); +      xfprintf(fp, "\n"); +      glp_check_kkt(P, GLP_SOL, GLP_KKT_PE, &ae_max, &ae_ind, &re_max, +         &re_ind); +      xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n", +         ae_max, ae_ind); +      xfprintf(fp, "        max.rel.err = %.2e on row %d\n", +         re_max, re_ind); +      xfprintf(fp, "%8s%s\n", "", +         re_max <= 1e-9 ? "High quality" : +         re_max <= 1e-6 ? "Medium quality" : +         re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS WRONG"); +      xfprintf(fp, "\n"); +      glp_check_kkt(P, GLP_SOL, GLP_KKT_PB, &ae_max, &ae_ind, &re_max, +         &re_ind); +      xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n", +            ae_max, ae_ind <= P->m ? "row" : "column", +            ae_ind <= P->m ? ae_ind : ae_ind - P->m); +      xfprintf(fp, "        max.rel.err = %.2e on %s %d\n", +            re_max, re_ind <= P->m ? "row" : "column", +            re_ind <= P->m ? re_ind : re_ind - P->m); +      xfprintf(fp, "%8s%s\n", "", +         re_max <= 1e-9 ? "High quality" : +         re_max <= 1e-6 ? "Medium quality" : +         re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS INFEASIBL" +            "E"); +      xfprintf(fp, "\n"); +      glp_check_kkt(P, GLP_SOL, GLP_KKT_DE, &ae_max, &ae_ind, &re_max, +         &re_ind); +      xfprintf(fp, "KKT.DE: max.abs.err = %.2e on column %d\n", +         ae_max, ae_ind == 0 ? 0 : ae_ind - P->m); +      xfprintf(fp, "        max.rel.err = %.2e on column %d\n", +         re_max, re_ind == 0 ? 0 : re_ind - P->m); +      xfprintf(fp, "%8s%s\n", "", +         re_max <= 1e-9 ? "High quality" : +         re_max <= 1e-6 ? "Medium quality" : +         re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS WRONG"); +      xfprintf(fp, "\n"); +      glp_check_kkt(P, GLP_SOL, GLP_KKT_DB, &ae_max, &ae_ind, &re_max, +         &re_ind); +      xfprintf(fp, "KKT.DB: max.abs.err = %.2e on %s %d\n", +            ae_max, ae_ind <= P->m ? "row" : "column", +            ae_ind <= P->m ? ae_ind : ae_ind - P->m); +      xfprintf(fp, "        max.rel.err = %.2e on %s %d\n", +            re_max, re_ind <= P->m ? "row" : "column", +            re_ind <= P->m ? re_ind : re_ind - P->m); +      xfprintf(fp, "%8s%s\n", "", +         re_max <= 1e-9 ? "High quality" : +         re_max <= 1e-6 ? "Medium quality" : +         re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS INFEASIBLE") +            ; +      xfprintf(fp, "\n"); +      xfprintf(fp, "End of output\n"); +#if 0 /* FIXME */ +      xfflush(fp); +#endif +      if (glp_ioerr(fp)) +      {  xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); +         ret = 1; +         goto done; +      } +      ret = 0; +done: if (fp != NULL) glp_close(fp); +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/rdasn.c b/glpk-5.0/src/api/rdasn.c new file mode 100644 index 0000000..1f22003 --- /dev/null +++ b/glpk-5.0/src/api/rdasn.c @@ -0,0 +1,162 @@ +/* rdasn.c (read assignment problem data in DIMACS format) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "dimacs.h" +#include "glpk.h" +#include "misc.h" + +#define error           dmx_error +#define warning         dmx_warning +#define read_char       dmx_read_char +#define read_designator dmx_read_designator +#define read_field      dmx_read_field +#define end_of_line     dmx_end_of_line +#define check_int       dmx_check_int + +/*********************************************************************** +*  NAME +* +*  glp_read_asnprob - read assignment problem data in DIMACS format +* +*  SYNOPSIS +* +*  int glp_read_asnprob(glp_graph *G, int v_set, int a_cost, +*     const char *fname); +* +*  DESCRIPTION +* +*  The routine glp_read_asnprob reads assignment problem data in DIMACS +*  format from a text file. +* +*  RETURNS +* +*  If the operation was successful, the routine returns zero. Otherwise +*  it prints an error message and returns non-zero. */ + +int glp_read_asnprob(glp_graph *G, int v_set, int a_cost, const char +      *fname) +{     DMX _csa, *csa = &_csa; +      glp_vertex *v; +      glp_arc *a; +      int nv, na, n1, i, j, k, ret = 0; +      double cost; +      char *flag = NULL; +      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int)) +         xerror("glp_read_asnprob: v_set = %d; invalid offset\n", +            v_set); +      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) +         xerror("glp_read_asnprob: a_cost = %d; invalid offset\n", +            a_cost); +      glp_erase_graph(G, G->v_size, G->a_size); +      if (setjmp(csa->jump)) +      {  ret = 1; +         goto done; +      } +      csa->fname = fname; +      csa->fp = NULL; +      csa->count = 0; +      csa->c = '\n'; +      csa->field[0] = '\0'; +      csa->empty = csa->nonint = 0; +      xprintf("Reading assignment problem data from '%s'...\n", fname); +      csa->fp = glp_open(fname, "r"); +      if (csa->fp == NULL) +      {  xprintf("Unable to open '%s' - %s\n", fname, get_err_msg()); +         longjmp(csa->jump, 1); +      } +      /* read problem line */ +      read_designator(csa); +      if (strcmp(csa->field, "p") != 0) +         error(csa, "problem line missing or invalid"); +      read_field(csa); +      if (strcmp(csa->field, "asn") != 0) +         error(csa, "wrong problem designator; 'asn' expected"); +      read_field(csa); +      if (!(str2int(csa->field, &nv) == 0 && nv >= 0)) +         error(csa, "number of nodes missing or invalid"); +      read_field(csa); +      if (!(str2int(csa->field, &na) == 0 && na >= 0)) +         error(csa, "number of arcs missing or invalid"); +      if (nv > 0) glp_add_vertices(G, nv); +      end_of_line(csa); +      /* read node descriptor lines */ +      flag = xcalloc(1+nv, sizeof(char)); +      memset(&flag[1], 0, nv * sizeof(char)); +      n1 = 0; +      for (;;) +      {  read_designator(csa); +         if (strcmp(csa->field, "n") != 0) break; +         read_field(csa); +         if (str2int(csa->field, &i) != 0) +            error(csa, "node number missing or invalid"); +         if (!(1 <= i && i <= nv)) +            error(csa, "node number %d out of range", i); +         if (flag[i]) +            error(csa, "duplicate descriptor of node %d", i); +         flag[i] = 1, n1++; +         end_of_line(csa); +      } +      xprintf( +         "Assignment problem has %d + %d = %d node%s and %d arc%s\n", +         n1, nv - n1, nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s"); +      if (v_set >= 0) +      {  for (i = 1; i <= nv; i++) +         {  v = G->v[i]; +            k = (flag[i] ? 0 : 1); +            memcpy((char *)v->data + v_set, &k, sizeof(int)); +         } +      } +      /* read arc descriptor lines */ +      for (k = 1; k <= na; k++) +      {  if (k > 1) read_designator(csa); +         if (strcmp(csa->field, "a") != 0) +            error(csa, "wrong line designator; 'a' expected"); +         read_field(csa); +         if (str2int(csa->field, &i) != 0) +            error(csa, "starting node number missing or invalid"); +         if (!(1 <= i && i <= nv)) +            error(csa, "starting node number %d out of range", i); +         if (!flag[i]) +            error(csa, "node %d cannot be a starting node", i); +         read_field(csa); +         if (str2int(csa->field, &j) != 0) +            error(csa, "ending node number missing or invalid"); +         if (!(1 <= j && j <= nv)) +            error(csa, "ending node number %d out of range", j); +         if (flag[j]) +            error(csa, "node %d cannot be an ending node", j); +         read_field(csa); +         if (str2num(csa->field, &cost) != 0) +            error(csa, "arc cost missing or invalid"); +         check_int(csa, cost); +         a = glp_add_arc(G, i, j); +         if (a_cost >= 0) +            memcpy((char *)a->data + a_cost, &cost, sizeof(double)); +         end_of_line(csa); +      } +      xprintf("%d lines were read\n", csa->count); +done: if (ret) glp_erase_graph(G, G->v_size, G->a_size); +      if (csa->fp != NULL) glp_close(csa->fp); +      if (flag != NULL) xfree(flag); +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/rdcc.c b/glpk-5.0/src/api/rdcc.c new file mode 100644 index 0000000..1e93a77 --- /dev/null +++ b/glpk-5.0/src/api/rdcc.c @@ -0,0 +1,160 @@ +/* rdcc.c (read graph in DIMACS clique/coloring format) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "dimacs.h" +#include "glpk.h" +#include "misc.h" + +#define error           dmx_error +#define warning         dmx_warning +#define read_char       dmx_read_char +#define read_designator dmx_read_designator +#define read_field      dmx_read_field +#define end_of_line     dmx_end_of_line +#define check_int       dmx_check_int + +/*********************************************************************** +*  NAME +* +*  glp_read_ccdata - read graph in DIMACS clique/coloring format +* +*  SYNOPSIS +* +*  int glp_read_ccdata(glp_graph *G, int v_wgt, const char *fname); +* +*  DESCRIPTION +* +*  The routine glp_read_ccdata reads an (undirected) graph in DIMACS +*  clique/coloring format from a text file. +* +*  RETURNS +* +*  If the operation was successful, the routine returns zero. Otherwise +*  it prints an error message and returns non-zero. */ + +int glp_read_ccdata(glp_graph *G, int v_wgt, const char *fname) +{     DMX _csa, *csa = &_csa; +      glp_vertex *v; +      int i, j, k, nv, ne, ret = 0; +      double w; +      char *flag = NULL; +      if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double)) +         xerror("glp_read_ccdata: v_wgt = %d; invalid offset\n", +            v_wgt); +      glp_erase_graph(G, G->v_size, G->a_size); +      if (setjmp(csa->jump)) +      {  ret = 1; +         goto done; +      } +      csa->fname = fname; +      csa->fp = NULL; +      csa->count = 0; +      csa->c = '\n'; +      csa->field[0] = '\0'; +      csa->empty = csa->nonint = 0; +      xprintf("Reading graph from '%s'...\n", fname); +      csa->fp = glp_open(fname, "r"); +      if (csa->fp == NULL) +      {  xprintf("Unable to open '%s' - %s\n", fname, get_err_msg()); +         longjmp(csa->jump, 1); +      } +      /* read problem line */ +      read_designator(csa); +      if (strcmp(csa->field, "p") != 0) +         error(csa, "problem line missing or invalid"); +      read_field(csa); +      if (strcmp(csa->field, "edge") != 0) +         error(csa, "wrong problem designator; 'edge' expected"); +      read_field(csa); +      if (!(str2int(csa->field, &nv) == 0 && nv >= 0)) +         error(csa, "number of vertices missing or invalid"); +      read_field(csa); +      if (!(str2int(csa->field, &ne) == 0 && ne >= 0)) +         error(csa, "number of edges missing or invalid"); +      xprintf("Graph has %d vert%s and %d edge%s\n", +         nv, nv == 1 ? "ex" : "ices", ne, ne == 1 ? "" : "s"); +      if (nv > 0) glp_add_vertices(G, nv); +      end_of_line(csa); +      /* read node descriptor lines */ +      flag = xcalloc(1+nv, sizeof(char)); +      memset(&flag[1], 0, nv * sizeof(char)); +      if (v_wgt >= 0) +      {  w = 1.0; +         for (i = 1; i <= nv; i++) +         {  v = G->v[i]; +            memcpy((char *)v->data + v_wgt, &w, sizeof(double)); +         } +      } +      for (;;) +      {  read_designator(csa); +         if (strcmp(csa->field, "n") != 0) break; +         read_field(csa); +         if (str2int(csa->field, &i) != 0) +            error(csa, "vertex number missing or invalid"); +         if (!(1 <= i && i <= nv)) +            error(csa, "vertex number %d out of range", i); +         if (flag[i]) +            error(csa, "duplicate descriptor of vertex %d", i); +         read_field(csa); +         if (str2num(csa->field, &w) != 0) +            error(csa, "vertex weight missing or invalid"); +         check_int(csa, w); +         if (v_wgt >= 0) +         {  v = G->v[i]; +            memcpy((char *)v->data + v_wgt, &w, sizeof(double)); +         } +         flag[i] = 1; +         end_of_line(csa); +      } +      xfree(flag), flag = NULL; +      /* read edge descriptor lines */ +      for (k = 1; k <= ne; k++) +      {  if (k > 1) read_designator(csa); +         if (strcmp(csa->field, "e") != 0) +            error(csa, "wrong line designator; 'e' expected"); +         read_field(csa); +         if (str2int(csa->field, &i) != 0) +            error(csa, "first vertex number missing or invalid"); +         if (!(1 <= i && i <= nv)) +            error(csa, "first vertex number %d out of range", i); +         read_field(csa); +         if (str2int(csa->field, &j) != 0) +            error(csa, "second vertex number missing or invalid"); +         if (!(1 <= j && j <= nv)) +            error(csa, "second vertex number %d out of range", j); +         glp_add_arc(G, i, j); +         end_of_line(csa); +      } +      xprintf("%d lines were read\n", csa->count); +done: if (ret) glp_erase_graph(G, G->v_size, G->a_size); +      if (csa->fp != NULL) glp_close(csa->fp); +      if (flag != NULL) xfree(flag); +      return ret; +} + +/**********************************************************************/ + +int glp_read_graph(glp_graph *G, const char *fname) +{     return +         glp_read_ccdata(G, -1, fname); +} + +/* eof */ diff --git a/glpk-5.0/src/api/rdcnf.c b/glpk-5.0/src/api/rdcnf.c new file mode 100644 index 0000000..f879a3c --- /dev/null +++ b/glpk-5.0/src/api/rdcnf.c @@ -0,0 +1,134 @@ +/* rdcnf.c (read CNF-SAT problem data in DIMACS format) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2010-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "dimacs.h" +#include "misc.h" +#include "prob.h" + +#define xfprintf        glp_format +#define error           dmx_error +#define warning         dmx_warning +#define read_char       dmx_read_char +#define read_designator dmx_read_designator +#define read_field      dmx_read_field +#define end_of_line     dmx_end_of_line +#define check_int       dmx_check_int + +int glp_read_cnfsat(glp_prob *P, const char *fname) +{     /* read CNF-SAT problem data in DIMACS format */ +      DMX _csa, *csa = &_csa; +      int m, n, i, j, len, neg, rhs, ret = 0, *ind = NULL; +      double *val = NULL; +      char *map = NULL; +#if 0 /* 04/IV-2016 */ +      if (P == NULL || P->magic != GLP_PROB_MAGIC) +         xerror("glp_read_cnfsat: P = %p; invalid problem object\n", +            P); +#endif +      if (fname == NULL) +         xerror("glp_read_cnfsat: fname = %p; invalid parameter\n", +            fname); +      glp_erase_prob(P); +      if (setjmp(csa->jump)) +      {  ret = 1; +         goto done; +      } +      csa->fname = fname; +      csa->fp = NULL; +      csa->count = 0; +      csa->c = '\n'; +      csa->field[0] = '\0'; +      csa->empty = csa->nonint = 0; +      xprintf("Reading CNF-SAT problem data from '%s'...\n", fname); +      csa->fp = glp_open(fname, "r"); +      if (csa->fp == NULL) +      {  xprintf("Unable to open '%s' - %s\n", fname, get_err_msg()); +         longjmp(csa->jump, 1); +      } +      /* read problem line */ +      read_designator(csa); +      if (strcmp(csa->field, "p") != 0) +         error(csa, "problem line missing or invalid"); +      read_field(csa); +      if (strcmp(csa->field, "cnf") != 0) +         error(csa, "wrong problem designator; 'cnf' expected\n"); +      read_field(csa); +      if (!(str2int(csa->field, &n) == 0 && n >= 0)) +         error(csa, "number of variables missing or invalid\n"); +      read_field(csa); +      if (!(str2int(csa->field, &m) == 0 && m >= 0)) +         error(csa, "number of clauses missing or invalid\n"); +      xprintf("Instance has %d variable%s and %d clause%s\n", +         n, n == 1 ? "" : "s", m, m == 1 ? "" : "s"); +      end_of_line(csa); +      if (m > 0) +         glp_add_rows(P, m); +      if (n > 0) +      {  glp_add_cols(P, n); +         for (j = 1; j <= n; j++) +            glp_set_col_kind(P, j, GLP_BV); +      } +      /* allocate working arrays */ +      ind = xcalloc(1+n, sizeof(int)); +      val = xcalloc(1+n, sizeof(double)); +      map = xcalloc(1+n, sizeof(char)); +      for (j = 1; j <= n; j++) map[j] = 0; +      /* read clauses */ +      for (i = 1; i <= m; i++) +      {  /* read i-th clause */ +         len = 0, rhs = 1; +         for (;;) +         {  /* skip white-space characters */ +            while (csa->c == ' ' || csa->c == '\n') +               read_char(csa); +            /* read term */ +            read_field(csa); +            if (str2int(csa->field, &j) != 0) +               error(csa, "variable number missing or invalid\n"); +            if (j > 0) +               neg = 0; +            else if (j < 0) +               neg = 1, j = -j, rhs--; +            else +               break; +            if (!(1 <= j && j <= n)) +               error(csa, "variable number out of range\n"); +            if (map[j]) +               error(csa, "duplicate variable number\n"); +            len++, ind[len] = j, val[len] = (neg ? -1.0 : +1.0); +            map[j] = 1; +         } +         glp_set_row_bnds(P, i, GLP_LO, (double)rhs, 0.0); +         glp_set_mat_row(P, i, len, ind, val); +         while (len > 0) map[ind[len--]] = 0; +      } +      xprintf("%d lines were read\n", csa->count); +      /* problem data has been successfully read */ +      glp_sort_matrix(P); +done: if (csa->fp != NULL) glp_close(csa->fp); +      if (ind != NULL) xfree(ind); +      if (val != NULL) xfree(val); +      if (map != NULL) xfree(map); +      if (ret) glp_erase_prob(P); +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/rdipt.c b/glpk-5.0/src/api/rdipt.c new file mode 100644 index 0000000..62bad69 --- /dev/null +++ b/glpk-5.0/src/api/rdipt.c @@ -0,0 +1,183 @@ +/* rdipt.c (read interior-point solution in GLPK format) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2010-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "dimacs.h" +#include "env.h" +#include "misc.h" +#include "prob.h" + +/*********************************************************************** +*  NAME +* +*  glp_read_ipt - read interior-point solution in GLPK format +* +*  SYNOPSIS +* +*  int glp_read_ipt(glp_prob *P, const char *fname); +* +*  DESCRIPTION +* +*  The routine glp_read_ipt reads interior-point solution from a text +*  file in GLPK format. +* +*  RETURNS +* +*  If the operation was successful, the routine returns zero. Otherwise +*  it prints an error message and returns non-zero. */ + +int glp_read_ipt(glp_prob *P, const char *fname) +{     DMX dmx_, *dmx = &dmx_; +      int i, j, k, m, n, sst, ret = 1; +      char *stat = NULL; +      double obj, *prim = NULL, *dual = NULL; +#if 0 /* 04/IV-2016 */ +      if (P == NULL || P->magic != GLP_PROB_MAGIC) +         xerror("glp_read_ipt: P = %p; invalid problem object\n", P); +#endif +      if (fname == NULL) +         xerror("glp_read_ipt: fname = %d; invalid parameter\n", fname); +      if (setjmp(dmx->jump)) +         goto done; +      dmx->fname = fname; +      dmx->fp = NULL; +      dmx->count = 0; +      dmx->c = '\n'; +      dmx->field[0] = '\0'; +      dmx->empty = dmx->nonint = 0; +      xprintf("Reading interior-point solution from '%s'...\n", fname); +      dmx->fp = glp_open(fname, "r"); +      if (dmx->fp == NULL) +      {  xprintf("Unable to open '%s' - %s\n", fname, get_err_msg()); +         goto done; +      } +      /* read solution line */ +      dmx_read_designator(dmx); +      if (strcmp(dmx->field, "s") != 0) +         dmx_error(dmx, "solution line missing or invalid"); +      dmx_read_field(dmx); +      if (strcmp(dmx->field, "ipt") != 0) +         dmx_error(dmx, "wrong solution designator; 'ipt' expected"); +      dmx_read_field(dmx); +      if (!(str2int(dmx->field, &m) == 0 && m >= 0)) +         dmx_error(dmx, "number of rows missing or invalid"); +      if (m != P->m) +         dmx_error(dmx, "number of rows mismatch"); +      dmx_read_field(dmx); +      if (!(str2int(dmx->field, &n) == 0 && n >= 0)) +         dmx_error(dmx, "number of columns missing or invalid"); +      if (n != P->n) +         dmx_error(dmx, "number of columns mismatch"); +      dmx_read_field(dmx); +      if (strcmp(dmx->field, "o") == 0) +         sst = GLP_OPT; +      else if (strcmp(dmx->field, "i") == 0) +         sst = GLP_INFEAS; +      else if (strcmp(dmx->field, "n") == 0) +         sst = GLP_NOFEAS; +      else if (strcmp(dmx->field, "u") == 0) +         sst = GLP_UNDEF; +      else +         dmx_error(dmx, "solution status missing or invalid"); +      dmx_read_field(dmx); +      if (str2num(dmx->field, &obj) != 0) +         dmx_error(dmx, "objective value missing or invalid"); +      dmx_end_of_line(dmx); +      /* allocate working arrays */ +      stat = xalloc(1+m+n, sizeof(stat[0])); +      for (k = 1; k <= m+n; k++) +         stat[k] = '?'; +      prim = xalloc(1+m+n, sizeof(prim[0])); +      dual = xalloc(1+m+n, sizeof(dual[0])); +      /* read solution descriptor lines */ +      for (;;) +      {  dmx_read_designator(dmx); +         if (strcmp(dmx->field, "i") == 0) +         {  /* row solution descriptor */ +            dmx_read_field(dmx); +            if (str2int(dmx->field, &i) != 0) +               dmx_error(dmx, "row number missing or invalid"); +            if (!(1 <= i && i <= m)) +               dmx_error(dmx, "row number out of range"); +            if (stat[i] != '?') +               dmx_error(dmx, "duplicate row solution descriptor"); +            stat[i] = GLP_BS; +            dmx_read_field(dmx); +            if (str2num(dmx->field, &prim[i]) != 0) +               dmx_error(dmx, "row primal value missing or invalid"); +            dmx_read_field(dmx); +            if (str2num(dmx->field, &dual[i]) != 0) +               dmx_error(dmx, "row dual value missing or invalid"); +            dmx_end_of_line(dmx); +         } +         else if (strcmp(dmx->field, "j") == 0) +         {  /* column solution descriptor */ +            dmx_read_field(dmx); +            if (str2int(dmx->field, &j) != 0) +               dmx_error(dmx, "column number missing or invalid"); +            if (!(1 <= j && j <= n)) +               dmx_error(dmx, "column number out of range"); +            if (stat[m+j] != '?') +               dmx_error(dmx, "duplicate column solution descriptor"); +            stat[m+j] = GLP_BS; +            dmx_read_field(dmx); +            if (str2num(dmx->field, &prim[m+j]) != 0) +               dmx_error(dmx, "column primal value missing or invalid"); +            dmx_read_field(dmx); +            if (str2num(dmx->field, &dual[m+j]) != 0) +               dmx_error(dmx, "column dual value missing or invalid"); +            dmx_end_of_line(dmx); +         } +         else if (strcmp(dmx->field, "e") == 0) +            break; +         else +            dmx_error(dmx, "line designator missing or invalid"); +         dmx_end_of_line(dmx); +      } +      /* store solution components into problem object */ +      for (k = 1; k <= m+n; k++) +      {  if (stat[k] == '?') +            dmx_error(dmx, "incomplete interior-point solution"); +      } +      P->ipt_stat = sst; +      P->ipt_obj = obj; +      for (i = 1; i <= m; i++) +      {  P->row[i]->pval = prim[i]; +         P->row[i]->dval = dual[i]; +      } +      for (j = 1; j <= n; j++) +      {  P->col[j]->pval = prim[m+j]; +         P->col[j]->dval = dual[m+j]; +      } +      /* interior-point solution has been successfully read */ +      xprintf("%d lines were read\n", dmx->count); +      ret = 0; +done: if (dmx->fp != NULL) +         glp_close(dmx->fp); +      if (stat != NULL) +         xfree(stat); +      if (prim != NULL) +         xfree(prim); +      if (dual != NULL) +         xfree(dual); +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/rdmaxf.c b/glpk-5.0/src/api/rdmaxf.c new file mode 100644 index 0000000..e30a07c --- /dev/null +++ b/glpk-5.0/src/api/rdmaxf.c @@ -0,0 +1,161 @@ +/* rdmaxf.c (read maximum flow problem data in DIMACS format) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "dimacs.h" +#include "glpk.h" +#include "misc.h" + +#define error           dmx_error +#define warning         dmx_warning +#define read_char       dmx_read_char +#define read_designator dmx_read_designator +#define read_field      dmx_read_field +#define end_of_line     dmx_end_of_line +#define check_int       dmx_check_int + +/*********************************************************************** +*  NAME +* +*  glp_read_maxflow - read maximum flow problem data in DIMACS format +* +*  SYNOPSIS +* +*  int glp_read_maxflow(glp_graph *G, int *s, int *t, int a_cap, +*     const char *fname); +* +*  DESCRIPTION +* +*  The routine glp_read_maxflow reads maximum flow problem data in +*  DIMACS format from a text file. +* +*  RETURNS +* +*  If the operation was successful, the routine returns zero. Otherwise +*  it prints an error message and returns non-zero. */ + +int glp_read_maxflow(glp_graph *G, int *_s, int *_t, int a_cap, +      const char *fname) +{     DMX _csa, *csa = &_csa; +      glp_arc *a; +      int i, j, k, s, t, nv, na, ret = 0; +      double cap; +      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) +         xerror("glp_read_maxflow: a_cap = %d; invalid offset\n", +            a_cap); +      glp_erase_graph(G, G->v_size, G->a_size); +      if (setjmp(csa->jump)) +      {  ret = 1; +         goto done; +      } +      csa->fname = fname; +      csa->fp = NULL; +      csa->count = 0; +      csa->c = '\n'; +      csa->field[0] = '\0'; +      csa->empty = csa->nonint = 0; +      xprintf("Reading maximum flow problem data from '%s'...\n", +         fname); +      csa->fp = glp_open(fname, "r"); +      if (csa->fp == NULL) +      {  xprintf("Unable to open '%s' - %s\n", fname, get_err_msg()); +         longjmp(csa->jump, 1); +      } +      /* read problem line */ +      read_designator(csa); +      if (strcmp(csa->field, "p") != 0) +         error(csa, "problem line missing or invalid"); +      read_field(csa); +      if (strcmp(csa->field, "max") != 0) +         error(csa, "wrong problem designator; 'max' expected"); +      read_field(csa); +      if (!(str2int(csa->field, &nv) == 0 && nv >= 2)) +         error(csa, "number of nodes missing or invalid"); +      read_field(csa); +      if (!(str2int(csa->field, &na) == 0 && na >= 0)) +         error(csa, "number of arcs missing or invalid"); +      xprintf("Flow network has %d node%s and %d arc%s\n", +         nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s"); +      if (nv > 0) glp_add_vertices(G, nv); +      end_of_line(csa); +      /* read node descriptor lines */ +      s = t = 0; +      for (;;) +      {  read_designator(csa); +         if (strcmp(csa->field, "n") != 0) break; +         read_field(csa); +         if (str2int(csa->field, &i) != 0) +            error(csa, "node number missing or invalid"); +         if (!(1 <= i && i <= nv)) +            error(csa, "node number %d out of range", i); +         read_field(csa); +         if (strcmp(csa->field, "s") == 0) +         {  if (s > 0) +               error(csa, "only one source node allowed"); +            s = i; +         } +         else if (strcmp(csa->field, "t") == 0) +         {  if (t > 0) +               error(csa, "only one sink node allowed"); +            t = i; +         } +         else +            error(csa, "wrong node designator; 's' or 't' expected"); +         if (s > 0 && s == t) +            error(csa, "source and sink nodes must be distinct"); +         end_of_line(csa); +      } +      if (s == 0) +         error(csa, "source node descriptor missing\n"); +      if (t == 0) +         error(csa, "sink node descriptor missing\n"); +      if (_s != NULL) *_s = s; +      if (_t != NULL) *_t = t; +      /* read arc descriptor lines */ +      for (k = 1; k <= na; k++) +      {  if (k > 1) read_designator(csa); +         if (strcmp(csa->field, "a") != 0) +            error(csa, "wrong line designator; 'a' expected"); +         read_field(csa); +         if (str2int(csa->field, &i) != 0) +            error(csa, "starting node number missing or invalid"); +         if (!(1 <= i && i <= nv)) +            error(csa, "starting node number %d out of range", i); +         read_field(csa); +         if (str2int(csa->field, &j) != 0) +            error(csa, "ending node number missing or invalid"); +         if (!(1 <= j && j <= nv)) +            error(csa, "ending node number %d out of range", j); +         read_field(csa); +         if (!(str2num(csa->field, &cap) == 0 && cap >= 0.0)) +            error(csa, "arc capacity missing or invalid"); +         check_int(csa, cap); +         a = glp_add_arc(G, i, j); +         if (a_cap >= 0) +            memcpy((char *)a->data + a_cap, &cap, sizeof(double)); +         end_of_line(csa); +      } +      xprintf("%d lines were read\n", csa->count); +done: if (ret) glp_erase_graph(G, G->v_size, G->a_size); +      if (csa->fp != NULL) glp_close(csa->fp); +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/rdmcf.c b/glpk-5.0/src/api/rdmcf.c new file mode 100644 index 0000000..716254d --- /dev/null +++ b/glpk-5.0/src/api/rdmcf.c @@ -0,0 +1,184 @@ +/* rdmcf.c (read min-cost flow problem data in DIMACS format) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "dimacs.h" +#include "glpk.h" +#include "misc.h" + +#define error           dmx_error +#define warning         dmx_warning +#define read_char       dmx_read_char +#define read_designator dmx_read_designator +#define read_field      dmx_read_field +#define end_of_line     dmx_end_of_line +#define check_int       dmx_check_int + +/*********************************************************************** +*  NAME +* +*  glp_read_mincost - read min-cost flow problem data in DIMACS format +* +*  SYNOPSIS +* +*  int glp_read_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap, +*     int a_cost, const char *fname); +* +*  DESCRIPTION +* +*  The routine glp_read_mincost reads minimum cost flow problem data in +*  DIMACS format from a text file. +* +*  RETURNS +* +*  If the operation was successful, the routine returns zero. Otherwise +*  it prints an error message and returns non-zero. */ + +int glp_read_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap, +      int a_cost, const char *fname) +{     DMX _csa, *csa = &_csa; +      glp_vertex *v; +      glp_arc *a; +      int i, j, k, nv, na, ret = 0; +      double rhs, low, cap, cost; +      char *flag = NULL; +      if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double)) +         xerror("glp_read_mincost: v_rhs = %d; invalid offset\n", +            v_rhs); +      if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double)) +         xerror("glp_read_mincost: a_low = %d; invalid offset\n", +            a_low); +      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) +         xerror("glp_read_mincost: a_cap = %d; invalid offset\n", +            a_cap); +      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) +         xerror("glp_read_mincost: a_cost = %d; invalid offset\n", +            a_cost); +      glp_erase_graph(G, G->v_size, G->a_size); +      if (setjmp(csa->jump)) +      {  ret = 1; +         goto done; +      } +      csa->fname = fname; +      csa->fp = NULL; +      csa->count = 0; +      csa->c = '\n'; +      csa->field[0] = '\0'; +      csa->empty = csa->nonint = 0; +      xprintf("Reading min-cost flow problem data from '%s'...\n", +         fname); +      csa->fp = glp_open(fname, "r"); +      if (csa->fp == NULL) +      {  xprintf("Unable to open '%s' - %s\n", fname, get_err_msg()); +         longjmp(csa->jump, 1); +      } +      /* read problem line */ +      read_designator(csa); +      if (strcmp(csa->field, "p") != 0) +         error(csa, "problem line missing or invalid"); +      read_field(csa); +      if (strcmp(csa->field, "min") != 0) +         error(csa, "wrong problem designator; 'min' expected"); +      read_field(csa); +      if (!(str2int(csa->field, &nv) == 0 && nv >= 0)) +         error(csa, "number of nodes missing or invalid"); +      read_field(csa); +      if (!(str2int(csa->field, &na) == 0 && na >= 0)) +         error(csa, "number of arcs missing or invalid"); +      xprintf("Flow network has %d node%s and %d arc%s\n", +         nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s"); +      if (nv > 0) glp_add_vertices(G, nv); +      end_of_line(csa); +      /* read node descriptor lines */ +      flag = xcalloc(1+nv, sizeof(char)); +      memset(&flag[1], 0, nv * sizeof(char)); +      if (v_rhs >= 0) +      {  rhs = 0.0; +         for (i = 1; i <= nv; i++) +         {  v = G->v[i]; +            memcpy((char *)v->data + v_rhs, &rhs, sizeof(double)); +         } +      } +      for (;;) +      {  read_designator(csa); +         if (strcmp(csa->field, "n") != 0) break; +         read_field(csa); +         if (str2int(csa->field, &i) != 0) +            error(csa, "node number missing or invalid"); +         if (!(1 <= i && i <= nv)) +            error(csa, "node number %d out of range", i); +         if (flag[i]) +            error(csa, "duplicate descriptor of node %d", i); +         read_field(csa); +         if (str2num(csa->field, &rhs) != 0) +            error(csa, "node supply/demand missing or invalid"); +         check_int(csa, rhs); +         if (v_rhs >= 0) +         {  v = G->v[i]; +            memcpy((char *)v->data + v_rhs, &rhs, sizeof(double)); +         } +         flag[i] = 1; +         end_of_line(csa); +      } +      xfree(flag), flag = NULL; +      /* read arc descriptor lines */ +      for (k = 1; k <= na; k++) +      {  if (k > 1) read_designator(csa); +         if (strcmp(csa->field, "a") != 0) +            error(csa, "wrong line designator; 'a' expected"); +         read_field(csa); +         if (str2int(csa->field, &i) != 0) +            error(csa, "starting node number missing or invalid"); +         if (!(1 <= i && i <= nv)) +            error(csa, "starting node number %d out of range", i); +         read_field(csa); +         if (str2int(csa->field, &j) != 0) +            error(csa, "ending node number missing or invalid"); +         if (!(1 <= j && j <= nv)) +            error(csa, "ending node number %d out of range", j); +         read_field(csa); +         if (!(str2num(csa->field, &low) == 0 && low >= 0.0)) +            error(csa, "lower bound of arc flow missing or invalid"); +         check_int(csa, low); +         read_field(csa); +         if (!(str2num(csa->field, &cap) == 0 && cap >= low)) +            error(csa, "upper bound of arc flow missing or invalid"); +         check_int(csa, cap); +         read_field(csa); +         if (str2num(csa->field, &cost) != 0) +            error(csa, "per-unit cost of arc flow missing or invalid"); +         check_int(csa, cost); +         a = glp_add_arc(G, i, j); +         if (a_low >= 0) +            memcpy((char *)a->data + a_low, &low, sizeof(double)); +         if (a_cap >= 0) +            memcpy((char *)a->data + a_cap, &cap, sizeof(double)); +         if (a_cost >= 0) +            memcpy((char *)a->data + a_cost, &cost, sizeof(double)); +         end_of_line(csa); +      } +      xprintf("%d lines were read\n", csa->count); +done: if (ret) glp_erase_graph(G, G->v_size, G->a_size); +      if (csa->fp != NULL) glp_close(csa->fp); +      if (flag != NULL) xfree(flag); +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/rdmip.c b/glpk-5.0/src/api/rdmip.c new file mode 100644 index 0000000..e6f4589 --- /dev/null +++ b/glpk-5.0/src/api/rdmip.c @@ -0,0 +1,170 @@ +/* rdmip.c (read MIP solution in GLPK format) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2010-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "dimacs.h" +#include "env.h" +#include "misc.h" +#include "prob.h" + +/*********************************************************************** +*  NAME +* +*  glp_read_mip - read MIP solution in GLPK format +* +*  SYNOPSIS +* +*  int glp_read_mip(glp_prob *P, const char *fname); +* +*  DESCRIPTION +* +*  The routine glp_read_mip reads MIP solution from a text file in GLPK +*  format. +* +*  RETURNS +* +*  If the operation was successful, the routine returns zero. Otherwise +*  it prints an error message and returns non-zero. */ + +int glp_read_mip(glp_prob *P, const char *fname) +{     DMX dmx_, *dmx = &dmx_; +      int i, j, k, m, n, sst, ret = 1; +      char *stat = NULL; +      double obj, *prim = NULL; +#if 0 /* 04/IV-2016 */ +      if (P == NULL || P->magic != GLP_PROB_MAGIC) +         xerror("glp_read_mip: P = %p; invalid problem object\n", P); +#endif +      if (fname == NULL) +         xerror("glp_read_mip: fname = %d; invalid parameter\n", fname); +      if (setjmp(dmx->jump)) +         goto done; +      dmx->fname = fname; +      dmx->fp = NULL; +      dmx->count = 0; +      dmx->c = '\n'; +      dmx->field[0] = '\0'; +      dmx->empty = dmx->nonint = 0; +      xprintf("Reading MIP solution from '%s'...\n", fname); +      dmx->fp = glp_open(fname, "r"); +      if (dmx->fp == NULL) +      {  xprintf("Unable to open '%s' - %s\n", fname, get_err_msg()); +         goto done; +      } +      /* read solution line */ +      dmx_read_designator(dmx); +      if (strcmp(dmx->field, "s") != 0) +         dmx_error(dmx, "solution line missing or invalid"); +      dmx_read_field(dmx); +      if (strcmp(dmx->field, "mip") != 0) +         dmx_error(dmx, "wrong solution designator; 'mip' expected"); +      dmx_read_field(dmx); +      if (!(str2int(dmx->field, &m) == 0 && m >= 0)) +         dmx_error(dmx, "number of rows missing or invalid"); +      if (m != P->m) +         dmx_error(dmx, "number of rows mismatch"); +      dmx_read_field(dmx); +      if (!(str2int(dmx->field, &n) == 0 && n >= 0)) +         dmx_error(dmx, "number of columns missing or invalid"); +      if (n != P->n) +         dmx_error(dmx, "number of columns mismatch"); +      dmx_read_field(dmx); +      if (strcmp(dmx->field, "o") == 0) +         sst = GLP_OPT; +      else if (strcmp(dmx->field, "f") == 0) +         sst = GLP_FEAS; +      else if (strcmp(dmx->field, "n") == 0) +         sst = GLP_NOFEAS; +      else if (strcmp(dmx->field, "u") == 0) +         sst = GLP_UNDEF; +      else +         dmx_error(dmx, "solution status missing or invalid"); +      dmx_read_field(dmx); +      if (str2num(dmx->field, &obj) != 0) +         dmx_error(dmx, "objective value missing or invalid"); +      dmx_end_of_line(dmx); +      /* allocate working arrays */ +      stat = xalloc(1+m+n, sizeof(stat[0])); +      for (k = 1; k <= m+n; k++) +         stat[k] = '?'; +      prim = xalloc(1+m+n, sizeof(prim[0])); +      /* read solution descriptor lines */ +      for (;;) +      {  dmx_read_designator(dmx); +         if (strcmp(dmx->field, "i") == 0) +         {  /* row solution descriptor */ +            dmx_read_field(dmx); +            if (str2int(dmx->field, &i) != 0) +               dmx_error(dmx, "row number missing or invalid"); +            if (!(1 <= i && i <= m)) +               dmx_error(dmx, "row number out of range"); +            if (stat[i] != '?') +               dmx_error(dmx, "duplicate row solution descriptor"); +            stat[i] = GLP_BS; +            dmx_read_field(dmx); +            if (str2num(dmx->field, &prim[i]) != 0) +               dmx_error(dmx, "row value missing or invalid"); +            dmx_end_of_line(dmx); +         } +         else if (strcmp(dmx->field, "j") == 0) +         {  /* column solution descriptor */ +            dmx_read_field(dmx); +            if (str2int(dmx->field, &j) != 0) +               dmx_error(dmx, "column number missing or invalid"); +            if (!(1 <= j && j <= n)) +               dmx_error(dmx, "column number out of range"); +            if (stat[m+j] != '?') +               dmx_error(dmx, "duplicate column solution descriptor"); +            stat[m+j] = GLP_BS; +            dmx_read_field(dmx); +            if (str2num(dmx->field, &prim[m+j]) != 0) +               dmx_error(dmx, "column value missing or invalid"); +            dmx_end_of_line(dmx); +         } +         else if (strcmp(dmx->field, "e") == 0) +            break; +         else +            dmx_error(dmx, "line designator missing or invalid"); +         dmx_end_of_line(dmx); +      } +      /* store solution components into problem object */ +      for (k = 1; k <= m+n; k++) +      {  if (stat[k] == '?') +            dmx_error(dmx, "incomplete MIP solution"); +      } +      P->mip_stat = sst; +      P->mip_obj = obj; +      for (i = 1; i <= m; i++) +         P->row[i]->mipx = prim[i]; +      for (j = 1; j <= n; j++) +         P->col[j]->mipx = prim[m+j]; +      /* MIP solution has been successfully read */ +      xprintf("%d lines were read\n", dmx->count); +      ret = 0; +done: if (dmx->fp != NULL) +         glp_close(dmx->fp); +      if (stat != NULL) +         xfree(stat); +      if (prim != NULL) +         xfree(prim); +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/rdprob.c b/glpk-5.0/src/api/rdprob.c new file mode 100644 index 0000000..306f0a8 --- /dev/null +++ b/glpk-5.0/src/api/rdprob.c @@ -0,0 +1,375 @@ +/* rdprob.c (read problem data in GLPK format) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2010-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "dimacs.h" +#include "misc.h" +#include "prob.h" + +#define xfprintf        glp_format +#define error           dmx_error +#define warning         dmx_warning +#define read_char       dmx_read_char +#define read_designator dmx_read_designator +#define read_field      dmx_read_field +#define end_of_line     dmx_end_of_line +#define check_int       dmx_check_int + +/*********************************************************************** +*  NAME +* +*  glp_read_prob - read problem data in GLPK format +* +*  SYNOPSIS +* +*  int glp_read_prob(glp_prob *P, int flags, const char *fname); +* +*  The routine glp_read_prob reads problem data in GLPK LP/MIP format +*  from a text file. +* +*  RETURNS +* +*  If the operation was successful, the routine returns zero. Otherwise +*  it prints an error message and returns non-zero. */ + +int glp_read_prob(glp_prob *P, int flags, const char *fname) +{     DMX _csa, *csa = &_csa; +      int mip, m, n, nnz, ne, i, j, k, type, kind, ret, *ln = NULL, +         *ia = NULL, *ja = NULL; +      double lb, ub, temp, *ar = NULL; +      char *rf = NULL, *cf = NULL; +#if 0 /* 04/IV-2016 */ +      if (P == NULL || P->magic != GLP_PROB_MAGIC) +         xerror("glp_read_prob: P = %p; invalid problem object\n", +            P); +#endif +      if (flags != 0) +         xerror("glp_read_prob: flags = %d; invalid parameter\n", +            flags); +      if (fname == NULL) +         xerror("glp_read_prob: fname = %d; invalid parameter\n", +            fname); +      glp_erase_prob(P); +      if (setjmp(csa->jump)) +      {  ret = 1; +         goto done; +      } +      csa->fname = fname; +      csa->fp = NULL; +      csa->count = 0; +      csa->c = '\n'; +      csa->field[0] = '\0'; +      csa->empty = csa->nonint = 0; +      xprintf("Reading problem data from '%s'...\n", fname); +      csa->fp = glp_open(fname, "r"); +      if (csa->fp == NULL) +      {  xprintf("Unable to open '%s' - %s\n", fname, get_err_msg()); +         longjmp(csa->jump, 1); +      } +      /* read problem line */ +      read_designator(csa); +      if (strcmp(csa->field, "p") != 0) +         error(csa, "problem line missing or invalid"); +      read_field(csa); +      if (strcmp(csa->field, "lp") == 0) +         mip = 0; +      else if (strcmp(csa->field, "mip") == 0) +         mip = 1; +      else +         error(csa, "wrong problem designator; 'lp' or 'mip' expected"); +      read_field(csa); +      if (strcmp(csa->field, "min") == 0) +         glp_set_obj_dir(P, GLP_MIN); +      else if (strcmp(csa->field, "max") == 0) +         glp_set_obj_dir(P, GLP_MAX); +      else +         error(csa, "objective sense missing or invalid"); +      read_field(csa); +      if (!(str2int(csa->field, &m) == 0 && m >= 0)) +         error(csa, "number of rows missing or invalid"); +      read_field(csa); +      if (!(str2int(csa->field, &n) == 0 && n >= 0)) +         error(csa, "number of columns missing or invalid"); +      read_field(csa); +      if (!(str2int(csa->field, &nnz) == 0 && nnz >= 0)) +         error(csa, "number of constraint coefficients missing or inval" +            "id"); +      if (m > 0) +      {  glp_add_rows(P, m); +         for (i = 1; i <= m; i++) +            glp_set_row_bnds(P, i, GLP_FX, 0.0, 0.0); +      } +      if (n > 0) +      {  glp_add_cols(P, n); +         for (j = 1; j <= n; j++) +         {  if (!mip) +               glp_set_col_bnds(P, j, GLP_LO, 0.0, 0.0); +            else +               glp_set_col_kind(P, j, GLP_BV); +         } +      } +      end_of_line(csa); +      /* allocate working arrays */ +      rf = xcalloc(1+m, sizeof(char)); +      memset(rf, 0, 1+m); +      cf = xcalloc(1+n, sizeof(char)); +      memset(cf, 0, 1+n); +      ln = xcalloc(1+nnz, sizeof(int)); +      ia = xcalloc(1+nnz, sizeof(int)); +      ja = xcalloc(1+nnz, sizeof(int)); +      ar = xcalloc(1+nnz, sizeof(double)); +      /* read descriptor lines */ +      ne = 0; +      for (;;) +      {  read_designator(csa); +         if (strcmp(csa->field, "i") == 0) +         {  /* row descriptor */ +            read_field(csa); +            if (str2int(csa->field, &i) != 0) +               error(csa, "row number missing or invalid"); +            if (!(1 <= i && i <= m)) +               error(csa, "row number out of range"); +            read_field(csa); +            if (strcmp(csa->field, "f") == 0) +               type = GLP_FR; +            else if (strcmp(csa->field, "l") == 0) +               type = GLP_LO; +            else if (strcmp(csa->field, "u") == 0) +               type = GLP_UP; +            else if (strcmp(csa->field, "d") == 0) +               type = GLP_DB; +            else if (strcmp(csa->field, "s") == 0) +               type = GLP_FX; +            else +               error(csa, "row type missing or invalid"); +            if (type == GLP_LO || type == GLP_DB || type == GLP_FX) +            {  read_field(csa); +               if (str2num(csa->field, &lb) != 0) +                  error(csa, "row lower bound/fixed value missing or in" +                     "valid"); +            } +            else +               lb = 0.0; +            if (type == GLP_UP || type == GLP_DB) +            {  read_field(csa); +               if (str2num(csa->field, &ub) != 0) +                  error(csa, "row upper bound missing or invalid"); +            } +            else +               ub = 0.0; +            if (rf[i] & 0x01) +               error(csa, "duplicate row descriptor"); +            glp_set_row_bnds(P, i, type, lb, ub), rf[i] |= 0x01; +         } +         else if (strcmp(csa->field, "j") == 0) +         {  /* column descriptor */ +            read_field(csa); +            if (str2int(csa->field, &j) != 0) +               error(csa, "column number missing or invalid"); +            if (!(1 <= j && j <= n)) +               error(csa, "column number out of range"); +            if (!mip) +               kind = GLP_CV; +            else +            {  read_field(csa); +               if (strcmp(csa->field, "c") == 0) +                  kind = GLP_CV; +               else if (strcmp(csa->field, "i") == 0) +                  kind = GLP_IV; +               else if (strcmp(csa->field, "b") == 0) +               {  kind = GLP_IV; +                  type = GLP_DB, lb = 0.0, ub = 1.0; +                  goto skip; +               } +               else +                  error(csa, "column kind missing or invalid"); +            } +            read_field(csa); +            if (strcmp(csa->field, "f") == 0) +               type = GLP_FR; +            else if (strcmp(csa->field, "l") == 0) +               type = GLP_LO; +            else if (strcmp(csa->field, "u") == 0) +               type = GLP_UP; +            else if (strcmp(csa->field, "d") == 0) +               type = GLP_DB; +            else if (strcmp(csa->field, "s") == 0) +               type = GLP_FX; +            else +               error(csa, "column type missing or invalid"); +            if (type == GLP_LO || type == GLP_DB || type == GLP_FX) +            {  read_field(csa); +               if (str2num(csa->field, &lb) != 0) +                  error(csa, "column lower bound/fixed value missing or" +                     " invalid"); +            } +            else +               lb = 0.0; +            if (type == GLP_UP || type == GLP_DB) +            {  read_field(csa); +               if (str2num(csa->field, &ub) != 0) +                  error(csa, "column upper bound missing or invalid"); +            } +            else +               ub = 0.0; +skip:       if (cf[j] & 0x01) +               error(csa, "duplicate column descriptor"); +            glp_set_col_kind(P, j, kind); +            glp_set_col_bnds(P, j, type, lb, ub), cf[j] |= 0x01; +         } +         else if (strcmp(csa->field, "a") == 0) +         {  /* coefficient descriptor */ +            read_field(csa); +            if (str2int(csa->field, &i) != 0) +               error(csa, "row number missing or invalid"); +            if (!(0 <= i && i <= m)) +               error(csa, "row number out of range"); +            read_field(csa); +            if (str2int(csa->field, &j) != 0) +               error(csa, "column number missing or invalid"); +            if (!((i == 0 ? 0 : 1) <= j && j <= n)) +               error(csa, "column number out of range"); +            read_field(csa); +            if (i == 0) +            {  if (str2num(csa->field, &temp) != 0) +                  error(csa, "objective %s missing or invalid", +                     j == 0 ? "constant term" : "coefficient"); +               if (cf[j] & 0x10) +                  error(csa, "duplicate objective %s", +                     j == 0 ? "constant term" : "coefficient"); +               glp_set_obj_coef(P, j, temp), cf[j] |= 0x10; +            } +            else +            {  if (str2num(csa->field, &temp) != 0) +                  error(csa, "constraint coefficient missing or invalid" +                     ); +               if (ne == nnz) +                  error(csa, "too many constraint coefficient descripto" +                     "rs"); +               ln[++ne] = csa->count; +               ia[ne] = i, ja[ne] = j, ar[ne] = temp; +            } +         } +         else if (strcmp(csa->field, "n") == 0) +         {  /* symbolic name descriptor */ +            read_field(csa); +            if (strcmp(csa->field, "p") == 0) +            {  /* problem name */ +               read_field(csa); +               if (P->name != NULL) +                  error(csa, "duplicate problem name"); +               glp_set_prob_name(P, csa->field); +            } +            else if (strcmp(csa->field, "z") == 0) +            {  /* objective name */ +               read_field(csa); +               if (P->obj != NULL) +                  error(csa, "duplicate objective name"); +               glp_set_obj_name(P, csa->field); +            } +            else if (strcmp(csa->field, "i") == 0) +            {  /* row name */ +               read_field(csa); +               if (str2int(csa->field, &i) != 0) +                  error(csa, "row number missing or invalid"); +               if (!(1 <= i && i <= m)) +                  error(csa, "row number out of range"); +               read_field(csa); +               if (P->row[i]->name != NULL) +                  error(csa, "duplicate row name"); +               glp_set_row_name(P, i, csa->field); +            } +            else if (strcmp(csa->field, "j") == 0) +            {  /* column name */ +               read_field(csa); +               if (str2int(csa->field, &j) != 0) +                  error(csa, "column number missing or invalid"); +               if (!(1 <= j && j <= n)) +                  error(csa, "column number out of range"); +               read_field(csa); +               if (P->col[j]->name != NULL) +                  error(csa, "duplicate column name"); +               glp_set_col_name(P, j, csa->field); +            } +            else +               error(csa, "object designator missing or invalid"); +         } +         else if (strcmp(csa->field, "e") == 0) +            break; +         else +            error(csa, "line designator missing or invalid"); +         end_of_line(csa); +      } +      if (ne < nnz) +         error(csa, "too few constraint coefficient descriptors"); +      xassert(ne == nnz); +      k = glp_check_dup(m, n, ne, ia, ja); +      xassert(0 <= k && k <= nnz); +      if (k > 0) +      {  csa->count = ln[k]; +         error(csa, "duplicate constraint coefficient"); +      } +      glp_load_matrix(P, ne, ia, ja, ar); +      /* print some statistics */ +      if (P->name != NULL) +         xprintf("Problem: %s\n", P->name); +      if (P->obj != NULL) +         xprintf("Objective: %s\n", P->obj); +      xprintf("%d row%s, %d column%s, %d non-zero%s\n", +         m, m == 1 ? "" : "s", n, n == 1 ? "" : "s", nnz, nnz == 1 ? +         "" : "s"); +      if (glp_get_num_int(P) > 0) +      {  int ni = glp_get_num_int(P); +         int nb = glp_get_num_bin(P); +         if (ni == 1) +         {  if (nb == 0) +               xprintf("One variable is integer\n"); +            else +               xprintf("One variable is binary\n"); +         } +         else +         {  xprintf("%d integer variables, ", ni); +            if (nb == 0) +               xprintf("none"); +            else if (nb == 1) +               xprintf("one"); +            else if (nb == ni) +               xprintf("all"); +            else +               xprintf("%d", nb); +            xprintf(" of which %s binary\n", nb == 1 ? "is" : "are"); +         } +      } +      xprintf("%d lines were read\n", csa->count); +      /* problem data has been successfully read */ +      glp_sort_matrix(P); +      ret = 0; +done: if (csa->fp != NULL) glp_close(csa->fp); +      if (rf != NULL) xfree(rf); +      if (cf != NULL) xfree(cf); +      if (ln != NULL) xfree(ln); +      if (ia != NULL) xfree(ia); +      if (ja != NULL) xfree(ja); +      if (ar != NULL) xfree(ar); +      if (ret) glp_erase_prob(P); +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/rdsol.c b/glpk-5.0/src/api/rdsol.c new file mode 100644 index 0000000..dcd8bf3 --- /dev/null +++ b/glpk-5.0/src/api/rdsol.c @@ -0,0 +1,223 @@ +/* rdsol.c (read basic solution in GLPK format) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2010-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "dimacs.h" +#include "env.h" +#include "misc.h" +#include "prob.h" + +/*********************************************************************** +*  NAME +* +*  glp_read_sol - read basic solution in GLPK format +* +*  SYNOPSIS +* +*  int glp_read_sol(glp_prob *P, const char *fname); +* +*  DESCRIPTION +* +*  The routine glp_read_sol reads basic solution from a text file in +*  GLPK format. +* +*  RETURNS +* +*  If the operation was successful, the routine returns zero. Otherwise +*  it prints an error message and returns non-zero. */ + +int glp_read_sol(glp_prob *P, const char *fname) +{     DMX dmx_, *dmx = &dmx_; +      int i, j, k, m, n, pst, dst, ret = 1; +      char *stat = NULL; +      double obj, *prim = NULL, *dual = NULL; +#if 0 /* 04/IV-2016 */ +      if (P == NULL || P->magic != GLP_PROB_MAGIC) +         xerror("glp_read_sol: P = %p; invalid problem object\n", P); +#endif +      if (fname == NULL) +         xerror("glp_read_sol: fname = %d; invalid parameter\n", fname); +      if (setjmp(dmx->jump)) +         goto done; +      dmx->fname = fname; +      dmx->fp = NULL; +      dmx->count = 0; +      dmx->c = '\n'; +      dmx->field[0] = '\0'; +      dmx->empty = dmx->nonint = 0; +      xprintf("Reading basic solution from '%s'...\n", fname); +      dmx->fp = glp_open(fname, "r"); +      if (dmx->fp == NULL) +      {  xprintf("Unable to open '%s' - %s\n", fname, get_err_msg()); +         goto done; +      } +      /* read solution line */ +      dmx_read_designator(dmx); +      if (strcmp(dmx->field, "s") != 0) +         dmx_error(dmx, "solution line missing or invalid"); +      dmx_read_field(dmx); +      if (strcmp(dmx->field, "bas") != 0) +         dmx_error(dmx, "wrong solution designator; 'bas' expected"); +      dmx_read_field(dmx); +      if (!(str2int(dmx->field, &m) == 0 && m >= 0)) +         dmx_error(dmx, "number of rows missing or invalid"); +      if (m != P->m) +         dmx_error(dmx, "number of rows mismatch"); +      dmx_read_field(dmx); +      if (!(str2int(dmx->field, &n) == 0 && n >= 0)) +         dmx_error(dmx, "number of columns missing or invalid"); +      if (n != P->n) +         dmx_error(dmx, "number of columns mismatch"); +      dmx_read_field(dmx); +      if (strcmp(dmx->field, "u") == 0) +         pst = GLP_UNDEF; +      else if (strcmp(dmx->field, "f") == 0) +         pst = GLP_FEAS; +      else if (strcmp(dmx->field, "i") == 0) +         pst = GLP_INFEAS; +      else if (strcmp(dmx->field, "n") == 0) +         pst = GLP_NOFEAS; +      else +         dmx_error(dmx, "primal solution status missing or invalid"); +      dmx_read_field(dmx); +      if (strcmp(dmx->field, "u") == 0) +         dst = GLP_UNDEF; +      else if (strcmp(dmx->field, "f") == 0) +         dst = GLP_FEAS; +      else if (strcmp(dmx->field, "i") == 0) +         dst = GLP_INFEAS; +      else if (strcmp(dmx->field, "n") == 0) +         dst = GLP_NOFEAS; +      else +         dmx_error(dmx, "dual solution status missing or invalid"); +      dmx_read_field(dmx); +      if (str2num(dmx->field, &obj) != 0) +         dmx_error(dmx, "objective value missing or invalid"); +      dmx_end_of_line(dmx); +      /* allocate working arrays */ +      stat = xalloc(1+m+n, sizeof(stat[0])); +      for (k = 1; k <= m+n; k++) +         stat[k] = '?'; +      prim = xalloc(1+m+n, sizeof(prim[0])); +      dual = xalloc(1+m+n, sizeof(dual[0])); +      /* read solution descriptor lines */ +      for (;;) +      {  dmx_read_designator(dmx); +         if (strcmp(dmx->field, "i") == 0) +         {  /* row solution descriptor */ +            dmx_read_field(dmx); +            if (str2int(dmx->field, &i) != 0) +               dmx_error(dmx, "row number missing or invalid"); +            if (!(1 <= i && i <= m)) +               dmx_error(dmx, "row number out of range"); +            if (stat[i] != '?') +               dmx_error(dmx, "duplicate row solution descriptor"); +            dmx_read_field(dmx); +            if (strcmp(dmx->field, "b") == 0) +               stat[i] = GLP_BS; +            else if (strcmp(dmx->field, "l") == 0) +               stat[i] = GLP_NL; +            else if (strcmp(dmx->field, "u") == 0) +               stat[i] = GLP_NU; +            else if (strcmp(dmx->field, "f") == 0) +               stat[i] = GLP_NF; +            else if (strcmp(dmx->field, "s") == 0) +               stat[i] = GLP_NS; +            else +               dmx_error(dmx, "row status missing or invalid"); +            dmx_read_field(dmx); +            if (str2num(dmx->field, &prim[i]) != 0) +               dmx_error(dmx, "row primal value missing or invalid"); +            dmx_read_field(dmx); +            if (str2num(dmx->field, &dual[i]) != 0) +               dmx_error(dmx, "row dual value missing or invalid"); +            dmx_end_of_line(dmx); +         } +         else if (strcmp(dmx->field, "j") == 0) +         {  /* column solution descriptor */ +            dmx_read_field(dmx); +            if (str2int(dmx->field, &j) != 0) +               dmx_error(dmx, "column number missing or invalid"); +            if (!(1 <= j && j <= n)) +               dmx_error(dmx, "column number out of range"); +            if (stat[m+j] != '?') +               dmx_error(dmx, "duplicate column solution descriptor"); +            dmx_read_field(dmx); +            if (strcmp(dmx->field, "b") == 0) +               stat[m+j] = GLP_BS; +            else if (strcmp(dmx->field, "l") == 0) +               stat[m+j] = GLP_NL; +            else if (strcmp(dmx->field, "u") == 0) +               stat[m+j] = GLP_NU; +            else if (strcmp(dmx->field, "f") == 0) +               stat[m+j] = GLP_NF; +            else if (strcmp(dmx->field, "s") == 0) +               stat[m+j] = GLP_NS; +            else +               dmx_error(dmx, "column status missing or invalid"); +            dmx_read_field(dmx); +            if (str2num(dmx->field, &prim[m+j]) != 0) +               dmx_error(dmx, "column primal value missing or invalid"); +            dmx_read_field(dmx); +            if (str2num(dmx->field, &dual[m+j]) != 0) +               dmx_error(dmx, "column dual value missing or invalid"); +            dmx_end_of_line(dmx); +         } +         else if (strcmp(dmx->field, "e") == 0) +            break; +         else +            dmx_error(dmx, "line designator missing or invalid"); +         dmx_end_of_line(dmx); +      } +      /* store solution components into problem object */ +      for (k = 1; k <= m+n; k++) +      {  if (stat[k] == '?') +            dmx_error(dmx, "incomplete basic solution"); +      } +      P->pbs_stat = pst; +      P->dbs_stat = dst; +      P->obj_val = obj; +      P->it_cnt = 0; +      P->some = 0; +      for (i = 1; i <= m; i++) +      {  glp_set_row_stat(P, i, stat[i]); +         P->row[i]->prim = prim[i]; +         P->row[i]->dual = dual[i]; +      } +      for (j = 1; j <= n; j++) +      {  glp_set_col_stat(P, j, stat[m+j]); +         P->col[j]->prim = prim[m+j]; +         P->col[j]->dual = dual[m+j]; +      } +      /* basic solution has been successfully read */ +      xprintf("%d lines were read\n", dmx->count); +      ret = 0; +done: if (dmx->fp != NULL) +         glp_close(dmx->fp); +      if (stat != NULL) +         xfree(stat); +      if (prim != NULL) +         xfree(prim); +      if (dual != NULL) +         xfree(dual); +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/rmfgen.c b/glpk-5.0/src/api/rmfgen.c new file mode 100644 index 0000000..c98c82c --- /dev/null +++ b/glpk-5.0/src/api/rmfgen.c @@ -0,0 +1,20 @@ +/* rmfgen.c */ + +#include "env.h" +#include "glpk.h" + +int glp_rmfgen(glp_graph *G_, int *s_, int *t_, int a_cap_, +      const int parm[1+5]) +{     static const char func[] = "glp_rmfgen"; +      xassert(G_ == G_); +      xassert(s_ == s_); +      xassert(t_ == t_); +      xassert(a_cap_ == a_cap_); +      xassert(parm == parm); +      xerror("%s: sorry, this routine is temporarily disabled due to li" +         "censing problems\n", func); +      abort(); +      return -1; +} + +/* eof */ diff --git a/glpk-5.0/src/api/strong.c b/glpk-5.0/src/api/strong.c new file mode 100644 index 0000000..8921f5e --- /dev/null +++ b/glpk-5.0/src/api/strong.c @@ -0,0 +1,108 @@ +/* strong.c (find all strongly connected components of graph) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" +#include "mc13d.h" + +/*********************************************************************** +*  NAME +* +*  glp_strong_comp - find all strongly connected components of graph +* +*  SYNOPSIS +* +*  int glp_strong_comp(glp_graph *G, int v_num); +* +*  DESCRIPTION +* +*  The routine glp_strong_comp finds all strongly connected components +*  of the specified graph. +* +*  The parameter v_num specifies an offset of the field of type int +*  in the vertex data block, to which the routine stores the number of +*  a strongly connected component containing that vertex. If v_num < 0, +*  no component numbers are stored. +* +*  The components are numbered in arbitrary order from 1 to nc, where +*  nc is the total number of components found, 0 <= nc <= |V|. However, +*  the component numbering has the property that for every arc (i->j) +*  in the graph the condition num(i) >= num(j) holds. +* +*  RETURNS +* +*  The routine returns nc, the total number of components found. */ + +int glp_strong_comp(glp_graph *G, int v_num) +{     glp_vertex *v; +      glp_arc *a; +      int i, k, last, n, na, nc, *icn, *ip, *lenr, *ior, *ib, *lowl, +         *numb, *prev; +      if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int)) +         xerror("glp_strong_comp: v_num = %d; invalid offset\n", +            v_num); +      n = G->nv; +      if (n == 0) +      {  nc = 0; +         goto done; +      } +      na = G->na; +      icn = xcalloc(1+na, sizeof(int)); +      ip = xcalloc(1+n, sizeof(int)); +      lenr = xcalloc(1+n, sizeof(int)); +      ior = xcalloc(1+n, sizeof(int)); +      ib = xcalloc(1+n, sizeof(int)); +      lowl = xcalloc(1+n, sizeof(int)); +      numb = xcalloc(1+n, sizeof(int)); +      prev = xcalloc(1+n, sizeof(int)); +      k = 1; +      for (i = 1; i <= n; i++) +      {  v = G->v[i]; +         ip[i] = k; +         for (a = v->out; a != NULL; a = a->t_next) +            icn[k++] = a->head->i; +         lenr[i] = k - ip[i]; +      } +      xassert(na == k-1); +      nc = mc13d(n, icn, ip, lenr, ior, ib, lowl, numb, prev); +      if (v_num >= 0) +      {  xassert(ib[1] == 1); +         for (k = 1; k <= nc; k++) +         {  last = (k < nc ? ib[k+1] : n+1); +            xassert(ib[k] < last); +            for (i = ib[k]; i < last; i++) +            {  v = G->v[ior[i]]; +               memcpy((char *)v->data + v_num, &k, sizeof(int)); +            } +         } +      } +      xfree(icn); +      xfree(ip); +      xfree(lenr); +      xfree(ior); +      xfree(ib); +      xfree(lowl); +      xfree(numb); +      xfree(prev); +done: return nc; +} + +/* eof */ diff --git a/glpk-5.0/src/api/topsort.c b/glpk-5.0/src/api/topsort.c new file mode 100644 index 0000000..d7aa7cc --- /dev/null +++ b/glpk-5.0/src/api/topsort.c @@ -0,0 +1,121 @@ +/* topsort.c (topological sorting of acyclic digraph) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2010-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" + +/*********************************************************************** +*  NAME +* +*  glp_top_sort - topological sorting of acyclic digraph +* +*  SYNOPSIS +* +*  int glp_top_sort(glp_graph *G, int v_num); +* +*  DESCRIPTION +* +*  The routine glp_top_sort performs topological sorting of vertices of +*  the specified acyclic digraph. +* +*  The parameter v_num specifies an offset of the field of type int in +*  the vertex data block, to which the routine stores the vertex number +*  assigned. If v_num < 0, vertex numbers are not stored. +* +*  The vertices are numbered from 1 to n, where n is the total number +*  of vertices in the graph. The vertex numbering has the property that +*  for every arc (i->j) in the graph the condition num(i) < num(j) +*  holds. Special case num(i) = 0 means that vertex i is not assigned a +*  number, because the graph is *not* acyclic. +* +*  RETURNS +* +*  If the graph is acyclic and therefore all the vertices have been +*  assigned numbers, the routine glp_top_sort returns zero. Otherwise, +*  if the graph is not acyclic, the routine returns the number of +*  vertices which have not been numbered, i.e. for which num(i) = 0. */ + +static int top_sort(glp_graph *G, int num[]) +{     glp_arc *a; +      int i, j, cnt, top, *stack, *indeg; +      /* allocate working arrays */ +      indeg = xcalloc(1+G->nv, sizeof(int)); +      stack = xcalloc(1+G->nv, sizeof(int)); +      /* determine initial indegree of each vertex; push into the stack +         the vertices having zero indegree */ +      top = 0; +      for (i = 1; i <= G->nv; i++) +      {  num[i] = indeg[i] = 0; +         for (a = G->v[i]->in; a != NULL; a = a->h_next) +            indeg[i]++; +         if (indeg[i] == 0) +            stack[++top] = i; +      } +      /* assign numbers to vertices in the sorted order */ +      cnt = 0; +      while (top > 0) +      {  /* pull vertex i from the stack */ +         i = stack[top--]; +         /* it has zero indegree in the current graph */ +         xassert(indeg[i] == 0); +         /* so assign it a next number */ +         xassert(num[i] == 0); +         num[i] = ++cnt; +         /* remove vertex i from the current graph, update indegree of +            its adjacent vertices, and push into the stack new vertices +            whose indegree becomes zero */ +         for (a = G->v[i]->out; a != NULL; a = a->t_next) +         {  j = a->head->i; +            /* there exists arc (i->j) in the graph */ +            xassert(indeg[j] > 0); +            indeg[j]--; +            if (indeg[j] == 0) +               stack[++top] = j; +         } +      } +      /* free working arrays */ +      xfree(indeg); +      xfree(stack); +      return G->nv - cnt; +} + +int glp_top_sort(glp_graph *G, int v_num) +{     glp_vertex *v; +      int i, cnt, *num; +      if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int)) +         xerror("glp_top_sort: v_num = %d; invalid offset\n", v_num); +      if (G->nv == 0) +      {  cnt = 0; +         goto done; +      } +      num = xcalloc(1+G->nv, sizeof(int)); +      cnt = top_sort(G, num); +      if (v_num >= 0) +      {  for (i = 1; i <= G->nv; i++) +         {  v = G->v[i]; +            memcpy((char *)v->data + v_num, &num[i], sizeof(int)); +         } +      } +      xfree(num); +done: return cnt; +} + +/* eof */ diff --git a/glpk-5.0/src/api/wcliqex.c b/glpk-5.0/src/api/wcliqex.c new file mode 100644 index 0000000..7008b95 --- /dev/null +++ b/glpk-5.0/src/api/wcliqex.c @@ -0,0 +1,120 @@ +/* wcliqex.c (find maximum weight clique with exact algorithm) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" +#include "wclique.h" + +static void set_edge(int nv, unsigned char a[], int i, int j) +{     int k; +      xassert(1 <= j && j < i && i <= nv); +      k = ((i - 1) * (i - 2)) / 2 + (j - 1); +      a[k / CHAR_BIT] |= +         (unsigned char)(1 << ((CHAR_BIT - 1) - k % CHAR_BIT)); +      return; +} + +int glp_wclique_exact(glp_graph *G, int v_wgt, double *sol, int v_set) +{     /* find maximum weight clique with exact algorithm */ +      glp_arc *e; +      int i, j, k, len, x, *w, *ind, ret = 0; +      unsigned char *a; +      double s, t; +      if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double)) +         xerror("glp_wclique_exact: v_wgt = %d; invalid parameter\n", +            v_wgt); +      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int)) +         xerror("glp_wclique_exact: v_set = %d; invalid parameter\n", +            v_set); +      if (G->nv == 0) +      {  /* empty graph has only empty clique */ +         if (sol != NULL) *sol = 0.0; +         return 0; +      } +      /* allocate working arrays */ +      w = xcalloc(1+G->nv, sizeof(int)); +      ind = xcalloc(1+G->nv, sizeof(int)); +      len = G->nv; /* # vertices */ +      len = len * (len - 1) / 2; /* # entries in lower triangle */ +      len = (len + (CHAR_BIT - 1)) / CHAR_BIT; /* # bytes needed */ +      a = xcalloc(len, sizeof(char)); +      memset(a, 0, len * sizeof(char)); +      /* determine vertex weights */ +      s = 0.0; +      for (i = 1; i <= G->nv; i++) +      {  if (v_wgt >= 0) +         {  memcpy(&t, (char *)G->v[i]->data + v_wgt, sizeof(double)); +            if (!(0.0 <= t && t <= (double)INT_MAX && t == floor(t))) +            {  ret = GLP_EDATA; +               goto done; +            } +            w[i] = (int)t; +         } +         else +            w[i] = 1; +         s += (double)w[i]; +      } +      if (s > (double)INT_MAX) +      {  ret = GLP_EDATA; +         goto done; +      } +      /* build the adjacency matrix */ +      for (i = 1; i <= G->nv; i++) +      {  for (e = G->v[i]->in; e != NULL; e = e->h_next) +         {  j = e->tail->i; +            /* there exists edge (j,i) in the graph */ +            if (i > j) set_edge(G->nv, a, i, j); +         } +         for (e = G->v[i]->out; e != NULL; e = e->t_next) +         {  j = e->head->i; +            /* there exists edge (i,j) in the graph */ +            if (i > j) set_edge(G->nv, a, i, j); +         } +      } +      /* find maximum weight clique in the graph */ +      len = wclique(G->nv, w, a, ind); +      /* compute the clique weight */ +      s = 0.0; +      for (k = 1; k <= len; k++) +      {  i = ind[k]; +         xassert(1 <= i && i <= G->nv); +         s += (double)w[i]; +      } +      if (sol != NULL) *sol = s; +      /* mark vertices included in the clique */ +      if (v_set >= 0) +      {  x = 0; +         for (i = 1; i <= G->nv; i++) +            memcpy((char *)G->v[i]->data + v_set, &x, sizeof(int)); +         x = 1; +         for (k = 1; k <= len; k++) +         {  i = ind[k]; +            memcpy((char *)G->v[i]->data + v_set, &x, sizeof(int)); +         } +      } +done: /* free working arrays */ +      xfree(w); +      xfree(ind); +      xfree(a); +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/weak.c b/glpk-5.0/src/api/weak.c new file mode 100644 index 0000000..a34d5a7 --- /dev/null +++ b/glpk-5.0/src/api/weak.c @@ -0,0 +1,148 @@ +/* weak.c (find all weakly connected components of graph) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" + +/*********************************************************************** +*  NAME +* +*  glp_weak_comp - find all weakly connected components of graph +* +*  SYNOPSIS +* +*  int glp_weak_comp(glp_graph *G, int v_num); +* +*  DESCRIPTION +* +*  The routine glp_weak_comp finds all weakly connected components of +*  the specified graph. +* +*  The parameter v_num specifies an offset of the field of type int +*  in the vertex data block, to which the routine stores the number of +*  a (weakly) connected component containing that vertex. If v_num < 0, +*  no component numbers are stored. +* +*  The components are numbered in arbitrary order from 1 to nc, where +*  nc is the total number of components found, 0 <= nc <= |V|. +* +*  RETURNS +* +*  The routine returns nc, the total number of components found. */ + +int glp_weak_comp(glp_graph *G, int v_num) +{     glp_vertex *v; +      glp_arc *a; +      int f, i, j, nc, nv, pos1, pos2, *prev, *next, *list; +      if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int)) +         xerror("glp_weak_comp: v_num = %d; invalid offset\n", v_num); +      nv = G->nv; +      if (nv == 0) +      {  nc = 0; +         goto done; +      } +      /* allocate working arrays */ +      prev = xcalloc(1+nv, sizeof(int)); +      next = xcalloc(1+nv, sizeof(int)); +      list = xcalloc(1+nv, sizeof(int)); +      /* if vertex i is unlabelled, prev[i] is the index of previous +         unlabelled vertex, and next[i] is the index of next unlabelled +         vertex; if vertex i is labelled, then prev[i] < 0, and next[i] +         is the connected component number */ +      /* initially all vertices are unlabelled */ +      f = 1; +      for (i = 1; i <= nv; i++) +         prev[i] = i - 1, next[i] = i + 1; +      next[nv] = 0; +      /* main loop (until all vertices have been labelled) */ +      nc = 0; +      while (f != 0) +      {  /* take an unlabelled vertex */ +         i = f; +         /* and remove it from the list of unlabelled vertices */ +         f = next[i]; +         if (f != 0) prev[f] = 0; +         /* label the vertex; it begins a new component */ +         prev[i] = -1, next[i] = ++nc; +         /* breadth first search */ +         list[1] = i, pos1 = pos2 = 1; +         while (pos1 <= pos2) +         {  /* dequeue vertex i */ +            i = list[pos1++]; +            /* consider all arcs incoming to vertex i */ +            for (a = G->v[i]->in; a != NULL; a = a->h_next) +            {  /* vertex j is adjacent to vertex i */ +               j = a->tail->i; +               if (prev[j] >= 0) +               {  /* vertex j is unlabelled */ +                  /* remove it from the list of unlabelled vertices */ +                  if (prev[j] == 0) +                     f = next[j]; +                  else +                     next[prev[j]] = next[j]; +                  if (next[j] == 0) +                     ; +                  else +                     prev[next[j]] = prev[j]; +                  /* label the vertex */ +                  prev[j] = -1, next[j] = nc; +                  /* and enqueue it for further consideration */ +                  list[++pos2] = j; +               } +            } +            /* consider all arcs outgoing from vertex i */ +            for (a = G->v[i]->out; a != NULL; a = a->t_next) +            {  /* vertex j is adjacent to vertex i */ +               j = a->head->i; +               if (prev[j] >= 0) +               {  /* vertex j is unlabelled */ +                  /* remove it from the list of unlabelled vertices */ +                  if (prev[j] == 0) +                     f = next[j]; +                  else +                     next[prev[j]] = next[j]; +                  if (next[j] == 0) +                     ; +                  else +                     prev[next[j]] = prev[j]; +                  /* label the vertex */ +                  prev[j] = -1, next[j] = nc; +                  /* and enqueue it for further consideration */ +                  list[++pos2] = j; +               } +            } +         } +      } +      /* store component numbers */ +      if (v_num >= 0) +      {  for (i = 1; i <= nv; i++) +         {  v = G->v[i]; +            memcpy((char *)v->data + v_num, &next[i], sizeof(int)); +         } +      } +      /* free working arrays */ +      xfree(prev); +      xfree(next); +      xfree(list); +done: return nc; +} + +/* eof */ diff --git a/glpk-5.0/src/api/wrasn.c b/glpk-5.0/src/api/wrasn.c new file mode 100644 index 0000000..0f60d8e --- /dev/null +++ b/glpk-5.0/src/api/wrasn.c @@ -0,0 +1,105 @@ +/* wrasn.c (write assignment problem data in DIMACS format) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" + +#define xfprintf        glp_format + +/*********************************************************************** +*  NAME +* +*  glp_write_asnprob - write assignment problem data in DIMACS format +* +*  SYNOPSIS +* +*  int glp_write_asnprob(glp_graph *G, int v_set, int a_cost, +*     const char *fname); +* +*  DESCRIPTION +* +*  The routine glp_write_asnprob writes assignment problem data in +*  DIMACS format to a text file. +* +*  RETURNS +* +*  If the operation was successful, the routine returns zero. Otherwise +*  it prints an error message and returns non-zero. */ + +int glp_write_asnprob(glp_graph *G, int v_set, int a_cost, const char +      *fname) +{     glp_file *fp; +      glp_vertex *v; +      glp_arc *a; +      int i, k, count = 0, ret; +      double cost; +      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int)) +         xerror("glp_write_asnprob: v_set = %d; invalid offset\n", +            v_set); +      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) +         xerror("glp_write_asnprob: a_cost = %d; invalid offset\n", +            a_cost); +      xprintf("Writing assignment problem data to '%s'...\n", fname); +      fp = glp_open(fname, "w"); +      if (fp == NULL) +      {  xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); +         ret = 1; +         goto done; +      } +      xfprintf(fp, "c %s\n", +         G->name == NULL ? "unknown" : G->name), count++; +      xfprintf(fp, "p asn %d %d\n", G->nv, G->na), count++; +      for (i = 1; i <= G->nv; i++) +      {  v = G->v[i]; +         if (v_set >= 0) +            memcpy(&k, (char *)v->data + v_set, sizeof(int)); +         else +            k = (v->out != NULL ? 0 : 1); +         if (k == 0) +            xfprintf(fp, "n %d\n", i), count++; +      } +      for (i = 1; i <= G->nv; i++) +      {  v = G->v[i]; +         for (a = v->out; a != NULL; a = a->t_next) +         {  if (a_cost >= 0) +               memcpy(&cost, (char *)a->data + a_cost, sizeof(double)); +            else +               cost = 1.0; +            xfprintf(fp, "a %d %d %.*g\n", +               a->tail->i, a->head->i, DBL_DIG, cost), count++; +         } +      } +      xfprintf(fp, "c eof\n"), count++; +#if 0 /* FIXME */ +      xfflush(fp); +#endif +      if (glp_ioerr(fp)) +      {  xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); +         ret = 1; +         goto done; +      } +      xprintf("%d lines were written\n", count); +      ret = 0; +done: if (fp != NULL) glp_close(fp); +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/wrcc.c b/glpk-5.0/src/api/wrcc.c new file mode 100644 index 0000000..cf1356b --- /dev/null +++ b/glpk-5.0/src/api/wrcc.c @@ -0,0 +1,100 @@ +/* wrcc.c (write graph in DIMACS clique/coloring format) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" + +#define xfprintf        glp_format + +/*********************************************************************** +*  NAME +* +*  glp_write_ccdata - write graph in DIMACS clique/coloring format +* +*  SYNOPSIS +* +*  int glp_write_ccdata(glp_graph *G, int v_wgt, const char *fname); +* +*  DESCRIPTION +* +*  The routine glp_write_ccdata writes the specified graph in DIMACS +*  clique/coloring format to a text file. +* +*  RETURNS +* +*  If the operation was successful, the routine returns zero. Otherwise +*  it prints an error message and returns non-zero. */ + +int glp_write_ccdata(glp_graph *G, int v_wgt, const char *fname) +{     glp_file *fp; +      glp_vertex *v; +      glp_arc *e; +      int i, count = 0, ret; +      double w; +      if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double)) +         xerror("glp_write_ccdata: v_wgt = %d; invalid offset\n", +            v_wgt); +      xprintf("Writing graph to '%s'\n", fname); +      fp = glp_open(fname, "w"); +      if (fp == NULL) +      {  xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); +         ret = 1; +         goto done; +      } +      xfprintf(fp, "c %s\n", +         G->name == NULL ? "unknown" : G->name), count++; +      xfprintf(fp, "p edge %d %d\n", G->nv, G->na), count++; +      if (v_wgt >= 0) +      {  for (i = 1; i <= G->nv; i++) +         {  v = G->v[i]; +            memcpy(&w, (char *)v->data + v_wgt, sizeof(double)); +            if (w != 1.0) +               xfprintf(fp, "n %d %.*g\n", i, DBL_DIG, w), count++; +         } +      } +      for (i = 1; i <= G->nv; i++) +      {  v = G->v[i]; +         for (e = v->out; e != NULL; e = e->t_next) +            xfprintf(fp, "e %d %d\n", e->tail->i, e->head->i), count++; +      } +      xfprintf(fp, "c eof\n"), count++; +#if 0 /* FIXME */ +      xfflush(fp); +#endif +      if (glp_ioerr(fp)) +      {  xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); +         ret = 1; +         goto done; +      } +      xprintf("%d lines were written\n", count); +      ret = 0; +done: if (fp != NULL) glp_close(fp); +      return ret; +} + +/**********************************************************************/ + +int glp_write_graph(glp_graph *G, const char *fname) +{     return +         glp_write_ccdata(G, -1, fname); +} + +/* eof */ diff --git a/glpk-5.0/src/api/wrcnf.c b/glpk-5.0/src/api/wrcnf.c new file mode 100644 index 0000000..fc41fa2 --- /dev/null +++ b/glpk-5.0/src/api/wrcnf.c @@ -0,0 +1,85 @@ +/* wrcnf.c (write CNF-SAT problem data in DIMACS format) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2010-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +#define xfprintf        glp_format + +int glp_write_cnfsat(glp_prob *P, const char *fname) +{     /* write CNF-SAT problem data in DIMACS format */ +      glp_file *fp = NULL; +      GLPAIJ *aij; +      int i, j, len, count = 0, ret; +      char s[50]; +#if 0 /* 04/IV-2016 */ +      if (P == NULL || P->magic != GLP_PROB_MAGIC) +         xerror("glp_write_cnfsat: P = %p; invalid problem object\n", +            P); +#endif +      if (glp_check_cnfsat(P) != 0) +      {  xprintf("glp_write_cnfsat: problem object does not encode CNF-" +            "SAT instance\n"); +         ret = 1; +         goto done; +      } +      xprintf("Writing CNF-SAT problem data to '%s'...\n", fname); +      fp = glp_open(fname, "w"); +      if (fp == NULL) +      {  xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); +         ret = 1; +         goto done; +      } +      xfprintf(fp, "c %s\n", +         P->name == NULL ? "unknown" : P->name), count++; +      xfprintf(fp, "p cnf %d %d\n", P->n, P->m), count++; +      for (i = 1; i <= P->m; i++) +      {  len = 0; +         for (aij = P->row[i]->ptr; aij != NULL; aij = aij->r_next) +         {  j = aij->col->j; +            if (aij->val < 0.0) j = -j; +            sprintf(s, "%d", j); +            if (len > 0 && len + 1 + strlen(s) > 72) +               xfprintf(fp, "\n"), count++, len = 0; +            xfprintf(fp, "%s%s", len == 0 ? "" : " ", s); +            if (len > 0) len++; +            len += strlen(s); +         } +         if (len > 0 && len + 1 + 1 > 72) +            xfprintf(fp, "\n"), count++, len = 0; +         xfprintf(fp, "%s0\n", len == 0 ? "" : " "), count++; +      } +      xfprintf(fp, "c eof\n"), count++; +#if 0 /* FIXME */ +      xfflush(fp); +#endif +      if (glp_ioerr(fp)) +      {  xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); +         ret = 1; +         goto done; +      } +      xprintf("%d lines were written\n", count); +      ret = 0; +done: if (fp != NULL) glp_close(fp); +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/wript.c b/glpk-5.0/src/api/wript.c new file mode 100644 index 0000000..f7f18fe --- /dev/null +++ b/glpk-5.0/src/api/wript.c @@ -0,0 +1,122 @@ +/* wript.c (write interior-point solution in GLPK format) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2010-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +/*********************************************************************** +*  NAME +* +*  glp_write_ipt - write interior-point solution in GLPK format +* +*  SYNOPSIS +* +*  int glp_write_ipt(glp_prob *P, const char *fname); +* +*  DESCRIPTION +* +*  The routine glp_write_ipt writes interior-point solution to a text +*  file in GLPK format. +* +*  RETURNS +* +*  If the operation was successful, the routine returns zero. Otherwise +*  it prints an error message and returns non-zero. */ + +int glp_write_ipt(glp_prob *P, const char *fname) +{     glp_file *fp; +      GLPROW *row; +      GLPCOL *col; +      int i, j, count, ret = 1; +      char *s; +#if 0 /* 04/IV-2016 */ +      if (P == NULL || P->magic != GLP_PROB_MAGIC) +         xerror("glp_write_ipt: P = %p; invalid problem object\n", P); +#endif +      if (fname == NULL) +         xerror("glp_write_ipt: fname = %d; invalid parameter\n", fname) +            ; +      xprintf("Writing interior-point solution to '%s'...\n", fname); +      fp = glp_open(fname, "w"), count = 0; +      if (fp == NULL) +      {  xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); +         goto done; +      } +      /* write comment lines */ +      glp_format(fp, "c %-12s%s\n", "Problem:", +         P->name == NULL ? "" : P->name), count++; +      glp_format(fp, "c %-12s%d\n", "Rows:", P->m), count++; +      glp_format(fp, "c %-12s%d\n", "Columns:", P->n), count++; +      glp_format(fp, "c %-12s%d\n", "Non-zeros:", P->nnz), count++; +      switch (P->ipt_stat) +      {  case GLP_OPT:    s = "OPTIMAL";                   break; +         case GLP_INFEAS: s = "INFEASIBLE (INTERMEDIATE)"; break; +         case GLP_NOFEAS: s = "INFEASIBLE (FINAL)";        break; +         case GLP_UNDEF:  s = "UNDEFINED";                 break; +         default:         s = "???";                       break; +      } +      glp_format(fp, "c %-12s%s\n", "Status:", s), count++; +      switch (P->dir) +      {  case GLP_MIN: s = "MINimum"; break; +         case GLP_MAX: s = "MAXimum"; break; +         default:      s = "???";     break; +      } +      glp_format(fp, "c %-12s%s%s%.10g (%s)\n", "Objective:", +         P->obj == NULL ? "" : P->obj, +         P->obj == NULL ? "" : " = ", P->ipt_obj, s), count++; +      glp_format(fp, "c\n"), count++; +      /* write solution line */ +      glp_format(fp, "s ipt %d %d ", P->m, P->n), count++; +      switch (P->ipt_stat) +      {  case GLP_OPT:    glp_format(fp, "o"); break; +         case GLP_INFEAS: glp_format(fp, "i"); break; +         case GLP_NOFEAS: glp_format(fp, "n"); break; +         case GLP_UNDEF:  glp_format(fp, "u"); break; +         default:         glp_format(fp, "?"); break; +      } +      glp_format(fp, " %.*g\n", DBL_DIG, P->ipt_obj); +      /* write row solution descriptor lines */ +      for (i = 1; i <= P->m; i++) +      {  row = P->row[i]; +         glp_format(fp, "i %d %.*g %.*g\n", i, DBL_DIG, row->pval, +            DBL_DIG, row->dval), count++; +      } +      /* write column solution descriptor lines */ +      for (j = 1; j <= P->n; j++) +      {  col = P->col[j]; +         glp_format(fp, "j %d %.*g %.*g\n", j, DBL_DIG, col->pval, +            DBL_DIG, col->dval), count++; +      } +      /* write end line */ +      glp_format(fp, "e o f\n"), count++; +      if (glp_ioerr(fp)) +      {  xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); +         goto done; +      } +      /* interior-point solution has been successfully written */ +      xprintf("%d lines were written\n", count); +      ret = 0; +done: if (fp != NULL) +         glp_close(fp); +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/wrmaxf.c b/glpk-5.0/src/api/wrmaxf.c new file mode 100644 index 0000000..783cfaa --- /dev/null +++ b/glpk-5.0/src/api/wrmaxf.c @@ -0,0 +1,102 @@ +/* wrmaxf.c (write maximum flow problem data in DIMACS format) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" + +#define xfprintf        glp_format + +/*********************************************************************** +*  NAME +* +*  glp_write_maxflow - write maximum flow problem data in DIMACS format +* +*  SYNOPSIS +* +*  int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap, +*     const char *fname); +* +*  DESCRIPTION +* +*  The routine glp_write_maxflow writes maximum flow problem data in +*  DIMACS format to a text file. +* +*  RETURNS +* +*  If the operation was successful, the routine returns zero. Otherwise +*  it prints an error message and returns non-zero. */ + +int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap, +      const char *fname) +{     glp_file *fp; +      glp_vertex *v; +      glp_arc *a; +      int i, count = 0, ret; +      double cap; +      if (!(1 <= s && s <= G->nv)) +         xerror("glp_write_maxflow: s = %d; source node number out of r" +            "ange\n", s); +      if (!(1 <= t && t <= G->nv)) +         xerror("glp_write_maxflow: t = %d: sink node number out of ran" +            "ge\n", t); +      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) +         xerror("glp_write_mincost: a_cap = %d; invalid offset\n", +            a_cap); +      xprintf("Writing maximum flow problem data to '%s'...\n", +         fname); +      fp = glp_open(fname, "w"); +      if (fp == NULL) +      {  xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); +         ret = 1; +         goto done; +      } +      xfprintf(fp, "c %s\n", +         G->name == NULL ? "unknown" : G->name), count++; +      xfprintf(fp, "p max %d %d\n", G->nv, G->na), count++; +      xfprintf(fp, "n %d s\n", s), count++; +      xfprintf(fp, "n %d t\n", t), count++; +      for (i = 1; i <= G->nv; i++) +      {  v = G->v[i]; +         for (a = v->out; a != NULL; a = a->t_next) +         {  if (a_cap >= 0) +               memcpy(&cap, (char *)a->data + a_cap, sizeof(double)); +            else +               cap = 1.0; +            xfprintf(fp, "a %d %d %.*g\n", +               a->tail->i, a->head->i, DBL_DIG, cap), count++; +         } +      } +      xfprintf(fp, "c eof\n"), count++; +#if 0 /* FIXME */ +      xfflush(fp); +#endif +      if (glp_ioerr(fp)) +      {  xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); +         ret = 1; +         goto done; +      } +      xprintf("%d lines were written\n", count); +      ret = 0; +done: if (fp != NULL) glp_close(fp); +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/wrmcf.c b/glpk-5.0/src/api/wrmcf.c new file mode 100644 index 0000000..234bc05 --- /dev/null +++ b/glpk-5.0/src/api/wrmcf.c @@ -0,0 +1,120 @@ +/* wrmcf.c (write min-cost flow problem data in DIMACS format) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2009-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" + +#define xfprintf        glp_format + +/*********************************************************************** +*  NAME +* +*  glp_write_mincost - write min-cost flow probl. data in DIMACS format +* +*  SYNOPSIS +* +*  int glp_write_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap, +*     int a_cost, const char *fname); +* +*  DESCRIPTION +* +*  The routine glp_write_mincost writes minimum cost flow problem data +*  in DIMACS format to a text file. +* +*  RETURNS +* +*  If the operation was successful, the routine returns zero. Otherwise +*  it prints an error message and returns non-zero. */ + +int glp_write_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap, +      int a_cost, const char *fname) +{     glp_file *fp; +      glp_vertex *v; +      glp_arc *a; +      int i, count = 0, ret; +      double rhs, low, cap, cost; +      if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double)) +         xerror("glp_write_mincost: v_rhs = %d; invalid offset\n", +            v_rhs); +      if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double)) +         xerror("glp_write_mincost: a_low = %d; invalid offset\n", +            a_low); +      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) +         xerror("glp_write_mincost: a_cap = %d; invalid offset\n", +            a_cap); +      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) +         xerror("glp_write_mincost: a_cost = %d; invalid offset\n", +            a_cost); +      xprintf("Writing min-cost flow problem data to '%s'...\n", +         fname); +      fp = glp_open(fname, "w"); +      if (fp == NULL) +      {  xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); +         ret = 1; +         goto done; +      } +      xfprintf(fp, "c %s\n", +         G->name == NULL ? "unknown" : G->name), count++; +      xfprintf(fp, "p min %d %d\n", G->nv, G->na), count++; +      if (v_rhs >= 0) +      {  for (i = 1; i <= G->nv; i++) +         {  v = G->v[i]; +            memcpy(&rhs, (char *)v->data + v_rhs, sizeof(double)); +            if (rhs != 0.0) +               xfprintf(fp, "n %d %.*g\n", i, DBL_DIG, rhs), count++; +         } +      } +      for (i = 1; i <= G->nv; i++) +      {  v = G->v[i]; +         for (a = v->out; a != NULL; a = a->t_next) +         {  if (a_low >= 0) +               memcpy(&low, (char *)a->data + a_low, sizeof(double)); +            else +               low = 0.0; +            if (a_cap >= 0) +               memcpy(&cap, (char *)a->data + a_cap, sizeof(double)); +            else +               cap = 1.0; +            if (a_cost >= 0) +               memcpy(&cost, (char *)a->data + a_cost, sizeof(double)); +            else +               cost = 0.0; +            xfprintf(fp, "a %d %d %.*g %.*g %.*g\n", +               a->tail->i, a->head->i, DBL_DIG, low, DBL_DIG, cap, +               DBL_DIG, cost), count++; +         } +      } +      xfprintf(fp, "c eof\n"), count++; +#if 0 /* FIXME */ +      xfflush(fp); +#endif +      if (glp_ioerr(fp)) +      {  xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); +         ret = 1; +         goto done; +      } +      xprintf("%d lines were written\n", count); +      ret = 0; +done: if (fp != NULL) glp_close(fp); +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/wrmip.c b/glpk-5.0/src/api/wrmip.c new file mode 100644 index 0000000..4ae36db --- /dev/null +++ b/glpk-5.0/src/api/wrmip.c @@ -0,0 +1,120 @@ +/* wrmip.c (write MIP solution in GLPK format) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2010-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +/*********************************************************************** +*  NAME +* +*  glp_write_mip - write MIP solution in GLPK format +* +*  SYNOPSIS +* +*  int glp_write_mip(glp_prob *P, const char *fname); +* +*  DESCRIPTION +* +*  The routine glp_write_mip writes MIP solution to a text file in GLPK +*  format. +* +*  RETURNS +* +*  If the operation was successful, the routine returns zero. Otherwise +*  it prints an error message and returns non-zero. */ + +int glp_write_mip(glp_prob *P, const char *fname) +{     glp_file *fp; +      GLPROW *row; +      GLPCOL *col; +      int i, j, count, ret = 1; +      char *s; +#if 0 /* 04/IV-2016 */ +      if (P == NULL || P->magic != GLP_PROB_MAGIC) +         xerror("glp_write_mip: P = %p; invalid problem object\n", P); +#endif +      if (fname == NULL) +         xerror("glp_write_mip: fname = %d; invalid parameter\n", fname) +            ; +      xprintf("Writing MIP solution to '%s'...\n", fname); +      fp = glp_open(fname, "w"), count = 0; +      if (fp == NULL) +      {  xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); +         goto done; +      } +      /* write comment lines */ +      glp_format(fp, "c %-12s%s\n", "Problem:", +         P->name == NULL ? "" : P->name), count++; +      glp_format(fp, "c %-12s%d\n", "Rows:", P->m), count++; +      glp_format(fp, "c %-12s%d\n", "Columns:", P->n), count++; +      glp_format(fp, "c %-12s%d\n", "Non-zeros:", P->nnz), count++; +      switch (P->mip_stat) +      {  case GLP_OPT:    s = "INTEGER OPTIMAL";           break; +         case GLP_FEAS:   s = "INTEGER NON-OPTIMAL";       break; +         case GLP_NOFEAS: s = "INTEGER EMPTY";             break; +         case GLP_UNDEF:  s = "INTEGER UNDEFINED";         break; +         default:         s = "???";                       break; +      } +      glp_format(fp, "c %-12s%s\n", "Status:", s), count++; +      switch (P->dir) +      {  case GLP_MIN: s = "MINimum"; break; +         case GLP_MAX: s = "MAXimum"; break; +         default:      s = "???";     break; +      } +      glp_format(fp, "c %-12s%s%s%.10g (%s)\n", "Objective:", +         P->obj == NULL ? "" : P->obj, +         P->obj == NULL ? "" : " = ", P->mip_obj, s), count++; +      glp_format(fp, "c\n"), count++; +      /* write solution line */ +      glp_format(fp, "s mip %d %d ", P->m, P->n), count++; +      switch (P->mip_stat) +      {  case GLP_OPT:    glp_format(fp, "o"); break; +         case GLP_FEAS:   glp_format(fp, "f"); break; +         case GLP_NOFEAS: glp_format(fp, "n"); break; +         case GLP_UNDEF:  glp_format(fp, "u"); break; +         default:         glp_format(fp, "?"); break; +      } +      glp_format(fp, " %.*g\n", DBL_DIG, P->mip_obj); +      /* write row solution descriptor lines */ +      for (i = 1; i <= P->m; i++) +      {  row = P->row[i]; +         glp_format(fp, "i %d %.*g\n", i, DBL_DIG, row->mipx), count++; +      } +      /* write column solution descriptor lines */ +      for (j = 1; j <= P->n; j++) +      {  col = P->col[j]; +         glp_format(fp, "j %d %.*g\n", j, DBL_DIG, col->mipx), count++; +      } +      /* write end line */ +      glp_format(fp, "e o f\n"), count++; +      if (glp_ioerr(fp)) +      {  xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); +         goto done; +      } +      /* MIP solution has been successfully written */ +      xprintf("%d lines were written\n", count); +      ret = 0; +done: if (fp != NULL) +         glp_close(fp); +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/wrprob.c b/glpk-5.0/src/api/wrprob.c new file mode 100644 index 0000000..52f016a --- /dev/null +++ b/glpk-5.0/src/api/wrprob.c @@ -0,0 +1,164 @@ +/* wrprob.c (write problem data in GLPK format) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2010-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +#define xfprintf        glp_format + +/*********************************************************************** +*  NAME +* +*  glp_write_prob - write problem data in GLPK format +* +*  SYNOPSIS +* +*  int glp_write_prob(glp_prob *P, int flags, const char *fname); +* +*  The routine glp_write_prob writes problem data in GLPK LP/MIP format +*  to a text file. +* +*  RETURNS +* +*  If the operation was successful, the routine returns zero. Otherwise +*  it prints an error message and returns non-zero. */ + +int glp_write_prob(glp_prob *P, int flags, const char *fname) +{     glp_file *fp; +      GLPROW *row; +      GLPCOL *col; +      GLPAIJ *aij; +      int mip, i, j, count, ret; +#if 0 /* 04/IV-2016 */ +      if (P == NULL || P->magic != GLP_PROB_MAGIC) +         xerror("glp_write_prob: P = %p; invalid problem object\n", +            P); +#endif +      if (flags != 0) +         xerror("glp_write_prob: flags = %d; invalid parameter\n", +            flags); +      if (fname == NULL) +         xerror("glp_write_prob: fname = %d; invalid parameter\n", +            fname); +      xprintf("Writing problem data to '%s'...\n", fname); +      fp = glp_open(fname, "w"), count = 0; +      if (fp == NULL) +      {  xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); +         ret = 1; +         goto done; +      } +      /* write problem line */ +      mip = (glp_get_num_int(P) > 0); +      xfprintf(fp, "p %s %s %d %d %d\n", !mip ? "lp" : "mip", +         P->dir == GLP_MIN ? "min" : P->dir == GLP_MAX ? "max" : "???", +         P->m, P->n, P->nnz), count++; +      if (P->name != NULL) +         xfprintf(fp, "n p %s\n", P->name), count++; +      if (P->obj != NULL) +         xfprintf(fp, "n z %s\n", P->obj), count++; +      /* write row descriptors */ +      for (i = 1; i <= P->m; i++) +      {  row = P->row[i]; +         if (row->type == GLP_FX && row->lb == 0.0) +            goto skip1; +         xfprintf(fp, "i %d ", i), count++; +         if (row->type == GLP_FR) +            xfprintf(fp, "f\n"); +         else if (row->type == GLP_LO) +            xfprintf(fp, "l %.*g\n", DBL_DIG, row->lb); +         else if (row->type == GLP_UP) +            xfprintf(fp, "u %.*g\n", DBL_DIG, row->ub); +         else if (row->type == GLP_DB) +            xfprintf(fp, "d %.*g %.*g\n", DBL_DIG, row->lb, DBL_DIG, +                  row->ub); +         else if (row->type == GLP_FX) +            xfprintf(fp, "s %.*g\n", DBL_DIG, row->lb); +         else +            xassert(row != row); +skip1:   if (row->name != NULL) +            xfprintf(fp, "n i %d %s\n", i, row->name), count++; +      } +      /* write column descriptors */ +      for (j = 1; j <= P->n; j++) +      {  col = P->col[j]; +         if (!mip && col->type == GLP_LO && col->lb == 0.0) +            goto skip2; +         if (mip && col->kind == GLP_IV && col->type == GLP_DB && +             col->lb == 0.0 && col->ub == 1.0) +            goto skip2; +         xfprintf(fp, "j %d ", j), count++; +         if (mip) +         {  if (col->kind == GLP_CV) +               xfprintf(fp, "c "); +            else if (col->kind == GLP_IV) +               xfprintf(fp, "i "); +            else +               xassert(col != col); +         } +         if (col->type == GLP_FR) +            xfprintf(fp, "f\n"); +         else if (col->type == GLP_LO) +            xfprintf(fp, "l %.*g\n", DBL_DIG, col->lb); +         else if (col->type == GLP_UP) +            xfprintf(fp, "u %.*g\n", DBL_DIG, col->ub); +         else if (col->type == GLP_DB) +            xfprintf(fp, "d %.*g %.*g\n", DBL_DIG, col->lb, DBL_DIG, +                  col->ub); +         else if (col->type == GLP_FX) +            xfprintf(fp, "s %.*g\n", DBL_DIG, col->lb); +         else +            xassert(col != col); +skip2:   if (col->name != NULL) +            xfprintf(fp, "n j %d %s\n", j, col->name), count++; +      } +      /* write objective coefficient descriptors */ +      if (P->c0 != 0.0) +         xfprintf(fp, "a 0 0 %.*g\n", DBL_DIG, P->c0), count++; +      for (j = 1; j <= P->n; j++) +      {  col = P->col[j]; +         if (col->coef != 0.0) +            xfprintf(fp, "a 0 %d %.*g\n", j, DBL_DIG, col->coef), +               count++; +      } +      /* write constraint coefficient descriptors */ +      for (i = 1; i <= P->m; i++) +      {  row = P->row[i]; +         for (aij = row->ptr; aij != NULL; aij = aij->r_next) +            xfprintf(fp, "a %d %d %.*g\n", i, aij->col->j, DBL_DIG, +               aij->val), count++; +      } +      /* write end line */ +      xfprintf(fp, "e o f\n"), count++; +#if 0 /* FIXME */ +      xfflush(fp); +#endif +      if (glp_ioerr(fp)) +      {  xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); +         ret = 1; +         goto done; +      } +      xprintf("%d lines were written\n", count); +      ret = 0; +done: if (fp != NULL) glp_close(fp); +      return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/wrsol.c b/glpk-5.0/src/api/wrsol.c new file mode 100644 index 0000000..85e7dd8 --- /dev/null +++ b/glpk-5.0/src/api/wrsol.c @@ -0,0 +1,172 @@ +/* wrsol.c (write basic solution in GLPK format) */ + +/*********************************************************************** +*  This code is part of GLPK (GNU Linear Programming Kit). +*  Copyright (C) 2010-2016 Free Software Foundation, Inc. +*  Written by Andrew Makhorin <mao@gnu.org>. +* +*  GLPK is free software: you can redistribute it and/or modify it +*  under the terms of the GNU General Public License as published by +*  the Free Software Foundation, either version 3 of the License, or +*  (at your option) any later version. +* +*  GLPK is distributed in the hope that it will be useful, but WITHOUT +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +*  License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +/*********************************************************************** +*  NAME +* +*  glp_write_sol - write basic solution in GLPK format +* +*  SYNOPSIS +* +*  int glp_write_sol(glp_prob *P, const char *fname); +* +*  DESCRIPTION +* +*  The routine glp_write_sol writes basic solution to a text file in +*  GLPK format. +* +*  RETURNS +* +*  If the operation was successful, the routine returns zero. Otherwise +*  it prints an error message and returns non-zero. */ + +int glp_write_sol(glp_prob *P, const char *fname) +{     glp_file *fp; +      GLPROW *row; +      GLPCOL *col; +      int i, j, count, ret = 1; +      char *s; +#if 0 /* 04/IV-2016 */ +      if (P == NULL || P->magic != GLP_PROB_MAGIC) +         xerror("glp_write_sol: P = %p; invalid problem object\n", P); +#endif +      if (fname == NULL) +         xerror("glp_write_sol: fname = %d; invalid parameter\n", fname) +            ; +      xprintf("Writing basic solution to '%s'...\n", fname); +      fp = glp_open(fname, "w"), count = 0; +      if (fp == NULL) +      {  xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); +         goto done; +      } +      /* write comment lines */ +      glp_format(fp, "c %-12s%s\n", "Problem:", +         P->name == NULL ? "" : P->name), count++; +      glp_format(fp, "c %-12s%d\n", "Rows:", P->m), count++; +      glp_format(fp, "c %-12s%d\n", "Columns:", P->n), count++; +      glp_format(fp, "c %-12s%d\n", "Non-zeros:", P->nnz), count++; +      switch (glp_get_status(P)) +      {  case GLP_OPT:    s = "OPTIMAL";                   break; +         case GLP_FEAS:   s = "FEASIBLE";                  break; +         case GLP_INFEAS: s = "INFEASIBLE (INTERMEDIATE)"; break; +         case GLP_NOFEAS: s = "INFEASIBLE (FINAL)";        break; +         case GLP_UNBND:  s = "UNBOUNDED";                 break; +         case GLP_UNDEF:  s = "UNDEFINED";                 break; +         default:         s = "???";                       break; +      } +      glp_format(fp, "c %-12s%s\n", "Status:", s), count++; +      switch (P->dir) +      {  case GLP_MIN: s = "MINimum"; break; +         case GLP_MAX: s = "MAXimum"; break; +         default:      s = "???";     break; +      } +      glp_format(fp, "c %-12s%s%s%.10g (%s)\n", "Objective:", +         P->obj == NULL ? "" : P->obj, +         P->obj == NULL ? "" : " = ", P->obj_val, s), count++; +      glp_format(fp, "c\n"), count++; +      /* write solution line */ +      glp_format(fp, "s bas %d %d ", P->m, P->n), count++; +      switch (P->pbs_stat) +      {  case GLP_UNDEF:  glp_format(fp, "u"); break; +         case GLP_FEAS:   glp_format(fp, "f"); break; +         case GLP_INFEAS: glp_format(fp, "i"); break; +         case GLP_NOFEAS: glp_format(fp, "n"); break; +         default:         glp_format(fp, "?"); break; +      } +      glp_format(fp, " "); +      switch (P->dbs_stat) +      {  case GLP_UNDEF:  glp_format(fp, "u"); break; +         case GLP_FEAS:   glp_format(fp, "f"); break; +         case GLP_INFEAS: glp_format(fp, "i"); break; +         case GLP_NOFEAS: glp_format(fp, "n"); break; +         default:         glp_format(fp, "?"); break; +      } +      glp_format(fp, " %.*g\n", DBL_DIG, P->obj_val); +      /* write row solution descriptor lines */ +      for (i = 1; i <= P->m; i++) +      {  row = P->row[i]; +         glp_format(fp, "i %d ", i), count++; +         switch (row->stat) +         {  case GLP_BS: +               glp_format(fp, "b"); +               break; +            case GLP_NL: +               glp_format(fp, "l"); +               break; +            case GLP_NU: +               glp_format(fp, "u"); +               break; +            case GLP_NF: +               glp_format(fp, "f"); +               break; +            case GLP_NS: +               glp_format(fp, "s"); +               break; +            default: +               xassert(row != row); +         } +         glp_format(fp, " %.*g %.*g\n", DBL_DIG, row->prim, DBL_DIG, +            row->dual); +      } +      /* write column solution descriptor lines */ +      for (j = 1; j <= P->n; j++) +      {  col = P->col[j]; +         glp_format(fp, "j %d ", j), count++; +         switch (col->stat) +         {  case GLP_BS: +               glp_format(fp, "b"); +               break; +            case GLP_NL: +               glp_format(fp, "l"); +               break; +            case GLP_NU: +               glp_format(fp, "u"); +               break; +            case GLP_NF: +               glp_format(fp, "f"); +               break; +            case GLP_NS: +               glp_format(fp, "s"); +               break; +            default: +               xassert(col != col); +         } +         glp_format(fp, " %.*g %.*g\n", DBL_DIG, col->prim, DBL_DIG, +            col->dual); +      } +      /* write end line */ +      glp_format(fp, "e o f\n"), count++; +      if (glp_ioerr(fp)) +      {  xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); +         goto done; +      } +      /* basic solution has been successfully written */ +      xprintf("%d lines were written\n", count); +      ret = 0; +done: if (fp != NULL) +         glp_close(fp); +      return ret; +} + +/* eof */  | 
