SCIP-SDP  2.0.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-2015 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-2015 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 
47  int* row,
48  int* col,
49  SCIP_Real* val,
50  int length
51  )
52 {
53  int firstentry;
54  int nextentry;
55 
56  /* first sort by row indices */
57  SCIPsortIntIntReal(row, col, val, length);
58 
59  /* for those with identical row-indices now sort by non-decreasing col-index, first find all entries with the same row-index */
60  nextentry = 0;
61  while (nextentry < length)
62  {
63  firstentry = nextentry; /* the next row starts where the last one ended*/
64 
65  while (nextentry < length && row[nextentry] == row[firstentry]) /* as long as the row still matches, increase nextentry */
66  {
67  nextentry++;
68  }
69 
70  /* now sort all entries between firstentry and nextentry-1 by their col-indices */
71  SCIPsortIntReal(col + firstentry, val + firstentry, nextentry - firstentry);
72  }
73 }
74 
84  BMS_BLKMEM* blkmem,
85  SCIP_Real feastol,
86  int* originrow,
87  int* origincol,
88  SCIP_Real* originval,
89  int originlength,
90  SCIP_Bool originsorted,
91  SCIP_Real scalar,
92  int* targetrow,
93  int* targetcol,
94  SCIP_Real* targetval,
95  int* targetlength,
97  int targetmemory
99  )
100 { /*lint --e{679}*/
101  /*lint --e{850}*/
102  int ind;
103  int i;
104  int nleftshifts; /* if some nonzeros of the target arrays get deleted, this saves the number of spots the following entries have to be moved
105  * to the left */
106  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
107  * the middle of the arrays by decreasing the number of leftshifts) */
108  int insertionpos;
109  SCIP_Bool debugmsg; /* should a debug message about insufficient length be thrown */
110 
111  assert ( blkmem != NULL );
112  assert ( originlength == 0 || (originlength > 0 && originrow != NULL && origincol != NULL && originval != NULL) );
113  assert ( targetrow != NULL );
114  assert ( targetcol != NULL );
115  assert ( targetval != NULL );
116  assert ( targetlength != NULL );
117  assert ( *targetlength >= 0 );
118 
119  /* sort the target and origin arrays first by row and then by col to make searching for entries easier */
120  SCIPsdpVarfixerSortRowCol(targetrow, targetcol, targetval, *targetlength);
121 
122  if ( ! (originsorted) )
123  SCIPsdpVarfixerSortRowCol(originrow, origincol, originval, originlength);
124 
125  ind = 0; /* this will be used to traverse the nonzeros of the target arrays */
126  naddednonz = 0;
127  nleftshifts = 0;
128  debugmsg = FALSE;
129 
130  /* iterate over all nonzeroes */
131  for (i = 0; i < originlength; i++)
132  {
133  /* search the target arrays for an entry at this position, as both the origin and the target arrays are sorted, we go on until
134  * 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,
135  * 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
136  * entry for this row and col */
137  while (ind < *targetlength && (targetrow[ind] < originrow[i] || (targetrow[ind] == originrow[i] && targetcol[ind] < origincol[i])))
138  {
139  /* shift the target nonzeros to the left if needed */
140  if ( nleftshifts > 0 )
141  {
142  targetrow[ind - nleftshifts] = targetrow[ind];
143  targetcol[ind - nleftshifts] = targetcol[ind];
144  targetval[ind - nleftshifts] = targetval[ind];
145  }
146  ind++;
147  }
148 
149  if ( ind < *targetlength && (targetrow[ind] == originrow[i] && targetcol[ind] == origincol[i]) )
150  {
151  /* add to the old entry */
152 
153  /* shift the entry to the left if needed and change the value */
154  if ( nleftshifts > 0 )
155  {
156  targetrow[ind - nleftshifts] = targetrow[ind];
157  targetcol[ind - nleftshifts] = targetcol[ind];
158  }
159  targetval[ind - nleftshifts] = targetval[ind] + scalar * originval[i];
160 
161  /* there could be multiple entries to add with identical row and col, so look for further ones in the next entries until there
162  * are no more */
163  while (i + 1 < originlength && originrow[i + 1] == targetrow[ind - nleftshifts] && origincol[i + 1] == targetcol[ind - nleftshifts])
164  {
165  targetval[ind - nleftshifts] += scalar * originval[i + 1];
166  i++;
167  }
168 
169  if ( REALABS(targetval[ind - nleftshifts]) < feastol )
170  {
171  /* the nonzero became zero */
172  nleftshifts++;
173  }
174  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 */
175  }
176  else /* create a new entry */
177  {
178  if ( nleftshifts > 0 )
179  {
180  /* we can add the nonzero at one of the empty spots */
181  insertionpos = ind - nleftshifts;
182  nleftshifts--; /* as one empty spot was filled, all remaining nonzeros should be moved one less position to the left */
183  }
184  else
185  {
186  /* add it to the end */
187  insertionpos = *targetlength + naddednonz;
188  naddednonz++;
189  }
190 
191  if ( insertionpos < targetmemory )
192  {
193  /* add the nonzero to the computed position */
194  targetrow[insertionpos] = originrow[i];
195  targetcol[insertionpos] = origincol[i];
196  targetval[insertionpos] = scalar * originval[i];
197 
198  /* 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 */
199  while (i + 1 < originlength && originrow[i + 1] == targetrow[insertionpos] && origincol[i + 1] == targetcol[insertionpos])
200  {
201  targetval[insertionpos] += scalar * originval[i + 1];
202  i++;
203  }
204 
205  /* if there were indeed multiple entries, check if they did cancel each other out, in that case remove the entry */
206  if ( REALABS(targetval[insertionpos]) < feastol )
207  {
208  /* depending on where this actually zero nonzero was added, either add another leftshift to overwrite it or decrease the number of addednonz */
209  if ( insertionpos < ind )
210  nleftshifts++;
211  else
212  naddednonz--;
213  }
214  }
215  else /* the memory was not sufficient, so we will throw a debug message, we only wait until we know the final needed size */
216  debugmsg = TRUE;
217  }
218  }
219  /* shift the remaining entries of the target arrays */
220  if ( nleftshifts > 0 )
221  {
222  while (ind < *targetlength + naddednonz && ind < targetmemory)
223  {
224  targetrow[ind - nleftshifts] = targetrow[ind];
225  targetcol[ind - nleftshifts] = targetcol[ind];
226  targetval[ind - nleftshifts] = targetval[ind];
227  ind++;
228  }
229  }
230 
231  if ( debugmsg )
232  SCIPdebugMessage("insufficient memory given for SCIPsdpVarfixerMergeArrays, targetmemorys had length %d, would have needed up to %d\n",
233  targetmemory, *targetlength + naddednonz);
234 
235  *targetlength = *targetlength + naddednonz - nleftshifts;
236 
237  return SCIP_OKAY;
238 }
239 
240 
250  BMS_BLKMEM* blkmem,
251  SCIP_Real feastol,
252  int* firstrow,
253  int* firstcol,
254  SCIP_Real* firstval,
255  int firstlength,
256  int* secondrow,
257  int* secondcol,
258  SCIP_Real* secondval,
259  int secondlength,
260  int* targetrow,
261  int* targetcol,
262  SCIP_Real* targetval,
263  int* targetlength
265  )
266 {
267  int firstind;
268  int secondind;
269  int targetind;
270  SCIP_Bool debugmsg; /* should we throw a debug message about insufficient memory */
271 
272  assert ( blkmem != NULL );
273  assert ( firstlength == 0 || (firstlength > 0 && firstrow != NULL && firstcol != NULL && firstval != NULL ) );
274  assert ( secondlength == 0 || (secondlength > 0 && secondrow != NULL && secondcol != NULL && secondval != NULL ) );
275  assert ( targetrow != NULL );
276  assert ( targetcol != NULL );
277  assert ( targetval != NULL );
278  assert ( targetlength != NULL );
279  assert ( *targetlength >= 0 );
280 
281  debugmsg = FALSE;
282 
283  /* sort both arrays by non-decreasing row and then col indices to make comparisons easier */
284  SCIPsdpVarfixerSortRowCol(firstrow, firstcol, firstval, firstlength);
285  SCIPsdpVarfixerSortRowCol(secondrow, secondcol, secondval, secondlength);
286 
287  /* as both arrays are sorted, traverse them simultanously, always adding the current entry with the lower index of either array to the
288  * target arrays (if they both have the same index, we have found entries that need to be merged) */
289  firstind = 0;
290  secondind = 0;
291  targetind = 0;
292 
293  while (firstind < firstlength && secondind < secondlength)
294  {
295  /* 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
296  * 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 */
297  if ( firstrow[firstind] < secondrow[secondind] || (firstrow[firstind] == secondrow[secondind] && firstcol[firstind] < secondcol[secondind]) )
298  {
299  if ( targetind < *targetlength )
300  {
301  targetrow[targetind] = firstrow[firstind];
302  targetcol[targetind] = firstcol[firstind];
303  targetval[targetind] = firstval[firstind];
304  }
305  else
306  debugmsg = TRUE;
307 
308  targetind++;
309  firstind++;
310  }
311  /* if the next entry of the second array comes first, we insert it */
312  else if ( firstrow[firstind] > secondrow[secondind] || (firstrow[firstind] == secondrow[secondind] && firstcol[firstind] > secondcol[secondind]) )
313  {
314  if ( targetind < *targetlength )
315  {
316  targetrow[targetind] = secondrow[secondind];
317  targetcol[targetind] = secondcol[secondind];
318  targetval[targetind] = secondval[secondind];
319  }
320  else
321  debugmsg = TRUE;
322  secondind++;
323 
324  /* 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
325  * add it's value to the created entry in the target entries and continue */
326  while (secondind < secondlength && (secondrow[secondind] == targetrow[targetind] && secondcol[secondind] == targetcol[targetind]))
327  {
328  if ( targetind < *targetlength )
329  targetval[targetind] += secondval[secondind];
330  secondind++;
331  }
332 
333  /* 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
334  * 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) */
335  if ( targetind >= *targetlength || REALABS(targetval[targetind]) >= feastol )
336  targetind++;
337  }
338  /* if the next entries of both arrays are equal according to the row then col sorting, then they need to be combined */
339  else
340  {
341  if ( targetind < *targetlength )
342  {
343  targetrow[targetind] = firstrow[firstind];
344  targetcol[targetind] = firstcol[firstind];
345  targetval[targetind] = firstval[firstind] + secondval[secondind];
346  }
347  else
348  debugmsg = TRUE;
349  firstind++;
350  secondind++;
351 
352  /* 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
353  * add it's value to the created entry in the target entries and continue */
354  while (secondind < secondlength && (secondrow[secondind] == targetrow[targetind] && secondcol[secondind] == targetcol[targetind]))
355  {
356  if ( targetind < *targetlength )
357  targetval[targetind] += secondval[secondind];
358  secondind++;
359  }
360 
361  /* 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
362  * 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) */
363  if ( targetind >= *targetlength || REALABS(targetval[targetind]) >= feastol )
364  targetind++;
365  }
366  }
367  /* 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
368  * 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
369  * queues are exactly the same as the corresponding if-case in the above while-queue (+ checking for the length of the target arrays) */
370  while (firstind < firstlength)
371  {
372  if ( targetind < *targetlength )
373  {
374  targetrow[targetind] = firstrow[firstind];
375  targetcol[targetind] = firstcol[firstind];
376  targetval[targetind] = firstval[firstind];
377  }
378  else
379  debugmsg = TRUE;
380  firstind++;
381  targetind++;
382  }
383 
384  while (secondind < secondlength)
385  {
386  if ( targetind < *targetlength )
387  {
388  targetrow[targetind] = secondrow[secondind];
389  targetcol[targetind] = secondcol[secondind];
390  targetval[targetind] = secondval[secondind];
391  }
392  else
393  debugmsg = TRUE;
394  secondind++;
395 
396  /* 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
397  * add it's value to the created entry in the target entries and continue */
398  while (secondind < secondlength && (secondrow[secondind] == targetrow[targetind] && secondcol[secondind] == targetcol[targetind]))
399  {
400  if ( targetind < *targetlength )
401  targetval[targetind] += secondval[secondind];
402  secondind++;
403  }
404 
405  /* 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
406  * target arrays */
407  if ( targetind >= *targetlength || REALABS(targetval[targetind]) >= feastol )
408  targetind++;
409  }
410 
411  if ( debugmsg )
412  {
413  SCIPdebugMessage("Insufficient arraylength in SCIPsdpVarfixerMergeArraysIntoNew, given targetarray-length was %d, would have needed %d",
414  *targetlength, targetind);
415  }
416 
417  *targetlength = targetind;
418 
419  return SCIP_OKAY;
420 }
void SCIPsdpVarfixerSortRowCol(int *row, int *col, SCIP_Real *val, int length)
Definition: SdpVarfixer.c:46
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:249
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:83
adds the main functionality to fix/unfix/(multi-)aggregate variables by merging two three-tuple-array...