/** execution method of primal heuristic */
static
SCIP_DECL_HEUREXEC(heurExecFixandinfer)
{  /*lint --e{715}*/
   SCIP_HEURDATA* heurdata;
   SCIP_VAR** cands;
   int ncands;
   int startncands;
   int divedepth;
   SCIP_Bool cutoff;
   SCIP_Real large;

   *result = SCIP_DIDNOTRUN;

   /* we cannot run on problems with continuous variables */
   if( SCIPgetNContVars(scip) > 0 )
      return SCIP_OKAY;

   /* get unfixed variables */
   SCIP_CALL( SCIPgetPseudoBranchCands(scip, &cands, &ncands, NULL) );
   if( ncands == 0 )
      return SCIP_OKAY;

   SCIPdebugMessage("starting fix-and-infer heuristic with %d unfixed integral variables\n", ncands);

   *result = SCIP_DIDNOTFIND;

   /* get heuristic data */
   heurdata = SCIPheurGetData(heur);
   assert(heurdata != NULL);

   /* start probing */
   SCIP_CALL( SCIPstartProbing(scip) );

   /* fix variables and propagate inferences as long as the problem is still feasible and there are
    * unfixed integral variables
    */
   cutoff = FALSE;
   divedepth = 0;
   startncands = ncands;

   /* determine large value to set variables to */
   large = SCIPinfinity(scip);
   if( !SCIPisInfinity(scip, 0.1 / SCIPfeastol(scip)) )
      large = 0.1 / SCIPfeastol(scip);

   while( !cutoff && ncands > 0
      && (divedepth < heurdata->minfixings || (startncands - ncands) * 2 * MAXDIVEDEPTH >= startncands * divedepth)
      && !SCIPisStopped(scip) )
   {
      divedepth++;

      /* create next probing node */
      SCIP_CALL( SCIPnewProbingNode(scip) );

      /* fix next variable */
      SCIP_CALL( fixVariable(scip, cands, ncands, large) );

      /* propagate the fixing */
      SCIP_CALL( SCIPpropagateProbing(scip, heurdata->proprounds, &cutoff, NULL) );

      /* get remaining unfixed variables */
      if( !cutoff )
      {
         SCIP_CALL( SCIPgetPseudoBranchCands(scip, &cands, &ncands, NULL) );
      }
   }

   /* check, if we are still feasible */
   if( cutoff )
   {
      SCIPdebugMessage("propagation detected a cutoff\n");
   }
   else if( ncands == 0 )
   {
      SCIP_Bool success;

      success = FALSE;

      /* try to add solution to SCIP */
      SCIP_CALL( SCIPtryCurrentSol(scip, heur, FALSE, FALSE, TRUE, &success) );

      if( success )
      {
         SCIPdebugMessage("found primal feasible solution\n");
         *result = SCIP_FOUNDSOL;
      }
      else
      {
         SCIPdebugMessage("primal solution was rejected\n");
      }
   }
   else
   {
      SCIPdebugMessage("probing was aborted (probing depth: %d, fixed: %d/%d)", divedepth, startncands - ncands, startncands);
   }

   /* end probing */
   SCIP_CALL( SCIPendProbing(scip) );

   return SCIP_OKAY;
}
char constraintPropagation(CPropagation *cp, int var, double value, vector<Fixation> &fixations,
                            int &unfixedVars, double *colLb, double *colUb, double *constrBound, int *unfixedVarsByRow)
{
	assert(value == 0.0 || value == 1.0);
	assert(var >= 0 && var < cp->numCols);
	//assert(colLb[var] != colUb[var]);
    if(colLb[var] == colUb[var])
    {
        // assert(colLb[var] == value);
        return NOIMPLICATION;
    }
	//assert(fixations.empty());

	char status = NOIMPLICATION;
	queue<int> C;
	Fixation tmp;
	vector<char> rowIsInQueue(cp->numRows, 0);

	fixVariable(cp, var, value, unfixedVars, colLb, colUb, constrBound, unfixedVarsByRow);

	for(int i = 0; i < (int)cp->matrixByCol[var].size(); i++)
	{
		const pair<int, double> constraint = cp->matrixByCol[var][i];
		const int idxRow = constraint.first;
		const double coef = constraint.second;

		if((unfixedVarsByRow[idxRow] > 0) && (value == 1.0 && coef > 0.0) || (value == 0.0 && coef < 0.0))
		{
			C.push(idxRow);
			rowIsInQueue[idxRow] = 1;
		}
	}

	while(!C.empty())
	{
		const int idxRow = C.front();
		C.pop();
		rowIsInQueue[idxRow] = 0;

		for(int i = 0; i < (int)cp->matrixByRow[idxRow].size(); i++)
		{
			const pair<int, double> var = cp->matrixByRow[idxRow][i];
			const int idxVar = var.first;
			const double coef = var.second;

			if(colLb[idxVar] == colUb[idxVar])
				continue;

			char eval = evaluateBound(cp, var, idxRow, constrBound);

            if(eval == ACTIVATE || eval == DEACTIVATE)
            {
            	assert(colLb[idxVar] != colUb[idxVar]);
            	tmp.idxVar = idxVar;
            	tmp.valueToFix = eval;
            	fixations.push_back(tmp);
            	status = FIXATION;
				unfixedVars--;
	            colLb[idxVar] = colUb[idxVar] = eval;

	            for(int j = 0; j < (int)cp->matrixByCol[idxVar].size(); j++)
	            {
	                const pair<int, double> constraint = cp->matrixByCol[idxVar][j];
	                const int idxRow2 = constraint.first;
	                const double coef2 = constraint.second;

	                unfixedVarsByRow[idxRow2]--;

	                if(eval == ACTIVATE && coef2 > 0.0)
	                {
	                    constrBound[idxRow2] -= coef2;
	                    if(unfixedVarsByRow[idxRow2] > 0 && !rowIsInQueue[idxRow2])
	                    {
	                    	C.push(idxRow2);
	                    	rowIsInQueue[idxRow2] = 1;
	                    }
	                }
	                else if(eval == DEACTIVATE && coef2 < 0.0)
	                {
	                    constrBound[idxRow2] += coef2;
	                    if(unfixedVarsByRow[idxRow2] > 0 && !rowIsInQueue[idxRow2])
	                    {
	                    	C.push(idxRow2);
	                    	rowIsInQueue[idxRow2] = 1;
	                    }
	                }
                    
                    if(unfixedVarsByRow[idxRow2] == 0 && constrBound[idxRow2] < 0.0)
                    	status = CONFLICT; //nao posso retornar direto pq tenho q atualizar os bounds das retricoes
	            }
	            if(status == CONFLICT)
	            	return CONFLICT;
        	}
            else if(eval == CONFLICT)
            	return CONFLICT;
		}
	}
	return status;
}