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