Пример #1
0
static int32 ipopt_eligible_solver(slv_system_t server){
	struct rel_relation **rp;
	struct var_variable **vp;
	rel_filter_t rfilt;
	var_filter_t vfilt;

	rfilt.matchbits = (REL_CONDITIONAL |  REL_INWHEN);
	rfilt.matchvalue = (REL_CONDITIONAL | REL_INWHEN);

	vfilt.matchbits = (VAR_BINARY);
	vfilt.matchvalue = (VAR_BINARY);

	/// @todo check that there is a MAXIMIZE or MINIMIZE statement
	if (slv_get_obj_relation(server) == NULL)
		ERROR_REPORTER_HERE(ASC_USER_ERROR,"No objective function found");

	/// @todo check that there are no WHENs or CONDITIONALs
	for( rp=slv_get_solvers_rel_list(server); *rp != NULL ; ++rp ) {
		if(rel_apply_filter(*rp,&rfilt)){
			ERROR_REPORTER_NOLINE(ASC_USER_ERROR,"WHEN and CONDITIONAL Statements are not supported.");
			return(FALSE);
		}
	}

	/// @todo check that there are no discrete-valued variables
	for( vp=slv_get_solvers_var_list(server); *vp != NULL ; ++vp ) {
		if(var_apply_filter(*vp,&vfilt)){
			ERROR_REPORTER_NOLINE(ASC_USER_ERROR,"Discrete Variables not supported.");
			return(FALSE);
		}
	}

	/// @todo check anything else?

	return 1;
}
Пример #2
0
int mr_bisect_partition(mr_reorder_t *sys, mtx_region_t *reg,
                        int top, MRBlockReorderF rfunc)
{
#if MRDEBUG
  FILE *fptr;
  static mtx_region_t graph_reg;
  static int fnum;
  static char fname[80];
#endif
  mtx_block_t mb;
  mtx_block_t *mbptr;
  mtx_region_t *block;
  struct rel_relation **rp;
  mtx_coord_t coord;
  int partition, newpart,size,threshold, status = 0;
  int32 k,row,mod=0,rmax,stop,nrows;

  /* check all our pointers */

  if (sys==NULL || sys->slv == NULL || sys->mtx == NULL ||
      sys->local == NULL || sys->active == NULL ||
      sys->tmpmodlist == NULL || sys->activelen == 0 ||
      sys->cutoff < 10 || rfunc == NULL
     ) {
#if MRDEBUG
    FPRINTF(stderr,"mr_bisect_partition miscalled.\n");
#endif
    return 1;
  }

  rp = slv_get_solvers_rel_list(sys->slv);

  /* CREATE block list as needed */
  if (top==1) {
    mbptr = &mb;
    mb.nblocks = 1;
    mb.block = reg;
#if MRDEBUG
    graph_reg = *reg;
    fnum=0;
#endif
  } else {
    mbptr = mtx_block_partition(sys->mtx,reg);
    if (mbptr == NULL || (mbptr->block == NULL && mbptr->nblocks) ) {
      if (mbptr != NULL) ascfree(mbptr);
      return 1;
    }
    sys->nblts++;
  }

#if MRDEBUG
  FPRINTF(stderr,"mtx_bisect_partition2 (%d,%d - %d,%d).\n",
    reg->row.low,reg->col.low,reg->row.high,reg->col.high);
  sprintf(fname,"/tmp/bisect1.plot.%d",fnum);
  fptr = fopen(fname,"w+");
  mtx_write_region_plot(fptr,sys->mtx,&graph_reg);
  fclose(fptr);
  fnum++;
#endif

  /* tear (or skip) the k remaining partitions */
  for (k=0; k < mbptr->nblocks; k++) {
    block = &(mbptr->block[k]);
    size = block->row.high - block->row.low +1;

    /* skip 1x1, 2x2 blocks which must be full */
    if (block->row.high - block->row.low < 3) {
      continue; /* next k */
    }

    /* blocks below cutoff the user reorders instead */
    if (size < sys->cutoff) {
#if MRDEBUG
      FPRINTF(stderr,"Calling user reorder on rows %d - %d.\n",
        block->row.low,block->row.high);
#endif
      rfunc(sys->slv,sys->mtx,block);
      continue; /* next k */
    }

    /* ok, here's where we do the work */
    threshold = size/2;		/* we want to divide in approximately half */
    rmax = block->row.high;

    /* tag in block models and count in block relations */
    for (row = block->row.low; row <= rmax; row++) {
      mod = rel_model(rp[mtx_row_to_org(sys->mtx,row)]);
      if (!(sys->active[mod])) {
        sys->active[mod] = 1;
        sys->tmpmodlist[sys->tmpmodused++] = mod;
      }
      sys->local[mod]++;
    }

    /* if block is all one MODEL, tell user to eat it */
    if (sys->tmpmodused < 2) {
#if MRDEBUG
      FPRINTF(stderr,"Found oversized MODEL including relation\n");
      rel_write_name(sys->slv,rp[mtx_row_to_org(sys->mtx,rmax)],stderr);
      FPRINTF(stderr,"\nCalling user reorder on rows %d - %d.\n",
        block->row.low,block->row.high);
#endif
      /* rezero active and local arrays, just 1! */
      sys->local[0] = 0;
      sys->active[0] = 0;
      rfunc(sys->slv,sys->mtx,block);
      continue; /* next k */
    }

    /* sort the MODEL indices in tmpmodlist. using this fact later
     * enables us to punt the rel_partition flag in favor of just
     * checking MODEL index of a row against the last MODEL in the
     * first partition when hunting in incidence for complicating cols.
     * We might want to reverse things if the tree was numbered top
     * down rather than bottom up.
     * It would be nice if we could prove this sort is not needed,
     * but I haven't had the time yet to try.
     * A slightly different, probably bigger, data structure
     * might also allow the sort to be avoided.
     * Probably we should create a doubly linked list version
     * of tmpmodlist and insert sorted as it is created,
     * then map the final thing down to the vector needed.
     * Who knows? It's a small list in any case.
     */
    qsort(sys->tmpmodlist,sys->tmpmodused,sizeof(int),
          (int (*)(const void *, const void *))intcompare);

    /* now try to split tmpmodlist approximately in relation count half */
    stop = 0;
    nrows = 0;
    /* local[mod] should be the size of the last MODEL in the first half
     * on loop exit.
     */
    while(stop < sys->tmpmodused && nrows < threshold) {
      /* stop at the first MODEL division after the halfway point */
      mod = sys->tmpmodlist[stop++];
      nrows += sys->local[mod];
    }
    /* check if the division BEFORE the halfway point is closer to center
     * but not at beginning.
     * This should help with large, centered blocks that OTHERWISE
     * would put us way past half and result in overtearing.
     *  |------d1---------|t|---------------------d2------------|
     * d1: threshold-(nrows-local[mod])    d2: nrows-threshold
     * the abs should not be needed, but to be safe.
     */
    if ( stop > 1 &&
         abs(nrows - threshold) > abs(threshold - (nrows - sys->local[mod])) ) {
      nrows -= sys->local[mod];
      stop--;
      mod = sys->tmpmodlist[stop-1];
    }

    /* now all relations with MODEL number > mod are in the
       second partition with MODEL number <= mod are in the first. */

    /* now we're going to identify and permute out the tears,
       diddling with the block. rmax preserves block->row.high */
    coord.col = block->row.low;
    while (coord.col <=  block->row.high) {
      coord.row = mtx_FIRST;
      partition = -1; /* neither partition seen */
      while ( mtx_next_in_col(sys->mtx,&coord,&(block->row)),
              coord.row != mtx_LAST) {

        /* check if this column crossed partitions */
        newpart = (rel_model(rp[mtx_row_to_org(sys->mtx,coord.row)]) > mod);
        if (partition >= 0 && partition != newpart) {
          /* this is a tear. */
          sys->ntears++;
          /* symmetrically permute tear to block outer edge */
          mtx_swap_cols(sys->mtx,coord.col,block->row.high);
          mtx_swap_rows(sys->mtx,coord.col,block->row.high);
          rel_set_torn(rp[mtx_row_to_org(sys->mtx,block->row.high)],1);
          /* reduce the block row range, break next_in loop.
           * with any luck, this stops us from double tearing, though
           * in a completely arbitrary way. Another covert tie-breaking.
           */
          block->row.high--;
          break; /* next coord.col. */
        }
        /* it doesn't cross a partition yet, keep looking */
        partition = newpart; /* slightly redundant. cheaper than checking */
      }
      coord.col++;
    }
    block->col.high = block->row.high;

    /* rezero active and local arrays so as not to confuse recursion */
    while (sys->tmpmodused > 0) {
      mod = sys->tmpmodlist[--(sys->tmpmodused)];
      sys->local[mod] = 0;
      sys->active[mod] = 0;
    }
    /* there are no flags on rels to rezero */

    /* attack block left after tearing. */
    status += mr_bisect_partition(sys,block,0,rfunc);
  }

  /* if block list is locally created, destroy it */
  if (!top) {
    mtx_destroy_blocklist(mbptr);
  }
  return status;
}
Пример #3
0
int mr_bisect_partition2(mr_reorder_t *sys, mtx_region_t *reg,
                        int top, MRBlockReorderF rfunc)
{
#if MRDEBUG
  FILE *fptr;
  static mtx_region_t graph_reg;
  static int fnum;
  static char fname[80];
#endif
  mtx_block_t mb;
  mtx_block_t *mbptr;
  mtx_region_t *block;
  struct rel_relation **rp;
  mtx_coord_t coord;
  int partition, newpart,size,threshold, status = 0;
  int32 k,row,mod=0,rmax,stop,nrows,nexttear;

  /* check all our pointers */

  if (sys==NULL || sys->slv == NULL || sys->mtx == NULL ||
      sys->local == NULL || sys->active == NULL ||
      sys->tmpmodlist == NULL || sys->activelen == 0 ||
      sys->cutoff < 10 || rfunc == NULL
     ) {
#if MRDEBUG
    FPRINTF(stderr,"mr_bisect_partition2 miscalled.\n");
#endif
    return 1;
  }

  rp = slv_get_solvers_rel_list(sys->slv);

  /* CREATE block list as needed */
  if (top==1) {
    mbptr = &mb;
    mb.nblocks = 1;
    mb.block = reg;
#if MRDEBUG
    graph_reg = *reg;
    fnum=0;
#endif
  } else {
#if MRDEBUG
    FPRINTF(stderr,"mtx_bisect_partition2 (%d,%d - %d,%d).\n",
      reg->row.low,reg->col.low,reg->row.high,reg->col.high);
#endif
    mbptr = mtx_block_partition(sys->mtx,reg);
    if (mbptr == NULL || (mbptr->block == NULL && mbptr->nblocks) ) {
      if (mbptr != NULL) ascfree(mbptr);
      return 1;
    }

#if MRDEBUG
    FPRINTF(stderr,"BLT List:\n");
    for (k=0;k < mbptr->nblocks; k++) {
      FPRINTF(stderr,"B: %d,%d - %d,%d\n",
        mbptr->block[k].row.low,mbptr->block[k].col.low,
        mbptr->block[k].row.high,mbptr->block[k].col.high);
    }
#endif
    sys->nblts++;
  }

#if MRDEBUG
  FPRINTF(stderr,"mtx_bisect_partition2 (%d,%d - %d,%d).\n",
    reg->row.low,reg->col.low,reg->row.high,reg->col.high);
  sprintf(fname,"/tmp/bisect2.plot.%d",fnum);
  fptr = fopen(fname,"w+");
  mtx_write_region_plot(fptr,sys->mtx,&graph_reg);
  fclose(fptr);
  fnum++;
#endif

  /* tear (or skip) the k remaining partitions */
  for (k=0; k < mbptr->nblocks; k++) {
    block = &(mbptr->block[k]);
    size = block->row.high - block->row.low +1;

    /* skip 1x1, 2x2 blocks which must be full */
    if (block->row.high - block->row.low < 3) {
      continue; /* next k */
    }

    /* blocks below cutoff the user reorders instead */
    if (size < sys->cutoff) {
#if MRDEBUG
      FPRINTF(stderr,"Calling user reorder on rows %d - %d.\n",
        block->row.low,block->row.high);
#endif
      rfunc(sys->slv,sys->mtx,block);
      continue; /* next k */
    }

    /* ok, here's where we do the work */
    threshold = size/2;		/* we want to divide in approximately half */
    rmax = block->row.high;

#if MRDEBUG
      FPRINTF(stderr,"Splitting block with threshold %d.\n", threshold);
#endif

    /* tag in block models and count in block relations */
    for (row = block->row.low; row <= rmax; row++) {
      mod = rel_model(rp[mtx_row_to_org(sys->mtx,row)]);
      if (!(sys->active[mod])) {
        sys->active[mod] = 1;
        sys->tmpmodlist[sys->tmpmodused++] = mod;
      }
      sys->local[mod]++;
    }

    /* if block is all one MODEL, tell user to eat it */
    if (sys->tmpmodused < 2) {
#if MRDEBUG
      FPRINTF(stderr,"Found oversized MODEL including relation\n");
      rel_write_name(sys->slv,rp[mtx_row_to_org(sys->mtx,rmax)],stderr);
      FPRINTF(stderr,"\nCalling user reorder on rows %d - %d.\n",
        block->row.low,block->row.high);
#endif
      /* rezero active and local arrays, just 1! */
      sys->local[0] = 0;
      sys->active[0] = 0;
      rfunc(sys->slv,sys->mtx,block);
      continue; /* next k */
    }

#if MRDEBUG
    FPRINTF(stderr,"Number of models in block %d\n",sys->tmpmodused);
    FPRINTF(stderr,"tearing block %d-%d\n",block->row.low,block->row.high);
#endif
    /* sort the MODEL indices in tmpmodlist. using this fact later
     * enables us to punt the rel_partition flag in favor of just
     * checking MODEL index of a row against the last MODEL in the
     * first partition.
     * We might want to reverse things if the tree was numbered top
     * down rather than bottom up.
     */
    qsort(sys->tmpmodlist,sys->tmpmodused,sizeof(int),
          (int (*)(const void *, const void *))intcompare);

    /* now try to split tmpmodlist approximately in relation count half */
    stop = 0;
    nrows = 0;
    while(stop < sys->tmpmodused && nrows < threshold) {
      mod = sys->tmpmodlist[stop++];
      nrows += sys->local[mod];
    }
    /* Now all relations with MODEL number > mod are in the
     * second partition with MODEL number <= mod are in the first.
     */
#if MRDEBUG
    FPRINTF(stderr,"Number of rows in first half %d\n",nrows);
    FPRINTF(stderr,"Number of models in first half %d\n",stop);
#endif

    /* now we're going to identify and permute out the tears,
     * diddling with the block. rmax preserves block->row.high
     */
    coord.col = block->row.low;
    nexttear = block->row.high;
    while (coord.col <=  nexttear) {
      coord.row = mtx_FIRST;
      partition = -1; /* neither partition seen */
      while ( mtx_next_in_col(sys->mtx,&coord,&(block->row)),
              coord.row != mtx_LAST) {

        /* check if this column crossed partitions */
        newpart = (rel_model(rp[mtx_row_to_org(sys->mtx,coord.row)]) > mod);
#if MRDEBUG
        if (newpart <0) {
          FPRINTF(stderr,"unexpect newpart < 0 (%d)\n",coord.row);
        }
#endif
        if (partition >= 0 && partition != newpart) {
          /* this is a tear. */
          sys->ntears++;
          /* symmetrically permute tear to block outer edge */
          mtx_swap_cols(sys->mtx,coord.col,nexttear);
          mtx_swap_rows(sys->mtx,coord.col,nexttear);
          rel_set_torn(rp[mtx_row_to_org(sys->mtx,nexttear)],1);
          /* reduce the block row range, break next_in loop.
           * with any luck, this stops us from double tearing, though
           * in a completely arbitrary way. Another covert tie-breaking.
           */
#if MRDEBUG
          FPRINTF(stderr,"tear row %d\n",nexttear);
#endif
          nexttear--;
          break; /* next coord.col. */
        }
        /* it doesn't cross a partition yet, keep looking */
        partition = newpart; /* slightly redundant. cheaper than checking */
      }
      coord.col++;
    }
#if MRDEBUG
    FPRINTF(stderr,"TORE %d rows\n", block->col.high-nexttear);
#endif
    block->col.high = block->row.high = nexttear;

    /* rezero active and local arrays so as not to confuse recursion */
    while (sys->tmpmodused > 0) {
      mod = sys->tmpmodlist[--(sys->tmpmodused)];
      sys->local[mod] = 0;
      sys->active[mod] = 0;
    }
    /* there are no flags on rels to rezero */

    /* attack block left after tearing. */
    status += mr_bisect_partition2(sys,block,0,rfunc);
  }

  /* if block list is locally created, destroy it */
  if (!top) {
    mtx_destroy_blocklist(mbptr);
  }
  return status;
}
Пример #4
0
static SlvClientToken ipopt_create(slv_system_t server, int32 *statusindex){
	IpoptSystem *sys;

	sys = ASC_NEW_CLEAR(IpoptSystem);
	if(sys==NULL){
		*statusindex = 1;
		return sys;
	}

	sys->p.parms = sys->pa;
	sys->p.dynamic_parms = 0;
	ipopt_get_default_parameters(server,(SlvClientToken)sys,&(sys->p));
	sys->p.whose = (*statusindex);

	sys->presolved = 0;
	sys->resolve = 0;

	sys->n = -1;
	sys->m = -1;

	sys->s.ok = TRUE;
	sys->s.calc_ok = TRUE;
	sys->s.costsize = 0;
	sys->s.cost = NULL; /*redundant, but sanity preserving */
	sys->s.block.number_of = 1;
	sys->s.block.current_block = 0;
	sys->s.block.current_reordered_block = 0;
	sys->s.block.current_size = 0;
	sys->s.block.previous_total_size = 0;
	sys->s.block.iteration = 0;
	sys->s.block.funcs = 0;
	sys->s.block.jacs = 0;
	sys->s.block.cpu_elapsed = 0;
	sys->s.block.functime = 0;
	sys->s.block.jactime = 0;
	sys->s.block.residual = 0;

	sys->rfilt.matchbits = (REL_INCLUDED |  REL_ACTIVE);
	sys->rfilt.matchvalue = (REL_INCLUDED | REL_ACTIVE);
	sys->vfilt.matchbits =  (VAR_ACTIVE | VAR_INCIDENT | VAR_SVAR | VAR_FIXED);
	sys->vfilt.matchvalue = (VAR_ACTIVE | VAR_INCIDENT | VAR_SVAR);

	sys->vlist = slv_get_solvers_var_list(server);
	sys->rlist = slv_get_solvers_rel_list(server);

	sys->rtot = slv_get_num_solvers_rels(server);
	sys->vtot = slv_get_num_solvers_vars(server);

	sys->obj = slv_get_obj_relation(server);

	sys->slv = server;

	/*char *tmp = rel_make_name(sys->slv,sys->obj);
	//CONSOLE_DEBUG("Objective relation is '%s'",tmp);
	ASC_FREE(tmp);*/

	//CONSOLE_DEBUG("There are %d constraint relations.", sys->rtot);

	if(sys->vlist == NULL) {
		ASC_FREE(sys);
		ERROR_REPORTER_HERE(ASC_PROG_ERR,"IPOPT called with no variables.");
		*statusindex = -2;
		return NULL;
	}

	if(sys->rlist == NULL && sys->obj == NULL) {
		ASC_FREE(sys);
		ERROR_REPORTER_HERE(ASC_PROG_ERR,"IPOPT called with no relations or objective.");
		*statusindex = -1;
		return NULL;
	}


	/* do nothing with the objective list, pars, bounds, extrels, etc etc */

	slv_check_var_initialization(server);
	*statusindex = 0;
	return((SlvClientToken)sys);
}
Пример #5
0
//-------------------------------------------------------------------------
void Prg_ASCEND::setup()
{
  int n, me, m;
  int i, j, row_idx, idx;
  SPMAT *J;
  int nincidences;
  const struct var_variable **incidences;

  // obtain ASCEND system
  // todo: should check that system can be solved with HQP (e.g. no integers)
  _nvars = slv_get_num_solvers_vars(_slv_system);
  _vars = slv_get_solvers_var_list(_slv_system);
  _nrels = slv_get_num_solvers_rels(_slv_system);
  _rels = slv_get_solvers_rel_list(_slv_system);
  _obj = slv_get_obj_relation(_slv_system);

  // count number of optimization variables and bounds
  _var_lb = v_resize(_var_lb, _nvars);
  _var_ub = v_resize(_var_ub, _nvars);
  _var_asc2hqp = iv_resize(_var_asc2hqp, _nvars);
  _derivatives = v_resize(_derivatives, _nvars);
  _var_master_idxs = iv_resize(_var_master_idxs, _nvars);
  _var_solver_idxs = iv_resize(_var_solver_idxs, _nvars);
  n = 0;
  me = 0;
  m = 0;
  for (i = 0; i < _nvars; i++) {
    _var_lb[i] = var_lower_bound(_vars[i]); 
    _var_ub[i] = var_upper_bound(_vars[i]);
    /*
    var_write_name(_slv_system, _vars[i], stderr);
    fprintf(stderr, ":\t%i,\t%g,\t%g\n", var_fixed(_vars[i]),
            _var_lb[i], _var_ub[i]);
    */
    if (var_fixed(_vars[i])) {
      _var_asc2hqp[i] = -1;
    }
    else {
      _var_asc2hqp[i] = n++;
      if (_var_lb[i] == _var_ub[i])
	++me;
      else {
	if (_var_lb[i] > -_Inf)
	  ++m;
	if (_var_ub[i] < _Inf)
	  ++m;
      }
    }
  }

  // consider bounds as linear constraints (i.e. no Jacobian update)
  _me_bounds = me;
  _m_bounds = m;

  // count number of HQP constraints
  for (i = 0; i < _nrels; i++) {
    if (rel_equal(_rels[i]))
      ++me;	// equality constraint
    else
      ++m;	// inequality constraint
  }

  // allocate QP approximation and optimization variables vector
  _qp->resize(n, me, m);
  _x = v_resize(_x, n);

  // allocate sparse structure for bounds
  // (write constant elements in Jacobians)
  me = m = 0;
  for (i = 0; i < _nvars; i++) {
    idx = _var_asc2hqp[i];
    if (idx < 0)
      continue;
    if (_var_lb[i] == _var_ub[i]) {
      row_idx = me++;
      sp_set_val(_qp->A, row_idx, idx, 1.0);
    }
    else {
      if (_var_lb[i] > -_Inf) {
	row_idx = m++;
	sp_set_val(_qp->C, row_idx, idx, 1.0);
      }
      if (_var_ub[i] < _Inf) {
	row_idx = m++;
	sp_set_val(_qp->C, row_idx, idx, -1.0);
      }
    }
  }
  
  // allocate sparse structure for general constraints
  // (just insert dummy values; actual values are set in update method)
  for (i = 0; i < _nrels; i++) {
    if (rel_equal(_rels[i])) {
      row_idx = me++;
      J = _qp->A;
    }
    else {
      row_idx = m++;
      J = _qp->C;
    }
    nincidences = rel_n_incidences(_rels[i]);
    incidences = rel_incidence_list(_rels[i]);
    for (j = 0; j < nincidences; j++) {
      idx = _var_asc2hqp[var_sindex(incidences[j])];
      if (idx >= 0)
	sp_set_val(J, row_idx, idx, 1.0);
    }      
  }

  // todo: setup sparse structure of Hessian
  // for now initialize something resulting in dense BFGS update
  for (j = 0; j < n-1; j++) {
    sp_set_val(_qp->Q, j, j, 0.0);
    sp_set_val(_qp->Q, j, j+1, 0.0);
  }
  sp_set_val(_qp->Q, j, j, 0.0);
}