Пример #1
0
static ssize_t	relevance_test(ssize_t col, int depth, t_grid *grid)
{
	ssize_t	weight;
	ssize_t	sub_col;
	int		ret;

	weight = 0;
	valid_or_cancel_turn(TRUE, grid, col);
	ret = check_row(AI, grid);
	weight = (ret == 4) ? weight + 1000 : weight + ret;
	ret = check_row(PLAYER, grid);
	weight = (ret == 4) ? weight - 1000 : weight - ret;
	sub_col = 0;
	if (depth)
	{
		while (sub_col < grid->column)
		{
			if (grid->grid[0][sub_col] == NONE)
				weight += relevance_test(sub_col, depth - 1, grid);
			sub_col++;
		}
	}
	valid_or_cancel_turn(FALSE, grid, col);
	return (weight);
}
Пример #2
0
int validate(grid board, int possible, int i, int j) {
    int valid_rows = check_row(board, possible, i, j);
    int valid_cols = check_column(board, possible, i, j);
    int valid_square = check_square(board, possible, i, j);

    return valid_rows && valid_cols && valid_square;
}
Пример #3
0
void
draw_numbers(void)
{
    
    
    // iterate over board's numbers
    for (int i = 0; i < 9; i++)
    {
        for (int j = 0; j < 9; j++)
        {            
            if (has_colors() && g.board[i][j] != 0 && g.board[i][j] == g.init_board[i][j])
            attron(COLOR_PAIR(PAIR_INIT)); 
            if( has_colors() && (!check_col(j) || !check_row(i) || !check_square(i,j)))
            attron(COLOR_PAIR(PAIR_ERR));           
            if (game_won() && has_colors())
            attron(COLOR_PAIR(PAIR_WON));
            // determine char
            char c = (g.board[i][j] == 0) ? '.' : g.board[i][j] + '0';
            mvaddch(g.top + i + 1 + i/3, g.left + 2 + 2*(j + j/3), c);
            if (has_colors())
            attroff(COLOR_PAIR(PAIR_INIT)); 
            refresh();
           
        }
    }
   
}
Пример #4
0
static int check_spreadsheet(FILE* spreadsheet)
{
	int checksum = 0;
	while (!feof(spreadsheet))
		checksum += check_row(spreadsheet);

	return checksum;
}
Пример #5
0
// logic for computer's turn
int computer_move()
{
if ( blocking_win() == 1) return( 1 );
if ( check_corner() == 1) return( 1 );
if ( check_row() == 1) return( 1 );

return( 0 );
}
Пример #6
0
int main(int argc, char** argv){
  setlocale(LC_ALL, "en_US.utf8");  
  initial_check();
  get_files_list();

  ESCDELAY = 1;
  menu_index = 0;
  previous_index = -1;
  
  initscr();
  noecho();
  keypad(stdscr, TRUE);
  getmaxyx(stdscr,rows,cols);
  diff_col_width = cols/2-1;
  start_color();
  use_default_colors();
  init_pair(1, COLOR_RED,     -1);
  init_pair(2, COLOR_GREEN,   -1);
  init_pair(3, COLOR_CYAN,    -1);
  refresh();

  print_files_menu();
  show_git_diff();

  ch = getch();  
  while(ch != 27 && ch != 'q'){
    switch(ch){
      case KEY_UP: 
        move_menu(-1);
        break;
      case KEY_DOWN: 
        move_menu(1);
        break;
      case 'h':
        show_help();
        break;
      case '?':
        show_help();
        break;
      case ' ':
        check_row();
        break;
      case 'a':
        check_all();
        break;
      case 'c':
        open_system_index_add_window();
        break;
    }
    ch = getch();  
  }
  
  endwin();
  git_threads_shutdown();
  return(EXIT_SUCCESS);
}
Пример #7
0
int update_status(sqlite3 *db, char *newstatus)
{
	int i;
	int return_ret=0;
 	int len_ret;
	int size_ret;
	int update_ret;
	int row_ret;
	
    len_ret=check_list_len(newstatus);
	if(len_ret==-1)
	{
		return_ret=-1;
		goto over;
	}
	if(len_ret==-2)
	{
		return_ret=-2;
		goto over;
	}

	for(i=0;i<MAX_IPC_NUM;i++)
	{
		if(newstatus[i]!='c')
		{
			size_ret=check_size(newstatus[i]);
		    if(size_ret==-1)
		    {
				return_ret=-4;
				goto over;
		    }
			row_ret=check_row(i);
			if(row_ret==-1)
			{
				return_ret=-5;
				goto over;
			}
			if(row_ret==-2)
			{
				return_ret=-3;
				goto over;
			}
			//printf("newstatus[%d]:%c\n",i,newstatus[i]);
			update_ret=update_status_value(i,newstatus[i]);
			if(update_ret==-1)
			{
				return_ret=-6;
				goto over;
			}
		}
	}
	over:
	return return_ret;
	
}
Пример #8
0
void Relation::delete_row(vector<string> key_list)
{
	for (int i = 0; i < table.size(); i++)
	{
		if (check_row(table[i], key_list))
		{
			table.erase(table.begin() + i);
			break;
		}
	}
}
Пример #9
0
static PyObject *
SearchResults_size(SearchResults *self, PyObject *args, PyObject *kwds) {
  static char *kwlist[] = {"row", NULL};
  int row;
  if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:size", kwlist, &row)) {
    return NULL;
  }
  if (!check_row(self->num_results, &row)) {
    return NULL;
  }
  return PyInt_FromLong(chemfp_get_num_hits(self->results+row));
}
Пример #10
0
static PyObject *
SearchResults_clear_row(SearchResults *self, PyObject *args, PyObject *kwds) {
  static char *kwlist[] = {"row", NULL};
  int row;
  if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:clear", kwlist, &row)) {
    return NULL;
  }
  if (!check_row(self->num_results, &row)) {
    return NULL;
  }
  chemfp_search_result_clear(self->results+row);
  Py_RETURN_NONE;
}
Пример #11
0
static int circular_buffer_get(lua_State* lua)
{
    circular_buffer* cb = check_circular_buffer(lua, 3);
    int row             = check_row(lua, cb, 2, 0);
    int column          = check_column(lua, cb, 3);

    if (row != -1) {
        lua_pushnumber(lua, cb->m_values[(row * cb->m_columns) + column]);
    } else {
        lua_pushnil(lua);
    }
    return 1;
}
Пример #12
0
static PyObject *
SearchResults_get_scores(SearchResults *self, PyObject *args, PyObject *kwds) {
  static char *kwlist[] = {"row", NULL};
  int row;
  if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:get_scores", kwlist, &row)) {
    return NULL;
  }
  if (!check_row(self->num_results, &row)) {
    return NULL;
  }
  return data_blob_to_array(chemfp_get_num_hits(self->results+row),
                            self->results[row].scores,
                            "d", sizeof(double));
}
Пример #13
0
void dig(int **puz, int x, int y, int emp_lim, int rc_lim){
/*randomly empties positions of a completed sudoku to generate a new puzzle, according to the limits passed*/	
	int g = 0, v, s;	
	srand(time(NULL));
	while(g <= emp_lim){
		if(puz[x][y]){
			if((v = check_row(puz, x, rc_lim)) && (s = check_col(puz, y, rc_lim))){
				g++;
				puz[x][y] = EMPTY;
			}
		}
		set_position(&x, &y);
	}	
	return;
}
Пример #14
0
static PyObject *
SearchResults_add_hit(SearchResults *self, PyObject *args, PyObject *kwds) {
  static char *kwlist[] = {"row", "column", "score", NULL};
  int row, column;
  double score;
  if (!PyArg_ParseTupleAndKeywords(args, kwds, "iid:_add_hit", kwlist,
                                   &row, &column, &score)) {
    return NULL;
  }
  if (!check_row(self->num_results, &row)) {
    return NULL;
  }
  return PyInt_FromLong(chemfp_add_hit(self->results+row, column, score));
  Py_RETURN_NONE;
}
Пример #15
0
static int circular_buffer_set(lua_State* lua)
{
    circular_buffer* cb = check_circular_buffer(lua, 4);
    int row             = check_row(lua, cb, 2, 1); // advance the buffer
                                                    // forward if necessary
    int column          = check_column(lua, cb, 3);
    double value        = luaL_checknumber(lua, 4);

    if (row != -1) {
        cb->m_values[(row * cb->m_columns) + column] = value;
        lua_pushnumber(lua, value);
    } else {
        lua_pushnil(lua);
    }
    return 1;
}
Пример #16
0
static PyObject *
SearchResults_reorder_row(SearchResults *self, PyObject *args, PyObject *kwds) {
  static char *kwlist[] = {"row", "order", NULL};
  int row=-1;
  int errval;
  const char *ordering = "decreasing-score";
  if (!PyArg_ParseTupleAndKeywords(args, kwds, "i|s:reorder_row", kwlist, &row, &ordering)) {
    return NULL;
  }
  if (!check_row(self->num_results, &row)) {
    return NULL;
  }
  errval = chemfp_search_result_reorder(self->results+row, ordering);
  if (errval) {
    PyErr_SetString(PyExc_ValueError, chemfp_strerror(errval));
    return NULL;
  }
  Py_RETURN_NONE;
}
Пример #17
0
int game_end(Board board)
{
	for (int x = 0; x < board.dimx; x++)
	{
		if (check_row(board,x))
			return 1;
	}
	for (int y = 0; y < board.dimy; y++)
	{
		if (check_column(board,y))
			return 1;
	}
	if (check_diagonals(board))
		return 1;
		
	if (board.used_spaces == board.dimx * board.dimy)
		return 2;	
		
	return 0;
}
Пример #18
0
static PyObject *
SearchResults_get_indices_and_scores(SearchResults *self, PyObject *args, PyObject *kwds) {
  int n, i;
  PyObject *hits, *obj;
  chemfp_search_result *result;
  static char *kwlist[] = {"row", NULL};
  int row;

  if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:get_indices", kwlist, &row)) {
    return NULL;
  }
  if (!check_row(self->num_results, &row)) {
    return NULL;
  }
  result = self->results+row;
  n = chemfp_get_num_hits(result);
  
  hits = PyList_New(n);
  if (!hits) {
    return NULL;
  }
  for (i=0; i<n; i++) {
    obj = Py_BuildValue("(id)", result->indices[i], result->scores[i]);
    if (!obj) {
      goto error;
    }
    PyList_SET_ITEM(hits, i, obj);
  }
  return hits;

 error:
  /* I could be smarter and only deallocate the ones which I know are present. */
  /* Proving that's correct is a bit trickier than I want to do. */
  for (i=0; i<n; i++) {
    Py_XDECREF(PyList_GET_ITEM(hits, i));
  }
  Py_DECREF(hits);
  return NULL;
}
Пример #19
0
static bool is_won(const game_t *game, const int x, const int y)
{
	const int min_win_count = game->grid_size - 1;
	int count;

	count = check_column(game, x, y);
	if (count >= min_win_count)
		return true;

	count = check_row(game, x, y);
	if (count >= min_win_count)
		return true;

	count = check_diagonal_1(game, x, y);
	if (count >= min_win_count)
		return true;

	count = check_diagonal_2(game, x, y);
	if (count >= min_win_count)
		return true;

	return false;
}
Пример #20
0
    bool isValidSudoku(vector<vector<char>>& board) {
        bool valid = true;
        vector<bool> check_row(false,10);
        vector<bool> check_line(false,10);
        for(int i=0; i<9; i++)
        {
            for(int k=0; k<10; k++)
            {
                check_row[k] = false;
                check_line[k] = false;
            }
            for(int j=0; j<9; j++)
            {
                if(board[i][j] != '.')
                {
                    int num_i_j = board[i][j]-'0';
                    if(!check_row[num_i_j])
                        check_row[num_i_j] = true;
                    else
                    {
                        valid = false;
                        break;
                    }
                } 
                if(board[j][i] != '.')
                {
                    int num_j_i = board[j][i]-'0';
                    if(!check_line[num_j_i])
                        check_line[num_j_i] = true;
                    else
                    {
                        valid = false;
                        break;
                    }
                }
            }
            if(!valid)
                break;
        }
        
        for(int i=0; i<=6; i+=3)
        {
            for(int j=0; j<=6; j+=3)
            {
                for(int k=0; k<10; k++)
                    check_row[k] = false;
                    
                for(int k=0; k<9; k++)
                {
                    if(board[i+k/3][j+k%3] != '.')
                    {
                        int num_k = board[i+k/3][j+k%3] -'0';
                        if(!check_row[num_k])
                            check_row[num_k] = true;
                        else
                        {
                            valid = false;
                            break; 
                        }
                    }

                }
                
                if(!valid)
                    break;
            }
            if(!valid)
                break;
        }
        return valid;
        
    }
Пример #21
0
const CoinPresolveAction *implied_free_action::presolve (
    CoinPresolveMatrix *prob, const CoinPresolveAction *next, int &fill_level)
{
# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
# if PRESOLVE_DEBUG > 0
  std::cout
    << "Entering implied_free_action::presolve, fill level " << fill_level
    << "." << std::endl ;
# endif
  presolve_consistent(prob) ;
  presolve_links_ok(prob) ;
  presolve_check_sol(prob) ;
  presolve_check_nbasic(prob) ;
# endif

# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
  const int startEmptyRows = prob->countEmptyRows() ;
  const int startEmptyColumns = prob->countEmptyCols() ;
# if COIN_PRESOLVE_TUNING > 0
  double startTime = 0.0 ;
  if (prob->tuning_) startTime = CoinCpuTime() ;
# endif
# endif

/*
  Unpack the row- and column-major representations.
*/
  const int m = prob->nrows_ ;
  const int n = prob->ncols_ ;

  const CoinBigIndex *rowStarts = prob->mrstrt_ ;
  int *rowLengths = prob->hinrow_ ;
  const int *colIndices = prob->hcol_ ;
  const double *rowCoeffs = prob->rowels_ ;
  presolvehlink *rlink = prob->rlink_ ;

  CoinBigIndex *colStarts = prob->mcstrt_ ;
  int *colLengths = prob->hincol_ ;
  int *rowIndices = prob->hrow_ ;
  double *colCoeffs = prob->colels_ ;
  presolvehlink *clink = prob->clink_ ;

/*
  Column bounds, row bounds, cost, integrality.
*/
  double *clo = prob->clo_ ;
  double *cup = prob->cup_ ;
  double *rlo = prob->rlo_ ;
  double *rup = prob->rup_ ;
  double *cost = prob->cost_ ;
  const unsigned char *integerType = prob->integerType_ ;

/*
  Documented as `inhibit x+y+z = 1 mods'.  From the code below, it's clear
  that this is intended to avoid removing SOS equalities with length >= 5
  (hardcoded). 
*/
  const bool stopSomeStuff = ((prob->presolveOptions()&0x04) != 0) ;
/*
  Ignore infeasibility. `Fix' is overly optimistic.
*/
  const bool fixInfeasibility = ((prob->presolveOptions_&0x4000) != 0) ;
/*
  Defaults to 0.0.
*/
  const double feasTol = prob->feasibilityTolerance_ ;

# if 0  
/*
  Tentatively moved to be a front-end function for useless_constraint_action,
  much as make_fixed is a front-end for make_fixed_action. This bit of code
  left for possible tuning.
  -- lh, 121127 --

  Original comment: This needs to be made faster.
*/
# ifdef COIN_LIGHTWEIGHT_PRESOLVE
  if (prob->pass_ == 1) {
#else
    if (prob->presolveOptions_&0x10) {
# endif
    next = testRedundant(prob,next) ;
    if (prob->status_&0x01 != 0) {
      if ((prob->presolveOptions_&0x4000) != 0)
        prob->status_ &= !0x01 ;
      else
	return (next) ;
    }
# if 1 //def COIN_LIGHTWEIGHT_PRESOLVE
  }
# endif
# endif

/*
  implied_free and subst take a fair bit of effort to scan for candidates.
  This is a hook to allow a presolve driver to avoid that work.
*/
  if (prob->pass_ > 15 && (prob->presolveOptions_&0x10000) != 0) { 
    fill_level = 2 ;
    return (next) ;
  }

/*
  Set up to collect implied_free actions.
*/
  action *actions = new action [n] ;
# ifdef ZEROFAULT
  CoinZeroN(reinterpret_cast<char *>(actions),n*sizeof(action)) ;
# endif
  int nactions = 0 ;

  int *implied_free = prob->usefulColumnInt_ ;
  int *whichFree = implied_free+n ;
  int numberFree = 0 ;
/*
  Arrays to hold row activity (row lhs) min and max values. Each row lhs bound
  is held as two components: a sum of finite column bounds and a count of
  infinite column bounds.
*/
  int *infiniteDown = new int[m] ;
  int *infiniteUp = new int[m] ;
  double *maxDown = new double[m] ;
  double *maxUp = new double[m] ;
/*
  Overload infiniteUp with row status codes:
  -1: L(i)/U(i) not yet computed,
  -2: do not use (empty or useless row),
  -3: give up (infeasible)
  -4: chosen as implied free row
*/
  for (int i = 0 ; i < m ; i++) {
    if (rowLengths[i] > 1)
      infiniteUp[i] = -1 ;
    else
      infiniteUp[i] = -2 ;
  }
  // Get rid of rows with prohibited columns
  if (prob->anyProhibited_) {
    for (int i = 0 ; i < m ; i++) {
      CoinBigIndex rStart = rowStarts[i];
      CoinBigIndex rEnd = rStart+rowLengths[i];
      bool badRow=false;
      for (CoinBigIndex j = rStart; j < rEnd; ++j) {
	if (prob->colProhibited(colIndices[j])) {
	  badRow=true;
	  break;
	}
      }
      if (badRow)
	infiniteUp[i] = -2 ;
    }
  }

// Can't go on without a suitable finite infinity, can we?
#ifdef USE_SMALL_LARGE
  const double large = 1.0e10 ;
#else
  const double large = 1.0e20 ;
#endif

/*
  Decide which columns we're going to look at. There are columns already queued
  in colsToDo_, but sometimes we want to look at all of them. Don't suck in
  prohibited columns. See comments at the head of the routine for fill_level.

  NOTE the overload on usefulColumnInt_. It was assigned above to whichFree
       (indices of interesting columns). We'll be ok because columns are
       consumed out of look at one per main loop iteration, but not all
       columns are interesting.

  Original comment: if gone from 2 to 3 look at all
*/
  int numberLook = prob->numberColsToDo_ ;
  int iLook ;
  int *look = prob->colsToDo_ ;
  if (fill_level < 0) {
    look = prob->usefulColumnInt_+n ;
    if (!prob->anyProhibited()) {
      CoinIotaN(look,n,0) ;
      numberLook = n ;
    } else {
      numberLook = 0 ;
      for (iLook = 0 ; iLook < n ; iLook++) 
	if (!prob->colProhibited(iLook))
	  look[numberLook++] = iLook ;
    }
  }
/*
  Step through the columns of interest looking for suitable x(tgt).

  Interesting columns are limited by number of nonzeros to minimise fill-in
  during substitution.
*/
  bool infeas = false ;
  const int maxLook = abs(fill_level) ;
  for (iLook = 0 ; iLook < numberLook ; iLook++) {
    const int tgtcol = look[iLook] ;
    const int tgtcol_len = colLengths[tgtcol] ;

    if (tgtcol_len <= 0 || tgtcol_len > maxLook) continue ;
/*
  Set up to reconnoiter the column.

  The initial value for ait_max is chosen to make sure that anything that
  satisfies the stability check is big enough to use (though we'd clearly like
  something better).
*/
    const CoinBigIndex kcs = colStarts[tgtcol] ;
    const CoinBigIndex kce = kcs+tgtcol_len ;
    const bool singletonCol = (tgtcol_len == 1) ;
    bool possibleRow = false ;
    bool singletonRow = false ;
    double ait_max = 20*ZTOLDP2 ;
/*
  If this is a singleton column, the only concern is that the row is not a
  singleton row (that has its own, simpler, transform: slack_doubleton). But
  make sure we're not dealing with some tiny a(it).

  Note that there's no point in marking a singleton row. By definition, we
  won't encounter it again.
*/
    if (singletonCol) {
      const int i = rowIndices[kcs] ;
      singletonRow = (rowLengths[i] == 1) ;
      possibleRow = (fabs(colCoeffs[kcs]) > ZTOLDP2) ;
    } else {
      
/*
  If the column is not a singleton, we'll need a numerically stable
  substitution formula. Check that this is possible.  One of the entangled
  rows must be an equality with a numerically stable coefficient, at least
  .1*MAX{i}a(it).
*/
      for (CoinBigIndex kcol = kcs ; kcol < kce ; ++kcol) {
	const int i = rowIndices[kcol] ;
	if (rowLengths[i] == 1) {
	  singletonRow = true ;
	  break ;
	}
	const double abs_ait = fabs(colCoeffs[kcol]) ;
	ait_max = CoinMax(ait_max,abs_ait) ;
	if (fabs(rlo[i]-rup[i]) < feasTol && abs_ait > .1*ait_max) {
	  possibleRow = true ;
	}
      }
    }
    if (singletonRow || !possibleRow) continue ;
/*
  The column has possibilities. Walk the column, calculate row activity
  bounds L(i) and U(i) for suitable entangled rows, then calculate the
  improvement (if any) on the column bounds for l(j) and u(j). The goal is to
  satisfy the implied free condition over all entangled rows and find at least
  one row suitable for a substitution formula (if the column is not a natural
  singleton).

  Suitable: If this is a natural singleton, we need to look at the single
  entangled constraint.  If we're attempting to create a singleton by
  substitution, only look at equalities with stable coefficients. If x(t) is
  integral, make sure the scaled rhs will be integral.
*/
#   if PRESOLVE_DEBUG > 2
    std::cout
      << "  Checking x(" << tgtcol << "), " << tgtcol_len << " nonzeros"
      << ", l(" << tgtcol << ") " << clo[tgtcol] << ", u(" << tgtcol
      << ") " << cup[tgtcol] << ", c(" << tgtcol << ") " << cost[tgtcol]
      << "." << std::endl ;
#   endif
    const double lt = clo[tgtcol] ;
    const double ut = cup[tgtcol] ;
    double impliedLow = -COIN_DBL_MAX ;
    double impliedHigh = COIN_DBL_MAX ;
    int subst_ndx = -1 ;
    int subst_len = n ;
    for (CoinBigIndex kcol = kcs ; kcol < kce ; ++kcol) {
      const int i = rowIndices[kcol] ;

      assert(infiniteUp[i] != -3) ;
      if (infiniteUp[i] <= -2) continue ;

      const double ait = colCoeffs[kcol] ;
      const int leni = rowLengths[i] ;
      const double rloi = rlo[i] ;
      const double rupi = rup[i] ;
/*
  A suitable row for substitution must
    * be an equality;
    * the entangled coefficient must be large enough to be numerically stable;
    * if x(t) is integer, the constant term in the substitution formula must be
      integer.
*/
      bool rowiOK = (fabs(rloi-rupi) < feasTol) && (fabs(ait) > .1*ait_max) ;
      rowiOK = rowiOK && ((integerType[tgtcol] == 0) ||
                          (fabs((rloi/ait)-floor((rloi/ait)+0.5)) < feasTol)) ;
/*
  If we don't already have L(i) and U(i), calculate now. Check for useless and
  infeasible constraints when that's done.
*/
      int infUi = 0 ;
      int infLi = 0 ;
      double maxUi = 0.0 ;
      double maxLi = 0.0 ;
      const CoinBigIndex krs = rowStarts[i] ;
      const CoinBigIndex kre = krs+leni ;

      if (infiniteUp[i] == -1) {
	for (CoinBigIndex krow = krs ; krow < kre ; ++krow) {
	  const double aik = rowCoeffs[krow] ;
	  const int k = colIndices[krow] ;
	  const double lk = clo[k] ;
	  const double uk = cup[k] ;
	  if (aik > 0.0) {
	    if (uk < large) 
	      maxUi += uk*aik ;
	    else
	      ++infUi ;
	    if (lk > -large) 
	      maxLi += lk*aik ;
	    else
	      ++infLi ;
	  } else if (aik < 0.0) {
	    if (uk < large) 
	      maxLi += uk*aik ;
	    else
	      ++infLi ;
	    if (lk > -large) 
	      maxUi += lk*aik ;
	    else
	      ++infUi ;
	  }
	}
	const double maxUinf = maxUi+infUi*1.0e31 ;
	const double maxLinf = maxLi-infLi*1.0e31 ;
	if (maxUinf <= rupi+feasTol && maxLinf >= rloi-feasTol) {
	  infiniteUp[i] = -2 ;
	} else if (maxUinf < rloi-feasTol && !fixInfeasibility) {
	  prob->status_|= 1 ;
	  infeas = true ;
	  prob->messageHandler()->message(COIN_PRESOLVE_ROWINFEAS,
					  prob->messages())
	    << i << rloi << rupi << CoinMessageEol ;
	  infiniteUp[i] = -3 ;
	} else if (maxLinf > rupi+feasTol && !fixInfeasibility) {
	  prob->status_|= 1 ;
	  infeas = true ;
	  prob->messageHandler()->message(COIN_PRESOLVE_ROWINFEAS,
					  prob->messages())
	    << i << rloi << rupi << CoinMessageEol ;
	  infiniteUp[i] = -3 ;
	} else {
	  infiniteUp[i] = infUi ;
	  infiniteDown[i] = infLi ;
	  maxUp[i] = maxUi ;
	  maxDown[i] = maxLi ;
	}
      } else {
        infUi = infiniteUp[i] ;
	infLi = infiniteDown[i] ;
	maxUi = maxUp[i] ;
	maxLi = maxDown[i] ;
      }
#     if PRESOLVE_DEBUG > 2
      std::cout
        << "    row(" << i << ") " << leni << " nonzeros, blow " << rloi
	<< ", L (" << infLi << "," << maxLi
	<< "), U (" << infUi << "," << maxUi
	<< "), b " << rupi ;
      if (infeas) std::cout << " infeas" ;
      if (infiniteUp[i] == -2) std::cout << " useless" ;
      std::cout << "." << std::endl ;
#     endif
/*
  If we're infeasible, no sense checking further; escape the implied bound
  loop. The other possibility is that we've just discovered the constraint
  is useless, in which case we just move on to the next one in the column.
*/
      if (infeas) break ;
      if (infiniteUp[i] == -2) continue ;
      assert(infiniteUp[i] >= 0 && infiniteUp[i] <= leni) ;
/*
  At this point we have L(i) and U(i), expressed as finite and infinite
  components, and constraint i is neither useless or infeasible. Calculate
  the implied bounds l'(t) and u'(t) on x(t). The calculation (for a(it) > 0)
  is
    u'(t) <= (b(i) - (L(i)-a(it)l(t)))/a(it) = l(t)+(b(i)-L(i))/a(it)
    l'(t) >= (blow(i) - (U(i)-a(it)u(t)))/a(it) = u(t)+(blow(i)-U(i))/a(it)
  Insert the appropriate flips for a(it) < 0. Notice that if there's exactly
  one infinite contribution to L(i) or U(i) and x(t) is responsible, then the
  finite portion of L(i) or U(i) is already correct.

  Cut some slack for possible numerical inaccuracy if the finite portion of
  L(i) or U(i) is very large. If the new bound is very large, force it to
  infinity.
*/
      double ltprime = -COIN_DBL_MAX ;
      double utprime = COIN_DBL_MAX ;
      if (ait > 0.0) {
	if (rloi > -large) {
	  if (!infUi) {
	    assert(ut < large) ;
	    ltprime = ut+(rloi-maxUi)/ait ;
	    if (fabs(maxUi) > 1.0e8 && !singletonCol)
	      ltprime -= 1.0e-12*fabs(maxUi) ;
	  } else if (infUi == 1 && ut > large) {
	    ltprime = (rloi-maxUi)/ait ;
	    if (fabs(maxUi) > 1.0e8 && !singletonCol)
	      ltprime -= 1.0e-12*fabs(maxUi) ;
	  } else {
	    ltprime = -COIN_DBL_MAX ;
	  }
	  impliedLow = CoinMax(impliedLow,ltprime) ;
	}
	if (rupi < large) {
	  if (!infLi) {
	    assert(lt > -large) ;
	    utprime = lt+(rupi-maxLi)/ait ;
	    if (fabs(maxLi) > 1.0e8 && !singletonCol)
	      utprime += 1.0e-12*fabs(maxLi) ;
	  } else if (infLi == 1 && lt < -large) {
	    utprime = (rupi-maxLi)/ait ;
	    if (fabs(maxLi) > 1.0e8 && !singletonCol)
	      utprime += 1.0e-12*fabs(maxLi) ;
	  } else {
	    utprime = COIN_DBL_MAX ;
	  }
	  impliedHigh = CoinMin(impliedHigh,utprime) ;
	}
      } else {
	if (rloi > -large) {
	  if (!infUi) {
	    assert(lt > -large) ;
	    utprime = lt+(rloi-maxUi)/ait ;
	    if (fabs(maxUi) > 1.0e8 && !singletonCol)
	      utprime += 1.0e-12*fabs(maxUi) ;
	  } else if (infUi == 1 && lt < -large) {
	    utprime = (rloi-maxUi)/ait ;
	    if (fabs(maxUi) > 1.0e8 && !singletonCol)
	      utprime += 1.0e-12*fabs(maxUi) ;
	  } else {
	    utprime = COIN_DBL_MAX ;
	  }
	  impliedHigh = CoinMin(impliedHigh,utprime) ;
	}
	if (rupi < large) {
	  if (!infLi) {
	    assert(ut < large) ;
	    ltprime = ut+(rupi-maxLi)/ait ;
	    if (fabs(maxLi) > 1.0e8 && !singletonCol)
	      ltprime -= 1.0e-12*fabs(maxLi) ;
	  } else if (infLi == 1 && ut > large) {
	    ltprime = (rupi-maxLi)/ait ;
	    if (fabs(maxLi) > 1.0e8 && !singletonCol)
	      ltprime -= 1.0e-12*fabs(maxLi) ;
	  } else {
	    ltprime = -COIN_DBL_MAX ;
	  }
	  impliedLow = CoinMax(impliedLow,ltprime) ;
	}
      }
#     if PRESOLVE_DEBUG > 2
      std::cout
        << "    row(" << i << ") l'(" << tgtcol << ") " << ltprime
	<< ", u'(" << tgtcol << ") " << utprime ;
      if (lt <= impliedLow && impliedHigh <= ut)
	std::cout << "; implied free satisfied" ;
      std::cout << "." << std::endl ;
#     endif
/*
  For x(t) integral, see if a substitution formula based on row i will
  preserve integrality.  The final check in this clause aims to preserve
  SOS equalities (i.e., don't eliminate a non-trivial SOS equality from
  the system using this transform).

  Note that this can't be folded into the L(i)/U(i) loop because the answer
  changes with x(t).

  Original comment: can only accept if good looking row
*/
      if (integerType[tgtcol]) {
	possibleRow = true ;
	bool allOnes = true ;
	for (CoinBigIndex krow = krs ; krow < kre ; ++krow) {
	  const int j = colIndices[krow] ;
	  const double scaled_aij = rowCoeffs[krow]/ait ;
	  if (fabs(scaled_aij) != 1.0)
	    allOnes = false ;
	  if (!integerType[j] ||
	      fabs(scaled_aij-floor(scaled_aij+0.5)) > feasTol) {
	    possibleRow = false ;
	    break ;
	  }
	}
	if (rloi == 1.0 && leni >= 5 && stopSomeStuff && allOnes)
	  possibleRow = false ;
	rowiOK = rowiOK && possibleRow ;
      }
/*
  Do we have a winner? If we have an incumbent, prefer the one with fewer
  coefficients.
*/
      if (rowiOK) {
	if (subst_ndx < 0 || (leni < subst_len)) {
#         if PRESOLVE_DEBUG > 2
          std::cout
	    << "    row(" << i << ") now candidate for x(" << tgtcol << ")."
	    << std::endl ;
#         endif
	  subst_ndx = i ;
	  subst_len = leni ;
	}
      }
    }

    if (infeas) break ;
/*
  Can we do the transform? If so, subst_ndx will have a valid row.
  Record the implied free variable and the equality we'll use to substitute
  it out. Take the row out of the running --- we can't use the same row
  for two substitutions.
*/
    if (lt <= impliedLow && impliedHigh <= ut &&
        (subst_ndx >= 0 || singletonRow)) {
      implied_free[numberFree] = subst_ndx ;
      infiniteUp[subst_ndx] = -4 ;
      whichFree[numberFree++] = tgtcol ;
#     if PRESOLVE_DEBUG > 1
      std::cout
        << "  x(" << tgtcol << ") implied free by row " << subst_ndx
	<< std::endl ;
#     endif
    }
  }

  delete[] infiniteDown ;
  delete[] infiniteUp ;
  delete[] maxDown ;
  delete[] maxUp ;

/*
  If we're infeasible, there's nothing more to be done.
*/
  if (infeas) {
#   if PRESOLVE_SUMMARY > 0 || PRESOLVE_DEBUG > 0
    std::cout << "  IMPLIED_FREE: infeasible." << std::endl ;
#   endif
    return (next) ;
  }

/*
  We have a list of implied free variables, each with a row that can be used
  to substitute the variable to singleton status if the variable is not a
  natural singleton. The loop here will only process natural singletons.
  We'll hand the remainder to subst_constraint_action below, if there is
  a remainder.

  The natural singletons processed here are compressed out of whichFree and
  implied_free.
*/
  int unprocessed = 0 ;
  for (iLook = 0 ; iLook < numberFree ; iLook++) {
    const int tgtcol = whichFree[iLook] ;
    
    if (colLengths[tgtcol] != 1) {
      whichFree[unprocessed] = whichFree[iLook] ;
      implied_free[unprocessed] = implied_free[iLook] ;
      unprocessed++ ;
      continue ;
    }
    
    const int tgtrow = implied_free[iLook] ;
    const int tgtrow_len = rowLengths[tgtrow] ;

    const CoinBigIndex kcs = colStarts[tgtcol] ;
    const double tgtcol_coeff = colCoeffs[kcs] ;
    const double tgtcol_cost = cost[tgtcol] ;

    const CoinBigIndex krs = rowStarts[tgtrow] ;
    const CoinBigIndex kre = krs+tgtrow_len ;
    if (tgtcol_cost != 0.0) {
      // Check costs don't make unstable
      //double minOldCost=COIN_DBL_MAX;
      double maxOldCost=0.0;
      //double minNewCost=COIN_DBL_MAX;
      double maxNewCost=0.0;
      for (CoinBigIndex krow = krs ; krow < kre ; krow++) {
	const int j = colIndices[krow] ;
	if (j != tgtcol) {
	  double oldCost = cost[j] ;
	  double newCost = oldCost - (tgtcol_cost*rowCoeffs[krow])/tgtcol_coeff ;
	  oldCost = fabs(oldCost);
	  newCost = fabs(newCost);
	  //minOldCost=CoinMin(minOldCost,oldCost);
	  maxOldCost=CoinMax(maxOldCost,oldCost);
	  //minNewCost=CoinMin(minNewCost,newCost);
	  maxNewCost=CoinMax(maxNewCost,newCost);
	}
      }
      if (maxNewCost>1000.0*(maxOldCost+1.0) && maxOldCost) {
	//printf("too big %d tgtcost %g maxOld %g maxNew %g\n",
	//   tgtcol,tgtcol_cost,maxOldCost,maxNewCost);
	continue;
      }
    }
/*
  Initialise the postsolve action. We need to remember the row and column.
*/
    action *s = &actions[nactions++] ;
    s->row = tgtrow ;
    s->col = tgtcol ;
    s->clo = clo[tgtcol] ;
    s->cup = cup[tgtcol] ;
    s->rlo = rlo[tgtrow] ;
    s->rup = rup[tgtrow] ;
    s->ninrow = tgtrow_len ;
    s->rowels = presolve_dupmajor(rowCoeffs,colIndices,tgtrow_len,krs) ;
    s->costs = NULL ;
/*
  We're processing a singleton, hence no substitutions in the matrix, but we
  do need to fix up the cost vector. The substitution formula is
    x(t) = (rhs(i) - SUM{j\t}a(ik)x(k))/a(it)
  hence
    c'(k) = c(k)-c(t)a(ik)/a(it)
  and there's a constant offset
    c(t)rhs(i)/a(it).
  where rhs(i) is one of blow(i) or b(i).

  For general constraints where blow(i) != b(i), we need to take a bit
  of care. If only one of blow(i) or b(i) is finite, that's the one to
  use. Where we have two finite but unequal bounds, choose the bound that
  will result in the most favourable value for x(t). For minimisation, if
  c(t) < 0 we want to maximise x(t), so choose b(i) if a(it) > 0, blow(i)
  if a(it) < 0.  A bit of case analysis says choose b(i) when c(t)a(it) <
  0, blow(i) when c(t)a(it) > 0. We shouldn't be here if both row bounds
  are infinite.

  Fortunately, the objective coefficients are not affected by this.
*/
    if (tgtcol_cost != 0.0) {
      double tgtrow_rhs = rup[tgtrow] ;
      if (fabs(rlo[tgtrow]-rup[tgtrow]) > feasTol) {
	const double rlot = rlo[tgtrow] ;
	const double rupt = rup[tgtrow] ;
        if (rlot > -COIN_DBL_MAX && rupt < COIN_DBL_MAX) {
	  if ((tgtcol_cost*tgtcol_coeff) > 0)
	    tgtrow_rhs = rlot ;
	  else
	    tgtrow_rhs = rupt ;
	} else if (rupt >= COIN_DBL_MAX) {
	  tgtrow_rhs = rlot ;
	}
      }
      assert(fabs(tgtrow_rhs) <= large) ;
      double *save_costs = new double[tgtrow_len] ;

      for (CoinBigIndex krow = krs ; krow < kre ; krow++) {
	const int j = colIndices[krow] ;
	save_costs[krow-krs] = cost[j] ;
	cost[j] -= (tgtcol_cost*rowCoeffs[krow])/tgtcol_coeff ;
      }
      prob->change_bias((tgtcol_cost*tgtrow_rhs)/tgtcol_coeff) ;
      cost[tgtcol] = 0.0 ;
      s->costs = save_costs ;
    }
/*
  Remove the row from the column-major representation, queuing up each column
  for reconsideration. Then remove the row from the row-major representation.
*/
    for (CoinBigIndex krow = krs ; krow < kre ; krow++) {
      const int j = colIndices[krow] ;
      presolve_delete_from_col(tgtrow,j,colStarts,colLengths,rowIndices,
      			       colCoeffs) ;
      if (colLengths[j] == 0) {
        PRESOLVE_REMOVE_LINK(prob->clink_,j) ;
      } else {
	prob->addCol(j) ;
      }
    }
    PRESOLVE_REMOVE_LINK(clink,tgtcol) ;
    colLengths[tgtcol] = 0 ;

    PRESOLVE_REMOVE_LINK(rlink,tgtrow) ;
    rowLengths[tgtrow] = 0 ;
    rlo[tgtrow] = 0.0 ;
    rup[tgtrow] = 0.0 ;
  }
/*
  We're done with the natural singletons. Trim actions to length and create
  the postsolve object.
*/
  if (nactions) {
#   if PRESOLVE_SUMMARY > 0 || PRESOLVE_DEBUG > 0
    printf("NIMPLIED FREE:  %d\n", nactions) ;
#   endif
    action *actions1 = new action[nactions] ;
    CoinMemcpyN(actions, nactions, actions1) ;
    next = new implied_free_action(nactions,actions1,next) ;
  } 
  delete [] actions ;
# if PRESOLVE_DEBUG > 0
  std::cout
    << "  IMPLIED_FREE: identified " << numberFree
    << " implied free transforms, processed " << numberFree-unprocessed
    << " natural singletons." << std::endl ;
# endif

/*
  Now take a stab at the columns that aren't natural singletons, if there are
  any left.
*/
  if (unprocessed != 0) {
    // if not integer - don't allow much fill
    if (!prob->anyInteger())
    {
      int numberFree=unprocessed;
      int nBad=0;
      unprocessed=0;
      // Take out ones that make much denser or might lead to instability
      /*
	Unpack the row- and column-major representations.
      */
      CoinBigIndex *rowStarts = prob->mrstrt_ ;
      int *rowLengths = prob->hinrow_ ;
      double *rowCoeffs = prob->rowels_ ;
      int *colIndices = prob->hcol_ ;
      
      CoinBigIndex *colStarts = prob->mcstrt_ ;
      int *colLengths = prob->hincol_ ;
      double *colCoeffs = prob->colels_ ;
      int *rowIndices = prob->hrow_ ;
      
      /*
	This array is used to hold the indices of columns involved in substitutions,
	where we have the potential for cancellation. At the end they'll be
	checked to eliminate any actual zeros that may result.
	
	NOTE that usefulColumnInt_ is already in use for parameters implied_free and
	whichFree when this routine is called from implied_free.
      */
      
      int *rowsUsed = &prob->usefulRowInt_[0] ;
      int nRowsUsed = 0 ;
      /*
	Open a loop to process the (equality r, implied free variable t) pairs
	in whichFree and implied_free.
	
	It can happen that removal of (row, natural singleton) pairs back in
	implied_free will reduce the length of column t. It can also happen
	that previous processing here has resulted in fillin or cancellation. So
	check again for column length and exclude natural singletons and overly
	dense columns.
      */
      for (int iLook = 0 ; iLook < numberFree ; iLook++) {
	const int tgtcol = whichFree[iLook] ;
	const int tgtrow = implied_free[iLook] ;
	
	if (colLengths[tgtcol] < 2 || colLengths[tgtcol] > maxLook) {
#     if PRESOLVE_DEBUG > 3
	  std::cout
	    << "    skipping eqn " << tgtrow << " x(" << tgtcol
	    << "); length now " << colLengths[tgtcol] << "." << std::endl ;
#     endif
	  continue ;
	}
	
	CoinBigIndex tgtcs = colStarts[tgtcol] ;
	CoinBigIndex tgtce = tgtcs+colLengths[tgtcol] ;
	/*
	  A few checks to make sure that the candidate pair is still suitable.
	  Processing candidates earlier in the list can eliminate coefficients.
	  * Don't use this pair if any involved row i has become a row singleton
	  or empty.
	  * Don't use this pair if any involved row has been modified as part of
	  the processing for a previous candidate pair on this call.
	  * Don't use this pair if a(i,tgtcol) has become zero.
	  
	  The checks on a(i,tgtcol) seem superfluous but it's possible that
	  implied_free identified two candidate pairs to eliminate the same column. If
	  we've already processed one of them, we could be in trouble.
	*/
	double tgtcoeff = 0.0 ;
	bool dealBreaker = false ;
	for (CoinBigIndex kcol = tgtcs ; kcol < tgtce ; ++kcol) {
	  const int i = rowIndices[kcol] ;
	  if (rowLengths[i] < 2 || prob->rowUsed(i)) {
	    dealBreaker = true ;
	    break ;
	  }
	  const double aij = colCoeffs[kcol] ;
	  if (fabs(aij) <= ZTOLDP2) {
	    dealBreaker = true ;
	    break ;
	  }
	  if (i == tgtrow) tgtcoeff = aij ;
	}
	
	if (dealBreaker == true) {
#     if PRESOLVE_DEBUG > 3
	  std::cout
	    << "    skipping eqn " << tgtrow << " x(" << tgtcol
	    << "); deal breaker (1)." << std::endl ;
#     endif
	  continue ;
	}
	/*
	  Check for numerical stability.A large coeff_factor will inflate the
	  coefficients in the substitution formula.
	*/
	dealBreaker = false ;
	for (CoinBigIndex kcol = tgtcs ; kcol < tgtce ; ++kcol) {
	  const double coeff_factor = fabs(colCoeffs[kcol]/tgtcoeff) ;
	  if (coeff_factor > 10.0)
	    dealBreaker = true ;
	}
	if (dealBreaker == true) {
#     if PRESOLVE_DEBUG > 3
	  std::cout
	    << "    skipping eqn " << tgtrow << " x(" << tgtcol
	    << "); deal breaker (2)." << std::endl ;
#     endif
	  continue ;
	}
	/*
	  Count up the total number of coefficients in entangled rows and mark them as
	  contaminated.
	*/
	int ntotels = 0 ;
	for (CoinBigIndex kcol = tgtcs ; kcol < tgtce ; ++kcol) {
	  const int i = rowIndices[kcol] ;
	  ntotels += rowLengths[i] ;
	  PRESOLVEASSERT(!prob->rowUsed(i)) ;
	  prob->setRowUsed(i) ;
	  rowsUsed[nRowsUsed++] = i ;
	}
	
	CoinBigIndex tgtrs = rowStarts[tgtrow] ;
	CoinBigIndex tgtre = tgtrs+rowLengths[tgtrow] ;
	
	// kill small if wanted
	int relax= (prob->presolveOptions()&0x60000)>>17;
	double tolerance = 1.0e-12;
	for (int i=0;i<relax;i++)
	  tolerance *= 10.0;
	
	/*
	  Sort the target row for efficiency
	*/
	CoinSort_2(colIndices+tgtrs,colIndices+tgtre,rowCoeffs+tgtrs) ;
	CoinBigIndex start=colStarts[tgtcol];
	CoinBigIndex end = start+colLengths[tgtcol];
	numberBadElements=0;
	int numberFill=-rowLengths[tgtrow];
	for (int colndx = start ; colndx < end ; ++colndx) {
	  int i = rowIndices[colndx] ;
	  if (i == tgtrow) continue ;
	  
	  double ait = colCoeffs[colndx] ;
	  double coeff_factor = -ait/tgtcoeff ;
	  
	  CoinBigIndex krs = rowStarts[i] ;
	  CoinBigIndex kre = krs+rowLengths[i] ;
	  /*
	    Sort the row for efficiency and call add_row to do the actual business of
	    changing coefficients due to substitution. This has the potential to trigger
	    compaction of the row-major bulk store, so update bulk store indices.
	  */
	  CoinSort_2(colIndices+krs,colIndices+kre,rowCoeffs+krs) ;
	  
	  numberFill += check_row(rowStarts,rowCoeffs,colIndices,
				  rowLengths,coeff_factor,tolerance,i,tgtrow);
	}
	if (numberBadElements||3*numberFill>2*(colLengths[tgtcol]+rowLengths[tgtrow])) {
	  //printf("Bad subst col %d row %d - %d small elements, fill %d\n",
	  //	 tgtcol,tgtrow,numberBadElements,numberFill);
	  if (numberBadElements)
	    nBad++;
	} else {
	  whichFree[unprocessed]=tgtcol;
	  implied_free[unprocessed++]=tgtrow;
	  //printf("Good subst col %d row %d - fill %d\n",
	  //	 tgtcol,tgtrow,numberFill);
	}
      }
      /*
	That's it, we've processed all the candidate pairs.
	
	Clear the row used flags.
      */
      for (int i = 0 ; i < nRowsUsed ; i++) prob->unsetRowUsed(rowsUsed[i]) ;
#if CLP_USEFUL_PRINTOUT
      printf("%d allowed through out of %d - %d on coefficient\n",
	     unprocessed,numberFree,nBad);
#endif      
    }
    next = subst_constraint_action::presolve(prob,implied_free,whichFree,
    					     unprocessed,next,maxLook) ;
  }
/*
  Give some feedback to the presolve driver. If we aren't finding enough
  candidates and haven't reached the limit, bump fill_level and return a
  negated value. The presolve driver can tweak this value or simply return
  it on the next call. See the top of the routine for a full explanation.
*/
  if (numberFree < 30 && maxLook < prob->maxSubstLevel_) {
    fill_level = -(maxLook+1) ;
  } else {
    fill_level = maxLook ;
  }

# if COIN_PRESOLVE_TUNING > 0
  double thisTime ;
  if (prob->tuning_) thisTime = CoinCpuTime() ;
# endif
# if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
  presolve_consistent(prob) ;
  presolve_links_ok(prob) ;
  presolve_check_sol(prob) ;
  presolve_check_nbasic(prob) ;
# endif
# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
  int droppedRows = prob->countEmptyRows()-startEmptyRows ;
  int droppedColumns = prob->countEmptyCols()-startEmptyColumns ;
  std::cout
    << "Leaving implied_free_action::presolve, fill level " << fill_level
    << ", " << droppedRows << " rows, "
    << droppedColumns << " columns dropped" ;
# if COIN_PRESOLVE_TUNING > 0
  std::cout << " in " << thisTime-startTime << "s" ;
# endif
  std::cout << "." << std::endl ;
# endif

  return (next) ;
}
Пример #22
0
int check( int x, int y )
{
    return check_col( y ) && check_row( x ) && check_fdiag( x, y ) && check_bdiag( x, y );
}
Пример #23
0
void test_row(int row[WIDTH], int expected_value) {
    test( check_row(row) == expected_value ? "Pass" : "Fail" );
}
Пример #24
0
static PyObject *
SearchResults_cumulative_score_row(SearchResults *self, PyObject *args, PyObject *kwds) {
  static char *kwlist[] = {"row", "min_score", "max_score", "interval", NULL};
  int row=-1;
  PyObject *min_score_obj=Py_None, *max_score_obj=Py_None;
  double min_score=0.0, max_score=1.0;
  int num_hits;
  double *scores;
  int include_min=0, include_max=0;
  double score=0.0;
  int i;
  const char *interval = "[]";
  if (!PyArg_ParseTupleAndKeywords(args, kwds, "i|OOs:cumulative_score_row", kwlist,
                                   &row, &min_score_obj, &max_score_obj, &interval)) {
    return NULL;
  }
  if (!check_row(self->num_results, &row) ||
      !check_min_max_score(min_score_obj, max_score_obj, &min_score, &max_score) ||
      !check_interval(interval, &include_min, &include_max)) {
    return NULL;
  }
  num_hits = chemfp_get_num_hits(self->results+row);
  scores = (self->results+row)->scores;

  if ((min_score > max_score) ||
      (min_score == max_score && (!include_min || !include_max))) {
    return PyFloat_FromDouble(0.0);
  }

  if (include_min) {
    if (include_max) {
      /* [] -- Include both ends */
      if (min_score_obj == Py_None) {
        if (max_score_obj == Py_None) {
          CUMULATIVE_SCORE_ROW_MACRO(1);
        } else {
          /* No lower bound */
          CUMULATIVE_SCORE_ROW_MACRO(scores[i] <= max_score);
        }
      } else {
        if (max_score_obj == Py_None) {
          /* Lower bound but no upper bound */
          CUMULATIVE_SCORE_ROW_MACRO(min_score <= scores[i]);
        } else {
          /* Definite lower and upper bound */
          CUMULATIVE_SCORE_ROW_MACRO(min_score <= scores[i] && scores[i] <= max_score);
        }
      }
    } else {
      /* [) -- Include the minimum but not the maximum */
      if (min_score_obj == Py_None) {
        /* There is no minimum */
        CUMULATIVE_SCORE_ROW_MACRO(scores[i] < max_score);
      } else {
        /* There is a minimum and a maximum test */
        CUMULATIVE_SCORE_ROW_MACRO(min_score <= scores[i] && scores[i] < max_score);
      }
    }
  } else {
    if (include_max) {
      /* (] -- Exclude the minimum, include the maximum */
      if (max_score_obj == Py_None) {
        /* No specified max, so must only be greater than the lower bound */
        CUMULATIVE_SCORE_ROW_MACRO(min_score < scores[i]);
      } else {
        CUMULATIVE_SCORE_ROW_MACRO(min_score < scores[i] && scores[i] <= max_score);
      }
    } else {
      /* () -- Exclude the minimum and exclude the maximum */
      CUMULATIVE_SCORE_ROW_MACRO(min_score < scores[i] && scores[i] < max_score);
    }
  }
  return PyFloat_FromDouble(score);
}