1    	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2    	/*                                                                           */
3    	/*                  This file is part of the program and library             */
4    	/*         SCIP --- Solving Constraint Integer Programs                      */
5    	/*                                                                           */
6    	/*  Copyright (c) 2002-2023 Zuse Institute Berlin (ZIB)                      */
7    	/*                                                                           */
8    	/*  Licensed under the Apache License, Version 2.0 (the "License");          */
9    	/*  you may not use this file except in compliance with the License.         */
10   	/*  You may obtain a copy of the License at                                  */
11   	/*                                                                           */
12   	/*      http://www.apache.org/licenses/LICENSE-2.0                           */
13   	/*                                                                           */
14   	/*  Unless required by applicable law or agreed to in writing, software      */
15   	/*  distributed under the License is distributed on an "AS IS" BASIS,        */
16   	/*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17   	/*  See the License for the specific language governing permissions and      */
18   	/*  limitations under the License.                                           */
19   	/*                                                                           */
20   	/*  You should have received a copy of the Apache-2.0 license                */
21   	/*  along with SCIP; see the file LICENSE. If not visit scipopt.org.         */
22   	/*                                                                           */
23   	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24   	
25   	/**@file   sepa_mcf.c
26   	 * @ingroup DEFPLUGINS_SEPA
27   	 * @brief  multi-commodity-flow network cut separator
28   	 * @author Tobias Achterberg
29   	 * @author Christian Raack
30   	 *
31   	 * We try to identify a multi-commodity flow structure in the LP relaxation of the
32   	 * following type:
33   	 *
34   	 *  (1)  sum_{a in delta^+(v)} f_a^k  - sum_{a in delta^-(v)} f_a^k  <=  -d_v^k   for all v in V and k in K
35   	 *  (2)  sum_{k in K} f_a^k - c_a x_a                                <=  0        for all a in A
36   	 *
37   	 * Constraints (1) are flow conservation constraints, which say that for each commodity k and node v the
38   	 * outflow (delta^+(v)) minus the inflow (delta^-(v)) of a node v must not exceed the negative of the demand of
39   	 * node v in commodity k. To say it the other way around, inflow minus outflow must be at least equal to the demand.
40   	 * Constraints (2) are the arc capacity constraints, which say that the sum of all flow over an arc a must not
41   	 * exceed its capacity c_a x_a, with x being a binary or integer variable.
42   	 * c_a x_a does not need to be a single product of a capacity and an integer variable; we also accept general scalar
43   	 * products.
44   	 */
45   	
46   	/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
47   	
48   	
49   	/* #define COUNTNETWORKVARIABLETYPES */
50   	/* #define MCF_DEBUG */
51   	
52   	/* algorithmic defines in testing phase*/
53   	/* #define USEFLOWFORTIEBREAKING */
54   	/* #define USECAPACITYFORTIEBREAKING */
55   	/* #define TIEBREAKING */
56   	#define BETTERWEIGHTFORDEMANDNODES
57   	
58   	#include "blockmemshell/memory.h"
59   	#include "scip/cons_knapsack.h"
60   	#include "scip/cuts.h"
61   	#include "scip/pub_lp.h"
62   	#include "scip/pub_message.h"
63   	#include "scip/pub_misc.h"
64   	#include "scip/pub_misc_sort.h"
65   	#include "scip/pub_sepa.h"
66   	#include "scip/pub_var.h"
67   	#include "scip/scip_branch.h"
68   	#include "scip/scip_cut.h"
69   	#include "scip/scip_general.h"
70   	#include "scip/scip_lp.h"
71   	#include "scip/scip_mem.h"
72   	#include "scip/scip_message.h"
73   	#include "scip/scip_numerics.h"
74   	#include "scip/scip_param.h"
75   	#include "scip/scip_prob.h"
76   	#include "scip/scip_sepa.h"
77   	#include "scip/scip_sol.h"
78   	#include "scip/scip_solvingstats.h"
79   	#include "scip/scip_tree.h"
80   	#include "scip/sepa_mcf.h"
81   	#include <string.h>
82   	
83   	
84   	#define SEPA_NAME                        "mcf"
85   	#define SEPA_DESC                        "multi-commodity-flow network cut separator"
86   	#define SEPA_PRIORITY                    -10000
87   	#define SEPA_FREQ                             0
88   	#define SEPA_MAXBOUNDDIST                   0.0
89   	#define SEPA_USESSUBSCIP                  FALSE /**< does the separator use a secondary SCIP instance? */
90   	#define SEPA_DELAY                        FALSE /**< should separation method be delayed, if other separators found cuts? */
91   	
92   	/* changeable parameters*/
93   	#define DEFAULT_NCLUSTERS                     5   /**< number of clusters to generate in the shrunken network */
94   	#define DEFAULT_MAXWEIGHTRANGE            1e+06   /**< maximal valid range max(|weights|)/min(|weights|) of row weights for CMIR */
95   	#define DEFAULT_MAXTESTDELTA                 20   /**< maximal number of different deltas to try (-1: unlimited) for CMIR */
96   	#define DEFAULT_TRYNEGSCALING             FALSE   /**< should negative values also be tested in scaling? for CMIR */
97   	#define DEFAULT_FIXINTEGRALRHS             TRUE   /**< should an additional variable be complemented if f0 = 0? for CMIR */
98   	#define DEFAULT_DYNAMICCUTS                TRUE   /**< should generated cuts be removed from the LP if they are no longer tight? */
99   	#define DEFAULT_MODELTYPE                     0   /**< model type of network (0: auto, 1:directed, 2:undirected) */
100  	#define DEFAULT_MAXSEPACUTS                 100   /**< maximal number of cuts separated per separation round (-1: unlimited) */
101  	#define DEFAULT_MAXSEPACUTSROOT             200   /**< maximal number of cuts separated per separation round in root node (-1: unlimited) */
102  	#define DEFAULT_MAXINCONSISTENCYRATIO       0.02  /**< maximum inconsistency ratio (inconsistencies/(arcs*commodities)) at all */
103  	#define DEFAULT_MAXARCINCONSISTENCYRATIO     0.5 /**< maximum inconsistency ratio for arcs not to be deleted */
104  	#define DEFAULT_CHECKCUTSHORECONNECTIVITY   TRUE  /**< should we only separate if the cuts shores are connected */
105  	#define DEFAULT_SEPARATESINGLENODECUTS      TRUE  /**< should we separate inequalities based on single node cuts */
106  	#define DEFAULT_SEPARATEFLOWCUTSET          TRUE  /**< should we separate flowcutset inequalities */
107  	#define DEFAULT_SEPARATEKNAPSACK            TRUE  /**< should we separate knapsack cover inequalities */
108  	
109  	/* fixed parameters */
110  	#define BOUNDSWITCH                         0.5
111  	#define POSTPROCESS                        TRUE
112  	#define USEVBDS                            TRUE
113  	#define MINFRAC                            0.05
114  	#define MAXFRAC                           0.999
115  	
116  	#define MAXCOLS                         2000000 /**< maximum number of columns */
117  	#define MAXAGGRLEN(nvars)                  (0.1*(nvars)+1000) /**< maximal length of base inequality */
118  	#define MINCOLROWRATIO                     0.01 /**< minimum ratio cols/rows for the separator to be switched on */
119  	#define MAXCOLROWRATIO                    100.0 /**< maximum ratio cols/rows for the separator to be switched on */
120  	#define MAXFLOWVARFLOWROWRATIO            100.0 /**< maximum ratio flowvars/flowrows for the separator to be switched on */
121  	#define MAXARCNODERATIO                   100.0 /**< maximum ratio arcs/nodes for the separator to be switched on */
122  	#define MAXNETWORKS                           4 /**< maximum number of networks to consider */
123  	#define MAXFLOWCANDDENSITY                  0.1 /**< maximum density of rows to be accepted as flow candidates*/
124  	#define MINCOMNODESFRACTION                 0.5 /**< minimal size of commodity relative to largest commodity to keep it in the network */
125  	#define MINNODES                              3 /**< minimal number of nodes in network to keep it for separation */
126  	#define MINARCS                               3 /**< minimal number of arcs in network to keep it for separation */
127  	#define MAXCAPACITYSLACK                    0.1 /**< maximal slack of weighted capacity constraints to use in aggregation */
128  	#define UNCAPACITATEDARCSTRESHOLD           0.8 /**< threshold for the percentage of commodities an uncapacitated arc should appear in */
129  	#define HASHSIZE_NODEPAIRS                  500 /**< minimal size of hash table for nodepairs */
130  	
131  	/* #define OUTPUTGRAPH                                   should a .gml graph of the network be generated for debugging purposes? */
132  	
133  	
134  	#ifdef SCIP_DEBUG
135  	#ifndef MCF_DEBUG
136  	#define MCF_DEBUG
137  	#endif
138  	#endif
139  	
140  	#ifdef MCF_DEBUG
141  	#define MCFdebugMessage printf
142  	#else
143  	/*lint --e{506}*/
144  	/*lint --e{681}*/
145  	#define MCFdebugMessage while(FALSE) printf
146  	#endif
147  	
148  	/*
149  	 * Data structures
150  	 */
151  	
152  	/** model type of the network */
153  	enum SCIP_McfModeltype
154  	{
155  	   SCIP_MCFMODELTYPE_AUTO       = 0,         /**< model type should be detected automatically */
156  	   SCIP_MCFMODELTYPE_DIRECTED   = 1,         /**< directed network where each arc has its own capacity */
157  	   SCIP_MCFMODELTYPE_UNDIRECTED = 2          /**< directed network where anti-parallel arcs share the capacity */
158  	};
159  	typedef enum SCIP_McfModeltype SCIP_MCFMODELTYPE;
160  	
161  	/** effort level for separation */
162  	enum McfEffortLevel
163  	{
164  	   MCFEFFORTLEVEL_OFF        = 0,            /**< no separation */
165  	   MCFEFFORTLEVEL_DEFAULT    = 1,            /**< conservative separation */
166  	   MCFEFFORTLEVEL_AGGRESSIVE = 2             /**< aggressive separation */
167  	};
168  	typedef enum McfEffortLevel MCFEFFORTLEVEL;
169  	
170  	/** extracted multi-commodity-flow network */
171  	struct SCIP_McfNetwork
172  	{
173  	   SCIP_ROW***           nodeflowrows;       /**< nodeflowrows[v][k]: flow conservation constraint for node v and
174  	                                              *   commodity k; NULL if this node does not exist in the commodity */
175  	   SCIP_Real**           nodeflowscales;     /**< scaling factors to convert nodeflowrows[v][k] into a +/-1 <= row */
176  	   SCIP_Bool**           nodeflowinverted;   /**< does nodeflowrows[v][k] have to be inverted to fit the network structure? */
177  	   SCIP_ROW**            arccapacityrows;    /**< arccapacity[a]: capacity constraint on arc a;
178  	                                              *   NULL if uncapacitated */
179  	   SCIP_Real*            arccapacityscales;  /**< scaling factors to convert arccapacity[a] into a <= row with
180  	                                              *   positive entries for the flow variables */
181  	   int*                  arcsources;         /**< source node ids of arcs */
182  	   int*                  arctargets;         /**< target node ids of arcs */
183  	   int*                  colcommodity;       /**< commodity number of each column, or -1 */
184  	   int                   nnodes;             /**< number of nodes in the graph */
185  	   int                   narcs;              /**< number of arcs in the graph */
186  	   int                   nuncapacitatedarcs; /**< number of uncapacitated arcs in the graph */
187  	   int                   ncommodities;       /**< number of commodities */
188  	   SCIP_MCFMODELTYPE     modeltype;          /**< detected model type of the network */
189  	};
190  	typedef struct SCIP_McfNetwork SCIP_MCFNETWORK;
191  	
192  	/** separator data */
193  	struct SCIP_SepaData
194  	{
195  	   SCIP_MCFNETWORK**     mcfnetworks;        /**< array of multi-commodity-flow network structures */
196  	   int                   nmcfnetworks;       /**< number of multi-commodity-flow networks (-1: extraction not yet done) */
197  	   int                   nclusters;          /**< number of clusters to generate in the shrunken network -- default separation */
198  	   SCIP_Real             maxweightrange;     /**< maximal valid range max(|weights|)/min(|weights|) of row weights */
199  	   int                   maxtestdelta;       /**< maximal number of different deltas to try (-1: unlimited)  -- default separation */
200  	   SCIP_Bool             trynegscaling;      /**< should negative values also be tested in scaling? */
201  	   SCIP_Bool             fixintegralrhs;     /**< should an additional variable be complemented if f0 = 0? */
202  	   SCIP_Bool             dynamiccuts;        /**< should generated cuts be removed from the LP if they are no longer tight? */
203  	   int                   modeltype;          /**< model type of the network */
204  	   int                   maxsepacuts;        /**< maximal number of cmir cuts separated per separation round */
205  	   int                   maxsepacutsroot;    /**< maximal number of cmir cuts separated per separation round in root node -- default separation */
206  	   SCIP_Real             maxinconsistencyratio; /**< maximum inconsistency ratio (inconsistencies/(arcs*commodities)) for separation at all*/
207  	   SCIP_Real             maxarcinconsistencyratio; /**< maximum inconsistency ratio for arcs not to be deleted */
208  	   SCIP_Bool             checkcutshoreconnectivity;/**< should we only separate if the cuts shores are connected */
209  	   SCIP_Bool             separatesinglenodecuts; /**< should we separate inequalities based on single node cuts ? */
210  	   SCIP_Bool             separateflowcutset; /**< should we separate flowcutset inequalities on the network cuts ? */
211  	   SCIP_Bool             separateknapsack;   /**< should we separate knapsack cover inequalities on the network cuts ? */
212  	   SCIP_Bool             lastroundsuccess;   /**< did we find a cut in the last round? */
213  	   MCFEFFORTLEVEL        effortlevel;        /**< effort level of separation (off / aggressive / default) */
214  	};
215  	
216  	/** internal MCF extraction data to pass to subroutines */
217  	struct mcfdata
218  	{
219  	   unsigned char*        flowrowsigns;       /**< potential or actual sides of rows to be used as flow conservation constraint */
220  	   SCIP_Real*            flowrowscalars;     /**< scalar of rows to transform into +/-1 coefficients */
221  	   SCIP_Real*            flowrowscores;      /**< score value indicating how sure we are that this is indeed a flow conservation constraint */
222  	   unsigned char*        capacityrowsigns;   /**< potential or actual sides of rows to be used as capacity constraint */
223  	   SCIP_Real*            capacityrowscores;  /**< score value indicating how sure we are that this is indeed a capacity constraint */
224  	   int*                  flowcands;          /**< list of row indices that are candidates for flow conservation constraints */
225  	   int                   nflowcands;         /**< number of elements in flow candidate list */
226  	   int*                  capacitycands;      /**< list of row indices that are candidates for capacity constraints */
227  	   int                   ncapacitycands;     /**< number of elements in capacity candidate list */
228  	   SCIP_Bool*            plusflow;           /**< is column c member of a flow row with coefficient +1? */
229  	   SCIP_Bool*            minusflow;          /**< is column c member of a flow row with coefficient -1? */
230  	   int                   ncommodities;       /**< number of commodities */
231  	   int                   nemptycommodities;  /**< number of commodities that have been discarded but still counted in 'ncommodities' */
232  	   int*                  commoditysigns;     /**< +1: regular, -1: all arcs have opposite direction; 0: undecided */
233  	   int                   commoditysignssize; /**< size of commoditysigns array */
234  	   int*                  colcommodity;       /**< commodity number of each column, or -1 */
235  	   int*                  rowcommodity;       /**< commodity number of each row, or -1 */
236  	   int*                  colarcid;           /**< arc id of each flow column, or -1 */
237  	   int*                  rowarcid;           /**< arc id of each capacity row, or -1 */
238  	   int*                  rownodeid;          /**< node id of each flow conservation row, or -1 */
239  	   int                   arcarraysize;       /**< size  of arrays indexed by arcs */
240  	   int*                  arcsources;         /**< source node ids of arcs */
241  	   int*                  arctargets;         /**< target node ids of arcs */
242  	   int*                  colsources;         /**< source node for flow columns, -1 for non existing, -2 for unknown */
243  	   int*                  coltargets;         /**< target node for flow columns, -1 for non existing, -2 for unknown */
244  	   int*                  firstoutarcs;       /**< for each node the first arc id for which the node is the source node */
245  	   int*                  firstinarcs;        /**< for each node the first arc id for which the node is the target node */
246  	   int*                  nextoutarcs;        /**< for each arc the next outgoing arc in the adjacency list */
247  	   int*                  nextinarcs;         /**< for each arc the next outgoing arc in the adjacency list */
248  	   int*                  newcols;            /**< columns of current commodity that have to be inspected for incident flow conservation rows */
249  	   int                   nnewcols;           /**< number of newcols */
250  	   int                   narcs;              /**< number of arcs in the extracted graph */
251  	   int                   nnodes;             /**< number of nodes in the extracted graph */
252  	   SCIP_Real             ninconsistencies;   /**< number of inconsistencies between the commodity graphs */
253  	   SCIP_ROW**            capacityrows;       /**< capacity row for each arc */
254  	   int                   capacityrowssize;   /**< size of array */
255  	   SCIP_Bool*            colisincident;      /**< temporary memory for column collection */
256  	   int*                  zeroarcarray;       /**< temporary array of zeros */
257  	   SCIP_MCFMODELTYPE     modeltype;          /**< model type that is used for this network extraction */
258  	};
259  	typedef struct mcfdata MCFDATA;              /**< internal MCF extraction data to pass to subroutines */
260  	
261  	/** data structure to put a nodepair on the heap -- it holds node1 <= node2 */
262  	struct nodepair
263  	{
264  	   int                   node1;              /**< index of the first node */
265  	   int                   node2;              /**< index of the second node */
266  	   SCIP_Real             weight;             /**< weight of the arc in the separation problem */
267  	};
268  	typedef struct nodepair NODEPAIRENTRY;
269  	
270  	/** nodepair priority queue */
271  	struct nodepairqueue
272  	{
273  	   SCIP_PQUEUE*          pqueue;             /**< priority queue of elements */
274  	   NODEPAIRENTRY*        nodepairs;          /**< elements on the heap */
275  	};
276  	typedef struct nodepairqueue NODEPAIRQUEUE;
277  	
278  	/** partitioning of the nodes into clusters */
279  	struct nodepartition
280  	{
281  	   int*                  representatives;    /**< mapping of node ids to their representatives within their cluster */
282  	   int*                  nodeclusters;       /**< cluster for each node id */
283  	   int*                  clusternodes;       /**< node ids sorted by cluster */
284  	   int*                  clusterbegin;       /**< first entry in clusternodes for each cluster (size: nclusters+1) */
285  	   int                   nclusters;          /**< number of clusters */
286  	};
287  	typedef struct nodepartition NODEPARTITION;
288  	
289  	/*
290  	 * Local methods
291  	 */
292  	
293  	#define LHSPOSSIBLE     1u                   /**< we may use the constraint as lhs <= a*x */
294  	#define RHSPOSSIBLE     2u                   /**< we may use the constraint as a*x <= rhs */
295  	#define LHSASSIGNED     4u                   /**< we have chosen to use the constraint as lhs <= a*x */
296  	#define RHSASSIGNED     8u                   /**< we have chosen to use the constraint as a*x <= rhs */
297  	#define INVERTED       16u                   /**< we need to invert the row */
298  	#define DISCARDED      32u                   /**< we have chosen to not use the constraint */
299  	#define UNDIRECTED     64u                   /**< the capacity candidate has two flow variables for a commodity */
300  	
301  	
302  	/** creates an empty MCF network data structure */
303  	static
304  	SCIP_RETCODE mcfnetworkCreate(
305  	   SCIP*                 scip,               /**< SCIP data structure */
306  	   SCIP_MCFNETWORK**     mcfnetwork          /**< MCF network structure */
307  	   )
308  	{
309  	   assert(mcfnetwork != NULL);
310  	
311  	   SCIP_CALL( SCIPallocBlockMemory(scip, mcfnetwork) );
312  	   (*mcfnetwork)->nodeflowrows = NULL;
313  	   (*mcfnetwork)->nodeflowscales = NULL;
314  	   (*mcfnetwork)->nodeflowinverted = NULL;
315  	   (*mcfnetwork)->arccapacityrows = NULL;
316  	   (*mcfnetwork)->arccapacityscales = NULL;
317  	   (*mcfnetwork)->arcsources = NULL;
318  	   (*mcfnetwork)->arctargets = NULL;
319  	   (*mcfnetwork)->colcommodity = NULL;
320  	   (*mcfnetwork)->nnodes = 0;
321  	   (*mcfnetwork)->nuncapacitatedarcs = 0;
322  	   (*mcfnetwork)->narcs = 0;
323  	   (*mcfnetwork)->ncommodities = 0;
324  	
325  	   return SCIP_OKAY;
326  	}
327  	
328  	/** frees MCF network data structure */
329  	static
330  	SCIP_RETCODE mcfnetworkFree(
331  	   SCIP*                 scip,               /**< SCIP data structure */
332  	   SCIP_MCFNETWORK**     mcfnetwork          /**< MCF network structure */
333  	   )
334  	{
335  	   assert(mcfnetwork != NULL);
336  	
337  	   if( *mcfnetwork != NULL )
338  	   {
339  	      int v;
340  	      int a;
341  	
342  	      for( v = 0; v < (*mcfnetwork)->nnodes; v++ )
343  	      {
344  	         int k;
345  	
346  	         for( k = 0; k < (*mcfnetwork)->ncommodities; k++ )
347  	         {
348  	            if( (*mcfnetwork)->nodeflowrows[v][k] != NULL )
349  	            {
350  	               SCIP_CALL( SCIPreleaseRow(scip, &(*mcfnetwork)->nodeflowrows[v][k]) );
351  	            }
352  	         }
353  	         SCIPfreeBlockMemoryArrayNull(scip, &(*mcfnetwork)->nodeflowrows[v], (*mcfnetwork)->ncommodities);
354  	         SCIPfreeBlockMemoryArrayNull(scip, &(*mcfnetwork)->nodeflowscales[v], (*mcfnetwork)->ncommodities);
355  	         SCIPfreeBlockMemoryArrayNull(scip, &(*mcfnetwork)->nodeflowinverted[v], (*mcfnetwork)->ncommodities);
356  	      }
357  	      for( a = 0; a < (*mcfnetwork)->narcs; a++ )
358  	      {
359  	         if( (*mcfnetwork)->arccapacityrows[a] != NULL )
360  	         {
361  	            SCIP_CALL( SCIPreleaseRow(scip, &(*mcfnetwork)->arccapacityrows[a]) );
362  	         }
363  	      }
364  	      SCIPfreeBlockMemoryArrayNull(scip, &(*mcfnetwork)->nodeflowrows, (*mcfnetwork)->nnodes);
365  	      SCIPfreeBlockMemoryArrayNull(scip, &(*mcfnetwork)->nodeflowscales, (*mcfnetwork)->nnodes);
366  	      SCIPfreeBlockMemoryArrayNull(scip, &(*mcfnetwork)->nodeflowinverted, (*mcfnetwork)->nnodes);
367  	      SCIPfreeBlockMemoryArrayNull(scip, &(*mcfnetwork)->arccapacityrows, (*mcfnetwork)->narcs);
368  	      SCIPfreeBlockMemoryArrayNull(scip, &(*mcfnetwork)->arccapacityscales, (*mcfnetwork)->narcs);
369  	      SCIPfreeBlockMemoryArrayNull(scip, &(*mcfnetwork)->arcsources, (*mcfnetwork)->narcs);
370  	      SCIPfreeBlockMemoryArrayNull(scip, &(*mcfnetwork)->arctargets, (*mcfnetwork)->narcs);
371  	      SCIPfreeMemoryArrayNull(scip, &(*mcfnetwork)->colcommodity);
372  	
373  	      SCIPfreeBlockMemory(scip, mcfnetwork);
374  	   }
375  	
376  	   return SCIP_OKAY;
377  	}
378  	
379  	/** fills the MCF network structure with the MCF data */
380  	static
381  	SCIP_RETCODE mcfnetworkFill(
382  	   SCIP*                 scip,               /**< SCIP data structure */
383  	   SCIP_MCFNETWORK*      mcfnetwork,         /**< MCF network structure */
384  	   MCFDATA*              mcfdata,            /**< internal MCF extraction data to pass to subroutines */
385  	   int*                  compnodeid,         /**< temporary storage for v -> compv mapping; must be set to -1 for all v */
386  	   int*                  compnodes,          /**< array of node ids of the component */
387  	   int                   ncompnodes,         /**< number of nodes in the component */
388  	   int*                  comparcs,           /**< array of arc ids of the component */
389  	   int                   ncomparcs           /**< number of arcs in the component */
390  	   )
391  	{
392  	   unsigned char*    flowrowsigns     = mcfdata->flowrowsigns;
393  	   SCIP_Real*        flowrowscalars   = mcfdata->flowrowscalars;
394  	   unsigned char*    capacityrowsigns = mcfdata->capacityrowsigns;
395  	   int*              flowcands        = mcfdata->flowcands;
396  	   int               nflowcands       = mcfdata->nflowcands;
397  	   int               ncommodities     = mcfdata->ncommodities;
398  	   int*              commoditysigns   = mcfdata->commoditysigns;
399  	   int*              colcommodity     = mcfdata->colcommodity;
400  	   int*              rowcommodity     = mcfdata->rowcommodity;
401  	   int*              rownodeid        = mcfdata->rownodeid;
402  	   SCIP_ROW**        capacityrows     = mcfdata->capacityrows;
403  	   SCIP_MCFMODELTYPE modeltype        = mcfdata->modeltype;
404  	
405  	   SCIP_Real* comdemands;
406  	   SCIP_ROW** rows;
407  	   SCIP_COL** cols;
408  	   int nrows;
409  	   int ncols;
410  	   int* compcommodity;
411  	   int ncompcommodities;
412  	   int v;
413  	   int a;
414  	   int k;
415  	   int i;
416  	   int c;
417  	
418  	   assert(mcfnetwork != NULL);
419  	   assert(modeltype != SCIP_MCFMODELTYPE_AUTO);
420  	   assert(2 <= ncompnodes && ncompnodes <= mcfdata->nnodes);
421  	   assert(1 <= ncomparcs && ncomparcs <= mcfdata->narcs);
422  	   assert(ncommodities > 0);
423  	
424  	#ifndef NDEBUG
425  	   /* v -> compv mapping must be all -1 */
426  	   for( v = 0; v < mcfdata->nnodes; v++ )
427  	      assert(compnodeid[v] == -1);
428  	#endif
429  	
430  	   /* allocate temporary memory */
431  	   SCIP_CALL( SCIPallocBufferArray(scip, &comdemands, ncommodities) );
432  	   SCIP_CALL( SCIPallocBufferArray(scip, &compcommodity, ncommodities) );
433  	
434  	   /* initialize demand array */
435  	   BMSclearMemoryArray(comdemands, ncommodities);
436  	
437  	   /* initialize k -> compk mapping */
438  	   for( k = 0; k < ncommodities; k++ )
439  	      compcommodity[k] = -1;
440  	
441  	   /* get LP rows and cols data */
442  	   SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
443  	   SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
444  	
445  	   /* generate v -> compv mapping */
446  	   for( i = 0; i < ncompnodes; i++ )
447  	   {
448  	      v = compnodes[i];
449  	      assert(0 <= v && v < mcfdata->nnodes);
450  	      compnodeid[v] = i;
451  	   }
452  	
453  	   /* generate k -> compk mapping */
454  	   ncompcommodities = 0;
455  	   for( i = 0; i < nflowcands; i++ )
456  	   {
457  	      int r;
458  	      int rv;
459  	
460  	      r = flowcands[i];
461  	      assert(0 <= r && r < nrows);
462  	
463  	      rv = rownodeid[r];
464  	      if( rv >= 0 && compnodeid[rv] >= 0 )
465  	      {
466  	         k = rowcommodity[r];
467  	         assert(0 <= k && k < ncommodities);
468  	         if( compcommodity[k] == -1 )
469  	         {
470  	            compcommodity[k] = ncompcommodities;
471  	            ncompcommodities++;
472  	         }
473  	      }
474  	   }
475  	
476  	   /** @todo model type and flow type may be different for each component */
477  	   /* record model and flow type */
478  	   mcfnetwork->modeltype = modeltype;
479  	
480  	   /* record network size */
481  	   mcfnetwork->nnodes = ncompnodes;
482  	   mcfnetwork->narcs = ncomparcs;
483  	   mcfnetwork->nuncapacitatedarcs = 0;
484  	   mcfnetwork->ncommodities = ncompcommodities;
485  	
486  	   /* allocate memory for arrays and initialize with default values */
487  	   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &mcfnetwork->nodeflowrows, mcfnetwork->nnodes) );
488  	   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &mcfnetwork->nodeflowscales, mcfnetwork->nnodes) );
489  	   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &mcfnetwork->nodeflowinverted, mcfnetwork->nnodes) );
490  	   for( v = 0; v < mcfnetwork->nnodes; v++ )
491  	   {
492  	      SCIP_CALL( SCIPallocBlockMemoryArray(scip, &mcfnetwork->nodeflowrows[v], mcfnetwork->ncommodities) ); /*lint !e866*/
493  	      SCIP_CALL( SCIPallocBlockMemoryArray(scip, &mcfnetwork->nodeflowscales[v], mcfnetwork->ncommodities) ); /*lint !e866*/
494  	      SCIP_CALL( SCIPallocBlockMemoryArray(scip, &mcfnetwork->nodeflowinverted[v], mcfnetwork->ncommodities) ); /*lint !e866*/
495  	      for( k = 0; k < mcfnetwork->ncommodities; k++ )
496  	      {
497  	         mcfnetwork->nodeflowrows[v][k] = NULL;
498  	         mcfnetwork->nodeflowscales[v][k] = 0.0;
499  	         mcfnetwork->nodeflowinverted[v][k] = FALSE;
500  	      }
501  	   }
502  	
503  	   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &mcfnetwork->arccapacityrows, mcfnetwork->narcs) );
504  	   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &mcfnetwork->arccapacityscales, mcfnetwork->narcs) );
505  	   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &mcfnetwork->arcsources, mcfnetwork->narcs) );
506  	   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &mcfnetwork->arctargets, mcfnetwork->narcs) );
507  	   SCIP_CALL( SCIPallocMemoryArray(scip, &mcfnetwork->colcommodity, ncols) );
508  	   for( a = 0; a < mcfnetwork->narcs; a++ )
509  	   {
510  	      mcfnetwork->arcsources[a] = -1;
511  	      mcfnetwork->arctargets[a] = -1;
512  	   }
513  	   BMSclearMemoryArray(mcfnetwork->arccapacityrows, mcfnetwork->narcs);
514  	   BMSclearMemoryArray(mcfnetwork->arccapacityscales, mcfnetwork->narcs);
515  	   BMSclearMemoryArray(mcfnetwork->colcommodity, mcfnetwork->ncommodities);
516  	
517  	   /* fill in existing node data */
518  	   for( i = 0; i < nflowcands; i++ )
519  	   {
520  	      int r;
521  	      int rv;
522  	
523  	      r = flowcands[i];
524  	      assert(0 <= r && r < nrows);
525  	
526  	      rv = rownodeid[r];
527  	      if( rv >= 0 && compnodeid[rv] >= 0 )
528  	      {
529  	         SCIP_Real scale;
530  	         int rk;
531  	
532  	         v = compnodeid[rv];
533  	         rk = rowcommodity[r];
534  	         assert(v < mcfnetwork->nnodes);
535  	         assert(0 <= rk && rk < ncommodities);
536  	         assert((flowrowsigns[r] & (LHSASSIGNED | RHSASSIGNED)) != 0);
537  	
538  	         k = compcommodity[rk];
539  	         assert(0 <= k && k < mcfnetwork->ncommodities);
540  	
541  	         /* fill in node -> row assignment */
542  	         SCIP_CALL( SCIPcaptureRow(scip, rows[r]) );
543  	         mcfnetwork->nodeflowrows[v][k] = rows[r];
544  	         scale = flowrowscalars[r];
545  	         if( (flowrowsigns[r] & LHSASSIGNED) != 0 )
546  	            scale *= -1.0;
547  	         if( commoditysigns[rk] == -1 )
548  	            scale *= -1.0;
549  	         mcfnetwork->nodeflowscales[v][k] = scale;
550  	         mcfnetwork->nodeflowinverted[v][k] = ((flowrowsigns[r] & INVERTED) != 0);
551  	      }
552  	   }
553  	
554  	   /* fill in existing arc data */
555  	   for( a = 0; a < mcfnetwork->narcs; a++ )
556  	   {
557  	      SCIP_ROW* capacityrow;
558  	      SCIP_COL** rowcols;
559  	      SCIP_Real* rowvals;
560  	      int rowlen;
561  	      int globala;
562  	      int r;
563  	      int j;
564  	
565  	      globala = comparcs[a];
566  	      capacityrow = capacityrows[globala];
567  	
568  	      mcfnetwork->arccapacityscales[a] = 1.0;
569  	
570  	      /* If arc is capacitated */
571  	      if( capacityrow != NULL)
572  	      {
573  	         r = SCIProwGetLPPos(capacityrow);
574  	         assert(0 <= r && r < nrows);
575  	         assert((capacityrowsigns[r] & (LHSASSIGNED | RHSASSIGNED)) != 0);
576  	         assert((capacityrowsigns[r] & INVERTED) == 0);
577  	         assert(mcfdata->rowarcid[r] == globala);
578  	
579  	         SCIP_CALL( SCIPcaptureRow(scip, capacityrow) );
580  	         mcfnetwork->arccapacityrows[a] = capacityrow;
581  	
582  	         /* Scale constraint such that the coefficients for the flow variables are normalized in such a way that coefficients in
583  	          * multiple capacity constraints that belong to the same commodity are (hopefully) equal.
584  	          * This is needed for binary flow variable models in which the demand of each commodity is stored as the coefficient in
585  	          * the capacity constraints. Since it may happen (e.g., due to presolve) that different capacity constraints are scaled
586  	          * differently, we need to find scaling factors to make the demand coefficients of each commodity equal.
587  	          * To do this, we scale the first capacity constraint with +1 and then store the coefficients of the flow variables
588  	          * as target demands for the commodities. Then, we scale the other constraints in such a way that these demands are hit, if possible.
589  	          * Note that for continuous flow variable models, the coefficients in the capacity constraints are usually +1.0.
590  	          * This is achieved automatically by our scaling routine.
591  	          */
592  	         rowcols = SCIProwGetCols(capacityrow);
593  	         rowvals = SCIProwGetVals(capacityrow);
594  	         rowlen = SCIProwGetNLPNonz(capacityrow);
595  	         for( j = 0; j < rowlen; j++ )
596  	         {
597  	            c = SCIPcolGetLPPos(rowcols[j]);
598  	            assert(0 <= c && c < SCIPgetNLPCols(scip));
599  	            k = colcommodity[c];
600  	            if( k >= 0 )
601  	            {
602  	               if( comdemands[k] != 0.0 )
603  	               {
604  	                  /* update the scaling factor */
605  	                  mcfnetwork->arccapacityscales[a] = comdemands[k]/rowvals[j];
606  	                  break;
607  	               }
608  	            }
609  	         }
610  	
611  	         /* use negative scaling if we use the left hand side, use positive scaling if we use the right hand side */
612  	         mcfnetwork->arccapacityscales[a] = ABS(mcfnetwork->arccapacityscales[a]);
613  	         if( (capacityrowsigns[r] & LHSASSIGNED) != 0 )
614  	            mcfnetwork->arccapacityscales[a] *= -1.0;
615  	
616  	         /* record the commodity demands */
617  	         for( j = 0; j < rowlen; j++ )
618  	         {
619  	            c = SCIPcolGetLPPos(rowcols[j]);
620  	            assert(0 <= c && c < SCIPgetNLPCols(scip));
621  	            k = colcommodity[c];
622  	            if( k >= 0 && comdemands[k] == 0.0 )
623  	               comdemands[k] = mcfnetwork->arccapacityscales[a] * rowvals[j];
624  	         }
625  	      }
626  	      else
627  	      {
628  	         /* arc is uncapacitated */
629  	         mcfnetwork->arccapacityrows[a] = NULL;
630  	         mcfnetwork->nuncapacitatedarcs++;
631  	      }
632  	
633  	      /* copy the source/target node assignment */
634  	      if( mcfdata->arcsources[globala] >= 0 )
635  	      {
636  	         assert(mcfdata->arcsources[globala] < mcfdata->nnodes);
637  	         assert(0 <= compnodeid[mcfdata->arcsources[globala]] && compnodeid[mcfdata->arcsources[globala]] < mcfnetwork->nnodes);
638  	         mcfnetwork->arcsources[a] = compnodeid[mcfdata->arcsources[globala]];
639  	      }
640  	      if( mcfdata->arctargets[globala] >= 0 )
641  	      {
642  	         assert(mcfdata->arctargets[globala] < mcfdata->nnodes);
643  	         assert(0 <= compnodeid[mcfdata->arctargets[globala]] && compnodeid[mcfdata->arctargets[globala]] < mcfnetwork->nnodes);
644  	         mcfnetwork->arctargets[a] = compnodeid[mcfdata->arctargets[globala]];
645  	      }
646  	   }
647  	
648  	   /* translate colcommodity array */
649  	   for( c = 0; c < ncols; c++ )
650  	   {
651  	      k = colcommodity[c];
652  	      if( k >= 0 )
653  	         mcfnetwork->colcommodity[c] = compcommodity[k];
654  	      else
655  	         mcfnetwork->colcommodity[c] = -1;
656  	   }
657  	
658  	   /* reset v -> compv mapping */
659  	   for( i = 0; i < ncompnodes; i++ )
660  	   {
661  	      assert(0 <= compnodes[i] && compnodes[i] < mcfdata->nnodes);
662  	      assert(compnodeid[compnodes[i]] == i);
663  	      compnodeid[compnodes[i]] = -1;
664  	   }
665  	
666  	   /* free temporary memory */
667  	   SCIPfreeBufferArray(scip, &compcommodity);
668  	   SCIPfreeBufferArray(scip, &comdemands);
669  	
670  	   return SCIP_OKAY;
671  	}
672  	
673  	#ifdef SCIP_DEBUG
674  	/** displays the MCF network */
675  	static
676  	void mcfnetworkPrint(
677  	   SCIP_MCFNETWORK*      mcfnetwork          /**< MCF network structure */
678  	   )
679  	{
680  	   if( mcfnetwork == NULL )
681  	      MCFdebugMessage("MCF network is empty\n");
682  	   else
683  	   {
684  	      int v;
685  	      int a;
686  	
687  	      for( v = 0; v < mcfnetwork->nnodes; v++ )
688  	      {
689  	         int k;
690  	
691  	         MCFdebugMessage("node %2d:\n", v);
692  	         for( k = 0; k < mcfnetwork->ncommodities; k++ )
693  	         {
694  	            MCFdebugMessage("  commodity %2d: ", k);
695  	            if( mcfnetwork->nodeflowrows[v][k] != NULL )
696  	            {
697  	               MCFdebugMessage("<%s> [%+g] [inv:%u]\n", SCIProwGetName(mcfnetwork->nodeflowrows[v][k]),
698  	                      mcfnetwork->nodeflowscales[v][k], mcfnetwork->nodeflowinverted[v][k]);
699  	               /*SCIP_CALL( SCIProwPrint(mcfnetwork->nodeflowrows[v][k], NULL) );*/
700  	            }
701  	            else
702  	               MCFdebugMessage("-\n");
703  	         }
704  	      }
705  	
706  	      for( a = 0; a < mcfnetwork->narcs; a++ )
707  	      {
708  	         MCFdebugMessage("arc %2d [%2d -> %2d]: ", a, mcfnetwork->arcsources[a], mcfnetwork->arctargets[a]);
709  	         if( mcfnetwork->arccapacityrows[a] != NULL )
710  	         {
711  	            MCFdebugMessage("<%s> [%+g]\n", SCIProwGetName(mcfnetwork->arccapacityrows[a]), mcfnetwork->arccapacityscales[a]);
712  	            /*SCIProwPrint(mcfnetwork->arccapacityrows[a], NULL);*/
713  	         }
714  	         else
715  	            MCFdebugMessage("-\n");
716  	      }
717  	   }
718  	}
719  	
720  	/** displays commodities and its members */
721  	static
722  	void printCommodities(
723  	   SCIP*                 scip,               /**< SCIP data structure */
724  	   MCFDATA*              mcfdata             /**< internal MCF extraction data to pass to subroutines */
725  	   )
726  	{
727  	   unsigned char* flowrowsigns     = mcfdata->flowrowsigns;
728  	   unsigned char* capacityrowsigns = mcfdata->capacityrowsigns;
729  	   int            ncommodities     = mcfdata->ncommodities;
730  	   int*           commoditysigns   = mcfdata->commoditysigns;
731  	   int*           colcommodity     = mcfdata->colcommodity;
732  	   int*           rowcommodity     = mcfdata->rowcommodity;
733  	   int*           colarcid         = mcfdata->colarcid;
734  	   int*           rownodeid        = mcfdata->rownodeid;
735  	   int            nnodes           = mcfdata->nnodes;
736  	   SCIP_ROW**     capacityrows     = mcfdata->capacityrows;
737  	
738  	   SCIP_COL** cols;
739  	   SCIP_ROW** rows;
740  	   int ncols;
741  	   int nrows;
742  	   int k;
743  	   int c;
744  	   int r;
745  	   int a;
746  	
747  	   cols = SCIPgetLPCols(scip);
748  	   ncols = SCIPgetNLPCols(scip);
749  	   rows = SCIPgetLPRows(scip);
750  	   nrows = SCIPgetNLPRows(scip);
751  	
752  	   for( k = 0; k < ncommodities; k++ )
753  	   {
754  	      MCFdebugMessage("commodity %d (sign: %+d):\n", k, commoditysigns[k]);
755  	
756  	      for( c = 0; c < ncols; c++ )
757  	      {
758  	         if( colcommodity[c] == k )
759  	            MCFdebugMessage(" col <%s>: arc %d\n", SCIPvarGetName(SCIPcolGetVar(cols[c])), colarcid != NULL ? colarcid[c] : -1);
760  	      }
761  	      for( r = 0; r < nrows; r++ )
762  	      {
763  	         if( rowcommodity[r] == k )
764  	            MCFdebugMessage(" row <%s>: node %d [sign:%+d, inv:%+d]\n", SCIProwGetName(rows[r]), rownodeid != NULL ? rownodeid[r] : -1,
765  	                   (flowrowsigns[r] & RHSASSIGNED) != 0 ? +1 : -1,
766  	                   (flowrowsigns[r] & INVERTED) != 0 ? -1 : +1);
767  	      }
768  	      MCFdebugMessage("\n");
769  	   }
770  	
771  	   if( rownodeid != NULL )
772  	   {
773  	      int v;
774  	
775  	      for( v = 0; v < nnodes; v++ )
776  	      {
777  	         MCFdebugMessage("node %d:\n", v);
778  	         for( r = 0; r < nrows; r++ )
779  	         {
780  	            if( rownodeid[r] == v )
781  	               MCFdebugMessage(" row <%s> [sign:%+d, inv:%+d]\n", SCIProwGetName(rows[r]),
782  	                      (flowrowsigns[r] & RHSASSIGNED) != 0 ? +1 : -1,
783  	                      (flowrowsigns[r] & INVERTED) != 0 ? -1 : +1);
784  	         }
785  	         MCFdebugMessage("\n");
786  	      }
787  	   }
788  	
789  	   assert(capacityrows != NULL || mcfdata->narcs == 0);
790  	
791  	   MCFdebugMessage("capacities:\n");
792  	   for( a = 0; a < mcfdata->narcs; a++ )
793  	   {
794  	      MCFdebugMessage("  arc %d: ", a);
795  	      if( capacityrows[a] != NULL ) /*lint !e613*/
796  	      {
797  	         r = SCIProwGetLPPos(capacityrows[a]); /*lint !e613*/
798  	         assert(0 <= r && r < nrows);
799  	         if( (capacityrowsigns[r] & LHSASSIGNED) != 0 )
800  	            MCFdebugMessage(" row <%s> [sign:-1]\n", SCIProwGetName(rows[r]));
801  	         else if( (capacityrowsigns[r] & RHSASSIGNED) != 0 )
802  	            MCFdebugMessage(" row <%s> [sign:+1]\n", SCIProwGetName(rows[r]));
803  	      }
804  	      else
805  	         MCFdebugMessage(" -\n");
806  	   }
807  	   MCFdebugMessage("\n");
808  	
809  	   assert(colcommodity != NULL || ncols == 0);
810  	
811  	   MCFdebugMessage("unused columns:\n");
812  	   for( c = 0; c < ncols; c++ )
813  	   {
814  	      if( colcommodity[c] == -1 ) /*lint !e613*/
815  	      {
816  	         SCIP_VAR* var = SCIPcolGetVar(cols[c]);
817  	         MCFdebugMessage(" col <%s> [%g,%g]\n", SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
818  	      }
819  	   }
820  	   MCFdebugMessage("\n");
821  	
822  	   MCFdebugMessage("unused rows:\n");
823  	   for( r = 0; r < nrows; r++ )
824  	   {
825  	      assert(rowcommodity != NULL);
826  	
827  	      if( rowcommodity[r] == -1 && (capacityrowsigns == NULL || (capacityrowsigns[r] & (LHSASSIGNED | RHSASSIGNED)) == 0) )
828  	      {
829  	         MCFdebugMessage(" row <%s>\n", SCIProwGetName(rows[r]));
830  	         /*SCIPdebug( SCIP_CALL(SCIPprintRow(scip, rows[r], NULL)) );*/
831  	      }
832  	   }
833  	   MCFdebugMessage("\n");
834  	}
835  	#endif
836  	
837  	/** comparator method for flow and capacity row candidates */
838  	static
839  	SCIP_DECL_SORTINDCOMP(compCands)
840  	{
841  	   SCIP_Real* rowscores = (SCIP_Real*)dataptr;
842  	
843  	   if( rowscores[ind2] < rowscores[ind1] )
844  	      return -1;
845  	   else if( rowscores[ind2] > rowscores[ind1] )
846  	      return +1;
847  	   else
848  	      return 0;
849  	}
850  	
851  	/** extracts flow conservation from the LP */
852  	static
853  	SCIP_RETCODE extractFlowRows(
854  	   SCIP*                 scip,               /**< SCIP data structure */
855  	   MCFDATA*              mcfdata             /**< internal MCF extraction data to pass to subroutines */
856  	   )
857  	{
858  	   unsigned char* flowrowsigns;
859  	   SCIP_Real*     flowrowscalars;
860  	   SCIP_Real*     flowrowscores;
861  	   int*           flowcands;
862  	
863  	   SCIP_ROW** rows;
864  	   int nrows;
865  	   int ncols;
866  	   int r;
867  	
868  	   SCIP_Real maxdualflow;
869  	
870  	   SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
871  	   ncols = SCIPgetNLPCols(scip);
872  	
873  	   /* allocate temporary memory for extraction data */
874  	   SCIP_CALL( SCIPallocMemoryArray(scip, &mcfdata->flowrowsigns, nrows) ); /*lint !e685*/
875  	   SCIP_CALL( SCIPallocMemoryArray(scip, &mcfdata->flowrowscalars, nrows) );
876  	   SCIP_CALL( SCIPallocMemoryArray(scip, &mcfdata->flowrowscores, nrows) );
877  	   SCIP_CALL( SCIPallocMemoryArray(scip, &mcfdata->flowcands, nrows) );
878  	   flowrowsigns      = mcfdata->flowrowsigns;
879  	   flowrowscalars    = mcfdata->flowrowscalars;
880  	   flowrowscores     = mcfdata->flowrowscores;
881  	   flowcands         = mcfdata->flowcands;
882  	
883  	   assert(mcfdata->nflowcands == 0);
884  	
885  	   maxdualflow = 0.0;
886  	   for( r = 0; r < nrows; r++ )
887  	   {
888  	      SCIP_ROW* row;
889  	      SCIP_COL** rowcols;
890  	      SCIP_Real* rowvals;
891  	      SCIP_Real rowlhs;
892  	      SCIP_Real rowrhs;
893  	      int rowlen;
894  	      int nbinvars;
895  	      int nintvars;
896  	      int nimplintvars;
897  	      int ncontvars;
898  	      SCIP_Real coef;
899  	      SCIP_Bool hasposcoef;
900  	      SCIP_Bool hasnegcoef;
901  	      SCIP_Real absdualsol;
902  	      int i;
903  	
904  	      row = rows[r];
905  	      assert(SCIProwGetLPPos(row) == r);
906  	
907  	      /* get dual solution, if available */
908  	      absdualsol = SCIProwGetDualsol(row);
909  	      if( absdualsol == SCIP_INVALID ) /*lint !e777*/
910  	         absdualsol = 0.0;
911  	      absdualsol = ABS(absdualsol);
912  	
913  	      flowrowsigns[r] = 0;
914  	      flowrowscalars[r] = 0.0;
915  	      flowrowscores[r] = 0.0;
916  	
917  	      /* ignore modifiable rows */
918  	      if( SCIProwIsModifiable(row) )
919  	         continue;
920  	
921  	      /* ignore empty rows */
922  	      rowlen = SCIProwGetNLPNonz(row);
923  	      if( rowlen == 0 )
924  	         continue;
925  	
926  	      /* No dense rows please */
927  	      if( rowlen > MAXFLOWCANDDENSITY * ncols )
928  	         continue;
929  	
930  	      rowcols = SCIProwGetCols(row);
931  	      rowvals = SCIProwGetVals(row);
932  	      rowlhs  = SCIProwGetLhs(row) - SCIProwGetConstant(row);
933  	      rowrhs  = SCIProwGetRhs(row) - SCIProwGetConstant(row);
934  	
935  	      /* identify flow conservation constraints */
936  	      coef = ABS(rowvals[0]);
937  	      hasposcoef = FALSE;
938  	      hasnegcoef = FALSE;
939  	      nbinvars = 0;
940  	      nintvars = 0;
941  	      nimplintvars = 0;
942  	      ncontvars = 0;
943  	      for( i = 0; i < rowlen; i++ )
944  	      {
945  	         SCIP_Real absval = ABS(rowvals[i]);
946  	         if( !SCIPisEQ(scip, absval, coef) )
947  	            break;
948  	
949  	         hasposcoef = hasposcoef || (rowvals[i] > 0.0);
950  	         hasnegcoef = hasnegcoef || (rowvals[i] < 0.0);
951  	         switch( SCIPvarGetType(SCIPcolGetVar(rowcols[i])) )
952  	         {
953  	         case SCIP_VARTYPE_BINARY:
954  	            nbinvars++;
955  	            break;
956  	         case SCIP_VARTYPE_INTEGER:
957  	            nintvars++;
958  	            break;
959  	         case SCIP_VARTYPE_IMPLINT:
960  	            nimplintvars++;
961  	            break;
962  	         case SCIP_VARTYPE_CONTINUOUS:
963  	               ncontvars++;
964  	               break;
965  	         default:
966  	            SCIPerrorMessage("unknown variable type\n");
967  	            SCIPABORT();
968  	            return SCIP_INVALIDDATA;  /*lint !e527*/
969  	         }
970  	      }
971  	      if( i == rowlen )
972  	      {
973  	         /* Flow conservation constraints should always be a*x <= -d.
974  	          * If lhs and rhs are finite, both sides are still valid candidates.
975  	          */
976  	         if( !SCIPisInfinity(scip, -rowlhs) )
977  	            flowrowsigns[r] |= LHSPOSSIBLE;
978  	         if( !SCIPisInfinity(scip, rowrhs) )
979  	            flowrowsigns[r] |= RHSPOSSIBLE;
980  	         flowrowscalars[r] = 1.0/coef;
981  	         flowcands[mcfdata->nflowcands] = r;
982  	         mcfdata->nflowcands++;
983  	      }
984  	
985  	      /* calculate flow row score */
986  	      if( (flowrowsigns[r] & (LHSPOSSIBLE | RHSPOSSIBLE)) != 0 )
987  	      {
988  	         /* row does not need to be scaled: score +1000 */
989  	         if( SCIPisEQ(scip, flowrowscalars[r], 1.0) )
990  	            flowrowscores[r] += 1000.0;
991  	
992  	         /* row has positive and negative coefficients: score +500 */
993  	         if( hasposcoef && hasnegcoef )
994  	            flowrowscores[r] += 500.0;
995  	
996  	         /* all variables are of the same type:
997  	          *    continuous: score +1000
998  	          *    integer:    score  +500
999  	          *    binary:     score  +100
1000 	          */
1001 	         if( ncontvars == rowlen )
1002 	            flowrowscores[r] += 1000.0;
1003 	         else if( nintvars + nimplintvars == rowlen )
1004 	            flowrowscores[r] += 500.0;
1005 	         else if( nbinvars == rowlen )
1006 	            flowrowscores[r] += 100.0;
1007 	
1008 	         /* the longer the row, the earlier we want to process it: score +10*len/(len+10) */
1009 	         /* value is in [1,10) */
1010 	         flowrowscores[r] += 10.0*rowlen/(rowlen+10.0);
1011 	
1012 	         /* row is an equation: score +50, tie-breaking */
1013 	         if( (flowrowsigns[r] & (LHSPOSSIBLE | RHSPOSSIBLE)) == (LHSPOSSIBLE | RHSPOSSIBLE) )
1014 	            flowrowscores[r] += 50.0;
1015 	
1016 	         assert(flowrowscores[r] > 0.0);
1017 	
1018 	         /* update maximum dual solution value for additional score tie breaking */
1019 	         maxdualflow = MAX(maxdualflow, absdualsol);
1020 	
1021 	         /** @todo go through list of several model types, depending on the current model type throw away invalid constraints
1022 	          *       instead of assigning a low score
1023 	          */
1024 	      }
1025 	   }
1026 	
1027 	   /* apply additional score tie breaking using the dual solutions */
1028 	   if( SCIPisPositive(scip, maxdualflow) )
1029 	   {
1030 	      int i;
1031 	
1032 	      for( i = 0; i < mcfdata->nflowcands; i++ )
1033 	      {
1034 	         SCIP_Real dualsol;
1035 	
1036 	         r = flowcands[i];
1037 	         assert(0 <= r && r < nrows);
1038 	         dualsol = SCIProwGetDualsol(rows[r]);
1039 	         if( dualsol == SCIP_INVALID ) /*lint !e777*/
1040 	            dualsol = 0.0;
1041 	         else if( flowrowsigns[r] == (LHSPOSSIBLE | RHSPOSSIBLE) )
1042 	            dualsol = ABS(dualsol);
1043 	         else if( flowrowsigns[r] == RHSPOSSIBLE )
1044 	            dualsol = -dualsol;
1045 	         assert(maxdualflow > 0.0); /*for flexelint*/
1046 	         flowrowscores[r] += dualsol/maxdualflow + 1.0;
1047 	         assert(flowrowscores[r] > 0.0);
1048 	      }
1049 	   }
1050 	
1051 	   /* sort candidates by score */
1052 	   SCIPsortInd(mcfdata->flowcands, compCands, (void*)flowrowscores, mcfdata->nflowcands);
1053 	
1054 	   MCFdebugMessage("flow conservation candidates [%d]\n", mcfdata->nflowcands);
1055 	#ifdef SCIP_DEBUG
1056 	   for( r = 0; r < mcfdata->nflowcands; r++ )
1057 	   {
1058 	      /*SCIPdebug( SCIP_CALL(SCIPprintRow(scip, rows[mcfdata->flowcands[r]], NULL)) );*/
1059 	      SCIPdebugMsg(scip, "%4d [score: %2g]: %s\n", mcfdata->flowcands[r], flowrowscores[mcfdata->flowcands[r]],
1060 	                       SCIProwGetName(rows[mcfdata->flowcands[r]]));
1061 	   }
1062 	#endif
1063 	
1064 	   return SCIP_OKAY;
1065 	}
1066 	
1067 	/** extracts capacity rows from the LP */
1068 	static
1069 	SCIP_RETCODE extractCapacityRows(
1070 	   SCIP*                 scip,               /**< SCIP data structure */
1071 	   MCFDATA*              mcfdata             /**< internal MCF extraction data to pass to subroutines */
1072 	   )
1073 	{
1074 	   unsigned char*    flowrowsigns       = mcfdata->flowrowsigns;
1075 	   int*              colcommodity       = mcfdata->colcommodity;
1076 	   int               ncommodities       = mcfdata->ncommodities;
1077 	   int               nactivecommodities = mcfdata->ncommodities - mcfdata->nemptycommodities;
1078 	   SCIP_MCFMODELTYPE modeltype          = mcfdata->modeltype;
1079 	
1080 	   unsigned char* capacityrowsigns;
1081 	   SCIP_Real*     capacityrowscores;
1082 	   int*           capacitycands;
1083 	
1084 	   SCIP_ROW** rows;
1085 	   int nrows;
1086 	   int r;
1087 	
1088 	   SCIP_Real maxdualcapacity;
1089 	   int maxcolspercommoditylimit;
1090 	   int *ncolspercommodity;
1091 	   int *maxcolspercommodity;
1092 	   SCIP_Real directedcandsscore;
1093 	   SCIP_Real undirectedcandsscore;
1094 	
1095 	   SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
1096 	
1097 	   /* allocate temporary memory for extraction data */
1098 	   SCIP_CALL( SCIPallocMemoryArray(scip, &mcfdata->capacityrowsigns, nrows) ); /*lint !e685*/
1099 	   SCIP_CALL( SCIPallocMemoryArray(scip, &mcfdata->capacityrowscores, nrows) );
1100 	   SCIP_CALL( SCIPallocMemoryArray(scip, &mcfdata->capacitycands, nrows) );
1101 	   capacityrowsigns  = mcfdata->capacityrowsigns;
1102 	   capacityrowscores = mcfdata->capacityrowscores;
1103 	   capacitycands     = mcfdata->capacitycands;
1104 	
1105 	   assert(mcfdata->ncapacitycands == 0);
1106 	
1107 	   /* allocate temporary memory for model type identification */
1108 	   SCIP_CALL( SCIPallocBufferArray(scip, &ncolspercommodity, ncommodities) );
1109 	   SCIP_CALL( SCIPallocBufferArray(scip, &maxcolspercommodity, nrows) );
1110 	
1111 	   /* identify model type and set the maximal number of flow variables per capacity constraint and commodity */
1112 	   switch( modeltype )
1113 	   {
1114 	      case SCIP_MCFMODELTYPE_AUTO:
1115 	         maxcolspercommoditylimit = 2; /* will be set to 1 later if we detect that the network is directed */
1116 	         break;
1117 	      case SCIP_MCFMODELTYPE_DIRECTED:
1118 	         maxcolspercommoditylimit = 1;
1119 	         break;
1120 	      case SCIP_MCFMODELTYPE_UNDIRECTED:
1121 	         maxcolspercommoditylimit = 2;
1122 	         break;
1123 	      default:
1124 	         SCIPerrorMessage("invalid parameter value %d for model type\n", modeltype);
1125 	         return SCIP_INVALIDDATA;
1126 	   }
1127 	
1128 	   maxdualcapacity = 0.0;
1129 	   directedcandsscore = 0.0;
1130 	   undirectedcandsscore = 0.0;
1131 	   for( r = 0; r < nrows; r++ )
1132 	   {
1133 	      SCIP_ROW* row;
1134 	      SCIP_COL** rowcols;
1135 	      SCIP_Real* rowvals;
1136 	      SCIP_Real rowlhs;
1137 	      SCIP_Real rowrhs;
1138 	      int rowlen;
1139 	      int nposflowcoefs;
1140 	      int nnegflowcoefs;
1141 	      int nposcapacitycoefs;
1142 	      int nnegcapacitycoefs;
1143 	      int nbadcoefs;
1144 	      int ncoveredcommodities;
1145 	      SCIP_Real sameflowcoef;
1146 	      SCIP_Real sameabsflowcoef;
1147 	      SCIP_Real maxabscapacitycoef;
1148 	      SCIP_Real absdualsol;
1149 	      unsigned char rowsign;
1150 	      int i;
1151 	
1152 	      row = rows[r];
1153 	      assert(SCIProwGetLPPos(row) == r);
1154 	
1155 	      capacityrowsigns[r] = 0;
1156 	      capacityrowscores[r] = 0.0;
1157 	
1158 	      /* ignore modifiable rows */
1159 	      if( SCIProwIsModifiable(row) )
1160 	         continue;
1161 	
1162 	      /* ignore empty rows */
1163 	      rowlen = SCIProwGetNLPNonz(row);
1164 	      if( rowlen == 0 )
1165 	         continue;
1166 	
1167 	      /* ignore rows that have already been used as flow conservation constraints */
1168 	      if( (flowrowsigns[r] & (LHSASSIGNED | RHSASSIGNED)) != 0 )
1169 	         continue;
1170 	
1171 	      /* get dual solution, if available */
1172 	      absdualsol = SCIProwGetDualsol(row);
1173 	      if( absdualsol == SCIP_INVALID ) /*lint !e777*/
1174 	         absdualsol = 0.0;
1175 	      absdualsol = ABS(absdualsol);
1176 	
1177 	      rowcols = SCIProwGetCols(row);
1178 	      rowvals = SCIProwGetVals(row);
1179 	      rowlhs = SCIProwGetLhs(row) - SCIProwGetConstant(row);
1180 	      rowrhs = SCIProwGetRhs(row) - SCIProwGetConstant(row);
1181 	
1182 	      /* reset commodity counting array */
1183 	      BMSclearMemoryArray(ncolspercommodity, ncommodities);
1184 	      maxcolspercommodity[r] = 0;
1185 	
1186 	      /* identify capacity constraints */
1187 	      nposflowcoefs = 0;
1188 	      nnegflowcoefs = 0;
1189 	      nposcapacitycoefs = 0;
1190 	      nnegcapacitycoefs = 0;
1191 	      nbadcoefs = 0;
1192 	      ncoveredcommodities = 0;
1193 	      sameflowcoef = 0.0;
1194 	      sameabsflowcoef = 0.0;
1195 	      maxabscapacitycoef = 0.0;
1196 	
1197 	      rowsign = 0;
1198 	      if( !SCIPisInfinity(scip, -rowlhs) )
1199 	         rowsign |= LHSPOSSIBLE;
1200 	      if( !SCIPisInfinity(scip, rowrhs) )
1201 	         rowsign |= RHSPOSSIBLE;
1202 	      for( i = 0; i < rowlen; i++ )
1203 	      {
1204 	         int c;
1205 	         int k;
1206 	
1207 	         c = SCIPcolGetLPPos(rowcols[i]);
1208 	         assert(0 <= c && c < SCIPgetNLPCols(scip));
1209 	         assert(colcommodity != NULL);  /* for lint */
1210 	
1211 	         /* check if this is a flow variable */
1212 	         k = colcommodity[c];
1213 	         assert(-1 <= k && k < ncommodities);
1214 	         if( k >= 0 )
1215 	         {
1216 	            SCIP_Real abscoef;
1217 	
1218 	            abscoef = ABS(rowvals[i]);
1219 	            if( sameflowcoef == 0.0 )
1220 	               sameflowcoef = rowvals[i];
1221 	            else if( !SCIPisEQ(scip, sameflowcoef, rowvals[i]) )
1222 	               sameflowcoef = SCIP_REAL_MAX;
1223 	            if( sameabsflowcoef == 0.0 )
1224 	               sameabsflowcoef = abscoef;
1225 	            else if( !SCIPisEQ(scip, sameabsflowcoef, abscoef) )
1226 	               sameabsflowcoef = SCIP_REAL_MAX;
1227 	
1228 	            if( rowvals[i] > 0.0 )
1229 	               nposflowcoefs++;
1230 	            else
1231 	               nnegflowcoefs++;
1232 	
1233 	            /* count number of covered commodities in capacity candidate */
1234 	            if( ncolspercommodity[k] == 0 )
1235 	               ncoveredcommodities++;
1236 	            ncolspercommodity[k]++;
1237 	            maxcolspercommodity[r] = MAX(maxcolspercommodity[r], ncolspercommodity[k]);
1238 	
1239 	            if( ncolspercommodity[k] >= 2 )
1240 	               capacityrowsigns[r] |= UNDIRECTED;
1241 	         }
1242 	         else
1243 	/*             if( SCIPvarGetType(SCIPcolGetVar(rowcols[i])) != SCIP_VARTYPE_CONTINUOUS ) */
1244 	         {
1245 	            SCIP_Real abscoef;
1246 	
1247 	            /* save maximal capacity coef*/
1248 	            abscoef = ABS(rowvals[i]);
1249 	            if( abscoef > maxabscapacitycoef )
1250 	               maxabscapacitycoef = abscoef;
1251 	
1252 	            /* a variable which is not a flow variable can be used as capacity variable */
1253 	            if( rowvals[i] > 0.0 )
1254 	               nposcapacitycoefs++;
1255 	            else
1256 	               nnegcapacitycoefs++;
1257 	
1258 	            /* a continuous variable is considered to be not so nice*/
1259 	            if( SCIPvarGetType(SCIPcolGetVar(rowcols[i])) == SCIP_VARTYPE_CONTINUOUS )
1260 	               nbadcoefs++;
1261 	         }
1262 	      }
1263 	
1264 	      /* check if this is a valid capacity constraint */
1265 	      /* it has at least one flow variable */
1266 	      if( rowsign != 0 && nposflowcoefs + nnegflowcoefs > 0 )
1267 	      {
1268 	         SCIP_Real commodityexcessratio;
1269 	
1270 	         capacityrowsigns[r] |= rowsign;
1271 	         capacitycands[mcfdata->ncapacitycands] = r;
1272 	         mcfdata->ncapacitycands++;
1273 	
1274 	         /* calculate capacity row score */
1275 	         capacityrowscores[r] = 1.0;
1276 	
1277 	         /* calculate mean commodity excess: in the (un)directed case there should be exactly */
1278 	         /* one (two) flow variable per commodity. in this case commodityexcessratio = 0   */
1279 	         assert(ncoveredcommodities > 0);
1280 	         /* coverity[divide_by_zero] */
1281 	         commodityexcessratio =
1282 	               ABS((nposflowcoefs + nnegflowcoefs)/(SCIP_Real)ncoveredcommodities - maxcolspercommoditylimit);
1283 	
1284 	         capacityrowscores[r] += 1000.0 * MAX(0.0, 2.0 - commodityexcessratio);
1285 	
1286 	         /* row has at most 'maxcolspercommoditylimit' columns per commodity: score +1000 */
1287 	/*         if( maxcolspercommodity[r] <= maxcolspercommoditylimit )
1288 	            capacityrowscores[r] += 1000.0;*/
1289 	
1290 	         /* row is of type f - c*x <= b: score +1000 */
1291 	         if( (capacityrowsigns[r] & RHSPOSSIBLE) != 0 && nnegflowcoefs == 0 && nposcapacitycoefs == 0 && nnegcapacitycoefs > 0 )
1292 	            capacityrowscores[r] += 1000.0;
1293 	         if( (capacityrowsigns[r] & LHSPOSSIBLE) != 0 && nposflowcoefs == 0 && nposcapacitycoefs > 0 && nnegcapacitycoefs == 0 )
1294 	            capacityrowscores[r] += 1000.0;
1295 	
1296 	         /* row has no continuous variables that are not flow variables: score +1000 */
1297 	/*         if( nbadcoefs == 0 )
1298 	            capacityrowscores[r] += 1000.0;*/
1299 	
1300 	         /* almost all commodities are covered: score +2000*ncoveredcommodities/(nactivecommodities+3)
1301 	          * use slightly increased denominator in order to not increase score too much for very few commodities
1302 	          */
1303 	         assert(nactivecommodities + 3 > 0);
1304 	         capacityrowscores[r] += 2000.0 * ncoveredcommodities/(SCIP_Real)(nactivecommodities + 3);
1305 	
1306 	         /* all coefficients of flow variables are +1 or all are -1: score +500 */
1307 	         if( SCIPisEQ(scip, ABS(sameflowcoef), 1.0) )
1308 	            capacityrowscores[r] += 500.0;
1309 	
1310 	         /* all coefficients of flow variables are equal: score +250 */
1311 	         if( sameflowcoef != 0.0 && sameflowcoef != SCIP_REAL_MAX ) /*lint !e777*/
1312 	            capacityrowscores[r] += 250.0;
1313 	
1314 	         /* all coefficients of flow variables are +1 or -1: score +100 */
1315 	         if( SCIPisEQ(scip, sameabsflowcoef, 1.0) )
1316 	            capacityrowscores[r] += 100.0;
1317 	
1318 	         /* there is at least one capacity variable with coefficient not equal to +/-1: score +100 */
1319 	         if( maxabscapacitycoef > 0.0 && !SCIPisEQ(scip, maxabscapacitycoef, 1.0) )
1320 	            capacityrowscores[r] += 100.0;
1321 	
1322 	         /* flow coefficients are mostly of the same sign: score +20*max(npos,nneg)/(npos+nneg) */
1323 	         capacityrowscores[r] += 20.0 * MAX(nposflowcoefs, nnegflowcoefs)/MAX(1.0,(SCIP_Real)(nposflowcoefs + nnegflowcoefs));
1324 	
1325 	         /* capacity coefficients are mostly of the same sign: score +10*max(npos,nneg)/(npos+nneg+1) */
1326 	         capacityrowscores[r] += 10.0 * MAX(nposcapacitycoefs, nnegcapacitycoefs)/(SCIP_Real)(nposcapacitycoefs+nnegcapacitycoefs+1.0);
1327 	
1328 	         /* row is a <= row with non-negative right hand side: score +10 */
1329 	         if( (capacityrowsigns[r] & RHSPOSSIBLE) != 0 && !SCIPisNegative(scip, rowrhs)  )
1330 	            capacityrowscores[r] += 10.0;
1331 	
1332 	         /* row is an inequality: score +10 */
1333 	         if( SCIPisInfinity(scip, -rowlhs) != SCIPisInfinity(scip, rowrhs) )
1334 	            capacityrowscores[r] += 10.0;
1335 	
1336 	         assert(capacityrowscores[r] > 0.0);
1337 	         SCIPdebugMsg(scip, "row <%s>: maxcolspercommodity=%d capacityrowsign=%d nposflowcoefs=%d nnegflowcoefs=%d nposcapacitycoefs=%d nnegcapacitycoefs=%d nbadcoefs=%d nactivecommodities=%d sameflowcoef=%g -> score=%g\n",
1338 	                          SCIProwGetName(row), maxcolspercommodity[r], capacityrowsigns[r], nposflowcoefs, nnegflowcoefs, nposcapacitycoefs, nnegcapacitycoefs, nbadcoefs, nactivecommodities, sameflowcoef, capacityrowscores[r]);
1339 	
1340 	         /* update maximum dual solution value for additional score tie breaking */
1341 	         maxdualcapacity = MAX(maxdualcapacity, absdualsol);
1342 	
1343 	         /* if the model type should be detected automatically, count the number of directed and undirected capacity candidates */
1344 	         if( modeltype == SCIP_MCFMODELTYPE_AUTO )
1345 	         {
1346 	            assert(maxcolspercommoditylimit == 2);
1347 	            if( (capacityrowsigns[r] & UNDIRECTED) != 0 )
1348 	               undirectedcandsscore += capacityrowscores[r];
1349 	            else
1350 	               directedcandsscore += capacityrowscores[r];
1351 	         }
1352 	      }
1353 	      else
1354 	      {
1355 	         SCIPdebugMsg(scip, "row <%s>: rowsign = %d  nposflowcoefs = %d  nnegflowcoefs = %d -> discard\n",
1356 	                          SCIProwGetName(row), rowsign, nposflowcoefs, nnegflowcoefs);
1357 	      }
1358 	   }
1359 	
1360 	   /* if the model type should be detected automatically, decide it by a majority vote */
1361 	   if( modeltype == SCIP_MCFMODELTYPE_AUTO )
1362 	   {
1363 	      if( directedcandsscore > undirectedcandsscore )
1364 	         modeltype = SCIP_MCFMODELTYPE_DIRECTED;
1365 	      else
1366 	         modeltype = SCIP_MCFMODELTYPE_UNDIRECTED;
1367 	
1368 	      MCFdebugMessage("detected model type: %s (%g directed score, %g undirected score)\n",
1369 	                      modeltype == SCIP_MCFMODELTYPE_DIRECTED ? "directed" : "undirected", directedcandsscore, undirectedcandsscore);
1370 	
1371 	      if( modeltype == SCIP_MCFMODELTYPE_DIRECTED )
1372 	      {
1373 	         int i;
1374 	
1375 	         /* discard all undirected arcs */
1376 	         for( i = 0; i < mcfdata->ncapacitycands; i++ )
1377 	         {
1378 	            r = capacitycands[i];
1379 	            assert(0 <= r && r < nrows);
1380 	            if( (capacityrowsigns[r] & UNDIRECTED) != 0 )
1381 	            {
1382 	               /* reduce the score of the undirected row in the directed model */
1383 	               if( maxcolspercommodity[r] <= maxcolspercommoditylimit )
1384 	                  capacityrowscores[r] -= 1000.0;
1385 	            }
1386 	         }
1387 	      }
1388 	
1389 	      /* record the detected model type */
1390 	      mcfdata->modeltype = modeltype;
1391 	   }
1392 	
1393 	   /* apply additional score tie breaking using the dual solutions */
1394 	   if( SCIPisPositive(scip, maxdualcapacity) )
1395 	   {
1396 	      int i;
1397 	
1398 	      for( i = 0; i < mcfdata->ncapacitycands; i++ )
1399 	      {
1400 	         SCIP_Real dualsol;
1401 	
1402 	         r = capacitycands[i];
1403 	         assert(0 <= r && r < nrows);
1404 	         dualsol = SCIProwGetDualsol(rows[r]);
1405 	         if( dualsol == SCIP_INVALID ) /*lint !e777*/
1406 	            dualsol = 0.0;
1407 	         else if( capacityrowsigns[r] == (LHSPOSSIBLE | RHSPOSSIBLE) )
1408 	            dualsol = ABS(dualsol);
1409 	         else if( capacityrowsigns[r] == RHSPOSSIBLE )
1410 	            dualsol = -dualsol;
1411 	         assert(maxdualcapacity > 0.0); /*for flexelint*/
1412 	         capacityrowscores[r] += MAX(dualsol, 0.0)/maxdualcapacity;
1413 	         assert(capacityrowscores[r] > 0.0);
1414 	      }
1415 	   }
1416 	
1417 	   /* sort candidates by score */
1418 	   SCIPsortInd(mcfdata->capacitycands, compCands, (void*)capacityrowscores, mcfdata->ncapacitycands);
1419 	
1420 	   MCFdebugMessage("capacity candidates [%d]\n", mcfdata->ncapacitycands);
1421 	#ifdef SCIP_DEBUG
1422 	   for( r = 0; r < mcfdata->ncapacitycands; r++ )
1423 	   {
1424 	      SCIPdebugMsg(scip, "row %4d [score: %2g]: %s\n", mcfdata->capacitycands[r],
1425 	                       capacityrowscores[mcfdata->capacitycands[r]], SCIProwGetName(rows[mcfdata->capacitycands[r]]));
1426 	      /*SCIPdebug( SCIP_CALL(SCIPprintRow(scip, rows[mcfdata->capacitycands[r]], NULL)) );*/
1427 	   }
1428 	#endif
1429 	
1430 	   /* free temporary memory */
1431 	   SCIPfreeBufferArray(scip, &maxcolspercommodity);
1432 	   SCIPfreeBufferArray(scip, &ncolspercommodity);
1433 	
1434 	   return SCIP_OKAY;
1435 	}
1436 	
1437 	/** creates a new commodity */
1438 	static
1439 	SCIP_RETCODE createNewCommodity(
1440 	   SCIP*                 scip,               /**< SCIP data structure */
1441 	   MCFDATA*              mcfdata             /**< internal MCF extraction data to pass to subroutines */
1442 	   )
1443 	{
1444 	   /* get memory for commoditysigns array */
1445 	   assert(mcfdata->ncommodities <= mcfdata->commoditysignssize);
1446 	   if( mcfdata->ncommodities == mcfdata->commoditysignssize )
1447 	   {
1448 	      mcfdata->commoditysignssize = MAX(2*mcfdata->commoditysignssize, mcfdata->ncommodities+1);
1449 	      SCIP_CALL( SCIPreallocMemoryArray(scip, &mcfdata->commoditysigns, mcfdata->commoditysignssize) );
1450 	   }
1451 	   assert(mcfdata->ncommodities < mcfdata->commoditysignssize);
1452 	
1453 	   /* create commodity */
1454 	   SCIPdebugMsg(scip, "**** creating new commodity %d ****\n", mcfdata->ncommodities);
1455 	   mcfdata->commoditysigns[mcfdata->ncommodities] = 0;
1456 	   mcfdata->ncommodities++;
1457 	
1458 	   return SCIP_OKAY;
1459 	}
1460 	
1461 	/** creates a new arc */
1462 	static
1463 	SCIP_RETCODE createNewArc(
1464 	   SCIP*                 scip,               /**< SCIP data structure */
1465 	   MCFDATA*              mcfdata,            /**< internal MCF extraction data to pass to subroutines */
1466 	   int                   source,             /**< source of new arc */
1467 	   int                   target,             /**< target of new arc */
1468 	   int*                  newarcid            /**< pointer to store id of new arc */
1469 	   )
1470 	{
1471 	   assert(source != target );
1472 	   assert(0 <= source && source < mcfdata->nnodes);
1473 	   assert(0 <= target && target < mcfdata->nnodes);
1474 	   assert(newarcid != NULL);
1475 	
1476 	   *newarcid = mcfdata->narcs;
1477 	
1478 	   /* get memory for arrays indexed by arcs */
1479 	   assert(mcfdata->narcs <= mcfdata->arcarraysize);
1480 	   if( mcfdata->narcs == mcfdata->arcarraysize )
1481 	   {
1482 	      mcfdata->arcarraysize = MAX(2*mcfdata->arcarraysize, mcfdata->narcs+1);
1483 	      SCIP_CALL( SCIPreallocMemoryArray(scip, &mcfdata->arcsources, mcfdata->arcarraysize) );
1484 	      SCIP_CALL( SCIPreallocMemoryArray(scip, &mcfdata->arctargets, mcfdata->arcarraysize) );
1485 	      SCIP_CALL( SCIPreallocMemoryArray(scip, &mcfdata->nextinarcs, mcfdata->arcarraysize) );
1486 	      SCIP_CALL( SCIPreallocMemoryArray(scip, &mcfdata->nextoutarcs, mcfdata->arcarraysize) );
1487 	   }
1488 	   assert(mcfdata->narcs < mcfdata->arcarraysize);
1489 	
1490 	   /* capacityrows is a special case since it is used earlier */
1491 	   if( mcfdata->capacityrowssize < mcfdata->arcarraysize )
1492 	   {
1493 	      mcfdata->capacityrowssize = mcfdata->arcarraysize;
1494 	      SCIP_CALL( SCIPreallocMemoryArray(scip, &mcfdata->capacityrows, mcfdata->capacityrowssize) );
1495 	   }
1496 	   assert(mcfdata->narcs < mcfdata->capacityrowssize);
1497 	
1498 	   /* create new arc */
1499 	   SCIPdebugMsg(scip, "**** creating new arc %d: %d -> %d ****\n", mcfdata->narcs, source, target);
1500 	
1501 	   mcfdata->arcsources[*newarcid]   = source;
1502 	   mcfdata->arctargets[*newarcid]   = target;
1503 	   mcfdata->nextoutarcs[*newarcid]  = mcfdata->firstoutarcs[source];
1504 	   mcfdata->firstoutarcs[source]    = *newarcid;
1505 	   mcfdata->nextinarcs[*newarcid]   = mcfdata->firstinarcs[target];
1506 	   mcfdata->firstinarcs[target]     = *newarcid;
1507 	   mcfdata->capacityrows[*newarcid] = NULL;
1508 	
1509 	   mcfdata->narcs++;
1510 	
1511 	   return SCIP_OKAY;
1512 	}
1513 	
1514 	/** adds the given flow row and all involved columns to the current commodity */
1515 	static
1516 	void addFlowrowToCommodity(
1517 	   SCIP*                 scip,               /**< SCIP data structure */
1518 	   MCFDATA*              mcfdata,            /**< internal MCF extraction data to pass to subroutines */
1519 	   SCIP_ROW*             row,                /**< flow row to add to current commodity */
1520 	   unsigned char         rowsign,            /**< possible flow row signs to use */
1521 	   int*                  comcolids,          /**< array of column indices of columns in commodity */
1522 	   int*                  ncomcolids          /**< pointer to number of columns in commodity */
1523 	   )
1524 	{
1525 	   unsigned char* flowrowsigns   = mcfdata->flowrowsigns;
1526 	   SCIP_Bool*     plusflow       = mcfdata->plusflow;
1527 	   SCIP_Bool*     minusflow      = mcfdata->minusflow;
1528 	   int            ncommodities   = mcfdata->ncommodities;
1529 	   int*           commoditysigns = mcfdata->commoditysigns;
1530 	   int*           colcommodity   = mcfdata->colcommodity;
1531 	   int*           rowcommodity   = mcfdata->rowcommodity;
1532 	   int*           newcols        = mcfdata->newcols;
1533 	
1534 	   SCIP_COL** rowcols;
1535 	   SCIP_Real* rowvals;
1536 	   int rowlen;
1537 	   int rowscale;
1538 	   SCIP_Bool invertrow;
1539 	   int r;
1540 	   int k;
1541 	   int i;
1542 	
1543 	   assert(comcolids != NULL);
1544 	   assert(ncomcolids != NULL);
1545 	
1546 	   k = ncommodities-1;
1547 	   assert(k >= 0);
1548 	
1549 	   r = SCIProwGetLPPos(row);
1550 	   assert(r >= 0);
1551 	
1552 	   /* check if row has to be inverted */
1553 	   invertrow = ((rowsign & INVERTED) != 0);
1554 	   rowsign &= ~INVERTED;
1555 	
1556 	   assert(rowcommodity[r] == -1);
1557 	   assert((flowrowsigns[r] | rowsign) == flowrowsigns[r]);
1558 	   assert((rowsign & (LHSPOSSIBLE | RHSPOSSIBLE)) == rowsign);
1559 	   assert(rowsign != 0);
1560 	
1561 	   /* if the row is only usable as flow row in one direction, we cannot change the sign
1562 	    * of the whole commodity anymore
1563 	    */
1564 	   if( (flowrowsigns[r] & (LHSPOSSIBLE | RHSPOSSIBLE)) != (LHSPOSSIBLE | RHSPOSSIBLE) )
1565 	      commoditysigns[k] = +1; /* we cannot switch directions */
1566 	
1567 	   /* decide the sign (direction) of the row */
1568 	   if( rowsign == LHSPOSSIBLE )
1569 	      rowsign = LHSASSIGNED;
1570 	   else if( rowsign == RHSPOSSIBLE )
1571 	      rowsign = RHSASSIGNED;
1572 	   else
1573 	   {
1574 	      SCIP_Real dualsol = SCIProwGetDualsol(row);
1575 	
1576 	      assert(rowsign == (LHSPOSSIBLE | RHSPOSSIBLE));
1577 	
1578 	      /* if we have a valid non-zero dual solution, choose the side which is tight */
1579 	      if( !SCIPisZero(scip, dualsol) && dualsol != SCIP_INVALID ) /*lint !e777*/
1580 	      {
1581 	         if( dualsol > 0.0 )
1582 	            rowsign = LHSASSIGNED;
1583 	         else
1584 	            rowsign = RHSASSIGNED;
1585 	      }
1586 	      else
1587 	      {
1588 	         SCIP_Real rowlhs = SCIProwGetLhs(row) - SCIProwGetConstant(row);
1589 	         SCIP_Real rowrhs = SCIProwGetRhs(row) - SCIProwGetConstant(row);
1590 	
1591 	         /* choose row sign such that we get a*x <= -d with d non-negative */
1592 	         if( rowrhs < 0.0 )
1593 	            rowsign = RHSASSIGNED;
1594 	         else if( rowlhs > 0.0 )
1595 	            rowsign = LHSASSIGNED;
1596 	         else
1597 	            rowsign = RHSASSIGNED; /* if we are still undecided, choose rhs */
1598 	      }
1599 	   }
1600 	   if( rowsign == RHSASSIGNED )
1601 	      rowscale = +1;
1602 	   else
1603 	      rowscale = -1;
1604 	
1605 	   /* reintroduce inverted flag */
1606 	   if( invertrow )
1607 	   {
1608 	      rowsign |= INVERTED;
1609 	      rowscale *= -1;
1610 	   }
1611 	   flowrowsigns[r] |= rowsign;
1612 	
1613 	   SCIPdebugMsg(scip, "adding flow row %d <%s> with sign %+d%s to commodity %d [score:%g]\n",
1614 	                    r, SCIProwGetName(row), rowscale, (rowsign & INVERTED) != 0 ? " (inverted)" : "",
1615 	                    k, mcfdata->flowrowscores[r]);
1616 	   /*SCIPdebug( SCIP_CALL(SCIPprintRow(scip, row, NULL)) );*/
1617 	
1618 	   /* add row to commodity */
1619 	   rowcommodity[r] = k;
1620 	   rowcols = SCIProwGetCols(row);
1621 	   rowvals = SCIProwGetVals(row);
1622 	   rowlen = SCIProwGetNLPNonz(row);
1623 	   for( i = 0; i < rowlen; i++ )
1624 	   {
1625 	      SCIP_Real val;
1626 	      int c;
1627 	
1628 	      c = SCIPcolGetLPPos(rowcols[i]);
1629 	      assert(0 <= c && c < SCIPgetNLPCols(scip));
1630 	
1631 	      /* assign column to commodity */
1632 	      if( colcommodity[c] == -1 )
1633 	      {
1634 	         assert(!plusflow[c]);
1635 	         assert(!minusflow[c]);
1636 	         assert(mcfdata->nnewcols < SCIPgetNLPCols(scip));
1637 	         colcommodity[c] = k;
1638 	         newcols[mcfdata->nnewcols] = c;
1639 	         mcfdata->nnewcols++;
1640 	         comcolids[*ncomcolids] = c;
1641 	         (*ncomcolids)++;
1642 	      }
1643 	      assert(colcommodity[c] == k);
1644 	
1645 	      /* update plusflow/minusflow */
1646 	      val = rowscale * rowvals[i];
1647 	      if( val > 0.0 )
1648 	      {
1649 	         assert(!plusflow[c]);
1650 	         plusflow[c] = TRUE;
1651 	      }
1652 	      else
1653 	      {
1654 	         assert(!minusflow[c]);
1655 	         minusflow[c] = TRUE;
1656 	      }
1657 	   }
1658 	}
1659 	
1660 	/* inverts the lhs/rhs assignment of all rows in the given commodity */
1661 	static
1662 	void invertCommodity(
1663 	   SCIP*                 scip,               /**< SCIP data structure */
1664 	   MCFDATA*              mcfdata,            /**< internal MCF extraction data to pass to subroutines */
1665 	   int                   k,                  /**< commodity that the flow row should enter */
1666 	   SCIP_ROW**            comrows,            /**< flow rows in commodity k */
1667 	   int                   ncomrows,           /**< number of flow rows (number of nodes) in commodity k */
1668 	   int*                  comcolids,          /**< column indices of columns in commodity k */
1669 	   int                   ncomcolids          /**< number of columns in commodity k */
1670 	   )
1671 	{
1672 	   unsigned char* flowrowsigns = mcfdata->flowrowsigns;
1673 	   SCIP_Bool*     plusflow     = mcfdata->plusflow;
1674 	   SCIP_Bool*     minusflow    = mcfdata->minusflow;
1675 	
1676 	   int i;
1677 	
1678 	   assert(mcfdata->commoditysigns[k] == 0);
1679 	   assert(comrows != NULL || ncomrows == 0);
1680 	   assert(comcolids != NULL);
1681 	
1682 	   /* switch assignments of rows */
1683 	   for( i = 0; i < ncomrows; i++ )
1684 	   {
1685 	      SCIP_ROW* row;
1686 	      int r;
1687 	      unsigned char rowsign;
1688 	
1689 	      assert(comrows != NULL);
1690 	      row = comrows[i];
1691 	      assert( row != NULL );
1692 	      r = SCIProwGetLPPos(row);
1693 	      assert(0 <= r && r < SCIPgetNLPRows(scip));
1694 	      assert(mcfdata->rowcommodity[r] == k);
1695 	      assert(!SCIPisInfinity(scip, -SCIProwGetLhs(row)));
1696 	      assert(!SCIPisInfinity(scip, SCIProwGetRhs(row)));
1697 	
1698 	      rowsign = flowrowsigns[r];
1699 	      assert((rowsign & (LHSASSIGNED | RHSASSIGNED)) != 0);
1700 	      assert((rowsign & INVERTED) == 0);
1701 	
1702 	      flowrowsigns[r] &= ~(LHSASSIGNED | RHSASSIGNED);
1703 	      if( (rowsign & LHSASSIGNED) != 0 )
1704 	         flowrowsigns[r] |= RHSASSIGNED;
1705 	      else
1706 	         flowrowsigns[r] |= LHSASSIGNED;
1707 	   }
1708 	
1709 	   /* switch plus/minusflow of columns of the given commodity */
1710 	   for( i = 0; i < ncomcolids; i++ )
1711 	   {
1712 	      int c;
1713 	      SCIP_Bool tmp;
1714 	
1715 	      c = comcolids[i];
1716 	      assert(0 <= c && c < SCIPgetNLPCols(scip));
1717 	      assert(mcfdata->colcommodity[c] == k);
1718 	
1719 	      tmp = plusflow[c];
1720 	      plusflow[c] = minusflow[c];
1721 	      minusflow[c] = tmp;
1722 	   }
1723 	}
1724 	
1725 	/** deletes a commodity and removes the flow rows again from the system */
1726 	static
1727 	void deleteCommodity(
1728 	   SCIP*                 scip,               /**< SCIP data structure */
1729 	   MCFDATA*              mcfdata,            /**< internal MCF extraction data to pass to subroutines */
1730 	   int                   k,                  /**< commodity to delete */
1731 	   SCIP_ROW**            comrows,            /**< flow rows of the commodity */
1732 	   int                   nrows,              /**< number of flow rows in the commodity */
1733 	   int*                  ndelflowrows,       /**< pointer to store number of flow rows in deleted commodity */
1734 	   int*                  ndelflowvars        /**< pointer to store number of flow vars in deleted commodity */
1735 	   )
1736 	{
1737 	   unsigned char* flowrowsigns = mcfdata->flowrowsigns;
1738 	   SCIP_Bool*     plusflow     = mcfdata->plusflow;
1739 	   SCIP_Bool*     minusflow    = mcfdata->minusflow;
1740 	   int            ncommodities = mcfdata->ncommodities;
1741 	   int*           colcommodity = mcfdata->colcommodity;
1742 	   int*           rowcommodity = mcfdata->rowcommodity;
1743 	
1744 	   int n;
1745 	
1746 	   assert(0 <= k && k < ncommodities);
1747 	
1748 	   assert( ndelflowrows != NULL );
1749 	   assert( ndelflowvars != NULL );
1750 	
1751 	   SCIPdebugMsg(scip, "deleting commodity %d (%d total commodities) with %d flow rows\n", k, ncommodities, nrows);
1752 	
1753 	   *ndelflowrows = 0;
1754 	   *ndelflowvars = 0;
1755 	
1756 	   for( n = 0; n < nrows; n++ )
1757 	   {
1758 	      SCIP_ROW* row;
1759 	      SCIP_COL** rowcols;
1760 	      int rowlen;
1761 	      int r;
1762 	      int i;
1763 	
1764 	      row = comrows[n];
1765 	      r = SCIProwGetLPPos(row);
1766 	      assert(r >= 0);
1767 	      assert(rowcommodity[r] == k);
1768 	      assert((flowrowsigns[r] & (LHSASSIGNED | RHSASSIGNED)) != 0);
1769 	
1770 	      SCIPdebugMsg(scip, " -> removing row <%s> from commodity\n", SCIProwGetName(row));
1771 	
1772 	      /* remove the lhs/rhs assignment and the inverted flag */
1773 	      flowrowsigns[r] &= ~(LHSASSIGNED | RHSASSIGNED | INVERTED);
1774 	
1775 	      /* remove row from commodity */
1776 	      rowcommodity[r] = -1;
1777 	      rowcols = SCIProwGetCols(row);
1778 	      rowlen = SCIProwGetNLPNonz(row);
1779 	      for( i = 0; i < rowlen; i++ )
1780 	      {
1781 	         int c;
1782 	
1783 	         c = SCIPcolGetLPPos(rowcols[i]);
1784 	         assert(0 <= c && c < SCIPgetNLPCols(scip));
1785 	
1786 	         /* remove column from commodity */
1787 	         assert(colcommodity[c] == k || colcommodity[c] == -1);
1788 	         if(colcommodity[c] == k)
1789 	            (*ndelflowvars)++;
1790 	         colcommodity[c] = -1;
1791 	
1792 	         /* reset plusflow/minusflow */
1793 	         plusflow[c] = FALSE;
1794 	         minusflow[c] = FALSE;
1795 	      }
1796 	
1797 	      (*ndelflowrows)++;
1798 	   }
1799 	
1800 	   /* get rid of commodity if it is the last one; otherwise, just leave it
1801 	    * as an empty commodity which will be discarded later
1802 	    */
1803 	   if( k == ncommodities-1 )
1804 	      mcfdata->ncommodities--;
1805 	   else
1806 	      mcfdata->nemptycommodities++;
1807 	}
1808 	
1809 	/** checks whether the given row fits into the given commodity and returns the possible flow row signs */
1810 	static
1811 	void getFlowrowFit(
1812 	   SCIP*                 scip,               /**< SCIP data structure */
1813 	   MCFDATA*              mcfdata,            /**< internal MCF extraction data to pass to subroutines */
1814 	   SCIP_ROW*             row,                /**< flow row to check */
1815 	   int                   k,                  /**< commodity that the flow row should enter */
1816 	   unsigned char*        rowsign,            /**< pointer to store the possible flow row signs */
1817 	   SCIP_Bool*            invertcommodity     /**< pointer to store whether the commodity has to be inverted to accommodate the row */
1818 	   )
1819 	{
1820 	   unsigned char* flowrowsigns   = mcfdata->flowrowsigns;
1821 	   SCIP_Bool*     plusflow       = mcfdata->plusflow;
1822 	   SCIP_Bool*     minusflow      = mcfdata->minusflow;
1823 	   int*           colcommodity   = mcfdata->colcommodity;
1824 	   int*           rowcommodity   = mcfdata->rowcommodity;
1825 	   int*           commoditysigns = mcfdata->commoditysigns;
1826 	
1827 	   SCIP_COL** rowcols;
1828 	   SCIP_Real* rowvals;
1829 	   int rowlen;
1830 	   unsigned char flowrowsign;
1831 	   unsigned char invflowrowsign;
1832 	   int r;
1833 	   int j;
1834 	
1835 	   assert(invertcommodity != NULL);
1836 	
1837 	   *rowsign = 0;
1838 	   *invertcommodity = FALSE;
1839 	
1840 	   r = SCIProwGetLPPos(row);
1841 	   assert(0 <= r && r < SCIPgetNLPRows(scip));
1842 	
1843 	   /* ignore rows that are already used */
1844 	   if( rowcommodity[r] != -1 )
1845 	      return;
1846 	
1847 	   /* check if row is an available flow row */
1848 	   flowrowsign = flowrowsigns[r];
1849 	   assert((flowrowsign & (LHSPOSSIBLE | RHSPOSSIBLE | DISCARDED)) == flowrowsign);
1850 	   if( (flowrowsign & DISCARDED) != 0 )
1851 	      return;
1852 	   if( (flowrowsign & (LHSPOSSIBLE | RHSPOSSIBLE)) == 0 )
1853 	      return;
1854 	   invflowrowsign = flowrowsign;
1855 	
1856 	   /* check whether the row fits w.r.t. the signs of the coefficients */
1857 	   rowcols = SCIProwGetCols(row);
1858 	   rowvals = SCIProwGetVals(row);
1859 	   rowlen = SCIProwGetNLPNonz(row);
1860 	   for( j = 0; j < rowlen && (flowrowsign != 0 || invflowrowsign != 0); j++ )
1861 	   {
1862 	      int rowc;
1863 	
1864 	      rowc = SCIPcolGetLPPos(rowcols[j]);
1865 	      assert(0 <= rowc && rowc < SCIPgetNLPCols(scip));
1866 	
1867 	      /* check if column already belongs to the same commodity */
1868 	      if( colcommodity[rowc] == k )
1869 	      {
1870 	         /* column only fits if it is not yet present with the same sign */
1871 	         if( plusflow[rowc] )
1872 	         {
1873 	            /* column must not be included with positive sign */
1874 	            if( rowvals[j] > 0.0 )
1875 	            {
1876 	               flowrowsign &= ~RHSPOSSIBLE;
1877 	               invflowrowsign &= ~LHSPOSSIBLE;
1878 	            }
1879 	            else
1880 	            {
1881 	               flowrowsign &= ~LHSPOSSIBLE;
1882 	               invflowrowsign &= ~RHSPOSSIBLE;
1883 	            }
1884 	         }
1885 	         if( minusflow[rowc] )
1886 	         {
1887 	            /* column must not be included with negative sign */
1888 	            if( rowvals[j] > 0.0 )
1889 	            {
1890 	               flowrowsign &= ~LHSPOSSIBLE;
1891 	               invflowrowsign &= ~RHSPOSSIBLE;
1892 	            }
1893 	            else
1894 	            {
1895 	               flowrowsign &= ~RHSPOSSIBLE;
1896 	               invflowrowsign &= ~LHSPOSSIBLE;
1897 	            }
1898 	         }
1899 	      }
1900 	      else if( colcommodity[rowc] != -1 )
1901 	      {
1902 	         /* column does not fit if it already belongs to a different commodity */
1903 	         flowrowsign = 0;
1904 	         invflowrowsign = 0;
1905 	      }
1906 	   }
1907 	
1908 	   if( flowrowsign != 0 )
1909 	   {
1910 	      /* flow row fits without inverting anything */
1911 	      *rowsign = flowrowsign;
1912 	      *invertcommodity = FALSE;
1913 	   }
1914 	   else if( invflowrowsign != 0 )
1915 	   {
1916 	      /* this must be an inequality */
1917 	      assert((flowrowsigns[r] & (LHSPOSSIBLE | RHSPOSSIBLE)) != (LHSPOSSIBLE | RHSPOSSIBLE));
1918 	
1919 	      /* flow row fits only if row or commodity is inverted */
1920 	      if( commoditysigns == NULL || commoditysigns[k] == 0 )
1921 	      {
1922 	         /* commodity can be inverted */
1923 	         *rowsign = invflowrowsign;
1924 	         *invertcommodity = TRUE;
1925 	      }
1926 	      else
1927 	      {
1928 	         /* row has to be inverted */
1929 	         *rowsign = (invflowrowsign | INVERTED);
1930 	         *invertcommodity = FALSE;
1931 	      }
1932 	   }
1933 	   else
1934 	   {
1935 	      /* we can discard the row, since it can also not be member of a different commodity */
1936 	      SCIPdebugMsg(scip, " -> discard flow row %d <%s>, comoditysign=%d\n", r, SCIProwGetName(row), commoditysigns[k]);
1937 	      flowrowsigns[r] |= DISCARDED;
1938 	   }
1939 	}
1940 	
1941 	/** returns a flow conservation row that fits into the current commodity, or NULL */
1942 	static
1943 	void getNextFlowrow(
1944 	   SCIP*                 scip,               /**< SCIP data structure */
1945 	   MCFDATA*              mcfdata,            /**< internal MCF extraction data to pass to subroutines */
1946 	   SCIP_ROW**            nextrow,            /**< pointer to store next row */
1947 	   unsigned char*        nextrowsign,        /**< pointer to store possible signs of next row */
1948 	   SCIP_Bool*            nextinvertcommodity /**< pointer to store whether current commodity has to be inverted to accommodate the next row */
1949 	   )
1950 	{
1951 	   SCIP_Real* flowrowscores = mcfdata->flowrowscores;
1952 	   SCIP_Bool* plusflow      = mcfdata->plusflow;
1953 	   SCIP_Bool* minusflow     = mcfdata->minusflow;
1954 	   int*       newcols       = mcfdata->newcols;
1955 	   int        ncommodities  = mcfdata->ncommodities;
1956 	
1957 	   SCIP_COL** cols;
1958 	   int k;
1959 	
1960 	   assert(nextrow != NULL);
1961 	   assert(nextrowsign != NULL);
1962 	
1963 	   *nextrow = NULL;
1964 	   *nextrowsign = 0;
1965 	   *nextinvertcommodity = FALSE;
1966 	
1967 	   k = ncommodities-1;
1968 	
1969 	   cols = SCIPgetLPCols(scip);
1970 	   assert(cols != NULL);
1971 	
1972 	   /* check if there are any columns left in the commodity that have not yet been inspected for incident flow rows */
1973 	   while( mcfdata->nnewcols > 0 )
1974 	   {
1975 	      SCIP_COL* col;
1976 	      SCIP_ROW** colrows;
1977 	      int collen;
1978 	      SCIP_ROW* bestrow;
1979 	      unsigned char bestrowsign;
1980 	      SCIP_Bool bestinvertcommodity;
1981 	      SCIP_Real bestscore;
1982 	      int c;
1983 	      int i;
1984 	
1985 	      /* pop next new column from stack */
1986 	      c = newcols[mcfdata->nnewcols-1];
1987 	      mcfdata->nnewcols--;
1988 	      assert(0 <= c && c < SCIPgetNLPCols(scip));
1989 	
1990 	      /* check if this columns already as both signs */
1991 	      assert(plusflow[c] || minusflow[c]);
1992 	      if( plusflow[c] && minusflow[c] )
1993 	         continue;
1994 	
1995 	      /* check whether column is incident to a valid flow row that fits into the current commodity */
1996 	      bestrow = NULL;
1997 	      bestrowsign = 0;
1998 	      bestinvertcommodity = FALSE;
1999 	      bestscore = 0.0;
2000 	      col = cols[c];
2001 	      colrows = SCIPcolGetRows(col);
2002 	      collen = SCIPcolGetNLPNonz(col);
2003 	      for( i = 0; i < collen; i++ )
2004 	      {
2005 	         SCIP_ROW* row;
2006 	         unsigned char flowrowsign;
2007 	         SCIP_Bool invertcommodity;
2008 	
2009 	         row = colrows[i];
2010 	
2011 	         /* check if row fits into the current commodity */
2012 	         getFlowrowFit(scip, mcfdata, row, k, &flowrowsign, &invertcommodity);
2013 	
2014 	         /* do we have a winner? */
2015 	         if( flowrowsign != 0 )
2016 	         {
2017 	            int r;
2018 	            SCIP_Real score;
2019 	
2020 	            r = SCIProwGetLPPos(row);
2021 	            assert(0 <= r && r < SCIPgetNLPRows(scip));
2022 	            score = flowrowscores[r];
2023 	            assert(score > 0.0);
2024 	
2025 	            /* If we have to invert the row, this will lead to a negative slack variable in the MIR cut,
2026 	             * which needs to be substituted in the end. We like to avoid this and therefore reduce the
2027 	             * score.
2028 	             */
2029 	            if( (flowrowsign & INVERTED) != 0 )
2030 	               score *= 0.75;
2031 	
2032 	            if( score > bestscore )
2033 	            {
2034 	               bestrow = row;
2035 	               bestrowsign = flowrowsign;
2036 	               bestinvertcommodity = invertcommodity;
2037 	               bestscore = score;
2038 	            }
2039 	         }
2040 	      }
2041 	
2042 	      /* if there was a valid row for this column, pick the best one
2043 	       * Note: This is not the overall best row, only the one for the first column that has a valid row.
2044 	       *       However, picking the overall best row seems to be too expensive
2045 	       */
2046 	      if( bestrow != NULL )
2047 	      {
2048 	         assert(bestscore > 0.0);
2049 	         assert(bestrowsign != 0);
2050 	         *nextrow = bestrow;
2051 	         *nextrowsign = bestrowsign;
2052 	         *nextinvertcommodity = bestinvertcommodity;
2053 	         break;
2054 	      }
2055 	   }
2056 	}
2057 	
2058 	/** extracts flow conservation rows and puts them into commodities */
2059 	static
2060 	SCIP_RETCODE extractFlow(
2061 	   SCIP*                 scip,               /**< SCIP data structure */
2062 	   MCFDATA*              mcfdata,            /**< internal MCF extraction data to pass to subroutines */
2063 	   SCIP_Real             maxflowvarflowrowratio, /**< maximum ratio of flowvars and flowrows */
2064 	   SCIP_Bool*            failed              /**< pointer to store whether flowrowflowvarratio exceeded */
2065 	   )
2066 	{
2067 	   int* flowcands = mcfdata->flowcands;
2068 	
2069 	   SCIP_Bool* plusflow;
2070 	   SCIP_Bool* minusflow;
2071 	   int* colcommodity;
2072 	   int* rowcommodity;
2073 	
2074 	   SCIP_ROW** comrows;
2075 	   int* ncomnodes;
2076 	   int* comcolids;
2077 	   int ncomcolids;
2078 	   SCIP_ROW** rows;
2079 	   int nrows;
2080 	   int ncols;
2081 	   int maxnnodes;
2082 	   int nflowrows;
2083 	   int nflowvars;
2084 	   int i;
2085 	   int c;
2086 	   int r;
2087 	   int k;
2088 	
2089 	   /* get LP data */
2090 	   rows = SCIPgetLPRows(scip);
2091 	   nrows = SCIPgetNLPRows(scip);
2092 	   ncols = SCIPgetNLPCols(scip);
2093 	
2094 	   assert(failed != NULL);
2095 	   assert(!*failed);
2096 	
2097 	   /* allocate memory */
2098 	   SCIP_CALL( SCIPallocMemoryArray(scip, &mcfdata->plusflow, ncols) );
2099 	   SCIP_CALL( SCIPallocMemoryArray(scip, &mcfdata->minusflow, ncols) );
2100 	   SCIP_CALL( SCIPallocMemoryArray(scip, &mcfdata->colcommodity, ncols) );
2101 	   SCIP_CALL( SCIPallocMemoryArray(scip, &mcfdata->rowcommodity, nrows) );
2102 	   SCIP_CALL( SCIPallocMemoryArray(scip, &mcfdata->newcols, ncols) );
2103 	   plusflow = mcfdata->plusflow;
2104 	   minusflow = mcfdata->minusflow;
2105 	   colcommodity = mcfdata->colcommodity;
2106 	   rowcommodity = mcfdata->rowcommodity;
2107 	
2108 	   /* allocate temporary memory */
2109 	   SCIP_CALL( SCIPallocBufferArray(scip, &comrows, nrows) );
2110 	   SCIP_CALL( SCIPallocBufferArray(scip, &ncomnodes, nrows) );
2111 	   SCIP_CALL( SCIPallocBufferArray(scip, &comcolids, ncols) );
2112 	
2113 	   /* 3. Extract network structure of flow conservation constraints:
2114 	    *    (a) Initialize plusflow[c] = minusflow[c] = FALSE for all columns c and other local data.
2115 	    */
2116 	   BMSclearMemoryArray(plusflow, ncols);
2117 	   BMSclearMemoryArray(minusflow, ncols);
2118 	   for( c = 0; c < ncols; c++ )
2119 	      colcommodity[c] = -1;
2120 	   for( r = 0; r < nrows; r++ )
2121 	      rowcommodity[r] = -1;
2122 	
2123 	   assert(flowcands != NULL || mcfdata->nflowcands == 0);
2124 	
2125 	   /*    (b) As long as there are flow conservation candidates left:
2126 	    *        (i) Create new commodity and use first flow conservation constraint as new row.
2127 	    *       (ii) Add new row to commodity, update pluscom/minuscom accordingly.
2128 	    *      (iii) For the newly added columns search for an incident flow conservation constraint. Pick the one of highest ranking.
2129 	    *       (iv) If found, set new row to this row and goto (ii).
2130 	    */
2131 	   maxnnodes = 0;
2132 	   nflowrows = 0;
2133 	   nflowvars = 0;
2134 	   for( i = 0; i < mcfdata->nflowcands; i++ )
2135 	   {
2136 	      SCIP_ROW* newrow;
2137 	      unsigned char newrowsign;
2138 	      SCIP_Bool newinvertcommodity;
2139 	      int nnodes;
2140 	
2141 	      assert(flowcands != NULL);
2142 	      r = flowcands[i];
2143 	      assert(0 <= r && r < nrows);
2144 	      newrow = rows[r];
2145 	
2146 	      /* check if row fits into a new commodity */
2147 	      getFlowrowFit(scip, mcfdata, newrow, mcfdata->ncommodities, &newrowsign, &newinvertcommodity);
2148 	      if( newrowsign == 0 )
2149 	         continue;
2150 	      assert(!newinvertcommodity);
2151 	      assert((newrowsign & INVERTED) == 0);
2152 	
2153 	      /* start new commodity */
2154 	      SCIPdebugMsg(scip, " -------------------start new commodity %d--------------------- \n", mcfdata->ncommodities );
2155 	      SCIP_CALL( createNewCommodity(scip, mcfdata) );
2156 	      nnodes = 0;
2157 	      ncomcolids = 0;
2158 	
2159 	      /* fill commodity with flow conservation constraints */
2160 	      do
2161 	      {
2162 	         /* if next flow row demands an inverting of the commodity, do it now */
2163 	         if( newinvertcommodity )
2164 	            invertCommodity(scip, mcfdata, mcfdata->ncommodities-1, comrows, nnodes, comcolids, ncomcolids);
2165 	
2166 	         /* add new row to commodity */
2167 	         SCIPdebugMsg(scip, " -> add flow row  <%s> \n",  SCIProwGetName(newrow));
2168 	         addFlowrowToCommodity(scip, mcfdata, newrow, newrowsign, comcolids, &ncomcolids);
2169 	         comrows[nnodes] = newrow;
2170 	         nnodes++;
2171 	         nflowrows++;
2172 	
2173 	         /* get next row to add */
2174 	         getNextFlowrow(scip, mcfdata, &newrow, &newrowsign, &newinvertcommodity);
2175 	      }
2176 	      while( newrow != NULL );
2177 	
2178 	      ncomnodes[mcfdata->ncommodities-1] = nnodes;
2179 	      maxnnodes = MAX(maxnnodes, nnodes);
2180 	      nflowvars += ncomcolids;
2181 	      SCIPdebugMsg(scip, " -> finished commodity %d: identified %d nodes, maxnnodes=%d\n", mcfdata->ncommodities-1, nnodes, maxnnodes);
2182 	
2183 	      /* if the commodity has too few nodes, or if it has much fewer nodes than the largest commodity, discard it */
2184 	      if( nnodes < MINNODES || nnodes < MINCOMNODESFRACTION * maxnnodes )
2185 	      {
2186 	         int ndelflowrows;
2187 	         int ndelflowvars;
2188 	
2189 	         deleteCommodity(scip, mcfdata, mcfdata->ncommodities-1, comrows, nnodes, &ndelflowrows, &ndelflowvars);
2190 	         nflowrows -= ndelflowrows;
2191 	         nflowvars -= ndelflowvars;
2192 	         assert(nflowvars >= 0);
2193 	         assert(nflowrows >= 0);
2194 	      }
2195 	   }
2196 	   /* final cleanup of small commodities */
2197 	   for( k = 0; k < mcfdata->ncommodities; k++ )
2198 	   {
2199 	      assert(ncomnodes[k] >= MINNODES);
2200 	
2201 	      /* if the commodity has much fewer nodes than the largest commodity, discard it */
2202 	      if( ncomnodes[k] < MINCOMNODESFRACTION * maxnnodes )
2203 	      {
2204 	         int nnodes;
2205 	         int ndelflowrows;
2206 	         int ndelflowvars;
2207 	
2208 	         nnodes = 0;
2209 	         for( i = 0; i < mcfdata->nflowcands; i++ )
2210 	         {
2211 	            assert(flowcands != NULL);
2212 	            r = flowcands[i];
2213 	            if( rowcommodity[r] == k )
2214 	            {
2215 	               comrows[nnodes] = rows[r];
2216 	               nnodes++;
2217 	#ifdef NDEBUG
2218 	               if( nnodes == ncomnodes[k] )
2219 	                  break;
2220 	#endif
2221 	            }
2222 	         }
2223 	         assert(nnodes == ncomnodes[k]);
2224 	         deleteCommodity(scip, mcfdata, k, comrows, nnodes, &ndelflowrows, &ndelflowvars);
2225 	         nflowrows -= ndelflowrows;
2226 	         nflowvars -= ndelflowvars;
2227 	         assert(nflowvars >= 0);
2228 	         assert(nflowrows >= 0);
2229 	      }
2230 	   }
2231 	
2232 	   /* free temporary memory */
2233 	   SCIPfreeBufferArray(scip, &comcolids);
2234 	   SCIPfreeBufferArray(scip, &ncomnodes);
2235 	   SCIPfreeBufferArray(scip, &comrows);
2236 	
2237 	   MCFdebugMessage("identified %d commodities (%d empty) with a maximum of %d nodes and %d flowrows, %d flowvars \n",
2238 	                   mcfdata->ncommodities, mcfdata->nemptycommodities, maxnnodes, nflowrows, nflowvars);
2239 	
2240 	   assert(nflowvars >= 0);
2241 	   assert(nflowrows >= 0);
2242 	
2243 	   /* do not allow flow system exceeding the flowvarflowrowratio (average node degree)*/
2244 	   if( nflowrows == 0)
2245 	      *failed = TRUE;
2246 	   else if( (SCIP_Real)nflowvars / (SCIP_Real)nflowrows > maxflowvarflowrowratio )
2247 	      *failed = TRUE;
2248 	
2249 	   return SCIP_OKAY;
2250 	}
2251 	
2252 	/** Arc-Detection -- identifies capacity constraints for the arcs and assigns arc ids to columns and capacity constraints */
2253 	static
2254 	SCIP_RETCODE extractCapacities(
2255 	   SCIP*                 scip,               /**< SCIP data structure */
2256 	   MCFDATA*              mcfdata             /**< internal MCF extraction data to pass to subroutines */
2257 	   )
2258 	{
2259 	   unsigned char*    capacityrowsigns   = mcfdata->capacityrowsigns;
2260 	   int*              colcommodity       = mcfdata->colcommodity;
2261 	#ifndef NDEBUG
2262 	   unsigned char*    flowrowsigns       = mcfdata->capacityrowsigns;
2263 	   int*              rowcommodity       = mcfdata->rowcommodity;
2264 	#endif
2265 	
2266 	   int* colarcid;
2267 	   int* rowarcid;
2268 	
2269 	   SCIP_ROW** rows;
2270 	   SCIP_COL** cols;
2271 	   int nrows;
2272 	   int ncols;
2273 	
2274 	   int r;
2275 	   int c;
2276 	   int i;
2277 	
2278 	#ifndef NDEBUG
2279 	   SCIP_Real* capacityrowscores  = mcfdata->capacityrowscores;
2280 	#endif
2281 	   int        *capacitycands     = mcfdata->capacitycands;
2282 	   int        ncapacitycands     = mcfdata->ncapacitycands;
2283 	
2284 	   assert(mcfdata->narcs == 0);
2285 	   assert(capacitycands != NULL || ncapacitycands == 0);
2286 	
2287 	   /* get LP data */
2288 	   SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
2289 	   SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
2290 	
2291 	   /* allocate temporary memory for extraction data */
2292 	   SCIP_CALL( SCIPallocMemoryArray(scip, &mcfdata->colarcid, ncols) );
2293 	   SCIP_CALL( SCIPallocMemoryArray(scip, &mcfdata->rowarcid, nrows) );
2294 	   colarcid = mcfdata->colarcid;
2295 	   rowarcid = mcfdata->rowarcid;
2296 	
2297 	   /* initialize arcid arrays */
2298 	   for( c = 0; c < ncols; c++ )
2299 	      colarcid[c] = -1;
2300 	   for( r = 0; r < nrows; r++ )
2301 	      rowarcid[r] = -1;
2302 	
2303 	   /* ->  loop through the list of capacity cands in non-increasing score order  */
2304 	   for( i = 0; i < ncapacitycands; i++ )
2305 	   {
2306 	      SCIP_ROW*  capacityrow;
2307 	      SCIP_COL** rowcols;
2308 	      int rowlen;
2309 	      int nassignedflowvars;
2310 	      int nunassignedflowvars;
2311 	      int k;
2312 	
2313 	      assert(capacitycands != NULL);
2314 	      r = capacitycands[i];
2315 	      assert(0 <= r && r < nrows );
2316 	      capacityrow = rows[r];
2317 	
2318 	      assert(capacityrowsigns != NULL); /* for lint */
2319 	      assert(capacityrowscores != NULL);
2320 	      assert(rowcommodity != NULL);
2321 	      assert(flowrowsigns != NULL);
2322 	
2323 	      /* row must be a capacity candidate */
2324 	      assert((capacityrowsigns[r] & (LHSPOSSIBLE | RHSPOSSIBLE)) != 0);
2325 	      assert((capacityrowsigns[r] & DISCARDED) == 0);
2326 	      assert(capacityrowscores[r] > 0.0);
2327 	
2328 	      /* row must not be already assigned */
2329 	      assert((capacityrowsigns[r] & (LHSASSIGNED | RHSASSIGNED)) == 0);
2330 	      assert(rowarcid[r] == -1);
2331 	
2332 	      /* row should not be a flow conservation constraint */
2333 	      assert( rowcommodity[r] == -1 );
2334 	      assert( (flowrowsigns[r] & (LHSASSIGNED | RHSASSIGNED)) == 0 );
2335 	
2336 	      /* count the number of already assigned and not yet assigned flow variables */
2337 	      rowcols = SCIProwGetCols(capacityrow);
2338 	      rowlen  = SCIProwGetNLPNonz(capacityrow);
2339 	      nassignedflowvars = 0;
2340 	      nunassignedflowvars = 0;
2341 	      for( k = 0; k < rowlen; k++ )
2342 	      {
2343 	         c = SCIPcolGetLPPos(rowcols[k]);
2344 	         assert(0 <= c && c < ncols);
2345 	         assert(colcommodity != NULL); /* for lint */
2346 	
2347 	         assert(-1 <= colcommodity[c] && colcommodity[c] < mcfdata->ncommodities);
2348 	         assert(-1 <= colarcid[c] && colarcid[c] < mcfdata->narcs);
2349 	
2350 	         /* ignore columns that are not flow variables */
2351 	         if( colcommodity[c] == -1 )
2352 	            continue;
2353 	
2354 	         /* check if column is already assigned to an arc */
2355 	         if( colarcid[c] >= 0 )
2356 	            nassignedflowvars++;
2357 	         else
2358 	            nunassignedflowvars++;
2359 	      }
2360 	
2361 	      /* Ignore row if all of its flow variables have already been assigned to some other arc.
2362 	       * Only accept the row as capacity constraint if at least 1/3 of its flow vars are
2363 	       * not yet assigned to some other arc.
2364 	       */
2365 	      if( nunassignedflowvars == 0 || nassignedflowvars >= nunassignedflowvars * 2 )
2366 	      {
2367 	         SCIPdebugMsg(scip, "discarding capacity candidate row %d <%s> [score:%g]: %d assigned flowvars, %d unassigned flowvars\n",
2368 	                          r, SCIProwGetName(capacityrow), mcfdata->capacityrowscores[r], nassignedflowvars, nunassignedflowvars);
2369 	         capacityrowsigns[r] |= DISCARDED;
2370 	         continue;
2371 	      }
2372 	
2373 	      /* create new arc -- store capacity row */
2374 	      assert(mcfdata->narcs <= mcfdata->capacityrowssize);
2375 	      if( mcfdata->narcs == mcfdata->capacityrowssize )
2376 	      {
2377 	         mcfdata->capacityrowssize = MAX(2*mcfdata->capacityrowssize, mcfdata->narcs+1);
2378 	         SCIP_CALL( SCIPreallocMemoryArray(scip, &mcfdata->capacityrows, mcfdata->capacityrowssize) );
2379 	      }
2380 	      assert(mcfdata->narcs < mcfdata->capacityrowssize);
2381 	      assert(mcfdata->narcs < nrows);
2382 	
2383 	      mcfdata->capacityrows[mcfdata->narcs] = capacityrow;
2384 	
2385 	      /* assign the capacity row to a new arc id */
2386 	      assert(0 <= r && r < nrows);
2387 	      rowarcid[r] = mcfdata->narcs;
2388 	
2389 	      /* decide which sign to use */
2390 	      if( (capacityrowsigns[r] & RHSPOSSIBLE) != 0 )
2391 	         capacityrowsigns[r] |= RHSASSIGNED;
2392 	      else
2393 	      {
2394 	         assert((capacityrowsigns[r] & LHSPOSSIBLE) != 0);
2395 	         capacityrowsigns[r] |= LHSASSIGNED;
2396 	      }
2397 	
2398 	      SCIPdebugMsg(scip, "assigning capacity row %d <%s> with sign %+d to arc %d [score:%g]: %d assigned flowvars, %d unassigned flowvars\n",
2399 	                       r, SCIProwGetName(capacityrow), (capacityrowsigns[r] & RHSASSIGNED) != 0 ? +1 : -1, mcfdata->narcs,
2400 	                       mcfdata->capacityrowscores[r], nassignedflowvars, nunassignedflowvars);
2401 	
2402 	      /* assign all involved flow variables to the new arc id */
2403 	      for( k = 0; k < rowlen; k++ )
2404 	      {
2405 	         int rowc = SCIPcolGetLPPos(rowcols[k]);
2406 	         assert(0 <= rowc && rowc < ncols);
2407 	         assert(colcommodity != NULL); /* for lint */
2408 	
2409 	         /* due to aggregations in preprocessing it may happen that a flow variable appears in multiple capacity constraints;
2410 	          * in this case, assign it to the first that has been found
2411 	          */
2412 	         if( colcommodity[rowc] >= 0 && colarcid[rowc] == -1 )
2413 	            colarcid[rowc] = mcfdata->narcs;
2414 	      }
2415 	
2416 	      /* increase number of arcs */
2417 	      mcfdata->narcs++;
2418 	   }
2419 	   return SCIP_OKAY;
2420 	}  /* END extractcapacities */
2421 	
2422 	
2423 	/** collects all flow columns of all commodities (except the one of the base row) that are incident to the node described by the given flow row */
2424 	static
2425 	void collectIncidentFlowCols(
2426 	   SCIP*                 scip,               /**< SCIP data structure */
2427 	   MCFDATA*              mcfdata,            /**< internal MCF extraction data to pass to subroutines */
2428 	   SCIP_ROW*             flowrow,            /**< flow conservation constraint that defines the node */
2429 	   int                   basecommodity       /**< commodity of the base row */
2430 	   )
2431 	{
2432 	   int*           colcommodity  = mcfdata->colcommodity;
2433 	   int*           colarcid      = mcfdata->colarcid;
2434 	   int*           newcols       = mcfdata->newcols;
2435 	   SCIP_ROW**     capacityrows  = mcfdata->capacityrows;
2436 	   SCIP_Bool*     colisincident = mcfdata->colisincident;
2437 	
2438 	   SCIP_COL** rowcols;
2439 	   int rowlen;
2440 	   int i;
2441 	
2442 	#ifndef NDEBUG
2443 	   /* check that the marker array is correctly initialized */
2444 	   for( i = 0; i < SCIPgetNLPCols(scip); i++ )
2445 	      assert(!colisincident[i]);
2446 	#endif
2447 	
2448 	   /* loop through all flow columns in the flow conservation constraint */
2449 	   rowcols = SCIProwGetCols(flowrow);
2450 	   rowlen = SCIProwGetNLPNonz(flowrow);
2451 	   mcfdata->nnewcols = 0;
2452 	
2453 	   for( i = 0; i < rowlen; i++ )
2454 	   {
2455 	      SCIP_COL** capacityrowcols;
2456 	      int capacityrowlen;
2457 	      int arcid;
2458 	      int c;
2459 	      int j;
2460 	
2461 	      c = SCIPcolGetLPPos(rowcols[i]);
2462 	      assert(0 <= c && c < SCIPgetNLPCols(scip));
2463 	
2464 	      /* get arc id of the column in the flow conservation constraint */
2465 	      arcid = colarcid[c];
2466 	      if( arcid == -1 )
2467 	         continue;
2468 	      assert(arcid < mcfdata->narcs);
2469 	
2470 	      /* collect flow variables in the capacity constraint of this arc */
2471 	      assert(capacityrows[arcid] != NULL);
2472 	      capacityrowcols = SCIProwGetCols(capacityrows[arcid]);
2473 	      capacityrowlen = SCIProwGetNLPNonz(capacityrows[arcid]);
2474 	
2475 	      for( j = 0; j < capacityrowlen; j++ )
2476 	      {
2477 	         int caprowc;
2478 	
2479 	         caprowc = SCIPcolGetLPPos(capacityrowcols[j]);
2480 	         assert(0 <= caprowc && caprowc < SCIPgetNLPCols(scip));
2481 	
2482 	         /* ignore columns that do not belong to a commodity, i.e., are not flow variables */
2483 	         if( colcommodity[caprowc] == -1 )
2484 	         {
2485 	            assert(colarcid[caprowc] == -1);
2486 	            continue;
2487 	         }
2488 	         assert(colarcid[caprowc] <= arcid); /* colarcid < arcid if column belongs to multiple arcs, for example, due to an aggregation in presolving */
2489 	
2490 	         /* ignore columns in the same commodity as the base row */
2491 	         if( colcommodity[caprowc] == basecommodity )
2492 	            continue;
2493 	
2494 	         /* if not already done, collect the column */
2495 	         if( !colisincident[caprowc] )
2496 	         {
2497 	            assert(mcfdata->nnewcols < SCIPgetNLPCols(scip));
2498 	            colisincident[caprowc] = TRUE;
2499 	            newcols[mcfdata->nnewcols] = caprowc;
2500 	            mcfdata->nnewcols++;
2501 	         }
2502 	      }
2503 	   }
2504 	}
2505 	
2506 	/** compares given row against a base node flow row and calculates a similarity score;
2507 	 *  score is 0.0 if the rows are incompatible
2508 	 */
2509 	static
2510 	SCIP_RETCODE getNodeSimilarityScore(
2511 	   SCIP*                 scip,               /**< SCIP data structure */
2512 	   MCFDATA*              mcfdata,            /**< internal MCF extraction data to pass to subroutines */
2513 	   int                   baserowlen,         /**< length of base node flow row */
2514 	   int*                  basearcpattern,     /**< arc pattern of base node flow row */
2515 	   int                   basenposuncap,      /**< number of uncapacitated vars in base node flow row with positive coeff*/
2516 	   int                   basenneguncap,      /**< number of uncapacitated vars in base node flow row with negative coeff*/
2517 	   SCIP_ROW*             row,                /**< row to compare against base node flow row */
2518 	   SCIP_Real*            score,              /**< pointer to store the similarity score */
2519 	   SCIP_Bool*            invertcommodity     /**< pointer to store whether the arcs in the commodity of the row have
2520 	                                              *   to be inverted for the row to be compatible to the base row */
2521 	   )
2522 	{
2523 	   unsigned char*    flowrowsigns   = mcfdata->flowrowsigns;
2524 	   int*              commoditysigns = mcfdata->commoditysigns;
2525 	   int               narcs          = mcfdata->narcs;
2526 	   int*              rowcommodity   = mcfdata->rowcommodity;
2527 	   int*              colarcid       = mcfdata->colarcid;
2528 	   int*              arcpattern     = mcfdata->zeroarcarray;
2529 	   SCIP_MCFMODELTYPE modeltype      = mcfdata->modeltype;
2530 	
2531 	   SCIP_COL** rowcols;
2532 	   SCIP_Real* rowvals;
2533 	   int nposuncap;
2534 	   int nneguncap;
2535 	   int ncols;
2536 	   int rowlen;
2537 	   int rowcom;
2538 	   int rowcomsign;
2539 	   SCIP_Bool incompatible;
2540 	   SCIP_Real overlap;
2541 	   int* overlappingarcs;
2542 	   int noverlappingarcs;
2543 	   int r;
2544 	   int i;
2545 	
2546 	   *score = 0.0;
2547 	   *invertcommodity = FALSE;
2548 	
2549 	#ifndef NDEBUG
2550 	   for( i = 0; i < narcs; i++ )
2551 	      assert(arcpattern[i] == 0);
2552 	#endif
2553 	
2554 	   /* allocate temporary memory */
2555 	   SCIP_CALL( SCIPallocBufferArray(scip, &overlappingarcs, narcs) );
2556 	
2557 	   r = SCIProwGetLPPos(row);
2558 	   assert(0 <= r && r < SCIPgetNLPRows(scip));
2559 	   assert((flowrowsigns[r] & (LHSASSIGNED | RHSASSIGNED)) != 0);
2560 	   rowcom = rowcommodity[r];
2561 	   assert(0 <= rowcom && rowcom < mcfdata->ncommodities);
2562 	   rowcomsign = commoditysigns[rowcom];
2563 	   assert(-1 <= rowcomsign && rowcomsign <= +1);
2564 	
2565 	   rowcols = SCIProwGetCols(row);
2566 	   rowvals = SCIProwGetVals(row);
2567 	   rowlen = SCIProwGetNLPNonz(row);
2568 	   incompatible = FALSE;
2569 	   noverlappingarcs = 0;
2570 	   nposuncap=0;
2571 	   nneguncap=0;
2572 	   ncols = SCIPgetNLPCols(scip);
2573 	   for( i = 0; i < rowlen; i++ )
2574 	   {
2575 	      int c;
2576 	      int arcid;
2577 	      int valsign;
2578 	
2579 	      c = SCIPcolGetLPPos(rowcols[i]);
2580 	      assert(0 <= c && c < SCIPgetNLPCols(scip));
2581 	
2582 	      /* get the sign of the coefficient in the flow conservation constraint */
2583 	      valsign = (rowvals[i] > 0.0 ? +1 : -1);
2584 	      if( (flowrowsigns[r] & LHSASSIGNED) != 0 )
2585 	         valsign *= -1;
2586 	      if( (flowrowsigns[r] & INVERTED) != 0 )
2587 	         valsign *= -1;
2588 	
2589 	      arcid = colarcid[c];
2590 	      if( arcid == -1 )
2591 	      {
2592 	         if( valsign > 0 )
2593 	            nposuncap++;
2594 	         else
2595 	            nneguncap++;
2596 	         continue;
2597 	      }
2598 	      assert(arcid < narcs);
2599 	
2600 	      /* check if this arc is also member of the base row */
2601 	      if( basearcpattern[arcid] != 0 )
2602 	      {
2603 	         /* check if the sign of the arc matches in the directed case */
2604 	         if( modeltype == SCIP_MCFMODELTYPE_DIRECTED )
2605 	         {
2606 	            int validcomsign;
2607 	
2608 	            if( ( valsign * basearcpattern[arcid] ) > 0 )
2609 	               validcomsign = +1;
2610 	            else
2611 	               validcomsign = -1;
2612 	
2613 	            if( rowcomsign == 0 )
2614 	            {
2615 	               /* the first entry decides whether we have to invert the commodity */
2616 	               rowcomsign = validcomsign;
2617 	            }
2618 	            else if( rowcomsign != validcomsign )
2619 	            {
2620 	               /* the signs do not fit: this is incompatible */
2621 	               incompatible = TRUE;
2622 	               break;
2623 	            }
2624 	         }
2625 	         else
2626 	         {
2627 	            /* in the undirected case, we ignore the sign of the coefficient */
2628 	            valsign = +1;
2629 	         }
2630 	
2631 	         /* store overlapping arc pattern */
2632 	         if( arcpattern[arcid] == 0 )
2633 	         {
2634 	            overlappingarcs[noverlappingarcs] = arcid;
2635 	            noverlappingarcs++;
2636 	         }
2637 	         arcpattern[arcid] += valsign;
2638 	      }
2639 	   }
2640 	
2641 	   /* calculate the weighted overlap and reset the zeroarcarray */
2642 	   overlap = 0.0;
2643 	   for( i = 0; i < noverlappingarcs; i++ )
2644 	   {
2645 	      SCIP_Real basenum;
2646 	      SCIP_Real arcnum;
2647 	      int arcid;
2648 	
2649 	      arcid = overlappingarcs[i];
2650 	      assert(0 <= arcid && arcid < narcs);
2651 	      assert(modeltype == SCIP_MCFMODELTYPE_UNDIRECTED || rowcomsign * basearcpattern[arcid] * arcpattern[arcid] > 0);
2652 	
2653 	      basenum = ABS(basearcpattern[arcid]);
2654 	      arcnum = ABS(arcpattern[arcid]);
2655 	      assert(basenum != 0.0);
2656 	      assert(arcnum != 0.0);
2657 	
2658 	      if( basenum > arcnum )
2659 	         overlap += arcnum/basenum;
2660 	      else
2661 	         overlap += basenum/arcnum;
2662 	
2663 	      arcpattern[arcid] = 0;
2664 	   }
2665 	
2666 	/* calculate the score: maximize overlap and use minimal number of non-overlapping entries as tie breaker */
2667 	   if( !incompatible && overlap > 0.0 )
2668 	   {
2669 	      /* flow variables with arc-id */
2670 	      int rowarcs = rowlen - nposuncap - nneguncap;
2671 	      int baserowarcs = baserowlen - basenposuncap - basenneguncap;
2672 	
2673 	      assert(overlap <= (SCIP_Real) rowlen);
2674 	      assert(overlap <= (SCIP_Real) baserowlen);
2675 	      assert(noverlappingarcs >= 1);
2676 	
2677 	      *invertcommodity = (rowcomsign == -1);
2678 	
2679 	      /* only one overlapping arc is very dangerous,
2680 	      since this can also be the other end node of the arc */
2681 	      if( noverlappingarcs >= 2 )
2682 	         *score += 1000.0;
2683 	
2684 	      assert(rowarcs >= 0 && baserowarcs >= 0 );
2685 	      /* in the ideal undirected case there are two flow variables with the same arc-id */
2686 	      if( modeltype == SCIP_MCFMODELTYPE_DIRECTED )
2687 	         *score = overlap - (rowarcs + baserowarcs - 2.0 * overlap)/(2.0 * ncols + 1.0);
2688 	      else
2689 	         *score = overlap - (rowarcs + baserowarcs - 4.0 * overlap)/(2.0 * ncols + 1.0);
2690 	
2691 	      /* Also use number of uncapacitated flowvars (variables without arcid) as tie-breaker */
2692 	      if(*invertcommodity)
2693 	         *score += 1.0 - (ABS(nneguncap - basenposuncap) + ABS(nposuncap - basenneguncap))/(2.0 * ncols + 1.0);
2694 	      else
2695 	         *score += 1.0 - (ABS(nposuncap - basenposuncap) + ABS(nneguncap - basenneguncap))/(2.0 * ncols + 1.0);
2696 	
2697 	      *score = MAX(*score, 1e-6); /* score may get negative due to many columns having the same arcid */
2698 	   }
2699 	
2700 	   SCIPdebugMsg(scip, " -> node similarity: row <%s>: incompatible=%u overlap=%g rowlen=%d baserowlen=%d score=%g\n",
2701 	                    SCIProwGetName(row), incompatible, overlap, rowlen, baserowlen, *score);
2702 	
2703 	   /* free temporary memory */
2704 	   SCIPfreeBufferArray(scip, &overlappingarcs);
2705 	
2706 	   return SCIP_OKAY;
2707 	}
2708 	
2709 	/** assigns node ids to flow conservation constraints */
2710 	static
2711 	SCIP_RETCODE extractNodes(
2712 	   SCIP*                 scip,               /**< SCIP data structure */
2713 	   MCFDATA*              mcfdata             /**< internal MCF extraction data to pass to subroutines */
2714 	   )
2715 	{
2716 	   unsigned char*    flowrowsigns   = mcfdata->flowrowsigns;
2717 	   int               ncommodities   = mcfdata->ncommodities;
2718 	   int*              commoditysigns = mcfdata->commoditysigns;
2719 	   int               narcs          = mcfdata->narcs;
2720 	   int*              flowcands      = mcfdata->flowcands;
2721 	   int               nflowcands     = mcfdata->nflowcands;
2722 	   int*              rowcommodity   = mcfdata->rowcommodity;
2723 	   int*              colarcid       = mcfdata->colarcid;
2724 	   int*              newcols        = mcfdata->newcols;
2725 	   SCIP_MCFMODELTYPE modeltype      = mcfdata->modeltype;
2726 	   int*              rownodeid;
2727 	   SCIP_Bool*        colisincident;
2728 	   SCIP_Bool*        rowprocessed;
2729 	
2730 	   SCIP_ROW** rows;
2731 	   SCIP_COL** cols;
2732 	   int nrows;
2733 	   int ncols;
2734 	
2735 	   int* arcpattern;
2736 	   int  nposuncap;
2737 	   int  nneguncap;
2738 	   SCIP_ROW** bestflowrows;
2739 	   SCIP_Real* bestscores;
2740 	   SCIP_Bool* bestinverted;
2741 	   int r;
2742 	   int c;
2743 	   int n;
2744 	
2745 	   assert(mcfdata->nnodes == 0);
2746 	   assert(modeltype != SCIP_MCFMODELTYPE_AUTO);
2747 	
2748 	   /* get LP data */
2749 	   SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
2750 	   SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
2751 	
2752 	   /* allocate temporary memory */
2753 	   SCIP_CALL( SCIPallocMemoryArray(scip, &mcfdata->rownodeid, nrows) );
2754 	   SCIP_CALL( SCIPallocMemoryArray(scip, &mcfdata->colisincident, ncols) );
2755 	   SCIP_CALL( SCIPallocMemoryArray(scip, &mcfdata->zeroarcarray, narcs) );
2756 	   BMSclearMemoryArray(mcfdata->zeroarcarray, narcs);
2757 	   rownodeid = mcfdata->rownodeid;
2758 	   colisincident = mcfdata->colisincident;
2759 	
2760 	   /* allocate temporary local memory */
2761 	   SCIP_CALL( SCIPallocBufferArray(scip, &arcpattern, narcs) );
2762 	   SCIP_CALL( SCIPallocBufferArray(scip, &bestflowrows, ncommodities) );
2763 	   SCIP_CALL( SCIPallocBufferArray(scip, &bestscores, ncommodities) );
2764 	   SCIP_CALL( SCIPallocBufferArray(scip, &bestinverted, ncommodities) );
2765 	   SCIP_CALL( SCIPallocBufferArray(scip, &rowprocessed, nrows) );
2766 	
2767 	   /* initialize temporary memory */
2768 	   for( r = 0; r < nrows; r++ )
2769 	      rownodeid[r] = -1;
2770 	   for( c = 0; c < ncols; c++ )
2771 	      colisincident[c] = FALSE;
2772 	
2773 	   assert(flowcands != NULL || nflowcands == 0);
2774 	
2775 	   /* process all flow conservation constraints that have been used */
2776 	   for( n = 0; n < nflowcands; n++ )
2777 	   {
2778 	      SCIP_COL** rowcols;
2779 	      SCIP_Real* rowvals;
2780 	      int rowlen;
2781 	      int rowscale;
2782 	      int basecommodity;
2783 	      int i;
2784 	
2785 	      assert(flowcands != NULL);
2786 	      r = flowcands[n];
2787 	      assert(0 <= r && r < nrows);
2788 	      assert(rowcommodity != NULL);
2789 	
2790 	      /* ignore rows that are not used as flow conservation constraint */
2791 	      basecommodity = rowcommodity[r];
2792 	      if( basecommodity == -1 )
2793 	         continue;
2794 	      assert((flowrowsigns[r] & (LHSASSIGNED | RHSASSIGNED)) != 0);
2795 	      assert(mcfdata->rowarcid[r] == -1);
2796 	
2797 	      /* skip rows that are already assigned to a node */
2798 	      if( rownodeid[r] >= 0 )
2799 	         continue;
2800 	
2801 	      /* assign row to new node id */
2802 	      SCIPdebugMsg(scip, "assigning row %d <%s> of commodity %d to node %d [score: %g]\n",
2803 	                       r, SCIProwGetName(rows[r]), basecommodity, mcfdata->nnodes, mcfdata->flowrowscores[r]);
2804 	      rownodeid[r] = mcfdata->nnodes;
2805 	
2806 	      /* increase number of nodes */
2807 	      mcfdata->nnodes++;
2808 	
2809 	      /* For single commodity models we are done --
2810 	       * no matching flow rows need to be found
2811 	       */
2812 	      if(ncommodities == 1)
2813 	         continue;
2814 	
2815 	      /* get the arc pattern of the flow row */
2816 	      BMSclearMemoryArray(arcpattern, narcs);
2817 	      nposuncap=0;
2818 	      nneguncap=0;
2819 	
2820 	      rowcols = SCIProwGetCols(rows[r]);
2821 	      rowvals = SCIProwGetVals(rows[r]);
2822 	      rowlen = SCIProwGetNLPNonz(rows[r]);
2823 	
2824 	      assert(commoditysigns != NULL);
2825 	
2826 	      if( (flowrowsigns[r] & RHSASSIGNED) != 0 )
2827 	         rowscale = +1;
2828 	      else
2829 	         rowscale = -1;
2830 	      if( (flowrowsigns[r] & INVERTED) != 0 )
2831 	         rowscale *= -1;
2832 	      if( commoditysigns[basecommodity] == -1 )
2833 	         rowscale *= -1;
2834 	
2835 	      for( i = 0; i < rowlen; i++ )
2836 	      {
2837 	         int arcid;
2838 	
2839 	         c = SCIPcolGetLPPos(rowcols[i]);
2840 	         assert(0 <= c && c < ncols);
2841 	         arcid = colarcid[c];
2842 	         if( arcid >= 0 )
2843 	         {
2844 	            /* due to presolving we may have multiple flow variables of the same arc in the row */
2845 	            if( modeltype == SCIP_MCFMODELTYPE_UNDIRECTED || rowscale * rowvals[i] > 0.0 )
2846 	               arcpattern[arcid]++;
2847 	            else
2848 	               arcpattern[arcid]--;
2849 	         }
2850 	         /* we also count variables that have no arc -- these have no capacity constraint --> uncapacitated */
2851 	         else
2852 	         {
2853 	            if( modeltype == SCIP_MCFMODELTYPE_UNDIRECTED || rowscale * rowvals[i] > 0.0 )
2854 	               nposuncap++;
2855 	            else
2856 	               nneguncap++;
2857 	         }
2858 	      }
2859 	
2860 	      /* initialize arrays to store best flow rows */
2861 	      for( i = 0; i < ncommodities; i++ )
2862 	      {
2863 	         bestflowrows[i] = NULL;
2864 	         bestscores[i] = 0.0;
2865 	         bestinverted[i] = FALSE;
2866 	      }
2867 	
2868 	      /* collect columns that are member of incident arc capacity constraints */
2869 	      collectIncidentFlowCols(scip, mcfdata, rows[r], basecommodity);
2870 	
2871 	      /* initialize rowprocessed array */
2872 	      BMSclearMemoryArray(rowprocessed, nrows);
2873 	
2874 	      /* identify flow conservation constraints in other commodities that match this node;
2875 	       * search for flow rows in the column vectors of the incident columns
2876 	       */
2877 	      for( i = 0; i < mcfdata->nnewcols; i++ )
2878 	      {
2879 	         SCIP_ROW** colrows;
2880 	         int collen;
2881 	         int j;
2882 	
2883 	         assert(newcols != NULL);
2884 	         c = newcols[i];
2885 	         assert(0 <= c && c < ncols);
2886 	         assert(mcfdata->colcommodity[c] >= 0);
2887 	         assert(mcfdata->colcommodity[c] != basecommodity);
2888 	
2889 	         /* clean up the marker array */
2890 	         assert(colisincident[c]);
2891 	         colisincident[c] = FALSE;
2892 	
2893 	         /* scan column vector for flow conservation constraints */
2894 	         colrows = SCIPcolGetRows(cols[c]);
2895 	         collen = SCIPcolGetNLPNonz(cols[c]);
2896 	
2897 	         for( j = 0; j < collen; j++ )
2898 	         {
2899 	            int colr;
2900 	            int rowcom;
2901 	            SCIP_Real score;
2902 	            SCIP_Bool invertcommodity;
2903 	
2904 	            colr = SCIProwGetLPPos(colrows[j]);
2905 	            assert(0 <= colr && colr < nrows);
2906 	
2907 	            /* ignore rows that have already been processed */
2908 	            if( rowprocessed[colr] )
2909 	               continue;
2910 	            rowprocessed[colr] = TRUE;
2911 	
2912 	            /* ignore rows that are not flow conservation constraints in the network */
2913 	            rowcom = rowcommodity[colr];
2914 	            assert(rowcom != basecommodity);
2915 	            if( rowcom == -1 )
2916 	               continue;
2917 	
2918 	            assert(rowcom == mcfdata->colcommodity[c]);
2919 	            assert((flowrowsigns[colr] & (LHSASSIGNED | RHSASSIGNED)) != 0);
2920 	            assert(mcfdata->rowarcid[colr] == -1);
2921 	
2922 	            /* ignore rows that are already assigned to a node */
2923 	            if( rownodeid[colr] >= 0 )
2924 	               continue;
2925 	
2926 	            /* compare row against arc pattern and calculate score */
2927 	            SCIP_CALL( getNodeSimilarityScore(scip, mcfdata, rowlen, arcpattern,
2928 	                       nposuncap, nneguncap, colrows[j], &score, &invertcommodity) );
2929 	            assert( !SCIPisNegative(scip, score) );
2930 	
2931 	            if( score > bestscores[rowcom] )
2932 	            {
2933 	               bestflowrows[rowcom] = colrows[j];
2934 	               bestscores[rowcom] = score;
2935 	               bestinverted[rowcom] = invertcommodity;
2936 	            }
2937 	         }
2938 	      }
2939 	      assert(bestflowrows[basecommodity] == NULL);
2940 	
2941 	      /* for each commodity, pick the best flow conservation constraint to define this node */
2942 	      for( i = 0; i < ncommodities; i++ )
2943 	      {
2944 	         int comr;
2945 	
2946 	         if( bestflowrows[i] == NULL )
2947 	            continue;
2948 	
2949 	         comr = SCIProwGetLPPos(bestflowrows[i]);
2950 	         assert(0 <= comr && comr < nrows);
2951 	         assert(rowcommodity[comr] == i);
2952 	         assert((flowrowsigns[comr] & (LHSASSIGNED | RHSASSIGNED)) != 0);
2953 	         assert(rownodeid[comr] == -1);
2954 	         assert(mcfdata->nnodes >= 1);
2955 	         /* assign flow row to current node */
2956 	         SCIPdebugMsg(scip, " -> assigning row %d <%s> of commodity %d to node %d [invert:%u]\n",
2957 	                          comr, SCIProwGetName(rows[comr]), i, mcfdata->nnodes-1, bestinverted[i]);
2958 	         rownodeid[comr] = mcfdata->nnodes-1;
2959 	
2960 	         /* fix the direction of the arcs of the commodity */
2961 	         if( bestinverted[i] )
2962 	         {
2963 	            assert(commoditysigns[i] != +1);
2964 	            commoditysigns[i] = -1;
2965 	         }
2966 	         else
2967 	         {
2968 	            assert(commoditysigns[i] != -1);
2969 	            commoditysigns[i] = +1;
2970 	         }
2971 	      }
2972 	   }
2973 	
2974 	   /* free local temporary memory */
2975 	
2976 	   SCIPfreeBufferArray(scip, &rowprocessed);
2977 	   SCIPfreeBufferArray(scip, &bestinverted);
2978 	   SCIPfreeBufferArray(scip, &bestscores);
2979 	   SCIPfreeBufferArray(scip, &bestflowrows);
2980 	   SCIPfreeBufferArray(scip, &arcpattern);
2981 	
2982 	   return SCIP_OKAY;
2983 	}
2984 	
2985 	/** if there are still undecided commodity signs, fix them to +1 */
2986 	static
2987 	void fixCommoditySigns(
2988 	   MCFDATA*              mcfdata             /**< internal MCF extraction data to pass to subroutines */
2989 	   )
2990 	{
2991 	   int* commoditysigns = mcfdata->commoditysigns;
2992 	   int k;
2993 	
2994 	   for( k = 0; k < mcfdata->ncommodities; k++ )
2995 	   {
2996 	      if( commoditysigns[k] == 0 )
2997 	         commoditysigns[k] = +1;
2998 	   }
2999 	}
3000 	
3001 	
3002 	/** identifies the (at most) two nodes which contain the given flow variable */
3003 	static
3004 	void getIncidentNodes(
3005 	   SCIP*                 scip,               /**< SCIP data structure */
3006 	   MCFDATA*              mcfdata,            /**< internal MCF extraction data to pass to subroutines */
3007 	   SCIP_COL*             col,                /**< flow column */
3008 	   int*                  sourcenode,         /**< pointer to store the source node of the flow column */
3009 	   int*                  targetnode          /**< pointer to store the target node of the flow column */
3010 	   )
3011 	{
3012 	   unsigned char*    flowrowsigns     = mcfdata->flowrowsigns;
3013 	   int*              commoditysigns   = mcfdata->commoditysigns;
3014 	   int*              rowcommodity     = mcfdata->rowcommodity;
3015 	   int*              rownodeid        = mcfdata->rownodeid;
3016 	   int*              colsources       = mcfdata->colsources;
3017 	   int*              coltargets       = mcfdata->coltargets;
3018 	
3019 	   SCIP_ROW** colrows;
3020 	   SCIP_Real* colvals;
3021 	   int collen;
3022 	   int c;
3023 	   int i;
3024 	
3025 	   assert(sourcenode != NULL);
3026 	   assert(targetnode != NULL);
3027 	   assert(colsources != NULL);
3028 	   assert(coltargets != NULL);
3029 	
3030 	   c = SCIPcolGetLPPos(col);
3031 	   assert(0 <= c && c < SCIPgetNLPCols(scip));
3032 	
3033 	   /* check if we have this column already in cache */
3034 	   if( colsources[c] >= -1 )
3035 	   {
3036 	      assert(coltargets[c] >= -1);
3037 	      *sourcenode = colsources[c];
3038 	      *targetnode = coltargets[c];
3039 	   }
3040 	   else
3041 	   {
3042 	      *sourcenode = -1;
3043 	      *targetnode = -1;
3044 	
3045 	      /* search for flow conservation rows in the column vector */
3046 	      colrows = SCIPcolGetRows(col);
3047 	      colvals = SCIPcolGetVals(col);
3048 	      collen = SCIPcolGetNLPNonz(col);
3049 	      for( i = 0; i < collen; i++ )
3050 	      {
3051 	         int r;
3052 	
3053 	         r = SCIProwGetLPPos(colrows[i]);
3054 	         assert(0 <= r && r < SCIPgetNLPRows(scip));
3055 	
3056 	         if( rownodeid[r] >= 0 )
3057 	         {
3058 	            int v;
3059 	            int k;
3060 	            int scale;
3061 	
3062 	            v = rownodeid[r];
3063 	            k = rowcommodity[r];
3064 	            assert(0 <= v && v < mcfdata->nnodes);
3065 	            assert(0 <= k && k < mcfdata->ncommodities);
3066 	            assert((flowrowsigns[r] & (LHSASSIGNED | RHSASSIGNED)) != 0);
3067 	
3068 	            /* check whether the flow row is inverted */
3069 	            scale = +1;
3070 	            if( (flowrowsigns[r] & LHSASSIGNED) != 0 )
3071 	               scale *= -1;
3072 	            if( (flowrowsigns[r] & INVERTED) != 0 )
3073 	               scale *= -1;
3074 	            if( commoditysigns[k] == -1 )
3075 	               scale *= -1;
3076 	
3077 	            /* decide whether this node is source or target */
3078 	            if( ( scale * colvals[i] ) > 0.0 )
3079 	            {
3080 	               assert(*sourcenode == -1);
3081 	               *sourcenode = v;
3082 	               if( *targetnode >= 0 )
3083 	                  break;
3084 	            }
3085 	            else
3086 	            {
3087 	               assert(*targetnode == -1);
3088 	               *targetnode = v;
3089 	               if( *sourcenode >= 0 )
3090 	                  break;
3091 	            }
3092 	         }
3093 	      }
3094 	
3095 	      /* cache result for future use */
3096 	      colsources[c] = *sourcenode;
3097 	      coltargets[c] = *targetnode;
3098 	   }
3099 	}
3100 	
3101 	/** find uncapacitated arcs for flow columns that have no associated arc yet */
3102 	static
3103 	SCIP_RETCODE findUncapacitatedArcs(
3104 	   SCIP*                 scip,               /**< SCIP data structure */
3105 	   MCFDATA*              mcfdata             /**< internal MCF extraction data to pass to subroutines */
3106 	   )
3107 	{
3108 	   int*              flowcands          = mcfdata->flowcands;
3109 	   int               nflowcands         = mcfdata->nflowcands;
3110 	#ifndef NDEBUG
3111 	   unsigned char*    flowrowsigns       = mcfdata->flowrowsigns;
3112 	   int*              colcommodity       = mcfdata->colcommodity;
3113 	   int*              rowcommodity       = mcfdata->rowcommodity;
3114 	#endif
3115 	   int*              rownodeid          = mcfdata->rownodeid;
3116 	   int*              colarcid           = mcfdata->colarcid;
3117 	   int               nnodes             = mcfdata->nnodes;
3118 	   int               ncommodities       = mcfdata->ncommodities;
3119 	   SCIP_MCFMODELTYPE modeltype          = mcfdata->modeltype;
3120 	
3121 	   SCIP_ROW** rows;
3122 	   SCIP_COL** cols;
3123 	   int ncols;
3124 	
3125 	   int* sortedflowcands;
3126 	   int* sortedflowcandnodeid;
3127 	   int* sourcecount;
3128 	   int* targetcount;
3129 	   int* adjnodes;
3130 	   int nadjnodes;
3131 	   int* inccols;
3132 	   int ninccols;
3133 	   int arcsthreshold;
3134 	
3135 	   int v;
3136 	   int n;
3137 	
3138 	   /* there should have been a cleanup already */
3139 	   assert(mcfdata->nemptycommodities == 0);
3140 	   assert(ncommodities >= 0);
3141 	   assert(modeltype == SCIP_MCFMODELTYPE_UNDIRECTED || modeltype == SCIP_MCFMODELTYPE_DIRECTED);
3142 	
3143 	   /* avoid trivial cases */
3144 	   if( ncommodities == 0 || nflowcands == 0 || nnodes == 0 )
3145 	      return SCIP_OKAY;
3146 	
3147 	   SCIPdebugMsg(scip, "finding uncapacitated arcs\n");
3148 	
3149 	   /* get LP data */
3150 	   rows = SCIPgetLPRows(scip);
3151 	   cols = SCIPgetLPCols(scip);
3152 	   ncols = SCIPgetNLPCols(scip);
3153 	   assert(rows != NULL);
3154 	   assert(cols != NULL || ncols == 0);
3155 	
3156 	   /* allocate temporary memory */
3157 	   SCIP_CALL( SCIPallocBufferArray(scip, &sortedflowcands, nflowcands) );
3158 	   SCIP_CALL( SCIPallocBufferArray(scip, &sortedflowcandnodeid, nflowcands) );
3159 	   SCIP_CALL( SCIPallocBufferArray(scip, &sourcecount, nnodes) );
3160 	   SCIP_CALL( SCIPallocBufferArray(scip, &targetcount, nnodes) );
3161 	   SCIP_CALL( SCIPallocBufferArray(scip, &adjnodes, nnodes) );
3162 	   SCIP_CALL( SCIPallocBufferArray(scip, &inccols, ncols) );
3163 	
3164 	   /* copy flowcands and initialize sortedflowcandnodeid arrays */
3165 	   for( n = 0; n < nflowcands; n++ )
3166 	   {
3167 	      sortedflowcands[n] = flowcands[n];
3168 	      sortedflowcandnodeid[n] = rownodeid[flowcands[n]];
3169 	   }
3170 	
3171 	   /* sort flow candidates by node id */
3172 	   SCIPsortIntInt(sortedflowcandnodeid, sortedflowcands, nflowcands);
3173 	   assert(sortedflowcandnodeid[0] <= 0);
3174 	   assert(sortedflowcandnodeid[nflowcands-1] == nnodes-1);
3175 	
3176 	   /* initialize sourcecount and targetcount arrays */
3177 	   for( v = 0; v < nnodes; v++ )
3178 	   {
3179 	      sourcecount[v] = 0;
3180 	      targetcount[v] = 0;
3181 	   }
3182 	   nadjnodes = 0;
3183 	   ninccols = 0;
3184 	
3185 	   /* we only accept an arc if at least this many flow variables give rise to this arc */
3186 	      arcsthreshold = (int) SCIPceil(scip, (SCIP_Real) ncommodities * UNCAPACITATEDARCSTRESHOLD );
3187 	
3188 	   /* in the undirected case, there are two variables per commodity in each capacity row */
3189 	   if( modeltype == SCIP_MCFMODELTYPE_UNDIRECTED )
3190 	      arcsthreshold *= 2;
3191 	
3192 	   /* skip unused flow candidates */
3193 	   for( n = 0; n < nflowcands; n++ )
3194 	   {
3195 	      if( sortedflowcandnodeid[n] >= 0 )
3196 	         break;
3197 	      assert(0 <= sortedflowcands[n] && sortedflowcands[n] < SCIPgetNLPRows(scip));
3198 	      assert(rowcommodity[sortedflowcands[n]] == -1);
3199 	   }
3200 	   assert(n < nflowcands);
3201 	   assert(sortedflowcandnodeid[n] == 0);
3202 	
3203 	   /* for each node s, count for each other node t the number of flow variables that are not yet assigned
3204 	    * to an arc and that give rise to an (s,t) arc or an (t,s) arc
3205 	    */
3206 	   for( v = 0; n < nflowcands; v++ ) /*lint !e440*/ /* for flexelint: n is used as abort criterion for loop */
3207 	   {
3208 	      int l;
3209 	
3210 	      assert(v < nnodes);
3211 	      assert(0 <= sortedflowcands[n] && sortedflowcands[n] < SCIPgetNLPRows(scip));
3212 	      assert(rowcommodity[sortedflowcands[n]] >= 0);
3213 	      assert(rownodeid[sortedflowcands[n]] == sortedflowcandnodeid[n]);
3214 	      assert(sortedflowcandnodeid[n] == v); /* we must have at least one row per node */
3215 	      assert(nadjnodes == 0);
3216 	      assert(ninccols == 0);
3217 	
3218 	      SCIPdebugMsg(scip, " node %d starts with flowcand %d: <%s>\n", v, n, SCIProwGetName(rows[sortedflowcands[n]]));
3219 	
3220 	      /* process all flow rows that belong to node v */
3221 	      for( ; n < nflowcands && sortedflowcandnodeid[n] == v; n++ )
3222 	      {
3223 	         SCIP_COL** rowcols;
3224 	         int rowlen;
3225 	         int r;
3226 	         int i;
3227 	
3228 	         r = sortedflowcands[n];
3229 	         assert((flowrowsigns[r] & (LHSASSIGNED | RHSASSIGNED)) != 0);
3230 	         assert(mcfdata->rowarcid[r] == -1);
3231 	
3232 	         /* update sourcecount and targetcount for all flow columns in the row that are not yet assigned to an arc */
3233 	         rowcols = SCIProwGetCols(rows[r]);
3234 	         rowlen  = SCIProwGetNLPNonz(rows[r]);
3235 	         for( i = 0; i < rowlen; i++ )
3236 	         {
3237 	            SCIP_COL* col;
3238 	            int arcid;
3239 	            int c;
3240 	            int s;
3241 	            int t;
3242 	
3243 	            col = rowcols[i];
3244 	            c = SCIPcolGetLPPos(col);
3245 	            assert(0 <= c && c < SCIPgetNLPCols(scip));
3246 	            arcid = colarcid[c];
3247 	            assert(-2 <= arcid && arcid < mcfdata->narcs);
3248 	            assert(rowcommodity[r] == colcommodity[c]);
3249 	
3250 	            if( arcid == -2 )
3251 	            {
3252 	               /* This is the second time we see this column, and we were unable to assign an arc
3253 	                * to this column at the first time. So, this time we can ignore it. Just reset the
3254 	                * temporary arcid -2 to -1.
3255 	                */
3256 	               colarcid[c] = -1;
3257 	            }
3258 	            else if( arcid == -1 )
3259 	            {
3260 	               int u;
3261 	
3262 	               /* identify the (at most) two nodes which contain this flow variable */
3263 	               getIncidentNodes(scip, mcfdata, col, &s, &t);
3264 	
3265 	               SCIPdebugMsg(scip, "   col <%s> [%g,%g] (s,t):(%i,%i)\n", SCIPvarGetName(SCIPcolGetVar(col)),
3266 	                                SCIPvarGetLbGlobal(SCIPcolGetVar(col)), SCIPvarGetUbGlobal(SCIPcolGetVar(col)), s, t);
3267 	
3268 	               assert(-1 <= s && s < nnodes);
3269 	               assert(-1 <= t && t < nnodes);
3270 	               assert(s == v || t == v);
3271 	               assert(s != t);
3272 	
3273 	               /* in the undirected case, always use s as other node */
3274 	               if( modeltype == SCIP_MCFMODELTYPE_UNDIRECTED && s == v )
3275 	               {
3276 	                  s = t;
3277 	                  t = v;
3278 	               }
3279 	
3280 	               /* if there is no other node than v, ignore column */
3281 	               if( s < 0 || t < 0 )
3282 	                  continue;
3283 	
3284 	               /* remember column in incidence list
3285 	                * Note: each column can be collected at most once for node v, because each column can appear in at most one
3286 	                * commodity, and in each commodity a column can have at most one +1 and one -1 entry. One of the two +/-1 entries
3287 	                * is already used for v.
3288 	                */
3289 	               assert(ninccols < ncols);
3290 	               inccols[ninccols] = c;
3291 	               ninccols++;
3292 	
3293 	               /* update source or target count */
3294 	               if( s != v )
3295 	               {
3296 	                  sourcecount[s]++;
3297 	                  u = s;
3298 	               }
3299 	               else
3300 	               {
3301 	                  targetcount[t]++;
3302 	                  u = t;
3303 	               }
3304 	
3305 	               /* if other node has been seen the first time, store it in adjlist for sparse access of count arrays */
3306 	               if( sourcecount[u] + targetcount[u] == 1 )
3307 	               {
3308 	                  assert(nadjnodes < nnodes);
3309 	                  adjnodes[nadjnodes] = u;
3310 	                  nadjnodes++;
3311 	               }
3312 	            }
3313 	         }
3314 	      }
3315 	
3316 	      /* check if we want to add uncapacitated arcs s -> v or v -> t */
3317 	      for( l = 0; l < nadjnodes; l++ )
3318 	      {
3319 	         int u;
3320 	
3321 	         u = adjnodes[l];
3322 	         assert(0 <= u && u < nnodes);
3323 	         assert(sourcecount[u] > 0 || targetcount[u] > 0);
3324 	         assert(modeltype != SCIP_MCFMODELTYPE_UNDIRECTED || targetcount[u] == 0);
3325 	         assert(ninccols >= 0);
3326 	
3327 	         /* add arcs u -> v */
3328 	         if( sourcecount[u] >= arcsthreshold )
3329 	         {
3330 	            int arcid;
3331 	            int m;
3332 	
3333 	            /* create new arc */
3334 	            SCIP_CALL( createNewArc(scip, mcfdata, u, v, &arcid) );
3335 	            SCIPdebugMsg(scip, "         -> new arc: <%i> = (%i,%i)\n", arcid, u, v);
3336 	
3337 	            /* assign arcid to all involved columns */
3338 	            for( m = 0; m < ninccols; m++ )
3339 	            {
3340 	               int c;
3341 	               int s;
3342 	               int t;
3343 	
3344 	               c = inccols[m];
3345 	               assert(0 <= c && c < ncols);
3346 	
3347 	               assert(cols != NULL);
3348 	               getIncidentNodes(scip, mcfdata, cols[c], &s, &t);
3349 	               assert(s == v || t == v);
3350 	
3351 	               if( s == u || (modeltype == SCIP_MCFMODELTYPE_UNDIRECTED && t == u) )
3352 	               {
3353 	                  SCIPdebugMsg(scip, "         -> assign arcid:%i to column <%s>\n", arcid, SCIPvarGetName(SCIPcolGetVar(cols[c])));
3354 	                  colarcid[c] = arcid;
3355 	
3356 	                  /* remove column from incidence array */
3357 	                  inccols[m] = inccols[ninccols-1];
3358 	                  ninccols--;
3359 	                  m--;
3360 	               }
3361 	            } /*lint --e{850}*/
3362 	         }
3363 	
3364 	         /* add arcs v -> u */
3365 	         if( targetcount[u] >= arcsthreshold )
3366 	         {
3367 	            int arcid;
3368 	            int m;
3369 	
3370 	            /* create new arc */
3371 	            SCIP_CALL( createNewArc(scip, mcfdata, v, u, &arcid) );
3372 	            SCIPdebugMsg(scip, "         -> new arc: <%i> = (%i,%i)\n", arcid, v, u);
3373 	
3374 	            /* assign arcid to all involved columns */
3375 	            for( m = 0; m < ninccols; m++ )
3376 	            {
3377 	               int c;
3378 	               int s;
3379 	               int t;
3380 	
3381 	               c = inccols[m];
3382 	               assert(0 <= c && c < ncols);
3383 	
3384 	               assert(cols != NULL);
3385 	               getIncidentNodes(scip, mcfdata, cols[c], &s, &t);
3386 	               assert(s == v || t == v);
3387 	
3388 	               if( t == u )
3389 	               {
3390 	                  SCIPdebugMsg(scip, "         -> assign arcid:%i to column <%s>\n", arcid, SCIPvarGetName(SCIPcolGetVar(cols[c])));
3391 	                  colarcid[c] = arcid;
3392 	
3393 	                  /* remove column from incidence array */
3394 	                  inccols[m] = inccols[ninccols-1];
3395 	                  ninccols--;
3396 	                  m--;
3397 	               }
3398 	            } /*lint --e{850}*/
3399 	         }
3400 	      }
3401 	
3402 	      /* reset sourcecount and targetcount arrays */
3403 	      for( l = 0; l < nadjnodes; l++ )
3404 	      {
3405 	         sourcecount[l] = 0;
3406 	         targetcount[l] = 0;
3407 	      }
3408 	      nadjnodes = 0;
3409 	
3410 	      /* mark the incident columns that could not be assigned to a new arc such that we do not inspect them again */
3411 	      for( l = 0; l < ninccols; l++ )
3412 	      {
3413 	         assert(colarcid[inccols[l]] == -1);
3414 	         colarcid[inccols[l]] = -2;
3415 	      }
3416 	      ninccols = 0;
3417 	   }
3418 	   assert(n == nflowcands);
3419 	   assert(v == nnodes);
3420 	
3421 	#ifdef SCIP_DEBUG
3422 	   /* eventually, we must have reset all temporary colarcid[c] = -2 settings to -1 */
3423 	   for( n = 0; n < ncols; n++ )
3424 	      assert(colarcid[n] >= -1);
3425 	#endif
3426 	
3427 	   /* free temporary memory */
3428 	   SCIPfreeBufferArray(scip, &inccols);
3429 	   SCIPfreeBufferArray(scip, &adjnodes);
3430 	   SCIPfreeBufferArray(scip, &targetcount);
3431 	   SCIPfreeBufferArray(scip, &sourcecount);
3432 	   SCIPfreeBufferArray(scip, &sortedflowcandnodeid);
3433 	   SCIPfreeBufferArray(scip, &sortedflowcands);
3434 	
3435 	   MCFdebugMessage("network after finding uncapacitated arcs has %d nodes, %d arcs, and %d commodities\n",
3436 	                   mcfdata->nnodes, mcfdata->narcs, mcfdata->ncommodities);
3437 	
3438 	   return SCIP_OKAY;
3439 	}
3440 	
3441 	/** cleans up the network: gets rid of commodities without arcs or with at most one node */
3442 	static
3443 	SCIP_RETCODE cleanupNetwork(
3444 	   SCIP*                 scip,               /**< SCIP data structure */
3445 	   MCFDATA*              mcfdata             /**< internal MCF extraction data to pass to subroutines */
3446 	   )
3447 	{
3448 	   int*       flowcands      = mcfdata->flowcands;
3449 	   int        nflowcands     = mcfdata->nflowcands;
3450 	   int*       colcommodity   = mcfdata->colcommodity;
3451 	   int*       rowcommodity   = mcfdata->rowcommodity;
3452 	   int*       colarcid       = mcfdata->colarcid;
3453 	   int*       rowarcid       = mcfdata->rowarcid;
3454 	   int*       rownodeid      = mcfdata->rownodeid;
3455 	   int        ncommodities   = mcfdata->ncommodities;
3456 	   int*       commoditysigns = mcfdata->commoditysigns;
3457 	   int        narcs          = mcfdata->narcs;
3458 	   int        nnodes         = mcfdata->nnodes;
3459 	   SCIP_ROW** capacityrows   = mcfdata->capacityrows;
3460 	
3461 	   SCIP_ROW** rows;
3462 	   int nrows;
3463 	   int ncols;
3464 	
3465 	   int* nnodespercom;
3466 	   int* narcspercom;
3467 	   SCIP_Bool* arcisincom;
3468 	   int* perm;
3469 	   int permsize;
3470 	   int maxnnodes;
3471 	   int nnodesthreshold;
3472 	   int newncommodities;
3473 	
3474 	   int i;
3475 	   int a;
3476 	   int k;
3477 	
3478 	   MCFdebugMessage("network before cleanup has %d nodes, %d arcs, and %d commodities\n", nnodes, narcs, ncommodities);
3479 	
3480 	   /* get LP data */
3481 	   SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
3482 	   ncols = SCIPgetNLPCols(scip);
3483 	
3484 	   /* allocate temporary memory */
3485 	   permsize = ncommodities;
3486 	   permsize = MAX(permsize, narcs);
3487 	   permsize = MAX(permsize, nnodes);
3488 	   SCIP_CALL( SCIPallocBufferArray(scip, &nnodespercom, ncommodities) );
3489 	   SCIP_CALL( SCIPallocBufferArray(scip, &narcspercom, ncommodities) );
3490 	   SCIP_CALL( SCIPallocBufferArray(scip, &arcisincom, ncommodities) );
3491 	   SCIP_CALL( SCIPallocBufferArray(scip, &perm, permsize) );
3492 	   BMSclearMemoryArray(nnodespercom, ncommodities);
3493 	   BMSclearMemoryArray(narcspercom, ncommodities);
3494 	
3495 	   /** @todo remove nodes without any incoming and outgoing arcs */
3496 	
3497 	   assert(flowcands != NULL || nflowcands == 0);
3498 	
3499 	   /* count the number of nodes in each commodity */
3500 	   for( i = 0; i < nflowcands; i++ )
3501 	   {
3502 	      int r;
3503 	
3504 	      assert(flowcands != NULL);
3505 	      r = flowcands[i];
3506 	      assert(0 <= r && r < nrows);
3507 	      assert((rownodeid[r] >= 0) == (rowcommodity[r] >= 0));
3508 	      if( rowcommodity[r] >= 0 )
3509 	      {
3510 	         assert(rowcommodity[r] < ncommodities);
3511 	         nnodespercom[rowcommodity[r]]++;
3512 	      }
3513 	   }
3514 	
3515 	   assert(capacityrows != NULL || narcs == 0);
3516 	
3517 	   /* count the number of arcs in each commodity */
3518 	   for( a = 0; a < narcs; a++ )
3519 	   {
3520 	      SCIP_COL** rowcols;
3521 	      int rowlen;
3522 	      int r;
3523 	      int j;
3524 	
3525 	      assert(capacityrows != NULL);
3526 	      r = SCIProwGetLPPos(capacityrows[a]);
3527 	      assert(0 <= r && r < nrows);
3528 	      assert(rowarcid[r] == a);
3529 	
3530 	      /* identify commodities which are touched by this arc capacity constraint */
3531 	      BMSclearMemoryArray(arcisincom, ncommodities);
3532 	      rowcols = SCIProwGetCols(rows[r]);
3533 	      rowlen = SCIProwGetNLPNonz(rows[r]);
3534 	      for( j = 0; j < rowlen; j++ )
3535 	      {
3536 	         int c;
3537 	
3538 	         c = SCIPcolGetLPPos(rowcols[j]);
3539 	         assert(0 <= c && c < ncols);
3540 	         if( colcommodity[c] >= 0 && colarcid[c] == a )
3541 	         {
3542 	            assert(colcommodity[c] < ncommodities);
3543 	            arcisincom[colcommodity[c]] = TRUE;
3544 	         }
3545 	      }
3546 	
3547 	      /* increase arc counters of touched commodities */
3548 	      for( k = 0; k < ncommodities; k++ )
3549 	      {
3550 	         if( arcisincom[k] )
3551 	            narcspercom[k]++;
3552 	      }
3553 	   }
3554 	
3555 	   /* calculate maximal number of nodes per commodity */
3556 	   maxnnodes = 0;
3557 	   for( k = 0; k < ncommodities; k++ )
3558 	      maxnnodes = MAX(maxnnodes, nnodespercom[k]);
3559 	
3560 	   /* we want to keep only commodities that have at least a certain size relative
3561 	    * to the largest commodity
3562 	    */
3563 	
3564 	   nnodesthreshold = (int)(MINCOMNODESFRACTION * maxnnodes);
3565 	   nnodesthreshold = MAX(nnodesthreshold, MINNODES);
3566 	   SCIPdebugMsg(scip, " -> node threshold: %d\n", nnodesthreshold);
3567 	
3568 	   /* discard trivial commodities */
3569 	   newncommodities = 0;
3570 	   for( k = 0; k < ncommodities; k++ )
3571 	   {
3572 	      SCIPdebugMsg(scip, " -> commodity %d: %d nodes, %d arcs\n", k, nnodespercom[k], narcspercom[k]);
3573 	
3574 	      /* only keep commodities of a certain size that have at least one arc */
3575 	      if( nnodespercom[k] >= nnodesthreshold && narcspercom[k] >= 1 )
3576 	      {
3577 	         assert(newncommodities <= k);
3578 	         perm[k] = newncommodities;
3579 	         commoditysigns[newncommodities] = commoditysigns[k];
3580 	         newncommodities++;
3581 	      }
3582 	      else
3583 	         perm[k] = -1;
3584 	   }
3585 	
3586 	   if( newncommodities < ncommodities )
3587 	   {
3588 	      SCIP_Bool* arcisused;
3589 	      SCIP_Bool* nodeisused;
3590 	      int newnarcs;
3591 	      int newnnodes;
3592 	      int c;
3593 	      int v;
3594 	
3595 	      SCIPdebugMsg(scip, " -> discarding %d of %d commodities\n", ncommodities - newncommodities, ncommodities);
3596 	
3597 	      SCIP_CALL( SCIPallocBufferArray(scip, &arcisused, narcs) );
3598 	      SCIP_CALL( SCIPallocBufferArray(scip, &nodeisused, nnodes) );
3599 	
3600 	      /* update data structures to new commodity ids */
3601 	      BMSclearMemoryArray(arcisused, narcs);
3602 	      BMSclearMemoryArray(nodeisused, nnodes);
3603 	      for( c = 0; c < ncols; c++ )
3604 	      {
3605 	         if( colcommodity[c] >= 0 )
3606 	         {
3607 	            assert(-1 <= colarcid[c] && colarcid[c] < narcs);
3608 	            assert(colcommodity[c] < mcfdata->ncommodities);
3609 	            colcommodity[c] = perm[colcommodity[c]];
3610 	            assert(colcommodity[c] < newncommodities);
3611 	            if( colcommodity[c] == -1 )
3612 	            {
3613 	               /* we are lazy and do not update plusflow and minusflow */
3614 	               colarcid[c] = -1;
3615 	            }
3616 	            else if( colarcid[c] >= 0 )
3617 	               arcisused[colarcid[c]] = TRUE;
3618 	         }
3619 	      }
3620 	      for( i = 0; i < nflowcands; i++ )
3621 	      {
3622 	         int r;
3623 	
3624 	         assert(flowcands != NULL);
3625 	         r = flowcands[i];
3626 	         assert(0 <= r && r < nrows);
3627 	         assert((rownodeid[r] >= 0) == (rowcommodity[r] >= 0));
3628 	         if( rowcommodity[r] >= 0 )
3629 	         {
3630 	            assert(0 <= rownodeid[r] && rownodeid[r] < nnodes);
3631 	            assert(rowcommodity[r] < mcfdata->ncommodities);
3632 	            rowcommodity[r] = perm[rowcommodity[r]];
3633 	            assert(rowcommodity[r] < newncommodities);
3634 	            if( rowcommodity[r] == -1 )
3635 	            {
3636 	               /* we are lazy and do not update flowrowsigns */
3637 	               rownodeid[r] = -1;
3638 	            }
3639 	            else
3640 	               nodeisused[rownodeid[r]] = TRUE;
3641 	         }
3642 	      }
3643 	
3644 	      mcfdata->ncommodities = newncommodities;
3645 	      ncommodities = newncommodities;
3646 	
3647 	      /* discard unused arcs */
3648 	      newnarcs = 0;
3649 	      for( a = 0; a < narcs; a++ )
3650 	      {
3651 	         int r;
3652 	
3653 	         assert(capacityrows != NULL);
3654 	
3655 	         if( arcisused[a] )
3656 	         {
3657 	            assert(newnarcs <= a);
3658 	            perm[a] = newnarcs;
3659 	            capacityrows[newnarcs] = capacityrows[a];
3660 	            newnarcs++;
3661 	         }
3662 	         else
3663 	         {
3664 	            /* we are lazy and do not update capacityrowsigns */
3665 	            perm[a] = -1;
3666 	         }
3667 	         r = SCIProwGetLPPos(capacityrows[a]);
3668 	         assert(0 <= r && r < nrows);
3669 	         assert(rowarcid[r] == a);
3670 	         rowarcid[r] = perm[a];
3671 	      }
3672 	
3673 	      /* update remaining data structures to new arc ids */
3674 	      if( newnarcs < narcs )
3675 	      {
3676 	         SCIPdebugMsg(scip, " -> discarding %d of %d arcs\n", narcs - newnarcs, narcs);
3677 	
3678 	         for( c = 0; c < ncols; c++ )
3679 	         {
3680 	            if( colarcid[c] >= 0 )
3681 	            {
3682 	               colarcid[c] = perm[colarcid[c]];
3683 	               assert(colarcid[c] >= 0); /* otherwise colarcid[c] was set to -1 in the colcommodity update */
3684 	            }
3685 	         }
3686 	         mcfdata->narcs = newnarcs;
3687 	         narcs = newnarcs;
3688 	      }
3689 	#ifndef NDEBUG
3690 	      for( a = 0; a < narcs; a++ )
3691 	      {
3692 	         int r;
3693 	         assert(capacityrows != NULL);
3694 	         r = SCIProwGetLPPos(capacityrows[a]);
3695 	         assert(0 <= r && r < nrows);
3696 	         assert(rowarcid[r] == a);
3697 	      }
3698 	#endif
3699 	
3700 	      /* discard unused nodes */
3701 	      newnnodes = 0;
3702 	      for( v = 0; v < nnodes; v++ )
3703 	      {
3704 	         if( nodeisused[v] )
3705 	         {
3706 	            assert(newnnodes <= v);
3707 	            perm[v] = newnnodes;
3708 	            newnnodes++;
3709 	         }
3710 	         else
3711 	            perm[v] = -1;
3712 	      }
3713 	
3714 	      /* update data structures to new node ids */
3715 	      if( newnnodes < nnodes )
3716 	      {
3717 	         SCIPdebugMsg(scip, " -> discarding %d of %d nodes\n", nnodes - newnnodes, nnodes);
3718 	
3719 	         for( i = 0; i < nflowcands; i++ )
3720 	         {
3721 	            int r;
3722 	
3723 	            assert(flowcands != NULL);
3724 	            r = flowcands[i];
3725 	            assert(0 <= r && r < nrows);
3726 	            assert((rownodeid[r] >= 0) == (rowcommodity[r] >= 0));
3727 	            if( rowcommodity[r] >= 0 )
3728 	            {
3729 	               assert(rowcommodity[r] < ncommodities);
3730 	               rownodeid[r] = perm[rownodeid[r]];
3731 	               assert(rownodeid[r] >= 0); /* otherwise we would have deleted the commodity in the rowcommodity update above */
3732 	            }
3733 	         }
3734 	         mcfdata->nnodes = newnnodes;
3735 	#ifdef MCF_DEBUG
3736 	         nnodes = newnnodes;
3737 	#endif
3738 	      }
3739 	
3740 	      /* free temporary memory */
3741 	      SCIPfreeBufferArray(scip, &nodeisused);
3742 	      SCIPfreeBufferArray(scip, &arcisused);
3743 	   }
3744 	
3745 	   /* empty commodities have been removed here */
3746 	   mcfdata->nemptycommodities = 0;
3747 	
3748 	   /* free temporary memory */
3749 	   SCIPfreeBufferArray(scip, &perm);
3750 	   SCIPfreeBufferArray(scip, &arcisincom);
3751 	   SCIPfreeBufferArray(scip, &narcspercom);
3752 	   SCIPfreeBufferArray(scip, &nnodespercom);
3753 	
3754 	   MCFdebugMessage("network after cleanup has %d nodes, %d arcs, and %d commodities\n", nnodes, narcs, ncommodities);
3755 	
3756 	   return SCIP_OKAY;
3757 	}
3758 	
3759 	/** for each arc identifies a source and target node */
3760 	static
3761 	SCIP_RETCODE identifySourcesTargets(
3762 	   SCIP*                 scip,               /**< SCIP data structure */
3763 	   MCFDATA*              mcfdata,            /**< internal MCF extraction data to pass to subroutines */
3764 	   SCIP_SEPADATA*        sepadata,           /**< separator data */
3765 	   MCFEFFORTLEVEL*       effortlevel         /**< pointer to store effort level of separation */
3766 	   )
3767 	{
3768 	   int*              colarcid                 = mcfdata->colarcid;
3769 	   int*              colcommodity             = mcfdata->colcommodity;
3770 	   int               narcs                    = mcfdata->narcs;
3771 	   int               nnodes                   = mcfdata->nnodes;
3772 	   int               ncommodities             = mcfdata->ncommodities;
3773 	   SCIP_ROW**        capacityrows             = mcfdata->capacityrows;
3774 	   SCIP_MCFMODELTYPE modeltype                = mcfdata->modeltype;
3775 	   SCIP_Real         maxinconsistencyratio    = sepadata->maxinconsistencyratio;
3776 	   SCIP_Real         maxarcinconsistencyratio = sepadata->maxarcinconsistencyratio;
3777 	   int*              arcsources;
3778 	   int*              arctargets;
3779 	   int*              colsources;
3780 	   int*              coltargets;
3781 	   int*              firstoutarcs;
3782 	   int*              firstinarcs;
3783 	   int*              nextoutarcs;
3784 	   int*              nextinarcs;
3785 	
3786 	   SCIP_Real *sourcenodecnt;
3787 	   SCIP_Real *targetnodecnt;
3788 	   int *flowvarspercom;
3789 	   int *comtouched;
3790 	   int *touchednodes;
3791 	   int ntouchednodes;
3792 	
3793 	   int ncols;
3794 	   SCIP_Real maxninconsistencies;
3795 	
3796 	   int c;
3797 	   int v;
3798 	   int a;
3799 	
3800 	   /* initialize effort level of separation */
3801 	   assert(effortlevel != NULL);
3802 	   *effortlevel = MCFEFFORTLEVEL_DEFAULT;
3803 	
3804 	   ncols = SCIPgetNLPCols(scip);
3805 	
3806 	   /* allocate memory in mcfdata */
3807 	   SCIP_CALL( SCIPallocMemoryArray(scip, &mcfdata->arcsources, narcs) );
3808 	   SCIP_CALL( SCIPallocMemoryArray(scip, &mcfdata->arctargets, narcs) );
3809 	   SCIP_CALL( SCIPallocMemoryArray(scip, &mcfdata->colsources, ncols) );
3810 	   SCIP_CALL( SCIPallocMemoryArray(scip, &mcfdata->coltargets, ncols) );
3811 	   SCIP_CALL( SCIPallocMemoryArray(scip, &mcfdata->firstoutarcs, nnodes) );
3812 	   SCIP_CALL( SCIPallocMemoryArray(scip, &mcfdata->firstinarcs, nnodes) );
3813 	   SCIP_CALL( SCIPallocMemoryArray(scip, &mcfdata->nextoutarcs, narcs) );
3814 	   SCIP_CALL( SCIPallocMemoryArray(scip, &mcfdata->nextinarcs, narcs) );
3815 	   arcsources   = mcfdata->arcsources;
3816 	   arctargets   = mcfdata->arctargets;
3817 	   colsources   = mcfdata->colsources;
3818 	   coltargets   = mcfdata->coltargets;
3819 	   firstoutarcs = mcfdata->firstoutarcs;
3820 	   firstinarcs  = mcfdata->firstinarcs;
3821 	   nextoutarcs  = mcfdata->nextoutarcs;
3822 	   nextinarcs   = mcfdata->nextinarcs;
3823 	
3824 	   mcfdata->arcarraysize = narcs;
3825 	
3826 	   /* initialize colsources and coltargets */
3827 	   for( c = 0; c < ncols; c++ )
3828 	   {
3829 	      colsources[c] = -2;
3830 	      coltargets[c] = -2;
3831 	   }
3832 	
3833 	   /* initialize adjacency lists */
3834 	   for( v = 0; v < nnodes; v++ )
3835 	   {
3836 	      firstoutarcs[v] = -1;
3837 	      firstinarcs[v] = -1;
3838 	   }
3839 	   for( a = 0; a < narcs; a++ )
3840 	   {
3841 	      nextoutarcs[a] = -1;
3842 	      nextinarcs[a] = -1;
3843 	   }
3844 	
3845 	   /* allocate temporary memory for source and target node identification */
3846 	   SCIP_CALL( SCIPallocBufferArray(scip, &sourcenodecnt, nnodes) );
3847 	   SCIP_CALL( SCIPallocBufferArray(scip, &targetnodecnt, nnodes) );
3848 	   SCIP_CALL( SCIPallocBufferArray(scip, &flowvarspercom, ncommodities) );
3849 	   SCIP_CALL( SCIPallocBufferArray(scip, &comtouched, ncommodities) );
3850 	   SCIP_CALL( SCIPallocBufferArray(scip, &touchednodes, nnodes) );
3851 	
3852 	   BMSclearMemoryArray(sourcenodecnt, nnodes);
3853 	   BMSclearMemoryArray(targetnodecnt, nnodes);
3854 	
3855 	   mcfdata->ninconsistencies = 0.0;
3856 	   maxninconsistencies = maxinconsistencyratio * (SCIP_Real)narcs;
3857 	
3858 	   /* search for source and target nodes */
3859 	   for( a = 0; a < narcs; a++ )
3860 	   {
3861 	      SCIP_COL** rowcols;
3862 	      int rowlen;
3863 	      int bestsourcev;
3864 	      int besttargetv;
3865 	      SCIP_Real bestsourcecnt;
3866 	      SCIP_Real besttargetcnt;
3867 	      SCIP_Real totalsourcecnt;
3868 	      SCIP_Real totaltargetcnt;
3869 	      SCIP_Real totalnodecnt;
3870 	      SCIP_Real nsourceinconsistencies;
3871 	      SCIP_Real ntargetinconsistencies;
3872 	      int ntouchedcoms;
3873 	      int i;
3874 	#ifndef NDEBUG
3875 	      int r;
3876 	
3877 	      r = SCIProwGetLPPos(capacityrows[a]);
3878 	#endif
3879 	      assert(0 <= r && r < SCIPgetNLPRows(scip));
3880 	      assert((mcfdata->capacityrowsigns[r] & (LHSASSIGNED | RHSASSIGNED)) != 0);
3881 	      assert(mcfdata->rowarcid[r] == a);
3882 	
3883 	#ifndef NDEBUG
3884 	      for( i = 0; i < nnodes; i++ )
3885 	      {
3886 	         assert(sourcenodecnt[i] == 0);
3887 	         assert(targetnodecnt[i] == 0);
3888 	      }
3889 	#endif
3890 	
3891 	      rowcols = SCIProwGetCols(capacityrows[a]);
3892 	      rowlen = SCIProwGetNLPNonz(capacityrows[a]);
3893 	
3894 	      /* count number of flow variables per commodity */
3895 	      BMSclearMemoryArray(flowvarspercom, ncommodities);
3896 	      BMSclearMemoryArray(comtouched, ncommodities);
3897 	      ntouchedcoms = 0;
3898 	      for( i = 0; i < rowlen; i++ )
3899 	      {
3900 	         c = SCIPcolGetLPPos(rowcols[i]);
3901 	         assert(0 <= c && c < SCIPgetNLPCols(scip));
3902 	         if( colarcid[c] >= 0 )
3903 	         {
3904 	            int k = colcommodity[c];
3905 	            assert (0 <= k && k < ncommodities);
3906 	            flowvarspercom[k]++;
3907 	            if( !comtouched[k] )
3908 	            {
3909 	               ntouchedcoms++;
3910 	               comtouched[k] = TRUE;
3911 	            }
3912 	         }
3913 	      }
3914 	
3915 	      /* if the row does not have any flow variable, it is not a capacity constraint */
3916 	      if( ntouchedcoms == 0 )
3917 	      {
3918 	         capacityrows[a] = NULL;
3919 	         arcsources[a] = -1;
3920 	         arctargets[a] = -1;
3921 	         continue;
3922 	      }
3923 	
3924 	      /* check the flow variables of the capacity row for flow conservation constraints */
3925 	      ntouchednodes = 0;
3926 	      totalsourcecnt = 0.0;
3927 	      totaltargetcnt = 0.0;
3928 	      totalnodecnt = 0.0;
3929 	      for( i = 0; i < rowlen; i++ )
3930 	      {
3931 	         c = SCIPcolGetLPPos(rowcols[i]);
3932 	         assert(0 <= c && c < SCIPgetNLPCols(scip));
3933 	         if( colarcid[c] >= 0 )
3934 	         {
3935 	            int k = colcommodity[c];
3936 	            int sourcev;
3937 	            int targetv;
3938 	            SCIP_Real weight;
3939 	
3940 	            assert (0 <= k && k < ncommodities);
3941 	            assert (comtouched[k]);
3942 	            assert (flowvarspercom[k] >= 1);
3943 	
3944 	            /* identify the (at most) two nodes which contain this flow variable */
3945 	            getIncidentNodes(scip, mcfdata, rowcols[i], &sourcev, &targetv);
3946 	
3947 	            /* count the nodes */
3948 	            weight = 1.0/flowvarspercom[k];
3949 	            if( sourcev >= 0 )
3950 	            {
3951 	               if( sourcenodecnt[sourcev] == 0.0 && targetnodecnt[sourcev] == 0.0 )
3952 	               {
3953 	                  touchednodes[ntouchednodes] = sourcev;
3954 	                  ntouchednodes++;
3955 	               }
3956 	               sourcenodecnt[sourcev] += weight;
3957 	               totalsourcecnt += weight;
3958 	            }
3959 	            if( targetv >= 0 )
3960 	            {
3961 	               if( sourcenodecnt[targetv] == 0.0 && targetnodecnt[targetv] == 0.0 )
3962 	               {
3963 	                  touchednodes[ntouchednodes] = targetv;
3964 	                  ntouchednodes++;
3965 	               }
3966 	               targetnodecnt[targetv] += weight;
3967 	               totaltargetcnt += weight;
3968 	            }
3969 	            if( sourcev >= 0 || targetv >= 0 )
3970 	               totalnodecnt += weight;
3971 	         }
3972 	      }
3973 	
3974 	      /* perform a majority vote on source and target node */
3975 	      bestsourcev = -1;
3976 	      besttargetv = -1;
3977 	      bestsourcecnt = 0.0;
3978 	      besttargetcnt = 0.0;
3979 	      for( i = 0; i < ntouchednodes; i++ )
3980 	      {
3981 	         v = touchednodes[i];
3982 	         assert(0 <= v && v < nnodes);
3983 	
3984 	         if( modeltype == SCIP_MCFMODELTYPE_DIRECTED )
3985 	         {
3986 	            /* in the directed model, we distinguish between source and target */
3987 	            if( sourcenodecnt[v] >= targetnodecnt[v] )
3988 	            {
3989 	               if( sourcenodecnt[v] > bestsourcecnt )
3990 	               {
3991 	                  bestsourcev = v;
3992 	                  bestsourcecnt = sourcenodecnt[v];
3993 	               }
3994 	            }
3995 	            else
3996 	            {
3997 	               if( targetnodecnt[v] > besttargetcnt )
3998 	               {
3999 	                  besttargetv = v;
4000 	                  besttargetcnt = targetnodecnt[v];
4001 	               }
4002 	            }
4003 	         }
4004 	         else
4005 	         {
4006 	            SCIP_Real nodecnt = sourcenodecnt[v] + targetnodecnt[v];
4007 	
4008 	            /* in the undirected model, we use source for the maximum and target for the second largest number of total hits */
4009 	            assert( modeltype == SCIP_MCFMODELTYPE_UNDIRECTED );
4010 	            if( nodecnt > bestsourcecnt )
4011 	            {
4012 	               besttargetv = bestsourcev;
4013 	               besttargetcnt = bestsourcecnt;
4014 	               bestsourcev = v;
4015 	               bestsourcecnt = nodecnt;
4016 	            }
4017 	            else if( nodecnt > besttargetcnt )
4018 	            {
4019 	               besttargetv = v;
4020 	               besttargetcnt = nodecnt;
4021 	            }
4022 	         }
4023 	
4024 	         /* clear the nodecnt arrays */
4025 	         sourcenodecnt[v] = 0;
4026 	         targetnodecnt[v] = 0;
4027 	      }
4028 	
4029 	      /* check inconsistency of arcs */
4030 	      if( modeltype == SCIP_MCFMODELTYPE_UNDIRECTED )
4031 	      {
4032 	         totalsourcecnt = totalnodecnt;
4033 	         totaltargetcnt = totalnodecnt;
4034 	      }
4035 	      assert(SCIPisGE(scip,totalsourcecnt,bestsourcecnt));
4036 	      assert(SCIPisGE(scip,totaltargetcnt,besttargetcnt));
4037 	      nsourceinconsistencies = (totalsourcecnt - bestsourcecnt)/ntouchedcoms;
4038 	      ntargetinconsistencies = (totaltargetcnt - besttargetcnt)/ntouchedcoms;
4039 	
4040 	      /* delete arcs that have to large inconsistency */
4041 	      if( nsourceinconsistencies > maxarcinconsistencyratio )
4042 	      {
4043 	         /* delete source assignment */
4044 	         bestsourcev = -1;
4045 	      }
4046 	
4047 	      if( ntargetinconsistencies > maxarcinconsistencyratio )
4048 	      {
4049 	         /* delete target assignment */
4050 	         besttargetv = -1;
4051 	      }
4052 	
4053 	      /* assign the incident nodes */
4054 	      assert(bestsourcev == -1 || bestsourcev != besttargetv);
4055 	      arcsources[a] = bestsourcev;
4056 	      arctargets[a] = besttargetv;
4057 	      SCIPdebugMsg(scip, "arc %d: %d -> %d (len=%d, sourcecnt=%g/%g, targetcnt=%g/%g, %g/%g inconsistencies)\n",
4058 	                       a, bestsourcev, besttargetv, rowlen,
4059 	                       bestsourcecnt, totalsourcecnt, besttargetcnt, totaltargetcnt,
4060 	                       nsourceinconsistencies, ntargetinconsistencies);
4061 	
4062 	      /* update adjacency lists */
4063 	      if( bestsourcev != -1 )
4064 	      {
4065 	         nextoutarcs[a] = firstoutarcs[bestsourcev];
4066 	         firstoutarcs[bestsourcev] = a;
4067 	      }
4068 	      if( besttargetv != -1 )
4069 	      {
4070 	         nextinarcs[a] = firstinarcs[besttargetv];
4071 	         firstinarcs[besttargetv] = a;
4072 	      }
4073 	
4074 	      /* update the number of inconsistencies */
4075 	      mcfdata->ninconsistencies += 0.5*(nsourceinconsistencies + ntargetinconsistencies);
4076 	
4077 	      if( mcfdata->ninconsistencies > maxninconsistencies )
4078 	      {
4079 	         MCFdebugMessage(" -> reached maximal number of inconsistencies: %g > %g\n",
4080 	                         mcfdata->ninconsistencies, maxninconsistencies);
4081 	         break;
4082 	      }
4083 	   }
4084 	
4085 	   /**@todo should we also use an aggressive parameter setting -- this should be done here */
4086 	   if( mcfdata->ninconsistencies <= maxninconsistencies && narcs > 0 && ncommodities > 0 )
4087 	      *effortlevel = MCFEFFORTLEVEL_DEFAULT;
4088 	   else
4089 	      *effortlevel = MCFEFFORTLEVEL_OFF;
4090 	
4091 	   MCFdebugMessage("extracted network has %g inconsistencies (ratio %g) -> separating with effort %d\n",
4092 	                   mcfdata->ninconsistencies, mcfdata->ninconsistencies/(SCIP_Real)narcs, *effortlevel);
4093 	
4094 	   /* free temporary memory */
4095 	   SCIPfreeBufferArray(scip, &touchednodes);
4096 	   SCIPfreeBufferArray(scip, &comtouched);
4097 	   SCIPfreeBufferArray(scip, &flowvarspercom);
4098 	   SCIPfreeBufferArray(scip, &targetnodecnt);
4099 	   SCIPfreeBufferArray(scip, &sourcenodecnt);
4100 	
4101 	   return SCIP_OKAY;
4102 	}
4103 	
4104 	#define UNKNOWN 0  /**< node has not yet been seen */
4105 	#define ONSTACK 1  /**< node is currently on the processing stack */
4106 	#define VISITED 2  /**< node has been visited and assigned to some component */
4107 	
4108 	/** returns lists of nodes and arcs in the connected component of the given startv */
4109 	static
4110 	SCIP_RETCODE identifyComponent(
4111 	   SCIP*                 scip,               /**< SCIP data structure */
4112 	   MCFDATA*              mcfdata,            /**< internal MCF extraction data to pass to subroutines */
4113 	   int*                  nodevisited,        /**< array to mark visited nodes */
4114 	   int                   startv,             /**< node for which the connected component should be generated */
4115 	   int*                  compnodes,          /**< array to store node ids of the component */
4116 	   int*                  ncompnodes,         /**< pointer to store the number of nodes in the component */
4117 	   int*                  comparcs,           /**< array to store arc ids of the component */
4118 	   int*                  ncomparcs           /**< pointer to store the number of arcs in the component */
4119 	   )
4120 	{
4121 	   int* arcsources   = mcfdata->arcsources;
4122 	   int* arctargets   = mcfdata->arctargets;
4123 	   int* firstoutarcs = mcfdata->firstoutarcs;
4124 	   int* firstinarcs  = mcfdata->firstinarcs;
4125 	   int* nextoutarcs  = mcfdata->nextoutarcs;
4126 	   int* nextinarcs   = mcfdata->nextinarcs;
4127 	   int  nnodes       = mcfdata->nnodes;
4128 	
4129 	   int* stacknodes;
4130 	   int nstacknodes;
4131 	
4132 	   assert(nodevisited != NULL);
4133 	   assert(0 <= startv && startv < nnodes);
4134 	   assert(nodevisited[startv] == UNKNOWN);
4135 	   assert(compnodes != NULL);
4136 	   assert(ncompnodes != NULL);
4137 	   assert(comparcs != NULL);
4138 	   assert(ncomparcs != NULL);
4139 	
4140 	   *ncompnodes = 0;
4141 	   *ncomparcs = 0;
4142 	
4143 	   /* allocate temporary memory for node stack */
4144 	   SCIP_CALL( SCIPallocBufferArray(scip, &stacknodes, nnodes) );
4145 	
4146 	   /* put startv on stack */
4147 	   stacknodes[0] = startv;
4148 	   nstacknodes = 1;
4149 	   nodevisited[startv] = ONSTACK;
4150 	
4151 	   /* perform depth-first search */
4152 	   while( nstacknodes > 0 )
4153 	   {
4154 	      int v;
4155 	      int a;
4156 	
4157 	      assert(firstoutarcs != NULL);
4158 	      assert(firstinarcs != NULL);
4159 	      assert(nextoutarcs != NULL);
4160 	      assert(nextinarcs != NULL);
4161 	
4162 	      /* pop first element from stack */
4163 	      v = stacknodes[nstacknodes-1];
4164 	      nstacknodes--;
4165 	      assert(0 <= v && v < nnodes);
4166 	      assert(nodevisited[v] == ONSTACK);
4167 	      nodevisited[v] = VISITED;
4168 	
4169 	      /* put node into component */
4170 	      assert(*ncompnodes < nnodes);
4171 	      compnodes[*ncompnodes] = v;
4172 	      (*ncompnodes)++;
4173 	
4174 	      /* go through the list of outgoing arcs */
4175 	      for( a = firstoutarcs[v]; a != -1; a = nextoutarcs[a] )
4176 	      {
4177 	         int targetv;
4178 	
4179 	         assert(0 <= a && a < mcfdata->narcs);
4180 	         assert(arctargets != NULL);
4181 	
4182 	         targetv = arctargets[a];
4183 	
4184 	         /* check if we have already visited the target node */
4185 	         if( targetv != -1 && nodevisited[targetv] == VISITED )
4186 	            continue;
4187 	
4188 	         /* put arc to component */
4189 	         assert(*ncomparcs < mcfdata->narcs);
4190 	         comparcs[*ncomparcs] = a;
4191 	         (*ncomparcs)++;
4192 	
4193 	         /* push target node to stack */
4194 	         if( targetv != -1 && nodevisited[targetv] == UNKNOWN )
4195 	         {
4196 	            assert(nstacknodes < nnodes);
4197 	            stacknodes[nstacknodes] = targetv;
4198 	            nstacknodes++;
4199 	            nodevisited[targetv] = ONSTACK;
4200 	         }
4201 	      }
4202 	
4203 	      /* go through the list of ingoing arcs */
4204 	      for( a = firstinarcs[v]; a != -1; a = nextinarcs[a] )
4205 	      {
4206 	         int sourcev;
4207 	
4208 	         assert(0 <= a && a < mcfdata->narcs);
4209 	         assert(arcsources != NULL);
4210 	
4211 	         sourcev = arcsources[a];
4212 	
4213 	         /* check if we have already seen the source node */
4214 	         if( sourcev != -1 && nodevisited[sourcev] == VISITED )
4215 	            continue;
4216 	
4217 	         /* put arc to component */
4218 	         assert(*ncomparcs < mcfdata->narcs);
4219 	         comparcs[*ncomparcs] = a;
4220 	         (*ncomparcs)++;
4221 	
4222 	         /* push source node to stack */
4223 	         if( sourcev != -1 && nodevisited[sourcev] == UNKNOWN )
4224 	         {
4225 	            assert(nstacknodes < nnodes);
4226 	            stacknodes[nstacknodes] = sourcev;
4227 	            nstacknodes++;
4228 	            nodevisited[sourcev] = ONSTACK;
4229 	         }
4230 	      }
4231 	   }
4232 	
4233 	   /* free temporary memory */
4234 	   SCIPfreeBufferArray(scip, &stacknodes);
4235 	
4236 	   return SCIP_OKAY;
4237 	}
4238 	
4239 	/** extracts MCF network structures from the current LP */
4240 	static
4241 	SCIP_RETCODE mcfnetworkExtract(
4242 	   SCIP*                 scip,               /**< SCIP data structure */
4243 	   SCIP_SEPADATA*        sepadata,           /**< separator data */
4244 	   SCIP_MCFNETWORK***    mcfnetworks,        /**< pointer to store array of MCF network structures */
4245 	   int*                  nmcfnetworks,       /**< pointer to store number of MCF networks */
4246 	   MCFEFFORTLEVEL*       effortlevel         /**< effort level of separation */
4247 	   )
4248 	{
4249 	   MCFDATA mcfdata;
4250 	
4251 	   SCIP_MCFMODELTYPE modeltype = (SCIP_MCFMODELTYPE) sepadata->modeltype;
4252 	
4253 	   SCIP_Bool      failed;
4254 	
4255 	   SCIP_ROW** rows;
4256 	   SCIP_COL** cols;
4257 	   int nrows;
4258 	   int ncols;
4259 	   int mcfnetworkssize;
4260 	
4261 	   assert(mcfnetworks != NULL);
4262 	   assert(nmcfnetworks != NULL);
4263 	   assert(effortlevel != NULL);
4264 	
4265 	   failed = FALSE;
4266 	   *effortlevel = MCFEFFORTLEVEL_OFF;
4267 	   *mcfnetworks = NULL;
4268 	   *nmcfnetworks = 0;
4269 	   mcfnetworkssize = 0;
4270 	
4271 	   /* Algorithm to identify multi-commodity-flow network with capacity constraints
4272 	    *
4273 	    * 1. Identify candidate rows for flow conservation constraints in the LP.
4274 	    * 2. Sort flow conservation candidates by a ranking on how sure we are that it is indeed a constraint of the desired type.
4275 	    * 3. Extract network structure of flow conservation constraints:
4276 	    *    (a) Initialize plusflow[c] = minusflow[c] = FALSE for all columns c and other local data.
4277 	    *    (b) As long as there are flow conservation candidates left:
4278 	    *        (i) Create new commodity and use first flow conservation constraint as new row.
4279 	    *       (ii) Add new row to commodity, update pluscom/minuscom accordingly.
4280 	    *      (iii) For the newly added columns search for an incident flow conservation constraint. Pick the one of highest ranking.
4281 	    *            Reflect row or commodity if necessary (multiply with -1)
4282 	    *       (iv) If found, set new row to this row and goto (ii).
4283 	    *        (v) If only very few flow rows have been used, discard the commodity immediately.
4284 	    * 4. Identify candidate rows for capacity constraints in the LP.
4285 	    * 5. Sort capacity constraint candidates by a ranking on how sure we are that it is indeed a constraint of the desired type.
4286 	    * 6. Identify capacity constraints for the arcs and assign arc ids to columns and capacity constraints.
4287 	    * 7. Assign node ids to flow conservation constraints.
4288 	    * 8. PostProcessing
4289 	    *    a  if there are still undecided commodity signs, fix them to +1
4290 	    *    b  clean up the network: get rid of commodities without arcs or with at most one node
4291 	    *    c  assign source and target nodes to capacitated arc
4292 	    *    d  find uncapacitated arcs
4293 	    */
4294 	
4295 	   /* get LP data */
4296 	   SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
4297 	   SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
4298 	
4299 	   /* initialize local extraction data */
4300 	   mcfdata.flowrowsigns = NULL;
4301 	   mcfdata.flowrowscalars = NULL;
4302 	   mcfdata.flowrowscores = NULL;
4303 	   mcfdata.capacityrowsigns = NULL;
4304 	   mcfdata.capacityrowscores = NULL;
4305 	   mcfdata.flowcands = NULL;
4306 	   mcfdata.nflowcands = 0;
4307 	   mcfdata.capacitycands = NULL;
4308 	   mcfdata.ncapacitycands = 0;
4309 	   mcfdata.plusflow = NULL;
4310 	   mcfdata.minusflow = NULL;
4311 	   mcfdata.ncommodities = 0;
4312 	   mcfdata.nemptycommodities = 0;
4313 	   mcfdata.commoditysigns = NULL;
4314 	   mcfdata.commoditysignssize = 0;
4315 	   mcfdata.colcommodity = NULL;
4316 	   mcfdata.rowcommodity = NULL;
4317 	   mcfdata.colarcid = NULL;
4318 	   mcfdata.rowarcid = NULL;
4319 	   mcfdata.rownodeid = NULL;
4320 	   mcfdata.arcarraysize = 0;
4321 	   mcfdata.arcsources = NULL;
4322 	   mcfdata.arctargets = NULL;
4323 	   mcfdata.colsources = NULL;
4324 	   mcfdata.coltargets = NULL;
4325 	   mcfdata.firstoutarcs = NULL;
4326 	   mcfdata.firstinarcs = NULL;
4327 	   mcfdata.nextoutarcs = NULL;
4328 	   mcfdata.nextinarcs = NULL;
4329 	   mcfdata.newcols = NULL;
4330 	   mcfdata.nnewcols = 0;
4331 	   mcfdata.narcs = 0;
4332 	   mcfdata.nnodes = 0;
4333 	   mcfdata.ninconsistencies = 0.0;
4334 	   mcfdata.capacityrows = NULL;
4335 	   mcfdata.capacityrowssize = 0;
4336 	   mcfdata.colisincident = NULL;
4337 	   mcfdata.zeroarcarray = NULL;
4338 	   mcfdata.modeltype = modeltype;
4339 	
4340 	   /* 1. identify candidate rows for flow conservation constraints in the LP
4341 	    * 2. Sort flow conservation candidates by a ranking on how sure we are that it is indeed a constraint of the desired type
4342 	    */
4343 	   SCIP_CALL( extractFlowRows(scip, &mcfdata) );
4344 	   assert(mcfdata.flowrowsigns != NULL);
4345 	   assert(mcfdata.flowrowscalars != NULL);
4346 	   assert(mcfdata.flowrowscores != NULL);
4347 	   assert(mcfdata.flowcands != NULL);
4348 	
4349 	   if( mcfdata.nflowcands == 0 )
4350 	      failed = TRUE;
4351 	
4352 	   if( !failed )
4353 	   {
4354 	      /* 3. extract network structure of flow conservation constraints. */
4355 	      /* coverity[var_deref_model] */
4356 	      SCIP_CALL( extractFlow(scip, &mcfdata, MAXFLOWVARFLOWROWRATIO, &failed) );
4357 	      assert(mcfdata.plusflow != NULL);
4358 	      assert(mcfdata.minusflow != NULL);
4359 	      assert(mcfdata.colcommodity != NULL);
4360 	      assert(mcfdata.rowcommodity != NULL);
4361 	      assert(mcfdata.newcols != NULL);
4362 	   }
4363 	
4364 	   if( !failed )
4365 	   {
4366 	#ifdef SCIP_DEBUG
4367 	      printCommodities(scip, &mcfdata);
4368 	#endif
4369 	
4370 	      /* 4. identify candidate rows for capacity constraints in the LP
4371 	       * 5. sort capacity constraint candidates by a ranking on how sure we are that it is indeed a constraint of the desired type
4372 	       */
4373 	      SCIP_CALL( extractCapacityRows(scip, &mcfdata) );
4374 	      assert(mcfdata.capacityrowsigns != NULL);
4375 	      assert(mcfdata.capacityrowscores != NULL);
4376 	      assert(mcfdata.capacitycands != NULL);
4377 	
4378 	      if( mcfdata.ncapacitycands == 0 )
4379 	         failed = TRUE;
4380 	   }
4381 	
4382 	   if( !failed )
4383 	   {
4384 	      /* 6. arc-detection -- identify capacity constraints for the arcs and assign arc ids to columns and capacity constraints */
4385 	      SCIP_CALL( extractCapacities(scip, &mcfdata) );
4386 	      assert(mcfdata.colarcid != NULL);
4387 	      assert(mcfdata.rowarcid != NULL);
4388 	
4389 	      /* 7. node-detection -- assign node ids to flow conservation constraints */
4390 	      SCIP_CALL( extractNodes(scip, &mcfdata) );
4391 	      assert(mcfdata.rownodeid != NULL);
4392 	      assert(mcfdata.colisincident != NULL);
4393 	      assert(mcfdata.zeroarcarray != NULL);
4394 	
4395 	      /* 8. postprocessing */
4396 	      /* 8.a if there are still undecided commodity signs, fix them to +1 */
4397 	      fixCommoditySigns(&mcfdata);
4398 	
4399 	      /* 8.b clean up the network: get rid of commodities without arcs or with at most one node */
4400 	      SCIP_CALL( cleanupNetwork(scip, &mcfdata) );
4401 	
4402 	      /* 8.c construct incidence function -- assign source and target nodes to capacitated arcs */
4403 	      SCIP_CALL( identifySourcesTargets(scip, &mcfdata, sepadata, effortlevel) );
4404 	      assert(mcfdata.arcsources != NULL);
4405 	      assert(mcfdata.arctargets != NULL);
4406 	      assert(mcfdata.colsources != NULL);
4407 	      assert(mcfdata.coltargets != NULL);
4408 	      assert(mcfdata.firstoutarcs != NULL);
4409 	      assert(mcfdata.firstinarcs != NULL);
4410 	      assert(mcfdata.nextoutarcs != NULL);
4411 	      assert(mcfdata.nextinarcs != NULL);
4412 	   }
4413 	
4414 	   if( !failed && *effortlevel != MCFEFFORTLEVEL_OFF)
4415 	   {
4416 	      int* nodevisited;
4417 	      int* compnodeid;
4418 	      int* compnodes;
4419 	      int* comparcs;
4420 	      int minnodes;
4421 	      int v;
4422 	
4423 	      /* 8.d find uncapacitated arcs */
4424 	      SCIP_CALL( findUncapacitatedArcs(scip, &mcfdata) );
4425 	
4426 	#ifdef SCIP_DEBUG
4427 	      printCommodities(scip, &mcfdata);
4428 	#endif
4429 	
4430 	      minnodes = MINNODES;
4431 	
4432 	      /* allocate temporary memory for component finding */
4433 	      SCIP_CALL( SCIPallocBufferArray(scip, &nodevisited, mcfdata.nnodes) );
4434 	      SCIP_CALL( SCIPallocBufferArray(scip, &compnodes, mcfdata.nnodes) );
4435 	      SCIP_CALL( SCIPallocBufferArray(scip, &comparcs, mcfdata.narcs) );
4436 	      BMSclearMemoryArray(nodevisited, mcfdata.nnodes);
4437 	
4438 	      /* allocate temporary memory for v -> compv mapping */
4439 	      SCIP_CALL( SCIPallocBufferArray(scip, &compnodeid, mcfdata.nnodes) );
4440 	      for( v = 0; v < mcfdata.nnodes; v++ )
4441 	         compnodeid[v] = -1;
4442 	
4443 	      /* search components and create a network structure for each of them */
4444 	      for( v = 0; v < mcfdata.nnodes; v++ )
4445 	      {
4446 	         int ncompnodes;
4447 	         int ncomparcs;
4448 	
4449 	         /* ignore nodes that have been already assigned to a component */
4450 	         assert(nodevisited[v] == UNKNOWN || nodevisited[v] == VISITED);
4451 	         if( nodevisited[v] == VISITED )
4452 	            continue;
4453 	
4454 	         /* identify nodes and arcs of this component */
4455 	         SCIP_CALL( identifyComponent(scip, &mcfdata, nodevisited, v, compnodes, &ncompnodes, comparcs, &ncomparcs) );
4456 	         assert(ncompnodes >= 1);
4457 	         assert(compnodes[0] == v);
4458 	         assert(nodevisited[v] == VISITED);
4459 	
4460 	         /* ignore network component if it is trivial */
4461 	         if( ncompnodes >= minnodes && ncomparcs >= MINARCS )
4462 	         {
4463 	            SCIP_MCFNETWORK* mcfnetwork;
4464 	            int i;
4465 	
4466 	            /* make sure that we have enough memory for the new network pointer */
4467 	            assert(*nmcfnetworks <= MAXNETWORKS);
4468 	            assert(*nmcfnetworks <= mcfnetworkssize);
4469 	            if( *nmcfnetworks == mcfnetworkssize )
4470 	            {
4471 	               mcfnetworkssize = MAX(2*mcfnetworkssize, *nmcfnetworks+1);
4472 	               SCIP_CALL( SCIPreallocMemoryArray(scip, mcfnetworks, mcfnetworkssize) );
4473 	            }
4474 	            assert(*nmcfnetworks < mcfnetworkssize);
4475 	
4476 	            /* create network data structure */
4477 	            SCIP_CALL( mcfnetworkCreate(scip, &mcfnetwork) );
4478 	
4479 	            /* fill sparse network structure */
4480 	            SCIP_CALL( mcfnetworkFill(scip, mcfnetwork, &mcfdata, compnodeid, compnodes, ncompnodes, comparcs, ncomparcs) );
4481 	
4482 	            /* insert in sorted network list */
4483 	            assert(*mcfnetworks != NULL);
4484 	            for( i = *nmcfnetworks; i > 0 && mcfnetwork->nnodes > (*mcfnetworks)[i-1]->nnodes; i-- )
4485 	               (*mcfnetworks)[i] = (*mcfnetworks)[i-1];
4486 	            (*mcfnetworks)[i] = mcfnetwork;
4487 	            (*nmcfnetworks)++;
4488 	
4489 	            /* if we reached the maximal number of networks, update minnodes */
4490 	            if( *nmcfnetworks >= MAXNETWORKS )
4491 	               minnodes = MAX(minnodes, (*mcfnetworks)[*nmcfnetworks-1]->nnodes);
4492 	
4493 	            /* if we exceeded the maximal number of networks, delete the last one */
4494 	            if( *nmcfnetworks > MAXNETWORKS )
4495 	            {
4496 	               SCIPdebugMsg(scip, " -> discarded network with %d nodes and %d arcs due to maxnetworks (minnodes=%d)\n",
4497 	                                (*mcfnetworks)[*nmcfnetworks-1]->nnodes, (*mcfnetworks)[*nmcfnetworks-1]->narcs, minnodes);
4498 	               SCIP_CALL( mcfnetworkFree(scip, &(*mcfnetworks)[*nmcfnetworks-1]) );
4499 	               (*nmcfnetworks)--;
4500 	            }
4501 	            assert(*nmcfnetworks <= MAXNETWORKS);
4502 	         }
4503 	         else
4504 	         {
4505 	            SCIPdebugMsg(scip, " -> discarded component with %d nodes and %d arcs\n", ncompnodes, ncomparcs);
4506 	         }
4507 	      }
4508 	
4509 	      /* free temporary memory */
4510 	      SCIPfreeBufferArray(scip, &compnodeid);
4511 	      SCIPfreeBufferArray(scip, &comparcs);
4512 	      SCIPfreeBufferArray(scip, &compnodes);
4513 	      SCIPfreeBufferArray(scip, &nodevisited);
4514 	   }
4515 	
4516 	   /* free memory */
4517 	   SCIPfreeMemoryArrayNull(scip, &mcfdata.arcsources);
4518 	   SCIPfreeMemoryArrayNull(scip, &mcfdata.arctargets);
4519 	   SCIPfreeMemoryArrayNull(scip, &mcfdata.colsources);
4520 	   SCIPfreeMemoryArrayNull(scip, &mcfdata.coltargets);
4521 	   SCIPfreeMemoryArrayNull(scip, &mcfdata.firstoutarcs);
4522 	   SCIPfreeMemoryArrayNull(scip, &mcfdata.firstinarcs);
4523 	   SCIPfreeMemoryArrayNull(scip, &mcfdata.nextoutarcs);
4524 	   SCIPfreeMemoryArrayNull(scip, &mcfdata.nextinarcs);
4525 	   SCIPfreeMemoryArrayNull(scip, &mcfdata.zeroarcarray);
4526 	   SCIPfreeMemoryArrayNull(scip, &mcfdata.colisincident);
4527 	   SCIPfreeMemoryArrayNull(scip, &mcfdata.capacityrows);
4528 	   SCIPfreeMemoryArrayNull(scip, &mcfdata.rownodeid);
4529 	   SCIPfreeMemoryArrayNull(scip, &mcfdata.rowarcid);
4530 	   SCIPfreeMemoryArrayNull(scip, &mcfdata.colarcid);
4531 	   SCIPfreeMemoryArrayNull(scip, &mcfdata.newcols);
4532 	   SCIPfreeMemoryArrayNull(scip, &mcfdata.rowcommodity);
4533 	   SCIPfreeMemoryArrayNull(scip, &mcfdata.colcommodity);
4534 	   SCIPfreeMemoryArrayNull(scip, &mcfdata.commoditysigns);
4535 	   SCIPfreeMemoryArrayNull(scip, &mcfdata.minusflow);
4536 	   SCIPfreeMemoryArrayNull(scip, &mcfdata.plusflow);
4537 	   SCIPfreeMemoryArrayNull(scip, &mcfdata.capacitycands);
4538 	   SCIPfreeMemoryArrayNull(scip, &mcfdata.flowcands);
4539 	   SCIPfreeMemoryArrayNull(scip, &mcfdata.capacityrowscores);
4540 	   SCIPfreeMemoryArrayNull(scip, &mcfdata.capacityrowsigns);
4541 	   SCIPfreeMemoryArrayNull(scip, &mcfdata.flowrowscores);
4542 	   SCIPfreeMemoryArrayNull(scip, &mcfdata.flowrowscalars);
4543 	   SCIPfreeMemoryArrayNull(scip, &mcfdata.flowrowsigns);
4544 	
4545 	   return SCIP_OKAY;
4546 	}
4547 	#ifdef COUNTNETWORKVARIABLETYPES
4548 	/** extracts MCF network structures from the current LP */
4549 	static
4550 	SCIP_RETCODE printFlowSystemInfo(
4551 	   SCIP*                 scip,               /**< SCIP data structure */
4552 	   SCIP_MCFNETWORK**     mcfnetworks,        /**< array of MCF network structures */
4553 	   int                   nmcfnetworks        /**< number of MCF networks */
4554 	   )
4555 	{
4556 	   SCIP_ROW** rows;
4557 	   SCIP_COL** cols;
4558 	   SCIP_Bool* colvisited;
4559 	   int nrows;
4560 	   int ncols;
4561 	   int m;
4562 	   int c;
4563 	   int a;
4564 	   int k;
4565 	   int v;
4566 	   int nflowrows = 0;
4567 	   int ncaprows = 0;
4568 	   int nflowvars = 0;
4569 	   int nintflowvars = 0;
4570 	   int nbinflowvars = 0;
4571 	   int ncontflowvars = 0;
4572 	   int ncapvars = 0;
4573 	   int nintcapvars = 0;
4574 	   int nbincapvars = 0;
4575 	   int ncontcapvars = 0;
4576 	
4577 	   /* get LP data */
4578 	   SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
4579 	   SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
4580 	   SCIP_CALL( SCIPallocBufferArray(scip, &colvisited, ncols) );
4581 	
4582 	   /* get flow variable types */
4583 	   for(c=0; c < ncols; c++)
4584 	      colvisited[c]=FALSE;
4585 	
4586 	   MCFdebugMessage("\n\n****** VAR COUNTING ********* \n");
4587 	
4588 	   for(m=0; m < nmcfnetworks; m++)
4589 	   {
4590 	      SCIP_MCFNETWORK* mcfnetwork = mcfnetworks[m];
4591 	
4592 	      int narcs                           = mcfnetwork->narcs;
4593 	      int nnodes                          = mcfnetwork->nnodes;
4594 	      int ncommodities                    = mcfnetwork->ncommodities;
4595 	      SCIP_ROW**        arccapacityrows   = mcfnetwork->arccapacityrows;
4596 	      SCIP_ROW***       nodeflowrows      = mcfnetwork->nodeflowrows;
4597 	      int*              colcommodity      = mcfnetwork->colcommodity;
4598 	
4599 	      /* get flow variable types */
4600 	      for(c=0; c < ncols; c++)
4601 	      {
4602 	         SCIP_COL*         col;
4603 	
4604 	         if(colcommodity[c] >= 0 && ! colvisited[c])
4605 	         {
4606 	            /* this is a flow variable */
4607 	            nflowvars++;
4608 	            col = cols[c];
4609 	            colvisited[c] = TRUE;
4610 	            switch( SCIPvarGetType(SCIPcolGetVar(col)) )
4611 	            {
4612 	            case SCIP_VARTYPE_BINARY:
4613 	               nbinflowvars++;
4614 	               break;
4615 	            case SCIP_VARTYPE_INTEGER:
4616 	               nintflowvars++;
4617 	               break;
4618 	            case SCIP_VARTYPE_IMPLINT:
4619 	               nintflowvars++;
4620 	               break;
4621 	               case SCIP_VARTYPE_CONTINUOUS:
4622 	                  ncontflowvars++;
4623 	                  break;
4624 	            default:
4625 	               SCIPerrorMessage("unknown variable type\n");
4626 	               SCIPABORT();
4627 	               return SCIP_INVALIDDATA;  /*lint !e527*/
4628 	            }
4629 	         }
4630 	      }
4631 	      /* get capacity variable types and number of capacity rows*/
4632 	      for( a = 0; a < narcs; a++ )
4633 	      {
4634 	         SCIP_ROW* row;
4635 	         row = arccapacityrows[a];
4636 	
4637 	         if( row != NULL )
4638 	         {
4639 	            SCIP_COL** rowcols;
4640 	            int rowlen;
4641 	            int i;
4642 	
4643 	            ncaprows++;
4644 	            rowcols = SCIProwGetCols(row);
4645 	            rowlen = SCIProwGetNLPNonz(row);
4646 	
4647 	            for( i = 0; i < rowlen; i++ )
4648 	            {
4649 	               c = SCIPcolGetLPPos(rowcols[i]);
4650 	               assert(0 <= c && c < SCIPgetNLPCols(scip));
4651 	
4652 	               if(colcommodity[c] == -1 && ! colvisited[c] )
4653 	               {
4654 	                  ncapvars++;
4655 	                  colvisited[c] = TRUE;
4656 	                  switch( SCIPvarGetType(SCIPcolGetVar(rowcols[i]) ) )
4657 	                  {
4658 	                  case SCIP_VARTYPE_BINARY:
4659 	                     nbincapvars++;
4660 	                     break;
4661 	                  case SCIP_VARTYPE_INTEGER:
4662 	                     nintcapvars++;
4663 	                     break;
4664 	                  case SCIP_VARTYPE_IMPLINT:
4665 	                     nintcapvars++;
4666 	                     break;
4667 	                  case SCIP_VARTYPE_CONTINUOUS:
4668 	                     ncontcapvars++;
4669 	                     break;
4670 	                  default:
4671 	                     SCIPerrorMessage("unknown variable type\n");
4672 	                     SCIPABORT();
4673 	                     return SCIP_INVALIDDATA;  /*lint !e527*/
4674 	                  }
4675 	               }
4676 	            }
4677 	         }
4678 	      }
4679 	      /* get number of flow rows */
4680 	      for( k = 0; k < ncommodities; k++ )
4681 	      {
4682 	         for( v = 0; v < nnodes; v++ )
4683 	         {
4684 	            SCIP_ROW*         row;
4685 	            row = nodeflowrows[v][k];
4686 	
4687 	            if( row != NULL )
4688 	               nflowrows++;
4689 	         }
4690 	      }
4691 	
4692 	      MCFdebugMessage("----- network %i -----\n",m);
4693 	      MCFdebugMessage("   nof flowrows: %5d\n", nflowrows);
4694 	      MCFdebugMessage("   nof caprows:  %5d\n", ncaprows);
4695 	      MCFdebugMessage("   nof flowvars: %5d of which [ %d , %d , %d ] are continuous, integer, binary\n",
4696 	         nflowvars, ncontflowvars, nintflowvars, nbinflowvars);
4697 	      MCFdebugMessage("   nof capvars:  %5d of which [ %d , %d , %d ] are continuous, integer, binary\n",
4698 	         ncapvars, ncontcapvars, nintcapvars, nbincapvars);
4699 	   }
4700 	
4701 	   MCFdebugMessage("****** END VAR COUNTING ********* \n\n");
4702 	
4703 	   SCIPfreeBufferArray(scip, &colvisited);
4704 	
4705 	   return SCIP_OKAY;
4706 	}
4707 	#endif
4708 	/*
4709 	 * Union find methods
4710 	 * used for generating partitions of node sets and
4711 	 *      for checking connectivity of cut shores
4712 	 */
4713 	
4714 	/** initializes a union find data structure by putting each element into its own set */
4715 	static
4716 	void unionfindInitSets(
4717 	   int*                  representatives,    /**< mapping an element v to its representative */
4718 	   int                   nelems              /**< number of elements in the ground set */
4719 	   )
4720 	{
4721 	   int v;
4722 	
4723 	   /* we start with each element being in its own set */
4724 	   for( v = 0; v < nelems; v++ )
4725 	      representatives[v] = v;
4726 	}
4727 	
4728 	/** applies a union find algorithm to get the representative of v */
4729 	static
4730 	int unionfindGetRepresentative(
4731 	   int*                  representatives,    /**< mapping an element v to its representative */
4732 	   int                   v                   /**< element v to get a representative for */
4733 	   )
4734 	{
4735 	   assert(representatives != NULL);
4736 	
4737 	   while( v != representatives[v] )
4738 	   {
4739 	      representatives[v] = representatives[representatives[v]];
4740 	      v = representatives[v];
4741 	   }
4742 	
4743 	   return v;
4744 	}
4745 	
4746 	/** joins two sets in the union find framework */
4747 	static
4748 	void unionfindJoinSets(
4749 	   int*                  representatives,    /**< mapping an element v to its representative */
4750 	   int                   rep1,               /**< representative of first set */
4751 	   int                   rep2                /**< representative of second set */
4752 	   )
4753 	{
4754 	   assert(rep1 != rep2);
4755 	   assert(representatives[rep1] == rep1);
4756 	   assert(representatives[rep2] == rep2);
4757 	
4758 	   /* make sure that the smaller representative survives
4759 	    *  -> element 0 is always a representative
4760 	    */
4761 	   if( rep1 < rep2 )
4762 	      representatives[rep2] = rep1;
4763 	   else
4764 	      representatives[rep1] = rep2;
4765 	}
4766 	
4767 	/*
4768 	 * Node pair methods
4769 	 * used for shrinking the network based on nodepair-weights
4770 	 * -> creating partition
4771 	*/
4772 	
4773 	/** comparison method for weighted nodepairs */
4774 	static
4775 	SCIP_DECL_SORTPTRCOMP(compNodepairs)
4776 	{
4777 	   NODEPAIRENTRY* nodepair1 = (NODEPAIRENTRY*)elem1;
4778 	   NODEPAIRENTRY* nodepair2 = (NODEPAIRENTRY*)elem2;
4779 	
4780 	   if( nodepair1->weight > nodepair2->weight )
4781 	      return -1;
4782 	   else if( nodepair1->weight < nodepair2->weight )
4783 	      return +1;
4784 	   else
4785 	      return 0;
4786 	}
4787 	
4788 	/** NodePair HashTable
4789 	 * gets the key of the given element */
4790 	static
4791 	SCIP_DECL_HASHGETKEY(hashGetKeyNodepairs)
4792 	{
4793 	   /*lint --e{715}*/
4794 	   /* the key is the element itself */
4795 	   return elem;
4796 	}
4797 	
4798 	/** NodePair HashTable
4799 	 * returns TRUE iff both keys are equal;
4800 	 * two nodepairs are equal if both nodes equal
4801 	 */
4802 	static
4803 	SCIP_DECL_HASHKEYEQ(hashKeyEqNodepairs)
4804 	{
4805 	#ifndef NDEBUG
4806 	   SCIP_MCFNETWORK*  mcfnetwork;
4807 	#endif
4808 	   NODEPAIRENTRY*    nodepair1;
4809 	   NODEPAIRENTRY*    nodepair2;
4810 	   int source1;
4811 	   int source2;
4812 	   int target1;
4813 	   int target2;
4814 	
4815 	#ifndef NDEBUG
4816 	   mcfnetwork = (SCIP_MCFNETWORK*)userptr;
4817 	   assert(mcfnetwork != NULL);
4818 	#endif
4819 	
4820 	   nodepair1 = (NODEPAIRENTRY*)key1;
4821 	   nodepair2 = (NODEPAIRENTRY*)key2;
4822 	
4823 	   assert(nodepair1 != NULL);
4824 	   assert(nodepair2 != NULL);
4825 	
4826 	   source1 = nodepair1->node1;
4827 	   source2 = nodepair2->node1;
4828 	   target1 = nodepair1->node2;
4829 	   target2 = nodepair2->node2;
4830 	
4831 	   assert(source1 >=0 && source1 < mcfnetwork->nnodes);
4832 	   assert(source2 >=0 && source2 < mcfnetwork->nnodes);
4833 	   assert(target1 >=0 && target1 < mcfnetwork->nnodes);
4834 	   assert(target2 >=0 && target2 < mcfnetwork->nnodes);
4835 	   assert(source1 <= target1);
4836 	   assert(source2 <= target2);
4837 	
4838 	   return (source1 == source2 && target1 == target2);
4839 	}
4840 	
4841 	/** NodePair HashTable
4842 	 * returns the hash value of the key */
4843 	static
4844 	SCIP_DECL_HASHKEYVAL(hashKeyValNodepairs)
4845 	{
4846 	#ifndef NDEBUG
4847 	   SCIP_MCFNETWORK*  mcfnetwork;
4848 	#endif
4849 	   NODEPAIRENTRY*    nodepair;
4850 	   int source;
4851 	   int target;
4852 	   unsigned int hashval;
4853 	
4854 	#ifndef NDEBUG
4855 	   mcfnetwork = (SCIP_MCFNETWORK*)userptr;
4856 	   assert(mcfnetwork != NULL);
4857 	#endif
4858 	
4859 	   nodepair = (NODEPAIRENTRY*)key;
4860 	   assert( nodepair != NULL);
4861 	
4862 	   source = nodepair->node1;
4863 	   target = nodepair->node2;
4864 	
4865 	   assert(source >=0 && source < mcfnetwork->nnodes);
4866 	   assert(target >=0 && target < mcfnetwork->nnodes);
4867 	   assert(source <= target);
4868 	
4869 	   hashval = (unsigned)((source << 16) + target); /*lint !e701*/
4870 	
4871 	   return hashval;
4872 	}
4873 	
4874 	/** creates a priority queue and fills it with the given nodepair entries
4875 	 *
4876 	 */
4877 	static
4878 	SCIP_RETCODE nodepairqueueCreate(
4879 	   SCIP*                 scip,               /**< SCIP data structure */
4880 	   SCIP_MCFNETWORK*      mcfnetwork,         /**< MCF network structure */
4881 	   NODEPAIRQUEUE**       nodepairqueue       /**< pointer to nodepair priority queue */
4882 	   )
4883 	{
4884 	   /* For every nodepair that is used in the network (at least one arc exists having this nodepair as endnodes)
4885 	    * we calculate a weight:
4886 	    * The weight w_st of a nodepair (s,t) is the minimum of the weights of all s-t and t-s arcs
4887 	    * The weight w_a of an arc a is calculated as:
4888 	    *    w_a : = s_a + pi_a
4889 	    * where s_a>=0 is the slack of the capacity constraint and pi_a<=0  its dual.
4890 	    * The weight of uncapacitated arcs (without capacity constraints) is infinite.
4891 	    */
4892 	#ifdef BETTERWEIGHTFORDEMANDNODES
4893 	   int          ncommodities;
4894 	   SCIP_ROW***  nodeflowrows;
4895 	   SCIP_Real**  nodeflowscales;
4896 	   SCIP_Real    maxweight;
4897 	   SCIP_Real    minweight;
4898 	#endif
4899 	
4900 	#ifdef TIEBREAKING
4901 	   int*         colcommodity;
4902 	#endif
4903 	
4904 	   SCIP_HASHTABLE* hashtable;
4905 	   NODEPAIRENTRY*  nodepairs;
4906 	
4907 	   int hashtablesize;
4908 	   int a;
4909 	   int nnodepairs;
4910 	   int n;
4911 	
4912 	   assert(mcfnetwork != NULL);
4913 	
4914 	#ifdef BETTERWEIGHTFORDEMANDNODES
4915 	   ncommodities   = mcfnetwork->ncommodities;
4916 	   nodeflowrows   = mcfnetwork->nodeflowrows;
4917 	   nodeflowscales = mcfnetwork->nodeflowscales;
4918 	#endif
4919 	
4920 	#ifdef TIEBREAKING
4921 	   colcommodity   = mcfnetwork->colcommodity;
4922 	#endif
4923 	
4924 	   assert(nodepairqueue != NULL);
4925 	
4926 	   SCIP_CALL( SCIPallocBuffer(scip, nodepairqueue) );
4927 	
4928 	   /* create a hash table for all used node pairs
4929 	    * hash table is only needed to have unique nodepairs (identify arcs using the same nodepair)
4930 	    */
4931 	   hashtablesize = mcfnetwork->narcs;
4932 	   hashtablesize = MAX(hashtablesize, HASHSIZE_NODEPAIRS);
4933 	   SCIP_CALL( SCIPhashtableCreate(&hashtable, SCIPblkmem(scip), hashtablesize,
4934 	                                  hashGetKeyNodepairs, hashKeyEqNodepairs, hashKeyValNodepairs, (void*) mcfnetwork) );
4935 	
4936 	   /* nodepairs will contain all constructed nodepairs and is used to fill the priority queue */
4937 	   SCIP_CALL( SCIPallocBufferArray(scip, &(*nodepairqueue)->nodepairs, mcfnetwork->narcs) );
4938 	
4939 	   /* initialize hash table of all used node pairs and fill nodepairs */
4940 	   nnodepairs = 0;
4941 	   for( a = 0; a < mcfnetwork->narcs; a++ )
4942 	   {
4943 	      NODEPAIRENTRY  nodepair;
4944 	      NODEPAIRENTRY* nodepairptr;
4945 	      SCIP_ROW* capacityrow;
4946 	
4947 	      capacityrow = mcfnetwork->arccapacityrows[a];
4948 	
4949 	      SCIPdebugMsg(scip, "arc %i = (%i %i)\n", a, mcfnetwork->arcsources[a], mcfnetwork->arctargets[a]);
4950 	
4951 	      /* construct fresh nodepair: smaller node gets node1 in nodeentry */
4952 	      if( mcfnetwork->arcsources[a] <= mcfnetwork->arctargets[a] )
4953 	      {
4954 	         nodepair.node1 = mcfnetwork->arcsources[a];
4955 	         nodepair.node2 = mcfnetwork->arctargets[a];
4956 	      }
4957 	      else
4958 	      {
4959 	         nodepair.node2 = mcfnetwork->arcsources[a];
4960 	         nodepair.node1 = mcfnetwork->arctargets[a];
4961 	      }
4962 	
4963 	      assert(nodepair.node1 < mcfnetwork->nnodes);
4964 	      assert(nodepair.node2 < mcfnetwork->nnodes);
4965 	      if( nodepair.node1 == -1 || nodepair.node2 == -1 )
4966 	         continue;
4967 	
4968 	      /* construct arc weight of a */
4969 	      if( capacityrow != NULL )
4970 	      {
4971 	         SCIP_Real maxval;
4972 	         SCIP_Real slack;
4973 	         SCIP_Real dualsol;
4974 	         SCIP_Real scale;
4975 	#ifdef TIEBREAKING
4976 	         SCIP_Real totalflow;
4977 	         SCIP_Real totalcap;
4978 	         SCIP_COL** rowcols;
4979 	         int rowlen;
4980 	         int i;
4981 	         int c;
4982 	#endif
4983 	
4984 	         slack = SCIPgetRowFeasibility(scip, mcfnetwork->arccapacityrows[a]);
4985 	         slack = MAX(slack, 0.0); /* can only be negative due to numerics */
4986 	         dualsol = SCIProwGetDualsol(mcfnetwork->arccapacityrows[a]);
4987 	         maxval = SCIPgetRowMaxCoef(scip, mcfnetwork->arccapacityrows[a]);
4988 	         scale = ABS(mcfnetwork->arccapacityscales[a])/maxval; /* divide by maxval to normalize rows */
4989 	         assert(scale > 0.0);
4990 	
4991 	#ifdef TIEBREAKING
4992 	         /* get flow on arc for tie breaking */
4993 	         rowcols   = SCIProwGetCols(capacityrow);
4994 	         rowlen    = SCIProwGetNLPNonz(capacityrow);
4995 	         totalflow = 0.0;
4996 	         totalcap  = 0.0;
4997 	         SCIPdebugMsg(scip, " row <%s>: \n", SCIProwGetName(capacityrow));
4998 	
4999 	         for( i = 0; i < rowlen; i++ )
5000 	         {
5001 	            c = SCIPcolGetLPPos(rowcols[i]);
5002 	            assert(0 <= c && c < SCIPgetNLPCols(scip));
5003 	
5004 	            SCIPdebugMsg(scip, "    col <%s>: %g\n", SCIPvarGetName(SCIPcolGetVar(rowcols[i])), SCIPcolGetPrimsol(rowcols[i]) );
5005 	            /* sum up flow on arc a*/
5006 	            if(colcommodity[c] >= 0)
5007 	            {
5008 	               SCIPdebugMsg(scip, "  flow  col <%s>: %g\n", SCIPvarGetName(SCIPcolGetVar(rowcols[i])), REALABS(SCIPcolGetPrimsol(rowcols[i])) );
5009 	               totalflow += REALABS(SCIPcolGetPrimsol(rowcols[i]));
5010 	            }
5011 	            else
5012 	            {
5013 	               SCIPdebugMsg(scip, "  cap  col <%s>: %g\n", SCIPvarGetName(SCIPcolGetVar(rowcols[i])), REALABS(SCIPcolGetPrimsol(rowcols[i])) );
5014 	               totalcap += REALABS(SCIPcolGetPrimsol(rowcols[i]));
5015 	            }
5016 	         }
5017 	
5018 	         SCIPdebugMsg(scip, "cap arc -- slack:%g -- dual:%g -- flow:%g -- cap:%g \n", scale * slack, dualsol/scale, totalflow * scale, totalcap * scale);
5019 	#else
5020 	         SCIPdebugMsg(scip, "cap arc -- slack:%g -- dual:%g1\n", scale * slack, dualsol/scale);
5021 	#endif
5022 	
5023 	         /* put the arc weight into a fresh nodepair */
5024 	         nodepair.weight = scale * slack - ABS(dualsol)/scale;
5025 	#ifdef USEFLOWFORTIEBREAKING
5026 	         if( !SCIPisPositive(scip, nodepair.weight) )
5027 	         {
5028 	            nodepair.weight += totalflow * scale;
5029 	            nodepair.weight = MIN( nodepair.weight, -0.0001);
5030 	         }
5031 	#endif
5032 	#ifdef USECAPACITYFORTIEBREAKING
5033 	         if( !SCIPisPositive(scip, nodepair.weight) )
5034 	         {
5035 	            nodepair.weight += totalcap * scale;
5036 	            nodepair.weight = MIN( nodepair.weight, -0.0001);
5037 	         }
5038 	#endif
5039 	      }
5040 	      else
5041 	      {
5042 	         /* uncapacitated arc has infinite slack */
5043 	         SCIPdebugMsg(scip, "uncap arc ... slack infinite\n");
5044 	         nodepair.weight = SCIPinfinity(scip);
5045 	      }
5046 	
5047 	      /* check if nodepair already exists in hash-table */
5048 	      nodepairptr = (NODEPAIRENTRY*)(SCIPhashtableRetrieve(hashtable, (void*) (&nodepair) ));
5049 	
5050 	      /* if nodepair already exists update its weight */
5051 	      if( nodepairptr != NULL )
5052 	      {
5053 	         /* adapt weight */
5054 	         SCIPdebugMsg(scip, "nodepair known [%d,%d] -- old weight:%g -- new weight:%g\n", nodepair.node1,nodepair.node2,nodepairptr->weight,
5055 	                          MIN(nodepair.weight, nodepairptr->weight));
5056 	         nodepairptr->weight = MIN(nodepair.weight, nodepairptr->weight);
5057 	      }
5058 	      else
5059 	      {
5060 	         /* no such nodepair in current hash table: insert into array and hashtable */
5061 	         nodepairs = (*nodepairqueue)->nodepairs;
5062 	
5063 	         assert(nnodepairs < mcfnetwork->narcs);
5064 	         nodepairs[nnodepairs] = nodepair;
5065 	         SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) (&nodepairs[nnodepairs]) ) );
5066 	
5067 	         SCIPdebugMsg(scip, "new nodepair [%d,%d]-- weight:%g\n", nodepair.node1, nodepair.node2, nodepair.weight);
5068 	
5069 	         nnodepairs++;
5070 	      }
5071 	   }
5072 	
5073 	   /* free hash table */
5074 	   SCIPhashtableFree(&hashtable);
5075 	
5076 	   /* we still have to fill the priority queue */
5077 	
5078 	#ifdef BETTERWEIGHTFORDEMANDNODES
5079 	   /* initial weights have been calculated
5080 	    * we modify them now depending on the demand emanating at the endnodes of nodepairs
5081 	   */
5082 	
5083 	   /* calculate max and min weight */
5084 	   maxweight = +1; /* we want maxweight to be positive */
5085 	   minweight = -1; /* we want minweight to be negative */
5086 	   nodepairs = (*nodepairqueue)->nodepairs;
5087 	   for( n = 0; n < nnodepairs; n++ )
5088 	   {
5089 	      /* maxweight should not be infinity (uncap arcs have infinity weight)*/
5090 	      if(!SCIPisInfinity(scip,nodepairs[n].weight))
5091 	         maxweight = MAX(maxweight, nodepairs[n].weight);
5092 	
5093 	      minweight = MIN(minweight, nodepairs[n].weight);
5094 	   }
5095 	
5096 	   SCIPdebugMsg(scip, "min/max weight:%g / %g\n", minweight, maxweight);
5097 	#endif
5098 	
5099 	   /* initialize priority queue */
5100 	   SCIP_CALL( SCIPpqueueCreate(&(*nodepairqueue)->pqueue, nnodepairs, 2.0, compNodepairs, NULL) );
5101 	
5102 	   /* fill priority queue using array nodepairs */
5103 	   for( n = 0; n < nnodepairs; n++ )
5104 	   {
5105 	      int node1 = nodepairs[n].node1;
5106 	      int node2 = nodepairs[n].node2;
5107 	
5108 	#ifdef BETTERWEIGHTFORDEMANDNODES
5109 	      SCIP_Real rhs = 0;
5110 	      SCIP_Bool hasdemand1 = FALSE;
5111 	      SCIP_Bool hasdemand2 = FALSE;
5112 	
5113 	      int k; /* commodity */
5114 	
5115 	      SCIPdebugMsg(scip, "nodepair [%d,%d] weight %g\n", node1,node2,nodepairs[n].weight);
5116 	      /* check both nodes for their demand value in all commodities
5117 	       * the demand value can be read from the rhs
5118 	       * of the flowrows
5119 	       */
5120 	      /* node1 */
5121 	      for( k = 0; k < ncommodities; k++ )
5122 	      {
5123 	         if( nodeflowrows[node1][k] == NULL )
5124 	            continue;
5125 	
5126 	         if( nodeflowscales[node1][k] > 0.0 )
5127 	            rhs = SCIProwGetRhs(nodeflowrows[node1][k]) - SCIProwGetConstant(nodeflowrows[node1][k]);
5128 	         else
5129 	            rhs = SCIProwGetLhs(nodeflowrows[node1][k]) - SCIProwGetConstant(nodeflowrows[node1][k]);
5130 	
5131 	         assert( !SCIPisInfinity(scip,ABS(rhs)) );
5132 	
5133 	         if( ! SCIPisZero(scip, rhs) )
5134 	         {
5135 	            hasdemand1 = TRUE;
5136 	            break;
5137 	         }
5138 	      }
5139 	
5140 	      /* node2 */
5141 	      for( k = 0; k < ncommodities; k++ )
5142 	      {
5143 	         if( nodeflowrows[node2][k] == NULL )
5144 	            continue;
5145 	
5146 	         if( nodeflowscales[node2][k] > 0.0 )
5147 	            rhs = SCIProwGetRhs(nodeflowrows[node2][k]) - SCIProwGetConstant(nodeflowrows[node2][k]);
5148 	         else
5149 	            rhs = SCIProwGetLhs(nodeflowrows[node2][k]) - SCIProwGetConstant(nodeflowrows[node2][k]);
5150 	
5151 	         assert(! SCIPisInfinity(scip, ABS(rhs)));
5152 	
5153 	         if( ! SCIPisZero(scip, rhs) )
5154 	         {
5155 	            hasdemand2 = TRUE;
5156 	            break;
5157 	         }
5158 	      }
5159 	
5160 	      /* if one of the nodes has no demand increase the score
5161 	       * (slack arcs are still shrunk first)
5162 	       *
5163 	      */
5164 	      if( SCIPisPositive(scip, nodepairs[n].weight))
5165 	      {
5166 	         assert(SCIPisPositive(scip, maxweight));
5167 	
5168 	         if( !hasdemand1 || !hasdemand2 )
5169 	            nodepairs[n].weight += maxweight;
5170 	      }
5171 	      else
5172 	      {
5173 	         assert( SCIPisNegative(scip, minweight));
5174 	
5175 	         if( hasdemand1 && hasdemand2)
5176 	            nodepairs[n].weight += minweight;
5177 	      }
5178 	#endif
5179 	      SCIPdebugMsg(scip, "nodepair [%d,%d] weight %g\n", node1,node2,nodepairs[n].weight);
5180 	
5181 	      /* fill priority queue */
5182 	      SCIP_CALL( SCIPpqueueInsert((*nodepairqueue)->pqueue, (void*)&(*nodepairqueue)->nodepairs[n]) );
5183 	   }
5184 	
5185 	   return SCIP_OKAY;
5186 	}
5187 	
5188 	
5189 	/** frees memory of a nodepair queue */
5190 	static
5191 	void nodepairqueueFree(
5192 	   SCIP*                 scip,               /**< SCIP data structure */
5193 	   NODEPAIRQUEUE**       nodepairqueue       /**< pointer to nodepair priority queue */
5194 	   )
5195 	{
5196 	   assert(nodepairqueue != NULL);
5197 	   assert(*nodepairqueue != NULL);
5198 	
5199 	   SCIPpqueueFree(&(*nodepairqueue)->pqueue);
5200 	   SCIPfreeBufferArray(scip, &(*nodepairqueue)->nodepairs);
5201 	   SCIPfreeBuffer(scip, nodepairqueue);
5202 	}
5203 	
5204 	
5205 	/** returns whether there are any nodepairs left on the queue */
5206 	static
5207 	SCIP_Bool nodepairqueueIsEmpty(
5208 	   NODEPAIRQUEUE*        nodepairqueue       /**< nodepair priority queue */
5209 	   )
5210 	{
5211 	   assert(nodepairqueue != NULL);
5212 	
5213 	   return (SCIPpqueueFirst(nodepairqueue->pqueue) == NULL);
5214 	}
5215 	
5216 	
5217 	/** removes the top element from the nodepair priority queue, returns nodepair entry or NULL */
5218 	static
5219 	NODEPAIRENTRY* nodepairqueueRemove(
5220 	   NODEPAIRQUEUE*        nodepairqueue       /**< nodepair priority queue */
5221 	   )
5222 	{
5223 	   assert(nodepairqueue != NULL);
5224 	
5225 	   return (NODEPAIRENTRY*)SCIPpqueueRemove(nodepairqueue->pqueue);
5226 	}
5227 	
5228 	/*
5229 	 * Node partition methods
5230 	 * used for creating partitions of nodes
5231 	 * use  union find algorithm
5232 	*/
5233 	
5234 	/** returns the representative node in the cluster of the given node */
5235 	static
5236 	int nodepartitionGetRepresentative(
5237 	   NODEPARTITION*        nodepartition,      /**< node partition data structure */
5238 	   int                   v                   /**< node id to get representative for */
5239 	   )
5240 	{
5241 	   return unionfindGetRepresentative(nodepartition->representatives, v);
5242 	}
5243 	
5244 	/** joins two clusters given by their representative nodes */
5245 	static
5246 	void nodepartitionJoin(
5247 	   NODEPARTITION*        nodepartition,      /**< node partition data structure */
5248 	   int                   rep1,               /**< representative of first cluster */
5249 	   int                   rep2                /**< representative of second cluster */
5250 	   )
5251 	{
5252 	   unionfindJoinSets (nodepartition->representatives, rep1, rep2);
5253 	}
5254 	
5255 	/** partitions nodes into a small number of clusters */
5256 	static
5257 	SCIP_RETCODE nodepartitionCreate(
5258 	   SCIP*                 scip,               /**< SCIP data structure */
5259 	   SCIP_MCFNETWORK*      mcfnetwork,         /**< MCF network structure */
5260 	   NODEPARTITION**       nodepartition,      /**< pointer to node partition data structure */
5261 	   int                   nclusters           /**< number of clusters to generate */
5262 	   )
5263 	{
5264 	   NODEPAIRQUEUE* nodepairqueue;
5265 	   int* clustersize;
5266 	   int nclustersleft;
5267 	   int v;
5268 	   int c;
5269 	   int pos;
5270 	
5271 	   assert(mcfnetwork != NULL);
5272 	   assert(nodepartition != NULL);
5273 	   assert(mcfnetwork->nnodes >= 1);
5274 	
5275 	   /* allocate and initialize memory */
5276 	   SCIP_CALL( SCIPallocBuffer(scip, nodepartition) );
5277 	   SCIP_CALL( SCIPallocBufferArray(scip, &(*nodepartition)->representatives, mcfnetwork->nnodes) );
5278 	   SCIP_CALL( SCIPallocBufferArray(scip, &(*nodepartition)->nodeclusters, mcfnetwork->nnodes) );
5279 	   SCIP_CALL( SCIPallocBufferArray(scip, &(*nodepartition)->clusternodes, mcfnetwork->nnodes) );
5280 	   SCIP_CALL( SCIPallocBufferArray(scip, &(*nodepartition)->clusterbegin, nclusters+1) );
5281 	   (*nodepartition)->nclusters = 0;
5282 	
5283 	   /* we start with each node being in its own cluster */
5284 	   unionfindInitSets((*nodepartition)->representatives, mcfnetwork->nnodes);
5285 	
5286 	   /* create priority queue for nodepairs */
5287 	   SCIP_CALL( nodepairqueueCreate(scip, mcfnetwork, &nodepairqueue) );
5288 	
5289 	   /* loop over nodepairs in order of their weights */
5290 	   nclustersleft = mcfnetwork->nnodes;
5291 	   while( !nodepairqueueIsEmpty(nodepairqueue) && nclustersleft > nclusters )
5292 	   {
5293 	      NODEPAIRENTRY* nodepair;
5294 	      int node1;
5295 	      int node2;
5296 	      int node1rep;
5297 	      int node2rep;
5298 	
5299 	      /* get the next nodepair */
5300 	      nodepair = nodepairqueueRemove(nodepairqueue);
5301 	      assert(nodepair != NULL);
5302 	      node1 = nodepair->node1;
5303 	      node2 = nodepair->node2;
5304 	
5305 	      assert(node1 >= 0 && node1 < mcfnetwork->nnodes);
5306 	      assert(node2 >= 0 && node2 < mcfnetwork->nnodes);
5307 	
5308 	      /* identify the representatives of the two nodes */
5309 	      node1rep = nodepartitionGetRepresentative(*nodepartition, node1);
5310 	      node2rep = nodepartitionGetRepresentative(*nodepartition, node2);
5311 	      assert(0 <= node1rep && node1rep < mcfnetwork->nnodes);
5312 	      assert(0 <= node2rep && node2rep < mcfnetwork->nnodes);
5313 	
5314 	      /* there is nothing to do if the two nodes are already in the same cluster */
5315 	      if( node1rep == node2rep )
5316 	         continue;
5317 	
5318 	      /* shrink nodepair by joining the two clusters */
5319 	      SCIPdebugMsg(scip, "shrinking nodepair (%d,%d) with weight %g: join representatives %d and %d\n",
5320 	                       node1, node2, nodepair->weight, node1rep, node2rep);
5321 	      nodepartitionJoin(*nodepartition, node1rep, node2rep);
5322 	      nclustersleft--;
5323 	   }
5324 	
5325 	   /* node 0 must be a representative due to our join procedure */
5326 	   assert((*nodepartition)->representatives[0] == 0);
5327 	
5328 	   /* if there have been too few arcs to shrink the graph to the required number of clusters, join clusters with first cluster
5329 	    * to create a larger disconnected cluster
5330 	    */
5331 	   if( nclustersleft > nclusters )
5332 	   {
5333 	      for( v = 1; v < mcfnetwork->nnodes && nclustersleft > nclusters; v++ )
5334 	      {
5335 	         int rep;
5336 	
5337 	         rep = nodepartitionGetRepresentative(*nodepartition, v);
5338 	         if( rep != 0 )
5339 	         {
5340 	            nodepartitionJoin(*nodepartition, 0, rep);
5341 	            nclustersleft--;
5342 	         }
5343 	      }
5344 	   }
5345 	   assert(nclustersleft <= nclusters);
5346 	
5347 	   /* extract the clusters */
5348 	   SCIP_CALL( SCIPallocBufferArray(scip, &clustersize, nclusters) );
5349 	   BMSclearMemoryArray(clustersize, nclusters);
5350 	   for( v = 0; v < mcfnetwork->nnodes; v++ )
5351 	   {
5352 	      int rep;
5353 	
5354 	      /* get cluster of node */
5355 	      rep = nodepartitionGetRepresentative(*nodepartition, v);
5356 	      assert(rep <= v); /* due to our joining procedure */
5357 	      if( rep == v )
5358 	      {
5359 	         /* node is its own representative: this is a new cluster */
5360 	         c = (*nodepartition)->nclusters;
5361 	         (*nodepartition)->nclusters++;
5362 	      }
5363 	      else
5364 	         c = (*nodepartition)->nodeclusters[rep];
5365 	      assert(0 <= c && c < nclusters);
5366 	
5367 	      /* assign node to cluster */
5368 	      (*nodepartition)->nodeclusters[v] = c;
5369 	      clustersize[c]++;
5370 	   }
5371 	
5372 	   /* fill the clusterbegin array */
5373 	   pos = 0;
5374 	   for( c = 0; c < (*nodepartition)->nclusters; c++ )
5375 	   {
5376 	      (*nodepartition)->clusterbegin[c] = pos;
5377 	      pos += clustersize[c];
5378 	   }
5379 	   assert(pos == mcfnetwork->nnodes);
5380 	   (*nodepartition)->clusterbegin[(*nodepartition)->nclusters] = mcfnetwork->nnodes;
5381 	
5382 	   /* fill the clusternodes array */
5383 	   BMSclearMemoryArray(clustersize, (*nodepartition)->nclusters);
5384 	   for( v = 0; v < mcfnetwork->nnodes; v++ )
5385 	   {
5386 	      c = (*nodepartition)->nodeclusters[v];
5387 	      assert(0 <= c && c < (*nodepartition)->nclusters);
5388 	      pos = (*nodepartition)->clusterbegin[c] + clustersize[c];
5389 	      assert(pos < (*nodepartition)->clusterbegin[c+1]);
5390 	      (*nodepartition)->clusternodes[pos] = v;
5391 	      clustersize[c]++;
5392 	   }
5393 	
5394 	   /* free temporary memory */
5395 	   SCIPfreeBufferArray(scip, &clustersize);
5396 	
5397 	   /* free nodepair queue */
5398 	   nodepairqueueFree(scip, &nodepairqueue);
5399 	
5400 	   return SCIP_OKAY;
5401 	}
5402 	
5403 	/** frees node partition data */
5404 	static
5405 	void nodepartitionFree(
5406 	   SCIP*                 scip,               /**< SCIP data structure */
5407 	   NODEPARTITION**       nodepartition       /**< pointer to node partition data structure */
5408 	   )
5409 	{
5410 	   assert(nodepartition != NULL);
5411 	   assert(*nodepartition != NULL);
5412 	
5413 	   SCIPfreeBufferArray(scip, &(*nodepartition)->clusterbegin);
5414 	   SCIPfreeBufferArray(scip, &(*nodepartition)->clusternodes);
5415 	   SCIPfreeBufferArray(scip, &(*nodepartition)->nodeclusters);
5416 	   SCIPfreeBufferArray(scip, &(*nodepartition)->representatives);
5417 	   SCIPfreeBuffer(scip, nodepartition);
5418 	}
5419 	
5420 	/** returns whether given node v is in a cluster that belongs to the partition S */
5421 	static
5422 	SCIP_Bool nodeInPartition(
5423 	   NODEPARTITION*        nodepartition,      /**< node partition data structure, or NULL */
5424 	   unsigned int          partition,          /**< partition of nodes, or node number in single-node partition */
5425 	   SCIP_Bool             inverted,           /**< should partition be inverted? */
5426 	   int                   v                   /**< node to check */
5427 	   )
5428 	{
5429 	   /* if the node does not exist, it is not in the partition
5430 	    * (and also not in the inverted partition)
5431 	    */
5432 	   if( v < 0 )
5433 	      return FALSE;
5434 	
5435 	   if( nodepartition == NULL )
5436 	      return ((v == (int)partition) == !inverted);
5437 	   else
5438 	   {
5439 	      int cluster;
5440 	      unsigned int clusterbit;
5441 	
5442 	      cluster = nodepartition->nodeclusters[v];
5443 	      assert(0 <= cluster && cluster < nodepartition->nclusters);
5444 	      clusterbit = (1 << cluster); /*lint !e701*/
5445 	
5446 	      return (((partition & clusterbit) != 0) == !inverted);
5447 	   }
5448 	}
5449 	
5450 	/** returns whether each of the sets S and T defined by the nodepartition is connected */
5451 	static
5452 	int nodepartitionIsConnected(
5453 	   SCIP*                 scip,               /**< SCIP data structure */
5454 	   SCIP_MCFNETWORK*      mcfnetwork,         /**< MCF network structure */
5455 	   NODEPARTITION*        nodepartition,      /**< node partition data structure */
5456 	   unsigned int          partition           /**< partition of nodes, or node number in single-node partition */
5457 	   )
5458 	{
5459 	   const int* nodeclusters = nodepartition->nodeclusters;
5460 	   const int* arcsources   = mcfnetwork->arcsources;
5461 	   const int* arctargets   = mcfnetwork->arctargets;
5462 	   int        narcs        = mcfnetwork->narcs;
5463 	   int        nclusters;
5464 	
5465 	   int  ncomponents;
5466 	   int  a;
5467 	   int* rep;
5468 	
5469 	   assert(nodepartition->nodeclusters != NULL);
5470 	   nclusters = nodepartition->nclusters;
5471 	
5472 	   if( SCIPallocBufferArray(scip, &rep, nclusters) != SCIP_OKAY )
5473 	      return 0;
5474 	
5475 	   /* start with each cluster being isolated */
5476 	   unionfindInitSets(rep, nclusters);
5477 	   ncomponents = nclusters;
5478 	   assert(ncomponents >= 2);
5479 	
5480 	   /* for each arc within S or within T join the connected clusters */
5481 	   for( a = 0; a < narcs; a++ )
5482 	   {
5483 	      int s = arcsources[a];
5484 	      int t = arctargets[a];
5485 	
5486 	      /* ignore arcs that connect the pseudo node -1 */
5487 	      if( s == -1 || t == -1 )
5488 	         continue;
5489 	
5490 	      /* check if arc is within one of the components */
5491 	      if( nodeInPartition(nodepartition, partition, FALSE, s) == nodeInPartition(nodepartition, partition, FALSE, t) )
5492 	      {
5493 	         int cs;
5494 	         int ct;
5495 	         int repcs;
5496 	         int repct;
5497 	
5498 	         assert(0 <= s && s < mcfnetwork->nnodes);
5499 	         assert(0 <= t && t < mcfnetwork->nnodes);
5500 	
5501 	         /* get clusters of the two nodes */
5502 	         cs = nodeclusters[s];
5503 	         ct = nodeclusters[t];
5504 	         assert(0 <= cs && cs < nclusters);
5505 	         assert(0 <= ct && ct < nclusters);
5506 	
5507 	         /* nothing to do if we are already in the same cluster */
5508 	         if( cs == ct )
5509 	            continue;
5510 	
5511 	         /* get representatives of clusters in the union structure */
5512 	         repcs = unionfindGetRepresentative (rep, cs);
5513 	         repct = unionfindGetRepresentative (rep, ct);
5514 	         if( repcs == repct )
5515 	            continue;
5516 	
5517 	         /* the arc connects two previously unconnected components of S or T */
5518 	
5519 	         /* check if we already reached two distinct components */
5520 	         ncomponents--;
5521 	         if( ncomponents <= 2 )
5522 	            break;
5523 	
5524 	         /* join the two cluster sets and continue */
5525 	         unionfindJoinSets (rep, repcs, repct);
5526 	      }
5527 	   }
5528 	
5529 	   /* each of the two shores S and T are connected if we were able to shrink the graph
5530 	      into two components */
5531 	   assert(ncomponents >= 2);
5532 	   SCIPfreeBufferArray(scip, &rep);
5533 	   return (ncomponents == 2);
5534 	}
5535 	
5536 	#ifdef SCIP_DEBUG
5537 	static
5538 	void nodepartitionPrint(
5539 	   NODEPARTITION*        nodepartition       /**< node partition data structure */
5540 	   )
5541 	{
5542 	   int c;
5543 	
5544 	   for( c = 0; c < nodepartition->nclusters; c++ )
5545 	   {
5546 	      int i;
5547 	
5548 	      MCFdebugMessage("cluster %d:", c);
5549 	      for( i = nodepartition->clusterbegin[c]; i < nodepartition->clusterbegin[c+1]; i++ )
5550 	         MCFdebugMessage(" %d", nodepartition->clusternodes[i]);
5551 	      MCFdebugMessage("\n");
5552 	   }
5553 	}
5554 	#endif
5555 	
5556 	#ifdef OUTPUTGRAPH
5557 	/** generates a GML file to visualize the network graph and LP solution */
5558 	static
5559 	SCIP_RETCODE outputGraph(
5560 	   SCIP*                 scip,               /**< SCIP data structure */
5561 	   SCIP_MCFNETWORK*      mcfnetwork,         /**< MCF network structure */
5562 	   NODEPARTITION*        nodepartition,      /**< node partition data structure, or NULL */
5563 	   SCIP_Bool             inverted,           /**< should partition be inverted? */
5564 	   unsigned int          partition           /**< partition of nodes, or node number */
5565 	   )
5566 	{
5567 	   FILE* file;
5568 	   char filename[SCIP_MAXSTRLEN];
5569 	   int v;
5570 	   int a;
5571 	
5572 	   /* open file */
5573 	   if( nodepartition == NULL )
5574 	      (void) SCIPsnprintf(filename, SCIP_MAXSTRLEN, "mcf-node-%d.gml", partition);
5575 	   else
5576 	      (void) SCIPsnprintf(filename, SCIP_MAXSTRLEN, "mcf-part-%d.gml", partition);
5577 	   SCIPinfoMessage(scip, NULL, "creating GML output file <%s>...\n", filename);
5578 	   file = fopen(filename, "w");
5579 	   if( file == NULL )
5580 	   {
5581 	      SCIPerrorMessage("cannot create GML output file <%s>\n", filename);
5582 	      return SCIP_FILECREATEERROR;
5583 	   }
5584 	
5585 	   /* print GML header */
5586 	   fprintf(file, "graph\n");
5587 	   fprintf(file, "[\n");
5588 	   fprintf(file, "        hierarchic      1\n");
5589 	   fprintf(file, "        label   \"\"\n");
5590 	   fprintf(file, "        directed        1\n");
5591 	
5592 	   /* nodes */
5593 	   for( v = 0; v < mcfnetwork->nnodes; v++ )
5594 	   {
5595 	      char label[SCIP_MAXSTRLEN];
5596 	      SCIP_Bool inpartition;
5597 	
5598 	      if( mcfnetwork->nodeflowrows[v][0] != NULL )
5599 	         (void) SCIPsnprintf(label, SCIP_MAXSTRLEN, "%s", SCIProwGetName(mcfnetwork->nodeflowrows[v][0]));
5600 	      else
5601 	         (void) SCIPsnprintf(label, SCIP_MAXSTRLEN, "%d", v);
5602 	      inpartition = nodeInPartition(nodepartition, partition, inverted, v);
5603 	
5604 	      fprintf(file, "        node\n");
5605 	      fprintf(file, "        [\n");
5606 	      fprintf(file, "                id      %d\n", v);
5607 	      fprintf(file, "                label   \"%s\"\n", label);
5608 	      fprintf(file, "                graphics\n");
5609 	      fprintf(file, "                [\n");
5610 	      fprintf(file, "                        w       30.0\n");
5611 	      fprintf(file, "                        h       30.0\n");
5612 	      fprintf(file, "                        type    \"ellipse\"\n");
5613 	      if( inpartition )
5614 	         fprintf(file, "                        fill    \"#FF0000\"\n");
5615 	      else
5616 	         fprintf(file, "                        fill    \"#00FF00\"\n");
5617 	      fprintf(file, "                        outline \"#000000\"\n");
5618 	      fprintf(file, "                ]\n");
5619 	      fprintf(file, "                LabelGraphics\n");
5620 	      fprintf(file, "                [\n");
5621 	      fprintf(file, "                        text    \"%s\"\n", label);
5622 	      fprintf(file, "                        fontSize        13\n");
5623 	      fprintf(file, "                        fontName        \"Dialog\"\n");
5624 	      fprintf(file, "                        anchor  \"c\"\n");
5625 	      fprintf(file, "                ]\n");
5626 	      if( inpartition )
5627 	         fprintf(file, "                gid     %d\n", mcfnetwork->nnodes+1);
5628 	      else
5629 	         fprintf(file, "                gid     %d\n", mcfnetwork->nnodes+2);
5630 	      fprintf(file, "        ]\n");
5631 	   }
5632 	
5633 	   /* dummy node for missing arc sources or arc targets */
5634 	   fprintf(file, "        node\n");
5635 	   fprintf(file, "        [\n");
5636 	   fprintf(file, "                id      %d\n", mcfnetwork->nnodes);
5637 	   fprintf(file, "                label   \"?\"\n");
5638 	   fprintf(file, "                graphics\n");
5639 	   fprintf(file, "                [\n");
5640 	   fprintf(file, "                        w       30.0\n");
5641 	   fprintf(file, "                        h       30.0\n");
5642 	   fprintf(file, "                        type    \"ellipse\"\n");
5643 	   fprintf(file, "                        fill    \"#FFFFFF\"\n");
5644 	   fprintf(file, "                        outline \"#000000\"\n");
5645 	   fprintf(file, "                ]\n");
5646 	   fprintf(file, "                LabelGraphics\n");
5647 	   fprintf(file, "                [\n");
5648 	   fprintf(file, "                        text    \"?\"\n");
5649 	   fprintf(file, "                        fontSize        13\n");
5650 	   fprintf(file, "                        fontName        \"Dialog\"\n");
5651 	   fprintf(file, "                        anchor  \"c\"\n");
5652 	   fprintf(file, "                ]\n");
5653 	   fprintf(file, "        ]\n");
5654 	
5655 	   /* group node for partition S */
5656 	   fprintf(file, "        node\n");
5657 	   fprintf(file, "        [\n");
5658 	   fprintf(file, "                id      %d\n", mcfnetwork->nnodes+1);
5659 	   fprintf(file, "                label   \"Partition S\"\n");
5660 	   fprintf(file, "                graphics\n");
5661 	   fprintf(file, "                [\n");
5662 	   fprintf(file, "                        type    \"roundrectangle\"\n");
5663 	   fprintf(file, "                        fill    \"#CAECFF84\"\n");
5664 	   fprintf(file, "                        outline \"#666699\"\n");
5665 	   fprintf(file, "                        outlineStyle    \"dotted\"\n");
5666 	   fprintf(file, "                        topBorderInset  0\n");
5667 	   fprintf(file, "                        bottomBorderInset       0\n");
5668 	   fprintf(file, "                        leftBorderInset 0\n");
5669 	   fprintf(file, "                        rightBorderInset        0\n");
5670 	   fprintf(file, "                ]\n");
5671 	   fprintf(file, "                LabelGraphics\n");
5672 	   fprintf(file, "                [\n");
5673 	   fprintf(file, "                        text    \"Partition S\"\n");
5674 	   fprintf(file, "                        fill    \"#99CCFF\"\n");
5675 	   fprintf(file, "                        fontSize        15\n");
5676 	   fprintf(file, "                        fontName        \"Dialog\"\n");
5677 	   fprintf(file, "                        alignment       \"right\"\n");
5678 	   fprintf(file, "                        autoSizePolicy  \"node_width\"\n");
5679 	   fprintf(file, "                        anchor  \"t\"\n");
5680 	   fprintf(file, "                        borderDistance  0.0\n");
5681 	   fprintf(file, "                ]\n");
5682 	   fprintf(file, "                isGroup 1\n");
5683 	   fprintf(file, "        ]\n");
5684 	
5685 	   /* group node for partition T */
5686 	   fprintf(file, "        node\n");
5687 	   fprintf(file, "        [\n");
5688 	   fprintf(file, "                id      %d\n", mcfnetwork->nnodes+2);
5689 	   fprintf(file, "                label   \"Partition T\"\n");
5690 	   fprintf(file, "                graphics\n");
5691 	   fprintf(file, "                [\n");
5692 	   fprintf(file, "                        type    \"roundrectangle\"\n");
5693 	   fprintf(file, "                        fill    \"#CAECFF84\"\n");
5694 	   fprintf(file, "                        outline \"#666699\"\n");
5695 	   fprintf(file, "                        outlineStyle    \"dotted\"\n");
5696 	   fprintf(file, "                        topBorderInset  0\n");
5697 	   fprintf(file, "                        bottomBorderInset       0\n");
5698 	   fprintf(file, "                        leftBorderInset 0\n");
5699 	   fprintf(file, "                        rightBorderInset        0\n");
5700 	   fprintf(file, "                ]\n");
5701 	   fprintf(file, "                LabelGraphics\n");
5702 	   fprintf(file, "                [\n");
5703 	   fprintf(file, "                        text    \"Partition T\"\n");
5704 	   fprintf(file, "                        fill    \"#99CCFF\"\n");
5705 	   fprintf(file, "                        fontSize        15\n");
5706 	   fprintf(file, "                        fontName        \"Dialog\"\n");
5707 	   fprintf(file, "                        alignment       \"right\"\n");
5708 	   fprintf(file, "                        autoSizePolicy  \"node_width\"\n");
5709 	   fprintf(file, "                        anchor  \"t\"\n");
5710 	   fprintf(file, "                        borderDistance  0.0\n");
5711 	   fprintf(file, "                ]\n");
5712 	   fprintf(file, "                isGroup 1\n");
5713 	   fprintf(file, "        ]\n");
5714 	
5715 	   /* arcs */
5716 	   for( a = 0; a < mcfnetwork->narcs; a++ )
5717 	   {
5718 	      SCIP_ROW* row;
5719 	      SCIP_Real slack;
5720 	      SCIP_Bool hasfractional;
5721 	      char label[SCIP_MAXSTRLEN];
5722 	
5723 	      if( mcfnetwork->arccapacityrows[a] != NULL )
5724 	         (void) SCIPsnprintf(label, SCIP_MAXSTRLEN, "%s", SCIProwGetName(mcfnetwork->arccapacityrows[a]));
5725 	      else
5726 	         (void) SCIPsnprintf(label, SCIP_MAXSTRLEN, "%d", a);
5727 	
5728 	      hasfractional = FALSE;
5729 	      row = mcfnetwork->arccapacityrows[a];
5730 	      if( row != NULL )
5731 	      {
5732 	         SCIP_COL** rowcols;
5733 	         int rowlen;
5734 	         int i;
5735 	
5736 	         slack = ABS(mcfnetwork->arccapacityscales[a]) * SCIPgetRowLPFeasibility(scip, row);
5737 	         rowcols = SCIProwGetCols(row);
5738 	         rowlen = SCIProwGetNLPNonz(row);
5739 	         for( i = 0; i < rowlen; i++ )
5740 	         {
5741 	            SCIP_VAR* var;
5742 	
5743 	            var = SCIPcolGetVar(rowcols[i]);
5744 	            if( SCIPvarIsIntegral(var) && !SCIPisFeasIntegral(scip, SCIPvarGetLPSol(var)) )
5745 	            {
5746 	               hasfractional = TRUE;
5747 	               break;
5748 	            }
5749 	         }
5750 	      }
5751 	      else
5752 	         slack = SCIPinfinity(scip);
5753 	
5754 	      fprintf(file, "        edge\n");
5755 	      fprintf(file, "        [\n");
5756 	      fprintf(file, "                source  %d\n", mcfnetwork->arcsources[a] >= 0 ? mcfnetwork->arcsources[a] : mcfnetwork->nnodes);
5757 	      fprintf(file, "                target  %d\n", mcfnetwork->arctargets[a] >= 0 ? mcfnetwork->arctargets[a] : mcfnetwork->nnodes);
5758 	      fprintf(file, "                label \"%s\"\n", label);
5759 	      fprintf(file, "                graphics\n");
5760 	      fprintf(file, "                [\n");
5761 	      if( SCIPisFeasPositive(scip, slack) )
5762 	         fprintf(file, "                        fill    \"#000000\"\n");
5763 	      else
5764 	         fprintf(file, "                        fill    \"#FF0000\"\n");
5765 	      if( hasfractional )
5766 	         fprintf(file, "                        style   \"dashed\"\n");
5767 	      fprintf(file, "                        width   1\n");
5768 	      fprintf(file, "                        targetArrow     \"standard\"\n");
5769 	      fprintf(file, "                ]\n");
5770 	      fprintf(file, "                LabelGraphics\n");
5771 	      fprintf(file, "                [\n");
5772 	      fprintf(file, "                        text    \"%s\"\n", label);
5773 	      fprintf(file, "                ]\n");
5774 	      fprintf(file, "        ]\n");
5775 	   }
5776 	
5777 	   /* print GML footer */
5778 	   fprintf(file, "]\n");
5779 	
5780 	   /* close file */
5781 	   fclose(file);
5782 	
5783 	   return SCIP_OKAY;
5784 	}
5785 	#endif
5786 	
5787 	/** adds given cut to LP if violated */
5788 	static
5789 	SCIP_RETCODE addCut(
5790 	   SCIP*                 scip,               /**< SCIP data structure */
5791 	   SCIP_SEPA*            sepa,               /**< separator */
5792 	   SCIP_SEPADATA*        sepadata,           /**< separator data */
5793 	   SCIP_SOL*             sol,                /**< the solution that should be separated, or NULL for LP solution */
5794 	   SCIP_Real*            cutcoefs,           /**< coefficients of active variables in cut */
5795 	   SCIP_Real             cutrhs,             /**< right hand side of cut */
5796 	   int*                  cutinds,            /**< problem indices of variables with non-zero coefficient */
5797 	   int                   cutnnz,             /**< number of non-zeros in cut */
5798 	   SCIP_Bool             cutislocal,         /**< is the cut only locally valid? */
5799 	   int                   cutrank,            /**< rank of the cut */
5800 	   int*                  ncuts,              /**< pointer to count the number of added cuts */
5801 	   SCIP_Bool*            cutoff              /**< pointer to store whether a cutoff was found */
5802 	   )
5803 	{
5804 	   SCIP_ROW* cut;
5805 	   char cutname[SCIP_MAXSTRLEN];
5806 	   SCIP_VAR** vars;
5807 	   int nvars;
5808 	   int i;
5809 	
5810 	   /* variables for knapsack cover separation */
5811 	   SCIP_VAR** cutvars;
5812 	
5813 	   assert(scip != NULL);
5814 	   assert(sepadata != NULL);
5815 	   assert(cutcoefs != NULL);
5816 	   assert(ncuts != NULL);
5817 	   assert(cutoff != NULL);
5818 	
5819 	   /* get active problem variables */
5820 	   SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
5821 	   assert(nvars == 0 || vars != NULL);
5822 	
5823 	   *cutoff = FALSE;
5824 	
5825 	   SCIP_CALL( SCIPallocBufferArray(scip, &cutvars, cutnnz) );
5826 	
5827 	   for( i = 0; i < cutnnz; ++i )
5828 	   {
5829 	      cutvars[i] = vars[cutinds[i]];
5830 	   }
5831 	
5832 	   /* create the cut */
5833 	   (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "mcf%" SCIP_LONGINT_FORMAT "_%d", SCIPgetNLPs(scip), *ncuts);
5834 	   SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &cut, sepa, cutname, -SCIPinfinity(scip), cutrhs, cutislocal, FALSE,
5835 	         sepadata->dynamiccuts) );
5836 	
5837 	   SCIP_CALL( SCIPaddVarsToRow(scip, cut, cutnnz, cutvars, cutcoefs) );
5838 	
5839 	   /* set cut rank */
5840 	   SCIProwChgRank(cut, cutrank);
5841 	
5842 	   /* check efficacy */
5843 	   assert(SCIPisCutEfficacious(scip, sol, cut));
5844 	
5845 	   SCIPdebugMsg(scip, " -> found MCF cut <%s>: rhs=%f, act=%f eff=%f rank=%d\n",
5846 	                cutname, cutrhs, SCIPgetRowSolActivity(scip, cut, sol), SCIPgetCutEfficacy(scip, sol, cut), SCIProwGetRank(cut));
5847 	   /*SCIPdebug( SCIP_CALL(SCIPprintRow(scip, cut, NULL)) );*/
5848 	
5849 	   if( !cutislocal )
5850 	   {
5851 	      SCIP_CALL( SCIPaddPoolCut(scip, cut) );
5852 	   }
5853 	   else
5854 	   {
5855 	      SCIP_CALL( SCIPaddRow(scip, cut, FALSE, cutoff) );
5856 	   }
5857 	   (*ncuts)++;
5858 	
5859 	   /* release the row */
5860 	   SCIP_CALL( SCIPreleaseRow(scip, &cut) );
5861 	
5862 	   if( !(*cutoff) && sepadata->separateknapsack)
5863 	   {
5864 	      /* relax cut to knapsack row and separate lifted cover cuts */
5865 	      SCIP_CALL( SCIPseparateRelaxedKnapsack(scip, NULL, sepa, cutnnz, cutvars, cutcoefs, +1.0, cutrhs, sol, cutoff, ncuts) );
5866 	   }
5867 	   SCIPfreeBufferArray(scip, &cutvars);
5868 	
5869 	   return SCIP_OKAY;
5870 	}
5871 	
5872 	/** enumerates cuts between subsets of the clusters
5873 	 *  generates single-node cuts if nodepartition == NULL, otherwise generates cluster cuts
5874 	 */
5875 	static
5876 	SCIP_RETCODE generateClusterCuts(
5877 	   SCIP*                 scip,               /**< SCIP data structure */
5878 	   SCIP_SEPA*            sepa,               /**< separator */
5879 	   SCIP_SEPADATA*        sepadata,           /**< separator data */
5880 	   SCIP_SOL*             sol,                /**< the solution that should be separated, or NULL for LP solution */
5881 	   SCIP_Bool             allowlocal,         /**< should local cuts be allowed */
5882 	   int                   depth,              /**< current depth */
5883 	   SCIP_MCFNETWORK*      mcfnetwork,         /**< MCF network structure */
5884 	   NODEPARTITION*        nodepartition,      /**< node partition data structure, or NULL */
5885 	   int*                  ncuts,              /**< pointer to count the number of added cuts */
5886 	   SCIP_Bool*            cutoff              /**< pointer to store whether a cutoff was found */
5887 	   )
5888 	{
5889 	   SCIP_ROW***       nodeflowrows      = mcfnetwork->nodeflowrows;
5890 	   SCIP_Real**       nodeflowscales    = mcfnetwork->nodeflowscales;
5891 	   SCIP_Bool**       nodeflowinverted  = mcfnetwork->nodeflowinverted;
5892 	   SCIP_ROW**        arccapacityrows   = mcfnetwork->arccapacityrows;
5893 	   SCIP_Real*        arccapacityscales = mcfnetwork->arccapacityscales;
5894 	   int*              colcommodity      = mcfnetwork->colcommodity;
5895 	   int*              arcsources        = mcfnetwork->arcsources;
5896 	   int*              arctargets        = mcfnetwork->arctargets;
5897 	   int               nnodes            = mcfnetwork->nnodes;
5898 	   int               narcs             = mcfnetwork->narcs;
5899 	   int               ncommodities      = mcfnetwork->ncommodities;
5900 	   SCIP_MCFMODELTYPE modeltype         = mcfnetwork->modeltype;
5901 	   MCFEFFORTLEVEL    effortlevel       = sepadata->effortlevel;
5902 	   int maxsepacuts;
5903 	
5904 	   int nrows;
5905 	   int nvars;
5906 	
5907 	   SCIP_AGGRROW* aggrrow;
5908 	   SCIP_Real* cutcoefs;
5909 	   SCIP_Real* deltas;
5910 	   int* cutinds;
5911 	   int deltassize;
5912 	   int ndeltas;
5913 	   SCIP_Real* rowweights;
5914 	   SCIP_Real* comcutdemands;
5915 	   SCIP_Real* comdemands;
5916 	   unsigned int partition;
5917 	   unsigned int allpartitions;
5918 	   unsigned int startpartition;
5919 	   SCIP_Bool useinverted;
5920 	   SCIP_Bool inverted;
5921 	   int maxtestdelta;
5922 	
5923 	   int oldncuts = 0; /* to check success of separation for one nodeset */
5924 	   *cutoff = FALSE;
5925 	
5926 	   assert( effortlevel == MCFEFFORTLEVEL_AGGRESSIVE || effortlevel == MCFEFFORTLEVEL_DEFAULT );
5927 	   nrows = SCIPgetNLPRows(scip);
5928 	   nvars = SCIPgetNVars(scip);
5929 	
5930 	   /* get the maximal number of cuts allowed in a separation round */
5931 	   if( depth == 0 )
5932 	      maxsepacuts = sepadata->maxsepacutsroot;
5933 	   else
5934 	      maxsepacuts = sepadata->maxsepacuts;
5935 	   if( maxsepacuts < 0 )
5936 	      maxsepacuts = INT_MAX;
5937 	   else if( effortlevel == MCFEFFORTLEVEL_AGGRESSIVE )
5938 	      maxsepacuts *= 2;
5939 	
5940 	   /* get the maximal number of deltas to use for cmir separation */
5941 	   maxtestdelta = sepadata->maxtestdelta;
5942 	   if( maxtestdelta <= 0 )
5943 	      maxtestdelta = INT_MAX;
5944 	   else if( effortlevel == MCFEFFORTLEVEL_AGGRESSIVE )
5945 	      maxtestdelta *= 2;
5946 	
5947 	   /* Our system has the following form:
5948 	    *  (1)  \sum_{a \in \delta^+(v)} f_a^k  - \sum_{a \in \delta^-(v)} f_a^k  <=  -d_v^k   for all v \in V and k \in K
5949 	    *  (2)  \sum_{k \in K} f_a^k - c_a x_a                                    <=  0        for all a \in A
5950 	    *
5951 	    * The partitioning yields two clusters:
5952 	    *
5953 	    *                A^+
5954 	    *   cluster S  ------>  cluster T
5955 	    *              <------
5956 	    *                A^-
5957 	    *
5958 	    * Now we look at all commodities in which we have to route flow from T to S:
5959 	    *   K^+ = {k : d^k_S := sum_{v \in S} d_v^k > 0}
5960 	    *
5961 	    * Then, the base constraint of the c-MIR cut is the sum of those flow conservation constraints and the
5962 	    * capacity constraints for arcs A^-:
5963 	    *
5964 	    *   sum_{k \in K^+} sum_{v \in S} (sum_{a \in \delta^+(v)} f_a^k  - sum_{a \in \delta^-(v)} f_a^k)           <=  sum_{k \in K^+} sum_{v \in S} -d_v^k
5965 	    *                                                           + sum_{a \in A^-} sum_{k \in K} f_a^k - c_a x_a  <=  0
5966 	    */
5967 	
5968 	   deltassize = 16;
5969 	   SCIP_CALL( SCIPallocBufferArray(scip, &deltas, deltassize) );
5970 	   SCIP_CALL( SCIPallocBufferArray(scip, &rowweights, nrows) );
5971 	   SCIP_CALL( SCIPallocBufferArray(scip, &comcutdemands, ncommodities) );
5972 	   SCIP_CALL( SCIPallocBufferArray(scip, &comdemands, ncommodities) );
5973 	   SCIP_CALL( SCIPallocBufferArray(scip, &cutcoefs, nvars) );
5974 	   SCIP_CALL( SCIPallocBufferArray(scip, &cutinds, nvars) );
5975 	
5976 	   /* create empty aggregation row */
5977 	   SCIP_CALL( SCIPaggrRowCreate(scip, &aggrrow) );
5978 	
5979 	   if( nodepartition == NULL )
5980 	   {
5981 	      /* loop over all nodes and generate single-node cuts */
5982 	      startpartition = 0;
5983 	      allpartitions = (unsigned int) nnodes;
5984 	      SCIPdebugMsg(scip, "maxtestdelta: %d, maxsepacuts: %d, nnodes: %d \n", maxtestdelta, maxsepacuts, nnodes);
5985 	   }
5986 	   else
5987 	   {
5988 	      /* loop over all possible partitions of the clusters;
5989 	       * cluster i is in S iff bit i of 'partition' is 1
5990 	       */
5991 	      int nclusters = nodepartition->nclusters;
5992 	
5993 	      assert((unsigned int)nclusters <= 8*sizeof(unsigned int));
5994 	      SCIPdebugMsg(scip, "maxtestdelta: %d, maxsepacuts: %d, nclusters: %d \n", maxtestdelta, maxsepacuts, nclusters);
5995 	
5996 	      /* We fix the last cluster to belong to partition T. In the undirected case, this is sufficient,
5997 	       * because S-T is equivalent to T-S. In the directed case, the loop below is conducted two times,
5998 	       * one with regular S-T and one with inverted partitions.
5999 	       */
6000 	      startpartition = 1;
6001 	      allpartitions = (1 << (nclusters-1)); /*lint !e701*/
6002 	   }
6003 	   useinverted = (mcfnetwork->modeltype == SCIP_MCFMODELTYPE_DIRECTED);
6004 	
6005 	   for( partition = startpartition; partition <= allpartitions-1 && !SCIPisStopped(scip) && *ncuts < maxsepacuts && !*cutoff; partition++ )
6006 	   {
6007 	      int v;
6008 	      int a;
6009 	      int k;
6010 	      int d;
6011 	      int nnodesinS;
6012 	      SCIP_Bool success;
6013 	      /* variables for flowcutset separation */
6014 	      SCIP_Real baserhs;
6015 	      SCIP_Real bestdelta = 1.0;
6016 	      SCIP_Real bestefficacy;
6017 	      SCIP_Real f0;
6018 	
6019 	      if( sepadata->checkcutshoreconnectivity )
6020 	      {
6021 	         if( nodepartition != NULL && !nodepartitionIsConnected(scip, mcfnetwork, nodepartition, partition ) )
6022 	         {
6023 	            /* if S or T are not connected, it is very likely that there is a cut in our cluster partition
6024 	               that gives dominating inequalities
6025 	             */
6026 	            SCIPdebugMsg(scip, "generating cluster cuts for partition 0x%x \n", partition );
6027 	            SCIPdebugMsg(scip, " -> either shore S or shore T is not connected - skip partition.\n");
6028 	            continue;
6029 	         }
6030 	      }
6031 	
6032 	      for( inverted = FALSE; inverted <= useinverted && !*cutoff; inverted++ )
6033 	      {
6034 	         if( nodepartition == NULL )
6035 	         {
6036 	            SCIPdebugMsg(scip, "generating single-node cuts for node %u (inverted: %u)\n", partition, inverted);
6037 	         }
6038 	         else
6039 	         {
6040 	            SCIPdebugMsg(scip, "generating cluster cuts for partition 0x%x (inverted: %u)\n", partition, inverted);
6041 	         }
6042 	
6043 	#ifdef OUTPUTGRAPH
6044 	         SCIP_CALL( outputGraph(scip, mcfnetwork, nodepartition, inverted, partition) );
6045 	#endif
6046 	         /* Check if S and T are connected via union find algorithm.
6047 	          * We do not check this for single node cuts. First, this can be expensive since
6048 	          * in this case the graph still contains all nodes. Second, we may not find a dominating cut,
6049 	          * because we may not have the corresponding dominating node set in our cluster partition.
6050 	         */
6051 	
6052 	         /* clear memory */
6053 	         BMSclearMemoryArray(rowweights, nrows);
6054 	         BMSclearMemoryArray(comcutdemands, ncommodities);
6055 	         BMSclearMemoryArray(comdemands, ncommodities);
6056 	
6057 	         baserhs = 0.0;
6058 	         ndeltas = 0;
6059 	
6060 	         /* Identify commodities with positive T -> S demand */
6061 	         nnodesinS = 0;
6062 	         for( v = 0; v < nnodes; v++ )
6063 	         {
6064 	            /* check if node belongs to S */
6065 	            if( !nodeInPartition(nodepartition, partition, inverted, v) )
6066 	            {
6067 	               /* node does not belong to S */
6068 	               continue;
6069 	            }
6070 	            nnodesinS++;
6071 	            /* update commodity demand */
6072 	            for( k = 0; k < ncommodities; k++ )
6073 	            {
6074 	               SCIP_Real rhs;
6075 	
6076 	               if( nodeflowrows[v][k] == NULL )
6077 	                  continue;
6078 	
6079 	               if( nodeflowscales[v][k] > 0.0 )
6080 	                  rhs = SCIProwGetRhs(nodeflowrows[v][k]) - SCIProwGetConstant(nodeflowrows[v][k]);
6081 	               else
6082 	                  rhs = SCIProwGetLhs(nodeflowrows[v][k]) - SCIProwGetConstant(nodeflowrows[v][k]);
6083 	               if( nodeflowinverted[v][k] )
6084 	                  rhs *= -1.0;
6085 	
6086 	               comcutdemands[k] += rhs * nodeflowscales[v][k];
6087 	            }
6088 	         }
6089 	         assert (1 <= nnodesinS && nnodesinS <= nnodes-1);
6090 	
6091 	         /* ignore cuts with only a single node in S or in T, since these have
6092 	          * already been tried as single node cuts
6093 	          */
6094 	         if( sepadata->separatesinglenodecuts && nodepartition != NULL && (nnodesinS == 1 || nnodesinS == nnodes-1) )
6095 	         {
6096 	            SCIPdebugMsg(scip, " -> shore S or T has only one node - skip partition.\n");
6097 	            break;
6098 	         }
6099 	
6100 	         /* check if there is at least one useful commodity */
6101 	         if( modeltype == SCIP_MCFMODELTYPE_DIRECTED )
6102 	         {
6103 	            for( k = 0; k < ncommodities; k++ )
6104 	            {
6105 	               /* in the directed case, use commodities with positive demand (negative -d_k) */
6106 	               SCIPdebugMsg(scip, " -> commodity %d: directed cutdemand=%g\n", k, comcutdemands[k]);
6107 	               if( SCIPisNegative(scip, comcutdemands[k]) )
6108 	                  break;
6109 	            }
6110 	         }
6111 	         else
6112 	         {
6113 	            for( k = 0; k < ncommodities; k++ )
6114 	            {
6115 	               /* in the undirected case, use commodities with non-zero demand */
6116 	               SCIPdebugMsg(scip, " -> commodity %d: undirected cutdemand=%g\n", k, comcutdemands[k]);
6117 	               if( !SCIPisZero(scip, comcutdemands[k]) )
6118 	                  break;
6119 	            }
6120 	         }
6121 	         if( k == ncommodities )
6122 	            continue;
6123 	
6124 	         /* set weights of capacity rows that go from T to S, i.e., a \in A^- */
6125 	         for( a = 0; a < narcs; a++ )
6126 	         {
6127 	            SCIP_COL** rowcols;
6128 	            SCIP_Real* rowvals;
6129 	            SCIP_Real feasibility;
6130 	            int rowlen;
6131 	            int r;
6132 	            int j;
6133 	
6134 	            assert(arcsources[a] < nnodes);
6135 	            assert(arctargets[a] < nnodes);
6136 	
6137 	            /* check if this is an arc of our cut */
6138 	            if( modeltype == SCIP_MCFMODELTYPE_DIRECTED )
6139 	            {
6140 	               /* in the directed case, check if arc goes from T to S */
6141 	               if( nodeInPartition(nodepartition, partition, inverted, arcsources[a])  ||
6142 	                     !nodeInPartition(nodepartition, partition, inverted, arctargets[a])   )
6143 	               {
6144 	                  /* arc has source in S or target in T */
6145 	                  continue;
6146 	               }
6147 	            }
6148 	            else
6149 	            {
6150 	               /* in the undirected case, check if the arc has endpoints in S and T */
6151 	               if( nodeInPartition(nodepartition, partition, inverted, arcsources[a]) &&
6152 	                     nodeInPartition(nodepartition, partition, inverted, arctargets[a])   )
6153 	               {
6154 	                  /* both endpoints are in S */
6155 	                  continue;
6156 	               }
6157 	               if( !nodeInPartition(nodepartition, partition, inverted, arcsources[a]) &&
6158 	                     !nodeInPartition(nodepartition, partition, inverted, arctargets[a])   )
6159 	               {
6160 	                  /* both endpoints are in T */
6161 	                  continue;
6162 	               }
6163 	            }
6164 	
6165 	            /* arc might be uncapacitated */
6166 	            if( arccapacityrows[a] == NULL )
6167 	               continue;
6168 	
6169 	            /* use capacity row in c-MIR cut */
6170 	            r = SCIProwGetLPPos(arccapacityrows[a]);
6171 	            assert(r < nrows);
6172 	            if( r == -1 ) /* row might have been removed from LP in the meantime */
6173 	               continue;
6174 	            assert(rowweights[r] == 0.0);
6175 	
6176 	            /* if one of the arc nodes is unknown, we only use the capacity row if it does not have slack,
6177 	             * otherwise, we discard it if the slack is too large
6178 	             */
6179 	            feasibility = SCIPgetRowSolFeasibility(scip, arccapacityrows[a], sol);
6180 	            if( arcsources[a] == -1 || arctargets[a] == -1 )
6181 	            {
6182 	               if( SCIPisFeasPositive(scip, feasibility) )
6183 	                  continue;
6184 	            }
6185 	            else
6186 	            {
6187 	               SCIP_Real maxcoef;
6188 	
6189 	               maxcoef = SCIPgetRowMaxCoef(scip, arccapacityrows[a]);
6190 	               assert(maxcoef > 0.0);
6191 	               if( SCIPisFeasGT(scip, feasibility/maxcoef, MAXCAPACITYSLACK) )
6192 	                  continue;
6193 	            }
6194 	
6195 	            rowweights[r] = arccapacityscales[a];
6196 	            SCIPdebugMsg(scip, " -> arc %d, r=%d, capacity row <%s>: weight=%g slack=%g dual=%g\n", a, r, SCIProwGetName(arccapacityrows[a]), rowweights[r],
6197 	                             SCIPgetRowFeasibility(scip, arccapacityrows[a]), SCIProwGetDualsol(arccapacityrows[a]));
6198 	            /*SCIPdebug( SCIP_CALL(SCIPprintRow(scip, arccapacityrows[a], NULL)) );*/
6199 	
6200 	            if( sepadata->separateflowcutset )
6201 	            {
6202 	               if( rowweights[r] > 0.0 )
6203 	                  baserhs += rowweights[r] * (SCIProwGetRhs(arccapacityrows[a]) - SCIProwGetConstant(arccapacityrows[a]));
6204 	               else
6205 	                  baserhs += rowweights[r] * (SCIProwGetLhs(arccapacityrows[a]) - SCIProwGetConstant(arccapacityrows[a]));
6206 	            }
6207 	
6208 	            /* extract useful deltas for c-MIR scaling and update the demand value for commodities (in binary flow model) */
6209 	            rowcols = SCIProwGetCols(arccapacityrows[a]);
6210 	            rowvals = SCIProwGetVals(arccapacityrows[a]);
6211 	            rowlen = SCIProwGetNLPNonz(arccapacityrows[a]);
6212 	            for( j = 0; j < rowlen; j++ )
6213 	            {
6214 	               SCIP_Real coef;
6215 	               int c;
6216 	
6217 	               coef = rowvals[j] * arccapacityscales[a];
6218 	               coef = ABS(coef);
6219 	
6220 	               /* update commodity demands */
6221 	               c = SCIPcolGetLPPos(rowcols[j]);
6222 	               assert(0 <= c && c < SCIPgetNLPCols(scip));
6223 	               k = colcommodity[c];
6224 	               if( k >= 0 )
6225 	                  comdemands[k] = coef;
6226 	
6227 	               /* insert coefficients of integer variables into deltas array */
6228 	               /* coefficients should not be too small and not be too big */
6229 	               if( !SCIPisZero(scip, 1.0 / coef) && !SCIPisFeasZero(scip, coef) && SCIPcolIsIntegral(rowcols[j]) )
6230 	               {
6231 	                  SCIP_Bool exists;
6232 	                  int left;
6233 	                  int right;
6234 	
6235 	                  /* binary search if we already know this coefficient */
6236 	                  exists = FALSE;
6237 	                  left = 0;
6238 	                  right = ndeltas-1;
6239 	                  while( left <= right )
6240 	                  {
6241 	                     int mid = (left+right)/2;
6242 	                     /* take deltas that are not too close */
6243 	                     if( REALABS( deltas[mid] / coef - 1.0 ) <  1e-03 ) /*lint !e771*/
6244 	                     {
6245 	                        exists = TRUE;
6246 	                        break;
6247 	                     }
6248 	                     else if( coef < deltas[mid] )
6249 	                        right = mid-1;
6250 	                     else
6251 	                        left = mid+1;
6252 	                  }
6253 	
6254 	                  /* insert new candidate value */
6255 	                  if( !exists )
6256 	                  {
6257 	                     assert(right == left-1);
6258 	                     assert(ndeltas <= deltassize);
6259 	                     if( ndeltas == deltassize )
6260 	                     {
6261 	                        deltassize *= 2;
6262 	                        SCIP_CALL( SCIPreallocBufferArray(scip, &deltas, deltassize) );
6263 	                     }
6264 	                     if( left < ndeltas )
6265 	                     {
6266 	                        for( d = ndeltas; d > left; d-- )
6267 	                           deltas[d] = deltas[d-1];
6268 	                     }
6269 	                     deltas[left] = coef;
6270 	                     ndeltas++;
6271 	                     SCIPdebugMsg(scip, " -> new capacity %g considered as delta\n", coef);
6272 	                  }
6273 	               }
6274 	            }
6275 	         }
6276 	
6277 	         /* set weights of node flow conservation constraints in c-MIR aggregation */
6278 	         for( v = 0; v < nnodes; v++ )
6279 	         {
6280 	            /* aggregate flow conservation constraints of the 'active' commodities */
6281 	            for( k = 0; k < ncommodities; k++ )
6282 	            {
6283 	               SCIP_Real scale;
6284 	               int r;
6285 	
6286 	               /* if commodity was not hit by the capacity constraints of the cut in the graph, ignore the commodity */
6287 	               if( comdemands[k] == 0.0 )
6288 	                  continue;
6289 	
6290 	               scale = comdemands[k];
6291 	               if( modeltype == SCIP_MCFMODELTYPE_DIRECTED )
6292 	               {
6293 	                  /* in the directed case, use rows of commodities with positive demand (negative -d_k) */
6294 	                  if( !SCIPisNegative(scip, comcutdemands[k]) )
6295 	                     continue;
6296 	
6297 	                  /* check if node belongs to S */
6298 	                  if( !nodeInPartition(nodepartition, partition, inverted, v) )
6299 	                  {
6300 	                     /* node belongs to T */
6301 	                     continue;
6302 	                  }
6303 	               }
6304 	               else
6305 	               {
6306 	                  /* in the undirected case, use rows of commodities with non-zero demand */
6307 	                  if( SCIPisZero(scip, comcutdemands[k]) )
6308 	                     continue;
6309 	
6310 	                  /* If the demand (-d_k) is negative (i.e., points into the wrong direction), we use the flow
6311 	                   * in the opposite direction, i.e., sum over all nodes in T instead of S.
6312 	                   */
6313 	                  if( comcutdemands[k] > 0.0 )
6314 	                  {
6315 	                     /* check if node belongs to T */
6316 	                     if( nodeInPartition(nodepartition, partition, inverted, v) )
6317 	                     {
6318 	                        /* node belongs to S */
6319 	                        continue;
6320 	                     }
6321 	                  }
6322 	                  else
6323 	                  {
6324 	                     /* check if node belongs to S */
6325 	                     if( !nodeInPartition(nodepartition, partition, inverted, v) )
6326 	                     {
6327 	                        /* node belongs to T */
6328 	                        continue;
6329 	                     }
6330 	                  }
6331 	               }
6332 	               if( nodeflowrows[v][k] == NULL )
6333 	                  continue;
6334 	
6335 	               r = SCIProwGetLPPos(nodeflowrows[v][k]);
6336 	               assert(r < nrows);
6337 	               if( r >= 0 ) /* row might have been removed from LP in the meantime */
6338 	               {
6339 	                  SCIP_Real feasibility;
6340 	
6341 	                  assert(rowweights[r] == 0.0);
6342 	
6343 	                  /* ignore rows with slack */
6344 	                  feasibility = SCIPgetRowSolFeasibility(scip, nodeflowrows[v][k], sol);
6345 	                  if( !SCIPisFeasPositive(scip, feasibility) )
6346 	                  {
6347 	                     rowweights[r] = scale * nodeflowscales[v][k];
6348 	                     if( nodeflowinverted[v][k] )
6349 	                        rowweights[r] *= -1.0;
6350 	                     SCIPdebugMsg(scip, " -> node %d, commodity %d, r=%d, flow row <%s>: scale=%g weight=%g slack=%g dual=%g\n",
6351 	                                      v, k, r, SCIProwGetName(nodeflowrows[v][k]), scale, rowweights[r],
6352 	                                      SCIPgetRowFeasibility(scip, nodeflowrows[v][k]), SCIProwGetDualsol(nodeflowrows[v][k]));
6353 	                     /*SCIPdebug( SCIP_CALL(SCIPprintRow(scip, nodeflowrows[v][k], NULL)) );*/
6354 	                     if( sepadata->separateflowcutset )
6355 	                     {
6356 	                        if( nodeflowscales[v][k] > 0.0 )
6357 	                           baserhs += rowweights[r] * (SCIProwGetRhs(nodeflowrows[v][k]) - SCIProwGetConstant(nodeflowrows[v][k]));
6358 	                        else
6359 	                           baserhs += rowweights[r] * (SCIProwGetLhs(nodeflowrows[v][k]) - SCIProwGetConstant(nodeflowrows[v][k]));
6360 	                     }
6361 	                  }
6362 	               }
6363 	            }
6364 	         }
6365 	
6366 	         /* try out deltas to generate c-MIR cuts: use larger deltas first */
6367 	         /** @todo use only the best delta instead of generating all cuts ?? */
6368 	
6369 	         /* use best delta for flowcutset separation */
6370 	         bestefficacy = SCIP_REAL_MIN;
6371 	
6372 	         if( sepadata->separateflowcutset )
6373 	         {
6374 	            if( ndeltas > 0 )
6375 	               bestdelta = deltas[ndeltas-1];  /* if nothing else is found, use maxdelta */
6376 	         }
6377 	
6378 	         oldncuts = *ncuts; /* save number of cuts */
6379 	
6380 	         SCIP_CALL( SCIPaggrRowSumRows(scip, aggrrow, rowweights, NULL, -1,
6381 	               FALSE, allowlocal, 2, (int)MAXAGGRLEN(nvars), &success) );
6382 	
6383 	         if( success )
6384 	         {
6385 	            SCIPdebugMsg(scip, " -> found %d different deltas to try\n", ndeltas);
6386 	            for( d = ndeltas-1; d >= 0 && d >= ndeltas-maxtestdelta; d-- )
6387 	            {
6388 	               SCIP_Real cutrhs = 0.0;
6389 	               SCIP_Real cutefficacy = 0.0;
6390 	               SCIP_Bool cutislocal = FALSE;
6391 	               /* variables for flowcutset separation */
6392 	               int cutrank;
6393 	               int cutnnz;
6394 	
6395 	               /* we should not have too small deltas */
6396 	               assert( !SCIPisFeasZero(scip, deltas[d]) );
6397 	               /* we should not have too large deltas */
6398 	               assert( !SCIPisZero(scip, 1.0/deltas[d]) );
6399 	
6400 	               SCIPdebugMsg(scip, "applying MIR with delta = %g\n", deltas[d]);
6401 	               SCIP_CALL( SCIPcalcMIR(scip, sol, POSTPROCESS, BOUNDSWITCH, USEVBDS, allowlocal, sepadata->fixintegralrhs, NULL, NULL, MINFRAC, MAXFRAC,
6402 	                     1.0/deltas[d], aggrrow, cutcoefs, &cutrhs, cutinds, &cutnnz, &cutefficacy, &cutrank, &cutislocal, &success) );
6403 	               assert(allowlocal || !cutislocal);
6404 	
6405 	               /* // no success means row was too long or empty, there is a free
6406 	                *   // variable or for numerical reasons, it does not mean that the
6407 	                *   // cMIR cut was not violated */
6408 	               if( ! success )
6409 	                  continue;
6410 	
6411 	               if( sepadata->separateflowcutset )
6412 	               {
6413 	                  if( cutefficacy > bestefficacy )
6414 	                  {
6415 	                     bestdelta = deltas[d];
6416 	                     bestefficacy = cutefficacy;
6417 	                  }
6418 	               }
6419 	
6420 	               if( SCIPisEfficacious(scip, cutefficacy) )
6421 	               {
6422 	                  SCIPdebugMsg(scip, "success -> delta = %g  -> rhs: %g, efficacy: %g\n", deltas[d], cutrhs, cutefficacy);
6423 	                  SCIP_CALL( addCut(scip, sepa, sepadata, sol, cutcoefs, cutrhs, cutinds, cutnnz, cutislocal, cutrank, ncuts, cutoff) );
6424 	                  if( *cutoff )
6425 	                     break;
6426 	
6427 	#ifdef SCIP_DEBUG
6428 	                  for( a = 0; a < narcs; a++ )
6429 	                  {
6430 	                     if( arccapacityrows[a] != NULL )
6431 	                     {
6432 	                        int r;
6433 	
6434 	                        r = SCIProwGetLPPos(arccapacityrows[a]);
6435 	                        assert(r < nrows);
6436 	                        if( r >= 0 && rowweights[r] != 0.0 )
6437 	                        {
6438 	                           MCFdebugMessage(" -> arc %d, capacity row <%s>: weight=%g slack=%g prod=%g dual=%g\n", a,
6439 	                                 SCIProwGetName(arccapacityrows[a]), rowweights[r],
6440 	                                 SCIPgetRowFeasibility(scip, arccapacityrows[a]),
6441 	                                 SCIPgetRowFeasibility(scip, arccapacityrows[a]) * arccapacityscales[a], SCIProwGetDualsol(arccapacityrows[a]));
6442 	                        }
6443 	                     }
6444 	                  }
6445 	#endif
6446 	               }
6447 	            }
6448 	         }
6449 	
6450 	         /* only separate flowcutset inequalities if no cutset inequalities have been found */
6451 	         if( sepadata->separateflowcutset && oldncuts == *ncuts && !*cutoff )
6452 	         {
6453 	            /* try to separate flow cuts for the best delta */
6454 	            f0 = SCIPfrac(scip, baserhs/bestdelta);
6455 	            if( MINFRAC <= f0 && f0 <= MAXFRAC )
6456 	            {
6457 	               SCIP_Real onedivoneminsf0;
6458 	               SCIP_Real totalviolationdelta;
6459 	               totalviolationdelta = 0.0;
6460 	               onedivoneminsf0 = 1.0/(1.0 - f0);
6461 	               for( a = 0; a < narcs; a++ )
6462 	               {
6463 	                  SCIP_COL** rowcols;
6464 	                  SCIP_Real* rowvals;
6465 	                  int rowlen;
6466 	                  SCIP_Real rowweight;
6467 	                  SCIP_Real rowlhs;
6468 	                  SCIP_Real rowrhs;
6469 	                  SCIP_Real rowconstant;
6470 	                  SCIP_Real violationdelta;
6471 	                  int r;
6472 	                  int j;
6473 	
6474 	                  /* arc might be uncapacitated */
6475 	                  if( arccapacityrows[a] == NULL )
6476 	                     continue;
6477 	
6478 	                  r = SCIProwGetLPPos(arccapacityrows[a]);
6479 	
6480 	                  /* row might have been removed from LP in the meantime */
6481 	                  assert(r < nrows);
6482 	                  if( r == -1 )
6483 	                     continue;
6484 	
6485 	                  /* ignore rows that are not in the aggregation */
6486 	                  if( rowweights[r] == 0.0 )
6487 	                     continue;
6488 	
6489 	                  /* check if removing the capacity inequality will lead to a more violated MIR inequality:
6490 	                   * in a "perfect" MCF model, adding the capacity constraints means to cancel the flow
6491 	                   * variables of the capacity constraints and instead to add the capacity variables.
6492 	                   * Thus, removing it means to add the flow variables (with negative sign) and to remove
6493 	                   * the capacity variables.
6494 	                   * We assume that the right hand side of the scaled capacity inequality is integral (usually 0)
6495 	                   * and thus, the fractionality of the rhs of the base inequality does not change, hence the
6496 	                   * cut coefficients of all other involved variables do not change.
6497 	                   */
6498 	                  rowcols = SCIProwGetCols(arccapacityrows[a]);
6499 	                  rowvals = SCIProwGetVals(arccapacityrows[a]);
6500 	                  rowlen = SCIProwGetNLPNonz(arccapacityrows[a]);
6501 	                  rowweight = rowweights[r]/bestdelta;
6502 	                  rowlhs = SCIProwGetLhs(arccapacityrows[a]);
6503 	                  rowrhs = SCIProwGetRhs(arccapacityrows[a]);
6504 	                  rowconstant = SCIProwGetConstant(arccapacityrows[a]);
6505 	                  if( SCIPisInfinity(scip, rowrhs) || (!SCIPisInfinity(scip, -rowlhs) && rowweight < 0.0) )
6506 	                     violationdelta = rowweight * (rowlhs - rowconstant);
6507 	                  else
6508 	                     violationdelta = rowweight * (rowrhs - rowconstant);
6509 	
6510 	                  for( j = 0; j < rowlen; j++ )
6511 	                  {
6512 	                     SCIP_VAR* var;
6513 	                     SCIP_Real coef;
6514 	                     SCIP_Real mircoef;
6515 	                     SCIP_Real solval;
6516 	                     int c;
6517 	
6518 	                     coef = rowvals[j] * rowweight;
6519 	
6520 	                     c = SCIPcolGetLPPos(rowcols[j]);
6521 	                     assert(0 <= c && c < SCIPgetNLPCols(scip));
6522 	                     var = SCIPcolGetVar(rowcols[j]);
6523 	
6524 	                     /* variable is flow variable: if we are not using the capacity constraint, this
6525 	                      *   would appear with negative coefficient in the base inequality instead of being canceled.
6526 	                      * variable is capacity variable: if we are not using the capacity constraint, this
6527 	                      *   would not appear in the base inequality.
6528 	                      */
6529 	                     if( colcommodity[c] >= 0 )
6530 	                        coef *= -1.0;
6531 	
6532 	                     if( SCIPvarIsIntegral(var) )
6533 	                     {
6534 	                        SCIP_Real fj;
6535 	
6536 	                        fj = SCIPfrac(scip, coef);
6537 	                        if( fj <= f0 )
6538 	                           mircoef = SCIPfloor(scip, coef);
6539 	                        else
6540 	                           mircoef = SCIPfloor(scip, coef) + (fj - f0)*onedivoneminsf0;
6541 	                     }
6542 	                     else
6543 	                     {
6544 	                        if( coef >= 0.0 )
6545 	                           mircoef = 0.0;
6546 	                        else
6547 	                           mircoef = coef * onedivoneminsf0;
6548 	                     }
6549 	
6550 	                     /* add flow variable MIR coefficients, and subtract capacity variable MIR coefficients */
6551 	                     solval = SCIPgetSolVal(scip, sol, var);
6552 	                     if( colcommodity[c] >= 0 )
6553 	                        violationdelta += mircoef * solval;
6554 	                     else
6555 	                        violationdelta -= mircoef * solval;
6556 	                  }
6557 	
6558 	                  if( SCIPisPositive(scip, violationdelta) )
6559 	                  {
6560 	                     SCIPdebugMsg(scip, " -> discarding capacity row <%s> of weight %g and slack %g: increases MIR violation by %g\n",
6561 	                                      SCIProwGetName(arccapacityrows[a]), rowweights[r], SCIPgetRowFeasibility(scip, arccapacityrows[a]),
6562 	                                      violationdelta);
6563 	                     rowweights[r] = 0.0;
6564 	                     totalviolationdelta += violationdelta;
6565 	                  }
6566 	               }
6567 	
6568 	               /* if we removed a capacity constraint from the aggregation, try the new aggregation */
6569 	               if( totalviolationdelta > 0.0 )
6570 	               {
6571 	                  SCIP_Real cutrhs;
6572 	                  SCIP_Real cutefficacy = 0.0;
6573 	                  SCIP_Bool cutislocal;
6574 	                  int cutnnz;
6575 	                  int cutrank;
6576 	
6577 	                  /* we should not have too small deltas */
6578 	                  assert( !SCIPisFeasZero(scip, bestdelta) );
6579 	                  /* we should not have too large deltas */
6580 	                  assert( !SCIPisZero(scip, 1.0/bestdelta) );
6581 	
6582 	                  SCIPdebugMsg(scip, "applying MIR with delta = %g to flowcut inequality (violation improvement: %g)\n", bestdelta, totalviolationdelta);
6583 	
6584 	                  SCIP_CALL( SCIPaggrRowSumRows(scip, aggrrow, rowweights, NULL, -1,
6585 	                     FALSE, allowlocal, 2, (int)MAXAGGRLEN(nvars), &success) );
6586 	
6587 	                  if( success )
6588 	                  {
6589 	                     SCIP_CALL( SCIPcalcMIR(scip, sol, POSTPROCESS, BOUNDSWITCH, USEVBDS, allowlocal, sepadata->fixintegralrhs, NULL, NULL, MINFRAC, MAXFRAC,
6590 	                                            1.0/bestdelta, aggrrow, cutcoefs, &cutrhs, cutinds, &cutnnz, &cutefficacy, &cutrank, &cutislocal, &success) );
6591 	
6592 	                     assert(allowlocal || !cutislocal);
6593 	
6594 	                     if( success && SCIPisEfficacious(scip, cutefficacy) )
6595 	                     {
6596 	                        SCIPdebugMsg(scip, " -> delta = %g  -> rhs: %g, efficacy: %g\n", bestdelta, cutrhs, cutefficacy);
6597 	                        SCIP_CALL( addCut(scip, sepa, sepadata, sol, cutcoefs, cutrhs, cutinds, cutnnz, cutislocal, cutrank, ncuts, cutoff) );
6598 	                     }
6599 	                  }
6600 	               }
6601 	            }
6602 	         }
6603 	      }
6604 	   }
6605 	
6606 	   /* free local memory */
6607 	   SCIPaggrRowFree(scip, &aggrrow);
6608 	   SCIPfreeBufferArray(scip, &cutinds);
6609 	   SCIPfreeBufferArray(scip, &cutcoefs);
6610 	   SCIPfreeBufferArray(scip, &comdemands);
6611 	   SCIPfreeBufferArray(scip, &comcutdemands);
6612 	   SCIPfreeBufferArray(scip, &rowweights);
6613 	   SCIPfreeBufferArray(scip, &deltas);
6614 	
6615 	   return SCIP_OKAY;
6616 	}
6617 	
6618 	/** searches and adds MCF network cuts that separate the given primal solution */
6619 	static
6620 	SCIP_RETCODE separateCuts(
6621 	   SCIP*                 scip,               /**< SCIP data structure */
6622 	   SCIP_SEPA*            sepa,               /**< the cut separator itself */
6623 	   SCIP_SOL*             sol,                /**< primal solution that should be separated, or NULL for LP solution */
6624 	   SCIP_Bool             allowlocal,         /**< should local cuts be allowed */
6625 	   int                   depth,              /**< current depth */
6626 	   SCIP_RESULT*          result              /**< pointer to store the result of the separation call */
6627 	   )
6628 	{
6629 	   /*lint --e{715}*/
6630 	   SCIP_SEPADATA* sepadata;
6631 	   SCIP_MCFNETWORK** mcfnetworks;
6632 	   int nmcfnetworks;
6633 	   int ncuts;
6634 	   int ncols;
6635 	   int nrows;
6636 	   int nvars;
6637 	   SCIP_Real colrowratio;
6638 	   int i;
6639 	   SCIP_Bool cutoff;
6640 	
6641 	   assert(result != NULL);
6642 	   assert(*result == SCIP_DIDNOTRUN);
6643 	
6644 	   ncuts = 0;
6645 	   cutoff = FALSE;
6646 	
6647 	   /* check for number of columns, number of variables, column/row ratio */
6648 	   nrows = SCIPgetNLPRows(scip);
6649 	   ncols = SCIPgetNLPCols(scip);
6650 	   nvars = SCIPgetNVars(scip);
6651 	
6652 	   /* exit if not all variables are in the LP (e.g. dynamic columns) */
6653 	   /* Notice that in principle we should have most of the columns in the LP to be able to detect a structure */
6654 	   if( ncols != nvars )
6655 	   {
6656 	      MCFdebugMessage("%d variables but %d columns -> exit\n", nvars, ncols );
6657 	
6658 	      return SCIP_OKAY;
6659 	   }
6660 	
6661 	   /* exit if number of columns is too large (expensive detection) */
6662 	   if( ncols > MAXCOLS )
6663 	   {
6664 	      MCFdebugMessage("%d > %d columns -> exit\n", ncols, MAXCOLS );
6665 	
6666 	      return SCIP_OKAY;
6667 	   }
6668 	
6669 	   colrowratio = (SCIP_Real)ncols/(nrows+1e-9);
6670 	
6671 	   /* get separator data */
6672 	   sepadata = SCIPsepaGetData(sepa);
6673 	   assert(sepadata != NULL);
6674 	
6675 	   /* if separation was not delayed before and we had no success in previous round then delay the separation*/
6676 	   if( !SCIPsepaWasLPDelayed(sepa) && !sepadata->lastroundsuccess )
6677 	   {
6678 	      *result = SCIP_DELAYED;
6679 	      return SCIP_OKAY;
6680 	   }
6681 	
6682 	   if( colrowratio < MINCOLROWRATIO || colrowratio > MAXCOLROWRATIO )
6683 	   {
6684 	      MCFdebugMessage("%d columns, %d rows, ratio %g is not in [%g,%g] -> exit\n", ncols, nrows, colrowratio, MINCOLROWRATIO, MAXCOLROWRATIO);
6685 	
6686 	      return SCIP_OKAY;
6687 	   }
6688 	
6689 	   /* ######################## NETWORK DETECTION ##################################### */
6690 	   /* get or extract network flow structure */
6691 	   if( sepadata->nmcfnetworks == -1 )
6692 	   {
6693 	      *result = SCIP_DIDNOTFIND;
6694 	
6695 	      SCIP_CALL( mcfnetworkExtract(scip, sepadata, &sepadata->mcfnetworks, &sepadata->nmcfnetworks, &sepadata->effortlevel) );
6696 	
6697 	      MCFdebugMessage("extracted %d networks\n", sepadata->nmcfnetworks);
6698 	
6699 	      for( i = 0; i < sepadata->nmcfnetworks; i++ )
6700 	      {
6701 	         MCFdebugMessage(" -> extracted network %d has %d nodes, %d (%d) arcs (uncapacitated), and %d commodities (modeltype: %s)\n",
6702 	                         i, sepadata->mcfnetworks[i]->nnodes, sepadata->mcfnetworks[i]->narcs, sepadata->mcfnetworks[i]->nuncapacitatedarcs,
6703 	                         sepadata->mcfnetworks[i]->ncommodities,
6704 	                         sepadata->mcfnetworks[i]->modeltype == SCIP_MCFMODELTYPE_DIRECTED ? "directed" : "undirected");
6705 	         SCIPdebug( mcfnetworkPrint(sepadata->mcfnetworks[i]) );
6706 	      }
6707 	
6708 	#ifdef COUNTNETWORKVARIABLETYPES
6709 	      SCIP_CALL( printFlowSystemInfo(scip,sepadata->mcfnetworks,sepadata->nmcfnetworks));
6710 	
6711 	#endif
6712 	   }
6713 	   assert(sepadata->nmcfnetworks >= 0);
6714 	   assert(sepadata->mcfnetworks != NULL || sepadata->nmcfnetworks == 0);
6715 	   mcfnetworks = sepadata->mcfnetworks;
6716 	   nmcfnetworks = sepadata->nmcfnetworks;
6717 	
6718 	   /* ######################## SEPARATION ##################################### */
6719 	   if( nmcfnetworks > 0 && sepadata->effortlevel != MCFEFFORTLEVEL_OFF )
6720 	   {
6721 	      /* separate cuts */
6722 	      *result = SCIP_DIDNOTFIND;
6723 	      sepadata->lastroundsuccess = FALSE;
6724 	
6725 	      for( i = 0; i < nmcfnetworks && !cutoff; i++ )
6726 	      {
6727 	         SCIP_MCFNETWORK* mcfnetwork;
6728 	         NODEPARTITION* nodepartition;
6729 	         SCIP_Real arcnoderatio;
6730 	
6731 	         mcfnetwork = mcfnetworks[i];
6732 	
6733 	         /* if the network does not have at least 2 nodes and 1 arc, we did not create it */
6734 	         assert(mcfnetwork->nnodes >= 2);
6735 	         assert(mcfnetwork->narcs >= 1);
6736 	
6737 	         arcnoderatio = (SCIP_Real)mcfnetwork->narcs / (SCIP_Real)mcfnetwork->nnodes;
6738 	
6739 	         /* do not allow networks exceeding the arcs/nodes ratio ( = average node degree / 2 (directed)) */
6740 	         if( arcnoderatio > MAXARCNODERATIO )
6741 	         {
6742 	            MCFdebugMessage("MCF network has %d nodes and %d arcs. arc node ratio %.2f exceed --> exit\n",
6743 	                            mcfnetwork->nnodes, mcfnetwork->narcs, MAXARCNODERATIO);
6744 	            continue;
6745 	         }
6746 	
6747 	         /* enumerate single node cuts */
6748 	         if( sepadata->separatesinglenodecuts )
6749 	         {
6750 	            SCIP_CALL( generateClusterCuts(scip, sepa, sepadata, sol, allowlocal, depth, mcfnetwork, NULL, &ncuts, &cutoff) );
6751 	         }
6752 	
6753 	         if( !cutoff )
6754 	         {
6755 	            /* partition nodes into a small number of clusters */
6756 	            SCIP_CALL( nodepartitionCreate(scip, mcfnetwork, &nodepartition,
6757 	                  sepadata->effortlevel == MCFEFFORTLEVEL_DEFAULT ? sepadata->nclusters : 2 * sepadata->nclusters) );
6758 	#ifdef SCIP_DEBUG
6759 	            nodepartitionPrint(nodepartition);
6760 	#endif
6761 	
6762 	            /* enumerate cuts between subsets of the clusters */
6763 	            SCIP_CALL( generateClusterCuts(scip, sepa, sepadata, sol, allowlocal, depth, mcfnetwork, nodepartition, &ncuts, &cutoff) );
6764 	
6765 	            /* free node partition */
6766 	            nodepartitionFree(scip, &nodepartition);
6767 	         }
6768 	
6769 	         MCFdebugMessage("MCF network has %d nodes, %d arcs, %d commodities. Found %d MCF network cuts, cutoff = %u.\n",
6770 	                         mcfnetwork->nnodes, mcfnetwork->narcs, mcfnetwork->ncommodities, ncuts, cutoff);
6771 	
6772 	         /* adjust result code */
6773 	         if( cutoff )
6774 	         {
6775 	            *result = SCIP_CUTOFF;
6776 	            sepadata->lastroundsuccess = TRUE;
6777 	         }
6778 	         else if( ncuts > 0 )
6779 	         {
6780 	            *result = SCIP_SEPARATED;
6781 	            sepadata->lastroundsuccess = TRUE;
6782 	         }
6783 	      }
6784 	   }
6785 	
6786 	   return SCIP_OKAY;
6787 	}
6788 	
6789 	
6790 	/*
6791 	 * Callback methods of separator
6792 	 */
6793 	
6794 	/** copy method for separator plugins (called when SCIP copies plugins) */
6795 	static
6796 	SCIP_DECL_SEPACOPY(sepaCopyMcf)
6797 	{  /*lint --e{715}*/
6798 	   assert(scip != NULL);
6799 	   assert(sepa != NULL);
6800 	   assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0);
6801 	
6802 	   /* call inclusion method of constraint handler */
6803 	   SCIP_CALL( SCIPincludeSepaMcf(scip) );
6804 	
6805 	   return SCIP_OKAY;
6806 	}
6807 	
6808 	/** destructor of separator to free user data (called when SCIP is exiting) */
6809 	static
6810 	SCIP_DECL_SEPAFREE(sepaFreeMcf)
6811 	{
6812 	   /*lint --e{715}*/
6813 	   SCIP_SEPADATA* sepadata;
6814 	
6815 	   /* free separator data */
6816 	   sepadata = SCIPsepaGetData(sepa);
6817 	   assert(sepadata != NULL);
6818 	   assert(sepadata->mcfnetworks == NULL);
6819 	   assert(sepadata->nmcfnetworks == -1);
6820 	
6821 	   SCIPfreeMemory(scip, &sepadata);
6822 	
6823 	   SCIPsepaSetData(sepa, NULL);
6824 	
6825 	   return SCIP_OKAY;
6826 	}
6827 	
6828 	/** solving process initialization method of separator (called when branch and bound process is about to begin) */
6829 	static
6830 	SCIP_DECL_SEPAINITSOL(sepaInitsolMcf)
6831 	{
6832 	   /*lint --e{715}*/
6833 	   SCIP_SEPADATA* sepadata;
6834 	
6835 	   /* get separator data */
6836 	   sepadata = SCIPsepaGetData(sepa);
6837 	   assert(sepadata != NULL);
6838 	
6839 	   sepadata->lastroundsuccess = TRUE;
6840 	   sepadata->effortlevel = MCFEFFORTLEVEL_OFF;
6841 	
6842 	   return SCIP_OKAY;
6843 	}
6844 	
6845 	
6846 	/** solving process deinitialization method of separator (called before branch and bound process data is freed) */
6847 	static
6848 	SCIP_DECL_SEPAEXITSOL(sepaExitsolMcf)
6849 	{
6850 	   /*lint --e{715}*/
6851 	   SCIP_SEPADATA* sepadata;
6852 	   int i;
6853 	
6854 	   /* get separator data */
6855 	   sepadata = SCIPsepaGetData(sepa);
6856 	   assert(sepadata != NULL);
6857 	
6858 	   /* free MCF networks */
6859 	   for( i = 0; i < sepadata->nmcfnetworks; i++ )
6860 	   {
6861 	      SCIP_CALL( mcfnetworkFree(scip, &sepadata->mcfnetworks[i]) );
6862 	   }
6863 	   SCIPfreeMemoryArrayNull(scip, &sepadata->mcfnetworks);
6864 	   sepadata->nmcfnetworks = -1;
6865 	
6866 	   return SCIP_OKAY;
6867 	}
6868 	
6869 	
6870 	/** LP solution separation method of separator */
6871 	static
6872 	SCIP_DECL_SEPAEXECLP(sepaExeclpMcf)
6873 	{
6874 	   /*lint --e{715}*/
6875 	
6876 	   *result = SCIP_DIDNOTRUN;
6877 	
6878 	   /* only call separator, if we are not close to terminating */
6879 	   if( SCIPisStopped(scip) )
6880 	      return SCIP_OKAY;
6881 	
6882 	   /* only call separator, if an optimal LP solution is at hand */
6883 	   if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL )
6884 	      return SCIP_OKAY;
6885 	
6886 	   /* only call separator, if there are fractional variables */
6887 	   if( SCIPgetNLPBranchCands(scip) == 0 )
6888 	      return SCIP_OKAY;
6889 	
6890 	   /* separate cuts on the LP solution */
6891 	   SCIP_CALL( separateCuts(scip, sepa, NULL, allowlocal, depth, result) );
6892 	
6893 	   return SCIP_OKAY;
6894 	}
6895 	
6896 	
6897 	/** arbitrary primal solution separation method of separator */
6898 	static
6899 	SCIP_DECL_SEPAEXECSOL(sepaExecsolMcf)
6900 	{
6901 	   /*lint --e{715}*/
6902 	
6903 	   *result = SCIP_DIDNOTRUN;
6904 	
6905 	   /* separate cuts on the given primal solution */
6906 	   SCIP_CALL( separateCuts(scip, sepa, sol, allowlocal, depth, result) );
6907 	
6908 	   return SCIP_OKAY;
6909 	}
6910 	
6911 	
6912 	/*
6913 	 * separator specific interface methods
6914 	 */
6915 	
6916 	/** creates the mcf separator and includes it in SCIP */
6917 	SCIP_RETCODE SCIPincludeSepaMcf(
6918 	   SCIP*                 scip                /**< SCIP data structure */
6919 	   )
6920 	{
6921 	   SCIP_SEPADATA* sepadata;
6922 	   SCIP_SEPA* sepa;
6923 	
6924 	   /* create mcf separator data */
6925 	   SCIP_CALL( SCIPallocMemory(scip, &sepadata) );
6926 	   sepadata->mcfnetworks = NULL;
6927 	   sepadata->nmcfnetworks = -1;
6928 	
6929 	   sepadata->lastroundsuccess = TRUE;
6930 	   sepadata->effortlevel = MCFEFFORTLEVEL_OFF;
6931 	
6932 	   /* include separator */
6933 	   SCIP_CALL( SCIPincludeSepaBasic(scip, &sepa, SEPA_NAME, SEPA_DESC, SEPA_PRIORITY, SEPA_FREQ, SEPA_MAXBOUNDDIST,
6934 	         SEPA_USESSUBSCIP, SEPA_DELAY,
6935 	         sepaExeclpMcf, sepaExecsolMcf,
6936 	         sepadata) );
6937 	
6938 	   assert(sepa != NULL);
6939 	
6940 	   /* set non-NULL pointers to callback methods */
6941 	   SCIP_CALL( SCIPsetSepaCopy(scip, sepa, sepaCopyMcf) );
6942 	   SCIP_CALL( SCIPsetSepaFree(scip, sepa, sepaFreeMcf) );
6943 	   SCIP_CALL( SCIPsetSepaInitsol(scip, sepa, sepaInitsolMcf) );
6944 	   SCIP_CALL( SCIPsetSepaExitsol(scip, sepa, sepaExitsolMcf) );
6945 	
6946 	   /** @todo introduce parameters such as maxrounds (see other separators) */
6947 	   /* add mcf separator parameters */
6948 	   SCIP_CALL( SCIPaddIntParam(scip,
6949 	         "separating/mcf/nclusters",
6950 	         "number of clusters to generate in the shrunken network -- default separation",
6951 	         &sepadata->nclusters, TRUE, DEFAULT_NCLUSTERS, 2, (int) (8*sizeof(unsigned int)), NULL, NULL) );
6952 	   SCIP_CALL( SCIPaddRealParam(scip,
6953 	         "separating/mcf/maxweightrange",
6954 	         "maximal valid range max(|weights|)/min(|weights|) of row weights",
6955 	         &sepadata->maxweightrange, TRUE, DEFAULT_MAXWEIGHTRANGE, 1.0, SCIP_REAL_MAX, NULL, NULL) );
6956 	   SCIP_CALL( SCIPaddIntParam(scip,
6957 	         "separating/mcf/maxtestdelta",
6958 	         "maximal number of different deltas to try (-1: unlimited)  -- default separation",
6959 	         &sepadata->maxtestdelta, TRUE, DEFAULT_MAXTESTDELTA, -1, INT_MAX, NULL, NULL) );
6960 	   SCIP_CALL( SCIPaddBoolParam(scip,
6961 	         "separating/mcf/trynegscaling",
6962 	         "should negative values also be tested in scaling?",
6963 	         &sepadata->trynegscaling, TRUE, DEFAULT_TRYNEGSCALING, NULL, NULL) );
6964 	   SCIP_CALL( SCIPaddBoolParam(scip,
6965 	         "separating/mcf/fixintegralrhs",
6966 	         "should an additional variable be complemented if f0 = 0?",
6967 	         &sepadata->fixintegralrhs, TRUE, DEFAULT_FIXINTEGRALRHS, NULL, NULL) );
6968 	   SCIP_CALL( SCIPaddBoolParam(scip,
6969 	         "separating/mcf/dynamiccuts",
6970 	         "should generated cuts be removed from the LP if they are no longer tight?",
6971 	         &sepadata->dynamiccuts, FALSE, DEFAULT_DYNAMICCUTS, NULL, NULL) );
6972 	   SCIP_CALL( SCIPaddIntParam(scip,
6973 	         "separating/mcf/modeltype",
6974 	         "model type of network (0: auto, 1:directed, 2:undirected)",
6975 	         &sepadata->modeltype, TRUE, DEFAULT_MODELTYPE, 0, 2, NULL, NULL) );
6976 	   SCIP_CALL( SCIPaddIntParam(scip,
6977 	         "separating/mcf/maxsepacuts",
6978 	         "maximal number of mcf cuts separated per separation round",
6979 	         &sepadata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, -1, INT_MAX, NULL, NULL) );
6980 	   SCIP_CALL( SCIPaddIntParam(scip,
6981 	         "separating/mcf/maxsepacutsroot",
6982 	         "maximal number of mcf cuts separated per separation round in the root node  -- default separation",
6983 	         &sepadata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, -1, INT_MAX, NULL, NULL) );
6984 	   SCIP_CALL( SCIPaddRealParam(scip,
6985 	         "separating/mcf/maxinconsistencyratio",
6986 	         "maximum inconsistency ratio for separation at all",
6987 	         &sepadata->maxinconsistencyratio, TRUE, DEFAULT_MAXINCONSISTENCYRATIO, 0.0, SCIP_REAL_MAX, NULL, NULL) );
6988 	   SCIP_CALL( SCIPaddRealParam(scip,
6989 	         "separating/mcf/maxarcinconsistencyratio",
6990 	         "maximum inconsistency ratio of arcs not to be deleted",
6991 	         &sepadata->maxarcinconsistencyratio, TRUE, DEFAULT_MAXARCINCONSISTENCYRATIO, 0.0, SCIP_REAL_MAX, NULL, NULL) );
6992 	   SCIP_CALL( SCIPaddBoolParam(scip,
6993 	         "separating/mcf/checkcutshoreconnectivity",
6994 	         "should we separate only if the cuts shores are connected?",
6995 	         &sepadata->checkcutshoreconnectivity, TRUE, DEFAULT_CHECKCUTSHORECONNECTIVITY, NULL, NULL) );
6996 	   SCIP_CALL( SCIPaddBoolParam(scip,
6997 	         "separating/mcf/separatesinglenodecuts",
6998 	         "should we separate inequalities based on single-node cuts?",
6999 	         &sepadata->separatesinglenodecuts, TRUE, DEFAULT_SEPARATESINGLENODECUTS, NULL, NULL) );
7000 	   SCIP_CALL( SCIPaddBoolParam(scip,
7001 	         "separating/mcf/separateflowcutset",
7002 	         "should we separate flowcutset inequalities on the network cuts?",
7003 	         &sepadata->separateflowcutset, TRUE, DEFAULT_SEPARATEFLOWCUTSET, NULL, NULL) );
7004 	   SCIP_CALL( SCIPaddBoolParam(scip,
7005 	         "separating/mcf/separateknapsack",
7006 	         "should we separate knapsack cover inequalities on the network cuts?",
7007 	         &sepadata->separateknapsack, TRUE, DEFAULT_SEPARATEKNAPSACK, NULL, NULL) );
7008 	
7009 	   return SCIP_OKAY;
7010 	}
7011