rowgraph_weighted_def.h
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program */
4 /* GCG --- Generic Column Generation */
5 /* a Dantzig-Wolfe decomposition based extension */
6 /* of the branch-cut-and-price framework */
7 /* SCIP --- Solving Constraint Integer Programs */
8 /* */
9 /* Copyright (C) 2010-2018 Operations Research, RWTH Aachen University */
10 /* Zuse Institute Berlin (ZIB) */
11 /* */
12 /* This program is free software; you can redistribute it and/or */
13 /* modify it under the terms of the GNU Lesser General Public License */
14 /* as published by the Free Software Foundation; either version 3 */
15 /* of the License, or (at your option) any later version. */
16 /* */
17 /* This program is distributed in the hope that it will be useful, */
18 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
19 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
20 /* GNU Lesser General Public License for more details. */
21 /* */
22 /* You should have received a copy of the GNU Lesser General Public License */
23 /* along with this program; if not, write to the Free Software */
24 /* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.*/
25 /* */
26 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
27 
34 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
35 // #define SCIP_DEBUG
36 
37 #ifndef GCG_ROWGRAPH_WEIGHTED_DEF_H_
38 #define GCG_ROWGRAPH_WEIGHTED_DEF_H_
39 
40 #include "rowgraph_weighted.h"
41 #include "graph_gcg.h"
42 #include "graphalgorithms.h"
43 #include "priority_graph.h"
44 #include <algorithm>
45 #include <iostream>
46 #include <vector>
47 #include <map>
48 #include <set>
49 #include <climits>
50 #include <queue>
51 
52 using namespace std;
53 
54 namespace gcg {
55 
56 template <class T>
58  SCIP* scip,
59  Weights w
60  ) : RowGraph<T>(scip,w)
61 {
62  this->name = string("rowgraph_weighted");
63  n_blocks = -1;
64  non_cl = INT_MAX;
65 }
66 
67 template <class T>
69 {
70  // Auto-generated destructor stub
71 }
72 
73 
74 template <class T>
76  SCIP_CONS** conss,
77  SCIP_VAR** vars,
78  int nconss_,
79  int nvars_,
80  DISTANCE_MEASURE dist,
81  WEIGHT_TYPE w_type
82  )
83 {
84  int i;
85  int j;
86  int k;
87  int l;
88  SCIP_Bool success;
89 
90  assert(conss != NULL);
91  assert(vars != NULL);
92  assert(nvars_ > 0);
93  assert(nconss_ > 0);
94 
95  this->nvars = nvars_;
96  this->nconss = nconss_;
97 
98  SCIP_CALL( this->graph.addNNodes(this->nconss) );
99 
100  /* go through all constraints */
101  for( i = 0; i < this->nconss; ++i )
102  {
103  SCIP_VAR **curvars1;
104 
105  int ncurvars1;
106  SCIP_CALL( SCIPgetConsNVars(this->scip_, conss[i], &ncurvars1, &success) );
107  assert(success);
108  if( ncurvars1 == 0 )
109  continue;
110 
111  /*
112  * may work as is, as we are copying the constraint later regardless
113  * if there are variables in it or not
114  */
115  SCIP_CALL( SCIPallocBufferArray(this->scip_, &curvars1, ncurvars1) );
116  SCIP_CALL( SCIPgetConsVars(this->scip_, conss[i], curvars1, ncurvars1, &success) );
117  assert(success);
118 
119  /* go through all constraints again */
120  for( j = 0; j < i; ++j )
121  {
122  SCIP_VAR **curvars2;
123  int ncurvars2;
124  SCIP_CALL( SCIPgetConsNVars(this->scip_, conss[j], &ncurvars2, &success) );
125  assert(success);
126  if( ncurvars2 == 0 )
127  continue;
128 
129 
130  /*
131  * may work as is, as we are copying the constraint later regardless
132  * if there are variables in it or not
133  */
134  SCIP_CALL( SCIPallocBufferArray(this->scip_, &curvars2, ncurvars2) );
135  SCIP_CALL( SCIPgetConsVars(this->scip_, conss[j], curvars2, ncurvars2, &success) );
136  assert(success);
137 
138 
142  int a = 0; // number of common variables
143  int b = 0; // number of variables that appear ONLY in the second row
144  int c = 0; // number of variables that appear ONLY in the first row
145  for( k = 0; k < ncurvars1; ++k )
146  {
147  SCIP_VAR* var1;
148  int varIndex1;
149 
150  if( !GCGisVarRelevant(curvars1[k]) )
151  continue;
152 
153  if( SCIPgetStage(this->scip_) >= SCIP_STAGE_TRANSFORMED)
154  var1 = SCIPvarGetProbvar(curvars1[k]);
155  else
156  var1 = curvars1[k];
157 
158  assert(var1 != NULL);
159  varIndex1 = SCIPvarGetProbindex(var1);
160  assert(varIndex1 >= 0);
161  assert(varIndex1 < this->nvars);
162 
163  for( l = 0; l < ncurvars2; ++l )
164  {
165  SCIP_VAR* var2;
166  int varIndex2;
167 
168  if( !GCGisVarRelevant(curvars2[l]) )
169  continue;
170 
171  if( SCIPgetStage(this->scip_) >= SCIP_STAGE_TRANSFORMED)
172  var2 = SCIPvarGetProbvar(curvars2[l]);
173  else
174  var2 = curvars2[l];
175 
176  assert(var2 != NULL);
177  varIndex2 = SCIPvarGetProbindex(var2);
178  assert(varIndex2 >= 0);
179  assert(varIndex2 < this->nvars);
180 
181  if(varIndex1 == varIndex2)
182  {
183  a++;
184  break; // stop comparing the variable from the 1st const. with the rest of vars. in the 2nd const.
185  }
186  }
187  }
188  b = ncurvars2 - a;
189  c = ncurvars1 - a;
190  assert(a >= 0); // number of common var
191  assert(b >= 0); // number of variables in the second conss
192  assert(c >= 0); // number of variables in the first conss
193  if(a != 0){
194  double edge_weight = calculateSimilarity(a, b, c, dist, w_type, i==j);
195  this->graph.addEdge(i, j, edge_weight);
196  }
197 
198  SCIPfreeBufferArray(this->scip_, &curvars2);
199  }
200  SCIPfreeBufferArray(this->scip_, &curvars1);
201  }
202 
203  if(dist == INTERSECTION)
204  {
205  this->graph.normalize();
206  if(w_type == DIST)
207  {
208  return SCIP_INVALIDCALL;
209  }
210  }
211 
212  SCIP_CALL( this->graph.flush() );
213 
214  assert(this->graph.getNNodes() == nconss_);
215 
216  return SCIP_OKAY;
217 }
218 
219 template <class T>
221  Seeedpool* seeedpool,
222  Seeed* seeed,
223  DISTANCE_MEASURE dist,
224  WEIGHT_TYPE w_type
225  )
226 {
227 
228  int i;
229  int j;
230  int k;
231  int l;
232  int m;
233  vector<int> conssForGraph;
234  vector<int> varsForGraph;
235  vector<bool> varsBool(seeed->getNVars(), false);
236  vector<bool> conssBool(seeed->getNConss(), false);
237  unordered_map<int, int> oldToNewConsIndex;
238  unordered_map<int, int> oldToNewVarIndex;
240  for(int c = 0; c < seeed->getNOpenconss(); ++c)
241  {
242  int cons = seeed->getOpenconss()[c];
243  for(int v = 0; v < seeed->getNOpenvars(); ++v)
244  {
245  int var = seeed->getOpenvars()[v];
246  for(i = 0; i < seeedpool->getNVarsForCons(cons); ++i)
247  {
248  if(var == seeedpool->getVarsForCons(cons)[i])
249  {
250  varsBool[var] = true;
251  conssBool[cons] = true;
252  }
253  }
254  }
255  }
256 
257  for(int v = 0; v < seeed->getNOpenvars(); ++v)
258  {
259  int var = seeed->getOpenvars()[v];
260  if(varsBool[var])
261  varsForGraph.push_back(var);
262  }
263  for(int c = 0; c < seeed->getNOpenconss(); ++c)
264  {
265  int cons = seeed->getOpenconss()[c];
266  if(conssBool[cons])
267  conssForGraph.push_back(cons);
268  }
269 
270  this->nvars = (int)varsForGraph.size();
271  this->nconss = (int)conssForGraph.size();
272  assert(this->nconss > 0);
273  assert(this->nvars > 0);
274 
275  for(int v = 0; v < (int)varsForGraph.size(); ++v)
276  {
277  int oldVarId = varsForGraph[v];
278  oldToNewVarIndex.insert({oldVarId,v});
279  }
280  for(int c = 0; c < (int)conssForGraph.size(); ++c)
281  {
282  int oldConsId = conssForGraph[c];
283  oldToNewConsIndex.insert({oldConsId,c});
284  }
285 
286 
287 
288  SCIP_CALL( this->graph.addNNodes(this->nconss) );
289 
290  /* go through all constraints */
291  for( i = 0; i < this->nconss; ++i )
292  {
293  int cons1 = conssForGraph[i];
294  assert(conssBool[cons1]);
295 
296  /* go through all constraints again */
297  for( j = 0; j < i; ++j )
298  {
299  int cons2 = conssForGraph[j];
300 
301  int a = 0; // number of common variables
302  int b = 0; // number of variables that appear ONLY in the second row
303  int c = 0; // number of variables that appear ONLY in the first row
304 
305 
306  for( k = 0; k < seeedpool->getNVarsForCons(cons1); ++k)
307  {
308  int var1 = seeedpool->getVarsForCons(cons1)[k];
309  if(!varsBool[var1])
310  continue;
311  assert(varsBool[var1]);
312 
313  for(l = 0; l < seeedpool->getNVarsForCons(cons2); ++l)
314  {
315  int var2 = seeedpool->getVarsForCons(cons2)[l];
316  if(!varsBool[var2])
317  continue;
318 
319  if(var1 == var2)
320  {
321  a++;
322  break; // stop comparing the variable from the 1st const. with the rest of vars. in the 2nd const.
323  }
324  }
325  for(m = 0; m < seeedpool->getNVarsForCons(cons2); ++m)
326  {
327  int var = seeedpool->getVarsForCons(cons2)[m];
328  if(varsBool[var])
329  b++;
330  }
331  b = b - a;
332 
333  for(m = 0; m < seeedpool->getNVarsForCons(cons1); ++m)
334  {
335  int var = seeedpool->getVarsForCons(cons1)[m];
336  if(varsBool[var])
337  c++;
338  }
339  c = c - a;
340 
341  assert(a >= 0); // number of common var
342  assert(b >= 0); // number of variables in the second conss
343  assert(c >= 0); // number of variables in the first conss
344  if(a != 0){
345  double edge_weight = calculateSimilarity(a, b, c, dist, w_type, i==j);
346  this->graph.addEdge(oldToNewConsIndex[cons1], oldToNewConsIndex[cons2], edge_weight);
347  }
348  }
349  }
350  }
351 
352  if(dist == INTERSECTION)
353  {
354  this->graph.normalize();
355  if(w_type == DIST)
356  {
357  return SCIP_INVALIDCALL;
358  }
359  }
360 
361  SCIP_CALL( this->graph.flush() );
362 
363  return SCIP_OKAY;
364 }
365 
366 template <class T>
367 double RowGraphWeighted<T>::calculateSimilarity(int _a, int _b, int _c, DISTANCE_MEASURE dist, WEIGHT_TYPE w_type, bool itself)
368 {
369  if(w_type == DIST )
370  {
371  if(_c == 0 && _b == 0) return 1e-10;
372  }
373  else
374  {
375  if(_c == 0 && _b == 0) return (1.0 - 1e-10);
376  }
377  double result = 0.0;
378  double a = (double)_a;
379  double b = (double)_b;
380  double c = (double)_c;
381  switch( dist ) {
382  case JOHNSON:
383  result = (a/(a+b) + a/(a+c)) / 2.0;
384  break;
385  case INTERSECTION:
386  result = a;
387  break;
388  case JACCARD:
389  result = a / (a+b+c);
390  break;
391  case COSINE:
392  result = a / (sqrt(a+b)*sqrt(a+c));
393  break;
394  case SIMPSON:
395  result = a / MIN(a+b, a+c);
396  break;
397  }
398 
399 
400 
401  if(dist != INTERSECTION)
402  {
403  assert(result >= 0.0);
404  assert(result <= 1.0);
405  }
406 
407  if(!itself)
408  {
409  result *= (1 - 1e-10);
410  }
411 
412  if(w_type == DIST && dist != INTERSECTION)
413  {
414  result = 1.0 - result;
415  }
416 
417  return result;
418 }
419 
420 template <>
421 SCIP_RETCODE RowGraphWeighted<GraphGCG>::postProcess(vector<int>& labels, bool enabled)
422 {
423  assert((int)labels.size() == graph.getNNodes());
424  set<int> diff_blocks_beginning;
425  for(auto curr_int = labels.begin(), end = labels.end(); curr_int != end; ++curr_int)
426  {
427  diff_blocks_beginning.insert(*curr_int);
428  }
429  //std::cout << "diff_blocks_beginning: " << diff_blocks_beginning.size() << std::endl;
430  bool skip_me = false;
431  if(diff_blocks_beginning.size() == labels.size())
432  {
433  skip_me = true;
434  }
435  // If the post processing is enabled, remove the coliding conss, otherwise just set the partition
436  if(enabled && !skip_me)
437  {
438  this->non_cl = (int)labels.size();
439  // for each column in the conss matrix we save labels of all the constraints where the variable appears
440  vector< vector<int> > all_labels_in_col(this->nvars);
441 
442  // for each column in the conss matrix we count the number of occurrences of each label
443  vector< map<int, int> > all_label_occ_in_col(this->nvars);
444 
445  // item i saves number which appears most often in the all_labels_in_col[i]
446  vector<int> col_labels(this->nvars, -1);
447 
448  SCIP_CONS** conss = SCIPgetConss(this->scip_);
449  SCIP_Bool success;
450 
451  // For each var save the labels of all the constraints where this var appears.
452  for(auto i = 0; i < this->nconss; i++)
453  {
454  SCIP_VAR **curvars;
455  int ncurvars;
456  SCIP_CALL( SCIPgetConsNVars(this->scip_, conss[i], &ncurvars, &success) );
457  assert(success);
458  if( ncurvars == 0 )
459  continue;
460 
461  /*
462  * may work as is, as we are copying the constraint later regardless
463  * if there are variables in it or not
464  */
465  SCIP_CALL( SCIPallocBufferArray(this->scip_, &curvars, ncurvars) );
466  SCIP_CALL( SCIPgetConsVars(this->scip_, conss[i], curvars, ncurvars, &success) );
467  assert(success);
468 
469  for(auto j = 0; j < ncurvars; j++)
470  {
471  SCIP_VAR* var;
472 
473  if( !GCGisVarRelevant(curvars[j]) )
474  continue;
475 
476  if( SCIPgetStage(this->scip_) >= SCIP_STAGE_TRANSFORMED)
477  var = SCIPvarGetProbvar(curvars[j]);
478  else
479  var = curvars[j];
480 
481  assert(var != NULL);
482  int varIndex = SCIPvarGetProbindex(var);
483  assert(varIndex >= 0);
484  assert(varIndex < this->nvars);
485 
486  // push the label of the constraint to the columns where the variable appears
487  all_labels_in_col[varIndex].push_back(labels[i]);
488  all_label_occ_in_col[varIndex][labels[i]]++;
489  }
490  SCIPfreeBufferArray(this->scip_, &curvars);
491  }
492 
493  // fill the col_labels
494  for(auto i = 0; i < this->nvars; i++)
495  {
496  /*int max = 0;
497  int most_common = -1;
498  map<int,int> m;
499  for (auto vi = all_labels_in_col[i].begin(); vi != all_labels_in_col[i].end(); vi++)
500  {
501  m[*vi]++;
502  if (m[*vi] > max)
503  {
504  max = m[*vi];
505  most_common = *vi;
506  }
507  }*/
508  //using pair_type = decltype(all_label_occ_in_col[i])::value_type;
509  auto pr = max_element
510  (
511  all_label_occ_in_col[i].begin(), all_label_occ_in_col[i].end(),
512  [] (const pair<int,int> & p1, const pair<int,int> & p2) {
513  return p1.second < p2.second;
514  }
515  );
516  // new code
517  //col_labels[i] = most_common;
518  col_labels[i] = pr->first;
519  //assert(most_common == pr->first);
520  }
521 
522 
523  // Iterate all the conss and remove them (i.e. set label to -1) if necessary
524  for(auto i = 0; i < this->nconss; i++)
525  {
526  SCIP_VAR **curvars1;
527  int ncurvars1;
528  SCIP_CALL( SCIPgetConsNVars(this->scip_, conss[i], &ncurvars1, &success) );
529  assert(success);
530  if( ncurvars1 == 0 )
531  continue;
532 
533  /*
534  * may work as is, as we are copying the constraint later regardless
535  * if there are variables in it or not
536  */
537  SCIP_CALL( SCIPallocBufferArray(this->scip_, &curvars1, ncurvars1) );
538  SCIP_CALL( SCIPgetConsVars(this->scip_, conss[i], curvars1, ncurvars1, &success) );
539  assert(success);
540 
541  for(auto j = 0; j < ncurvars1; j++)
542  {
543  SCIP_VAR* var1;
544 
545  if( !GCGisVarRelevant(curvars1[j]) )
546  continue;
547 
548  if( SCIPgetStage(this->scip_) >= SCIP_STAGE_TRANSFORMED)
549  var1 = SCIPvarGetProbvar(curvars1[j]);
550  else
551  var1 = curvars1[j];
552 
553  assert(var1 != NULL);
554  int varIndex = SCIPvarGetProbindex(var1);//curvars1[j]);
555  assert(varIndex >= 0);
556  assert(varIndex < this->nvars);
557 
558  // Check if in a conss we have found a var with different label than the conss label.
559  // This means that this var is mostly belonging to some other block, so remove it
560  if(col_labels[varIndex] != labels[i])
561  {
562  labels[i] = -1;
563 
564  // this is new part
565  // it updates the column labels each time after eliminating some conss
566  all_label_occ_in_col[varIndex][labels[i]]--;
567  auto pr = max_element
568  (
569  all_label_occ_in_col[varIndex].begin(), all_label_occ_in_col[varIndex].end(),
570  [] (const pair<int,int> & p1, const pair<int,int> & p2) {
571  return p1.second < p2.second;
572  }
573  );
574  col_labels[varIndex] = pr->first;
575  }
576  }
577  SCIPfreeBufferArray(this->scip_, &curvars1);
578 
579  }
580  }
581 
582  if(!skip_me)
583  {
584  // Fix the labeling so that it starts from 0 without skipping the enumeration order
585  // And set the graph partition accordingly.
586  set<int> diff_blocks;
587 
588  for(auto curr_int = labels.begin(), end = labels.end(); curr_int != end; ++curr_int)
589  {
590  diff_blocks.insert(*curr_int);
591  }
592 
593  const int non_cl_pts = count(labels.begin(), labels.end(), -1);
594  if(non_cl_pts > 0)
595  {
596  this->n_blocks = diff_blocks.size() - 1;
597  }
598  else
599  {
600  this->n_blocks = diff_blocks.size();
601  }
602  this->non_cl = non_cl_pts;
603 
604  map<int,int> labels_fix;
605  int new_label;
606  if(this->non_cl > 0) new_label = -1;
607  else new_label = 0;
608 
609  for(int old_label: diff_blocks)
610  {
611  labels_fix[old_label] = new_label;
612  new_label++;
613  }
614  for(int i = 0; i < (int)labels.size(); i++)
615  {
616  labels[i] = labels_fix[labels[i]];
617  }
618  }
619 
620  // put the labels as the partition...
621  for(int i = 0; i < (int)labels.size(); i++)
622  {
623  this->graph.setPartition(i, labels[i]);
624  }
625  return SCIP_OKAY;
626 }
627 
628 template <>
629 SCIP_RETCODE RowGraphWeighted<GraphGCG>::postProcessForPartialGraph(gcg::Seeedpool* seeedpool, gcg::Seeed* seeed, vector<int>& labels, bool enabled)
630 {
631  assert((int)labels.size() == graph.getNNodes());
632  set<int> diff_blocks_beginning;
633  for(auto curr_int = labels.begin(), end = labels.end(); curr_int != end; ++curr_int)
634  {
635  diff_blocks_beginning.insert(*curr_int);
636  }
637  //std::cout << "diff_blocks_beginning: " << diff_blocks_beginning.size() << std::endl;
638  bool skip_me = false;
639  if(diff_blocks_beginning.size() == labels.size())
640  {
641  skip_me = true;
642  }
643  // If the post processing is enabled, remove the coliding conss, otherwise just set the partition
644  if(enabled && !skip_me)
645  {
646  //fillout conssForGraph and varsForGraph
647  vector<int> conssForGraph;
648  vector<int> varsForGraph;
649  vector<bool> varsBool(seeed->getNVars(), false);
650  vector<bool> conssBool(seeed->getNConss(), false);
651  unordered_map<int, int> oldToNewConsIndex;
652  unordered_map<int, int> oldToNewVarIndex;
654  for(int c = 0; c < seeed->getNOpenconss(); ++c)
655  {
656  int cons = seeed->getOpenconss()[c];
657  for(int v = 0; v < seeed->getNOpenvars(); ++v)
658  {
659  int var = seeed->getOpenvars()[v];
660  for(int i = 0; i < seeedpool->getNVarsForCons(cons); ++i)
661  {
662  if(var == seeedpool->getVarsForCons(cons)[i])
663  {
664  varsBool[var] = true;
665  conssBool[cons] = true;
666  }
667  }
668  }
669  }
670 
671  for(int v = 0; v < seeed->getNOpenvars(); ++v)
672  {
673  int var = seeed->getOpenvars()[v];
674  if(varsBool[var] == true)
675  varsForGraph.push_back(var);
676  }
677  for(int c = 0; c < seeed->getNOpenconss(); ++c)
678  {
679  int cons = seeed->getOpenconss()[c];
680  if(conssBool[cons] == true)
681  conssForGraph.push_back(cons);
682  }
683 
684  assert(this->nvars == (int) varsForGraph.size());
685  assert(this->nconss == (int) conssForGraph.size());
686 
687  sort(conssForGraph.begin(), conssForGraph.end());
688  sort(varsForGraph.begin(), varsForGraph.end());
689 
690  //fillout oldToNewVarIndex and oldToNewConsIndex
691  for(int v = 0; v < this->nvars; ++v)
692  {
693  int oldVarId = varsForGraph[v];
694  oldToNewVarIndex.insert({oldVarId,v});
695  }
696 
697  for(int c = 0; c < this->nconss; ++c)
698  {
699  int oldConsId = conssForGraph[c];
700  oldToNewConsIndex.insert({oldConsId,c});
701  }
702 
703  this->non_cl = (int)labels.size();
704  // for each column in the conss matrix we save labels of all the constraints where the variable appears
705  vector< vector<int> > all_labels_in_col(this->nvars);
706 
707  // for each column in the conss matrix we count the number of occurrences of each label
708  vector< map<int, int> > all_label_occ_in_col(this->nvars);
709 
710  // item i saves number which appears most often in the all_labels_in_col[i]
711  vector<int> col_labels(this->nvars, -1);
712 
713 
714  // For each var save the labels of all the constraints where this var appears.
715  for(size_t c = 0; c < conssForGraph.size(); c++)
716  {
717  int cons = conssForGraph[c];
718  int consIndex = oldToNewConsIndex[cons];
719  assert(consIndex >= 0);
720  assert(consIndex < this->nconss);
721  for(int v = 0; v < seeedpool->getNVarsForCons(cons); ++v)
722  {
723  int var = seeedpool->getVarsForCons(cons)[v];
724  if(find(varsForGraph.begin(), varsForGraph.end(), var) == varsForGraph.end())
725  continue;
726  int varIndex = oldToNewVarIndex[var];
727  assert(varIndex >= 0);
728  assert(varIndex < this->nvars);
729  all_labels_in_col[varIndex].push_back(labels[consIndex]);
730  }
731  }
732 
733  // fill the col_labels
734  for(size_t v = 0; v < varsForGraph.size(); ++v)
735  {
736  int var = varsForGraph[v];
737  int varIndex = oldToNewVarIndex[var];
738  assert(varIndex >= 0);
739  assert(varIndex < this->nvars);
740 
741  auto pr = max_element
742  (
743  all_label_occ_in_col[varIndex].begin(), all_label_occ_in_col[varIndex].end(),
744  [] (const pair<int,int> & p1, const pair<int,int> & p2) {
745  return p1.second < p2.second;
746  }
747  );
748  col_labels[varIndex] = pr->first;
749  }
750 
751 
752  // Iterate all the conss and remove them (i.e. set label to -1) if necessary
753  for(size_t c = 0; c < conssForGraph.size(); ++c)
754  {
755  int cons = conssForGraph[c];
756  assert(cons >= 0);
757  int consIndex = oldToNewConsIndex[cons];
758  assert(consIndex >= 0);
759  assert(consIndex < this->nconss);
760  for(int v = 0; v < seeedpool->getNVarsForCons(cons); ++v)
761  {
762  int var = seeedpool->getVarsForCons(cons)[v];
763  if(find(varsForGraph.begin(), varsForGraph.end(), var) == varsForGraph.end())
764  continue;
765  int varIndex = oldToNewVarIndex[var];
766  assert(varIndex >= 0);
767  assert(varIndex < this->nvars);
768  // Check if in a conss we have found a var with different label than the conss label.
769  // This means that this var is mostly belonging to some other block, so remove it
770  if(col_labels[varIndex] != labels[consIndex])
771  {
772  labels.at(consIndex) = -1;
773 
774  // this is new part
775  // it updates the column labels each time after eliminating some conss
776  all_label_occ_in_col[varIndex][labels[consIndex]]--;
777  auto pr = max_element
778  (
779  all_label_occ_in_col[varIndex].begin(), all_label_occ_in_col[varIndex].end(),
780  [] (const pair<int,int> & p1, const pair<int,int> & p2) {
781  return p1.second < p2.second;
782  }
783  );
784  col_labels[varIndex] = pr->first;
785  }
786  }
787  }
788  }
789 
790  if(!skip_me)
791  {
792  // Fix the labeling so that it starts from 0 without skipping the enumeration order
793  // And set the graph partition accordingly.
794  set<int> diff_blocks;
795 
796  for(auto curr_int = labels.begin(), end = labels.end(); curr_int != end; ++curr_int)
797  {
798  diff_blocks.insert(*curr_int);
799  }
800 
801  const int non_cl_pts = count(labels.begin(), labels.end(), -1);
802  if(non_cl_pts > 0)
803  {
804  this->n_blocks = diff_blocks.size() - 1;
805  }
806  else
807  {
808  this->n_blocks = diff_blocks.size();
809  }
810  this->non_cl = non_cl_pts;
811 
812  map<int,int> labels_fix;
813  int new_label;
814  if(this->non_cl > 0) new_label = -1;
815  else new_label = 0;
816 
817  for(int old_label: diff_blocks)
818  {
819  labels_fix[old_label] = new_label;
820  new_label++;
821  }
822  for(int i = 0; i < (int)labels.size(); i++)
823  {
824  labels[i] = labels_fix[labels[i]];
825  }
826  }
827 
828  // put the labels as the partition...
829  for(int i = 0; i < (int)labels.size(); i++)
830  {
831  this->graph.setPartition(i, labels[i]);
832  }
833  return SCIP_OKAY;
834 }
835 
836 
837 // this function is obsolete
838 template <>
839 SCIP_RETCODE RowGraphWeighted<GraphGCG>::postProcessStableSet(vector<int>& labels, bool enabled)
840 {
841  assert((int)labels.size() == graph.getNNodes());
842  set<int> diff_blocks_beginning;
843  for(auto curr_int = labels.begin(), end = labels.end(); curr_int != end; ++curr_int)
844  {
845  diff_blocks_beginning.insert(*curr_int);
846  }
847  bool skip_me = false;
848  if(diff_blocks_beginning.size() == labels.size())
849  {
850  skip_me = true;
851  }
852 
853 
854  // If the post processing is enabled, remove the coliding conss, otherwise just set the partition
855  if(enabled && !skip_me)
856  {
857  priority_graph stable_set_graph;
858  //SCIPverbMessage(this->scip_, SCIP_VERBLEVEL_NORMAL, NULL, " running postProcessStableSet\n");
859  this->non_cl = (int)labels.size();
860  // for each column in the conss matrix we save labels of all the constraints where the variable appears
861  vector< vector<int> > all_ind_in_col(this->nvars);
862 
863 
864  SCIP_CONS** conss = SCIPgetConss(this->scip_);
865  SCIP_Bool success;
866 
867  /* go through all constraints */
868  for(int i = 0; i < this->nconss; ++i )
869  {
870  SCIP_VAR **curvars1;
871 
872  int ncurvars1;
873  SCIP_CALL( SCIPgetConsNVars(this->scip_, conss[i], &ncurvars1, &success) );
874  assert(success);
875  if( ncurvars1 == 0 )
876  continue;
877 
878  /*
879  * may work as is, as we are copying the constraint later regardless
880  * if there are variables in it or not
881  */
882  SCIP_CALL( SCIPallocBufferArray(this->scip_, &curvars1, ncurvars1) );
883  SCIP_CALL( SCIPgetConsVars(this->scip_, conss[i], curvars1, ncurvars1, &success) );
884  assert(success);
885 
886  /* go through all constraints */
887  for(int j = 0; j < i; ++j )
888  {
889  if(labels[i] == labels[j]) continue;
890  SCIP_VAR **curvars2;
891  SCIP_Bool continueloop;
892  int ncurvars2;
893  SCIP_CALL( SCIPgetConsNVars(this->scip_, conss[j], &ncurvars2, &success) );
894  assert(success);
895  if( ncurvars2 == 0 )
896  continue;
897 
898  continueloop = FALSE;
899  /*
900  * may work as is, as we are copying the constraint later regardless
901  * if there are variables in it or not
902  */
903  SCIP_CALL( SCIPallocBufferArray(this->scip_, &curvars2, ncurvars2) );
904  SCIP_CALL( SCIPgetConsVars(this->scip_, conss[j], curvars2, ncurvars2, &success) );
905  assert(success);
906 
907 
911  for(int k = 0; k < ncurvars1; ++k )
912  {
913  SCIP_VAR* var1;
914  int varIndex1;
915 
916  if( !GCGisVarRelevant(curvars1[k]) )
917  continue;
918 
919  if( SCIPgetStage(this->scip_) >= SCIP_STAGE_TRANSFORMED)
920  var1 = SCIPvarGetProbvar(curvars1[k]);
921  else
922  var1 = curvars1[k];
923 
924  assert(var1 != NULL);
925  varIndex1 = SCIPvarGetProbindex(var1);
926  assert(varIndex1 >= 0);
927  assert(varIndex1 < this->nvars);
928 
929  for(int l = 0; l < ncurvars2; ++l )
930  {
931  SCIP_VAR* var2;
932  int varIndex2;
933 
934  if( !GCGisVarRelevant(curvars2[l]) )
935  continue;
936 
937  if( SCIPgetStage(this->scip_) >= SCIP_STAGE_TRANSFORMED)
938  var2 = SCIPvarGetProbvar(curvars2[l]);
939  else
940  var2 = curvars2[l];
941 
942  assert(var2 != NULL);
943  varIndex2 = SCIPvarGetProbindex(var2);
944  assert(varIndex2 >= 0);
945  assert(varIndex2 < this->nvars);
946 
947  if(varIndex1 == varIndex2)
948  {
949  stable_set_graph.addNode(i);
950  stable_set_graph.addNode(j);
951  stable_set_graph.addEdge(i, j);
952 
953  /*
954  * this->graph.flush();
955  */
956 
957  continueloop = TRUE;
958  break;
959  }
960  }
961  if(continueloop)
962  break;
963  }
964  SCIPfreeBufferArray(this->scip_, &curvars2);
965  }
966  SCIPfreeBufferArray(this->scip_, &curvars1);
967  }
968 
969  // run greedy heuristic for stable set
970  vector<int> stable_set;
971  vector<int> no_stable_set;
972  while(!stable_set_graph.empty()){
973  int current = stable_set_graph.top().first;
974  stable_set.push_back(current);
975  set<int> neighbors = stable_set_graph.getNeighbors(current);
976  stable_set_graph.pop();
977  for(auto neighbor : neighbors){
978  stable_set_graph.removeNode(neighbor, no_stable_set);
979  }
980  }
981 
982 
983  // Iterate all the conss and remove them (i.e. set label to -1) if necessary
984  for(int to_remove : no_stable_set)
985  {
986  //SCIPverbMessage(this->scip_, SCIP_VERBLEVEL_NORMAL, NULL, " to_remove: %d \n", to_remove);
987  labels[to_remove] = -1;
988  }
989  }
990 
991 
992  if(!skip_me)
993  {
994  // Fix the labeling so that it starts from 0 without skipping the enumeration order
995  // And set the graph partition accordingly.
996  set<int> diff_blocks;
997  for(auto curr_int = labels.begin(), end = labels.end(); curr_int != end; ++curr_int)
998  {
999  diff_blocks.insert(*curr_int);
1000  }
1001 
1002  const int non_cl_pts = count(labels.begin(), labels.end(), -1);
1003  if(non_cl_pts > 0)
1004  {
1005  this->n_blocks = diff_blocks.size() - 1;
1006  }
1007  else
1008  {
1009  this->n_blocks = diff_blocks.size();
1010  }
1011  this->non_cl = non_cl_pts;
1012 
1013  map<int,int> labels_fix;
1014  int new_label;
1015  if(this->non_cl > 0) new_label = -1;
1016  else new_label = 0;
1017 
1018  for(int old_label: diff_blocks)
1019  {
1020  labels_fix[old_label] = new_label;
1021  new_label++;
1022  }
1023  for(int i = 0; i < (int)labels.size(); i++)
1024  {
1025  labels[i] = labels_fix[labels[i]];
1026  }
1027  }
1028 
1029  // put the labels as the partition...
1030  for(int i = 0; i < (int)labels.size(); i++)
1031  {
1032  this->graph.setPartition(i, labels[i]);
1033  }
1034  return SCIP_OKAY;
1035 }
1036 
1037 // this function is obsolete
1038 template <>
1039 SCIP_RETCODE RowGraphWeighted<GraphGCG>::postProcessStableSetForPartialGraph(gcg::Seeedpool* seeedpool, gcg::Seeed* seeed, vector<int>& labels, bool enabled)
1040 {
1041  assert((int)labels.size() == graph.getNNodes());
1042  set<int> diff_blocks_beginning;
1043  for(auto curr_int = labels.begin(), end = labels.end(); curr_int != end; ++curr_int)
1044  {
1045  diff_blocks_beginning.insert(*curr_int);
1046  }
1047  bool skip_me = false;
1048  if(diff_blocks_beginning.size() == labels.size())
1049  {
1050  skip_me = true;
1051  }
1052 
1053 
1054 
1055  // If the post processing is enabled, remove the coliding conss, otherwise just set the partition
1056  if(enabled && !skip_me)
1057  {
1058  //fillout conssForGraph and varsForGraph
1059  vector<int> conssForGraph;
1060  vector<int> varsForGraph;
1061  vector<bool> varsBool(seeed->getNVars(), false);
1062  vector<bool> conssBool(seeed->getNConss(), false);
1063  unordered_map<int, int> oldToNewConsIndex;
1064  unordered_map<int, int> oldToNewVarIndex;
1066  for(int c = 0; c < seeed->getNOpenconss(); ++c)
1067  {
1068  int cons = seeed->getOpenconss()[c];
1069  for(int v = 0; v < seeed->getNOpenvars(); ++v)
1070  {
1071  int var = seeed->getOpenvars()[v];
1072  for(int i = 0; i < seeedpool->getNVarsForCons(cons); ++i)
1073  {
1074  if(var == seeedpool->getVarsForCons(cons)[i])
1075  {
1076  varsBool[var] = true;
1077  conssBool[cons] = true;
1078  }
1079  }
1080  }
1081  }
1082 
1083  for(int v = 0; v < seeed->getNOpenvars(); ++v)
1084  {
1085  int var = seeed->getOpenvars()[v];
1086  if(varsBool[var] == true)
1087  varsForGraph.push_back(var);
1088  }
1089  for(int c = 0; c < seeed->getNOpenconss(); ++c)
1090  {
1091  int cons = seeed->getOpenconss()[c];
1092  if(conssBool[cons] == true)
1093  conssForGraph.push_back(cons);
1094  }
1095 
1096  assert(this->nvars == (int) varsForGraph.size());
1097  assert(this->nconss == (int) conssForGraph.size());
1098 
1099  sort(conssForGraph.begin(), conssForGraph.end());
1100  sort(varsForGraph.begin(), varsForGraph.end());
1101 
1102  //fillout oldToNewVarIndex and oltToNewConsIndex
1103  for(int v = 0; v < this->nvars; ++v)
1104  {
1105  int oldVarId = varsForGraph[v];
1106  oldToNewVarIndex.insert({oldVarId,v});
1107  }
1108 
1109  for(int c = 0; c < this->nconss; ++c)
1110  {
1111  int oldConsId = conssForGraph[c];
1112  oldToNewConsIndex.insert({oldConsId,c});
1113  }
1114 
1115  priority_graph stable_set_graph;
1116  this->non_cl = (int)labels.size();
1117  // for each column in the conss matrix we save labels of all the constraints where the variable appears
1118  vector< vector<int> > all_ind_in_col(this->nvars);
1119 
1120  /* go through all constraints */
1121  for(int c = 0; c < this->nconss; ++c)
1122  {
1123  int cons1 = conssForGraph[c];
1124  int consIndex1 = oldToNewConsIndex[cons1];
1125  assert(consIndex1 >= 0);
1126  assert(consIndex1 < this->nconss);
1127 
1128  /*
1129  * may work as is, as we are copying the constraint later regardless
1130  * if there are variables in it or not
1131  */
1132 
1133  /* go through all constraints */
1134  for(int d = 0; d < c; ++d )
1135  {
1136  int cons2 = conssForGraph[d];
1137  int consIndex2 = oldToNewConsIndex[cons2];
1138  assert(consIndex2 >= 0);
1139  assert(consIndex2 < this->nconss);
1140  if(labels[consIndex1] == labels[consIndex2])
1141  continue;
1142  SCIP_Bool continueloop = FALSE;
1143  /*
1144  * may work as is, as we are copying the constraint later regardless
1145  * if there are variables in it or not
1146  */
1147 
1150  for(int v = 0; v < seeedpool->getNVarsForCons(cons1); ++v)
1151  {
1152  int var1 = seeedpool->getVarsForCons(cons1)[v];
1153  if(find(varsForGraph.begin(), varsForGraph.end(), var1) == varsForGraph.end())
1154  continue;
1155  int varIndex1 = oldToNewVarIndex[var1];
1156  assert(varIndex1 >= 0);
1157  assert(varIndex1 < this->nvars);
1158  for(int w = 0; w < seeedpool->getNVarsForCons(cons2); ++w)
1159  {
1160  int var2 = seeedpool->getVarsForCons(cons2)[w];
1161  if(find(varsForGraph.begin(), varsForGraph.end(), var2) == varsForGraph.end())
1162  continue;
1163  int varIndex2 = oldToNewVarIndex[var2];
1164  assert(varIndex2 >= 0);
1165  assert(varIndex2 < this->nvars);
1166  if(varIndex1 == varIndex2)
1167  {
1168  stable_set_graph.addNode(consIndex1);
1169  stable_set_graph.addNode(consIndex2);
1170  stable_set_graph.addEdge(consIndex1, consIndex2);
1171  continueloop = TRUE;
1172  break;
1173  }
1174  }
1175  if(continueloop)
1176  break;
1177  }
1178  }
1179  }
1180 
1181  // run greedy heuristic for stable set
1182  vector<int> stable_set;
1183  vector<int> no_stable_set;
1184  while(!stable_set_graph.empty()){
1185  int current = stable_set_graph.top().first;
1186  stable_set.push_back(current);
1187  set<int> neighbors = stable_set_graph.getNeighbors(current);
1188  stable_set_graph.pop();
1189  for(auto neighbor : neighbors){
1190  stable_set_graph.removeNode(neighbor, no_stable_set);
1191  }
1192  }
1193 
1194 
1195  // Iterate all the conss and remove them (i.e. set label to -1) if necessary
1196  for(int to_remove : no_stable_set)
1197  {
1198  //SCIPverbMessage(this->scip_, SCIP_VERBLEVEL_NORMAL, NULL, " to_remove: %d \n", to_remove);
1199  labels[to_remove] = -1;
1200  }
1201  }
1202 
1203 
1204  if(!skip_me)
1205  {
1206  // Fix the labeling so that it starts from 0 without skipping the enumeration order
1207  // And set the graph partition accordingly.
1208  set<int> diff_blocks;
1209  for(auto curr_int = labels.begin(), end = labels.end(); curr_int != end; ++curr_int)
1210  {
1211  diff_blocks.insert(*curr_int);
1212  }
1213 
1214  const int non_cl_pts = count(labels.begin(), labels.end(), -1);
1215  if(non_cl_pts > 0)
1216  {
1217  this->n_blocks = diff_blocks.size() - 1;
1218  }
1219  else
1220  {
1221  this->n_blocks = diff_blocks.size();
1222  }
1223  this->non_cl = non_cl_pts;
1224 
1225  map<int,int> labels_fix;
1226  int new_label;
1227  if(this->non_cl > 0) new_label = -1;
1228  else new_label = 0;
1229 
1230  for(int old_label: diff_blocks)
1231  {
1232  labels_fix[old_label] = new_label;
1233  new_label++;
1234  }
1235  for(int i = 0; i < (int)labels.size(); i++)
1236  {
1237  labels[i] = labels_fix[labels[i]];
1238  }
1239  }
1240 
1241  // put the labels as the partition...
1242  for(int i = 0; i < (int)labels.size(); i++)
1243  {
1244  this->graph.setPartition(i, labels[i]);
1245  }
1246  return SCIP_OKAY;
1247 }
1248 
1249 template <>
1250 SCIP_RETCODE RowGraphWeighted<GraphGCG>::computePartitionDBSCAN(double eps, bool postprocenable)
1251 {
1252  vector<int> labels;
1254  assert((int)labels.size() == graph.getNNodes());
1255 
1256  SCIP_CALL( postProcess(labels, postprocenable) );
1257  return SCIP_OKAY;
1258 }
1259 
1260 template <>
1261 SCIP_RETCODE RowGraphWeighted<GraphGCG>::computePartitionDBSCANForPartialGraph(gcg::Seeedpool* seeedpool, gcg::Seeed* seeed, double eps, bool postprocenable)
1262 {
1263  vector<int> labels;
1265  assert((int)labels.size() == graph.getNNodes());
1266 
1267  SCIP_CALL( postProcessForPartialGraph(seeedpool, seeed, labels, postprocenable) );
1268  return SCIP_OKAY;
1269 }
1270 
1271 
1272 template <>
1273 SCIP_RETCODE RowGraphWeighted<GraphGCG>::computePartitionMST(double eps, bool postprocenable)
1274 {
1275  vector<int> labels;
1276  labels = GraphAlgorithms<GraphGCG>::mst(graph, eps);
1277  assert((int)labels.size() == graph.getNNodes());
1278 
1279  SCIP_CALL( postProcess(labels, postprocenable) );
1280  return SCIP_OKAY;
1281 }
1282 
1283 template <>
1284 SCIP_RETCODE RowGraphWeighted<GraphGCG>::computePartitionMSTForPartialGraph(gcg::Seeedpool* seeedpool, gcg::Seeed* seeed, double eps, bool postprocenable)
1285 {
1286  vector<int> labels;
1287  labels = GraphAlgorithms<GraphGCG>::mst(graph, eps);
1288  assert((int)labels.size() == graph.getNNodes());
1289 
1290  SCIP_CALL( postProcessForPartialGraph(seeedpool, seeed, labels, postprocenable) );
1291  return SCIP_OKAY;
1292 }
1293 
1294 template <>
1295 SCIP_RETCODE RowGraphWeighted<GraphGCG>::computePartitionMCL(int& stoppedAfter, double inflatefactor, bool postprocenable)
1296 {
1297  vector<int> labels;
1298  labels = GraphAlgorithms<GraphGCG>::mcl(graph, stoppedAfter, inflatefactor);
1299  assert((int)labels.size() == graph.getNNodes());
1300 
1301  SCIP_CALL( postProcess(labels, postprocenable) );
1302  return SCIP_OKAY;
1303 }
1304 
1305 template <>
1306 SCIP_RETCODE RowGraphWeighted<GraphGCG>::computePartitionMCLForPartialGraph(gcg::Seeedpool* seeedpool, gcg::Seeed* seeed, int& stoppedAfter, double inflatefactor, bool postprocenable)
1307 {
1308  vector<int> labels;
1309  labels = GraphAlgorithms<GraphGCG>::mcl(graph, stoppedAfter, inflatefactor);
1310  assert((int)labels.size() == graph.getNNodes());
1311 
1312  SCIP_CALL( postProcessForPartialGraph(seeedpool, seeed, labels, postprocenable) );
1313  return SCIP_OKAY;
1314 }
1315 
1316 template <class T>
1317 SCIP_RETCODE RowGraphWeighted<T>::getNBlocks(int& _n_blocks)
1318 {
1319  _n_blocks = n_blocks;
1320  return SCIP_OKAY;
1321 }
1322 
1323 template <class T>
1324 SCIP_RETCODE RowGraphWeighted<T>::nonClustered(int& _non_cl)
1325 {
1326  _non_cl = non_cl;
1327  return SCIP_OKAY;
1328 }
1329 
1330 template <class T>
1332 {
1333  return this->graph.getEdgeWeightPercentile(q);
1334 }
1335 
1336 } /* namespace gcg */
1337 #endif
virtual SCIP_RETCODE createFromMatrix(SCIP_CONS **conss, SCIP_VAR **vars, int nconss_, int nvars_, DISTANCE_MEASURE dist, WEIGHT_TYPE w_type)
static std::vector< int > mst(Graph< GraphGCG > &graph, double cutoff, int minPts=4)
std::string name
Definition: matrixgraph.h:56
int getNVarsForCons(int consIndex)
returns the number of variables for a given constraint
const int * getOpenconss()
returns array containing constraints not assigned yet
virtual SCIP_RETCODE computePartitionMCL(int &stoppedAfter, double inflatefactor, bool postprocenable)
virtual SCIP_RETCODE getNBlocks(int &_n_blocks)
int getNVars()
returns number of vars
int getNConss()
returns the number of constraints
void addNode(int id)
STL namespace.
virtual SCIP_RETCODE nonClustered(int &_non_cl)
int getNOpenvars()
returns size of vector containing variables not assigned yet
enum DistanceMeasure DISTANCE_MEASURE
virtual SCIP_RETCODE computePartitionMCLForPartialGraph(gcg::Seeedpool *seeedpool, gcg::Seeed *seeed, int &stoppedAfter, double inflatefactor, bool postprocenable)
Implementation of the graph which supports both node and edge weights.
class to manage partial decompositions (aka seeed), each seeed corresponds to one seeedpool which con...
Definition: class_seeed.h:71
virtual SCIP_RETCODE computePartitionMST(double eps, bool postprocenable)
virtual SCIP_RETCODE computePartitionMSTForPartialGraph(gcg::Seeedpool *seeedpool, gcg::Seeed *seeed, double eps, bool postprocenable)
virtual SCIP_RETCODE createFromPartialMatrix(Seeedpool *seeedpool, Seeed *seeed, DISTANCE_MEASURE dist, WEIGHT_TYPE w_type)
bool removeNode(int node, vector< int > &removed)
SCIP_Bool GCGisVarRelevant(SCIP_VAR *var)
Definition: scip_misc.c:41
A row graph where each row is a node and rows are adjacent if they share a variable. The edges are weighted according to specified similarity measure.
static std::vector< int > dbscan(Graph< GraphGCG > &graph, double eps, int minPts=4)
several metrics for graphs
const int * getOpenvars()
returns array containing variables not assigned yet
virtual SCIP_RETCODE computePartitionDBSCAN(double eps, bool postprocenable)
static std::vector< int > mcl(Graph< GraphGCG > &graph, int &stoppedAfter, double inflatefac, int maxiters=25, int expandfac=2)
static double calculateSimilarity(int a, int b, int c, DISTANCE_MEASURE dist, WEIGHT_TYPE w_type, bool itself)
gcg::Graph< T > graph
Definition: rowgraph.h:48
int getNOpenconss()
returns size of vector containing constraints not assigned yet
set< int > getNeighbors(int node)
virtual double getEdgeWeightPercentile(double q)
virtual SCIP_RETCODE computePartitionDBSCANForPartialGraph(gcg::Seeedpool *seeedpool, gcg::Seeed *seeed, double eps, bool postprocenable)
enum WeightType WEIGHT_TYPE
void addEdge(int node_i, int node_j)
const int * getVarsForCons(int consIndex)
returns the variable indices of the coefficient matrix for a constraint