SCIP-SDP  2.1.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
SdpVarfixer.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of SCIPSDP - a solving framework for mixed-integer */
4 /* semidefinite programms based on SCIP. */
5 /* */
6 /* Copyright (C) 2011-2013 Discrete Optimization, TU Darmstadt */
7 /* EDOM, FAU Erlangen-Nürnberg */
8 /* 2014-2016 Discrete Optimization, TU Darmstadt */
9 /* */
10 /* */
11 /* This program is free software; you can redistribute it and/or */
12 /* modify it under the terms of the GNU Lesser General Public License */
13 /* as published by the Free Software Foundation; either version 3 */
14 /* of the License, or (at your option) any later version. */
15 /* */
16 /* This program is distributed in the hope that it will be useful, */
17 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
18 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
19 /* GNU Lesser General Public License for more details. */
20 /* */
21 /* You should have received a copy of the GNU Lesser General Public License */
22 /* along with this program; if not, write to the Free Software */
23 /* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.*/
24 /* */
25 /* */
26 /* Based on SCIP - Solving Constraint Integer Programs */
27 /* Copyright (C) 2002-2016 Zuse Institute Berlin */
28 /* SCIP is distributed under the terms of the SCIP Academic Licence, */
29 /* see file COPYING in the SCIP distribution. */
30 /* */
31 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
32 
38 #include "scip/type_misc.h"
39 #include "scip/def.h"
40 #include "scip/pub_misc.h" /* for sorting */
41 #include "SdpVarfixer.h"
42 
43 /* turn off lint warnings for whole file: */
44 /*lint --e{788,818}*/
45 
51  int* row,
52  int* col,
53  SCIP_Real* val,
54  int length
55  )
56 {
57  int firstentry;
58  int nextentry;
59 
60  /* first sort by row indices */
61  SCIPsortIntIntReal(row, col, val, length);
62 
63  /* for those with identical row-indices now sort by non-decreasing col-index, first find all entries with the same row-index */
64  nextentry = 0;
65  while (nextentry < length)
66  {
67  firstentry = nextentry; /* the next row starts where the last one ended*/
68 
69  while (nextentry < length && row[nextentry] == row[firstentry]) /* as long as the row still matches, increase nextentry */
70  {
71  nextentry++;
72  }
73 
74  /* now sort all entries between firstentry and nextentry-1 by their col-indices */
75  SCIPsortIntReal(col + firstentry, val + firstentry, nextentry - firstentry);
76  }
77 }
78 
89  BMS_BLKMEM* blkmem,
90  SCIP_Real feastol,
91  int* originrow,
92  int* origincol,
93  SCIP_Real* originval,
94  int originlength,
95  SCIP_Bool originsorted,
96  SCIP_Real scalar,
97  int* targetrow,
98  int* targetcol,
99  SCIP_Real* targetval,
100  int* targetlength,
102  int targetmemory
104  )
105 { /*lint --e{679}*/
106  /*lint --e{850}*/
107  int ind;
108  int i;
109  int nleftshifts; /* if some nonzeros of the target arrays get deleted, this saves the number of spots the following entries have to be moved
110  * to the left */
111  int naddednonz; /* this gives the number of nonzeros that were added to the end of the arrays (this does NOT include those that were added in
112  * the middle of the arrays by decreasing the number of leftshifts) */
113  int insertionpos;
114  SCIP_Bool debugmsg; /* should a debug message about insufficient length be thrown */
115 
116  assert ( blkmem != NULL );
117  assert ( originlength == 0 || (originlength > 0 && originrow != NULL && origincol != NULL && originval != NULL) );
118  assert ( targetrow != NULL );
119  assert ( targetcol != NULL );
120  assert ( targetval != NULL );
121  assert ( targetlength != NULL );
122  assert ( *targetlength >= 0 );
123 
124  /* sort the target and origin arrays first by row and then by col to make searching for entries easier */
125  SCIPsdpVarfixerSortRowCol(targetrow, targetcol, targetval, *targetlength);
126 
127  if ( ! (originsorted) )
128  SCIPsdpVarfixerSortRowCol(originrow, origincol, originval, originlength);
129 
130  ind = 0; /* this will be used to traverse the nonzeros of the target arrays */
131  naddednonz = 0;
132  nleftshifts = 0;
133  debugmsg = FALSE;
134 
135  /* iterate over all nonzeroes */
136  for (i = 0; i < originlength; i++)
137  {
138  /* search the target arrays for an entry at this position, as both the origin and the target arrays are sorted, we go on until
139  * we find an entry that is not < as the current entry in the origin arrays according to this sorting, if this has equal row/col,
140  * we have found the entry we have to edit, if it is >, then we know, that there is no identical entry, and we can just add a new
141  * entry for this row and col */
142  while (ind < *targetlength && (targetrow[ind] < originrow[i] || (targetrow[ind] == originrow[i] && targetcol[ind] < origincol[i])))
143  {
144  /* shift the target nonzeros to the left if needed */
145  if ( nleftshifts > 0 )
146  {
147  targetrow[ind - nleftshifts] = targetrow[ind];
148  targetcol[ind - nleftshifts] = targetcol[ind];
149  targetval[ind - nleftshifts] = targetval[ind];
150  }
151  ind++;
152  }
153 
154  if ( ind < *targetlength && (targetrow[ind] == originrow[i] && targetcol[ind] == origincol[i]) )
155  {
156  /* add to the old entry */
157 
158  /* shift the entry to the left if needed and change the value */
159  if ( nleftshifts > 0 )
160  {
161  targetrow[ind - nleftshifts] = targetrow[ind];
162  targetcol[ind - nleftshifts] = targetcol[ind];
163  }
164  targetval[ind - nleftshifts] = targetval[ind] + scalar * originval[i];
165 
166  /* there could be multiple entries to add with identical row and col, so look for further ones in the next entries until there
167  * are no more */
168  while (i + 1 < originlength && originrow[i + 1] == targetrow[ind - nleftshifts] && origincol[i + 1] == targetcol[ind - nleftshifts])
169  {
170  targetval[ind - nleftshifts] += scalar * originval[i + 1];
171  i++;
172  }
173 
174  if ( REALABS(targetval[ind - nleftshifts]) < feastol )
175  {
176  /* the nonzero became zero */
177  nleftshifts++;
178  }
179  ind++; /* as we already added all origin-entries belonging to this row/col and also shifted the entry, we can continue with the next one */
180  }
181  else /* create a new entry */
182  {
183  if ( nleftshifts > 0 )
184  {
185  /* we can add the nonzero at one of the empty spots */
186  insertionpos = ind - nleftshifts;
187  nleftshifts--; /* as one empty spot was filled, all remaining nonzeros should be moved one less position to the left */
188  }
189  else
190  {
191  /* add it to the end */
192  insertionpos = *targetlength + naddednonz;
193  naddednonz++;
194  }
195 
196  if ( insertionpos < targetmemory )
197  {
198  /* add the nonzero to the computed position */
199  targetrow[insertionpos] = originrow[i];
200  targetcol[insertionpos] = origincol[i];
201  targetval[insertionpos] = scalar * originval[i];
202 
203  /* there could be multiple entries to add with identical row and col, so look for further ones in the next entries until there are no more */
204  while (i + 1 < originlength && originrow[i + 1] == targetrow[insertionpos] && origincol[i + 1] == targetcol[insertionpos])
205  {
206  targetval[insertionpos] += scalar * originval[i + 1];
207  i++;
208  }
209 
210  /* if there were indeed multiple entries, check if they did cancel each other out, in that case remove the entry */
211  if ( REALABS(targetval[insertionpos]) < feastol )
212  {
213  /* depending on where this actually zero nonzero was added, either add another leftshift to overwrite it or decrease the number of addednonz */
214  if ( insertionpos < ind )
215  nleftshifts++;
216  else
217  naddednonz--;
218  }
219  }
220  else /* the memory was not sufficient, so we will throw a debug message, we only wait until we know the final needed size */
221  debugmsg = TRUE;
222  }
223  }
224  /* shift the remaining entries of the target arrays */
225  if ( nleftshifts > 0 )
226  {
227  while (ind < *targetlength + naddednonz && ind < targetmemory)
228  {
229  targetrow[ind - nleftshifts] = targetrow[ind];
230  targetcol[ind - nleftshifts] = targetcol[ind];
231  targetval[ind - nleftshifts] = targetval[ind];
232  ind++;
233  }
234  }
235 
236  if ( debugmsg )
237  SCIPdebugMessage("insufficient memory given for SCIPsdpVarfixerMergeArrays, targetmemorys had length %d, would have needed up to %d\n",
238  targetmemory, *targetlength + naddednonz);
239 
240  *targetlength = *targetlength + naddednonz - nleftshifts;
241 
242  return SCIP_OKAY;
243 }
244 
245 
256  BMS_BLKMEM* blkmem,
257  SCIP_Real feastol,
258  int* firstrow,
259  int* firstcol,
260  SCIP_Real* firstval,
261  int firstlength,
262  int* secondrow,
263  int* secondcol,
264  SCIP_Real* secondval,
265  int secondlength,
266  int* targetrow,
267  int* targetcol,
268  SCIP_Real* targetval,
269  int* targetlength
271  )
272 {
273  int firstind;
274  int secondind;
275  int targetind;
276  SCIP_Bool debugmsg; /* should we throw a debug message about insufficient memory */
277 
278  assert ( blkmem != NULL );
279  assert ( firstlength == 0 || (firstlength > 0 && firstrow != NULL && firstcol != NULL && firstval != NULL ) );
280  assert ( secondlength == 0 || (secondlength > 0 && secondrow != NULL && secondcol != NULL && secondval != NULL ) );
281  assert ( targetrow != NULL );
282  assert ( targetcol != NULL );
283  assert ( targetval != NULL );
284  assert ( targetlength != NULL );
285  assert ( *targetlength >= 0 );
286 
287  debugmsg = FALSE;
288 
289  /* sort both arrays by non-decreasing row and then col indices to make comparisons easier */
290  SCIPsdpVarfixerSortRowCol(firstrow, firstcol, firstval, firstlength);
291  SCIPsdpVarfixerSortRowCol(secondrow, secondcol, secondval, secondlength);
292 
293  /* as both arrays are sorted, traverse them simultanously, always adding the current entry with the lower index of either array to the
294  * target arrays (if they both have the same index, we have found entries that need to be merged) */
295  firstind = 0;
296  secondind = 0;
297  targetind = 0;
298 
299  while (firstind < firstlength && secondind < secondlength)
300  {
301  /* if the next entry of the first arrays comes before the next entry of the second arrays according to the row then col sorting, then we can
302  * insert the next entry of the first arrays, as there can't be an entry in the second arrays for the same row/col-combination */
303  if ( firstrow[firstind] < secondrow[secondind] || (firstrow[firstind] == secondrow[secondind] && firstcol[firstind] < secondcol[secondind]) )
304  {
305  if ( targetind < *targetlength )
306  {
307  targetrow[targetind] = firstrow[firstind];
308  targetcol[targetind] = firstcol[firstind];
309  targetval[targetind] = firstval[firstind];
310  }
311  else
312  debugmsg = TRUE;
313 
314  targetind++;
315  firstind++;
316  }
317  /* if the next entry of the second array comes first, we insert it */
318  else if ( firstrow[firstind] > secondrow[secondind] || (firstrow[firstind] == secondrow[secondind] && firstcol[firstind] > secondcol[secondind]) )
319  {
320  if ( targetind < *targetlength )
321  {
322  targetrow[targetind] = secondrow[secondind];
323  targetcol[targetind] = secondcol[secondind];
324  targetval[targetind] = secondval[secondind];
325  }
326  else
327  debugmsg = TRUE;
328  secondind++;
329 
330  /* as the second arrays may have duplicate entries, we have to check the next entry, if it has the same row/col combination, if yes, then we
331  * add it's value to the created entry in the target entries and continue */
332  while (secondind < secondlength && (secondrow[secondind] == targetrow[targetind] && secondcol[secondind] == targetcol[targetind]))
333  {
334  if ( targetind < *targetlength )
335  targetval[targetind] += secondval[secondind];
336  secondind++;
337  }
338 
339  /* if we combined multiple fixed nonzeros, it is possible that they cancelled each other out, in that case, we shouldn't add a nonzero to the
340  * target arrays (if the array was too short we didn't compute the entry, but we add it, as we want to get an upper bound on the needed size) */
341  if ( targetind >= *targetlength || REALABS(targetval[targetind]) >= feastol )
342  targetind++;
343  }
344  /* if the next entries of both arrays are equal according to the row then col sorting, then they need to be combined */
345  else
346  {
347  if ( targetind < *targetlength )
348  {
349  targetrow[targetind] = firstrow[firstind];
350  targetcol[targetind] = firstcol[firstind];
351  targetval[targetind] = firstval[firstind] + secondval[secondind];
352  }
353  else
354  debugmsg = TRUE;
355  firstind++;
356  secondind++;
357 
358  /* as the second arrays may have duplicate entries, we have to check the next entry, if it has the same row/col combination, if yes, then we
359  * add it's value to the created entry in the target entries and continue */
360  while (secondind < secondlength && (secondrow[secondind] == targetrow[targetind] && secondcol[secondind] == targetcol[targetind]))
361  {
362  if ( targetind < *targetlength )
363  targetval[targetind] += secondval[secondind];
364  secondind++;
365  }
366 
367  /* as we combined multiple entires, it is possible that they cancelled each other out, in that case, we shouldn't add a nonzero to the
368  * target arrays (if the array was too short we didn't compute the entry, but we add it, as we want to get an upper bound on the needed size) */
369  if ( targetind >= *targetlength || REALABS(targetval[targetind]) >= feastol )
370  targetind++;
371  }
372  }
373  /* if we reach the end of one of the two arrays, we can just add the rest of the other array to the target arrays (in case of the second still
374  * combining duplicate entries of this same array), so at most one of the following two while-queues will be non-empty, the contents of these
375  * queues are exactly the same as the corresponding if-case in the above while-queue (+ checking for the length of the target arrays) */
376  while (firstind < firstlength)
377  {
378  if ( targetind < *targetlength )
379  {
380  targetrow[targetind] = firstrow[firstind];
381  targetcol[targetind] = firstcol[firstind];
382  targetval[targetind] = firstval[firstind];
383  }
384  else
385  debugmsg = TRUE;
386  firstind++;
387  targetind++;
388  }
389 
390  while (secondind < secondlength)
391  {
392  if ( targetind < *targetlength )
393  {
394  targetrow[targetind] = secondrow[secondind];
395  targetcol[targetind] = secondcol[secondind];
396  targetval[targetind] = secondval[secondind];
397  }
398  else
399  debugmsg = TRUE;
400  secondind++;
401 
402  /* as the second arrays may have duplicate entries, we have to check the next entry, if it has the same row/col combination, if yes, then we
403  * add it's value to the created entry in the target entries and continue */
404  while (secondind < secondlength && (secondrow[secondind] == targetrow[targetind] && secondcol[secondind] == targetcol[targetind]))
405  {
406  if ( targetind < *targetlength )
407  targetval[targetind] += secondval[secondind];
408  secondind++;
409  }
410 
411  /* if we combined multiple fixed nonzeros, it is possible that they cancelled each other out, in that case, we shouldn't add a nonzero to the
412  * target arrays */
413  if ( targetind >= *targetlength || REALABS(targetval[targetind]) >= feastol )
414  targetind++;
415  }
416 
417  if ( debugmsg )
418  {
419  SCIPdebugMessage("Insufficient arraylength in SCIPsdpVarfixerMergeArraysIntoNew, given targetarray-length was %d, would have needed %d",
420  *targetlength, targetind);
421  }
422 
423  *targetlength = targetind;
424 
425  return SCIP_OKAY;
426 }
void SCIPsdpVarfixerSortRowCol(int *row, int *col, SCIP_Real *val, int length)
Definition: SdpVarfixer.c:50
SCIP_RETCODE SCIPsdpVarfixerMergeArraysIntoNew(BMS_BLKMEM *blkmem, SCIP_Real feastol, int *firstrow, int *firstcol, SCIP_Real *firstval, int firstlength, int *secondrow, int *secondcol, SCIP_Real *secondval, int secondlength, int *targetrow, int *targetcol, SCIP_Real *targetval, int *targetlength)
Definition: SdpVarfixer.c:255
SCIP_RETCODE SCIPsdpVarfixerMergeArrays(BMS_BLKMEM *blkmem, SCIP_Real feastol, int *originrow, int *origincol, SCIP_Real *originval, int originlength, SCIP_Bool originsorted, SCIP_Real scalar, int *targetrow, int *targetcol, SCIP_Real *targetval, int *targetlength, int targetmemory)
Definition: SdpVarfixer.c:88
adds the main functionality to fix/unfix/(multi-)aggregate variables by merging two three-tuple-array...