Exemple #1
0
int ios_driver(glp_tree *T)
{     int p, curr_p, p_stat, d_stat, ret;
#if 1 /* carry out to glp_tree */
      int pred_p = 0;
      /* if the current subproblem has been just created due to
         branching, pred_p is the reference number of its parent
         subproblem, otherwise pred_p is zero */
#endif
      glp_long ttt = T->tm_beg;
#if 0
      ((glp_iocp *)T->parm)->msg_lev = GLP_MSG_DBG;
#endif
      /* on entry to the B&B driver it is assumed that the active list
         contains the only active (i.e. root) subproblem, which is the
         original MIP problem to be solved */
loop: /* main loop starts here */
      /* at this point the current subproblem does not exist */
      xassert(T->curr == NULL);
      /* if the active list is empty, the search is finished */
      if (T->head == NULL)
      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
            xprintf("Active list is empty!\n");
         xassert(dmp_in_use(T->pool).lo == 0);
         ret = 0;
         goto done;
      }
      /* select some active subproblem to continue the search */
      xassert(T->next_p == 0);
      /* let the application program select subproblem */
      if (T->parm->cb_func != NULL)
      {  xassert(T->reason == 0);
         T->reason = GLP_ISELECT;
         T->parm->cb_func(T, T->parm->cb_info);
         T->reason = 0;
         if (T->stop)
         {  ret = GLP_ESTOP;
            goto done;
         }
      }
      if (T->next_p != 0)
      {  /* the application program has selected something */
         ;
      }
      else if (T->a_cnt == 1)
      {  /* the only active subproblem exists, so select it */
         xassert(T->head->next == NULL);
         T->next_p = T->head->p;
      }
      else if (T->child != 0)
      {  /* select one of branching childs suggested by the branching
            heuristic */
         T->next_p = T->child;
      }
      else
      {  /* select active subproblem as specified by the backtracking
            technique option */
         T->next_p = ios_choose_node(T);
      }
      /* the active subproblem just selected becomes current */
      ios_revive_node(T, T->next_p);
      T->next_p = T->child = 0;
      /* invalidate pred_p, if it is not the reference number of the
         parent of the current subproblem */
      if (T->curr->up != NULL && T->curr->up->p != pred_p) pred_p = 0;
      /* determine the reference number of the current subproblem */
      p = T->curr->p;
      if (T->parm->msg_lev >= GLP_MSG_DBG)
      {  xprintf("-----------------------------------------------------"
            "-------------------\n");
         xprintf("Processing node %d at level %d\n", p, T->curr->level);
      }
      /* if it is the root subproblem, initialize cut generators */
      if (p == 1)
      {  if (T->parm->gmi_cuts == GLP_ON)
         {  if (T->parm->msg_lev >= GLP_MSG_ALL)
               xprintf("Gomory's cuts enabled\n");
         }
         if (T->parm->mir_cuts == GLP_ON)
         {  if (T->parm->msg_lev >= GLP_MSG_ALL)
               xprintf("MIR cuts enabled\n");
            xassert(T->mir_gen == NULL);
            T->mir_gen = ios_mir_init(T);
         }
         if (T->parm->cov_cuts == GLP_ON)
         {  if (T->parm->msg_lev >= GLP_MSG_ALL)
               xprintf("Cover cuts enabled\n");
         }
         if (T->parm->clq_cuts == GLP_ON)
         {  xassert(T->clq_gen == NULL);
            if (T->parm->msg_lev >= GLP_MSG_ALL)
               xprintf("Clique cuts enabled\n");
            T->clq_gen = ios_clq_init(T);
         }
      }
more: /* minor loop starts here */
      /* at this point the current subproblem needs either to be solved
         for the first time or re-optimized due to reformulation */
      /* display current progress of the search */
      if (T->parm->msg_lev >= GLP_MSG_DBG ||
          T->parm->msg_lev >= GLP_MSG_ON &&
        (double)(T->parm->out_frq - 1) <=
            1000.0 * xdifftime(xtime(), T->tm_lag))
         show_progress(T, 0);
      if (T->parm->msg_lev >= GLP_MSG_ALL &&
            xdifftime(xtime(), ttt) >= 60.0)
#if 0 /* 16/II-2012 */
      {  glp_long total;
         glp_mem_usage(NULL, NULL, &total, NULL);
         xprintf("Time used: %.1f secs.  Memory used: %.1f Mb.\n",
            xdifftime(xtime(), T->tm_beg), xltod(total) / 1048576.0);
         ttt = xtime();
      }
#else
      {  size_t total;
         glp_mem_usage(NULL, NULL, &total, NULL);
         xprintf("Time used: %.1f secs.  Memory used: %.1f Mb.\n",
            xdifftime(xtime(), T->tm_beg), (double)total / 1048576.0);
         ttt = xtime();
      }
#endif
      /* check the mip gap */
      if (T->parm->mip_gap > 0.0 &&
          ios_relative_gap(T) <= T->parm->mip_gap)
      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
            xprintf("Relative gap tolerance reached; search terminated "
               "\n");
         ret = GLP_EMIPGAP;
         goto done;
      }
      /* check if the time limit has been exhausted */
      if (T->parm->tm_lim < INT_MAX &&
         (double)(T->parm->tm_lim - 1) <=
         1000.0 * xdifftime(xtime(), T->tm_beg))
      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
            xprintf("Time limit exhausted; search terminated\n");
         ret = GLP_ETMLIM;
         goto done;
      }
      /* let the application program preprocess the subproblem */
      if (T->parm->cb_func != NULL)
      {  xassert(T->reason == 0);
         T->reason = GLP_IPREPRO;
         T->parm->cb_func(T, T->parm->cb_info);
         T->reason = 0;
         if (T->stop)
         {  ret = GLP_ESTOP;
            goto done;
         }
      }
      /* perform basic preprocessing */
      if (T->parm->pp_tech == GLP_PP_NONE)
         ;
      else if (T->parm->pp_tech == GLP_PP_ROOT)
      {  if (T->curr->level == 0)
         {  if (ios_preprocess_node(T, 100))
               goto fath;
         }
      }
      else if (T->parm->pp_tech == GLP_PP_ALL)
      {  if (ios_preprocess_node(T, T->curr->level == 0 ? 100 : 10))
            goto fath;
      }
      else
         xassert(T != T);
      /* preprocessing may improve the global bound */
      if (!is_branch_hopeful(T, p))
      {  xprintf("*** not tested yet ***\n");
         goto fath;
      }
      /* solve LP relaxation of the current subproblem */
      if (T->parm->msg_lev >= GLP_MSG_DBG)
         xprintf("Solving LP relaxation...\n");
      ret = ios_solve_node(T);
      if (!(ret == 0 || ret == GLP_EOBJLL || ret == GLP_EOBJUL))
      {  if (T->parm->msg_lev >= GLP_MSG_ERR)
            xprintf("ios_driver: unable to solve current LP relaxation;"
               " glp_simplex returned %d\n", ret);
         ret = GLP_EFAIL;
         goto done;
      }
      /* analyze status of the basic solution to LP relaxation found */
      p_stat = T->mip->pbs_stat;
      d_stat = T->mip->dbs_stat;
      if (p_stat == GLP_FEAS && d_stat == GLP_FEAS)
      {  /* LP relaxation has optimal solution */
         if (T->parm->msg_lev >= GLP_MSG_DBG)
            xprintf("Found optimal solution to LP relaxation\n");
      }
      else if (d_stat == GLP_NOFEAS)
      {  /* LP relaxation has no dual feasible solution */
         /* since the current subproblem cannot have a larger feasible
            region than its parent, there is something wrong */
         if (T->parm->msg_lev >= GLP_MSG_ERR)
            xprintf("ios_driver: current LP relaxation has no dual feas"
               "ible solution\n");
         ret = GLP_EFAIL;
         goto done;
      }
      else if (p_stat == GLP_INFEAS && d_stat == GLP_FEAS)
      {  /* LP relaxation has no primal solution which is better than
            the incumbent objective value */
         xassert(T->mip->mip_stat == GLP_FEAS);
         if (T->parm->msg_lev >= GLP_MSG_DBG)
            xprintf("LP relaxation has no solution better than incumben"
               "t objective value\n");
         /* prune the branch */
         goto fath;
      }
      else if (p_stat == GLP_NOFEAS)
      {  /* LP relaxation has no primal feasible solution */
         if (T->parm->msg_lev >= GLP_MSG_DBG)
            xprintf("LP relaxation has no feasible solution\n");
         /* prune the branch */
         goto fath;
      }
      else
      {  /* other cases cannot appear */
         xassert(T->mip != T->mip);
      }
      /* at this point basic solution to LP relaxation of the current
         subproblem is optimal */
      xassert(p_stat == GLP_FEAS && d_stat == GLP_FEAS);
      xassert(T->curr != NULL);
      T->curr->lp_obj = T->mip->obj_val;
      /* thus, it defines a local bound to integer optimal solution of
         the current subproblem */
      {  double bound = T->mip->obj_val;
         /* some local bound to the current subproblem could be already
            set before, so we should only improve it */
         bound = ios_round_bound(T, bound);
         if (T->mip->dir == GLP_MIN)
         {  if (T->curr->bound < bound)
               T->curr->bound = bound;
         }
         else if (T->mip->dir == GLP_MAX)
         {  if (T->curr->bound > bound)
               T->curr->bound = bound;
         }
         else
            xassert(T->mip != T->mip);
         if (T->parm->msg_lev >= GLP_MSG_DBG)
            xprintf("Local bound is %.9e\n", bound);
      }
      /* if the local bound indicates that integer optimal solution of
         the current subproblem cannot be better than the global bound,
         prune the branch */
      if (!is_branch_hopeful(T, p))
      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
            xprintf("Current branch is hopeless and can be pruned\n");
         goto fath;
      }
      /* let the application program generate additional rows ("lazy"
         constraints) */
      xassert(T->reopt == 0);
      xassert(T->reinv == 0);
      if (T->parm->cb_func != NULL)
      {  xassert(T->reason == 0);
         T->reason = GLP_IROWGEN;
         T->parm->cb_func(T, T->parm->cb_info);
         T->reason = 0;
         if (T->stop)
         {  ret = GLP_ESTOP;
            goto done;
         }
         if (T->reopt)
         {  /* some rows were added; re-optimization is needed */
            T->reopt = T->reinv = 0;
            goto more;
         }
         if (T->reinv)
         {  /* no rows were added, however, some inactive rows were
               removed */
            T->reinv = 0;
            xassert(glp_factorize(T->mip) == 0);
         }
      }
      /* check if the basic solution is integer feasible */
      check_integrality(T);
      /* if the basic solution satisfies to all integrality conditions,
         it is a new, better integer feasible solution */
      if (T->curr->ii_cnt == 0)
      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
            xprintf("New integer feasible solution found\n");
         if (T->parm->msg_lev >= GLP_MSG_ALL)
            display_cut_info(T);
         record_solution(T);
         if (T->parm->msg_lev >= GLP_MSG_ON)
            show_progress(T, 1);
         /* make the application program happy */
         if (T->parm->cb_func != NULL)
         {  xassert(T->reason == 0);
            T->reason = GLP_IBINGO;
            T->parm->cb_func(T, T->parm->cb_info);
            T->reason = 0;
            if (T->stop)
            {  ret = GLP_ESTOP;
               goto done;
            }
         }
         /* since the current subproblem has been fathomed, prune its
            branch */
         goto fath;
      }
      /* at this point basic solution to LP relaxation of the current
         subproblem is optimal, but integer infeasible */
      /* try to fix some non-basic structural variables of integer kind
         on their current bounds due to reduced costs */
      if (T->mip->mip_stat == GLP_FEAS)
         fix_by_red_cost(T);
      /* let the application program try to find some solution to the
         original MIP with a primal heuristic */
      if (T->parm->cb_func != NULL)
      {  xassert(T->reason == 0);
         T->reason = GLP_IHEUR;
         T->parm->cb_func(T, T->parm->cb_info);
         T->reason = 0;
         if (T->stop)
         {  ret = GLP_ESTOP;
            goto done;
         }
         /* check if the current branch became hopeless */
         if (!is_branch_hopeful(T, p))
         {  if (T->parm->msg_lev >= GLP_MSG_DBG)
               xprintf("Current branch became hopeless and can be prune"
                  "d\n");
            goto fath;
         }
      }
      /* try to find solution with the feasibility pump heuristic */
      if (T->parm->fp_heur)
      {  xassert(T->reason == 0);
         T->reason = GLP_IHEUR;
         ios_feas_pump(T);
         T->reason = 0;
         /* check if the current branch became hopeless */
         if (!is_branch_hopeful(T, p))
         {  if (T->parm->msg_lev >= GLP_MSG_DBG)
               xprintf("Current branch became hopeless and can be prune"
                  "d\n");
            goto fath;
         }
      }
      /* it's time to generate cutting planes */
      xassert(T->local != NULL);
      xassert(T->local->size == 0);
      /* let the application program generate some cuts; note that it
         can add cuts either to the local cut pool or directly to the
         current subproblem */
      if (T->parm->cb_func != NULL)
      {  xassert(T->reason == 0);
         T->reason = GLP_ICUTGEN;
         T->parm->cb_func(T, T->parm->cb_info);
         T->reason = 0;
         if (T->stop)
         {  ret = GLP_ESTOP;
            goto done;
         }
      }
      /* try to generate generic cuts with built-in generators
         (as suggested by Matteo Fischetti et al. the built-in cuts
         are not generated at each branching node; an intense attempt
         of generating new cuts is only made at the root node, and then
         a moderate effort is spent after each backtracking step) */
      if (T->curr->level == 0 || pred_p == 0)
      {  xassert(T->reason == 0);
         T->reason = GLP_ICUTGEN;
         generate_cuts(T);
         T->reason = 0;
      }
      /* if the local cut pool is not empty, select useful cuts and add
         them to the current subproblem */
      if (T->local->size > 0)
      {  xassert(T->reason == 0);
         T->reason = GLP_ICUTGEN;
         ios_process_cuts(T);
         T->reason = 0;
      }
      /* clear the local cut pool */
      ios_clear_pool(T, T->local);
      /* perform re-optimization, if necessary */
      if (T->reopt)
      {  T->reopt = 0;
         T->curr->changed++;
         goto more;
      }
      /* no cuts were generated; remove inactive cuts */
      remove_cuts(T);
      if (T->parm->msg_lev >= GLP_MSG_ALL && T->curr->level == 0)
         display_cut_info(T);
      /* update history information used on pseudocost branching */
      if (T->pcost != NULL) ios_pcost_update(T);
      /* it's time to perform branching */
      xassert(T->br_var == 0);
      xassert(T->br_sel == 0);
      /* let the application program choose variable to branch on */
      if (T->parm->cb_func != NULL)
      {  xassert(T->reason == 0);
         xassert(T->br_var == 0);
         xassert(T->br_sel == 0);
         T->reason = GLP_IBRANCH;
         T->parm->cb_func(T, T->parm->cb_info);
         T->reason = 0;
         if (T->stop)
         {  ret = GLP_ESTOP;
            goto done;
         }
      }
      /* if nothing has been chosen, choose some variable as specified
         by the branching technique option */
      if (T->br_var == 0)
         T->br_var = ios_choose_var(T, &T->br_sel);
      /* perform actual branching */
      curr_p = T->curr->p;
      ret = branch_on(T, T->br_var, T->br_sel);
      T->br_var = T->br_sel = 0;
      if (ret == 0)
      {  /* both branches have been created */
         pred_p = curr_p;
         goto loop;
      }
      else if (ret == 1)
      {  /* one branch is hopeless and has been pruned, so now the
            current subproblem is other branch */
         /* the current subproblem should be considered as a new one,
            since one bound of the branching variable was changed */
         T->curr->solved = T->curr->changed = 0;
         goto more;
      }
      else if (ret == 2)
      {  /* both branches are hopeless and have been pruned; new
            subproblem selection is needed to continue the search */
         goto fath;
      }
      else
         xassert(ret != ret);
fath: /* the current subproblem has been fathomed */
      if (T->parm->msg_lev >= GLP_MSG_DBG)
         xprintf("Node %d fathomed\n", p);
      /* freeze the current subproblem */
      ios_freeze_node(T);
      /* and prune the corresponding branch of the tree */
      ios_delete_node(T, p);
      /* if a new integer feasible solution has just been found, other
         branches may become hopeless and therefore must be pruned */
      if (T->mip->mip_stat == GLP_FEAS) cleanup_the_tree(T);
      /* new subproblem selection is needed due to backtracking */
      pred_p = 0;
      goto loop;
done: /* display progress of the search on exit from the solver */
      if (T->parm->msg_lev >= GLP_MSG_ON)
         show_progress(T, 0);
      if (T->mir_gen != NULL)
         ios_mir_term(T->mir_gen), T->mir_gen = NULL;
      if (T->clq_gen != NULL)
         ios_clq_term(T->clq_gen), T->clq_gen = NULL;
      /* return to the calling program */
      return ret;
}
Exemple #2
0
int glp_main(int argc, const char *argv[])
{     /* stand-alone LP/MIP solver */
      struct csa _csa, *csa = &_csa;
      int ret;
      xlong_t start;
      /* perform initialization */
      csa->prob = glp_create_prob();
      glp_get_bfcp(csa->prob, &csa->bfcp);
      glp_init_smcp(&csa->smcp);
      csa->smcp.presolve = GLP_ON;
      glp_init_iocp(&csa->iocp);
      csa->iocp.presolve = GLP_ON;
      csa->tran = NULL;
      csa->graph = NULL;
      csa->format = FMT_MPS_FILE;
      csa->in_file = NULL;
      csa->ndf = 0;
      csa->out_dpy = NULL;
      csa->solution = SOL_BASIC;
      csa->in_res = NULL;
      csa->dir = 0;
      csa->scale = 1;
      csa->out_sol = NULL;
      csa->out_res = NULL;
      csa->out_bnds = NULL;
      csa->check = 0;
      csa->new_name = NULL;
      csa->out_mps = NULL;
      csa->out_freemps = NULL;
      csa->out_cpxlp = NULL;
      csa->out_pb = NULL;
      csa->out_npb = NULL;
      csa->log_file = NULL;
      csa->crash = USE_ADV_BASIS;
      csa->exact = 0;
      csa->xcheck = 0;
      csa->nomip = 0;
      /* parse command-line parameters */
      ret = parse_cmdline(csa, argc, argv);
      if (ret < 0)
      {  ret = EXIT_SUCCESS;
         goto done;
      }
      if (ret > 0)
      {  ret = EXIT_FAILURE;
         goto done;
      }
      /*--------------------------------------------------------------*/
      /* remove all output files specified in the command line */
      if (csa->out_dpy != NULL) remove(csa->out_dpy);
      if (csa->out_sol != NULL) remove(csa->out_sol);
      if (csa->out_res != NULL) remove(csa->out_res);
      if (csa->out_bnds != NULL) remove(csa->out_bnds);
      if (csa->out_mps != NULL) remove(csa->out_mps);
      if (csa->out_freemps != NULL) remove(csa->out_freemps);
      if (csa->out_cpxlp != NULL) remove(csa->out_cpxlp);
      if (csa->out_pb != NULL) remove(csa->out_pb);
      if (csa->out_npb != NULL) remove(csa->out_npb);
      if (csa->log_file != NULL) remove(csa->log_file);
      /*--------------------------------------------------------------*/
      /* open log file, if required */
      if (csa->log_file != NULL)
      {  if (lib_open_log(csa->log_file))
         {  xprintf("Unable to create log file\n");
            ret = EXIT_FAILURE;
            goto done;
         }
      }
      /*--------------------------------------------------------------*/
      /* read problem data from the input file */
      if (csa->in_file == NULL)
      {  xprintf("No input problem file specified; try %s --help\n",
            argv[0]);
         ret = EXIT_FAILURE;
         goto done;
      }
      if (csa->format == FMT_MPS_DECK)
      {  ret = glp_read_mps(csa->prob, GLP_MPS_DECK, NULL,
            csa->in_file);
         if (ret != 0)
err1:    {  xprintf("MPS file processing error\n");
            ret = EXIT_FAILURE;
            goto done;
         }
      }
      else if (csa->format == FMT_MPS_FILE)
      {  ret = glp_read_mps(csa->prob, GLP_MPS_FILE, NULL,
            csa->in_file);
         if (ret != 0) goto err1;
      }
      else if (csa->format == FMT_CPLEX_LP)
      {  ret = glp_read_lp(csa->prob, NULL, csa->in_file);
         if (ret != 0)
         {  xprintf("CPLEX LP file processing error\n");
            ret = EXIT_FAILURE;
            goto done;
         }
      }
      else if (csa->format == FMT_MATHPROG)
      {  int k;
         /* allocate the translator workspace */
         csa->tran = glp_mpl_alloc_wksp();
         /* read model section and optional data section */
         if (glp_mpl_read_model(csa->tran, csa->in_file, csa->ndf > 0))
err2:    {  xprintf("MathProg model processing error\n");
            ret = EXIT_FAILURE;
            goto done;
         }
         /* read optional data section(s), if necessary */
         for (k = 1; k <= csa->ndf; k++)
         {  if (glp_mpl_read_data(csa->tran, csa->in_data[k]))
               goto err2;
         }
         /* generate the model */
         if (glp_mpl_generate(csa->tran, csa->out_dpy)) goto err2;
         /* build the problem instance from the model */
         glp_mpl_build_prob(csa->tran, csa->prob);
      }
      else if (csa->format == FMT_MIN_COST)
      {  csa->graph = glp_create_graph(sizeof(v_data), sizeof(a_data));
         ret = glp_read_mincost(csa->graph, offsetof(v_data, rhs),
            offsetof(a_data, low), offsetof(a_data, cap),
            offsetof(a_data, cost), csa->in_file);
         if (ret != 0)
         {  xprintf("DIMACS file processing error\n");
            ret = EXIT_FAILURE;
            goto done;
         }
         glp_mincost_lp(csa->prob, csa->graph, GLP_ON,
            offsetof(v_data, rhs), offsetof(a_data, low),
            offsetof(a_data, cap), offsetof(a_data, cost));
         glp_set_prob_name(csa->prob, csa->in_file);
      }
      else if (csa->format == FMT_MAX_FLOW)
      {  int s, t;
         csa->graph = glp_create_graph(sizeof(v_data), sizeof(a_data));
         ret = glp_read_maxflow(csa->graph, &s, &t,
            offsetof(a_data, cap), csa->in_file);
         if (ret != 0)
         {  xprintf("DIMACS file processing error\n");
            ret = EXIT_FAILURE;
            goto done;
         }
         glp_maxflow_lp(csa->prob, csa->graph, GLP_ON, s, t,
            offsetof(a_data, cap));
         glp_set_prob_name(csa->prob, csa->in_file);
      }
      else
         xassert(csa != csa);
      /*--------------------------------------------------------------*/
      /* change problem name, if required */
      if (csa->new_name != NULL)
         glp_set_prob_name(csa->prob, csa->new_name);
      /* change optimization direction, if required */
      if (csa->dir != 0)
         glp_set_obj_dir(csa->prob, csa->dir);
      /* order rows and columns of the constraint matrix */
      lpx_order_matrix(csa->prob);
      /*--------------------------------------------------------------*/
      /* write problem data in fixed MPS format, if required */
      if (csa->out_mps != NULL)
      {  ret = glp_write_mps(csa->prob, GLP_MPS_DECK, NULL,
            csa->out_mps);
         if (ret != 0)
         {  xprintf("Unable to write problem in fixed MPS format\n");
            ret = EXIT_FAILURE;
            goto done;
         }
      }
      /* write problem data in free MPS format, if required */
      if (csa->out_freemps != NULL)
      {  ret = glp_write_mps(csa->prob, GLP_MPS_FILE, NULL,
            csa->out_freemps);
         if (ret != 0)
         {  xprintf("Unable to write problem in free MPS format\n");
            ret = EXIT_FAILURE;
            goto done;
         }
      }
      /* write problem data in CPLEX LP format, if required */
      if (csa->out_cpxlp != NULL)
      {  ret = glp_write_lp(csa->prob, NULL, csa->out_cpxlp);
         if (ret != 0)
         {  xprintf("Unable to write problem in CPLEX LP format\n");
            ret = EXIT_FAILURE;
            goto done;
         }
      }
      /* write problem data in OPB format, if required */
      if (csa->out_pb != NULL)
      {  ret = lpx_write_pb(csa->prob, csa->out_pb, 0, 0);
         if (ret != 0)
         {  xprintf("Unable to write problem in OPB format\n");
            ret = EXIT_FAILURE;
            goto done;
         }
      }
      /* write problem data in normalized OPB format, if required */
      if (csa->out_npb != NULL)
      {  ret = lpx_write_pb(csa->prob, csa->out_npb, 1, 1);
         if (ret != 0)
         {  xprintf(
               "Unable to write problem in normalized OPB format\n");
            ret = EXIT_FAILURE;
            goto done;
         }
      }
      /*--------------------------------------------------------------*/
      /* if only problem data check is required, skip computations */
      if (csa->check)
      {  ret = EXIT_SUCCESS;
         goto done;
      }
      /*--------------------------------------------------------------*/
      /* determine the solution type */
      if (!csa->nomip &&
          glp_get_num_int(csa->prob) + glp_get_num_bin(csa->prob) > 0)
      {  if (csa->solution == SOL_INTERIOR)
         {  xprintf("Interior-point method is not able to solve MIP pro"
               "blem; use --simplex\n");
            ret = EXIT_FAILURE;
            goto done;
         }
         csa->solution = SOL_INTEGER;
      }
      /*--------------------------------------------------------------*/
      /* if solution is provided, read it and skip computations */
      if (csa->in_res != NULL)
      {  if (csa->solution == SOL_BASIC)
            ret = glp_read_sol(csa->prob, csa->in_res);
         else if (csa->solution == SOL_INTERIOR)
            ret = glp_read_ipt(csa->prob, csa->in_res);
         else if (csa->solution == SOL_INTEGER)
            ret = glp_read_mip(csa->prob, csa->in_res);
         else
            xassert(csa != csa);
         if (ret != 0)
         {  xprintf("Unable to read problem solution\n");
            ret = EXIT_FAILURE;
            goto done;
         }
         goto skip;
      }
      /*--------------------------------------------------------------*/
      /* scale the problem data, if required */
      if (csa->scale)
      {  if (csa->solution == SOL_BASIC && !csa->smcp.presolve ||
             csa->solution == SOL_INTERIOR ||
             csa->solution == SOL_INTEGER && !csa->iocp.presolve)
            glp_scale_prob(csa->prob, GLP_SF_AUTO);
      }
      /* construct starting LP basis */
      if (csa->solution == SOL_BASIC && !csa->smcp.presolve ||
          csa->solution == SOL_INTEGER && !csa->iocp.presolve)
      {  if (csa->crash == USE_STD_BASIS)
            glp_std_basis(csa->prob);
         else if (csa->crash == USE_ADV_BASIS)
            glp_adv_basis(csa->prob, 0);
         else if (csa->crash == USE_CPX_BASIS)
            glp_cpx_basis(csa->prob);
         else
            xassert(csa != csa);
      }
      /*--------------------------------------------------------------*/
      /* solve the problem */
      start = xtime();
      if (csa->solution == SOL_BASIC)
      {  if (!csa->exact)
         {  glp_set_bfcp(csa->prob, &csa->bfcp);
            glp_simplex(csa->prob, &csa->smcp);
            if (csa->xcheck)
            {  if (csa->smcp.presolve &&
                   glp_get_status(csa->prob) != GLP_OPT)
                  xprintf("If you need to check final basis for non-opt"
                     "imal solution, use --nopresol\n");
               else
                  glp_exact(csa->prob, &csa->smcp);
            }
            if (csa->out_sol != NULL || csa->out_res != NULL)
            {  if (csa->smcp.presolve &&
                   glp_get_status(csa->prob) != GLP_OPT)
               xprintf("If you need actual output for non-optimal solut"
                  "ion, use --nopresol\n");
            }
         }
         else
            glp_exact(csa->prob, &csa->smcp);
      }
      else if (csa->solution == SOL_INTERIOR)
         glp_interior(csa->prob, NULL);
      else if (csa->solution == SOL_INTEGER)
      {  if (!csa->iocp.presolve)
         {  glp_set_bfcp(csa->prob, &csa->bfcp);
            glp_simplex(csa->prob, &csa->smcp);
         }
         glp_intopt(csa->prob, &csa->iocp);
      }
      else
         xassert(csa != csa);
      /*--------------------------------------------------------------*/
      /* display statistics */
      xprintf("Time used:   %.1f secs\n", xdifftime(xtime(), start));
      {  xlong_t tpeak;
         char buf[50];
         lib_mem_usage(NULL, NULL, NULL, &tpeak);
         xprintf("Memory used: %.1f Mb (%s bytes)\n",
            xltod(tpeak) / 1048576.0, xltoa(tpeak, buf));
      }
      /*--------------------------------------------------------------*/
skip: /* postsolve the model, if necessary */
      if (csa->tran != NULL)
      {  if (csa->solution == SOL_BASIC)
            ret = glp_mpl_postsolve(csa->tran, csa->prob, GLP_SOL);
         else if (csa->solution == SOL_INTERIOR)
            ret = glp_mpl_postsolve(csa->tran, csa->prob, GLP_IPT);
         else if (csa->solution == SOL_INTEGER)
            ret = glp_mpl_postsolve(csa->tran, csa->prob, GLP_MIP);
         else
            xassert(csa != csa);
         if (ret != 0)
         {  xprintf("Model postsolving error\n");
            ret = EXIT_FAILURE;
            goto done;
         }
      }
      /*--------------------------------------------------------------*/
      /* write problem solution in printable format, if required */
      if (csa->out_sol != NULL)
      {  if (csa->solution == SOL_BASIC)
            ret = lpx_print_sol(csa->prob, csa->out_sol);
         else if (csa->solution == SOL_INTERIOR)
            ret = lpx_print_ips(csa->prob, csa->out_sol);
         else if (csa->solution == SOL_INTEGER)
            ret = lpx_print_mip(csa->prob, csa->out_sol);
         else
            xassert(csa != csa);
         if (ret != 0)
         {  xprintf("Unable to write problem solution\n");
            ret = EXIT_FAILURE;
            goto done;
         }
      }
      /* write problem solution in printable format, if required */
      if (csa->out_res != NULL)
      {  if (csa->solution == SOL_BASIC)
            ret = glp_write_sol(csa->prob, csa->out_res);
         else if (csa->solution == SOL_INTERIOR)
            ret = glp_write_ipt(csa->prob, csa->out_res);
         else if (csa->solution == SOL_INTEGER)
            ret = glp_write_mip(csa->prob, csa->out_res);
         else
            xassert(csa != csa);
         if (ret != 0)
         {  xprintf("Unable to write problem solution\n");
            ret = EXIT_FAILURE;
            goto done;
         }
      }
      /* write sensitivity bounds information, if required */
      if (csa->out_bnds != NULL)
      {  if (csa->solution == SOL_BASIC)
         {  ret = lpx_print_sens_bnds(csa->prob, csa->out_bnds);
            if (ret != 0)
            {  xprintf("Unable to write sensitivity bounds information "
                  "\n");
               ret = EXIT_FAILURE;
               goto done;
            }
         }
         else
            xprintf("Cannot write sensitivity bounds information for in"
               "terior-point or MIP solution\n");
      }
      /*--------------------------------------------------------------*/
      /* all seems to be ok */
      ret = EXIT_SUCCESS;
      /*--------------------------------------------------------------*/
done: /* delete the LP/MIP problem object */
      if (csa->prob != NULL)
         glp_delete_prob(csa->prob);
      /* free the translator workspace, if necessary */
      if (csa->tran != NULL)
         glp_mpl_free_wksp(csa->tran);
      /* delete the network problem object, if necessary */
      if (csa->graph != NULL)
         glp_delete_graph(csa->graph);
      xassert(gmp_pool_count() == 0);
      gmp_free_mem();
      /* close log file, if necessary */
      if (csa->log_file != NULL) lib_close_log();
      /* check that no memory blocks are still allocated */
      {  int count;
         xlong_t total;
         lib_mem_usage(&count, NULL, &total, NULL);
         if (count != 0)
            xerror("Error: %d memory block(s) were lost\n", count);
         xassert(count == 0);
         xassert(total.lo == 0 && total.hi == 0);
      }
      /* free the library environment */
      lib_free_env();
      /* return to the control program */
      return ret;
}