/* glpapi2.c (glp_call_rsm1) */

/*----------------------------------------------------------------------
-- Copyright (C) 2000, 2001, 2002 Andrew Makhorin <mao@mai2.rcnet.ru>,
--               Department for Applied Informatics, Moscow Aviation
--               Institute, Moscow, Russia. All rights reserved.
--
-- This file is a part of GLPK (GNU Linear Programming Kit).
--
-- 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 2, 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; see the file COPYING. If not, write to the Free
-- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-- 02111-1307, USA.
----------------------------------------------------------------------*/

#include <stddef.h>
#include "glpk.h"
#include "glprsm.h"

/*----------------------------------------------------------------------
-- glp_init_rsm1 - initialize parameter block by default values.
--
-- *Synopsis*
--
-- #include "glpk.h"
-- void glp_init_rsm1(struct rsm1 *parm);
--
-- *Description*
--
-- The routine glp_init_rsm1 initializes parameter block passed to the
-- revised simplex method by default values. */

void glp_init_rsm1(struct rsm1 *parm)
{     parm->what = 2;
      parm->scale = 1;
      parm->dual = 0;
      parm->steep = 1;
      parm->relax = 1;
      parm->tol_bnd = 1e-8;
      parm->tol_dj = 1e-7;
      parm->tol_piv = 1e-10;
      parm->iter_max = 0;
      parm->round = 1;
      return;
}

/*----------------------------------------------------------------------
-- glp_call_rsm1 - solve LP problem using revised simplex method.
--
-- *Synopsis*
--
-- #include "glpk.h"
-- int glp_call_rsm1(LPI *lpi, struct rsm1 *parm);
--
-- *Description*
--
-- The routine glp_call_rsm1 is an interface to a LP problem solver
-- based on the two-phase revised simplex method.
--
-- This routine obtains problem data from the problem object, which the
-- parameter lpi points to, solves the problem, and stores the computed
-- solution back to the problem object.
--
-- The parameter parm is a pointer to the parameter block used by the
-- solver. This block may be initialized by the routine glp_init_rsm1
-- by standard default values. It is allowed to specify NULL, in which
-- case standard default values are used. If the problem is not very
-- hard, standard default values fit for most cases.
--
-- Since large-scale problems may take a long time, the solver reports
-- some visual information about current status of the search. This
-- information is sent to stdout approximately once per second and has
-- the following format:
--
--    *nnn:   objval = xxx   infsum = yyy (ddd)
--
-- where nnn is an iteration count, xxx is the current value of the
-- objective function (which is unscaled and has correct sign), yyy is
-- the sum of infeasibilities (which is scaled and therefore it may be
-- used only for visual estimating), ddd is the current number of basis
-- fixed variables. If the asterisk (*) precedes to nnn, the solver is
-- searching for optimal solution (i.e. the feasible solution has been
-- found yet), otherwise the solver is searching for some feasible
-- solution.
--
-- Please note that this solver is not perfect. Although it has been
-- successfully tested on a wide set of real LP problems, there are so
-- called hard problems, which can't be resolved by this solver.
--
-- *Returns*
--
-- The routine glp_call_rsm1 returns one of the following codes:
--
-- 0 - no errors. This case means that the solver has successfully
--     finished solving the problem. (Note, for example, if the problem
--     has no feasible solution, the solver returns zero code);
-- 1 - iteration limit exceeded. In this case the solver reports the
--     recently obtained basis solution;
-- 2 - numerical problems with basis matrix. This case means that the
--     solver is not able to solve the problem. */

int glp_call_rsm1(LPI *lpi, struct rsm1 *parm)
{     LP *lp;
      LPSOL *sol;
      struct rsm1 _parm;
      struct rsm1_cp cp;
      int ret, bstat, status, i, j;
      /* if parameter block is not specified, create the dummy one */
      if (parm == NULL)
      {  parm = &_parm;
         glp_init_rsm1(parm);
      }
      /* check control parameters for correctness */
      if (!(0 <= parm->what && parm->what <= 2))
         fault("glp_call_rsm1: what = %d; invalid parameter",
            parm->what);
      if (!(0.0 < parm->tol_bnd && parm->tol_bnd < 1.0))
         fault("glp_call_rsm1: tol_bnd = %g; invalid parameter",
            parm->tol_bnd);
      if (!(0.0 < parm->tol_dj && parm->tol_dj < 1.0))
         fault("glp_call_rsm1: tol_dj = %g; invalid parameter",
            parm->tol_dj);
      if (!(0.0 < parm->tol_piv && parm->tol_piv < 1.0))
         fault("glp_call_rsm1: tol_piv = %g; invalid parameter",
            parm->tol_piv);
      /* extract LP problem data from the problem object */
      lp = extract_prob(lpi);
      /* create LP solution block */
      sol = create_lpsol(lp->m, lp->n);
      /* prepare control parameters */
      cp.what = parm->what;
      cp.scale = parm->scale;
      cp.dual = parm->dual;
      cp.steep = parm->steep;
      cp.relax = parm->relax;
      cp.tol_bnd = parm->tol_bnd;
      cp.tol_dj = parm->tol_dj;
      cp.tol_piv = parm->tol_piv;
      cp.iter_max = parm->iter_max;
      cp.round = parm->round;
      /* call the revised simplex method */
      ret = rsm1_driver(lp, sol, &cp);
      /* store obtained LP solution back to the problem object */
      switch (sol->status)
      {  case '?':
            bstat = '?', status = GLP_UNDEF; break;
         case 'O':
            bstat = 'O', status = GLP_OPT; break;
         case 'F':
            bstat = 'P', status = GLP_FEAS; break;
         case 'I':
            bstat = 'N', status = GLP_INFEAS; break;
         case 'N':
            bstat = 'N', status = GLP_NOFEAS; break;
         case 'U':
            bstat = 'P', status = GLP_UNBND; break;
         default:
            insist(sol->status != sol->status);
      }
      glp_put_soln_info(lpi, bstat, status, sol->objval);
      for (i = 1; i <= sol->m; i++)
         glp_put_row_soln(lpi, i, sol->tagx[i], sol->valx[i],
            sol->dx[i]);
      for (j = 1; j <= sol->n; j++)
         glp_put_col_soln(lpi, j, sol->tagx[sol->m+j],
            sol->valx[sol->m+j], sol->dx[sol->m+j]);
      /* free working data structures */
      delete_lp(lp);
      delete_lpsol(sol);
      /* return to the application program */
      return ret;
}

/* eof */
