Beispiel #1
0
//-------------------------------------------------------------------
// Generate Stored cuts
//-------------------------------------------------------------------
void
CglStored::generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
			const CglTreeInfo /*info*/) const
{
  // Get basic problem information
  const double * solution = si.getColSolution();
  int numberRowCuts = cuts_.sizeRowCuts();
  for (int i=0;i<numberRowCuts;i++) {
    const OsiRowCut * rowCutPointer = cuts_.rowCutPtr(i);
    double violation = rowCutPointer->violated(solution);
    if (violation>=requiredViolation_)
      cs.insert(*rowCutPointer);
  }
  if (probingInfo_) {
    int number01 = probingInfo_->numberIntegers();
    const cliqueEntry * entry = probingInfo_->fixEntries();
    const int * toZero = probingInfo_->toZero();
    const int * toOne = probingInfo_->toOne();
    const int * integerVariable = probingInfo_->integerVariable();
    const double * lower = si.getColLower();
    const double * upper = si.getColUpper();
    OsiRowCut cut;
    int column[2];
    double element[2];
    for (int i=0;i<number01;i++) {
      int iColumn=integerVariable[i];
      if (upper[iColumn]==lower[iColumn])
	continue;
      double value1 = solution[iColumn];
      for (int j=toZero[i];j<toOne[i];j++) {
	int jColumn=sequenceInCliqueEntry(entry[j]);
	if (jColumn<number01) {
	  jColumn=integerVariable[jColumn];
	  assert (jColumn>=0);
	  double value2 = solution[jColumn];
	  if (oneFixesInCliqueEntry(entry[j])) {
	    double violation = 1.0-value1-value2;
	    if (violation>requiredViolation_) {
	      //printf("XXX can do %d + %d >=1\n",iColumn,jColumn);
	      cut.setLb(1.0);
	      cut.setUb(COIN_DBL_MAX);
	      column[0]=iColumn;
	      element[0]=1.0;
	      column[1]=jColumn;
	      element[1]= 1.0;
	      cut.setEffectiveness(violation);
	      cut.setRow(2,column,element,false);
	      cs.insert(cut);
	    }
	  } else {
	    double violation = value2-value1;
	    if (violation>requiredViolation_) {
	      //printf("XXX can do %d >= %d\n",iColumn,jColumn);
	      cut.setLb(0.0);
	      cut.setUb(COIN_DBL_MAX);
	      column[0]=iColumn;
	      element[0]=1.0;
	      column[1]=jColumn;
	      element[1]= -1.0;
	      cut.setEffectiveness(violation);
	      cut.setRow(2,column,element,false);
	      cs.insert(cut);
	    }
	  }
	} else {
	  jColumn -= number01; // not 0-1
	  double value2 = solution[jColumn];
	  double lowerValue = lower[jColumn];
	  double upperValue = upper[jColumn];
	  if (oneFixesInCliqueEntry(entry[j])) {
	    double violation = upperValue-value1*(upperValue-lowerValue)-value2;
	    if (violation>requiredViolation_) {
	      //printf("XXX can do %g*%d + %d >=%g\n",(upperValue-lowerValue),iColumn,jColumn,upperValue);
	      cut.setLb(upperValue);
	      cut.setUb(COIN_DBL_MAX);
	      column[0]=iColumn;
	      element[0]=upperValue-lowerValue;
	      column[1]=jColumn;
	      element[1]= 1.0;
	      cut.setEffectiveness(violation);
	      cut.setRow(2,column,element,false);
	      cs.insert(cut);
	    }
	  } else {
	    double violation = value2-value1*(upperValue-lowerValue)-lowerValue;
	    if (violation>requiredViolation_) {
	      //printf("XXX can do %g*%d >= %d -%g\n",(upperValue-lowerValue),iColumn,jColumn,lowerValue);
	      cut.setLb(-lowerValue);
	      cut.setUb(COIN_DBL_MAX);
	      column[0]=iColumn;
	      element[0]=upperValue-lowerValue;
	      column[1]=jColumn;
	      element[1]= -1.0;
	      cut.setEffectiveness(violation);
	      cut.setRow(2,column,element,false);
	      cs.insert(cut);
	    }
	  }
	}
      }
      for (int j=toOne[i];j<toZero[i+1];j++) {
	int jColumn=sequenceInCliqueEntry(entry[j]);
	if (jColumn<number01) {
	  jColumn=integerVariable[jColumn];
	  assert (jColumn>=0);
	  double value2 = solution[jColumn];
	  if (oneFixesInCliqueEntry(entry[j])) {
	    double violation = value1-value2;
	    if (violation>requiredViolation_) {
	      //printf("XXX can do %d <= %d\n",iColumn,jColumn);
	      cut.setLb(-COIN_DBL_MAX);
	      cut.setUb(0.0);
	      column[0]=iColumn;
	      element[0]=1.0;
	      column[1]=jColumn;
	      element[1]= -1.0;
	      cut.setEffectiveness(violation);
	      cut.setRow(2,column,element,false);
	      cs.insert(cut);
	    }
	  } else {
	    double violation = value1+value2-1.0;
	    if (violation>requiredViolation_) {
	      //printf("XXX can do %d + %d <=1\n",iColumn,jColumn);
	      cut.setLb(-COIN_DBL_MAX);
	      cut.setUb(1.0);
	      column[0]=iColumn;
	      element[0]=1.0;
	      column[1]=jColumn;
	      element[1]= 1.0;
	      cut.setEffectiveness(violation);
	      cut.setRow(2,column,element,false);
	      cs.insert(cut);
	    }
	  }
	} else {
	  jColumn -= number01; // not 0-1
	  double value2 = solution[jColumn];
	  double lowerValue = lower[jColumn];
	  double upperValue = upper[jColumn];
	  if (oneFixesInCliqueEntry(entry[j])) {
	    double violation = lowerValue +(upperValue-lowerValue)*value1-value2;
	    if (violation>requiredViolation_) {
	      //printf("XXX can do %g*%d <= %d -%g\n",(upperValue-lowerValue),iColumn,jColumn,lowerValue);
	      cut.setLb(-COIN_DBL_MAX);
	      cut.setUb(-lowerValue);
	      column[0]=iColumn;
	      element[0]=upperValue-lowerValue;
	      column[1]=jColumn;
	      element[1]= -1.0;
	      cut.setEffectiveness(violation);
	      cut.setRow(2,column,element,false);
	      cs.insert(cut);
	    }
	  } else {
	    double violation = (upperValue-lowerValue)*value1+value2-upperValue;
	    if (violation>requiredViolation_) {
	      //printf("XXX can do %g*%d + %d <=%g\n",(upperValue-lowerValue),iColumn,jColumn,upperValue);
	      cut.setLb(-COIN_DBL_MAX);
	      cut.setUb(upperValue);
	      column[0]=iColumn;
	      element[0]=upperValue-lowerValue;
	      column[1]=jColumn;
	      element[1]= 1.0;
	      cut.setEffectiveness(violation);
	      cut.setRow(2,column,element,false);
	      cs.insert(cut);
	    }
	  }
	}
      }
    }
  }
}
static int outDupsEtc(int numberIntegers, int & numberCliques, int & numberMatrixCliques,
		      int * & cliqueStart, char * & cliqueType, CliqueEntry *& entry, 
		      int numberLastTime, int printit)
{
  bool allNew=false;
  int * whichP = new int [numberIntegers];
  int iClique;
  assert (sizeof(int)==4);
  assert (sizeof(CliqueEntry)==4);
  // If lots then get rid of short ones
#define KEEP_CLIQUES 10000
  if (numberCliques-numberMatrixCliques>KEEP_CLIQUES) {
    int * sort = new int [numberCliques];
    for (iClique=numberMatrixCliques;iClique<numberCliques;iClique++) {
      int j = cliqueStart[iClique];
      int n = cliqueStart[iClique+1]-j;
      sort[iClique]=n;
    }
    std::sort(sort+numberMatrixCliques,sort+numberCliques);
    int allow = sort[numberCliques-KEEP_CLIQUES];
    int nEqual=0;
    for (iClique=numberCliques-KEEP_CLIQUES;iClique<numberCliques;iClique++) {
      if (sort[iClique]>allow)
	break;
      else
	nEqual++;
    }
    delete [] sort;
    int j=cliqueStart[numberMatrixCliques];
    int put=j;
    int nClique=numberMatrixCliques;
    for (iClique=numberMatrixCliques;iClique<numberCliques;iClique++) {
      int end = cliqueStart[iClique+1];
      int n = end-j;
      bool copy=false;
      if (n>allow) {
	copy=true;
      } else if (n==allow&&nEqual) {
	copy=true;
	nEqual--;
      }
      if (copy) {
	cliqueType[nClique++]=cliqueType[iClique];
	for (;j<end;j++)
	  entry[put++]=entry[j];
      }
      j = cliqueStart[iClique+1];
      cliqueStart[nClique]=put;
    }
    numberCliques = nClique;
  }
  // sort
  for (iClique=0;iClique<numberCliques;iClique++) {
    int j = cliqueStart[iClique];
    int n = cliqueStart[iClique+1]-j;
    for (int i=0;i<n;i++) 
      whichP[i]=sequenceInCliqueEntry(entry[i+j]);
    CoinSort_2(whichP,whichP+n,(reinterpret_cast<int *>(entry))+j);
  }
  // lexicographic sort
  int * which = new int [numberCliques];
  int * position = new int [numberCliques];
  int * sort = new int [numberCliques];
  int * value = new int [numberCliques];
  for (iClique=0;iClique<numberCliques;iClique++) {
    which[iClique]=iClique;
    sort[iClique]=sequenceInCliqueEntry(entry[cliqueStart[iClique]]);
    value[iClique]=sort[iClique];
    position[iClique]=0;
  }
  CoinSort_2(sort,sort+numberCliques,which);
  int lastDone=-1;
  int nDup=0;
  int nSave=0;
  while (lastDone<numberCliques-1) {
    int jClique=lastDone+1;
    int jFirst = jClique;
    int iFirst = which[jFirst];
    int iValue = value[iFirst];
    int iPos = position[iFirst];
    jClique++;
    for (;jClique<numberCliques;jClique++) {
      int kClique = which[jClique];
      int jValue = value[kClique];
      if (jValue>iValue||position[kClique]<iPos)
	break;
    }
    if (jClique==jFirst+1) {
      // done that bit
      lastDone++;
    } else {
      // use next bit to sort and then repeat
      int jLast=jClique;
      for (jClique=jFirst;jClique<jLast;jClique++) {
	int kClique = which[jClique];
	int iValue = value[kClique];
	// put at end if finished
	if (iValue<numberIntegers) {
	  int kPos=position[kClique]+1;
	  position[kClique]=kPos;
	  kPos += cliqueStart[kClique];
	  if (kPos==cliqueStart[kClique+1]) {
	    iValue = numberIntegers;
	  } else {
	    iValue = sequenceInCliqueEntry(entry[kPos]);
	  }
	  value[kClique]=iValue;
	}
	sort[jClique]=iValue;
      }
      CoinSort_2(sort+jFirst,sort+jLast,which+jFirst);
      // if duplicate mark and move on
      int iLowest=numberCliques;
      for (jClique=jFirst;jClique<jLast;jClique++) {
	int kClique = which [jClique];
	int iValue = value[kClique];
	if (iValue<numberIntegers) 
	  break;
	iLowest = CoinMin(iLowest,kClique);
      }
      if (jClique>jFirst) {
	// mark all apart from lowest number as duplicate and move on
	lastDone =jClique-1;
	for (jClique=jFirst;jClique<=lastDone;jClique++) {
	  int kClique = which [jClique];
	  if (kClique!=iLowest) {
	    value[kClique]=-2;
	    nDup++;
	    nSave += cliqueStart[kClique+1]-cliqueStart[kClique];
	  }
	}
      }
    }
  }
  if (printit)
    printf("%d duplicates\n",nDup);
  // Now see if any subset
  int nOut=0;
  for (int jClique=0;jClique<numberCliques;jClique++) {
    if (value[jClique]!=-2) {
      position[jClique]=cliqueStart[jClique];
      value[jClique]=sequenceInCliqueEntry(entry[cliqueStart[jClique]]);
    }
  }
  nSave=0;
  int startLooking=0;
  for (int jClique=0;jClique<numberCliques;jClique++) {
    int kClique = which[jClique];
    if (value[kClique]==-2) {
      nOut++;
      nSave += cliqueStart[kClique+1]-cliqueStart[kClique];
      if (jClique==startLooking)
	startLooking++;
      continue;
    }
    int kValue =value[kClique];
    for (int iiClique=startLooking;iiClique<jClique;iiClique++) {
      int iClique = which[iiClique];
      int iValue = value[iClique];
      if (iValue==-2||iValue==numberIntegers) {
	if (iiClique==startLooking)
	  startLooking++;
	continue;
      } else {
	if (kValue>static_cast<int> (sequenceInCliqueEntry(entry[cliqueStart[iClique+1]-1]))) {
	  value[iClique]=numberIntegers;
	  continue;
	}
      }
      if (iValue<kValue) {
	while (iValue<kValue) {
	  int iPos=position[iClique]+1;
	  position[iClique]=iPos;
	  if (iPos==cliqueStart[iClique+1]) {
	    iValue = numberIntegers;
	  } else {
	    iValue = sequenceInCliqueEntry(entry[iPos]);
	  }
	  value[iClique]=iValue;
	}
      } 
      if (iValue>kValue) 
	continue; // not a candidate
      // See if subset (remember duplicates have gone)
      if (cliqueStart[iClique+1]-position[iClique]>
	  cliqueStart[kClique+1]-cliqueStart[kClique]) {
	// could be subset ?
	int offset = cliqueStart[iClique]-position[kClique];
	int j;
	bool subset=true;
	// what about different fixes bool odd=false;
	for (j=cliqueStart[kClique]+1;j<cliqueStart[kClique+1];j++) {
	  int kColumn = sequenceInCliqueEntry(entry[j]);
	  int iColumn = sequenceInCliqueEntry(entry[j+offset]);
	  if (iColumn>kColumn) {
	    subset=false;
	  } else {
	    while (iColumn<kColumn) {
	      offset++;
	      if (j+offset<cliqueStart[iClique+1]) {
		iColumn = sequenceInCliqueEntry(entry[j+offset]);
	      } else {
		subset=false;
		break;
	      }
	    }
	  }
	  if (!subset)
	    break;
	}
	if (subset) {
	  value[kClique]=-2;
	  if (printit>1)
	    printf("clique %d is subset of %d\n",kClique,iClique);
	  nOut++;
	  break;
	}
      }
    }
  }
  if (nOut) {
    if(printit) 
      printf("Can get rid of %d cliques\n",nOut);
    // make new copy
    int nNewC=numberCliques-nOut;
    int size = cliqueStart[numberCliques]-nSave;
    int n=0;
    int * start = new int [nNewC+1];
    char * type = new char [nNewC];
    start[0]=0;
    CliqueEntry * entryC = new CliqueEntry [size];
    int nel=0;
    allNew = true;
    for (int jClique=0;jClique<numberCliques;jClique++) {
      int kClique = which[jClique];
      if (value[kClique]!=-2&&kClique<numberMatrixCliques) {
	if (kClique>=numberLastTime)
	  allNew=false;
	int nn=cliqueStart[kClique+1]-cliqueStart[kClique];
	memcpy(entryC+nel,entry+cliqueStart[kClique],nn*sizeof(CliqueEntry));
	nel += nn;
	type[n++]=cliqueType[kClique];
	start[n]=nel;
      }
    }
    int nM=n;
    for (int jClique=0;jClique<numberCliques;jClique++) {
      int kClique = which[jClique];
      if (value[kClique]!=-2&&kClique>=numberMatrixCliques) {
	if (kClique>=numberLastTime)
	  allNew=false;
	int nn=cliqueStart[kClique+1]-cliqueStart[kClique];
	memcpy(entryC+nel,entry+cliqueStart[kClique],nn*sizeof(CliqueEntry));
	nel += nn;
	type[n++]=cliqueType[kClique];
	start[n]=nel;
      }
    }
    // move
    numberCliques=n;
    numberMatrixCliques=nM;
    delete [] cliqueStart;
    cliqueStart=start;
    delete [] entry;
    entry = entryC;
    delete [] cliqueType;
    cliqueType = type;
    if (printit>1) {
      for (int jClique=0;jClique<numberCliques;jClique++) {
	printf("%d [ ",jClique);
	for (int i=cliqueStart[jClique];i<cliqueStart[jClique+1];i++)
	  printf("%d(%d) ",sequenceInCliqueEntry(entry[i]),oneFixesInCliqueEntry(entry[i]));
	printf("]\n");
      }
    }
    if (printit)
      printf("%d matrix cliques and %d found by probing\n",numberMatrixCliques,numberCliques-numberMatrixCliques);
  }
  delete [] value;
  delete [] sort;
  delete [] which;
  delete [] position;
  delete [] whichP;
  if (!allNew)
    return nOut;
  else
    return -1;
}
OsiSolverInterface *
CglTreeProbingInfo::analyze(const OsiSolverInterface & si,int createSolver,
			    int numberExtraCliques,const int * starts,
			    const CliqueEntry * entries,const char * type)
{
  if (!createSolver)
    return NULL;
  convert();
  if (!numberIntegers_)
    return NULL;
  bool alwaysDo=false;
  if (numberExtraCliques<0) {
    alwaysDo=true;
    numberExtraCliques=0;
  }
  bool printit=false;
  int numberCliques=0;
  int numberEntries=0;
  int * cliqueStart = NULL;
  CliqueEntry * entry = NULL;
  char * cliqueType=NULL;
  int * whichP = new int [numberIntegers_];
  int * whichM = new int [numberIntegers_];
  int *whichClique=NULL;
  int numberRows=si.getNumRows(); 
  int numberMatrixCliques=0;
  const CoinPackedMatrix * rowCopy = si.getMatrixByRow();
  assert(numberRows&&si.getNumCols());
  int iRow;
  const int * column = rowCopy->getIndices();
  const double * elementByRow = rowCopy->getElements();
  const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
  const int * rowLength = rowCopy->getVectorLengths(); 
  const double * lower = si.getColLower();
  const double * upper = si.getColUpper();
  const double * rowLower = si.getRowLower();
  const double * rowUpper = si.getRowUpper();
  for (int iPass=0;iPass<2;iPass++) {
    if (iPass) {
      int numberExtraEntries=0;
      if (numberExtraCliques) 
	numberExtraEntries = starts[numberExtraCliques];
      cliqueStart = new int [numberCliques+1+numberExtraCliques];
      cliqueStart[0]=0;
      entry = new CliqueEntry [numberEntries+numberExtraEntries];
      cliqueType = new char [numberCliques+numberExtraCliques];
      whichClique = new int [numberEntries+numberExtraEntries];
      numberCliques=0;
      numberEntries=0;
    }
#if 1
    for (iRow=0;iRow<numberRows;iRow++) {
      int numberP1=0, numberM1=0;
      int numberTotal=0;
      CoinBigIndex j;
      double upperValue=rowUpper[iRow];
      double lowerValue=rowLower[iRow];
      bool good=true;
      for (j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
	int iColumn = column[j];
	double value = elementByRow[j];
	if (upper[iColumn]-lower[iColumn]<1.0e-8) {
	  // fixed
	  upperValue -= lower[iColumn]*value;
	  lowerValue -= lower[iColumn]*value;
	  continue;
	} else if (backward_[iColumn]<0) {
	  good = false;
	  break;
	} else {
	  iColumn = backward_[iColumn];
	  numberTotal++;
	}
	if (fabs(value)!=1.0) {
	  good=false;
	} else if (value>0.0) {
	  assert (numberP1<numberIntegers_);
	  whichP[numberP1++]=iColumn;;
	} else {
	  assert (numberM1<numberIntegers_);
	  whichM[numberM1++]=iColumn;
	}
      }
      int iUpper = static_cast<int> (floor(upperValue+1.0e-5));
      int iLower = static_cast<int> (ceil(lowerValue-1.0e-5));
      int state=0;
      if (upperValue<1.0e6) {
	if (iUpper==1-numberM1)
	  state=1;
	else if (iUpper==-numberM1)
	  state=2;
	else if (iUpper<-numberM1)
	  state=3;
	if (fabs(static_cast<double> (iUpper)-upperValue)>1.0e-9)
	  state =-1;
      }
      if (!state&&lowerValue>-1.0e6) {
	if (-iLower==1-numberP1)
	  state=-1;
	else if (-iLower==-numberP1)
	  state=-2;
	else if (-iLower<-numberP1)
	  state=-3;
	if (fabs(static_cast<double> (iLower)-lowerValue)>1.0e-9)
	  state =-1;
      }
      if (numberP1+numberM1<2)
	state=-1;
      if (good&&state>0) {
	if (abs(state)==3) {
	  // infeasible
	  printf("FFF Infeasible\n");;
	  //feasible=false;
	  break;
	} else if (abs(state)==2) {
	  // we can fix all
	  //numberFixed += numberP1+numberM1;
	  printf("FFF can fix %d\n",numberP1+numberM1);
	} else {
	  for (j=0;j<numberP1;j++) {
	    int iColumn = whichP[j];
	    if (iPass) {
	      CliqueEntry temp;
	      setOneFixesInCliqueEntry(temp,true);
	      setSequenceInCliqueEntry(temp,iColumn);
	      entry[numberEntries]=temp;
	    }
	    numberEntries++;
	  }
	  for (j=0;j<numberM1;j++) {
	    int iColumn = whichM[j];
	    if (iPass) {
	      CliqueEntry temp;
	      setOneFixesInCliqueEntry(temp,false);
	      setSequenceInCliqueEntry(temp,iColumn);
	      entry[numberEntries]=temp;
	    }
	    numberEntries++;
	  }
	  if (iPass) {
	    if (iLower!=iUpper) {
	      // slack
	      cliqueType[numberCliques]='S';
	    } else {
	      cliqueType[numberCliques]='E';
	    }
	    cliqueStart[numberCliques+1]=numberEntries;
	  }
	  numberCliques++;
	}
      }
    }
#endif
    if (numberExtraCliques) {
      int numberExtraEntries = starts[numberExtraCliques];
      memcpy(entry+numberEntries,entries,numberExtraEntries*sizeof(CliqueEntry));
      for (int iClique=0;iClique<numberExtraCliques;iClique++) {
	cliqueType[numberCliques] = type[iClique];
	numberCliques++;
	cliqueStart[numberCliques]=starts[iClique]+numberEntries;
      }
      numberEntries += numberExtraEntries;
    }
    numberMatrixCliques=numberCliques;
    //int size = toZero_[numberIntegers_];
    //char * used = new char [size];
    //memset(used,0,size);
    // find two cliques
    int nFix=0;
    for (int iColumn=0;iColumn<static_cast<int> (numberIntegers_);iColumn++) {
      int j;
      for ( j=toZero_[iColumn];j<toOne_[iColumn];j++) {
	int jColumn=sequenceInCliqueEntry(fixEntry_[j]);
	// just look at ones beore (this also skips non 0-1)
	if (jColumn<iColumn) {
	  int k;
	  for ( k=toZero_[jColumn];k<toOne_[jColumn];k++) {
	    if (sequenceInCliqueEntry(fixEntry_[k])== (iColumn)) {
	      if (oneFixesInCliqueEntry(fixEntry_[j])) {
		if (oneFixesInCliqueEntry(fixEntry_[k])) {
		  if (printit&&!iPass)
		    printf("%d to zero implies %d to one and %d to zero implies %d to one\n",
			   iColumn,jColumn,jColumn,iColumn);
		  //0-0 illegal
		  if (iPass) {
		    CliqueEntry temp;
		    setOneFixesInCliqueEntry(temp,false);
		    setSequenceInCliqueEntry(temp,iColumn);
		    entry[numberEntries]=temp;
		  }
		  numberEntries++;
		  if (iPass) {
		    CliqueEntry temp;
		    setOneFixesInCliqueEntry(temp,false);
		    setSequenceInCliqueEntry(temp,jColumn);
		    entry[numberEntries]=temp;
		  }
		  numberEntries++;
		  if (iPass) {
		    // slack
		    cliqueType[numberCliques]='S';
		    cliqueStart[numberCliques+1]=numberEntries;
		  }
		  numberCliques++;
		} else {
		  if (printit&&!iPass)
		    printf("%d to zero implies %d to one and %d to zero implies %d to zero\n",
			   iColumn,jColumn,jColumn,iColumn);
		  nFix++; // jColumn is 1
		}
	      } else {
		if (oneFixesInCliqueEntry(fixEntry_[k])) {
		  if (printit&&!iPass)
		    printf("%d to zero implies %d to zero and %d to zero implies %d to one\n",
			   iColumn,jColumn,jColumn,iColumn);
		  nFix++; // iColumn is 1
		} else {
		  if (printit&&!iPass)
		    printf("%d to zero implies %d to zero and %d to zero implies %d to zero\n",
			   iColumn,jColumn,jColumn,iColumn);
		  nFix++; // jColumn=iColumn
		}
	      }
	    }
	  }
	  for ( k=toOne_[jColumn];k<toZero_[jColumn+1];k++) {
	    if (sequenceInCliqueEntry(fixEntry_[k])== (iColumn)) {
	      if (oneFixesInCliqueEntry(fixEntry_[j])) {
		if (oneFixesInCliqueEntry(fixEntry_[k])) {
		  if (printit&&!iPass)
		    printf("%d to zero implies %d to one and %d to one implies %d to one\n",
			   iColumn,jColumn,jColumn,iColumn);
		  nFix++; //iColumn is 1
		} else {
		  if (printit&&!iPass)
		    printf("%d to zero implies %d to one and %d to one implies %d to zero\n",
			   iColumn,jColumn,jColumn,iColumn);
		  nFix++; // iColumn+jcolumn=1
		}
	      } else {
		if (oneFixesInCliqueEntry(fixEntry_[k])) {
		  if (printit&&!iPass)
		    printf("%d to zero implies %d to zero and %d to one implies %d to one\n",
			   iColumn,jColumn,jColumn,iColumn);
		  // 0-1 illegal
		  if (iPass) {
		    CliqueEntry temp;
		    setOneFixesInCliqueEntry(temp,false);
		    setSequenceInCliqueEntry(temp,iColumn);
		    entry[numberEntries]=temp;
		  }
		  numberEntries++;
		  if (iPass) {
		    CliqueEntry temp;
		    setOneFixesInCliqueEntry(temp,true);
		    setSequenceInCliqueEntry(temp,jColumn);
		    entry[numberEntries]=temp;
		  }
		  numberEntries++;
		  if (iPass) {
		    // slack
		    cliqueType[numberCliques]='S';
		    cliqueStart[numberCliques+1]=numberEntries;
		  }
		  numberCliques++;
		} else {
		  if (printit&&!iPass)
		    printf("%d to zero implies %d to zero and %d to one implies %d to zero\n",
			   iColumn,jColumn,jColumn,iColumn);
		  nFix++; // jColumn is 0
		}
	      }
	    }
	  }
	}
      }
      for ( j=toOne_[iColumn];j<toZero_[iColumn+1];j++) {
	int jColumn=sequenceInCliqueEntry(fixEntry_[j]);
	if (jColumn<iColumn) {
	  int k;
	  for ( k=toZero_[jColumn];k<toOne_[jColumn];k++) {
	    if (sequenceInCliqueEntry(fixEntry_[k])== (iColumn)) {
	      if (oneFixesInCliqueEntry(fixEntry_[j])) {
		if (oneFixesInCliqueEntry(fixEntry_[k])) {
		  if (printit&&!iPass)
		    printf("%d to one implies %d to one and %d to zero implies %d to one\n",
			   iColumn,jColumn,jColumn,iColumn);
		  nFix++; // jColumn is 1
		} else {
		  if (printit&&!iPass)
		    printf("%d to one implies %d to one and %d to zero implies %d to zero\n",
			   iColumn,jColumn,jColumn,iColumn);
		  // 1-0 illegal
		  if (iPass) {
		    CliqueEntry temp;
		    setOneFixesInCliqueEntry(temp,true);
		    setSequenceInCliqueEntry(temp,iColumn);
		    entry[numberEntries]=temp;
		  }
		  numberEntries++;
		  if (iPass) {
		    CliqueEntry temp;
		    setOneFixesInCliqueEntry(temp,false);
		    setSequenceInCliqueEntry(temp,jColumn);
		    entry[numberEntries]=temp;
		  }
		  numberEntries++;
		  if (iPass) {
		    // slack
		    cliqueType[numberCliques]='S';
		    cliqueStart[numberCliques+1]=numberEntries;
		  }
		  numberCliques++;
		}
	      } else {
		if (oneFixesInCliqueEntry(fixEntry_[k])) {
		  if (printit&&!iPass)
		    printf("%d to one implies %d to zero and %d to zero implies %d to one\n",
			   iColumn,jColumn,jColumn,iColumn);
		  nFix++; // iColumn+jColumn=1
		} else {
		  if (printit&&!iPass)
		    printf("%d to one implies %d to zero and %d to zero implies %d to zero\n",
			   iColumn,jColumn,jColumn,iColumn);
		  nFix++; // iColumn is 0
		}
	      }
	    }
	  }
	  for ( k=toOne_[jColumn];k<toZero_[jColumn+1];k++) {
	    if (sequenceInCliqueEntry(fixEntry_[k])== (iColumn)) {
	      if (oneFixesInCliqueEntry(fixEntry_[j])) {
		if (oneFixesInCliqueEntry(fixEntry_[k])) {
		  if (printit&&!iPass)
		    printf("%d to one implies %d to one and %d to one implies %d to one\n",
			   iColumn,jColumn,jColumn,iColumn);
		  nFix++; // iColumn == jColumn
		} else {
		  if (printit&&!iPass)
		    printf("%d to one implies %d to one and %d to one implies %d to zero\n",
			   iColumn,jColumn,jColumn,iColumn);
		  nFix++; // iColumn is 0
		}
	      } else {
		if (oneFixesInCliqueEntry(fixEntry_[k])) {
		  if (printit&&!iPass)
		    printf("%d to one implies %d to zero and %d to one implies %d to one\n",
			   iColumn,jColumn,jColumn,iColumn);
		  nFix++; // jColumn is 0
		} else {
		  if (printit&&!iPass)
		    printf("%d to one implies %d to zero and %d to one implies %d to zero\n",
			   iColumn,jColumn,jColumn,iColumn);
		  // 1-1 illegal
		  if (iPass) {
		    CliqueEntry temp;
		    setOneFixesInCliqueEntry(temp,true);
		    setSequenceInCliqueEntry(temp,iColumn);
		    entry[numberEntries]=temp;
		  }
		  numberEntries++;
		  if (iPass) {
		    CliqueEntry temp;
		    setOneFixesInCliqueEntry(temp,true);
		    setSequenceInCliqueEntry(temp,jColumn);
		    entry[numberEntries]=temp;
		  }
		  numberEntries++;
		  if (iPass) {
		    // slack
		    cliqueType[numberCliques]='S';
		    cliqueStart[numberCliques+1]=numberEntries;
		  }
		  numberCliques++;
		}
	      }
	    }
	  }
	}
      }
    }
    if (!iPass)
      printf("%d cliques and %d fixed (%d already from matrix))\n",
	     numberCliques-numberMatrixCliques,nFix,numberMatrixCliques);
  }
  int iClique;
  outDupsEtc(numberIntegers_, numberCliques, numberMatrixCliques,
	     cliqueStart, cliqueType, entry, -1, printit ? 2 : 1);
  printf("%d matrix cliques and %d found by probing\n",numberMatrixCliques,numberCliques-numberMatrixCliques);
  int * zeroStart = new int [numberIntegers_+1];
  int * oneStart = new int [numberIntegers_];
  int * zeroCount = new int [numberIntegers_];
  int * oneCount = new int [numberIntegers_];
  char * mark = new char [numberIntegers_];
  memset(mark,0,numberIntegers_);
  int nStrengthen=-1;
  int iPass=0;
  while (nStrengthen&&iPass<20) {
    iPass++;
    int numberLastTime = numberCliques;
    int * count = new int [numberCliques];
    int i,iColumn;
    for (i=0;i<numberCliques;i++) {
      count[i]=0;
    }
    int * whichCount = new int [numberCliques];
    CoinZeroN(zeroCount,numberIntegers_);
    CoinZeroN(oneCount,numberIntegers_);
    for (iClique=0;iClique<numberCliques;iClique++) {
      for (int j=cliqueStart[iClique];j<cliqueStart[iClique+1];j++) {
	int iColumn = static_cast<int> (sequenceInCliqueEntry(entry[j]));
	if (oneFixesInCliqueEntry(entry[j])) {
	  oneCount[iColumn]++;
	} else {
	  zeroCount[iColumn]++;
	}
      }
    }
    int j;
    zeroStart[0]=0;
    cliqueStart[0]=0;
    for (j=0;j<numberIntegers_;j++) {
      int n;
      n=zeroCount[j];
      zeroCount[j]=0;
      oneStart[j] = zeroStart[j]+n;
      n=oneCount[j];
      oneCount[j]=0;
      zeroStart[j+1] = oneStart[j]+n;
    }
    for (iClique=0;iClique<numberCliques;iClique++) {
      for (int j=cliqueStart[iClique];j<cliqueStart[iClique+1];j++) {
	int iColumn = static_cast<int> (sequenceInCliqueEntry(entry[j]));
	if (oneFixesInCliqueEntry(entry[j])) {
	  int k=oneCount[iColumn];
	  oneCount[iColumn]++;
	  int put = oneStart[iColumn]+k;
	  whichClique[put]=iClique;
	} else {
	  int k=zeroCount[iColumn];
	  zeroCount[iColumn]++;
	  int put = zeroStart[iColumn]+k;
	  whichClique[put]=iClique;
	}
      }
    }
    nStrengthen=0;
    int numberEntries=cliqueStart[numberCliques];
    int maximumEntries=numberEntries;
    int maximumCliques=numberCliques;
    for (iColumn=0;iColumn<numberIntegers_;iColumn++) {
      int i;
      int n;
      int nCount=0;
      n=0;
      for (i=zeroStart[iColumn];i<oneStart[iColumn];i++) {
	int jClique = whichClique[i];
	//if (jClique<numberMatrixCliques) 
	//continue;
	int j = cliqueStart[jClique];
	//assert (cliqueStart[jClique+1]==j+2);
	for (;j<cliqueStart[jClique+1];j++) {
	  CliqueEntry eJ = entry[j];
	  int jColumn = sequenceInCliqueEntry(eJ);
	  if (jColumn>iColumn&&!mark[jColumn]) {
	    mark[jColumn]=1;
	    whichP[n++]=jColumn;
	    assert (n<numberIntegers_);
	    if (oneFixesInCliqueEntry(eJ)) {
	      for (int k=oneStart[jColumn];k<zeroStart[jColumn+1];k++) {
		int jClique = whichClique[k];
		if (!count[jClique]) 
		  whichCount[nCount++]=jClique;
		count[jClique]++;
	      }
	    } else {
	      for (int k=zeroStart[jColumn];k<oneStart[jColumn];k++) {
		int jClique = whichClique[k];
		if (!count[jClique]) 
		  whichCount[nCount++]=jClique;
		count[jClique]++;
	      }
	    }
	  }
	}
      }
      std::sort(whichP,whichP+n);
      for (i=0;i<nCount;i++) {
	int jClique = whichCount[i];
	int jCount = count[jClique];
	count[jClique]=0;
	if (jCount==cliqueStart[jClique+1]-cliqueStart[jClique]) {
	  printf("Zero can extend %d [ ",jClique);
	  for (int i=cliqueStart[jClique];i<cliqueStart[jClique+1];i++)
	    printf("%d(%d) ",sequenceInCliqueEntry(entry[i]),oneFixesInCliqueEntry(entry[i]));
	  printf("] by %d(0)\n",iColumn);
	  nStrengthen++;
	  if (numberEntries+jCount+1>maximumEntries) {
	    maximumEntries = CoinMax(numberEntries+jCount+1,(maximumEntries*12)/10+100);
	    CliqueEntry * temp = new CliqueEntry [maximumEntries];
	    memcpy(temp,entry,numberEntries*sizeof(CliqueEntry));
	    delete [] entry;
	    entry=temp;
	    int * tempI = new int [maximumEntries];
	    memcpy(tempI,whichClique,numberEntries*sizeof(int));
	    delete [] whichClique;
	    whichClique=tempI;
	  }
	  if (numberCliques==maximumCliques) {
	    maximumCliques = (maximumCliques*12)/10+100;
	    int * temp = new int [maximumCliques+1];
	    memcpy(temp,cliqueStart,(numberCliques+1)*sizeof(int));
	    delete [] cliqueStart;
	    cliqueStart=temp;
	    char * tempT = new char [maximumCliques];
	    memcpy(tempT,cliqueType,numberCliques);
	    delete [] cliqueType;
	    cliqueType=tempT;
	  }
	  CliqueEntry eI;
	  eI.fixes=0;
	  setSequenceInCliqueEntry(eI,iColumn);
	  setOneFixesInCliqueEntry(eI,false);
	  entry[numberEntries++]=eI;
	  whichM[0]=iColumn;
	  int n=1;
	  for (int i=cliqueStart[jClique];i<cliqueStart[jClique+1];i++) {
	    entry[numberEntries++]=entry[i];
	    whichM[n++]=sequenceInCliqueEntry(entry[i]);
	  }
	  CoinSort_2(whichM,whichM+n,(reinterpret_cast<int *>(entry))+numberEntries-n);
	  cliqueType[numberCliques]='S';
	  numberCliques++;
	  cliqueStart[numberCliques]=numberEntries;
	}
      }
      for (i=0;i<n;i++)
	mark[whichP[i]]=0;
      nCount=0;
      n=0;
      for (i=oneStart[iColumn];i<zeroStart[iColumn+1];i++) {
	int jClique = whichClique[i];
	//if (jClique<numberMatrixCliques) 
	//continue;
	int j = cliqueStart[jClique];
	//assert (cliqueStart[jClique+1]==j+2);
	for (;j<cliqueStart[jClique+1];j++) {
	  CliqueEntry eJ = entry[j];
	  int jColumn = sequenceInCliqueEntry(eJ);
	  if (jColumn>iColumn&&!mark[jColumn]) {
	    mark[jColumn]=1;
	    whichP[n++]=jColumn;
	    assert (n<numberIntegers_);
	    if (oneFixesInCliqueEntry(eJ)) {
	      for (int k=oneStart[jColumn];k<zeroStart[jColumn+1];k++) {
		int jClique = whichClique[k];
		if (!count[jClique]) 
		  whichCount[nCount++]=jClique;
		count[jClique]++;
	      }
	    } else {
	      for (int k=zeroStart[jColumn];k<oneStart[jColumn];k++) {
		int jClique = whichClique[k];
		if (!count[jClique]) 
		  whichCount[nCount++]=jClique;
		count[jClique]++;
	      }
	    }
	  }
	}
      }
      std::sort(whichP,whichP+n);
      for (i=0;i<nCount;i++) {
	int jClique = whichCount[i];
	int jCount = count[jClique];
	count[jClique]=0;
	if (jCount==cliqueStart[jClique+1]-cliqueStart[jClique]) {
#if 1
		if (printit) {
	    printf("One can extend %d [ ",jClique);
	    for (int i=cliqueStart[jClique];i<cliqueStart[jClique+1];i++)
	      printf("%d(%d) ",sequenceInCliqueEntry(entry[i]),oneFixesInCliqueEntry(entry[i]));
	    printf("] by %d(1)\n",iColumn);
	  }
#endif
	  nStrengthen++;
	  if (numberEntries+jCount+1>maximumEntries) {
	    maximumEntries = CoinMax(numberEntries+jCount+1,(maximumEntries*12)/10+100);
	    CliqueEntry * temp = new CliqueEntry [maximumEntries];
	    memcpy(temp,entry,numberEntries*sizeof(CliqueEntry));
	    delete [] entry;
	    entry=temp;
	    int * tempI = new int [maximumEntries];
	    memcpy(tempI,whichClique,numberEntries*sizeof(int));
	    delete [] whichClique;
	    whichClique=tempI;
	  }
	  if (numberCliques==maximumCliques) {
	    maximumCliques = (maximumCliques*12)/10+100;
	    int * temp = new int [maximumCliques+1];
	    memcpy(temp,cliqueStart,(numberCliques+1)*sizeof(int));
	    delete [] cliqueStart;
	    cliqueStart=temp;
	    char * tempT = new char [maximumCliques];
	    memcpy(tempT,cliqueType,numberCliques);
	    delete [] cliqueType;
	    cliqueType=tempT;
	  }
	  CliqueEntry eI;
	  eI.fixes=0;
	  setSequenceInCliqueEntry(eI,iColumn);
	  setOneFixesInCliqueEntry(eI,true);
	  entry[numberEntries++]=eI;
	  whichM[0]=iColumn;
	  int n=1;
	  for (int i=cliqueStart[jClique];i<cliqueStart[jClique+1];i++) {
	    entry[numberEntries++]=entry[i];
	    whichM[n++]=sequenceInCliqueEntry(entry[i]);
	  }
	  CoinSort_2(whichM,whichM+n,(reinterpret_cast<int *>(entry))+numberEntries-n);
	  cliqueType[numberCliques]='S';
	  numberCliques++;
	  cliqueStart[numberCliques]=numberEntries;
	}
      }
      for (i=0;i<n;i++)
	mark[whichP[i]]=0;
    }
    if (nStrengthen) {
      int numberDeleted = outDupsEtc(numberIntegers_, numberCliques, numberMatrixCliques,
		 cliqueStart, cliqueType, entry, numberLastTime,printit ? 2 : 1);
      if (numberDeleted<0||(iPass>1&&numberCliques-numberDeleted>5000))
	nStrengthen=0;
    }
    delete [] count;
    delete [] whichCount;
  }
#if 0
  if (numberCliques>numberMatrixCliques) {
    // should keep as cliques and also use in branching ??
    double * element = new double [numberIntegers_];
    for (iClique=numberMatrixCliques;iClique<numberCliques;iClique++) {
      int n=0;
      double rhs=1.0;
      for (int i=cliqueStart[iClique];i<cliqueStart[iClique+1];i++) {
	CliqueEntry eI=entry[i];
	int iColumn = integerVariable_[sequenceInCliqueEntry(eI)];
	whichP[n]=iColumn;
	if (oneFixesInCliqueEntry(eI)) {
	  element[n++]=1.0;
	} else {
	  element[n++]=-1.0;
	  rhs -= 1.0;
	}
      }
      stored->addCut(-COIN_DBL_MAX,rhs,n,whichP,element);
    } 
    delete [] element;
  }
#endif
  OsiSolverInterface * newSolver=NULL; 
  if (numberCliques>numberMatrixCliques||alwaysDo) {
    newSolver = si.clone();
    // Delete all rows
    int * start = new int [ CoinMax(numberRows,numberCliques+1)];
    int i;
    for (i=0;i<numberRows;i++)
      start[i]=i;
    newSolver->deleteRows(numberRows,start);
    start[0]=0;
    int numberElements = cliqueStart[numberCliques];
    int * column = new int [numberElements];
    double * element = new double [numberElements];
    double * lower = new double [numberCliques];
    double * upper = new double [numberCliques];
    numberElements=0;
    for (iClique=0;iClique<numberCliques;iClique++) {
      double rhs=1.0;
      for (int i=cliqueStart[iClique];i<cliqueStart[iClique+1];i++) {
	CliqueEntry eI=entry[i];
	int iColumn = integerVariable_[sequenceInCliqueEntry(eI)];
	column[numberElements]=iColumn;
	if (oneFixesInCliqueEntry(eI)) {
	  element[numberElements++]=1.0;
	} else {
	  element[numberElements++]=-1.0;
	  rhs -= 1.0;
	}
      }
      start[iClique+1]=numberElements;
      assert (cliqueType[iClique]=='S'||
	      cliqueType[iClique]=='E');
      if (cliqueType[iClique]=='S')
	lower[iClique]=-COIN_DBL_MAX;
      else
	lower[iClique] = rhs;
      upper[iClique]=rhs;
    }
    newSolver->addRows(numberCliques,start,column,element,lower,upper);
    delete [] start;
    delete [] column;
    delete [] element;
    delete [] lower;
    delete [] upper;
  }
  delete [] mark;
  delete [] whichP;
  delete [] whichM;
  delete [] cliqueStart;
  delete [] entry;
  delete [] cliqueType;
  delete [] zeroStart;
  delete [] oneStart;
  delete [] zeroCount;
  delete [] oneCount;
  delete [] whichClique;
  return newSolver;
}
// Converts to ordered and takes out duplicates
void 
CglTreeProbingInfo::convert()
{
  if (numberEntries_>=0) {
    CoinSort_2( fixingEntry_, fixingEntry_+numberEntries_, fixEntry_);
    assert (!toZero_);
    toZero_ = new int [numberIntegers_+1];
    toOne_ = new int [numberIntegers_];
    toZero_[0]=0;
    int n=0;
    int put=0;
    for (int intVariable = 0;intVariable<numberIntegers_;intVariable++) {
      int last = n;
      for (;n<numberEntries_;n++) {
	int value = fixingEntry_[n];
	int iVar = value>>1;
	int way = value &1;
	if (intVariable!=iVar||way)
	  break;
      }
      if (n>last) {
	// sort
	assert (sizeof(int)==4);
	std::sort(reinterpret_cast<unsigned int *> (fixEntry_)+last,
		  reinterpret_cast<unsigned int *> (fixEntry_)+n);
	CliqueEntry temp2;
	temp2.fixes=0;
	setSequenceInCliqueEntry(temp2,numberVariables_+1);
	for (int i=last;i<n;i++) {
	  if (sequenceInCliqueEntry(temp2)!=sequenceInCliqueEntry(fixEntry_[i])||oneFixesInCliqueEntry(temp2)||oneFixesInCliqueEntry(fixEntry_[i])) {
	    temp2 = fixEntry_[i];
	    fixEntry_[put++]=temp2;
	  }
	}
      }
      toOne_[intVariable]=put;
      last = n;
      for (;n<numberEntries_;n++) {
	int value = fixingEntry_[n];
	int iVar = value>>1;
	if (intVariable!=iVar)
	  break;
      }
      if (n>last) {
	// sort
	assert (sizeof(int)==4);
	std::sort(reinterpret_cast<unsigned int *> (fixEntry_)+last,
		  reinterpret_cast<unsigned int *> (fixEntry_)+n);
	CliqueEntry temp2;
	temp2.fixes=0;
	setSequenceInCliqueEntry(temp2,numberVariables_+1);
	for (int i=last;i<n;i++) {
	  if (sequenceInCliqueEntry(temp2)!=sequenceInCliqueEntry(fixEntry_[i])||oneFixesInCliqueEntry(temp2)||oneFixesInCliqueEntry(fixEntry_[i])) {
	    temp2 = fixEntry_[i];
	    fixEntry_[put++]=temp2;
	  }
	}
	last=n;
      }
      toZero_[intVariable+1]=put;
    }
    delete [] fixingEntry_;
    fixingEntry_ = NULL;
    numberEntries_ = -2;
  }