Scippy

    SCIP

    Solving Constraint Integer Programs

    network.c
    Go to the documentation of this file.
    1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    2/* */
    3/* This file is part of the program and library */
    4/* SCIP --- Solving Constraint Integer Programs */
    5/* */
    6/* Copyright (c) 2002-2025 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 network.c
    26 * @ingroup OTHER_CFILES
    27 * @brief Methods for detecting network (sub)matrices
    28 * @author Rolf van der Hulst
    29 *
    30 * Detecting if a matrix is a network matrix can be quite complex. Below is an introductory text, which may help with
    31 * navigating the functions and datastructures in this file by giving a general overview.
    32 * More details can be found in;
    33 * R.P. van der Hulst and M. Walter "A row-wise algorithm for graph realization"
    34 * and
    35 * R.E. Bixby and D.K. Wagner "An almost linear-time algorithm for graph realization"
    36 * for the column-wise algorithm.
    37 *
    38 * The main difficulty with detecting network matrices is that there may exist many pairs of a graph and a spanning tree
    39 * that realize a matrix. The ambiguity of these graphs may be characterized in terms of \f$k\f$-separations on the
    40 * graph associated to the network matrix. An edge partition \f$(E_1,E_2)\f$ is considered a \f$k\f$-separation if
    41 * \f$|E_i|\geq k \f$ holds for \f$i\in\{1,2\}\f$. The ambiguity of network matrices is completely given by all
    42 * the 1-separations and 2-separations of the associated graph(s). In particular, if the graph realizing a
    43 * network matrix is 3-connected, then it is unique, up to inverting all edges of the graph.
    44 *
    45 * A 1-separation given by edge sets \f$(E_1,E_2)\f$, which is given by a singular node that is referred to as an
    46 * articulation node, implies that no column of the network matrix contains edges in both \f$E_1\f$ and \f$E_2\f$.
    47 * Remember that each edge in a realizing graph is associated with a row or column of the network matrix. Then, we have
    48 * a 1-separation exactly when the network matrix contains two (or more) disconnected blocks, where the rows and columns
    49 * of each block are contained in either \f$E_1\f$ or \f$E_2\f$. To obtain a graph realizing our network matrix, we can
    50 * attach the graph realizing \f$E_2\f$ at any node of the graph realizing \f$E_1\f$.
    51 * Thus, we store the graphs corresponding to the connected blocks of the network matrix separately.
    52 * Each block has a 2-connected realization graph.
    53 *
    54 * If a graph \f$G\f$ realizing the network matrix has a 2-separation \f$(E_1,E_2)\f$ at vertices u and v, then we can
    55 * obtain another graph representing the network matrix, by inverting the direction of all edges in \f$E_2\f$ and
    56 * replacing u by v and vice-versa. One can also imagine
    57 * adding a virtual edge \f$e'=\{u,v\}\f$ to both E_1 and E_2. In the trivial realization, we simply map the head of
    58 * \f$e'\f$ in \f$E_1\f$ to the head of \f$e'\f$ in \f$E_2\f$ and remove \f$e'\f$ from both graphs. In the second
    59 * realization we do the same thing, but first invert all the edges in \f$E_2\f$, including \f$e'\f$.
    60 * An SPQR tree \f$\mathcal{T}=(\mathcal{V},\mathcal{E})\f$ is a tree data structure that represents the structure of
    61 * all 2-separations in a 2-connected graph. Each member \f$\nu\in\mathcal{V}\f$ has an associated skeleton graph that
    62 * has one of four different types:
    63 * - (S) The member's skeleton graph is a cycle with at least 3 edges (also referred to as series or polygon)
    64 * - (P) The member's skeleton graph consists of at least 3 parallel edges and 2 nodes (also referred to as bond)
    65 * - (Q) The member's skeleton graph consists of at most 2 edges connecting two nodes (also referred to as loop)
    66 * - (R) The member's skeleton graph is 3-connected and consists of at least 4 edges.
    67 *
    68 * An SPQR tree is considered minimal if it has no P-P or S-S connections. Each connected matrix has a unique minimal
    69 * SPQR tree. Each edge \f$\{\nu,\mu\}\in\mathcal{E}\f$ defines a 2-separation of the underlying graph. In particular,
    70 * each edge has one virtual edge in the member graph that it connects to the other member graph in the edge.
    71 *
    72 * We can obtain a realization of the graph underlying the network matrix by doing the following operations:
    73 * 1. Permute the edges of each (S)-member arbitrarily
    74 * 2. For each edge in \f$\mathcal{E}\f$, pick one of the two orientations of the virtual edges and merge the adjacent
    75 * member graphs accordingly.
    76 *
    77 * In this way, all the graphs given by the network matrix are represented. In order to efficiently perform the merge
    78 * of two member graphs, the member and node labels are given by union-find datastructures. Additionally, we also
    79 * introduce a signed-union-find datastructure on the arcs of the graphs, so that we can efficiently invert the arcs
    80 * of one side of a 2-separation.
    81 * The 1-separations can be handled by storing an SPQR forest, with a (minimal) SPQR tree for every connected block
    82 * of the network matrix.
    83 *
    84 * For adding a column to the network matrix, one can show that one can add a column only if the nonzeros of the column
    85 * form a path with the correct signs in some graph represented by the network matrix. We solve the problem for each
    86 * graph represented by the network matrix simultaneously by decomposing over the SPQR tree. First, we compute the path
    87 * in each member. Then, we attempt to combine the paths by orienting the 2-separations so that the different member
    88 * paths form a path in the represented graph.
    89 * If some member has a set of edges that do not form a path, we can terminate.
    90 * An important step is 'propagation'; when we are in a leaf node of the sub-SPQR tree containing path edges and the
    91 * path in our leaf node forms a cycle with the virtual arc e connecting to the rest of the sub-tree, then we can
    92 * remove the leaf node from the SPQR tree and mark the virtual arc f that is paired with e.
    93 * After performing all such propagations, the sub-SPQR tree should form a path. Then, we merge these members into one,
    94 * forming a single path. By adding the new column edge to the end nodes of this path, we form a new member of type R.
    95 * Finally, we can easily join the paths of multiple SPQR trees using a series node to obtain the final path.
    96 *
    97 * The ideas for the row-wise algorithm have many parallels with the column-wise algorithm. One can add a row to a
    98 * network matrix if and only if a node is 'splittable' with respect to a certain auxiliary graph formed by the nonzero
    99 * columns indices of the row, for a graph represented by the network matrix. In particular, this auxiliary graph must
    100 * be a directed bipartite graph; then, the arcs incident to the given node can be reassigned to two new nodes, so that
    101 * the paths of the columns corresponding to the nonzeros of the row can be elongated to contain the new row, which is
    102 * placed between the two new nodes.
    103 * Similarly to the column-case, splittability of each graph represented by the network matrix can be computed at once
    104 * by computing the splittability (and the corresponding bipartition) of every member graph.
    105 * Similarly to the column algorithm, we can propagate; If a member is a leaf of the SPQR tree and both nodes of the
    106 * 2-separation connecting it to the rest of graph are splittable, then we can remove the leaf from the reduced
    107 * SPQR tree and mark the virtual edge connecting to the subtree.
    108 * Finally, we are left with some minimal subtree with splittable vertices for each member graph. If we can merge all
    109 * splittable vertices of the member graphs in the subtree into a single splittable vertex, then we perform this merge,
    110 * and split this vertex. This yields us a new, larger node of type R (rigid).
    111 *
    112 * Implementation notes:
    113 * 1. Quite a few algorithms used for network matrix detection are recursive in nature. However, recursive calls can
    114 * cause stack overflows, particularly with large graphs. Quite frequently in the code, we need to allocate the
    115 * call-data of these algorithms on the heap, instead, and use while loops to simulate the recursion.
    116 *
    117 * 2. In order to make the code fast in practice, a lot of emphasis is put on reusing allocated memory and avoiding
    118 * allocations. In particular for the column-wise algorithm, even allocating and zeroing an array of size m+n for an
    119 * m x n matrix can significantly slow down the code!
    120 *
    121 * 3. The graphs of the S, P and Q members do not need to be stored explicitly, as they always have the same structure.
    122 * This also makes it easier to permute edges of S nodes on the fly.
    123 */
    124
    125 /* TODO: fix tracking connectivity more cleanly, should not be left up to the algorithms ideally
    126 */
    127
    128#include <assert.h>
    129
    130#include "scip/misc.h"
    131#include "scip/pub_misc.h"
    132#include "scip/pub_network.h"
    133#include "scip/scip.h"
    134#include "blockmemshell/memory.h"
    135
    136/* types which define matrix sizes */
    140
    141#define SPQR_INVALID INT_MAX
    142#define SPQR_INVALID_ROW SPQR_INVALID
    143#define SPQR_INVALID_COL SPQR_INVALID
    144
    145
    146/* Only check in debug mode if the used indices are valid */
    147#ifndef NDEBUG
    148
    149/** Determine if the row index is invalid */
    150static
    152 spqr_row row /**< The row to check */
    153 )
    154{
    155 return row == SPQR_INVALID_ROW;
    156}
    157
    158/** Determine if the column index is invalid */
    159static
    161 spqr_col col /**< The column to check */
    162 )
    163{
    164 return col == SPQR_INVALID_COL;
    165}
    166
    167/** Determine if the row index is valid */
    168static
    170 spqr_row row /**< The row to check */
    171 )
    172{
    173 return !SPQRrowIsInvalid(row);
    174}
    175
    176/** Determine if the column index is valid */
    177static
    179 spqr_col col /**< The column to check */
    180 )
    181{
    182 return !SPQRcolIsInvalid(col);
    183}
    184
    185#endif
    186
    187/** Columns 0..x correspond to elements 0..x and rows 0..y correspond to elements -1.. -y-1 */
    188#define MARKER_ROW_ELEMENT (INT_MIN)
    189#define MARKER_COLUMN_ELEMENT (INT_MAX)
    190typedef int spqr_element;
    191
    192/** Checks if an element is a row */
    193static
    195 spqr_element element /**< The element to check */
    196 )
    197{
    198 return element < 0;
    199}
    200
    201/** Checks if an element is a column */
    202static
    204 spqr_element element /**< The element to check */
    205 )
    206{
    207 return !SPQRelementIsRow(element);
    208}
    209
    210/** Convert an element to the corresponding row index */
    211static
    213 spqr_element element /**< The element to convert */
    214 )
    215{
    216 assert(SPQRelementIsRow(element));
    217 return (spqr_row) ( -element - 1 );
    218}
    219
    220/** Convert a row to the corresponding element */
    221static
    223 spqr_row row /**< The row to convert */
    224 )
    225{
    226 assert(SPQRrowIsValid(row));
    227 return (spqr_element) -row - 1;
    228}
    229
    230/** Convert an element to the corresponding column index */
    231static
    233 spqr_element element /**< The element to convert */
    234 )
    235{
    236 assert(SPQRelementIsColumn(element));
    237 return (spqr_col) element;
    238}
    239
    240/** Convert a column to the corresponding element */
    241static
    243 spqr_col column /**< The column to convert */
    244 )
    245{
    246 assert(SPQRcolIsValid(column));
    247 return (spqr_element) column;
    248}
    249
    250/** spqr_member is an index for the members of the SPQR decomposition
    251 *
    252 * The members are the nodes of the SPQR tree.
    253 * Each member has an associated subgraph, sometimes called a skeleton.
    254 * If two members are adjacent in the SPQR tree, the two corresponding subgraphs are connected by a 2-separation in any
    255 * graph represented by the matrix.
    256 * For members, we reserve all negative values as invalid. We use these negative values in union-find datastructure,
    257 * where we store the rank of the representative as a negative number.
    258 */
    259typedef int spqr_member;
    260#define SPQR_INVALID_MEMBER (-1)
    261
    262/** Check if a member is invalid */
    263static
    265 spqr_member member /**< The member to check */
    266 )
    267{
    268 return member < 0;
    269}
    270
    271/** Check if a member is valid */
    273 spqr_member member /**< The member to check */
    274 )
    275{
    276 return !SPQRmemberIsInvalid(member);
    277}
    278
    279/** spqr_node is an index for the nodes stored in the decomposition.
    280 *
    281 * The nodes are part of each member's skeleton.
    282 * Similar to spqr_member, we reserve all negative values as invalid and use these in union-find.
    283 */
    284typedef int spqr_node;
    285#define SPQR_INVALID_NODE (-1)
    286
    287/** Check if a node is invalid */
    288static
    290 spqr_node node /**< The node to check */
    291 )
    292{
    293 return node < 0;
    294}
    295
    296/** Check if a node is valid */
    297static
    299 spqr_node node /**< The node to check */
    300 )
    301{
    302 return !SPQRnodeIsInvalid(node);
    303}
    304
    305/** spqr_arc is an index for the arcs stored in the decomposition.
    306 *
    307 * The arcs are part of each member's skeleton.
    308 * Similar to spqr_node and spqr_member, we reserve all negative values as invalid and use these in some union-find.
    309 * However, in contrast to spqr_node and spqr_member, the union-find data structure does not represent the arcs,
    310 * but rather if all arcs that have the same representative we know they are in the same member.
    311 */
    312typedef int spqr_arc;
    313#define SPQR_INVALID_ARC (-1)
    314
    315/** Check if an arc is invalid */
    316static
    318 spqr_arc arc /**< The arc to check */
    319 )
    320{
    321 return arc < 0;
    322}
    323
    324/** Check if an arc is valid */
    325static
    327 spqr_arc arc /**< The arc to check */
    328 )
    329{
    330 return !SPQRarcIsInvalid(arc);
    331}
    332
    333/** The type of the member */
    334typedef enum
    335{
    336 SPQR_MEMBERTYPE_RIGID = 0, /**< The member's skeleton is 3-connected and has at least 4 edges */
    337 SPQR_MEMBERTYPE_PARALLEL = 1, /**< The member's skeleton consists of 2 nodes with at least 3 edges */
    338 SPQR_MEMBERTYPE_SERIES = 2, /**< The member's skeleton is a cycle with at least 3 edges */
    339 SPQR_MEMBERTYPE_LOOP = 3, /**< The member's skeleton consists of 2 nodes connected by 1 or 2 edges */
    340 SPQR_MEMBERTYPE_UNASSIGNED = 4 /**< To indicate that the member is not a representative member anymore */
    342
    343/** Represents a single node of cyclic doubly-linked list of arc edges*/
    344typedef struct
    345{
    349
    350/** This structure stores the relevant data for a single node. */
    351typedef struct
    352{
    353 spqr_node representativeNode; /**< Points to the next node in the union-find data structure.
    354 * Stores the rank as a negative number if this node represents itself */
    355 spqr_arc firstArc; /**< Points to the head node of the cyclic doubly linked list containing
    356 * the arcs that are adjacent to this node. */
    357 int numArcs; /**< The number of arcs adjacent to this node */
    359
    360/** Structure that stores the relevant data for a single arc. */
    361typedef struct
    362{
    363 spqr_node head; /**< The head node of the arc */
    364 spqr_node tail; /**< The tail node of the arc */
    365 spqr_member member; /**< The member that contains the arc */
    366 spqr_member childMember; /**< Stores the child member, if this arc points to one */
    367 SPQRNetworkDecompositionArcListNode headArcListNode; /**< Linked-list node for iterating over the head's arcs */
    368 SPQRNetworkDecompositionArcListNode tailArcListNode; /**< Linked-list node for iterating over the tail's arcs */
    369 SPQRNetworkDecompositionArcListNode arcListNode; /**< Linked-list node for iterating over the member's arcs */
    370
    371 spqr_element element; /**< The element associated to this arc */
    372
    373 /** @name Signed union-find for arc directions.
    374 * @{
    375 *
    376 * If an arc is reversed, it's head becomes its tail and vice-versa.
    377 * For non-rigid members every arc is it's own representative, and the direction is simply given by the boolean.
    378 * For rigid members, every arc is represented by another arc in the member,
    379 * and the direction can be found by multiplying the signs along the union-find path
    380 * We use this data structure to efficiently reverse all arcs in a skeleton.
    381 */
    382 spqr_arc representative; /**< The representative of the arc */
    383 SCIP_Bool reversed; /**< Whether the arc's head and tail are reversed, or not */
    384 /** @} */
    386
    387/** Structure that stores the relevant data for a single member */
    388typedef struct
    389{
    390 spqr_member representativeMember; /**< The representative of this member (union-find) */
    391 SPQRMemberType type; /**< The type of this member */
    392
    393 /** @name The SPQR tree is stored as an arborescence.
    394 * @{
    395 *
    396 * Each member stores its parents, and each edge of the member
    397 * pointing to a child member stores the associated member in childMember
    398 */
    399 spqr_member parentMember; /**< The parent of this member in the arborescence */
    400 spqr_arc markerToParent; /**< The arc pointing to the parent */
    401 spqr_arc markerOfParent; /**< The arc of the parent pointing to this member */
    402 /** @} */
    403
    404 spqr_arc firstArc; /**< First arc of the linked list containing the member's arcs */
    405 int numArcs; /**< The number of arcs associated to the member */
    407
    408/** Stores the SPQR forest data structure and its relevant data */
    409typedef struct
    410{
    411 int numArcs; /**< The number of slots used in the arc data array */
    412 int memArcs; /**< The amount of space allocated in the arc data array */
    413 SPQRNetworkDecompositionArc* arcs; /**< Array of arcs of the SPQR forest, indexed by spqr_arc */
    414 spqr_arc firstFreeArc; /**< Points to the first unused slot in the arcs array */
    415
    416 int memMembers; /**< The amount of space allocated in the member data array */
    417 int numMembers; /**< The number of slots used in the member data array */
    418 SPQRNetworkDecompositionMember* members; /**< Array of members of the SPQR forest. Indexed by spqr_member */
    419
    420 int memNodes; /**< The amount of space allocated in the node data array */
    421 int numNodes; /**< The number of slots used in the node data array */
    422 SPQRNetworkDecompositionNode* nodes; /**< Array of nodes of the SPQR forest. Indexed by spqr_node */
    423
    424 int memRows; /**< The (maximal) number of rows of the matrix */
    425 spqr_arc* rowArcs; /**< Maps the rows of the matrix to arcs in the decomposition */
    426
    427 int memColumns; /**< The (maximal) number of columns of the matrix */
    428 spqr_arc* columnArcs; /**< Maps the columns of the matrix to arcs in the decomposition */
    429
    430 BMS_BLKMEM * env; /**< used memory allocator */
    431
    432 int numConnectedComponents; /**< The number of disjoint SPQR trees in the SPQR forest */
    434
    435
    436#ifndef NDEBUG
    437
    438/** Check if a node is a representative in the union-find data structure for nodes */
    439static
    441 const SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    442 spqr_node node /**< The node to check if it is representative */
    443 )
    444{
    445 assert(dec);
    446 assert(node < dec->memNodes);
    447 assert(SPQRnodeIsValid(node));
    448
    449 return SPQRnodeIsInvalid(dec->nodes[node].representativeNode);
    450}
    451
    452#endif
    453
    454/** Find the node its representative node in the union-find data structure */
    455static
    457 SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    458 spqr_node node /**< The node to find the representative for */
    459 )
    460{
    461 assert(dec);
    462 assert(SPQRnodeIsValid(node));
    463 assert(node < dec->memNodes);
    464
    465 spqr_node current = node;
    466 spqr_node next;
    467
    468 //traverse down tree to find the root
    469 while( SPQRnodeIsValid(next = dec->nodes[current].representativeNode) )
    470 {
    471 current = next;
    472 assert(current < dec->memNodes);
    473 }
    474
    475 spqr_node root = current;
    476 current = node;
    477
    478 //update all pointers along path to point to root, flattening the tree
    479 while( SPQRnodeIsValid(next = dec->nodes[current].representativeNode) )
    480 {
    481 dec->nodes[current].representativeNode = root;
    482 current = next;
    483 assert(current < dec->memNodes);
    484 }
    485 return root;
    486}
    487
    488/** Find the node its representative node in the union-find data structure, without compressing the union-find tree.
    489 *
    490 * Should only be used for debugging or asserts.
    491 */
    492static
    494 const SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    495 spqr_node node /**< The node to find the representative for */
    496 )
    497{
    498 assert(dec);
    499 assert(SPQRnodeIsValid(node));
    500 assert(node < dec->memNodes);
    501
    502 spqr_node current = node;
    503 spqr_node next;
    504
    505 //traverse down tree to find the root
    506 while( SPQRnodeIsValid(next = dec->nodes[current].representativeNode) )
    507 {
    508 current = next;
    509 assert(current < dec->memNodes);
    510 }
    511 spqr_node root = current;
    512 return root;
    513}
    514
    515/** Find the arc's tail node in the union find data structure of the nodes.
    516 *
    517 * Updates the arc's tail to point to the representative for faster future queries.
    518 */
    519static
    521 SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    522 spqr_arc arc /**< The arc whose tail we want to find */
    523 )
    524{
    525 assert(dec);
    526 assert(SPQRarcIsValid(arc));
    527 assert(arc < dec->memArcs);
    528
    529 spqr_node representative = findNode(dec, dec->arcs[arc].tail);
    530 dec->arcs[arc].tail = representative;//update the arc information
    531
    532 return representative;
    533}
    534
    535/** Find the arc's head node in the union find data structure of the nodes.
    536 *
    537 * Updates the arc's head to point to the representative for faster future queries.
    538 */
    539static
    541 SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    542 spqr_arc arc /**< The arc whose head we want to find */
    543 )
    544{
    545 assert(dec);
    546 assert(SPQRarcIsValid(arc));
    547 assert(arc < dec->memArcs);
    548
    549 spqr_node representative = findNode(dec, dec->arcs[arc].head);
    550 dec->arcs[arc].head = representative;//update the arc information
    551
    552 return representative;
    553}
    554
    555/** Find the arc's head node in the union find data structure of the nodes, without compressing the union-find tree.
    556 *
    557 * Should only be used in debugging statements or asserts.
    558 */
    559static
    561 const SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    562 spqr_arc arc /**< The arc whose head we want to find */
    563 )
    564{
    565 assert(dec);
    566 assert(SPQRarcIsValid(arc));
    567 assert(arc < dec->memArcs);
    568
    569 spqr_node representative = findNodeNoCompression(dec, dec->arcs[arc].head);
    570 return representative;
    571}
    572
    573/** Find the arc's tail node in the union find data structure of the nodes, without compressing the union-find tree.
    574 *
    575 * Should only be used in debugging statements or asserts.
    576 */
    577static
    579 const SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    580 spqr_arc arc /**< The arc whose tail we want to find */
    581 )
    582{
    583 assert(dec);
    584 assert(SPQRarcIsValid(arc));
    585 assert(arc < dec->memArcs);
    586
    587 spqr_node representative = findNodeNoCompression(dec, dec->arcs[arc].tail);
    588 return representative;
    589}
    590
    591/** Find the first arc in the list of arcs that are adjacent to the given node.
    592 *
    593 * These arcs form a cyclic linked-list.
    594 */
    595static
    597 const SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    598 spqr_node node /**< The node to find the arc for */
    599 )
    600{
    601 assert(dec);
    602 assert(SPQRnodeIsValid(node));
    603 assert(node < dec->memNodes);
    604
    605 return dec->nodes[node].firstArc;
    606}
    607
    608/** Given the current arc adjacent to this node, find the next arc in the cyclic linked list of adjacent arcs to the
    609 * given node.
    610 *
    611 * This function does not compress the union-find tree, and should only be used in debugging or asserts.
    612 */
    613static
    615 const SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    616 spqr_arc arc, /**< The current arc that is adjacent to this node */
    617 spqr_node node /**< The node to which the arc is adjacent */
    618 )
    619{
    620 assert(dec);
    621 assert(SPQRarcIsValid(arc));
    622 assert(arc < dec->memArcs);
    623 assert(nodeIsRepresentative(dec, node));
    624
    625 if( findArcHeadNoCompression(dec, arc) == node )
    626 {
    627 arc = dec->arcs[arc].headArcListNode.next;
    628 }
    629 else
    630 {
    631 assert(findArcTailNoCompression(dec, arc) == node);
    632 arc = dec->arcs[arc].tailArcListNode.next;
    633 }
    634 return arc;
    635}
    636
    637/** Given the current arc adjacent to this node, find the next arc in the cyclic linked list of adjacent arcs to the
    638 * given node.
    639 */
    640static
    642 SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    643 spqr_arc arc, /**< The current arc that is adjacent to this node */
    644 spqr_node node /**< The node to which the arc is adjacent */
    645 )
    646{
    647 assert(dec);
    648 assert(SPQRarcIsValid(arc));
    649 assert(arc < dec->memArcs);
    650 assert(nodeIsRepresentative(dec, node));
    651
    652 if( findArcHead(dec, arc) == node )
    653 {
    654 arc = dec->arcs[arc].headArcListNode.next;
    655 }
    656 else
    657 {
    658 assert(findArcTailNoCompression(dec, arc) == node);
    659 dec->arcs[arc].tail = node; //This assignment is not necessary but speeds up future queries.
    660 arc = dec->arcs[arc].tailArcListNode.next;
    661 }
    662 return arc;
    663}
    664
    665/** Given the current arc adjacent to this node, find the previous arc in the cyclic linked list of adjacent arcs
    666 * to the given node.
    667 */
    668static
    670 SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    671 spqr_arc arc, /**< The current arc that is adjacent to this node */
    672 spqr_node node /**< The node to which the arc is adjacent */
    673 )
    674{
    675 assert(dec);
    676 assert(SPQRarcIsValid(arc));
    677 assert(arc < dec->memArcs);
    678 assert(nodeIsRepresentative(dec, node));
    679
    680 if( findArcHead(dec, arc) == node )
    681 {
    682 arc = dec->arcs[arc].headArcListNode.previous;
    683 }
    684 else
    685 {
    686 assert(findArcTailNoCompression(dec, arc) == node);
    687 dec->arcs[arc].tail = node;//This assignment is not necessary but speeds up future queries.
    688 arc = dec->arcs[arc].tailArcListNode.previous;
    689 }
    690 return arc;
    691}
    692
    693/** Update the cyclic node-arc incidence data structure to move all arcs adjacent to one node to another node.
    694 *
    695 * We typically call this when two nodes are identified with one another, and we need to merge their adjacent arcs.
    696 */
    697static
    699 SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    700 spqr_node toMergeInto, /**< The node that we want to give all the arcs of both nodes */
    701 spqr_node toRemove /**< The node whose arcs we want to remove */
    702 )
    703{
    704 spqr_arc firstIntoArc = getFirstNodeArc(dec, toMergeInto);
    705 spqr_arc firstFromArc = getFirstNodeArc(dec, toRemove);
    706 if( SPQRarcIsInvalid(firstIntoArc))
    707 {
    708 //new node has no arcs
    709 dec->nodes[toMergeInto].numArcs += dec->nodes[toRemove].numArcs;
    710 dec->nodes[toRemove].numArcs = 0;
    711
    712 dec->nodes[toMergeInto].firstArc = dec->nodes[toRemove].firstArc;
    713 dec->nodes[toRemove].firstArc = SPQR_INVALID_ARC;
    714
    715 return;
    716 }
    717 if( SPQRarcIsInvalid(firstFromArc))
    718 {
    719 //Old node has no arcs; we can just return
    720 return;
    721 }
    722
    723 spqr_arc lastIntoArc = getPreviousNodeArc(dec, firstIntoArc, toMergeInto);
    724 assert(SPQRarcIsValid(lastIntoArc));
    725 spqr_arc lastFromArc = getPreviousNodeArc(dec, firstFromArc, toRemove);
    726 assert(SPQRarcIsValid(lastFromArc));
    727
    729 findArcHead(dec, firstIntoArc) == toMergeInto ? &dec->arcs[firstIntoArc].headArcListNode
    730 : &dec->arcs[firstIntoArc].tailArcListNode;
    732 findArcHead(dec, lastIntoArc) == toMergeInto ? &dec->arcs[lastIntoArc].headArcListNode
    733 : &dec->arcs[lastIntoArc].tailArcListNode;
    734
    736 findArcHead(dec, firstFromArc) == toRemove ? &dec->arcs[firstFromArc].headArcListNode
    737 : &dec->arcs[firstFromArc].tailArcListNode;
    739 findArcHead(dec, lastFromArc) == toRemove ? &dec->arcs[lastFromArc].headArcListNode
    740 : &dec->arcs[lastFromArc].tailArcListNode;
    741
    742 firstIntoNode->previous = lastFromArc;
    743 lastIntoNode->next = firstFromArc;
    744 firstFromNode->previous = lastIntoArc;
    745 lastFromNode->next = firstIntoArc;
    746
    747 dec->nodes[toMergeInto].numArcs += dec->nodes[toRemove].numArcs;
    748 dec->nodes[toRemove].numArcs = 0;
    749 dec->nodes[toRemove].firstArc = SPQR_INVALID_ARC;
    750}
    751
    752/** Flips the direction a given arc. */
    753static
    755 SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    756 spqr_arc arc /**< The arc that we want to flip */
    757 )
    758{
    759 assert(dec);
    760 assert(SPQRarcIsValid(arc));
    761 assert(arc < dec->memArcs);
    762
    763 dec->arcs[arc].reversed = !dec->arcs[arc].reversed;
    764}
    765
    766/** Sets the direction of a given arc */
    767static
    769 SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    770 spqr_arc arc, /**< The given arc */
    771 SCIP_Bool reversed /**< Are the head and tail reversed? */
    772 )
    773{
    774 assert(dec);
    775 assert(SPQRarcIsValid(arc));
    776 assert(arc < dec->memArcs);
    777
    778 dec->arcs[arc].reversed = reversed;
    779}
    780
    781
    782/** Sets the representative of a given arc.
    783 *
    784 * The arcs reversed field is given with respect to the representative.
    785 * In particular, whether an arc is reversed or not is determined by the sign of the path in the signed union-find
    786 * data structure for arcs, which can be computed by multiplying the signs of the individual edges (xor over bools).
    787 */
    788static
    790 SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    791 spqr_arc arc, /**< The given arc */
    792 spqr_arc representative /**< The representative to set the arc to */
    793 )
    794{
    795 assert(dec);
    796 assert(SPQRarcIsValid(arc));
    797 assert(arc < dec->memArcs);
    798 assert(representative == SPQR_INVALID_ARC || SPQRarcIsValid(representative));
    799
    800 dec->arcs[arc].representative = representative;
    801}
    802
    803/** Merge two representative nodes (Union operation) in the union-find data structure for nodes.
    804 *
    805 * Returns the id of the node that becomes representative for both.
    806 */
    807static
    809 SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    810 spqr_node first, /**< A node to merge */
    811 spqr_node second /**< A second node to merge */
    812 )
    813{
    814 assert(dec);
    815 assert(nodeIsRepresentative(dec, first));
    816 assert(nodeIsRepresentative(dec, second));
    817 assert(first != second);//We cannot merge a node into itself
    818 assert(first < dec->memNodes);
    819 assert(second < dec->memNodes);
    820
    821 //The rank is stored as a negative number: we decrement it making the negative number larger.
    822 //We want the new root to be the one with 'largest' rank, so smallest number. If they are equal, we decrement.
    823 spqr_node firstRank = dec->nodes[first].representativeNode;
    824 spqr_node secondRank = dec->nodes[second].representativeNode;
    825 if( firstRank > secondRank )
    826 {
    827 SCIPswapInts(&first, &second);
    828 }
    829 //first becomes representative; we merge all of the arcs of second into first
    830 mergeNodeArcList(dec, first, second);
    831 dec->nodes[second].representativeNode = first;
    832 if( firstRank == secondRank )
    833 {
    834 --dec->nodes[first].representativeNode;
    835 }
    836 return first;
    837}
    838
    839/** Check if a member is a representative in the union-find data structure for members. */
    840static
    842 const SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    843 spqr_member member /**< The member to check */
    844 )
    845{
    846 assert(dec);
    847 assert(member < dec->memMembers);
    848 assert(SPQRmemberIsValid(member));
    849
    851}
    852
    853/** Find the member its representative member in the union-find data structure */
    854static
    856 SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    857 spqr_member member /**< The member to find the representative for */
    858 )
    859{
    860 assert(dec);
    861 assert(member < dec->memMembers);
    862 assert(SPQRmemberIsValid(member));
    863
    864 spqr_member current = member;
    865 spqr_member next;
    866
    867 //traverse down tree to find the root
    868 while( SPQRmemberIsValid(next = dec->members[current].representativeMember) )
    869 {
    870 current = next;
    871 assert(current < dec->memMembers);
    872 }
    873
    874 spqr_member root = current;
    875 current = member;
    876
    877 //update all pointers along path to point to root, flattening the tree
    878 while( SPQRmemberIsValid(next = dec->members[current].representativeMember) )
    879 {
    880 dec->members[current].representativeMember = root;
    881 current = next;
    882 assert(current < dec->memMembers);
    883 }
    884 return root;
    885}
    886
    887/** Find the member's representative member in the union-find data structure, without compressing the union-find tree.
    888 *
    889 * Should only be used for debugging or asserts.
    890 */
    891static
    893 const SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    894 spqr_member member /**< The member to find the representative for */
    895 )
    896{
    897 assert(dec);
    898 assert(member < dec->memMembers);
    899 assert(SPQRmemberIsValid(member));
    900
    901 spqr_member current = member;
    902 spqr_member next;
    903
    904 //traverse down tree to find the root
    905 while( SPQRmemberIsValid(next = dec->members[current].representativeMember) )
    906 {
    907 current = next;
    908 assert(current < dec->memMembers);
    909 }
    910
    911 spqr_member root = current;
    912 return root;
    913}
    914
    915/** Merge two representative members (Union operation) in the union-find data structure.
    916 *
    917 * Returns the id of the member that becomes representative for both.
    918 */
    919static
    921 SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    922 spqr_member first, /**< The first member to merge */
    923 spqr_member second /**< The second member to merge */
    924 )
    925{
    926 assert(dec);
    927 assert(memberIsRepresentative(dec, first));
    928 assert(memberIsRepresentative(dec, second));
    929 assert(first != second);//We cannot merge a member into itself
    930 assert(first < dec->memMembers);
    931 assert(second < dec->memMembers);
    932
    933 //The rank is stored as a negative number: we decrement it making the negative number larger.
    934 // We want the new root to be the one with 'largest' rank, so smallest number. If they are equal, we decrement.
    935 spqr_member firstRank = dec->members[first].representativeMember;
    936 spqr_member secondRank = dec->members[second].representativeMember;
    937 if( firstRank > secondRank )
    938 {
    939 SCIPswapInts(&first, &second);
    940 }
    941 dec->members[second].representativeMember = first;
    942 if( firstRank == secondRank )
    943 {
    944 --dec->members[first].representativeMember;
    945 }
    946 return first;
    947}
    948
    949/** Finds the member in which the arc is located */
    950static
    952 SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    953 spqr_arc arc /**< The arc to find the member for */
    954 )
    955{
    956 assert(dec);
    957 assert(SPQRarcIsValid(arc));
    958 assert(arc < dec->memArcs);
    959
    960 spqr_member representative = findMember(dec, dec->arcs[arc].member);
    961 dec->arcs[arc].member = representative;
    962 return representative;
    963}
    964
    965/** Finds the member in which the arc is located, without compressing the member union-find tree */
    966static
    968 const SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    969 spqr_arc arc /**< The arc to find the member for */
    970 )
    971{
    972 assert(dec);
    973 assert(SPQRarcIsValid(arc));
    974 assert(arc < dec->memArcs);
    975
    976 spqr_member representative = findMemberNoCompression(dec, dec->arcs[arc].member);
    977 return representative;
    978}
    979
    980/** Find the representative parent member of the given member.
    981 *
    982 * Note the given member must be representative.
    983 */
    984static
    986 SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    987 spqr_member member /**< The member to find the parent for. Must be representative. */
    988 )
    989{
    990 assert(dec);
    991 assert(member < dec->memMembers);
    992 assert(SPQRmemberIsValid(member));
    993 assert(memberIsRepresentative(dec, member));
    994
    995 if( SPQRmemberIsInvalid(dec->members[member].parentMember))
    996 {
    997 return dec->members[member].parentMember;
    998 }
    999 spqr_member parent_representative = findMember(dec, dec->members[member].parentMember);
    1000 dec->members[member].parentMember = parent_representative;
    1001
    1002 return parent_representative;
    1003}
    1004
    1005/** Find the representative parent member of the given member.
    1006 *
    1007 * Note the given member must be representative.
    1008 * This version does not perform compression of the union-find tree, and should only be used in debug or asserts.
    1009 */
    1010static
    1012 const SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    1013 spqr_member member /**< The member to find the parent for. Must be representative. */
    1014 )
    1015{
    1016 assert(dec);
    1017 assert(member < dec->memMembers);
    1018 assert(SPQRmemberIsValid(member));
    1019 assert(memberIsRepresentative(dec, member));
    1020
    1021 if( SPQRmemberIsInvalid(dec->members[member].parentMember))
    1022 {
    1023 return dec->members[member].parentMember;
    1024 }
    1025 spqr_member parent_representative = findMemberNoCompression(dec, dec->members[member].parentMember);
    1026 return parent_representative;
    1027}
    1028
    1029/** Find the child member associated to the given arc, which must be virtual. */
    1030static
    1032 SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    1033 spqr_arc arc /**< The arc to find the child member for */
    1034 )
    1035{
    1036 assert(dec);
    1037 assert(SPQRarcIsValid(arc));
    1038 assert(arc < dec->memArcs);
    1039
    1040 spqr_member representative = findMember(dec, dec->arcs[arc].childMember);
    1041 dec->arcs[arc].childMember = representative;
    1042 return representative;
    1043}
    1044
    1045/** Find the child member associated to the given virtual arc.
    1046 *
    1047 * This version does not compress the union-find tree and should only be used for debugging and asserts.
    1048 */
    1049static
    1051 const SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    1052 spqr_arc arc /**< The arc to find the child member for */
    1053 )
    1054{
    1055 assert(dec);
    1056 assert(SPQRarcIsValid(arc));
    1057 assert(arc < dec->memArcs);
    1058
    1059 spqr_member representative = findMemberNoCompression(dec, dec->arcs[arc].childMember);
    1060 return representative;
    1061}
    1062
    1063/** Checks if the arc has a child member */
    1064static
    1066 const SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    1067 spqr_arc arc /**< The arc to check */
    1068 )
    1069{
    1070 assert(dec);
    1071 assert(SPQRarcIsValid(arc));
    1072 assert(arc < dec->memArcs);
    1073
    1074 return SPQRmemberIsValid(dec->arcs[arc].childMember);
    1075}
    1076
    1077/** Check whether the given arc is a tree arc or not, i.e. whether it belongs to a (virtual) row or column or not */
    1078static
    1080 const SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    1081 spqr_arc arc /**< The arc to check */
    1082 )
    1083{
    1084 assert(dec);
    1085 assert(SPQRarcIsValid(arc));
    1086 assert(arc < dec->memArcs);
    1087
    1088 return SPQRelementIsRow(dec->arcs[arc].element);
    1089}
    1090
    1091/** Output data structure that stores both the arc's sign and representative */
    1092typedef struct
    1093{
    1096} ArcSign;
    1097
    1098#ifndef NDEBUG
    1099
    1100/** Check if an arc is a representative in the signed union-find data structure for arc directions.
    1101 *
    1102 * In each member, exactly one arc is the representative.
    1103 */
    1104static
    1106 const SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    1107 spqr_arc arc /**< The arc to check */
    1108 )
    1109{
    1110 assert(dec);
    1111 assert(arc < dec->memArcs);
    1112 assert(SPQRarcIsValid(arc));
    1113
    1114 return SPQRarcIsInvalid(dec->arcs[arc].representative);
    1115}
    1116
    1117#endif
    1118
    1119/** Find an arcs representative and its direction in the signed union-find data structure for arcs. */
    1120static
    1122 SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    1123 spqr_arc arc /**< The arc to find the representative and direction for */
    1124 )
    1125{
    1126 assert(dec);
    1127 assert(arc < dec->memArcs);
    1128 assert(SPQRarcIsValid(arc));
    1129
    1130 spqr_arc current = arc;
    1131 spqr_arc next;
    1132
    1133 SCIP_Bool totalReversed = dec->arcs[current].reversed;
    1134 //traverse down tree to find the root
    1135 while( SPQRarcIsValid(next = dec->arcs[current].representative) )
    1136 {
    1137 current = next;
    1138 assert(current < dec->memArcs);
    1139 //swap boolean only if new arc is reversed
    1140 totalReversed = ( totalReversed != dec->arcs[current].reversed );
    1141 }
    1142
    1143 spqr_arc root = current;
    1144 current = arc;
    1145
    1146 SCIP_Bool currentReversed = totalReversed != dec->arcs[root].reversed;
    1147 //update all pointers along path to point to root, flattening the tree
    1148
    1149 while( SPQRarcIsValid(next = dec->arcs[current].representative) )
    1150 {
    1151 SCIP_Bool wasReversed = dec->arcs[current].reversed;
    1152
    1153 dec->arcs[current].reversed = currentReversed;
    1154 currentReversed = ( currentReversed != wasReversed );
    1155
    1156 dec->arcs[current].representative = root;
    1157 current = next;
    1158 assert(current < dec->memArcs);
    1159 }
    1160
    1161 ArcSign sign;
    1162 sign.reversed = totalReversed;
    1163 sign.representative = root;
    1164 return sign;
    1165}
    1166
    1167/** Find an arcs representative and its direction in the signed union-find data structure for arcs.
    1168 *
    1169 * This version does not compress the union-find tree and should only be used in debug and asserts.
    1170 */
    1171static
    1173 const SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    1174 spqr_arc arc /**< The arc to find the representative and direction for */
    1175 )
    1176{
    1177 assert(dec);
    1178 assert(arc < dec->memArcs);
    1179 assert(SPQRarcIsValid(arc));
    1180
    1181 spqr_arc current = arc;
    1182 spqr_arc next;
    1183
    1184 SCIP_Bool totalReversed = dec->arcs[current].reversed;
    1185 //traverse down tree to find the root
    1186 while( SPQRarcIsValid(next = dec->arcs[current].representative))
    1187 {
    1188 current = next;
    1189 assert(current < dec->memArcs);
    1190 //swap boolean only if new arc is reversed
    1191 totalReversed = ( totalReversed != dec->arcs[current].reversed );
    1192 }
    1193 ArcSign sign;
    1194 sign.reversed = totalReversed;
    1195 sign.representative = current;
    1196 return sign;
    1197}
    1198
    1199/** Finds the arcs head, taking into account whether it is reversed by the signed union-find data structure. */
    1200static
    1202 SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    1203 spqr_arc arc /**< The arc to find the head for */
    1204 )
    1205{
    1206 assert(dec);
    1207 if( findArcSign(dec, arc).reversed )
    1208 {
    1209 return findArcTail(dec, arc);
    1210 }
    1211 else
    1212 {
    1213 return findArcHead(dec, arc);
    1214 }
    1215}
    1216
    1217/** Finds the arcs tail, taking into account whether it is reversed by the signed union-find data structure. */
    1218static
    1220 SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    1221 spqr_arc arc /**< The arc to find the tail for */
    1222 )
    1223{
    1224 assert(dec);
    1225 if( findArcSign(dec, arc).reversed )
    1226 {
    1227 return findArcHead(dec, arc);
    1228 }
    1229 else
    1230 {
    1231 return findArcTail(dec, arc);
    1232 }
    1233}
    1234
    1235/** Finds the arcs head, taking into account whether it is reversed by the signed union-find data structure.
    1236 *
    1237 * This version does not compress the union-find tree and should only be used in debug and asserts.
    1238 */
    1239static
    1241 const SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    1242 spqr_arc arc /**< The arc to find the head for */
    1243 )
    1244{
    1245 assert(dec);
    1246
    1247 if( findArcSignNoCompression(dec, arc).reversed )
    1248 {
    1249 return findArcTailNoCompression(dec, arc);
    1250 }
    1251 else
    1252 {
    1253 return findArcHeadNoCompression(dec, arc);
    1254 }
    1255}
    1256
    1257/** Finds the arcs tail, taking into account whether it is reversed by the signed union-find data structure.
    1258 *
    1259 * This version does not compress the union-find tree and should only be used in debug and asserts.
    1260 */
    1261static
    1263 const SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    1264 spqr_arc arc /**< The arc to find the tail for */
    1265 )
    1266{
    1267 assert(dec);
    1268 if( findArcSignNoCompression(dec, arc).reversed )
    1269 {
    1270 return findArcHeadNoCompression(dec, arc);
    1271 }
    1272 else
    1273 {
    1274 return findArcTailNoCompression(dec, arc);
    1275 }
    1276}
    1277
    1278/** Merges the sign union-find structures for two arc sets.
    1279 *
    1280 * If reflectRelative is set to true then all arcs of the represented by the second arc are reversed
    1281 * w.r.t. their current orientation. Otherwise, all arcs keep the same
    1282 * reversed status with respect to the root node of the union find tree.
    1283 */
    1284static
    1286 SCIP_NETMATDECDATA* dec, /**< The decomposition data structure */
    1287 spqr_arc first, /**< Representative arc of the first arc set */
    1288 spqr_arc second, /**< Representative arc of the second arc set */
    1289 SCIP_Bool reflectRelative /**< Should all arcs in the second arc set be reversed?*/
    1290 )
    1291{
    1292 assert(dec);
    1293 assert(arcIsRepresentative(dec, first));
    1294 assert(arcIsRepresentative(dec, second));
    1295 assert(first != second);//We cannot merge a member into itself
    1296 assert(first < dec->memArcs);
    1297 assert(second < dec->memArcs);
    1298
    1299 //The rank is stored as a negative number: we decrement it making the negative number larger.
    1300 //We want the new root to be the one with 'largest' rank, so smallest number. If they are equal, we decrement.
    1301 spqr_member firstRank = dec->arcs[first].representative;
    1302 spqr_member secondRank = dec->arcs[second].representative;
    1303
    1304 if( firstRank > secondRank )
    1305 {
    1306 SCIPswapInts(&first, &second);
    1307 }
    1308 dec->arcs[second].representative = first;
    1309 if( firstRank == secondRank )
    1310 {
    1311 --dec->arcs[first].representative;
    1312 }
    1313 //These boolean formula's cover all 16 possible cases, such that the relative orientation of the first is not changed
    1314 //but the relative orientation of the second is changed based on whether we want to reflect.
    1315 SCIP_Bool equal = dec->arcs[first].reversed == dec->arcs[second].reversed;
    1316 dec->arcs[second].reversed = ( equal == reflectRelative );
    1317 if( firstRank > secondRank )
    1318 {
    1319 dec->arcs[first].reversed = ( dec->arcs[first].reversed != reflectRelative );
    1320 }
    1321 return first;
    1322}
    1323
    1324/** Checks whether an arc is reversed for arcs in non-rigid members.
    1325 *
    1326 * For non-rigid members, we do not use the union-find datastructure, as we can get away without it.
    1327 */
    1328static
    1330 const SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    1331 spqr_arc arc /**< The arc to check */
    1332 )
    1333{
    1334 assert(dec);
    1335 assert(SPQRarcIsValid(arc));
    1336 assert(arc < dec->memArcs);
    1337
    1338 return dec->arcs[arc].reversed;
    1339}
    1340
    1341/** Gets the element (row/column) associated to the given arc. */
    1342static
    1344 const SCIP_NETMATDECDATA* dec, /**< The network decomposition */
    1345 spqr_arc arc /**< The arc to get the element for */
    1346 )
    1347{
    1348 assert(dec);
    1349 assert(SPQRarcIsValid(arc));
    1350 assert(arc < dec->memArcs);
    1351
    1352 return dec->arcs[arc].element;
    1353}
    1354
    1355/** Check whether the network matrix decomposition contains an edge for the given row index. */
    1356static
    1358 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1359 int row /**< The row index that is checked */
    1360 )
    1361{
    1362 assert(SPQRrowIsValid(row) && row < dec->memRows);
    1363 assert(dec);
    1364
    1365 return SPQRarcIsValid(dec->rowArcs[row]);
    1366}
    1367
    1368/** Check whether the network matrix decomposition contains an edge for the given column index. */
    1369static
    1371 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1372 int column /**< The column index that is checked */
    1373 )
    1374{
    1375 assert(SPQRcolIsValid(column) && column < dec->memColumns);
    1376 assert(dec);
    1377
    1378 return SPQRarcIsValid(dec->columnArcs[column]);
    1379}
    1380
    1381/** Associate the given arc to the given column in the network matrix decomposition. */
    1382static
    1384 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1385 spqr_col col, /**< The column to associate */
    1386 spqr_arc arc /**< The arc to associate to the column */
    1387 )
    1388{
    1389 assert(SPQRcolIsValid(col) && col < dec->memColumns);
    1390 assert(dec);
    1391 assert(SPQRarcIsValid(arc));
    1392
    1393 dec->columnArcs[col] = arc;
    1394}
    1395
    1396/** Associate the given arc to the given row in the network matrix decomposition. */
    1397static
    1399 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1400 spqr_row row, /**< The row to associate */
    1401 spqr_arc arc /**< The arc to associate to the row */
    1402 )
    1403{
    1404 assert(SPQRrowIsValid(row) && row < dec->memRows);
    1405 assert(dec);
    1406 assert(SPQRarcIsValid(arc));
    1407
    1408 dec->rowArcs[row] = arc;
    1409}
    1410
    1411/** Get the decomposition arc associated to the given column. */
    1412static
    1414 const SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1415 spqr_col col /**< The given column */
    1416 )
    1417{
    1418 assert(SPQRcolIsValid(col) && col < dec->memColumns);
    1419 assert(dec);
    1420
    1421 return dec->columnArcs[col];
    1422}
    1423
    1424/** Get the decomposition arc associated to the given row. */
    1425static
    1427 const SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1428 spqr_row row /**< The given row */
    1429 )
    1430{
    1431 assert(SPQRrowIsValid(row) && row < dec->memRows);
    1432 assert(dec);
    1433
    1434 return dec->rowArcs[row];
    1435}
    1436
    1437/** Initialize the network matrix decomposition data structure. */
    1438static
    1440 BMS_BLKMEM* blkmem, /**< Block memory */
    1441 SCIP_NETMATDECDATA** pdec, /**< buffer to store pointer to created decomposition */
    1442 int nrows, /**< The maximal number of rows that the decomposition can expect */
    1443 int ncols /**< The maximal number of columns that the decomposition can expect */
    1444 )
    1445{
    1446 assert(blkmem);
    1447 assert(pdec);
    1448 assert(!*pdec);
    1449
    1450 SCIP_ALLOC( BMSallocBlockMemory(blkmem, pdec) );
    1451 SCIP_NETMATDECDATA* dec = *pdec;
    1452 dec->env = blkmem;
    1453
    1454 //Initialize arc array data
    1455 int initialMemArcs = 8;
    1456 {
    1457 assert(initialMemArcs > 0);
    1458 dec->memArcs = initialMemArcs;
    1459 dec->numArcs = 0;
    1460 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &dec->arcs, dec->memArcs) );
    1461 for( spqr_arc i = 0; i < dec->memArcs; ++i )
    1462 {
    1463 dec->arcs[i].arcListNode.next = i + 1;
    1465 }
    1466 dec->arcs[dec->memArcs - 1].arcListNode.next = SPQR_INVALID_ARC;
    1467 dec->firstFreeArc = 0;
    1468 }
    1469
    1470 //Initialize member array data
    1471 int initialMemMembers = 8;
    1472 {
    1473 assert(initialMemMembers > 0);
    1474 dec->memMembers = initialMemMembers;
    1475 dec->numMembers = 0;
    1476 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &dec->members, dec->memMembers) );
    1477 }
    1478
    1479 //Initialize node array data
    1480 int initialMemNodes = 8;
    1481 {
    1482 assert(initialMemNodes > 0);
    1483 dec->memNodes = initialMemNodes;
    1484 dec->numNodes = 0;
    1485 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &dec->nodes, dec->memNodes) );
    1486 }
    1487
    1488 //Initialize mappings for rows
    1489 {
    1490 dec->memRows = nrows;
    1491 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &dec->rowArcs, dec->memRows) );
    1492 for( int i = 0; i < dec->memRows; ++i )
    1493 {
    1494 dec->rowArcs[i] = SPQR_INVALID_ARC;
    1495 }
    1496 }
    1497 //Initialize mappings for columns
    1498 {
    1499 dec->memColumns = ncols;
    1501 for( int i = 0; i < dec->memColumns; ++i )
    1502 {
    1503 dec->columnArcs[i] = SPQR_INVALID_ARC;
    1504 }
    1505 }
    1506
    1507 dec->numConnectedComponents = 0;
    1508 return SCIP_OKAY;
    1509}
    1510
    1511/** Free the network matrix decomposition data structure */
    1512static
    1514 SCIP_NETMATDECDATA** pdec /**< pointer to the network matrix decomposition to freed */
    1515 )
    1516{
    1517 assert(pdec);
    1518 assert(*pdec);
    1519
    1520 SCIP_NETMATDECDATA* dec = *pdec;
    1522 BMSfreeBlockMemoryArray(dec->env, &dec->rowArcs, dec->memRows);
    1523 BMSfreeBlockMemoryArray(dec->env, &dec->nodes, dec->memNodes);
    1524 BMSfreeBlockMemoryArray(dec->env, &dec->members, dec->memMembers);
    1525 BMSfreeBlockMemoryArray(dec->env, &dec->arcs, dec->memArcs);
    1526
    1527 BMSfreeBlockMemory(dec->env, pdec);
    1528}
    1529
    1530/** Get the first arc of the linked list of arcs contained in the given member. */
    1531static
    1533 const SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1534 spqr_member member /**< The given member */
    1535 )
    1536{
    1537 assert(dec);
    1538 assert(SPQRmemberIsValid(member));
    1539 assert(member < dec->memMembers);
    1540
    1541 return dec->members[member].firstArc;
    1542}
    1543
    1544/** Given the current arc, get the next arc of the linked list of arcs that are in the same member. */
    1545static
    1547 const SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1548 spqr_arc arc /**< The current arc */
    1549 )
    1550{
    1551 assert(dec);
    1552 assert(SPQRarcIsValid(arc));
    1553 assert(arc < dec->memArcs);
    1554
    1555 arc = dec->arcs[arc].arcListNode.next;
    1556 return arc;
    1557}
    1558
    1559/** Given the current arc, get the previous arc of the linked list of arcs that are in the same member. */
    1560static
    1562 const SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1563 spqr_arc arc /**< The current arc */
    1564 )
    1565{
    1566 assert(dec);
    1567 assert(SPQRarcIsValid(arc));
    1568 assert(arc < dec->memArcs);
    1569
    1570 arc = dec->arcs[arc].arcListNode.previous;
    1571 return arc;
    1572}
    1573
    1574/** Adds an arc to the linked list of arcs of the given member. */
    1575static
    1577 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1578 spqr_arc arc, /**< The arc to add */
    1579 spqr_member member /**< The member to add the arc to */
    1580 )
    1581{
    1582 spqr_arc firstMemberArc = getFirstMemberArc(dec, member);
    1583
    1584 if( SPQRarcIsValid(firstMemberArc))
    1585 {
    1586 spqr_arc lastMemberArc = getPreviousMemberArc(dec, firstMemberArc);
    1587 dec->arcs[arc].arcListNode.next = firstMemberArc;
    1588 dec->arcs[arc].arcListNode.previous = lastMemberArc;
    1589 dec->arcs[firstMemberArc].arcListNode.previous = arc;
    1590 dec->arcs[lastMemberArc].arcListNode.next = arc;
    1591 }
    1592 else
    1593 {
    1594 assert(dec->members[member].numArcs == 0);
    1595 dec->arcs[arc].arcListNode.next = arc;
    1596 dec->arcs[arc].arcListNode.previous = arc;
    1597 }
    1598 dec->members[member].firstArc = arc;
    1599 ++( dec->members[member].numArcs );
    1600}
    1601
    1602/** Create a new arc in the network matrix decomposition. */
    1603static
    1605 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1606 spqr_member member, /**< The member that contains the arc */
    1607 SCIP_Bool reversed, /**< Is the arc reversed or not? */
    1608 spqr_arc* pArc /**< out-pointer to the id that is assigned to the arc. */
    1609 )
    1610{
    1611 assert(dec);
    1612 assert(pArc);
    1613 assert(SPQRmemberIsInvalid(member) || memberIsRepresentative(dec, member));
    1614
    1615 spqr_arc idx = dec->firstFreeArc;
    1616 if( SPQRarcIsValid(idx))
    1617 {
    1618 dec->firstFreeArc = dec->arcs[idx].arcListNode.next;
    1619 }
    1620 else
    1621 {
    1622 //Enlarge array, no free nodes in arc list
    1623 int newSize = 2 * dec->memArcs;
    1624 SCIP_ALLOC( BMSreallocBlockMemoryArray(dec->env, &dec->arcs, dec->memArcs, newSize) );
    1625 for( int i = dec->memArcs + 1; i < newSize; ++i )
    1626 {
    1627 dec->arcs[i].arcListNode.next = i + 1;
    1629 }
    1630 dec->arcs[newSize - 1].arcListNode.next = SPQR_INVALID_ARC;
    1631 dec->firstFreeArc = dec->memArcs + 1;
    1632 idx = dec->memArcs;
    1633 dec->memArcs = newSize;
    1634 }
    1635
    1636 dec->arcs[idx].tail = SPQR_INVALID_NODE;
    1637 dec->arcs[idx].head = SPQR_INVALID_NODE;
    1638 dec->arcs[idx].member = member;
    1640 dec->arcs[idx].reversed = reversed;
    1641
    1646
    1647 dec->numArcs++;
    1648
    1649 *pArc = idx;
    1650
    1651 return SCIP_OKAY;
    1652}
    1653
    1654/** Create a new arc in the network matrix decomposition that is associated to the given row. */
    1655static
    1657 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1658 spqr_member member, /**< The member that contains the arc */
    1659 spqr_arc* pArc, /**< out-pointer to the id that is assigned to the arc. */
    1660 spqr_row row, /**< The row associated to the arc */
    1661 SCIP_Bool reversed /**< Is the arc reversed or not? */
    1662 )
    1663{
    1664 SCIP_CALL( createArc(dec, member, reversed, pArc) );
    1665 setDecompositionRowArc(dec, row, *pArc);
    1666 addArcToMemberArcList(dec, *pArc, member);
    1667 dec->arcs[*pArc].element = SPQRrowToElement(row);
    1668
    1669 return SCIP_OKAY;
    1670}
    1671
    1672/** Create a new arc in the network matrix decomposition that is associated to the given column. */
    1673static
    1675 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1676 spqr_member member, /**< The member that contains the arc */
    1677 spqr_arc* pArc, /**< out-pointer to the id that is assigned to the arc. */
    1678 spqr_col column, /**< The column associated to the arc */
    1679 SCIP_Bool reversed /**< Is the arc reversed or not? */
    1680 )
    1681{
    1682 SCIP_CALL( createArc(dec, member, reversed, pArc) );
    1683 setDecompositionColumnArc(dec, column, *pArc);
    1684 addArcToMemberArcList(dec, *pArc, member);
    1685 dec->arcs[*pArc].element = SPQRcolumnToElement(column);
    1686
    1687 return SCIP_OKAY;
    1688}
    1689
    1690/** Create a new member in the network matrix decomposition. */
    1691static
    1693 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1694 SPQRMemberType type, /**< The SPQR-type of the member */
    1695 spqr_member* pMember /**< out-pointer to the id that is assigned to the member */
    1696 )
    1697{
    1698 assert(dec);
    1699 assert(pMember);
    1700
    1701 if( dec->numMembers == dec->memMembers )
    1702 {
    1703 int newSize = dec->memMembers * 2;
    1704 SCIP_ALLOC( BMSreallocBlockMemoryArray(dec->env, &dec->members, dec->memMembers, newSize) );
    1705 dec->memMembers = newSize;
    1706 }
    1710 data->firstArc = SPQR_INVALID_ARC;
    1712 data->numArcs = 0;
    1714 data->type = type;
    1715
    1716 *pMember = dec->numMembers;
    1717
    1718 dec->numMembers++;
    1719 return SCIP_OKAY;
    1720}
    1721
    1722/** Create a new node in the network matrix decomposition. */
    1723static
    1725 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1726 spqr_node* pNode /**< out-pointer to the id that is assigned to the node */
    1727 )
    1728{
    1729 if( dec->numNodes == dec->memNodes )
    1730 {
    1731 int newSize = dec->memNodes * 2;
    1732 SCIP_ALLOC( BMSreallocBlockMemoryArray(dec->env, &dec->nodes, dec->memNodes, newSize) );
    1733 dec->memNodes = newSize;
    1734 }
    1735 *pNode = dec->numNodes;
    1738 dec->nodes[dec->numNodes].numArcs = 0;
    1739 dec->numNodes++;
    1740
    1741 return SCIP_OKAY;
    1742}
    1743
    1744/** Remove an arc from the linked list of arcs that are adjacent to a given node. */
    1745static
    1747 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1748 spqr_arc arc, /**< The arc to remove */
    1749 spqr_node node, /**< The node to remove the arc from */
    1750 SCIP_Bool nodeIsHead /**< Indicates whether the node is the arcs head, or tail */
    1751 )
    1752{
    1753 SPQRNetworkDecompositionArcListNode* arcListNode = nodeIsHead ? &dec->arcs[arc].headArcListNode
    1754 : &dec->arcs[arc].tailArcListNode;
    1755
    1756 if( dec->nodes[node].numArcs == 1 )
    1757 {
    1758 dec->nodes[node].firstArc = SPQR_INVALID_ARC;
    1759 }
    1760 else
    1761 {
    1762 spqr_arc next_arc = arcListNode->next;
    1763 spqr_arc prev_arc = arcListNode->previous;
    1765 findArcHead(dec, next_arc) == node ? &dec->arcs[next_arc].headArcListNode
    1766 : &dec->arcs[next_arc].tailArcListNode;
    1768 findArcHead(dec, prev_arc) == node ? &dec->arcs[prev_arc].headArcListNode
    1769 : &dec->arcs[prev_arc].tailArcListNode;
    1770
    1771 nextListNode->previous = prev_arc;
    1772 prevListNode->next = next_arc;
    1773
    1774 if( dec->nodes[node].firstArc == arc )
    1775 {
    1776 dec->nodes[node].firstArc = next_arc;
    1777 }
    1778 }
    1779 --( dec->nodes[node].numArcs );
    1780}
    1781
    1782/** Add an arc to the linked list of arcs that are adjacent to a given node. */
    1783static
    1785 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1786 spqr_arc arc, /**< The arc to add */
    1787 spqr_node node, /**< The node to add the arc to */
    1788 SCIP_Bool nodeIsHead /**< Indicates whether the node is the arcs head, or tail */
    1789 )
    1790{
    1791 assert(nodeIsRepresentative(dec, node));
    1792
    1793 spqr_arc firstNodeArc = getFirstNodeArc(dec, node);
    1794
    1795 SPQRNetworkDecompositionArcListNode* arcListNode = nodeIsHead ? &dec->arcs[arc].headArcListNode
    1796 : &dec->arcs[arc].tailArcListNode;
    1797 if( SPQRarcIsValid(firstNodeArc))
    1798 {
    1799 SCIP_Bool nextIsHead = findArcHead(dec, firstNodeArc) == node;
    1800 SPQRNetworkDecompositionArcListNode* nextListNode = nextIsHead ? &dec->arcs[firstNodeArc].headArcListNode
    1801 : &dec->arcs[firstNodeArc].tailArcListNode;
    1802 spqr_arc lastNodeArc = nextListNode->previous;
    1803
    1804 arcListNode->next = firstNodeArc;
    1805 arcListNode->previous = lastNodeArc;
    1806
    1807 SCIP_Bool previousIsHead = findArcHead(dec, lastNodeArc) == node;
    1808 SPQRNetworkDecompositionArcListNode* previousListNode = previousIsHead ? &dec->arcs[lastNodeArc].headArcListNode
    1809 : &dec->arcs[lastNodeArc].tailArcListNode;
    1810 previousListNode->next = arc;
    1811 nextListNode->previous = arc;
    1812 }
    1813 else
    1814 {
    1815 arcListNode->next = arc;
    1816 arcListNode->previous = arc;
    1817 }
    1818 dec->nodes[node].firstArc = arc;
    1819 ++dec->nodes[node].numArcs;
    1820 if( nodeIsHead )
    1821 {
    1822 dec->arcs[arc].head = node;
    1823 }
    1824 else
    1825 {
    1826 dec->arcs[arc].tail = node;
    1827 }
    1828}
    1829
    1830/** Initializes the data structures of the arcs head and tail nodes. */
    1831static
    1833 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1834 spqr_arc arc, /**< The arc to initialize */
    1835 spqr_node head, /**< The arc its head node*/
    1836 spqr_node tail /**< The arc its tail node*/
    1837 )
    1838{
    1839 addArcToNodeArcList(dec, arc, head, TRUE);
    1840 addArcToNodeArcList(dec, arc, tail, FALSE);
    1841}
    1842
    1843/** Deinitializes the data structures of the arcs head and tail nodes. */
    1844static
    1846 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1847 spqr_arc arc /**< The arc to deinitialize */
    1848 )
    1849{
    1850 removeArcFromNodeArcList(dec, arc, findArcHead(dec, arc), TRUE);
    1851 removeArcFromNodeArcList(dec, arc, findArcTail(dec, arc), FALSE);
    1852 dec->arcs[arc].head = SPQR_INVALID_NODE;
    1853 dec->arcs[arc].tail = SPQR_INVALID_NODE;
    1854}
    1855
    1856/** Change the arc's head node to a new node. */
    1857static
    1859 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1860 spqr_arc arc, /**< The given arc */
    1861 spqr_node oldHead, /**< The current head node of the arc */
    1862 spqr_node newHead /**< The new head node of the arc */
    1863 )
    1864{
    1865 assert(nodeIsRepresentative(dec, oldHead));
    1866 assert(nodeIsRepresentative(dec, newHead));
    1867
    1868 removeArcFromNodeArcList(dec, arc, oldHead, TRUE);
    1869 addArcToNodeArcList(dec, arc, newHead, TRUE);
    1870}
    1871
    1872/** Change the arc's head node to a new node. */
    1873static
    1875 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1876 spqr_arc arc, /**< The given arc */
    1877 spqr_node oldTail, /**< The current tail node of the arc */
    1878 spqr_node newTail /**< The new tail node of the arc */
    1879 )
    1880{
    1881 assert(nodeIsRepresentative(dec, oldTail));
    1882 assert(nodeIsRepresentative(dec, newTail));
    1883
    1884 removeArcFromNodeArcList(dec, arc, oldTail, FALSE);
    1885 addArcToNodeArcList(dec, arc, newTail, FALSE);
    1886}
    1887
    1888/** Returns the degree of the given node. */
    1889static
    1891 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1892 spqr_node node /**< The given node */
    1893 )
    1894{
    1895 assert(dec);
    1896 assert(SPQRnodeIsValid(node));
    1897 assert(node < dec->memNodes);
    1898
    1899 return dec->nodes[node].numArcs;
    1900}
    1901
    1902/** Get the SPQR-type of the given member. */
    1903static
    1905 const SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1906 spqr_member member /**< The given member */
    1907 )
    1908{
    1909 assert(dec);
    1910 assert(SPQRmemberIsValid(member));
    1911 assert(member < dec->memMembers);
    1912 assert(memberIsRepresentative(dec, member));
    1913
    1914 return dec->members[member].type;
    1915}
    1916
    1917/** Update the SPQR-type of the given member. */
    1918static
    1920 const SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1921 spqr_member member, /**< The member to update the type for */
    1922 SPQRMemberType type /**< The new SPQR-type of the member */
    1923 )
    1924{
    1925 assert(dec);
    1926 assert(SPQRmemberIsValid(member));
    1927 assert(member < dec->memMembers);
    1928 assert(memberIsRepresentative(dec, member));
    1929
    1930 dec->members[member].type = type;
    1931}
    1932
    1933/** Returns the virtual arc pointing to the parent member (in the arborescence) of the given member. */
    1934static
    1936 const SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1937 spqr_member member /**< The given member */
    1938 )
    1939{
    1940 assert(dec);
    1941 assert(SPQRmemberIsValid(member));
    1942 assert(member < dec->memMembers);
    1943 assert(memberIsRepresentative(dec, member));
    1944
    1945 return dec->members[member].markerToParent;
    1946}
    1947
    1948/** Updates the parent information of a member that is identified with another another member. */
    1949static
    1951 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1952 const spqr_member newMember, /**< The new large member containing both members */
    1953 const spqr_member toRemove /**< The member that was merged and removed */
    1954 )
    1955{
    1956 assert(memberIsRepresentative(dec, newMember));
    1957 assert(findMemberNoCompression(dec, toRemove) == newMember);
    1958
    1959 dec->members[newMember].markerOfParent = dec->members[toRemove].markerOfParent;
    1960 dec->members[newMember].markerToParent = dec->members[toRemove].markerToParent;
    1961 dec->members[newMember].parentMember = dec->members[toRemove].parentMember;
    1962
    1963 dec->members[toRemove].markerOfParent = SPQR_INVALID_ARC;
    1964 dec->members[toRemove].markerToParent = SPQR_INVALID_ARC;
    1965 dec->members[toRemove].parentMember = SPQR_INVALID_MEMBER;
    1966}
    1967
    1968/** Returns the virtual arc of the parent member that points to the given member. */
    1969static
    1971 const SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1972 spqr_member member /**< The given member */
    1973 )
    1974{
    1975 assert(dec);
    1976 assert(SPQRmemberIsValid(member));
    1977 assert(member < dec->memMembers);
    1978 assert(memberIsRepresentative(dec, member));
    1979
    1980 return dec->members[member].markerOfParent;
    1981}
    1982
    1983/** Returns the number of arcs in the member. */
    1984static
    1986 const SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    1987 spqr_member member /**< The member to get the number of arcs of */
    1988 )
    1989{
    1990 assert(dec);
    1991 assert(SPQRmemberIsValid(member));
    1992 assert(member < dec->memMembers);
    1993 assert(memberIsRepresentative(dec, member));
    1994
    1995 return dec->members[member].numArcs;
    1996}
    1997
    1998/** Returns the number of nodes in complete network matrix decomposition. */
    1999static
    2001 const SCIP_NETMATDECDATA* dec /**< The network matrix decomposition */
    2002 )
    2003{
    2004 assert(dec);
    2005
    2006 return dec->numNodes;
    2007}
    2008
    2009/** Returns the number of members in complete network matrix decomposition. */
    2010static
    2012 const SCIP_NETMATDECDATA* dec /**< The network matrix decomposition */
    2013 )
    2014{
    2015 assert(dec);
    2016
    2017 return dec->numMembers;
    2018}
    2019
    2020/** Creates a standalone parallel member with the given row and columns that is not connected to other members of the
    2021 * network matrix decomposition.
    2022 *
    2023 * New arcs are created for the given row and columns.
    2024 */
    2025static
    2027 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    2028 spqr_col* columns, /**< The columns in the parallel member */
    2029 SCIP_Bool* reversed, /**< Array indicating the direction of each column edge */
    2030 int num_columns, /**< The number of columns in the parallel member */
    2031 spqr_row row, /**< The row in the parallel member */
    2032 spqr_member* pMember /**< out-pointer to the new parallel member id */
    2033 )
    2034{
    2035 spqr_member member;
    2036 SCIP_CALL( createMember(dec, num_columns <= 1 ? SPQR_MEMBERTYPE_LOOP : SPQR_MEMBERTYPE_PARALLEL, &member) );
    2037
    2038 spqr_arc row_arc;
    2039 SCIP_CALL( createRowArc(dec, member, &row_arc, row, num_columns <= 1) );
    2040
    2041 spqr_arc col_arc;
    2042 for( int i = 0; i < num_columns; ++i )
    2043 {
    2044 SCIP_CALL( createColumnArc(dec, member, &col_arc, columns[i], reversed[i]) );
    2045 }
    2046 *pMember = member;
    2047
    2049
    2050 return SCIP_OKAY;
    2051}
    2052
    2053/** Creates a parallel member with the given row and columns is connected to other members of the
    2054 * network matrix decomposition.
    2055 *
    2056 * New arcs are created for the given row and columns.
    2057 */
    2058static
    2060 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    2061 spqr_col* columns, /**< The columns in the parallel member */
    2062 SCIP_Bool* reversed, /**< Array indicating the direction of each column edge */
    2063 int num_columns, /**< The number of columns in the parallel member */
    2064 spqr_row row, /**< The row in the parallel member */
    2065 spqr_member* pMember /**< out-pointer to the new parallel member id */
    2066 )
    2067{
    2068 spqr_member member;
    2070
    2071 spqr_arc row_arc;
    2072 SCIP_CALL( createRowArc(dec, member, &row_arc, row, FALSE) );
    2073
    2074 spqr_arc col_arc;
    2075 for( int i = 0; i < num_columns; ++i )
    2076 {
    2077 SCIP_CALL( createColumnArc(dec, member, &col_arc, columns[i], reversed[i]) );
    2078 }
    2079 *pMember = member;
    2080
    2081 return SCIP_OKAY;
    2082}
    2083
    2084/** Creates a standalone series member with the given row and columns that is not connected to other members of the
    2085 * network matrix decomposition.
    2086 *
    2087 * New arcs are created for the given rows and column.
    2088 */
    2089static
    2091 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    2092 spqr_row* rows, /**< The rows in the series member */
    2093 SCIP_Bool* reversed, /**< Array indicating the direction of each row edge */
    2094 int numRows, /**< The number of rows in the parallel member */
    2095 spqr_col col, /**< The column in the parallel member */
    2096 spqr_member* pMember /**< out-pointer to the new series member id */
    2097 )
    2098{
    2099 spqr_member member;
    2100 SCIP_CALL( createMember(dec, numRows <= 1 ? SPQR_MEMBERTYPE_LOOP : SPQR_MEMBERTYPE_SERIES, &member) );
    2101
    2102 spqr_arc colArc;
    2103 SCIP_CALL( createColumnArc(dec, member, &colArc, col, FALSE) );
    2104
    2105 spqr_arc rowArc;
    2106 for( int i = 0; i < numRows; ++i )
    2107 {
    2108 SCIP_CALL( createRowArc(dec, member, &rowArc, rows[i], !reversed[i]) );
    2109 }
    2110 *pMember = member;
    2112
    2113 return SCIP_OKAY;
    2114}
    2115
    2116/** Creates a series member with the given row and columns that is connected to some other member of the
    2117 * network matrix decomposition.
    2118 *
    2119 * New arcs are created for the given rows and column.
    2120 */
    2121static
    2123 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    2124 spqr_row* rows, /**< The rows in the series member */
    2125 SCIP_Bool* reversed, /**< Array indicating the direction of each row edge */
    2126 int numRows, /**< The number of rows in the parallel member */
    2127 spqr_col col, /**< The column in the parallel member */
    2128 spqr_member* pMember /**< out-pointer to the new series member id */
    2129 )
    2130{
    2131 spqr_member member;
    2133
    2134 spqr_arc colArc;
    2135 SCIP_CALL( createColumnArc(dec, member, &colArc, col, FALSE) );
    2136
    2137 spqr_arc rowArc;
    2138 for( int i = 0; i < numRows; ++i )
    2139 {
    2140 SCIP_CALL( createRowArc(dec, member, &rowArc, rows[i], !reversed[i]) );
    2141 }
    2142 *pMember = member;
    2143
    2144 return SCIP_OKAY;
    2145}
    2146
    2147/** Remove an arc from the linked list containing all arcs of a single member. */
    2148static
    2150 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    2151 spqr_arc arc, /**< The arc to remove */
    2152 spqr_member member /**< The member to remove it from */
    2153 )
    2154{
    2155 assert(findArcMemberNoCompression(dec, arc) == member);
    2156 assert(memberIsRepresentative(dec, member));
    2157
    2158 if( dec->members[member].numArcs == 1 )
    2159 {
    2160 dec->members[member].firstArc = SPQR_INVALID_ARC;
    2161 }
    2162 else
    2163 {
    2164 spqr_arc nextArc = dec->arcs[arc].arcListNode.next;
    2165 spqr_arc prevArc = dec->arcs[arc].arcListNode.previous;
    2166
    2167 dec->arcs[nextArc].arcListNode.previous = prevArc;
    2168 dec->arcs[prevArc].arcListNode.next = nextArc;
    2169
    2170 if( dec->members[member].firstArc == arc )
    2171 {
    2172 dec->members[member].firstArc = nextArc;
    2173 }
    2174 }
    2175
    2176 --( dec->members[member].numArcs );
    2177}
    2178
    2179/** Data structure for the algorithms to find fundamental cycle within the network matrix decomposition */
    2180typedef struct
    2181{
    2185
    2186/** Processes a single arc for the algorithm to find cycles in the network matrix decomposition.
    2187 *
    2188 * if virtual, pushes it on the callstack, if non-virtual, adds it to the found cycle
    2189 */
    2190static
    2192 spqr_row* cyclearcs, /**< The found cycle so far */
    2193 int* num_cycle_arcs, /**< The number of arcs in the cycle so far */
    2194 FindCycleCall* callStack, /**< The call stack of virtual edges to process still */
    2195 int* callStackSize, /**< The number of virtual edges on the callstack */
    2196 spqr_arc arc, /**< The current arc to process */
    2197 const SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    2198 SCIP_Bool* cycledir, /**< Whether the current arc is reversed w.r.t to the cycle/path */
    2199 SCIP_Bool arcIsReversed /**< The arcIsReversed status from the network matrix decomposition */
    2200 )
    2201{
    2202 assert(arcIsTree(dec, arc));
    2203
    2204 if( !arcIsChildMarker(dec, arc))
    2205 {
    2206 spqr_member current_member = findArcMemberNoCompression(dec, arc);
    2207 if( markerToParent(dec, current_member) == arc )
    2208 {
    2209 spqr_arc other_arc = markerOfParent(dec, current_member);
    2210 assert(!arcIsTree(dec, other_arc));
    2211 callStack[*callStackSize].arc = other_arc;
    2212 callStack[*callStackSize].reversed = arcIsReversed;
    2213 ++( *callStackSize );
    2214 }
    2215 else
    2216 {
    2217 spqr_element element = arcGetElement(dec, arc);
    2218 assert(SPQRelementIsRow(element));
    2219 spqr_row row = SPQRelementToRow(element);
    2220 cyclearcs[*num_cycle_arcs] = row;
    2221 cycledir[*num_cycle_arcs] = arcIsReversed;
    2222 ++( *num_cycle_arcs );
    2223 }
    2224 }
    2225 else
    2226 {
    2227 spqr_member child_member = findArcChildMemberNoCompression(dec, arc);
    2228 spqr_arc other_arc = markerToParent(dec, child_member);
    2229 assert(!arcIsTree(dec, other_arc));
    2230 callStack[*callStackSize].arc = other_arc;
    2231 callStack[*callStackSize].reversed = arcIsReversed;
    2232 ++( *callStackSize );
    2233 }
    2234}
    2235
    2236/** Find the fundamental path of a cycle.
    2237 *
    2238 * This is a slow method and only intended for debugging and testing.
    2239 */
    2240static
    2242 const SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    2243 spqr_col column, /**< The column to find the fundamental path for */
    2244 spqr_row* output, /**< preallocated array to store fundamental path in. Must have at least
    2245 * the number of rows in the decomposition allocated */
    2246 SCIP_Bool* computedSignStorage /**< Boolean array for storage of whether the path occurs forwards or
    2247 * backwards. Must have at least the same size as output array. */
    2248 )
    2249{
    2250 /*Basic idea; for each component, do a dfs over the tree formed by the row arcs to find the relevant edges.
    2251 This is easy for SPQ-nodes, for R nodes we need to search */
    2252 spqr_arc arc = getDecompositionColumnArc(dec, column);
    2253 if( SPQRarcIsInvalid(arc))
    2254 {
    2255 return 0;
    2256 }
    2257 int num_rows = 0;
    2258
    2259 FindCycleCall* callStack;
    2260 if( BMSallocBlockMemoryArray(dec->env, &callStack, dec->memRows) == NULL )
    2261 {
    2262 return -1;
    2263 }
    2264 int callStackSize = 1;
    2265 callStack[0].arc = arc;
    2266 callStack[0].reversed = FALSE;
    2267
    2268 SCIP_Bool* nodeVisited;
    2269 if( BMSallocBlockMemoryArray(dec->env, &nodeVisited, dec->numNodes) == NULL )
    2270 {
    2271 return -1;
    2272 }
    2273 for( int i = 0; i < dec->numNodes; ++i )
    2274 {
    2275 nodeVisited[i] = FALSE;
    2276 }
    2277
    2278 typedef struct
    2279 {
    2280 spqr_node node; /* cppcheck-suppress unusedStructMember */
    2281 spqr_arc nodeArc; /* cppcheck-suppress unusedStructMember */
    2282 } DFSCallData;
    2283 DFSCallData* pathSearchCallStack;
    2284 if( BMSallocBlockMemoryArray(dec->env, &pathSearchCallStack, dec->numNodes) == NULL )
    2285 {
    2286 return -1;
    2287 }
    2288 int pathSearchCallStackSize = 0;
    2289
    2290 while( callStackSize > 0 )
    2291 {
    2292 spqr_arc column_arc = callStack[callStackSize - 1].arc;
    2293 SCIP_Bool reverseEverything = callStack[callStackSize - 1].reversed;
    2294 --callStackSize;
    2295 spqr_member column_arc_member = findArcMemberNoCompression(dec, column_arc);
    2296 switch( getMemberType(dec, column_arc_member))
    2297 {
    2299 {
    2300 spqr_node source = findEffectiveArcTailNoCompression(dec, column_arc);
    2301 spqr_node target = findEffectiveArcHeadNoCompression(dec, column_arc);
    2302
    2303 assert(pathSearchCallStackSize == 0);
    2304 pathSearchCallStack[0].node = source;
    2305 pathSearchCallStack[0].nodeArc = getFirstNodeArc(dec, source);
    2306 pathSearchCallStackSize++;
    2307 while( pathSearchCallStackSize > 0 )
    2308 {
    2309 DFSCallData* dfsData = &pathSearchCallStack[pathSearchCallStackSize - 1];
    2310 nodeVisited[dfsData->node] = TRUE;
    2311 //cannot be a tree arc which is its parent
    2312 if( arcIsTree(dec, dfsData->nodeArc) &&
    2313 ( pathSearchCallStackSize <= 1 ||
    2314 dfsData->nodeArc != pathSearchCallStack[pathSearchCallStackSize - 2].nodeArc ))
    2315 {
    2318 spqr_node other = head == dfsData->node ? tail : head;
    2319 assert(other != dfsData->node);
    2320 assert(!nodeVisited[other]);
    2321 if( other == target )
    2322 {
    2323 break;
    2324 }
    2325 //We go up a level: add new node to the call stack
    2326
    2327 pathSearchCallStack[pathSearchCallStackSize].node = other;
    2328 pathSearchCallStack[pathSearchCallStackSize].nodeArc = getFirstNodeArc(dec, other);
    2329 ++pathSearchCallStackSize;
    2330 continue;
    2331 }
    2332 do
    2333 {
    2334 dfsData->nodeArc = getNextNodeArcNoCompression(dec, dfsData->nodeArc, dfsData->node);
    2335 if( dfsData->nodeArc == getFirstNodeArc(dec, dfsData->node))
    2336 {
    2337 --pathSearchCallStackSize;
    2338 dfsData = &pathSearchCallStack[pathSearchCallStackSize - 1];
    2339 }
    2340 else
    2341 {
    2342 break;
    2343 }
    2344 }
    2345 while( pathSearchCallStackSize > 0 );
    2346 }
    2347 for( int i = 0; i < pathSearchCallStackSize; ++i )
    2348 {
    2349 if( arcIsTree(dec, pathSearchCallStack[i].nodeArc))
    2350 {
    2351 SCIP_Bool arcReversedInPath =
    2352 findEffectiveArcHeadNoCompression(dec, pathSearchCallStack[i].nodeArc) ==
    2353 pathSearchCallStack[i].node;
    2354 process_arc(output, &num_rows, callStack, &callStackSize, pathSearchCallStack[i].nodeArc, dec,
    2355 computedSignStorage, arcReversedInPath != reverseEverything);
    2356 }
    2357 }
    2358
    2359 pathSearchCallStackSize = 0;
    2360 break;
    2361 }
    2363 {
    2364 SCIP_Bool columnReversed = arcIsReversedNonRigid(dec, column_arc);
    2365
    2366 spqr_arc first_arc = getFirstMemberArc(dec, column_arc_member);
    2367 spqr_arc iter_arc = first_arc;
    2368 int tree_count = 0;
    2369 do
    2370 {
    2371 if( arcIsTree(dec, iter_arc))
    2372 {
    2373 SCIP_Bool treeIsReversed = arcIsReversedNonRigid(dec, iter_arc);
    2374 process_arc(output, &num_rows, callStack, &callStackSize, iter_arc, dec,
    2375 computedSignStorage, ( columnReversed != treeIsReversed ) != reverseEverything);
    2376 tree_count++;
    2377 }
    2378 iter_arc = getNextMemberArc(dec, iter_arc);
    2379 }
    2380 while( iter_arc != first_arc );
    2381 if( tree_count != 1 )
    2382 {
    2383 return -1;
    2384 }
    2385 break;
    2386 }
    2389 {
    2390 SCIP_Bool columnReversed = arcIsReversedNonRigid(dec, column_arc);
    2391 spqr_arc first_arc = getFirstMemberArc(dec, column_arc_member);
    2392 spqr_arc iter_arc = first_arc;
    2393 int nontree_count = 0;
    2394 do
    2395 {
    2396 if( arcIsTree(dec, iter_arc))
    2397 {
    2398 SCIP_Bool treeIsReversed = arcIsReversedNonRigid(dec, iter_arc);
    2399 process_arc(output, &num_rows, callStack, &callStackSize, iter_arc, dec,
    2400 computedSignStorage, ( columnReversed == treeIsReversed ) != reverseEverything);
    2401 }
    2402 else
    2403 {
    2404 nontree_count++;
    2405 }
    2406 iter_arc = getNextMemberArc(dec, iter_arc);
    2407 }
    2408 while( iter_arc != first_arc );
    2409 if( nontree_count != 1 )
    2410 {
    2411 return -1;
    2412 }
    2413 break;
    2414 }
    2416 SCIPABORT();
    2417 return -1;
    2418 }
    2419 }
    2420 }
    2421 BMSfreeBlockMemoryArray(dec->env, &pathSearchCallStack, dec->numNodes);
    2422 BMSfreeBlockMemoryArray(dec->env, &nodeVisited, dec->numNodes);
    2423 BMSfreeBlockMemoryArray(dec->env, &callStack, dec->memRows);
    2424
    2425 return num_rows;
    2426}
    2427
    2428/** Given a cycle (e.g. a matrix column), checks if the column's cycle matches the cycle in the
    2429 * network matrix decomposition.
    2430 */
    2431static
    2433 BMS_BUFMEM* bufmem, /**< Buffer memory */
    2434 const SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    2435 int column, /**< The column to check */
    2436 const int* nonzrowidx, /**< Array with the nonzero row indices of the column */
    2437 const double* nonzvals, /**< Array with the nonzero entry values of the column's row indices */
    2438 int num_rows, /**< The number of nonzeros in the column */
    2439 int* pathrowstorage, /**< Temporary storage vector for storing the fundamental path. Must have
    2440 * at least as many entries allocated as the number of rows in dec. */
    2441 SCIP_Bool* pathsignstorage /**< Temporary storage for the fundamental path directions. Must have
    2442 * at least as many entries allocated as the number of rows in dec. */
    2443 )
    2444{
    2445 int num_found_rows = decompositionGetFundamentalCycleRows(dec, column, pathrowstorage, pathsignstorage);
    2446
    2447 if( num_found_rows != num_rows )
    2448 {
    2449 return FALSE;
    2450 }
    2451 if( num_rows == 0 )
    2452 {
    2453 return TRUE;
    2454 }
    2455 spqr_row * pathRow;
    2456 int * pathRowReversed;
    2457
    2458 if( BMSallocBufferMemoryArray(bufmem, &pathRow, num_rows) == NULL )
    2459 {
    2460 return FALSE;
    2461 }
    2462
    2463 if( BMSallocBufferMemoryArray(bufmem, &pathRowReversed, num_rows) == NULL )
    2464 {
    2465 BMSfreeBufferMemoryArray(bufmem, &pathRow);
    2466 return FALSE;
    2467 }
    2468 for( int i = 0; i < num_rows; ++i )
    2469 {
    2470 pathRow[i] = pathrowstorage[i];
    2471 pathRowReversed[i] = pathsignstorage[i] ? 1 : 0;
    2472 }
    2473 SCIPsortIntInt(pathRow, pathRowReversed, num_rows);
    2474
    2475 spqr_row * secondPathRow;
    2476 int * secondPathRowReversed;
    2477 if( BMSallocBufferMemoryArray(bufmem, &secondPathRow, num_rows) == NULL )
    2478 {
    2479 BMSfreeBufferMemoryArray(bufmem, &pathRow);
    2480 BMSfreeBufferMemoryArray(bufmem, &pathRowReversed);
    2481 return FALSE;
    2482 }
    2483
    2484 if( BMSallocBufferMemoryArray(bufmem, &secondPathRowReversed, num_rows) == NULL )
    2485 {
    2486 BMSfreeBufferMemoryArray(bufmem, &pathRow);
    2487 BMSfreeBufferMemoryArray(bufmem, &pathRowReversed);
    2488 BMSfreeBufferMemoryArray(bufmem, &secondPathRow);
    2489 return FALSE;
    2490 }
    2491 for( int i = 0; i < num_rows; ++i )
    2492 {
    2493 secondPathRow[i] = nonzrowidx[i];
    2494 secondPathRowReversed[i] = nonzvals[i] < 0.0 ? 1 : 0;
    2495 }
    2496
    2497 SCIPsortIntInt(secondPathRow, secondPathRowReversed, num_rows);
    2498
    2499 SCIP_Bool good = TRUE;
    2500 for( int i = 0; i < num_rows; ++i )
    2501 {
    2502 if( pathRow[i] != secondPathRow[i] || pathRowReversed[i] != secondPathRowReversed[i] )
    2503 {
    2504 good = FALSE;
    2505 break;
    2506 }
    2507 }
    2508 BMSfreeBufferMemoryArray(bufmem, &secondPathRowReversed);
    2509 BMSfreeBufferMemoryArray(bufmem, &secondPathRow);
    2510 BMSfreeBufferMemoryArray(bufmem, &pathRowReversed);
    2511 BMSfreeBufferMemoryArray(bufmem, &pathRow);
    2512
    2513 return good;
    2514}
    2515
    2516/** Returns the largest member id that is currently in the decomposition. */
    2517static
    2519 const SCIP_NETMATDECDATA* dec /**< The network matrix decomposition */
    2520 )
    2521{
    2522 return dec->numMembers;
    2523}
    2524
    2525/** Returns the largest arc id that is currently in the decomposition. */
    2526static
    2528 const SCIP_NETMATDECDATA* dec /**< The network matrix decomposition */
    2529 )
    2530{
    2531 return dec->numArcs;
    2532}
    2533
    2534/** Returns the largest node id that is currently in the decomposition. */
    2535static
    2537 const SCIP_NETMATDECDATA* dec /**< The network matrix decomposition */
    2538 )
    2539{
    2540 return dec->numNodes;
    2541}
    2542
    2543/** Returns the number of SPQR trees in the SPQR forest, i.e. the number of connected components. */
    2544static
    2546 const SCIP_NETMATDECDATA* dec /**< The network matrix decomposition */
    2547 )
    2548{
    2549 return dec->numConnectedComponents;
    2550}
    2551
    2552/** Creates a child marker in the network decomposition. */
    2553static
    2555 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    2556 spqr_member member, /**< The member to create the arc in */
    2557 spqr_member child, /**< The member that the arc points to */
    2558 SCIP_Bool isTree, /**< Indicates if the new arc is a tree arc */
    2559 spqr_arc* pArc, /**< Out-pointer to store the new arc's id */
    2560 SCIP_Bool reversed /**< Sets the reversed field of the arc */
    2561 )
    2562{
    2563 SCIP_CALL( createArc(dec, member, reversed, pArc) );
    2564 dec->arcs[*pArc].element = isTree ? MARKER_ROW_ELEMENT : MARKER_COLUMN_ELEMENT;
    2565 dec->arcs[*pArc].childMember = child;
    2566
    2567 addArcToMemberArcList(dec, *pArc, member);
    2568
    2569 return SCIP_OKAY;
    2570}
    2571
    2572/** Creates a parent marker in the network decomposition. */
    2573static
    2575 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    2576 spqr_member member, /**< The member to create the arc in */
    2577 SCIP_Bool isTree, /**< Indicates if the new arc is a tree arc */
    2578 spqr_member parent, /**< The member that the arc points to */
    2579 spqr_arc parentMarker, /**< The parent arc in the parent that points to this member */
    2580 spqr_arc* arc, /**< Out-pointer to store the new arc's id */
    2581 SCIP_Bool reversed /**< Sets the reversed field of the arc */
    2582 )
    2583{
    2584 SCIP_CALL( createArc(dec, member, reversed, arc) );
    2585 dec->arcs[*arc].element = isTree ? MARKER_ROW_ELEMENT : MARKER_COLUMN_ELEMENT;
    2586
    2587 addArcToMemberArcList(dec, *arc, member);
    2588
    2589 dec->members[member].parentMember = parent;
    2590 dec->members[member].markerOfParent = parentMarker;
    2591 dec->members[member].markerToParent = *arc;
    2592
    2593 return SCIP_OKAY;
    2594}
    2595
    2596/** Creates a child-marker parent-marker pair in the network decomposition. */
    2597static
    2599 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    2600 spqr_member parentMember, /**< The parent member */
    2601 spqr_member childMember, /**< The child member */
    2602 SCIP_Bool parentIsTree, /**< Is the edge in the parent member (the child marker) a tree edge? */
    2603 SCIP_Bool childMarkerReversed, /**< Is the child marker arc reversed?*/
    2604 SCIP_Bool parentMarkerReversed /**< IS the parent marker arc reversed? */
    2605 )
    2606{
    2607 spqr_arc parentToChildMarker = SPQR_INVALID_ARC;
    2608 SCIP_CALL( createChildMarker(dec, parentMember, childMember, parentIsTree, &parentToChildMarker, childMarkerReversed) );
    2609
    2610 spqr_arc childToParentMarker = SPQR_INVALID_ARC;
    2611 SCIP_CALL( createParentMarker(dec, childMember, !parentIsTree, parentMember, parentToChildMarker,
    2612 &childToParentMarker, parentMarkerReversed) );
    2613
    2614 return SCIP_OKAY;
    2615}
    2616
    2617/** Creates a child-marker parent-marker pair in the network decomposition, and returns the assigned arc id's. */
    2618static
    2620 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    2621 spqr_member parentMember, /**< The parent member */
    2622 spqr_member childMember, /**< The child member */
    2623 SCIP_Bool parentIsTree, /**< Is the edge in the parent member (the child marker) a tree edge? */
    2624 SCIP_Bool childMarkerReversed, /**< Is the child marker arc reversed?*/
    2625 SCIP_Bool parentMarkerReversed, /**< IS the parent marker arc reversed? */
    2626 spqr_arc* parentToChild, /**< Output-pointer containing arc id of the arc in the parent member */
    2627 spqr_arc* childToParent /**< Output-pointer containing arc id of the arc in the child member */
    2628 )
    2629{
    2630 SCIP_CALL( createChildMarker(dec, parentMember, childMember, parentIsTree, parentToChild, childMarkerReversed) );
    2631 SCIP_CALL( createParentMarker(dec, childMember, !parentIsTree, parentMember, *parentToChild, childToParent,
    2632 parentMarkerReversed) );
    2633
    2634 return SCIP_OKAY;
    2635}
    2636
    2637/** Moves a given arc from one member to another, updating the linked lists it is contained in and the parent/child
    2638 * information of the relevant members.
    2639 */
    2640static
    2642 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    2643 spqr_arc arc, /**< The arc to move */
    2644 spqr_member oldMember, /**< The member that currently contains the arc */
    2645 spqr_member newMember /**< The member to move the arc to */
    2646 )
    2647{
    2648 assert(SPQRarcIsValid(arc));
    2649 assert(arc < dec->memArcs);
    2650 assert(dec);
    2651
    2652 assert(memberIsRepresentative(dec, oldMember));
    2653 assert(memberIsRepresentative(dec, newMember));
    2654 //Need to change the arc's member, remove it from the current member list and add it to the new member list
    2655 assert(findArcMemberNoCompression(dec, arc) == oldMember);
    2656
    2657 removeArcFromMemberArcList(dec, arc, oldMember);
    2658 addArcToMemberArcList(dec, arc, newMember);
    2659
    2660 dec->arcs[arc].member = newMember;
    2661
    2662 //If this arc has a childMember, update the information correctly!
    2663 spqr_member childMember = dec->arcs[arc].childMember;
    2664 if( SPQRmemberIsValid(childMember))
    2665 {
    2666 spqr_member childRepresentative = findArcChildMember(dec, arc);
    2667 dec->members[childRepresentative].parentMember = newMember;
    2668 }
    2669 //If this arc is a marker to the parent, update the child arc marker of the parent to reflect the move
    2670 if( dec->members[oldMember].markerToParent == arc )
    2671 {
    2672 dec->members[newMember].markerToParent = arc;
    2673 dec->members[newMember].parentMember = dec->members[oldMember].parentMember;
    2674 dec->members[newMember].markerOfParent = dec->members[oldMember].markerOfParent;
    2675
    2676 assert(findArcChildMemberNoCompression(dec, dec->members[oldMember].markerOfParent) == oldMember);
    2677 dec->arcs[dec->members[oldMember].markerOfParent].childMember = newMember;
    2678 }
    2679}
    2680
    2681/** Merges the arc linked list of two members into one linked list. */
    2682static
    2684 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    2685 spqr_member toMergeInto, /**< The member id that gets the new large linked list containing both */
    2686 spqr_member toRemove /**< The member id that is invalidated, whose linked list is moved away. */
    2687 )
    2688{
    2689 spqr_arc firstIntoArc = getFirstMemberArc(dec, toMergeInto);
    2690 spqr_arc firstFromArc = getFirstMemberArc(dec, toRemove);
    2691 assert(SPQRarcIsValid(firstIntoArc));
    2692 assert(SPQRarcIsValid(firstFromArc));
    2693
    2694 spqr_arc lastIntoArc = getPreviousMemberArc(dec, firstIntoArc);
    2695 spqr_arc lastFromArc = getPreviousMemberArc(dec, firstFromArc);
    2696
    2697 //Relink linked lists to merge them effectively
    2698 dec->arcs[firstIntoArc].arcListNode.previous = lastFromArc;
    2699 dec->arcs[lastIntoArc].arcListNode.next = firstFromArc;
    2700 dec->arcs[firstFromArc].arcListNode.previous = lastIntoArc;
    2701 dec->arcs[lastFromArc].arcListNode.next = firstIntoArc;
    2702
    2703 //Clean up old
    2704 dec->members[toMergeInto].numArcs += dec->members[toRemove].numArcs;
    2705 dec->members[toRemove].numArcs = 0;
    2706 dec->members[toRemove].firstArc = SPQR_INVALID_ARC;
    2707}
    2708
    2709/** Changes the type of a member from loop to series. */
    2710static
    2712 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    2713 spqr_member member /**< The member whose type is changed */
    2714 )
    2715{
    2716 assert(SPQRmemberIsValid(member));
    2717 assert(member < dec->memMembers);
    2718 assert(dec);
    2719 assert(( getMemberType(dec, member) == SPQR_MEMBERTYPE_PARALLEL ||
    2720 getMemberType(dec, member) == SPQR_MEMBERTYPE_SERIES ||
    2721 getMemberType(dec, member) == SPQR_MEMBERTYPE_LOOP ) &&
    2722 getNumMemberArcs(dec, member) == 2);
    2723 assert(memberIsRepresentative(dec, member));
    2724 dec->members[member].type = SPQR_MEMBERTYPE_SERIES;
    2725}
    2726
    2727/** Changes the type of a member from loop to parallel. */
    2728static
    2730 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    2731 spqr_member member /**< The member whose type is changed */
    2732 )
    2733{
    2734 assert(SPQRmemberIsValid(member));
    2735 assert(member < dec->memMembers);
    2736 assert(dec);
    2737 assert(( getMemberType(dec, member) == SPQR_MEMBERTYPE_PARALLEL ||
    2738 getMemberType(dec, member) == SPQR_MEMBERTYPE_SERIES ||
    2739 getMemberType(dec, member) == SPQR_MEMBERTYPE_LOOP ) &&
    2740 getNumMemberArcs(dec, member) == 2);
    2741 assert(memberIsRepresentative(dec, member));
    2742 dec->members[member].type = SPQR_MEMBERTYPE_PARALLEL;
    2743}
    2744
    2745/** Checks if the network decomposition is minimal, i.e. if it does not contain two adjacent parallel or series
    2746 * members.
    2747 */
    2748static
    2750 const SCIP_NETMATDECDATA* dec /**< The network matrix decomposition */
    2751 )
    2752{
    2753 //Relies on parents/children etc. being set correctly in the tree
    2754 SCIP_Bool isMinimal = TRUE;
    2755 for( spqr_member member = 0; member < dec->numMembers; ++member )
    2756 {
    2757 if( !memberIsRepresentative(dec, member) || getMemberType(dec, member) == SPQR_MEMBERTYPE_UNASSIGNED )
    2758 {
    2759 continue;
    2760 }
    2761 spqr_member memberParent = findMemberParentNoCompression(dec, member);
    2762 if( SPQRmemberIsValid(memberParent))
    2763 {
    2764 assert(memberIsRepresentative(dec, memberParent));
    2765 SPQRMemberType memberType = getMemberType(dec, member);
    2766 SPQRMemberType parentType = getMemberType(dec, memberParent);
    2767 if( memberType == parentType && memberType != SPQR_MEMBERTYPE_RIGID )
    2768 {
    2769 isMinimal = FALSE;
    2770 break;
    2771 }
    2772 }
    2773 }
    2774 return isMinimal;
    2775}
    2776
    2777/** Decreases the count of the number of connected components in the network matrix decomposition. */
    2778static
    2780 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    2781 int by /**< The number of connected components to remove. */
    2782 )
    2783{
    2784 dec->numConnectedComponents -= by;
    2785 assert(dec->numConnectedComponents >= 1);
    2786}
    2787
    2788/** Reorders the arborescence of the SPQR that contains a given member so that the given member becomes the new root
    2789 * of the arborescence.
    2790 */
    2791static
    2793 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    2794 spqr_member newRoot /**< The member to make the new root */
    2795 )
    2796{
    2797 assert(dec);
    2798 assert(memberIsRepresentative(dec, newRoot));
    2799 //If the newRoot has no parent, it is already the root, so then there's no need to reorder.
    2800 if( SPQRmemberIsValid(dec->members[newRoot].parentMember))
    2801 {
    2802 spqr_member member = findMemberParent(dec, newRoot);
    2803 spqr_member newParent = newRoot;
    2804 spqr_arc newMarkerToParent = dec->members[newRoot].markerOfParent;
    2805 spqr_arc markerOfNewParent = dec->members[newRoot].markerToParent;
    2806
    2807 //Recursively update the parent
    2808 do
    2809 {
    2810 assert(SPQRmemberIsValid(member));
    2811 assert(SPQRmemberIsValid(newParent));
    2812 spqr_member oldParent = findMemberParent(dec, member);
    2813 spqr_arc oldMarkerToParent = dec->members[member].markerToParent;
    2814 spqr_arc oldMarkerOfParent = dec->members[member].markerOfParent;
    2815
    2816 dec->members[member].markerToParent = newMarkerToParent;
    2817 dec->members[member].markerOfParent = markerOfNewParent;
    2818 dec->members[member].parentMember = newParent;
    2819 dec->arcs[markerOfNewParent].childMember = member;
    2820 dec->arcs[newMarkerToParent].childMember = SPQR_INVALID_MEMBER;
    2821
    2822 if( SPQRmemberIsValid(oldParent))
    2823 {
    2824 newParent = member;
    2825 member = oldParent;
    2826 newMarkerToParent = oldMarkerOfParent;
    2827 markerOfNewParent = oldMarkerToParent;
    2828 }
    2829 else
    2830 {
    2831 break;
    2832 }
    2833 }
    2834 while( TRUE ); /*lint !e506*/
    2836 dec->members[newRoot].markerToParent = SPQR_INVALID_ARC;
    2837 dec->members[newRoot].markerOfParent = SPQR_INVALID_ARC;
    2838 }
    2839}
    2840
    2841/** Deletes the SPQR tree (connected component) containing the given component rows and columns.
    2842 *
    2843 * Note that the implementation of this method does not actually modify the SPQR tree, but rather unlinks the rows and
    2844 * columns from the relevant arcs. Thus, this method is a bit hacky and should be used with care.
    2845 */
    2846static
    2848 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    2849 const int* componentRows, /**< The rows of the connected component*/
    2850 int numRows, /**< The number of rows */
    2851 const int* componentCols, /**< The columns of the connected component*/
    2852 int numCols /**< The number of columns */
    2853 )
    2854{
    2855 //The below just removes the 'link' but not the internal datastructures.
    2856 //This is sufficient for our purposes, as long as we do not re-introduce any of the 'negated' rows/columns back into the decomposition.
    2857
    2858 for( int i = 0; i < numRows; ++i )
    2859 {
    2860 spqr_row row = componentRows[i];
    2861 if( SPQRarcIsValid(dec->rowArcs[row]) )
    2862 {
    2863 dec->rowArcs[row] = SPQR_INVALID_ARC;
    2864 }
    2865 }
    2866
    2867 for( int i = 0; i < numCols; ++i )
    2868 {
    2869 spqr_col col = componentCols[i];
    2870 if( SPQRarcIsValid(dec->columnArcs[col]) )
    2871 {
    2872 dec->columnArcs[col] = SPQR_INVALID_ARC;
    2873 }
    2874 }
    2875}
    2876
    2877#ifdef SCIP_DEBUG
    2878/** Converts the members type to an associated character */ //Debugging functions to print the decomposition
    2879static
    2880char typeToChar(
    2881 SPQRMemberType type /**< The member type */
    2882 )
    2883{
    2884 switch (type)
    2885 {
    2887 return 'R';
    2889 return 'P';
    2891 return 'S';
    2893 return 'L';
    2894 default:
    2895 return '?';
    2896 }
    2897}
    2898
    2899/** Prints an arc in DOT format */
    2900static
    2901void arcToDot(
    2902 FILE* stream, /**< The stream to write the arc to */
    2903 const SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    2904 spqr_arc arc, /**< The arc to write */
    2905 unsigned long dot_head, /**< The head id of the arc */
    2906 unsigned long dot_tail, /**< The tail id of the arc */
    2907 SCIP_Bool useElementNames /**< If TRUE, prints the corresponding row/column index. If FALSE,
    2908 **< prints the spqr_arc id instead. */
    2909 )
    2910{
    2911 assert(SPQRarcIsValid(arc));
    2912 spqr_member member = findArcMemberNoCompression(dec, arc);
    2913 SPQRMemberType member_type = getMemberType(dec, member);
    2914 char type = typeToChar(member_type);
    2915 const char *color = arcIsTree(dec, arc) ? ",color=red" : ",color=blue";
    2916
    2917 int arc_name = arc;
    2918
    2919 if( markerToParent(dec, member) == arc )
    2920 {
    2921 if( useElementNames )
    2922 {
    2923 arc_name = -1;
    2924 }
    2925 fprintf(stream, " %c_%d_%lu -> %c_p_%d [label=\"%d\",style=dashed%s];\n", type, member, dot_tail, type, member, arc_name, color);
    2926 fprintf(stream, " %c_p_%d -> %c_%d_%lu [label=\"%d\",style=dashed%s];\n", type, member, type, member, dot_head, arc_name, color);
    2927 fprintf(stream, " %c_%d_%lu [shape=box];\n", type, member, dot_tail);
    2928 fprintf(stream, " %c_%d_%lu [shape=box];\n", type, member, dot_head);
    2929 fprintf(stream, " %c_p_%d [style=dashed];\n", type, member);
    2930 }
    2931 else if( arcIsChildMarker(dec, arc) )
    2932 {
    2934 char childType = typeToChar(getMemberType(dec, child));
    2935 if( useElementNames )
    2936 {
    2937 arc_name = -1;
    2938 }
    2939 fprintf(stream, " %c_%d_%lu -> %c_c_%d [label=\"%d\",style=dotted%s];\n", type, member, dot_tail, type, child, arc_name, color);
    2940 fprintf(stream, " %c_c_%d -> %c_%d_%lu [label=\"%d\",style=dotted%s];\n", type, child, type, member, dot_head, arc_name, color);
    2941 fprintf(stream, " %c_%d_%lu [shape=box];\n", type, member, dot_tail);
    2942 fprintf(stream, " %c_%d_%lu [shape=box];\n", type, member, dot_head);
    2943 fprintf(stream, " %c_c_%d [style=dotted];\n", type, child);
    2944 fprintf(stream, " %c_p_%d -> %c_c_%d [style=dashed,dir=forward];\n", childType, child, type, child);
    2945 }
    2946 else
    2947 {
    2948 if( useElementNames )
    2949 {
    2950 spqr_element element = dec->arcs[arc].element;
    2951 if( SPQRelementIsRow(element) )
    2952 {
    2953 arc_name = (int) SPQRelementToRow(element);
    2954 }
    2955 else
    2956 {
    2957 arc_name = (int) SPQRelementToColumn(element);
    2958 }
    2959 }
    2960
    2961 fprintf(stream, " %c_%d_%lu -> %c_%d_%lu [label=\"%d \",style=bold%s];\n", type, member, dot_tail, type, member, dot_head,
    2962 arc_name, color);
    2963 fprintf(stream, " %c_%d_%lu [shape=box];\n", type, member, dot_tail);
    2964 fprintf(stream, " %c_%d_%lu [shape=box];\n", type, member, dot_head);
    2965 }
    2966}
    2967
    2968/** Outputs the network decomposition as a DOT file. */
    2969static
    2970void decompositionToDot(
    2971 FILE* stream, /**< The stream to write to */
    2972 const SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    2973 SCIP_Bool useElementNames /**< If TRUE, prints the corresponding row/column index. If FALSE,
    2974 * prints the spqr_arc id instead. */
    2975 )
    2976{
    2977 fprintf(stream, "//decomposition\ndigraph decomposition{\n compound = TRUE;\n");
    2978 for( spqr_member member = 0; member < dec->numMembers; ++member )
    2979 {
    2980 if( !memberIsRepresentative(dec, member) )
    2981 continue;
    2982 fprintf(stream, " subgraph member_%d{\n", member);
    2983 switch( getMemberType(dec, member) )
    2984 {
    2986 {
    2987 spqr_arc first_arc = getFirstMemberArc(dec, member);
    2988 spqr_arc arc = first_arc;
    2989 do
    2990 {
    2991 unsigned long arcHead = (unsigned long) findEffectiveArcHeadNoCompression(dec, arc);
    2992 unsigned long arcTail = (unsigned long) findEffectiveArcTailNoCompression(dec, arc);
    2993 arcToDot(stream, dec, arc, arcHead, arcTail, useElementNames);
    2994 arc = getNextMemberArc(dec, arc);
    2995 }
    2996 while( arc != first_arc );
    2997 break;
    2998 }
    3001 {
    3002 spqr_arc first_arc = getFirstMemberArc(dec, member);
    3003 spqr_arc arc = first_arc;
    3004 do
    3005 {
    3006 if( arcIsReversedNonRigid(dec, arc) )
    3007 {
    3008 arcToDot(stream, dec, arc, 1, 0, useElementNames);
    3009 }
    3010 else
    3011 {
    3012 arcToDot(stream, dec, arc, 0, 1, useElementNames);
    3013 }
    3014 arc = getNextMemberArc(dec, arc);
    3015 }
    3016 while( arc != first_arc );
    3017 break;
    3018 }
    3020 {
    3021 unsigned long i = 0;
    3022 unsigned long num_member_arcs = (unsigned long) getNumMemberArcs(dec, member);
    3023 spqr_arc first_arc = getFirstMemberArc(dec, member);
    3024 spqr_arc arc = first_arc;
    3025 do
    3026 {
    3027 unsigned long head = i;
    3028 unsigned long tail = (i + 1) % num_member_arcs;
    3029 if( arcIsReversedNonRigid(dec, arc) )
    3030 {
    3031 unsigned long temp = head;
    3032 head = tail;
    3033 tail = temp;
    3034 }
    3035 arcToDot(stream, dec, arc, head, tail, useElementNames);
    3036 arc = getNextMemberArc(dec, arc);
    3037 i++;
    3038 }
    3039 while( arc != first_arc );
    3040 break;
    3041 }
    3043 break;
    3044 }
    3045 fprintf(stream, " }\n");
    3046 }
    3047 fprintf(stream, "}\n");
    3048}
    3049#endif
    3050
    3051static
    3053 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    3054 spqr_member member, /**< The member to merge */
    3055 spqr_member parent, /**< The parent of the member to merge into */
    3056 spqr_arc parentToChild, /**< The arc from the parent pointing to the member */
    3057 spqr_arc childToParent, /**< The arc in the child pointing to the parent */
    3058 SCIP_Bool headToHead, /**< Identify the head of parentToChild with the head of childToParent?*/
    3059 spqr_member* mergedMember /**< Out-pointer to the member id of the final member */
    3060 )
    3061{
    3062 assert(dec);
    3063 assert(SPQRmemberIsValid(member));
    3064 assert(memberIsRepresentative(dec, member));
    3065 assert(SPQRmemberIsValid(parent));
    3066 assert(memberIsRepresentative(dec, parent));
    3067 assert(findMemberParentNoCompression(dec, member) == parent);
    3068 assert(markerOfParent(dec, member) == parentToChild);
    3069 assert(markerToParent(dec, member) == childToParent);
    3070
    3071 removeArcFromMemberArcList(dec, parentToChild, parent);
    3072 removeArcFromMemberArcList(dec, childToParent, member);
    3073
    3074 spqr_node parentTail = findEffectiveArcTail(dec, parentToChild) ;
    3075 spqr_node parentHead = findEffectiveArcHead(dec, parentToChild);
    3076 spqr_node childTail = findEffectiveArcTail(dec, childToParent);
    3077 spqr_node childHead = findEffectiveArcHead(dec, childToParent);
    3078 spqr_node parentArcNodes[2] = { parentTail, parentHead };
    3079 spqr_node childArcNodes[2] = { childTail, childHead };
    3080
    3081 clearArcHeadAndTail(dec, parentToChild);
    3082 clearArcHeadAndTail(dec, childToParent);
    3083
    3084 spqr_node first = childArcNodes[headToHead ? 0 : 1];
    3085 spqr_node second = childArcNodes[headToHead ? 1 : 0];
    3086 {
    3087 spqr_node newNode = mergeNodes(dec, parentArcNodes[0], first);
    3088 spqr_node toRemoveFrom = newNode == first ? parentArcNodes[0] : first;
    3089 mergeNodeArcList(dec, newNode, toRemoveFrom);
    3090 }
    3091 {
    3092 spqr_node newNode = mergeNodes(dec, parentArcNodes[1], second);
    3093 spqr_node toRemoveFrom = newNode == second ? parentArcNodes[1] : second;
    3094 mergeNodeArcList(dec, newNode, toRemoveFrom);
    3095 }
    3096
    3097 spqr_member newMember = mergeMembers(dec, member, parent);
    3098 spqr_member toRemoveFrom = newMember == member ? parent : member;
    3099 mergeMemberArcList(dec, newMember, toRemoveFrom);
    3100 if( toRemoveFrom == parent )
    3101 {
    3102 updateMemberParentInformation(dec, newMember, toRemoveFrom);
    3103 }
    3104 updateMemberType(dec, newMember, SPQR_MEMBERTYPE_RIGID);
    3105 *mergedMember = newMember;
    3106
    3107 return SCIP_OKAY;
    3108}
    3109
    3110static
    3112 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    3113 BMS_BLKMEM * blkmem, /**< The block memory to use for the created digraph */
    3114 SCIP_DIGRAPH** pdigraph, /**< Pointer to the pointer to store the created digraph */
    3115 SCIP_Bool createrowarcs /**< Should the row arcs be added to the created digraph? */
    3116 )
    3117{
    3118 /* Compute the number of rows m in the network matrix decomposition. The underlying graph has m+1 vertices. */
    3119 int nrows = 0;
    3120 for( int i = 0; i < dec->memRows; ++i )
    3121 if( netMatDecDataContainsRow(dec, i) )
    3122 ++nrows;
    3123
    3124 int nvertices = nrows + 1;
    3125 SCIP_CALL( SCIPdigraphCreate(pdigraph, blkmem, nvertices) );
    3126
    3127 /* Map decomposition nodes to graph nodes. The first node of each component is mapped to node 0 */
    3128 int largestNode = largestNodeID(dec);
    3129 int* dectographnode;
    3130 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &dectographnode, largestNode) );
    3131 for( int i = 0; i < largestNode; ++i )
    3132 dectographnode[i] = -1;
    3133
    3134 SCIP_DIGRAPH* digraph = *pdigraph;
    3135 /* Recursively explore the decomposition, adding the edges of each component and identifying them as needed */
    3136
    3137 typedef struct {
    3138 spqr_member member;
    3139 spqr_arc arc;
    3140 int graphfirstarchead;
    3141 int graphfirstarctail;
    3142 } CallData;
    3143 spqr_member largestmember = largestMemberID(dec);
    3144 CallData* calldata;
    3145 int ncalldata = 0;
    3146 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &calldata, largestmember) );
    3147
    3148 SCIP_Bool* rowprocessed;
    3149 SCIP_ALLOC( BMSallocClearBlockMemoryArray(blkmem, &rowprocessed, dec->memRows) );
    3150
    3151 /* This outer loop loops over all components; this is a bit ugly unfortunately */
    3152 int nextnodeindex = 1; /* 0 is assigned to the first arc of the root members' head */
    3153 for( int i = 0; i < dec->memRows ; ++i )
    3154 {
    3155 spqr_arc rowarc = dec->rowArcs[i];
    3156 if( SPQRarcIsInvalid(rowarc) )
    3157 continue;
    3158
    3159 assert(netMatDecDataContainsRow(dec, i)) ;
    3160 if( rowprocessed[i] )
    3161 continue;
    3162
    3163 /* Find the root member of the SPQR tree */
    3164 spqr_member arcmember = findArcMember(dec, rowarc);
    3165 spqr_member rootmember = arcmember;
    3166 do
    3167 {
    3168 spqr_member parent = findMemberParent(dec, rootmember);
    3169 if( SPQRmemberIsInvalid(parent) )
    3170 break;
    3171 rootmember = parent;
    3172 }
    3173 while( TRUE ); /*lint !e506*/
    3174
    3175 /* We identify all the SPQR trees at node 0 */
    3176 calldata[0].member = rootmember;
    3177 calldata[0].arc = getFirstMemberArc(dec, rootmember);
    3178 calldata[0].graphfirstarchead = 0;
    3179 calldata[0].graphfirstarctail = nextnodeindex;
    3180 ++nextnodeindex;
    3181 ++ncalldata;
    3182
    3183 while( ncalldata != 0 )
    3184 {
    3185 /* Pop the next member to process of the call stack */
    3186 CallData explore = calldata[ncalldata-1];
    3187 --ncalldata;
    3188
    3189 switch( getMemberType(dec, explore.member) )
    3190 {
    3192 {
    3193 /* First, we set the initial arc's nodes */
    3194 {
    3195 assert(dectographnode[findEffectiveArcHeadNoCompression(dec, explore.arc)] == -1);
    3196 assert(dectographnode[findEffectiveArcTailNoCompression(dec, explore.arc)] == -1);
    3197 spqr_node exploreHead = findArcHead(dec, explore.arc);
    3198 spqr_node exploreTail = findArcTail(dec, explore.arc);
    3199 if( findArcSign(dec, explore.arc).reversed )
    3200 SCIPswapInts(&exploreTail, &exploreTail);
    3201 dectographnode[exploreHead] = explore.graphfirstarchead;
    3202 dectographnode[exploreTail] = explore.graphfirstarctail;
    3203 }
    3204
    3205 /* Add all the members arcs to the graph */
    3206 spqr_arc firstArc = getFirstMemberArc(dec, explore.member);
    3207 spqr_arc arc = firstArc;
    3208 do
    3209 {
    3210 spqr_node head = findArcHead(dec, arc);
    3211 spqr_node tail = findArcTail(dec, arc);
    3212 if( findArcSign(dec, arc).reversed )
    3213 SCIPswapInts(&head, &tail);
    3214
    3215 if( dectographnode[head] == -1 )
    3216 {
    3217 dectographnode[head] = nextnodeindex;
    3218 ++nextnodeindex;
    3219 }
    3220 if( dectographnode[tail] == -1 )
    3221 {
    3222 dectographnode[tail] = nextnodeindex;
    3223 ++nextnodeindex;
    3224 }
    3225
    3226 /* If an arc is a marker to a child node, we add it to the call stack */
    3227 if( arcIsChildMarker(dec, arc))
    3228 {
    3229 spqr_member child = findArcChildMember(dec, arc);
    3230 spqr_arc toparent = markerToParent(dec, child);
    3231
    3232 /* Identify head with head and tail with tail */
    3233 /* Push member onto the processing stack (recursive call) */
    3234 calldata[ncalldata].member = child;
    3235 calldata[ncalldata].arc = toparent;
    3236 calldata[ncalldata].graphfirstarchead = dectographnode[head];
    3237 calldata[ncalldata].graphfirstarctail = dectographnode[tail];
    3238
    3239 ++ncalldata;
    3240 }
    3241 else if( arc != markerToParent(dec, explore.member) )
    3242 {
    3243 /* We only realize non-virtual arcs */
    3244 if( createrowarcs || !arcIsTree(dec, arc) )
    3245 {
    3246 spqr_element element = arcGetElement(dec, arc);
    3247 size_t ind;
    3248 if( SPQRelementIsRow(element) )
    3249 {
    3250 ind = SPQRelementToRow(element); /*lint !e732 */
    3251 }
    3252 else
    3253 {
    3254 ind = SPQRelementToColumn(element) + dec->memRows; /*lint !e732 !e776 */
    3255 }
    3256 SCIP_CALL( SCIPdigraphAddArc(digraph, dectographnode[tail], dectographnode[head],
    3257 (void*) ind) );
    3258 }
    3259 }
    3260 spqr_element element = arcGetElement(dec, arc);
    3261 if( SPQRelementIsRow(element) && element != MARKER_ROW_ELEMENT )
    3262 {
    3263 spqr_row row = SPQRelementToRow(element);
    3264 assert(row < dec->memRows);
    3265 rowprocessed[row] = TRUE;
    3266 }
    3267 arc = getNextMemberArc(dec, arc);
    3268 }
    3269 while( arc != firstArc );
    3270 break;
    3271 }
    3272
    3275 {
    3276 spqr_arc firstArc = getFirstMemberArc(dec, explore.member);
    3277 spqr_arc arc = firstArc;
    3278 do
    3279 {
    3280 /* If an edge is a marker to a child node, we add it to the call stack */
    3281 if( arcIsChildMarker(dec, arc) )
    3282 {
    3283 spqr_member child = findArcChildMember(dec, arc);
    3284 spqr_arc toparent = markerToParent(dec, child);
    3285 SCIP_Bool directionsmatch =
    3286 arcIsReversedNonRigid(dec, explore.arc) == arcIsReversedNonRigid(dec, arc);
    3287
    3288 /* Identify head with head and tail with tail */
    3289 /* Push member onto the processing stack (recursive call) */
    3290 calldata[ncalldata].member = child;
    3291 calldata[ncalldata].arc = toparent;
    3292 calldata[ncalldata].graphfirstarchead = directionsmatch ? explore.graphfirstarchead
    3293 : explore.graphfirstarctail;
    3294 calldata[ncalldata].graphfirstarctail = directionsmatch ? explore.graphfirstarctail
    3295 : explore.graphfirstarchead;
    3296
    3297 ++ncalldata;
    3298 }
    3299 else if( arc != markerToParent(dec, explore.member) )
    3300 {
    3301 /* We only realize non-virtual arcs */
    3302 if( createrowarcs || !arcIsTree(dec, arc) )
    3303 {
    3304 spqr_element element = arcGetElement(dec, arc);
    3305 size_t ind;
    3306 if( SPQRelementIsRow(element) )
    3307 {
    3308 ind = SPQRelementToRow(element); /*lint !e732 */
    3309 }
    3310 else
    3311 {
    3312 ind = SPQRelementToColumn(element) + dec->memRows; /*lint !e732 !e776 */
    3313 }
    3314 if( arcIsReversedNonRigid(dec, explore.arc) == arcIsReversedNonRigid(dec, arc) )
    3315 {
    3316 SCIP_CALL( SCIPdigraphAddArc(digraph, explore.graphfirstarctail,
    3317 explore.graphfirstarchead, (void*) ind) );
    3318 }
    3319 else
    3320 {
    3321 SCIP_CALL( SCIPdigraphAddArc(digraph, explore.graphfirstarchead,
    3322 explore.graphfirstarctail, (void*) ind) );
    3323 }
    3324 }
    3325 }
    3326 spqr_element element = arcGetElement(dec, arc);
    3327 if( SPQRelementIsRow(element) && element != MARKER_ROW_ELEMENT )
    3328 {
    3329 spqr_row row = SPQRelementToRow(element);
    3330 assert(row < dec->memRows);
    3331 rowprocessed[row] = TRUE;
    3332 }
    3333 arc = getNextMemberArc(dec, arc);
    3334 }
    3335 while( arc != firstArc );
    3336 break;
    3337 }
    3338
    3340 {
    3341 int count = getNumMemberArcs(dec, explore.member);
    3342 spqr_arc arc = explore.arc;
    3343 int firstnode = explore.graphfirstarchead;
    3344 int secondnode = explore.graphfirstarctail;
    3345 for( int j = 0; j < count; ++j )
    3346 {
    3347 if( arcIsChildMarker(dec, arc) )
    3348 {
    3349 spqr_member child = findArcChildMember(dec, arc);
    3350 spqr_arc toparent = markerToParent(dec, child);
    3351 SCIP_Bool directionsmatch =
    3352 arcIsReversedNonRigid(dec, explore.arc) == arcIsReversedNonRigid(dec, arc);
    3353
    3354 /* Identify head with head and tail with tail */
    3355 /* Push member onto the processing stack (recursive call) */
    3356 calldata[ncalldata].member = child;
    3357 calldata[ncalldata].arc = toparent;
    3358 calldata[ncalldata].graphfirstarchead = directionsmatch ? firstnode : secondnode;
    3359 calldata[ncalldata].graphfirstarctail = directionsmatch ? secondnode : firstnode;
    3360
    3361 ++ncalldata;
    3362 }
    3363 else if( arc != markerToParent(dec, explore.member) )
    3364 {
    3365 /* We only realize non-virtual arcs */
    3366 if( createrowarcs || !arcIsTree(dec, arc) )
    3367 {
    3368 spqr_element element = arcGetElement(dec,arc);
    3369 size_t ind;
    3370 if( SPQRelementIsRow(element) )
    3371 {
    3372 ind = SPQRelementToRow(element); /*lint !e732 */
    3373 }
    3374 else
    3375 {
    3376 ind = SPQRelementToColumn(element) + dec->memRows; /*lint !e732 !e776 */
    3377 }
    3378
    3379 if( arcIsReversedNonRigid(dec, explore.arc) == arcIsReversedNonRigid(dec, arc) )
    3380 {
    3381 SCIP_CALL( SCIPdigraphAddArc(digraph, secondnode, firstnode, (void*) ind) );
    3382 }
    3383 else
    3384 {
    3385 SCIP_CALL( SCIPdigraphAddArc(digraph, firstnode, secondnode, (void*) ind) );
    3386 }
    3387 }
    3388 }
    3389
    3390 spqr_element element = arcGetElement(dec, arc);
    3391 if( SPQRelementIsRow(element) && element != MARKER_ROW_ELEMENT )
    3392 {
    3393 spqr_row row = SPQRelementToRow(element);
    3394 rowprocessed[row] = TRUE;
    3395 }
    3396
    3397 arc = getNextMemberArc(dec, arc);
    3398 secondnode = firstnode;
    3399 if( j >= count - 2 )
    3400 {
    3401 firstnode = explore.graphfirstarctail;
    3402 }
    3403 else
    3404 {
    3405 firstnode = nextnodeindex;
    3406 ++nextnodeindex;
    3407 }
    3408 }
    3409 assert(arc == explore.arc); /* Check that we added all arcs */
    3410 break;
    3411 }
    3412
    3414 {
    3415 SCIPerrorMessage("Can not create graph for unassigned member type, exiting.\n");
    3416 SCIPABORT();
    3417 return SCIP_ERROR;
    3418 }
    3419 }
    3420 }
    3421 }
    3422
    3423 /* We cannot have more vertices then there are in the graph.
    3424 * If we processed everything right, all vertices should have been hit.
    3425 */
    3426 assert(nextnodeindex == nvertices);
    3427
    3428 BMSfreeBlockMemoryArray(blkmem, &rowprocessed, dec->memRows);
    3429 BMSfreeBlockMemoryArray(blkmem, &calldata, largestmember);
    3430 BMSfreeBlockMemoryArray(blkmem, &dectographnode, largestNode);
    3431
    3432 return SCIP_OKAY;
    3433}
    3434
    3435/* ---------- START functions for column addition ------------------------------------------------------------------- */
    3436
    3437/** Path arcs are all those arcs that correspond to nonzeros of the column to be added. */
    3438typedef int path_arc_id;
    3439#define INVALID_PATH_ARC (-1)
    3440
    3441/** Returns true if the path arc is invalid. */
    3442static
    3444 const path_arc_id arc /**< The path arc to check */
    3445 )
    3446{
    3447 return arc < 0;
    3448}
    3449
    3450/** Returns true if the path arc is valid. */
    3451static
    3453 const path_arc_id arc /**< The path arc to check */
    3454 )
    3455{
    3456 return !pathArcIsInvalid(arc);
    3457}
    3458
    3459/** A forward linked list-node for the path arcs.
    3460 *
    3461 * Contains a pointer to the next path arc in the member graph and the
    3462 * next path arc in the SPQR tree. We additionally store copies of the corresponding arc's node indices.
    3463 */
    3464typedef struct
    3465{
    3466 spqr_arc arc; /**< The arc corresponding to the path ar c*/
    3467 spqr_node arcHead; /**< A copy of the arc's head node index */
    3468 spqr_node arcTail; /**< A copy of the arc's tail node index */
    3469 path_arc_id nextMember; /**< Array index of the next path arc in the member path arc linked list */
    3470 path_arc_id nextOverall; /**< Array index of the next path arc in the total path arc linked list */
    3471 SCIP_Bool reversed; /**< Is the path arc occuring forwards or backwards in the path?
    3472 * Corresponds to the sign of the nonzero */
    3474
    3475/** Index for the reduced members, which are the members of the sub-SPQR tree containing all path arcs.
    3476 *
    3477 * Note that these are indexed separately from the members of the SPQR tree!
    3478 */
    3480#define INVALID_REDUCED_MEMBER (-1)
    3481
    3482/** Returns true if the reduced member is invalid. */
    3483static
    3485 const reduced_member_id id /**< The reduced member to check */
    3486 )
    3487{
    3488 return id < 0;
    3489}
    3490
    3491/** Returns true if the reduced member is valid. */
    3492static
    3494 const reduced_member_id id /**< The reduced member to check */
    3495 )
    3496{
    3497 return !reducedMemberIsInvalid(id);
    3498}
    3499
    3500/** Array index for the children of a reduced member */
    3501typedef int children_idx;
    3502
    3503/** Type of the member, signifies to what degree we processed the member and how to treat with it when updating the
    3504 * graph.
    3505 */
    3506typedef enum
    3507{
    3508 REDUCEDMEMBER_TYPE_UNASSIGNED = 0, /**< We have not yet decided if the reduced member contains a valid path */
    3509 REDUCEDMEMBER_TYPE_CYCLE = 1, /**< The reduced member is a leaf node of the SPQR tree and contains a path
    3510 * that forms a cycle with the corresponding virtual edge, i.e.
    3511 * it is propagated */
    3512 REDUCEDMEMBER_TYPE_MERGED = 2, /**< The reduced member contains a path and is not propagated */
    3513 REDUCEDMEMBER_TYPE_NOT_NETWORK = 3 /**< The reduced member does not have a valid path or can not be oriented
    3514 * to form a valid path with the other members. */
    3516
    3517/** Defines the structure of the path in the reduced member */
    3518typedef enum
    3519{
    3520 INTO_HEAD = 0, /**< The directed path goes into the head of the virtual arc */
    3521 INTO_TAIL = 1, /**< The directed path goes into the tail of the virtual arc */
    3522 OUT_HEAD = 2, /**< The directed path goes out of the head of the virtual arc */
    3523 OUT_TAIL = 3 /**< The directed path goes out of the tail of the virtual arc */
    3525
    3526/** Check if the path type is into. */
    3527static
    3529 MemberPathType type /**< The path type to check */
    3530 )
    3531{
    3532 return type == INTO_HEAD || type == INTO_TAIL;
    3533}
    3534
    3535/** Check if the path end node is the head or tail node of the corresponding arc. */
    3536static
    3538 MemberPathType type /**< The path type to check */
    3539 )
    3540{
    3541 return type == INTO_HEAD || type == OUT_HEAD;
    3542}
    3543
    3544/** A struct that keeps track of the relevant data for the members that are in the subtree given by the specified row
    3545 * arcs.
    3546 *
    3547 * We typically call these 'reduced' members (members of the reduced tree).
    3548 */
    3549typedef struct
    3550{
    3551 spqr_member member; /**< The id of the member */
    3552 spqr_member rootMember; /**< The root member of the arborescence that contains this member */
    3553 int depth; /**< The depth of this member in the arborescence */
    3554 ReducedMemberType type; /**< The type of the member */
    3555 reduced_member_id parent; /**< The reduced member id of the parent of this reduced member */
    3556
    3557 children_idx firstChild; /**< The index of the first child in the children array. */
    3558 children_idx numChildren; /**< The number of children in the arborescence of this reduced member */
    3559
    3560 path_arc_id firstPathArc; /**< Head of the linked list containing the path arcs */
    3561 int numPathArcs; /**< The number of path arcs in the linked list */
    3562
    3563 SCIP_Bool reverseArcs; /**< Will the arcs in this component be reversed? */
    3564 spqr_node rigidPathStart; /**< The start node of the path. Only used for Rigid/3-connected nodes */
    3565 spqr_node rigidPathEnd; /**< The end node of the path. Only used for Rigid/3-connected nodes */
    3566
    3567 SCIP_Bool pathBackwards; /**< Indicates if the path direction is reversed with respect to the
    3568 * default orientation within series and parallel members. */
    3569
    3570 int numPropagatedChildren; /**< Counts the number of children that are cycles that propagated to this
    3571 * reduced member */
    3572 int componentIndex; /**< Stores the index of the component of the SPQR forest that this reduced
    3573 * member is contained in. */
    3574
    3575 MemberPathType pathType; /**< The type of the path with respect to the virtual arc */
    3576 reduced_member_id nextPathMember; /**< Indicates the id of the next reduced member in the path during merging.
    3577 * During merging, the SPQR tree must be a path itself. */
    3578 SCIP_Bool nextPathMemberIsParent; /**< Indicates if the next reduced member in the path is a parent of
    3579 * this member */
    3580 spqr_arc pathSourceArc; /**< The virtual arc from where the path originates */
    3581 spqr_arc pathTargetArc; /**< The virtual arc where the path has to go */
    3583
    3584/** Keeps track of the data relevant for each SPQR tree in the SPQR forest. */
    3585typedef struct
    3586{
    3587 int rootDepth; /**< The depth of the root node of the subtree in the arborescence */
    3588 reduced_member_id root; /**< The reduced member id of the root */
    3589
    3590 reduced_member_id pathEndMembers[2]; /**< The reduced members that contain the ends of the path */
    3591 int numPathEndMembers; /**< The number of reduced members that contain an end of the path */
    3593
    3594/** Keeps track of the reduced member and the reduced member that is the root of the arborescence for a single member */
    3595typedef struct
    3596{
    3597 reduced_member_id reducedMember; /**< The ID of the associated reduced member */
    3598 reduced_member_id rootDepthMinimizer; /**< The ID of the reduced member that is the root of the arborescence this
    3599 * reduced member is contained in. */
    3600} MemberInfo;
    3601
    3602/** Data to be used for the recursive algorithms that creates the sub-SPQR trees that contain the path edges */
    3603typedef struct
    3604{
    3605 spqr_member member; /**< The current member */
    3607
    3608/** The main datastructure that manages all the data for column-addition in network matrices */
    3609typedef struct
    3610{
    3611 SCIP_Bool remainsNetwork; /**< Does the addition of the current column give a network matrix? */
    3612
    3613 SPQRColReducedMember* reducedMembers; /**< The array of reduced members, that form the subtree containing the
    3614 * rows of the current column. */
    3615 int memReducedMembers; /**< Number of allocated slots in the reduced member array */
    3616 int numReducedMembers; /**< Number of used slots in the reduced member array */
    3617
    3618 SPQRColReducedComponent* reducedComponents;/**< The array of reduced components,
    3619 * that represent the SPQR trees in the SPQR forest */
    3620 int memReducedComponents;/**< Number of allocated slots in the reduced component array */
    3621 int numReducedComponents;/**< Number of used slots in the reduced component array */
    3622
    3623 MemberInfo* memberInformation; /**< Array with member information; tracks the reduced member id that
    3624 * corresponds to every member in the decomposition. */
    3625 int memMemberInformation;/**< Number of allocated slots in the member information array */
    3626 int numMemberInformation;/**< Number of used slots in the member information array */
    3627
    3628 reduced_member_id* childrenStorage; /**< Array that stores the children of the reduced member arborescences.
    3629 * Each reduced member has a 'firstChild' field and a length, that points
    3630 * to the subarray within this array with its children. This array is
    3631 * shared here in order to minimize allocations across iterations. */
    3632 int memChildrenStorage; /**< Number of allocated slots for the children storage array */
    3633 int numChildrenStorage; /**< Number of used slots for the children storage array */
    3634
    3635 PathArcListNode* pathArcs; /**< Array that contains the linked-list nodes of the path arcs, that
    3636 * correspond to the rows of the current column. */
    3637 int memPathArcs; /**< Number of allocated slots for the path arc array */
    3638 int numPathArcs; /**< Number of used slots for the path arc array */
    3639 path_arc_id firstOverallPathArc;/**< Head node of the linked list containing all path arcs */
    3640
    3641 int* nodeInPathDegree; /**< Array that contains the in degree of all nodes */
    3642 int* nodeOutPathDegree; /**< Array that contains the out degree of all nodes */
    3643 int memNodePathDegree; /**< The number of allocated slots for the node-degree arrays */
    3644
    3645 SCIP_Bool* arcInPath; /**< Is the given arc in the path? */
    3646 SCIP_Bool* arcInPathReversed; /**< Is the given arc's direction reversed in the path? */
    3647 int memArcsInPath; /**< The number of allocated slots for the arcInPath(Reversed) arrays */
    3648
    3649 CreateReducedMembersCallstack* createReducedMembersCallStack; /**< Callstack for createReducedMembers() */
    3650 int memCreateReducedMembersCallStack; /**< Allocated memory for callstack for createReducedMembers() */
    3651
    3652 spqr_col newColIndex; /**< The index of the new column to be added */
    3653
    3654 spqr_row* newRowArcs; /**< The row indices of the nonzeros of the column to be added, that are
    3655 * not yet in the decomposition. */
    3656 SCIP_Bool* newRowArcReversed; /**< True if the nonzero corresponding to the row index is -1,
    3657 * false otherwise */
    3658 int memNewRowArcs; /**< Number of allocated slots in newRowArcs(Reversed) */
    3659 int numNewRowArcs; /**< Number of new rows in the column to be added */
    3660
    3661 spqr_arc* decompositionRowArcs; /**< For each row nonzero that is in the decomposition,
    3662 * stores the corresponding decomposition arc */
    3663 SCIP_Bool* decompositionArcReversed; /**< For each row nonzero that is in the decomposition,
    3664 * stores whether the corresponding decomposition arc is reversed */
    3665 int memDecompositionRowArcs; /**< Number of allocated slots in decompositionRowArcs(Reversed) */
    3666 int numDecompositionRowArcs; /**< Number of used slots in decompositionRowArcs(Reversed) */
    3667
    3668 spqr_member* leafMembers; /**< Array that stores the leaf members of the SPQR forest */
    3669 int numLeafMembers; /**< Number of used slots in leafMembers array */
    3670 int memLeafMembers; /**< Number of allocated slots in leafMembers array */
    3672
    3673/** Clean up internal temporary data structures that were used in the previous column iteration. */
    3674static
    3676 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    3677 SCIP_NETCOLADD* newCol /**< The network matrix column addition data structure */
    3678 )
    3679{
    3680 assert(dec);
    3681 assert(newCol);
    3682
    3683 path_arc_id pathArc = newCol->firstOverallPathArc;
    3684 while( pathArcIsValid(pathArc) )
    3685 {
    3686 spqr_node head = newCol->pathArcs[pathArc].arcHead;
    3687 spqr_node tail = newCol->pathArcs[pathArc].arcTail;
    3688 if( SPQRnodeIsValid(head) )
    3689 {
    3690 newCol->nodeInPathDegree[head] = 0;
    3691 }
    3692 if( SPQRnodeIsValid(tail) )
    3693 {
    3694 newCol->nodeOutPathDegree[tail] = 0;
    3695 }
    3696
    3697 spqr_arc arc = newCol->pathArcs[pathArc].arc;
    3698 if( arc < newCol->memArcsInPath )
    3699 {
    3700 newCol->arcInPath[arc] = FALSE;
    3701 newCol->arcInPathReversed[arc] = FALSE;
    3702 }
    3703 pathArc = newCol->pathArcs[pathArc].nextOverall;
    3704 }
    3705#ifndef NDEBUG
    3706 for( int i = 0; i < newCol->memArcsInPath; ++i )
    3707 {
    3708 assert(newCol->arcInPath[i] == FALSE);
    3709 assert(newCol->arcInPathReversed[i] == FALSE);
    3710 }
    3711
    3712 for( int i = 0; i < newCol->memNodePathDegree; ++i )
    3713 {
    3714 assert(newCol->nodeInPathDegree[i] == 0);
    3715 assert(newCol->nodeOutPathDegree[i] == 0);
    3716 }
    3717#endif
    3718
    3720 newCol->numPathArcs = 0;
    3721}
    3722
    3723/** Create a new network column addition datastructure. */
    3724static
    3726 BMS_BLKMEM* blkmem, /**< Block memory */
    3727 SCIP_NETCOLADD** pcoladd /**< Out-pointer for the created network column addition datastructure */
    3728 )
    3729{
    3730 assert(blkmem);
    3731
    3732 SCIP_ALLOC( BMSallocBlockMemory(blkmem, pcoladd) );
    3733 SCIP_NETCOLADD* newCol = *pcoladd;
    3734
    3735 newCol->remainsNetwork = FALSE;
    3736 newCol->reducedMembers = NULL;
    3737 newCol->memReducedMembers = 0;
    3738 newCol->numReducedMembers = 0;
    3739
    3740 newCol->reducedComponents = NULL;
    3741 newCol->memReducedComponents = 0;
    3742 newCol->numReducedComponents = 0;
    3743
    3744 newCol->memberInformation = NULL;
    3745 newCol->memMemberInformation = 0;
    3746 newCol->numMemberInformation = 0;
    3747
    3748 newCol->childrenStorage = NULL;
    3749 newCol->memChildrenStorage = 0;
    3750 newCol->numChildrenStorage = 0;
    3751
    3752 newCol->pathArcs = NULL;
    3753 newCol->memPathArcs = 0;
    3754 newCol->numPathArcs = 0;
    3756
    3757 newCol->nodeInPathDegree = NULL;
    3758 newCol->nodeOutPathDegree = NULL;
    3759 newCol->memNodePathDegree = 0;
    3760
    3761 newCol->arcInPath = NULL;
    3762 newCol->arcInPathReversed = NULL;
    3763 newCol->memArcsInPath = 0;
    3764
    3767
    3768 newCol->newColIndex = SPQR_INVALID_COL;
    3769
    3770 newCol->newRowArcs = NULL;
    3771 newCol->newRowArcReversed = NULL;
    3772 newCol->memNewRowArcs = 0;
    3773 newCol->numNewRowArcs = 0;
    3774
    3775 newCol->decompositionRowArcs = NULL;
    3777 newCol->memDecompositionRowArcs = 0;
    3778 newCol->numDecompositionRowArcs = 0;
    3779
    3780 newCol->leafMembers = NULL;
    3781 newCol->numLeafMembers = 0;
    3782 newCol->memLeafMembers = 0;
    3783
    3784 return SCIP_OKAY;
    3785}
    3786
    3787/** Free a network column addition datastructure */
    3788static
    3790 BMS_BLKMEM* blkmem, /**< Block memory */
    3791 SCIP_NETCOLADD** pcoladd /**< Pointer to the network column addition datastructure to be freed */
    3792 )
    3793{
    3794 assert(blkmem);
    3795
    3796 SCIP_NETCOLADD* newCol = *pcoladd;
    3799 BMSfreeBlockMemoryArray(blkmem, &newCol->newRowArcs, newCol->memNewRowArcs);
    3800 BMSfreeBlockMemoryArray(blkmem, &newCol->newRowArcReversed, newCol->memNewRowArcs);
    3802 BMSfreeBlockMemoryArray(blkmem, &newCol->arcInPath, newCol->memArcsInPath);
    3803 BMSfreeBlockMemoryArray(blkmem, &newCol->arcInPathReversed, newCol->memArcsInPath);
    3806 BMSfreeBlockMemoryArray(blkmem, &newCol->pathArcs, newCol->memPathArcs);
    3810 BMSfreeBlockMemoryArray(blkmem, &newCol->reducedMembers, newCol->memReducedMembers);
    3811 BMSfreeBlockMemoryArray(blkmem, &newCol->leafMembers, newCol->memLeafMembers);
    3812
    3813 BMSfreeBlockMemory(blkmem, pcoladd);
    3814}
    3815
    3816/** Adds members to the reduced member tree, by starting at the given member, jumping up to the parent, repeating this
    3817 * procedure until the root has been added.
    3818 */
    3819static
    3821 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    3822 SCIP_NETCOLADD* newCol, /**< The network matrix column addition data structure */
    3823 const spqr_member firstMember /**< The member to create a reduced member for */
    3824 )
    3825{
    3826 assert(SPQRmemberIsValid(firstMember));
    3827
    3828 /* Originally a recursive algorithm, but for large matrices we need to unroll recursion to prevent stack overflows
    3829 * from too many recursive calls */
    3831 callstack[0].member = firstMember;
    3832 int callDepth = 0;
    3833
    3834 while( callDepth >= 0 )
    3835 {
    3836 spqr_member member = callstack[callDepth].member;
    3837 reduced_member_id reducedMember = newCol->memberInformation[member].reducedMember;
    3838
    3839 SCIP_Bool reducedValid = reducedMemberIsValid(reducedMember);
    3840 if( !reducedValid )
    3841 {
    3842 //reduced member was not yet created; we create it
    3843 reducedMember = newCol->numReducedMembers;
    3844
    3845 SPQRColReducedMember* reducedMemberData = &newCol->reducedMembers[reducedMember];
    3846 ++newCol->numReducedMembers;
    3847
    3848 reducedMemberData->member = member;
    3849 reducedMemberData->numChildren = 0;
    3850
    3851 reducedMemberData->type = REDUCEDMEMBER_TYPE_UNASSIGNED;
    3852 reducedMemberData->numPropagatedChildren = 0;
    3853 reducedMemberData->firstPathArc = INVALID_PATH_ARC;
    3854 reducedMemberData->numPathArcs = 0;
    3855 reducedMemberData->rigidPathStart = SPQR_INVALID_NODE;
    3856 reducedMemberData->rigidPathEnd = SPQR_INVALID_NODE;
    3857
    3858 reducedMemberData->componentIndex = -1;
    3859 //The children are set later
    3860
    3861 newCol->memberInformation[member].reducedMember = reducedMember;
    3862 assert(memberIsRepresentative(dec, member));
    3863 spqr_member parentMember = findMemberParent(dec, member);
    3864
    3865 if( SPQRmemberIsValid(parentMember) )
    3866 {
    3867 //recursive call to parent member
    3868 ++callDepth;
    3869 assert(callDepth < newCol->memCreateReducedMembersCallStack);
    3870 callstack[callDepth].member = parentMember;
    3871 continue;
    3872 }
    3873 else
    3874 {
    3875 //we found a new reduced decomposition component
    3876
    3877 reducedMemberData->parent = INVALID_REDUCED_MEMBER;
    3878 reducedMemberData->depth = 0;
    3879 reducedMemberData->rootMember = member;
    3880 reducedMemberData->componentIndex = newCol->numReducedComponents;
    3881
    3882 assert(newCol->numReducedComponents < newCol->memReducedComponents);
    3883 newCol->reducedComponents[newCol->numReducedComponents].root = reducedMember;
    3887 ++newCol->numReducedComponents;
    3888 }
    3889 }
    3890 if( reducedValid )
    3891 {
    3892 assert(reducedMember < newCol->numReducedMembers);
    3893 //Reduced member was already created in earlier call
    3894 //update the depth of the root if appropriate
    3895 reduced_member_id* depthMinimizer = &newCol->memberInformation[newCol->reducedMembers[reducedMember].rootMember].rootDepthMinimizer;
    3896 if( reducedMemberIsInvalid(*depthMinimizer) ||
    3897 newCol->reducedMembers[reducedMember].depth < newCol->reducedMembers[*depthMinimizer].depth )
    3898 {
    3899 *depthMinimizer = reducedMember;
    3900 }
    3901 }
    3902 while( TRUE ) /*lint !e716*/
    3903 {
    3904 --callDepth;
    3905 if( callDepth < 0 )
    3906 break;
    3907 spqr_member parentMember = callstack[callDepth + 1].member;
    3908 reduced_member_id parentReducedMember = newCol->memberInformation[parentMember].reducedMember;
    3909 spqr_member currentMember = callstack[callDepth].member;
    3910 reduced_member_id currentReducedMember = newCol->memberInformation[currentMember].reducedMember;
    3911
    3912 SPQRColReducedMember* parentReducedMemberData = &newCol->reducedMembers[parentReducedMember];
    3913 SPQRColReducedMember* reducedMemberData = &newCol->reducedMembers[currentReducedMember];
    3914
    3915 reducedMemberData->parent = parentReducedMember;
    3916 reducedMemberData->depth = parentReducedMemberData->depth + 1;
    3917 reducedMemberData->rootMember = parentReducedMemberData->rootMember;
    3918 //ensure that all newly created reduced members are pointing to the correct component
    3919 assert(parentReducedMemberData->componentIndex >= 0);
    3920 reducedMemberData->componentIndex = parentReducedMemberData->componentIndex;
    3921
    3922 newCol->reducedMembers[parentReducedMember].numChildren++;
    3923 }
    3924 }
    3925
    3926 reduced_member_id returnedMember = newCol->memberInformation[callstack[0].member].reducedMember;
    3927 return returnedMember;
    3928}
    3929
    3930/** Construct the reduced decomposition, which is the smallest subtree containing all members path arcs. */
    3931static
    3933 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    3934 SCIP_NETCOLADD* newCol /**< The network matrix column addition data structure */
    3935 )
    3936{
    3937 assert(dec);
    3938 assert(newCol);
    3939#ifndef NDEBUG
    3940 for( int i = 0; i < newCol->memMemberInformation; ++i )
    3941 {
    3943 }
    3944#endif
    3945
    3946 newCol->numReducedComponents = 0;
    3947 newCol->numReducedMembers = 0;
    3948 if( newCol->numDecompositionRowArcs == 0 )
    3949 {//Early return in case the reduced decomposition will be empty
    3950 return SCIP_OKAY;
    3951 }
    3952 assert(newCol->numReducedMembers == 0);
    3953 assert(newCol->numReducedComponents == 0);
    3954
    3955 int newSize = largestMemberID(dec);//Is this sufficient?
    3956 if( newSize > newCol->memReducedMembers )
    3957 {
    3958 int newArraySize = MAX(2 * newCol->memReducedMembers, newSize);
    3959 SCIP_ALLOC( BMSreallocBlockMemoryArray(dec->env, &newCol->reducedMembers, newCol->memReducedMembers, newArraySize) );
    3960 newCol->memReducedMembers = newArraySize;
    3961 }
    3962 if( newSize > newCol->memMemberInformation )
    3963 {
    3964 int updatedSize = MAX(2 * newCol->memMemberInformation, newSize);
    3965 SCIP_ALLOC( BMSreallocBlockMemoryArray(dec->env, &newCol->memberInformation, newCol->memMemberInformation, updatedSize) );
    3966 for( int i = newCol->memMemberInformation; i < updatedSize; ++i )
    3967 {
    3970 }
    3971 newCol->memMemberInformation = updatedSize;
    3972 }
    3973
    3974 int numComponents = numConnectedComponents(dec);
    3975 if( numComponents > newCol->memReducedComponents )
    3976 {
    3977 int updatedSize = MAX(2 * newCol->memReducedComponents, numComponents);
    3978 SCIP_ALLOC( BMSreallocBlockMemoryArray(dec->env, &newCol->reducedComponents, newCol->memReducedComponents, updatedSize) );
    3979 newCol->memReducedComponents = updatedSize;
    3980 }
    3981
    3982 int numMembers = getNumMembers(dec);
    3983 if( newCol->memCreateReducedMembersCallStack < numMembers )
    3984 {
    3985 int updatedSize = MAX(2 * newCol->memCreateReducedMembersCallStack, numMembers);
    3987 newCol->memCreateReducedMembersCallStack, updatedSize) );
    3988 newCol->memCreateReducedMembersCallStack = updatedSize;
    3989 }
    3990
    3991 //Create the reduced members (recursively)
    3992 for( int i = 0; i < newCol->numDecompositionRowArcs; ++i )
    3993 {
    3994 assert(i < newCol->memDecompositionRowArcs);
    3995 spqr_arc arc = newCol->decompositionRowArcs[i];
    3996 spqr_member arcMember = findArcMember(dec, arc);
    3997 reduced_member_id reducedMember = createReducedMembersToRoot(dec, newCol, arcMember);
    3998 reduced_member_id* depthMinimizer = &newCol->memberInformation[newCol->reducedMembers[reducedMember].rootMember].rootDepthMinimizer;
    3999 if( reducedMemberIsInvalid(*depthMinimizer) )
    4000 {
    4001 *depthMinimizer = reducedMember;
    4002 }
    4003 }
    4004
    4005 //Set the reduced roots according to the root depth minimizers
    4006 for( int i = 0; i < newCol->numReducedComponents; ++i )
    4007 {
    4008 SPQRColReducedComponent* component = &newCol->reducedComponents[i];
    4009 spqr_member rootMember = newCol->reducedMembers[component->root].member;
    4010 reduced_member_id reducedMinimizer = newCol->memberInformation[rootMember].rootDepthMinimizer;
    4011 component->rootDepth = newCol->reducedMembers[reducedMinimizer].depth;
    4012 component->root = reducedMinimizer;
    4013
    4014 //This simplifies code further down which does not need to be component-aware; just pretend that the reduced member is the new root.
    4015 newCol->reducedMembers[component->root].parent = INVALID_REDUCED_MEMBER;
    4016 assert(memberIsRepresentative(dec, rootMember));
    4017 }
    4018
    4019 //update the children array
    4020 int numTotalChildren = 0;
    4021 for( int i = 0; i < newCol->numReducedMembers; ++i )
    4022 {
    4023 SPQRColReducedMember* reducedMember = &newCol->reducedMembers[i];
    4024 reduced_member_id minimizer = newCol->memberInformation[reducedMember->rootMember].rootDepthMinimizer;
    4025 if( reducedMember->depth >= newCol->reducedMembers[minimizer].depth )
    4026 {
    4027 reducedMember->firstChild = numTotalChildren;
    4028 numTotalChildren += reducedMember->numChildren;
    4029 reducedMember->numChildren = 0;
    4030 }
    4031 }
    4032
    4033 if( newCol->memChildrenStorage < numTotalChildren )
    4034 {
    4035 int newMemSize = MAX(newCol->memChildrenStorage * 2, numTotalChildren);
    4036 SCIP_ALLOC( BMSreallocBlockMemoryArray(dec->env, &newCol->childrenStorage, newCol->memChildrenStorage, newMemSize) );
    4037 newCol->memChildrenStorage = newMemSize;
    4038 }
    4039 newCol->numChildrenStorage = numTotalChildren;
    4040
    4041 //Fill up the children array`
    4042 for( reduced_member_id reducedMember = 0; reducedMember < newCol->numReducedMembers; ++reducedMember )
    4043 {
    4044 SPQRColReducedMember* reducedMemberData = &newCol->reducedMembers[reducedMember];
    4045 if( reducedMemberData->depth <=
    4046 newCol->reducedMembers[newCol->memberInformation[reducedMemberData->rootMember].rootDepthMinimizer].depth )
    4047 {
    4048 continue;
    4049 }
    4050 spqr_member parentMember = findMemberParent(dec, reducedMemberData->member);
    4051 reduced_member_id parentReducedMember = SPQRmemberIsValid(parentMember)
    4052 ? newCol->memberInformation[parentMember].reducedMember
    4054 if( reducedMemberIsValid(parentReducedMember))
    4055 {
    4056 SPQRColReducedMember* parentReducedMemberData = &newCol->reducedMembers[parentReducedMember];
    4057 newCol->childrenStorage[parentReducedMemberData->firstChild +
    4058 parentReducedMemberData->numChildren] = reducedMember;
    4059 ++parentReducedMemberData->numChildren;
    4060 }
    4061 }
    4062
    4063 //Clean up the root depth minimizers.
    4064 for( int i = 0; i < newCol->numReducedMembers; ++i )
    4065 {
    4066 SPQRColReducedMember* reducedMember = &newCol->reducedMembers[i];
    4067 assert(reducedMember);
    4068 spqr_member rootMember = reducedMember->rootMember;
    4069 assert(rootMember >= 0);
    4070 assert(rootMember < dec->memMembers);
    4072 }
    4073
    4074 return SCIP_OKAY;
    4075}
    4076
    4077/** Clean up the memberinformation array at the end of an iteration. */
    4078static
    4080 SCIP_NETCOLADD* newCol /**< The network matrix column addition data structure */
    4081 )
    4082{
    4083 //This loop is at the end as memberInformation is also used to assign the cut arcs during propagation
    4084 //Clean up the memberInformation array
    4085 for( int i = 0; i < newCol->numReducedMembers; ++i )
    4086 {
    4088 }
    4089#ifndef NDEBUG
    4090 for( int i = 0; i < newCol->memMemberInformation; ++i )
    4091 {
    4093 }
    4094#endif
    4095}
    4096
    4097/** Marks the given arc as a path arc and adds it to the relevant data structures. */
    4098static
    4100 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    4101 SCIP_NETCOLADD* newCol, /**< The network matrix column addition data structure */
    4102 const spqr_arc arc, /**< The arc to mark as a path arc */
    4103 const reduced_member_id reducedMember, /**< The reduced member containing the arc */
    4104 SCIP_Bool reversed /**< Indicates if the new column entry has +1 or -1 (TRUE) for the arc */
    4105 )
    4106{
    4107 assert(dec);
    4108 assert(newCol);
    4109
    4110 path_arc_id path_arc = newCol->numPathArcs;
    4111 PathArcListNode* listNode = &newCol->pathArcs[path_arc];
    4112 listNode->arc = arc;
    4113
    4114 listNode->nextMember = newCol->reducedMembers[reducedMember].firstPathArc;
    4115 newCol->reducedMembers[reducedMember].firstPathArc = path_arc;
    4116 newCol->reducedMembers[reducedMember].numPathArcs += 1;
    4117
    4118 listNode->nextOverall = newCol->firstOverallPathArc;
    4119 newCol->firstOverallPathArc = path_arc;
    4120
    4121 ++newCol->numPathArcs;
    4122 assert(newCol->numPathArcs <= newCol->memPathArcs);
    4123
    4124 assert(arc < newCol->memArcsInPath);
    4125 newCol->arcInPath[arc] = TRUE;
    4126 newCol->arcInPathReversed[arc] = reversed;
    4127 assert(memberIsRepresentative(dec, newCol->reducedMembers[reducedMember].member));
    4128 if( getMemberType(dec, newCol->reducedMembers[reducedMember].member) == SPQR_MEMBERTYPE_RIGID )
    4129 {
    4130 listNode->arcHead = findEffectiveArcHead(dec, arc);
    4131 listNode->arcTail = findEffectiveArcTail(dec, arc);
    4132 if( reversed )
    4133 {
    4134 SCIPswapInts(&listNode->arcHead, &listNode->arcTail);
    4135 }
    4136 assert(SPQRnodeIsValid(listNode->arcHead) && SPQRnodeIsValid(listNode->arcTail));
    4137 assert(listNode->arcHead < newCol->memNodePathDegree && listNode->arcTail < newCol->memNodePathDegree);
    4138 ++newCol->nodeInPathDegree[listNode->arcHead];
    4139 ++newCol->nodeOutPathDegree[listNode->arcTail];
    4140 }
    4141 else
    4142 {
    4143 listNode->arcHead = SPQR_INVALID_NODE;
    4144 listNode->arcTail = SPQR_INVALID_NODE;
    4145 }
    4146 listNode->reversed = reversed;
    4147}
    4148
    4149/** Mark all the row indices of the new column as path arcs */
    4150static
    4152 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    4153 SCIP_NETCOLADD* newCol /**< The network matrix column addition data structure */
    4154 )
    4155{
    4156 int maxNumPathArcs = newCol->numDecompositionRowArcs + getNumMembers(dec);
    4157 if( newCol->memPathArcs < maxNumPathArcs )
    4158 {
    4159 int newMaxNumArcs = 2 * maxNumPathArcs;//safety factor to prevent very frequent reallocations
    4160 SCIP_ALLOC( BMSreallocBlockMemoryArray(dec->env, &newCol->pathArcs, newCol->memPathArcs, newMaxNumArcs) );
    4161 newCol->memPathArcs = newMaxNumArcs;
    4162 }
    4163 int maxPathArcIndex = largestArcID(dec);
    4164 if( newCol->memArcsInPath < maxPathArcIndex )
    4165 {
    4166 int newSize = 2 * maxPathArcIndex;//safety factor to prevent very frequent reallocations
    4167 SCIP_ALLOC( BMSreallocBlockMemoryArray(dec->env, &newCol->arcInPath, newCol->memArcsInPath, newSize) );
    4168 SCIP_ALLOC( BMSreallocBlockMemoryArray(dec->env, &newCol->arcInPathReversed, newCol->memArcsInPath, newSize) );
    4169
    4170 for( int i = newCol->memArcsInPath; i < newSize; ++i )
    4171 {
    4172 newCol->arcInPath[i] = FALSE;
    4173 newCol->arcInPathReversed[i] = FALSE;
    4174 }
    4175 newCol->memArcsInPath = newSize;
    4176 }
    4177 int maxNumNodes = largestNodeID(dec);
    4178 if( newCol->memNodePathDegree < maxNumNodes )
    4179 {
    4180 int newSize = 2 * maxNumNodes;//safety factor to prevent very frequent reallocations
    4181 SCIP_ALLOC( BMSreallocBlockMemoryArray(dec->env, &newCol->nodeInPathDegree, newCol->memNodePathDegree, newSize) );
    4183 for( int i = newCol->memNodePathDegree; i < newSize; ++i )
    4184 {
    4185 newCol->nodeInPathDegree[i] = 0;
    4186 newCol->nodeOutPathDegree[i] = 0;
    4187 }
    4188 newCol->memNodePathDegree = newSize;
    4189 }
    4190 for( int i = 0; i < newCol->numDecompositionRowArcs; ++i )
    4191 {
    4192 spqr_arc arc = newCol->decompositionRowArcs[i];
    4193 spqr_member member = findArcMember(dec, arc);
    4194 reduced_member_id reducedMember = newCol->memberInformation[member].reducedMember;
    4195 createPathArc(dec, newCol, arc, reducedMember, newCol->decompositionArcReversed[i]);
    4196 }
    4197
    4198 return SCIP_OKAY;
    4199}
    4200
    4201
    4202/** Saves the information of the current row and partitions it based on whether or not the given columns are
    4203 * already part of the decomposition.
    4204 */
    4205static
    4207 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    4208 SCIP_NETCOLADD* newCol, /**< The network matrix column addition data structure */
    4209 spqr_col column, /**< The column that is checked */
    4210 const spqr_row* nonzeroRows, /**< The column's row indices */
    4211 const double* nonzeroValues, /**< The column's nonzero values */
    4212 int numNonzeros /**< The number of nonzeros in the column */
    4213 )
    4214{
    4215 newCol->newColIndex = column;
    4216
    4217 newCol->numDecompositionRowArcs = 0;
    4218 newCol->numNewRowArcs = 0;
    4219
    4220 for( int i = 0; i < numNonzeros; ++i )
    4221 {
    4222 spqr_arc rowArc = getDecompositionRowArc(dec, nonzeroRows[i]);
    4223 SCIP_Bool reversed = nonzeroValues[i] < 0.0;
    4224 if( SPQRarcIsValid(rowArc) )
    4225 {//If the arc is the current decomposition: save it in the array
    4226 if( newCol->numDecompositionRowArcs == newCol->memDecompositionRowArcs )
    4227 {
    4228 int newNumArcs = newCol->memDecompositionRowArcs == 0 ? 8 : 2 * newCol->memDecompositionRowArcs;
    4230 newCol->memDecompositionRowArcs, newNumArcs) );
    4232 newCol->memDecompositionRowArcs, newNumArcs) );
    4233 newCol->memDecompositionRowArcs = newNumArcs;
    4234 }
    4235 newCol->decompositionRowArcs[newCol->numDecompositionRowArcs] = rowArc;
    4236 newCol->decompositionArcReversed[newCol->numDecompositionRowArcs] = reversed;
    4237 ++newCol->numDecompositionRowArcs;
    4238 }
    4239 else
    4240 {
    4241 //Not in the decomposition: add it to the set of arcs which are newly added with this row.
    4242 if( newCol->numNewRowArcs == newCol->memNewRowArcs )
    4243 {
    4244 int newNumArcs = newCol->memNewRowArcs == 0 ? 8 : 2 * newCol->memNewRowArcs;
    4246 newCol->memNewRowArcs, newNumArcs) );
    4248 newCol->memNewRowArcs, newNumArcs) );
    4249 newCol->memNewRowArcs = newNumArcs;
    4250 }
    4251 newCol->newRowArcs[newCol->numNewRowArcs] = nonzeroRows[i];
    4252 newCol->newRowArcReversed[newCol->numNewRowArcs] = reversed;
    4253 newCol->numNewRowArcs++;
    4254 }
    4255 }
    4256
    4257 return SCIP_OKAY;
    4258}
    4259
    4260/** Compute and store the leaf members of the reduced SPQR forest */
    4261static
    4263 const SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    4264 SCIP_NETCOLADD* newCol /**< The network matrix column addition data structure */
    4265 )
    4266{
    4267 if( newCol->numReducedMembers > newCol->memLeafMembers )
    4268 {
    4269 int newSize = MAX(newCol->numReducedMembers, 2 * newCol->memLeafMembers);
    4270 SCIP_ALLOC( BMSreallocBlockMemoryArray(dec->env, &newCol->leafMembers, newCol->memLeafMembers, newSize) );
    4271 newCol->memLeafMembers = newSize;
    4272 }
    4273 newCol->numLeafMembers = 0;
    4274
    4275 for( reduced_member_id reducedMember = 0; reducedMember < newCol->numReducedMembers; ++reducedMember )
    4276 {
    4277 if( newCol->reducedMembers[reducedMember].numChildren == 0 )
    4278 {
    4279 newCol->leafMembers[newCol->numLeafMembers] = reducedMember;
    4280 ++newCol->numLeafMembers;
    4281 }
    4282 }
    4283
    4284 return SCIP_OKAY;
    4285}
    4286
    4287/** Checks if the path arcs in the given rigid member form a path */
    4288static
    4290 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    4291 SCIP_NETCOLADD* newCol, /**< The network matrix column addition data structure */
    4292 SPQRColReducedMember* redMem /**< The rigid reduced member to determine the path in */
    4293 )
    4294{
    4295 assert(dec);
    4296 assert(newCol);
    4297 assert(redMem);
    4298
    4299 /* Simply count the in and out degrees of the nodes to check if the path arcs form a path. We have a valid path if
    4300 * and only if the head of the tail of the path are the only nodes with 1 adjacent edge, and all other nodes
    4301 * have 2 adjacent edges*/
    4302 SCIP_Bool isValidPath = TRUE;
    4305 for( path_arc_id pathArc = redMem->firstPathArc; pathArcIsValid(pathArc); pathArc = newCol->pathArcs[pathArc].nextMember )
    4306 {
    4307 spqr_node head = newCol->pathArcs[pathArc].arcHead;
    4308 spqr_node tail = newCol->pathArcs[pathArc].arcTail;
    4309 assert(nodeIsRepresentative(dec, head) && nodeIsRepresentative(dec, tail));
    4310
    4311 if( newCol->nodeInPathDegree[head] > 1 || newCol->nodeOutPathDegree[tail] > 1 )
    4312 {
    4313 //not network -> stop
    4314 isValidPath = FALSE;
    4315 break;
    4316 }
    4317 if( newCol->nodeOutPathDegree[head] == 0 )
    4318 {
    4319 //found end node
    4320 //If this is the second, stop
    4321 if( SPQRnodeIsValid(redMem->rigidPathEnd) )
    4322 {
    4323 isValidPath = FALSE;
    4324 break;
    4325 }
    4326 redMem->rigidPathEnd = head;
    4327 }
    4328 if( newCol->nodeInPathDegree[tail] == 0 )
    4329 {
    4330 //Found start node.
    4331 //If this is the second, stop.
    4332 if( SPQRnodeIsValid(redMem->rigidPathStart) )
    4333 {
    4334 isValidPath = FALSE;
    4335 break;
    4336 }
    4337 redMem->rigidPathStart = tail;
    4338 }
    4339 }
    4340 //assert that both a start and end node have been found
    4341 assert(!isValidPath || ( SPQRnodeIsValid(redMem->rigidPathStart) && SPQRnodeIsValid(redMem->rigidPathEnd)));
    4342 if( !isValidPath )
    4343 {
    4347 newCol->remainsNetwork = FALSE;
    4348 }
    4349}
    4350
    4351/** Determines the member's type for the case where the reduced tree consists of a single rigid member. */
    4352static
    4354 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    4355 SCIP_NETCOLADD* newCol, /**< The network matrix column addition data structure */
    4356 reduced_member_id reducedMember /**< The reduced member to check */
    4357 )
    4358{
    4359 assert(dec);
    4360 assert(newCol);
    4361 assert(reducedMemberIsValid(reducedMember));
    4362
    4363 SPQRColReducedMember* redMem = &newCol->reducedMembers[reducedMember];
    4364 assert(pathArcIsValid(redMem->firstPathArc));
    4365 determineRigidPath(dec, newCol, redMem);
    4366 if( redMem->type != REDUCEDMEMBER_TYPE_NOT_NETWORK )
    4367 {
    4369 }
    4370}
    4371
    4372/** Determines the member's type for the case where the reduced tree consists of a single member. */
    4373static
    4375 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    4376 SCIP_NETCOLADD* newCol, /**< The network matrix column addition data structure */
    4377 reduced_member_id reducedMember /**< The reduced member to check */
    4378 )
    4379{
    4380 assert(dec);
    4381 assert(newCol);
    4382
    4383 int numNonPropagatedAdjacent =
    4384 newCol->reducedMembers[reducedMember].numChildren - newCol->reducedMembers[reducedMember].numPropagatedChildren;
    4385 if( reducedMemberIsValid(newCol->reducedMembers[reducedMember].parent) &&
    4386 newCol->reducedMembers[newCol->reducedMembers[reducedMember].parent].type != REDUCEDMEMBER_TYPE_CYCLE )
    4387 {
    4388 ++numNonPropagatedAdjacent;
    4389 }
    4390
    4391 if( numNonPropagatedAdjacent > 2 )
    4392 {
    4393 newCol->reducedMembers[reducedMember].type = REDUCEDMEMBER_TYPE_NOT_NETWORK;
    4394 newCol->remainsNetwork = FALSE;
    4395 return;
    4396 }
    4397
    4398 spqr_member member = findMember(dec, newCol->reducedMembers[reducedMember].member);
    4399 SPQRMemberType type = getMemberType(dec, member);
    4400 switch( type )
    4401 {
    4403 {
    4404 determineSingleRigidType(dec, newCol, reducedMember);
    4405 break;
    4406 }
    4408 {
    4409 SPQRColReducedMember* redMem = &newCol->reducedMembers[reducedMember];
    4410 assert(pathArcIsValid(redMem->firstPathArc));
    4411 SCIP_Bool pathForwards = newCol->pathArcs[redMem->firstPathArc].reversed ==
    4412 arcIsReversedNonRigid(dec, newCol->pathArcs[redMem->firstPathArc].arc);
    4413 redMem->pathBackwards = !pathForwards;
    4415 break;
    4416 }
    4419 {
    4420 SPQRColReducedMember* redMem = &newCol->reducedMembers[reducedMember];
    4421 int countedPathArcs = 0;
    4422 SCIP_Bool good = TRUE;
    4423 SCIP_Bool passesForwards = TRUE;
    4424 for( path_arc_id pathArc = redMem->firstPathArc; pathArcIsValid(pathArc);
    4425 pathArc = newCol->pathArcs[pathArc].nextMember )
    4426 {
    4427 if( countedPathArcs == 0 )
    4428 {
    4429 passesForwards =
    4430 newCol->pathArcs[pathArc].reversed != arcIsReversedNonRigid(dec, newCol->pathArcs[pathArc].arc);
    4431 }
    4432 else if(
    4433 (newCol->pathArcs[pathArc].reversed != arcIsReversedNonRigid(dec, newCol->pathArcs[pathArc].arc)) !=
    4434 passesForwards )
    4435 {
    4436 good = FALSE;
    4437 break;
    4438 }
    4439 ++countedPathArcs;
    4440 }
    4441 if( !good )
    4442 {
    4444 newCol->remainsNetwork = FALSE;
    4445 break;
    4446 }
    4447
    4448 redMem->pathBackwards = !passesForwards;
    4449 if( countedPathArcs == getNumMemberArcs(dec, findMember(dec, redMem->member)) - 1 )
    4450 {
    4451 //Type -> Cycle;
    4452 //Propagate arc
    4454 }
    4455 else
    4456 {
    4457 //Type -> single_end
    4459 }
    4460 break;
    4461 }
    4463 {
    4464 SCIPABORT();
    4465 newCol->reducedMembers[reducedMember].type = REDUCEDMEMBER_TYPE_NOT_NETWORK;
    4466 break;
    4467 }
    4468 }
    4469}
    4470
    4471/** Determines the path type of a series member. */
    4472static
    4474 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    4475 SCIP_NETCOLADD* newCol, /**< The network matrix column addition data structure */
    4476 reduced_member_id reducedMember, /**< The reduced member to check */
    4477 spqr_member member, /**< The reduced member's member id */
    4478 MemberPathType previousType, /**< Type of the previous reduced member in the path */
    4479 spqr_arc source, /**< The marker connecting to the previous reduced member in the path */
    4480 spqr_arc target /**< The marker connecting to the next reduced member in the path */
    4481 )
    4482{
    4483 assert(dec);
    4484 assert(newCol);
    4485 assert(reducedMemberIsValid(reducedMember));
    4486 assert(SPQRmemberIsValid(member) && memberIsRepresentative(dec, member));
    4487 assert(getMemberType(dec, member) == SPQR_MEMBERTYPE_SERIES);
    4488
    4489 SPQRColReducedMember* redMem = &newCol->reducedMembers[reducedMember];
    4490 int countedPathArcs = 0;
    4491
    4492 SCIP_Bool good = TRUE;
    4493 SCIP_Bool passesForwards = TRUE;
    4494 for( path_arc_id pathArc = redMem->firstPathArc; pathArcIsValid(pathArc);
    4495 pathArc = newCol->pathArcs[pathArc].nextMember )
    4496 {
    4497 if( countedPathArcs == 0 )
    4498 {
    4499 passesForwards =
    4500 newCol->pathArcs[pathArc].reversed != arcIsReversedNonRigid(dec, newCol->pathArcs[pathArc].arc);
    4501 }
    4502 else if(( newCol->pathArcs[pathArc].reversed != arcIsReversedNonRigid(dec, newCol->pathArcs[pathArc].arc)) !=
    4503 passesForwards )
    4504 {
    4505 good = FALSE;
    4506 break;
    4507 }
    4508 ++countedPathArcs;
    4509 }
    4510 //If the internal directions of the arcs do not agree, we have no way to realize
    4511 if( !good )
    4512 {
    4514 newCol->remainsNetwork = FALSE;
    4515 return;
    4516 }
    4517 //If we are in the first skeleton processed, ignore the previous member type
    4518 if( !SPQRarcIsValid(source))
    4519 {
    4520 assert(countedPathArcs > 0);
    4521 assert(SPQRarcIsValid(target));
    4522 SCIP_Bool firstReversed = arcIsReversedNonRigid(dec, newCol->pathArcs[redMem->firstPathArc].arc);
    4523 SCIP_Bool targetReversed = arcIsReversedNonRigid(dec, target);
    4524 SCIP_Bool reversePath = newCol->pathArcs[redMem->firstPathArc].reversed;
    4525
    4526 if(( firstReversed == targetReversed ) == reversePath )
    4527 {
    4528 redMem->pathType = INTO_HEAD;
    4529 }
    4530 else
    4531 {
    4532 redMem->pathType = OUT_HEAD;
    4533 }
    4534 redMem->pathBackwards = !passesForwards;
    4535 return;
    4536 }
    4537 SCIP_Bool sourceReversed = arcIsReversedNonRigid(dec, source);
    4538 if( countedPathArcs > 0 )
    4539 {
    4540 SCIP_Bool isIntoHeadOrOutTail = isInto(previousType) == isHead(previousType);
    4541 SCIP_Bool isGood = isIntoHeadOrOutTail == ( sourceReversed == passesForwards );
    4542 if( !isGood )
    4543 {
    4545 newCol->remainsNetwork = FALSE;
    4546 return;
    4547 }
    4548 }
    4549 redMem->pathBackwards = !passesForwards;
    4550 if( SPQRarcIsValid(target) )
    4551 {
    4552 SCIP_Bool targetReversed = arcIsReversedNonRigid(dec, target);
    4553 SCIP_Bool inSameDirection = sourceReversed == targetReversed;
    4554
    4555 MemberPathType currentType;
    4556 switch( previousType )
    4557 {
    4558 case INTO_HEAD:
    4559 {
    4560 currentType = inSameDirection ? INTO_TAIL : INTO_HEAD;
    4561 break;
    4562 }
    4563 case INTO_TAIL:
    4564 {
    4565 currentType = inSameDirection ? INTO_HEAD : INTO_TAIL;
    4566 break;
    4567 }
    4568 case OUT_HEAD:
    4569 {
    4570 currentType = inSameDirection ? OUT_TAIL : OUT_HEAD;
    4571 break;
    4572 }
    4573 case OUT_TAIL:
    4574 default:
    4575 {
    4576 assert(previousType == OUT_TAIL);
    4577 currentType = inSameDirection ? OUT_HEAD : OUT_TAIL;
    4578 break;
    4579 }
    4580 }
    4581 redMem->pathType = currentType;
    4582 return;
    4583 }
    4584 //If we are in the last skeleton, we only have a source, so nothing further to do
    4585 assert(countedPathArcs > 0);
    4586 //Strictly speaking below are no-ops within the algorithm, but help with debugging
    4587 if( isInto(previousType))
    4588 {
    4589 redMem->pathType = INTO_HEAD;
    4590 }
    4591 else
    4592 {
    4593 redMem->pathType = OUT_HEAD;
    4594 }
    4595}
    4596
    4597/** Determines the path type of a parallel member. */
    4598static
    4600 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    4601 SCIP_NETCOLADD* newCol, /**< The network matrix column addition data structure */
    4602 reduced_member_id reducedMember, /**< The reduced member to check */
    4603 spqr_member member, /**< The reduced member's member id */
    4604 MemberPathType previousType, /**< Type of the previous reduced member in the path */
    4605 spqr_arc source, /**< The marker connecting to the previous reduced member in the path */
    4606 spqr_arc target /**< The marker connecting to the next reduced member in the path */
    4607 )
    4608{
    4609 assert(dec);
    4610 assert(newCol);
    4611 assert(reducedMemberIsValid(reducedMember));
    4612 assert(SPQRmemberIsValid(member) && memberIsRepresentative(dec, member));
    4613 assert(getMemberType(dec, member) == SPQR_MEMBERTYPE_PARALLEL);
    4614
    4615 //Parallel members must always be of degree two; if they are a leaf, they must contain an edge, which could have been propagated
    4616 assert(SPQRarcIsValid(source) && SPQRarcIsValid(target));
    4617 SCIP_Bool sourceReversed = arcIsReversedNonRigid(dec, source);
    4618 SCIP_Bool targetReversed = arcIsReversedNonRigid(dec, target);
    4619 SCIP_Bool inSameDirection = sourceReversed == targetReversed;
    4620
    4621 SPQRColReducedMember* redMem = &newCol->reducedMembers[reducedMember];
    4622
    4623 path_arc_id pathArc = redMem->firstPathArc;
    4624
    4625 SCIP_Bool arcPresent = FALSE;
    4626 if( pathArcIsValid(pathArc))
    4627 {
    4628 SCIP_Bool pathArcReversed =
    4629 newCol->pathArcs[pathArc].reversed != arcIsReversedNonRigid(dec, newCol->pathArcs[pathArc].arc);
    4630 SCIP_Bool intoHeadOrOutTail = isInto(previousType) == isHead(previousType);
    4631 SCIP_Bool good = intoHeadOrOutTail == ( pathArcReversed != sourceReversed );
    4632 if( !good )
    4633 {
    4635 newCol->remainsNetwork = FALSE;
    4636 return;
    4637 }
    4638 arcPresent = TRUE;
    4639 }
    4640
    4641 SCIP_Bool swapHeadTail = arcPresent != inSameDirection;
    4642 switch( previousType )
    4643 {
    4644 case INTO_HEAD:
    4645 {
    4646 redMem->pathType = swapHeadTail ? INTO_HEAD : INTO_TAIL;
    4647 break;
    4648 }
    4649 case INTO_TAIL:
    4650 {
    4651 redMem->pathType = swapHeadTail ? INTO_TAIL : INTO_HEAD;
    4652 break;
    4653 }
    4654 case OUT_HEAD:
    4655 {
    4656 redMem->pathType = swapHeadTail ? OUT_HEAD : OUT_TAIL;
    4657 break;
    4658 }
    4659 case OUT_TAIL:
    4660 {
    4661 redMem->pathType = swapHeadTail ? OUT_TAIL : OUT_HEAD;
    4662 break;
    4663 }
    4664 }
    4665}
    4666
    4667/** Determines the path type of a rigid member. */
    4668static
    4670 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    4671 SCIP_NETCOLADD* newCol, /**< The network matrix column addition data structure */
    4672 reduced_member_id reducedMember, /**< The reduced member to check */
    4673 MemberPathType previousType, /**< Type of the previous reduced member in the path */
    4674 spqr_arc source, /**< The marker connecting to the previous reduced member in the path */
    4675 spqr_arc target /**< The marker connecting to the next reduced member in the path */
    4676 )
    4677{
    4678 SPQRColReducedMember* redMem = &newCol->reducedMembers[reducedMember];
    4679 if( pathArcIsInvalid(redMem->firstPathArc))
    4680 {
    4681 assert(SPQRarcIsValid(source));
    4682 assert(SPQRarcIsValid(target));
    4683 //In this case, we need to check if the source and target are adjacent in any node
    4684
    4685 spqr_node sourceTail = findEffectiveArcTail(dec, source);
    4686 spqr_node sourceHead = findEffectiveArcHead(dec, source);
    4687 spqr_node targetTail = findEffectiveArcTail(dec, target);
    4688 spqr_node targetHead = findEffectiveArcHead(dec, target);
    4689 SCIP_Bool sourceHeadIsTargetHead = sourceHead == targetHead;
    4690 SCIP_Bool sourceTailIsTargetHead = sourceTail == targetHead;
    4691 SCIP_Bool sourceHeadIsTargetTail = sourceHead == targetTail;
    4692 SCIP_Bool sourceTailIsTargetTail = sourceTail == targetTail;
    4693
    4694 if( !(sourceHeadIsTargetHead || sourceTailIsTargetHead || sourceHeadIsTargetTail || sourceTailIsTargetTail) )
    4695 {
    4697 newCol->remainsNetwork = FALSE;
    4698 return;
    4699 }
    4700 assert(
    4701 ( sourceHeadIsTargetHead ? 1 : 0 ) + ( sourceHeadIsTargetTail ? 1 : 0 ) + ( sourceTailIsTargetHead ? 1 : 0 ) +
    4702 ( sourceTailIsTargetTail ? 1 : 0 ) == 1);
    4703 //assert simplicity; they can be adjacent in only exactly one node
    4704 SCIP_Bool isSourceHead = sourceHeadIsTargetHead || sourceHeadIsTargetTail;
    4705 SCIP_Bool isTargetTail = sourceHeadIsTargetTail || sourceTailIsTargetTail;
    4706 if( isHead(previousType) == isSourceHead )
    4707 {
    4708 //no need to reflect
    4709 redMem->reverseArcs = FALSE;
    4710 if( isInto(previousType))
    4711 {
    4712 if( isTargetTail )
    4713 {
    4714 redMem->pathType = INTO_TAIL;
    4715 }
    4716 else
    4717 {
    4718 redMem->pathType = INTO_HEAD;
    4719 }
    4720 }
    4721 else
    4722 {
    4723 if( isTargetTail )
    4724 {
    4725 redMem->pathType = OUT_TAIL;
    4726 }
    4727 else
    4728 {
    4729 redMem->pathType = OUT_HEAD;
    4730 }
    4731 }
    4732 }
    4733 else
    4734 {
    4735 redMem->reverseArcs = TRUE;
    4736 //because of the reversal, all the heads/tails are switched below
    4737 if( isInto(previousType))
    4738 {
    4739 if( isTargetTail )
    4740 {
    4741 redMem->pathType = INTO_HEAD;
    4742 }
    4743 else
    4744 {
    4745 redMem->pathType = INTO_TAIL;
    4746 }
    4747 }
    4748 else
    4749 {
    4750 if( isTargetTail )
    4751 {
    4752 redMem->pathType = OUT_HEAD;
    4753 }
    4754 else
    4755 {
    4756 redMem->pathType = OUT_TAIL;
    4757 }
    4758 }
    4759 }
    4760 assert(isInto(redMem->pathType) == isInto(previousType));
    4761 return;
    4762 }
    4763 determineRigidPath(dec, newCol, redMem);
    4764 if( redMem->type == REDUCEDMEMBER_TYPE_NOT_NETWORK )
    4765 {
    4766 return;
    4767 }
    4768 if( SPQRarcIsInvalid(source) )
    4769 {
    4770 assert(SPQRarcIsValid(target));
    4771 spqr_node targetTail = findEffectiveArcTail(dec, target);
    4772 spqr_node targetHead = findEffectiveArcHead(dec, target);
    4773 redMem->reverseArcs = FALSE;
    4774 if( redMem->rigidPathEnd == targetHead )
    4775 {
    4776 redMem->pathType = INTO_HEAD;
    4777 }
    4778 else if( redMem->rigidPathEnd == targetTail )
    4779 {
    4780 redMem->pathType = INTO_TAIL;
    4781 }
    4782 else if( redMem->rigidPathStart == targetHead )
    4783 {
    4784 redMem->pathType = OUT_HEAD;
    4785 }
    4786 else if( redMem->rigidPathStart == targetTail )
    4787 {
    4788 redMem->pathType = OUT_TAIL;
    4789 }
    4790 else
    4791 {
    4793 newCol->remainsNetwork = FALSE;
    4794 }
    4795 return;
    4796 }
    4797 assert(SPQRarcIsValid(source));
    4798 spqr_node sourceTail = findEffectiveArcTail(dec, source);
    4799 spqr_node sourceHead = findEffectiveArcHead(dec, source);
    4800
    4801 SCIP_Bool startsAtHead = sourceHead == redMem->rigidPathStart;
    4802 SCIP_Bool endsAtTail = sourceTail == redMem->rigidPathEnd;
    4803 SCIP_Bool startsAtTail = sourceTail == redMem->rigidPathStart;
    4804 SCIP_Bool endsAtHead = sourceHead == redMem->rigidPathEnd;
    4805
    4806 SCIP_Bool isIntoHeadOrOutTail = isInto(previousType) == isHead(previousType);
    4807 if( isIntoHeadOrOutTail )
    4808 {//into head or outTail
    4809 //Check if path starts at head or ends at tail
    4810 if( !startsAtHead && !endsAtTail )
    4811 {
    4813 newCol->remainsNetwork = FALSE;
    4814 return;
    4815 }
    4816 assert(startsAtHead || endsAtTail);//both can hold; they can form cycle but other components can not be reduced
    4817 // redMem->reverseArcs = isInto(previousType) != startsAtHead; //Reverse only if there is no path starting at head
    4818 }
    4819 else
    4820 {//Into tail or outHead
    4821 //Check if path starts at tail or ends at head
    4822 if( !startsAtTail && !endsAtHead )
    4823 {
    4825 newCol->remainsNetwork = FALSE;
    4826 return;
    4827 }
    4828 assert(startsAtTail || endsAtHead);// both can hold; they can form cycle but other components can not be reduced
    4829 // redMem->reverseArcs = isInto(previousType) != startsAtTail; //Reverse only if there is no path starting at tail
    4830 }
    4831
    4832 if( SPQRarcIsValid(target) )
    4833 {
    4834 spqr_node targetTail = findEffectiveArcTail(dec, target);
    4835 spqr_node targetHead = findEffectiveArcHead(dec, target);
    4836
    4837 //Check if they are not parallel; (below logic relies on this fact)
    4838 assert(!(( targetHead == sourceHead && targetTail == sourceTail ) ||
    4839 ( targetHead == sourceTail && targetTail == sourceHead )));
    4840
    4841 SCIP_Bool startsAtTargetHead = redMem->rigidPathStart == targetHead;
    4842 SCIP_Bool startsAtTargetTail = redMem->rigidPathStart == targetTail;
    4843 SCIP_Bool endsAtTargetHead = redMem->rigidPathEnd == targetHead;
    4844 SCIP_Bool endsAtTargetTail = redMem->rigidPathEnd == targetTail;
    4845
    4846 if( !(startsAtTargetHead || startsAtTargetTail || endsAtTargetHead || endsAtTargetTail) )
    4847 {
    4849 newCol->remainsNetwork = FALSE;
    4850 return;
    4851 }
    4852 SCIP_Bool outReverse = FALSE;
    4853 SCIP_Bool outHead = FALSE;
    4854
    4855 if( isInto(previousType) == isHead(previousType) )
    4856 {
    4857 if( startsAtHead && endsAtTail )
    4858 {
    4859 outReverse = ( startsAtTargetHead || startsAtTargetTail ) == isInto(previousType);
    4860 }
    4861 else if( startsAtHead )
    4862 {
    4863 outReverse = !isInto(previousType);
    4864 }
    4865 else
    4866 {
    4867 assert(endsAtTail);
    4868 outReverse = isInto(previousType);
    4869 }
    4870 }
    4871 else
    4872 {
    4873 if( startsAtTail && endsAtHead )
    4874 {
    4875 outReverse = ( startsAtTargetHead || startsAtTargetTail ) == isInto(previousType);
    4876 }
    4877 else if( startsAtTail )
    4878 {
    4879 outReverse = !isInto(previousType);
    4880 }
    4881 else
    4882 {
    4883 assert(endsAtHead);
    4884 outReverse = isInto(previousType);
    4885 }
    4886 }
    4887
    4888 //TODO: this if-else tree to compute two booleans can probably be simplified significantly
    4889 SCIP_Bool isBad = FALSE;
    4890 if( isInto(previousType) == isHead(previousType) )
    4891 {
    4892 if( startsAtHead && endsAtTail )
    4893 {
    4894 outHead = ( startsAtTargetTail || endsAtTargetHead ) == isInto(previousType);
    4895 }
    4896 else if( startsAtHead )
    4897 {
    4898 if( endsAtTargetHead )
    4899 {
    4900 outHead = isInto(previousType);
    4901 }
    4902 else if( endsAtTargetTail )
    4903 {
    4904 outHead = !isInto(previousType);
    4905 }
    4906 else
    4907 {
    4908 isBad = TRUE;
    4909 }
    4910 }
    4911 else
    4912 {
    4913 assert(endsAtTail);
    4914 if( startsAtTargetTail )
    4915 {
    4916 outHead = isInto(previousType);
    4917 }
    4918 else if( startsAtTargetHead )
    4919 {
    4920 outHead = !isInto(previousType);
    4921 }
    4922 else
    4923 {
    4924 isBad = TRUE;
    4925 }
    4926 }
    4927 }
    4928 else
    4929 {
    4930 if( startsAtTail && endsAtHead )
    4931 {
    4932 outHead = ( startsAtTargetTail || endsAtTargetHead ) == isInto(previousType);
    4933 }
    4934 else if( startsAtTail )
    4935 {
    4936 if( endsAtTargetHead )
    4937 {
    4938 outHead = isInto(previousType);
    4939 }
    4940 else if( endsAtTargetTail )
    4941 {
    4942 outHead = !isInto(previousType);
    4943 }
    4944 else
    4945 {
    4946 isBad = TRUE;
    4947 }
    4948 }
    4949 else
    4950 {
    4951 assert(endsAtHead);
    4952 if( startsAtTargetTail )
    4953 {
    4954 outHead = isInto(previousType);
    4955 }
    4956 else if( startsAtTargetHead )
    4957 {
    4958 outHead = !isInto(previousType);
    4959 }
    4960 else
    4961 {
    4962 isBad = TRUE;
    4963 }
    4964 }
    4965 }
    4966 if( isBad )
    4967 {
    4969 newCol->remainsNetwork = FALSE;
    4970 return;
    4971 }
    4972
    4973 redMem->reverseArcs = outReverse;
    4974 if( isInto(previousType) )
    4975 {
    4976 redMem->pathType = outHead ? INTO_HEAD : INTO_TAIL;
    4977 }
    4978 else
    4979 {
    4980 redMem->pathType = outHead ? OUT_HEAD : OUT_TAIL;
    4981 }
    4982 return;
    4983 }
    4984
    4985 //TODO: is this simplifyable?
    4986 if( isInto(previousType) == isHead(previousType) )
    4987 {
    4988 redMem->reverseArcs = startsAtHead != isInto(previousType);
    4989 }
    4990 else
    4991 {
    4992 redMem->reverseArcs = startsAtTail != isInto(previousType);
    4993 }
    4994 //last member of the path. Since we already checked the source,
    4995 //Below is technically no op, but helps with debugging
    4996 if( isInto(previousType) )
    4997 {
    4998 redMem->pathType = INTO_HEAD;
    4999 }
    5000 else
    5001 {
    5002 redMem->pathType = OUT_HEAD;
    5003 }
    5004}
    5005
    5006/** Determines the path type of a single member. */
    5007static
    5009 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    5010 SCIP_NETCOLADD* newCol, /**< The network matrix column addition data structure */
    5011 reduced_member_id reducedMember, /**< The reduced member to check */
    5012 spqr_member member, /**< The reduced member's member id */
    5013 MemberPathType previousType, /**< Type of the previous reduced member in the path */
    5014 spqr_arc source, /**< The marker connecting to the previous reduced member in the path */
    5015 spqr_arc target /**< The marker connecting to the next reduced member in the path */
    5016 )
    5017{
    5018 newCol->reducedMembers[reducedMember].pathSourceArc = source;
    5019 newCol->reducedMembers[reducedMember].pathTargetArc = target;
    5020 //Check if the marked edges with the given signs
    5021 //form a (reverse) directed path from one of the source's end nodes to one of the target's end nodes
    5022 switch( getMemberType(dec, member) )
    5023 {
    5025 {
    5026 determinePathRigidType(dec, newCol, reducedMember, previousType, source, target);
    5027 break;
    5028 }
    5030 {
    5031 determinePathParallelType(dec, newCol, reducedMember, member, previousType, source, target);
    5032 break;
    5033 }
    5035 {
    5036 determinePathSeriesType(dec, newCol, reducedMember, member, previousType, source, target);
    5037 break;
    5038 }
    5041 {
    5042 //In release
    5043 newCol->remainsNetwork = FALSE;
    5044 SCIPABORT();
    5045 break;
    5046 }
    5047 }
    5048}
    5049
    5050/** Determines the path types of all reduced members.
    5051 *
    5052 * The reduced members themselves also form a path in the reduced decomposition.
    5053 */
    5054static
    5056 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    5057 SCIP_NETCOLADD* newCol, /**< The network matrix column addition data structure */
    5058 SPQRColReducedComponent* component /**< The component to determine the path types for */
    5059 )
    5060{
    5061 assert(dec);
    5062 assert(newCol);
    5063 assert(component);
    5064 assert(component->numPathEndMembers == 2);
    5065
    5066 assert(component->pathEndMembers[0] != component->root);
    5067
    5068 //We check the path by going from end to end. We start at the leaf and process every component,
    5069 //walking down until we hit the root.
    5070 //Then, we walk up from the root and process each component in the same manner.
    5071 reduced_member_id reducedStart = component->pathEndMembers[0];
    5072 spqr_arc toPrevious = SPQR_INVALID_ARC;
    5073 spqr_arc toNext = SPQR_INVALID_ARC;
    5074 MemberPathType previousType = INTO_HEAD;//Arbitrary, is ignored in the first call
    5075
    5076 spqr_member member = newCol->reducedMembers[reducedStart].member;
    5077 reduced_member_id reducedMember = reducedStart;
    5078 reduced_member_id previousReducedMember = reducedStart;
    5079 while( reducedMember != component->root )
    5080 {
    5081 toNext = markerToParent(dec, member);
    5082 determinePathMemberType(dec, newCol, reducedMember, member, previousType, toPrevious, toNext);
    5083 if( !newCol->remainsNetwork )
    5084 {
    5085 return;
    5086 }
    5087 previousType = newCol->reducedMembers[reducedMember].pathType;
    5088 toPrevious = markerOfParent(dec, member);
    5089 member = findMemberParent(dec, newCol->reducedMembers[reducedMember].member);
    5090 previousReducedMember = reducedMember;
    5091 reducedMember = newCol->memberInformation[member].reducedMember;
    5092 newCol->reducedMembers[previousReducedMember].nextPathMember = reducedMember;
    5093 newCol->reducedMembers[previousReducedMember].nextPathMemberIsParent = TRUE;
    5094 }
    5095
    5096 while( reducedMember != component->pathEndMembers[1] )
    5097 {
    5098 //Search the (other) child node
    5100 //a bit ugly linear search, but not a problem for time complexity
    5101 for( children_idx i = newCol->reducedMembers[reducedMember].firstChild;
    5102 i <
    5103 newCol->reducedMembers[reducedMember].firstChild + newCol->reducedMembers[reducedMember].numChildren; ++i )
    5104 {
    5105 reduced_member_id childReduced = newCol->childrenStorage[i];
    5106 if( newCol->reducedMembers[childReduced].type != REDUCEDMEMBER_TYPE_CYCLE &&
    5107 childReduced != previousReducedMember )
    5108 {
    5109 child = childReduced;
    5110 break;
    5111 }
    5112 }
    5113 assert(reducedMemberIsValid(child));
    5114
    5115 spqr_member childMember = newCol->reducedMembers[child].member;
    5116 toNext = markerOfParent(dec, childMember);
    5117
    5118 determinePathMemberType(dec, newCol, reducedMember, member, previousType, toPrevious, toNext);
    5119 if( !newCol->remainsNetwork )
    5120 {
    5121 return;
    5122 }
    5123 previousType = newCol->reducedMembers[reducedMember].pathType;
    5124 toPrevious = markerToParent(dec, childMember);
    5125 member = childMember;
    5126 previousReducedMember = reducedMember;
    5127 reducedMember = child;
    5128 newCol->reducedMembers[previousReducedMember].nextPathMember = reducedMember;
    5129 newCol->reducedMembers[previousReducedMember].nextPathMemberIsParent = FALSE;
    5130 }
    5131 //The last iteration is not performed by the loops above.
    5132 //We explicitly set the target arc to invalid in order to indicate that this is the last iteration.
    5133 toNext = SPQR_INVALID_ARC;
    5134 determinePathMemberType(dec, newCol, reducedMember, member, previousType, toPrevious, toNext);
    5135 newCol->reducedMembers[reducedMember].nextPathMember = INVALID_REDUCED_MEMBER;
    5136 //since we return anyways, no need to check newCol->remainsNetwork explicitly
    5137}
    5138
    5139/** Check if a rigid leaf closes a cycle with its child.
    5140 *
    5141 * If so, we can propagate this cycle to a virtual arc of the child node member and shrink the decomposition.
    5142 */
    5143static
    5145 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    5146 SCIP_NETCOLADD* newCol, /**< The network matrix column addition data structure */
    5147 reduced_member_id leaf, /**< The leaf node of the reduced SPQR tree */
    5148 spqr_arc toParent, /**< The virtual arc to the leaf node's neighbour */
    5149 reduced_member_id parent, /**< The neighbouring member of the leaf node. */
    5150 spqr_arc toChild /**< The virtual arc from the neighbouring member pointing to the leaf. */
    5151 )
    5152{
    5153 SPQRColReducedMember* leafMember = &newCol->reducedMembers[leaf];
    5154 determineRigidPath(dec, newCol, leafMember);
    5155 if( leafMember->type == REDUCEDMEMBER_TYPE_NOT_NETWORK )
    5156 {
    5157 return;
    5158 }
    5159 spqr_node targetHead = findEffectiveArcHead(dec, toParent);
    5160 spqr_node targetTail = findEffectiveArcTail(dec, toParent);
    5161 SCIP_Bool matches = leafMember->rigidPathStart == targetTail && leafMember->rigidPathEnd == targetHead;
    5162 SCIP_Bool opposite = leafMember->rigidPathStart == targetHead && leafMember->rigidPathEnd == targetTail;
    5163 if( matches || opposite )
    5164 {
    5165 leafMember->type = REDUCEDMEMBER_TYPE_CYCLE;
    5166 createPathArc(dec, newCol, toChild, parent, opposite);
    5167 return;
    5168 }
    5169 leafMember->type = REDUCEDMEMBER_TYPE_MERGED;
    5170}
    5171
    5172/** Check if a leaf node closes a cycle with its child.
    5173 *
    5174 * If so, we can propagate this cycle to a virtual arc of the child node member and shrink the decomposition.
    5175 */
    5176static
    5178 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    5179 SCIP_NETCOLADD* newCol, /**< The network matrix column addition data structure */
    5180 reduced_member_id leaf, /**< The leaf node of the reduced SPQR tree */
    5181 spqr_arc toParent, /**< The virtual arc to the leaf node's neighbour */
    5182 reduced_member_id parent, /**< The neighbouring member of the leaf node. */
    5183 spqr_arc toChild /**< The virtual arc from the neighbouring member pointing to the leaf. */
    5184 )
    5185{
    5186 assert(dec);
    5187 assert(newCol);
    5188 assert(SPQRarcIsValid(toParent));
    5189 assert(SPQRarcIsValid(toChild));
    5190 assert(!arcIsTree(dec, toParent));
    5191 assert(reducedMemberIsValid(leaf));
    5192 assert(reducedMemberIsValid(parent));
    5193
    5194 switch( getMemberType(dec, newCol->reducedMembers[leaf].member) )
    5195 {
    5197 {
    5198 checkRigidLeaf(dec, newCol, leaf, toParent, parent, toChild);
    5199 break;
    5200 }
    5202 {
    5203 SPQRColReducedMember* reducedMember = &newCol->reducedMembers[leaf];
    5204 assert(pathArcIsValid(reducedMember->firstPathArc));
    5205 reducedMember->type = REDUCEDMEMBER_TYPE_CYCLE;
    5206
    5207 SCIP_Bool pathArcReversed = newCol->pathArcs[reducedMember->firstPathArc].reversed;
    5208 SCIP_Bool arcPathArcIsReverse = arcIsReversedNonRigid(dec, newCol->pathArcs[reducedMember->firstPathArc].arc);
    5209 SCIP_Bool parentReversed = arcIsReversedNonRigid(dec, toParent);
    5210 createPathArc(dec, newCol, toChild, parent, ( arcPathArcIsReverse == parentReversed ) == pathArcReversed);
    5211 break;
    5212 }
    5215 {
    5216 SPQRColReducedMember* reducedMember = &newCol->reducedMembers[leaf];
    5217 int countedPathArcs = 0;
    5218 SCIP_Bool good = TRUE;
    5219 SCIP_Bool passesForwards = TRUE;
    5220 for( path_arc_id pathArc = reducedMember->firstPathArc; pathArcIsValid(pathArc);
    5221 pathArc = newCol->pathArcs[pathArc].nextMember )
    5222 {
    5223 if( countedPathArcs == 0 )
    5224 {
    5225 passesForwards =
    5226 newCol->pathArcs[pathArc].reversed != arcIsReversedNonRigid(dec, newCol->pathArcs[pathArc].arc);
    5227 }
    5228 else if(
    5229 (newCol->pathArcs[pathArc].reversed != arcIsReversedNonRigid(dec, newCol->pathArcs[pathArc].arc)) !=
    5230 passesForwards )
    5231 {
    5232 good = FALSE;
    5233 break;
    5234 }
    5235 ++countedPathArcs;
    5236 }
    5237 if( !good )
    5238 {
    5239 reducedMember->type = REDUCEDMEMBER_TYPE_NOT_NETWORK;
    5240 newCol->remainsNetwork = FALSE;
    5241 break;
    5242 }
    5243
    5244 reducedMember->pathBackwards = !passesForwards;
    5245 if( countedPathArcs == getNumMemberArcs(dec, findMember(dec, reducedMember->member)) - 1 )
    5246 {
    5247 //Type -> Cycle;
    5248 //Propagate arc
    5249 reducedMember->type = REDUCEDMEMBER_TYPE_CYCLE;
    5250
    5251 SCIP_Bool firstArcReversed = arcIsReversedNonRigid(dec, newCol->pathArcs[reducedMember->firstPathArc].arc);
    5252 SCIP_Bool firstArcInPathReverse = newCol->pathArcs[reducedMember->firstPathArc].reversed;
    5253 SCIP_Bool parentReversed = arcIsReversedNonRigid(dec, toParent);
    5254 createPathArc(dec, newCol, toChild, parent,
    5255 ( parentReversed == firstArcReversed ) != firstArcInPathReverse);
    5256 }
    5257 else
    5258 {
    5259 //Type -> single_end
    5260 reducedMember->type = REDUCEDMEMBER_TYPE_MERGED;
    5261 }
    5262
    5263 break;
    5264 }
    5266 {
    5267 SCIPABORT();
    5269 break;
    5270 }
    5271 }
    5272 return newCol->reducedMembers[leaf].type;
    5273}
    5274
    5275/** Recursively removes leaf nodes whose path forms cycles with the virtual arc to its children. */
    5276static
    5278 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    5279 SCIP_NETCOLADD* newCol /**< The network matrix column addition data structure */
    5280 )
    5281{
    5282 assert(dec);
    5283 assert(newCol);
    5284
    5285 int leafArrayIndex = 0;
    5286 while( leafArrayIndex != newCol->numLeafMembers )
    5287 {
    5288 reduced_member_id leaf = newCol->leafMembers[leafArrayIndex];
    5289 //next is invalid if the member is not in the reduced decomposition.
    5290 reduced_member_id next = newCol->reducedMembers[leaf].parent;
    5291 spqr_arc parentMarker = markerToParent(dec, newCol->reducedMembers[leaf].member);
    5292 if( reducedMemberIsValid(next) && !arcIsTree(dec, parentMarker))
    5293 {
    5294 assert(reducedMemberIsValid(next));
    5295 assert(SPQRarcIsValid(parentMarker));
    5296 ReducedMemberType type = checkLeaf(dec, newCol, leaf, parentMarker, next,
    5297 markerOfParent(dec, newCol->reducedMembers[leaf].member));
    5298 if( type == REDUCEDMEMBER_TYPE_CYCLE )
    5299 {
    5300 ++newCol->reducedMembers[next].numPropagatedChildren;
    5301 if( newCol->reducedMembers[next].numPropagatedChildren == newCol->reducedMembers[next].numChildren )
    5302 {
    5303 newCol->leafMembers[leafArrayIndex] = next;
    5304 }
    5305 else
    5306 {
    5307 ++leafArrayIndex;
    5308 }
    5309 }
    5310 else if( type == REDUCEDMEMBER_TYPE_NOT_NETWORK )
    5311 {
    5312 return;
    5313 }
    5314 else
    5315 {
    5316 assert(type == REDUCEDMEMBER_TYPE_MERGED);
    5317 ++leafArrayIndex;
    5318 int component = newCol->reducedMembers[leaf].componentIndex;
    5319 if( newCol->reducedComponents[component].numPathEndMembers >= 2 )
    5320 {
    5321 newCol->remainsNetwork = FALSE;
    5322 return;
    5323 }
    5324 assert(newCol->reducedComponents[component].numPathEndMembers < 2);
    5325 newCol->reducedComponents[component].pathEndMembers[newCol->reducedComponents[component].numPathEndMembers] = leaf;
    5326 ++newCol->reducedComponents[component].numPathEndMembers;
    5327 }
    5328 }
    5329 else
    5330 {
    5331 ++leafArrayIndex;
    5332 int component = newCol->reducedMembers[leaf].componentIndex;
    5333 if( newCol->reducedComponents[component].numPathEndMembers >= 2 )
    5334 {
    5335 newCol->remainsNetwork = FALSE;
    5336 return;
    5337 }
    5338 assert(newCol->reducedComponents[component].numPathEndMembers < 2);
    5339 newCol->reducedComponents[component].pathEndMembers[newCol->reducedComponents[component].numPathEndMembers] = leaf;
    5340 ++newCol->reducedComponents[component].numPathEndMembers;
    5341 }
    5342 }
    5343
    5344 for( int j = 0; j < newCol->numReducedComponents; ++j )
    5345 {
    5346 //The reduced root might be a leaf as well: we propagate it last
    5347 reduced_member_id root = newCol->reducedComponents[j].root;
    5348
    5349 while( TRUE ) /*lint !e716*/
    5350 {
    5351 if( newCol->reducedMembers[root].numPropagatedChildren != newCol->reducedMembers[root].numChildren - 1 )
    5352 {
    5353 break;
    5354 }
    5355 //TODO: bit ugly, have to do a linear search for the child
    5357 spqr_arc markerToChild = SPQR_INVALID_ARC;
    5358 for( children_idx i = newCol->reducedMembers[root].firstChild;
    5359 i < newCol->reducedMembers[root].firstChild + newCol->reducedMembers[root].numChildren; ++i )
    5360 {
    5361 reduced_member_id childReduced = newCol->childrenStorage[i];
    5362 if( newCol->reducedMembers[childReduced].type != REDUCEDMEMBER_TYPE_CYCLE )
    5363 {
    5364 child = childReduced;
    5365 markerToChild = markerOfParent(dec, newCol->reducedMembers[child].member);
    5366 break;
    5367 }
    5368 }
    5369 assert(SPQRmemberIsValid(newCol->reducedMembers[child].member));
    5370 assert(SPQRarcIsValid(markerToChild));
    5371 if( !arcIsTree(dec, markerToChild) )
    5372 {
    5373 ReducedMemberType type = checkLeaf(dec, newCol, root, markerToChild, child,
    5374 markerToParent(dec, newCol->reducedMembers[child].member));
    5375 if( type == REDUCEDMEMBER_TYPE_CYCLE )
    5376 {
    5377 root = child;
    5378 continue;
    5379 }
    5380 else if( type == REDUCEDMEMBER_TYPE_NOT_NETWORK )
    5381 {
    5382 return;
    5383 }
    5384 }
    5385 //If the root has exactly one neighbour and is not contained, it is also considered a path end member
    5386 int component = newCol->reducedMembers[root].componentIndex;
    5387 SCIP_Bool rootPresent = FALSE;
    5388 for( int i = 0; i < newCol->reducedComponents[component].numPathEndMembers; ++i )
    5389 {
    5390 rootPresent = rootPresent || ( newCol->reducedComponents[component].pathEndMembers[i] == root );
    5391 }
    5392 if( !rootPresent )
    5393 {
    5394 if( newCol->reducedComponents[component].numPathEndMembers >= 2 )
    5395 {
    5396 newCol->remainsNetwork = FALSE;
    5397 return;
    5398 }
    5399 newCol->reducedComponents[component].pathEndMembers[newCol->reducedComponents[component].numPathEndMembers] = root;
    5400 ++newCol->reducedComponents[component].numPathEndMembers;
    5401 }
    5402 break;
    5403 }
    5404
    5405 newCol->reducedComponents[j].root = root;
    5407 }
    5408}
    5409
    5410/** Determine the type of a single component. */
    5411static
    5413 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    5414 SCIP_NETCOLADD* newCol, /**< The network matrix column addition data structure */
    5415 SPQRColReducedComponent* component /**< The component to determine the types for */
    5416 )
    5417{
    5418 assert(dec);
    5419 assert(newCol);
    5420 assert(component);
    5421
    5422 if( component->numPathEndMembers == 1 )
    5423 {
    5424 assert(component->root == component->pathEndMembers[0]);
    5425 determineSingleComponentType(dec, newCol, component->root);
    5426 }
    5427 else
    5428 {
    5429 assert(component->numPathEndMembers == 2);
    5430 determinePathTypes(dec, newCol, component);
    5431 }
    5432}
    5433
    5434/** Checks if the given column can be added to the network matrix decomposition.
    5435 *
    5436 * See header for more info.
    5437 */
    5438static
    5440 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    5441 SCIP_NETCOLADD* coladd, /**< The network matrix column addition data structure */
    5442 int column, /**< The column to add */
    5443 const int* nonzrows, /**< The column's nonzero row indices */
    5444 const double* nonzvals, /**< The column's nonzero entries */
    5445 int nnonzs /**< The number of nonzeros in the column */
    5446 )
    5447{
    5448 assert(dec);
    5449 assert(coladd);
    5450 assert(nnonzs == 0 || ( nonzrows && nonzvals ));
    5451
    5452 /* A column can only be added once */
    5453 if( netMatDecDataContainsColumn(dec,column) )
    5454 {
    5455 return SCIP_INVALIDDATA;
    5456 }
    5457 coladd->remainsNetwork = TRUE;
    5458 cleanupPreviousIteration(dec, coladd);
    5459 //assert that previous iteration was cleaned up
    5460
    5461 //Store call data
    5462 SCIP_CALL( newColUpdateColInformation(dec, coladd, column, nonzrows, nonzvals, nnonzs) );
    5463
    5464 //compute reduced decomposition
    5466 //initialize path arcs in reduced decomposition
    5467 SCIP_CALL( createPathArcs(dec, coladd) );
    5468 SCIP_CALL( computeLeafMembers(dec, coladd) );
    5469 propagateCycles(dec, coladd);
    5470 //determine types
    5471 if( coladd->remainsNetwork )
    5472 {
    5473 for( int i = 0; i < coladd->numReducedComponents; ++i )
    5474 {
    5475 determineComponentTypes(dec, coladd, &coladd->reducedComponents[i]);
    5476 }
    5477 }
    5478 //clean up memberInformation
    5480
    5481 return SCIP_OKAY;
    5482}
    5483
    5484/** Struct that contains the data that tells us how to add the new column after the graph has been modified.
    5485 *
    5486 * In the case the member is a series or parallel node, the new column and rows are placed in series or parallel,
    5487 * respectively. Otherwise, the edge can be added between head and tail in a rigid member.
    5488 */
    5489typedef struct
    5490{
    5491 spqr_member member; /**< The member where the new column should be added */
    5492 spqr_node head; /**< The head node of the new column (rigid members only) */
    5493 spqr_node tail; /**< The tail node of the new column (rigid members only) */
    5494 spqr_arc representative; /**< The representative arc of the new column */
    5495 SCIP_Bool reversed; /**< Is the new column reversed? */
    5497
    5498#define NEWCOLINFORMATION_EMPTY { SPQR_INVALID_MEMBER, SPQR_INVALID_NODE, SPQR_INVALID_NODE, SPQR_INVALID_ARC, FALSE }
    5499
    5500/** Set the head node of the new column edge to be added. */
    5501static
    5503 NewColInformation* info, /**< The new column information */
    5504 spqr_node node /**< The head node of the new column edge */
    5505 )
    5506{
    5507 assert(SPQRnodeIsValid(node));
    5508 assert(SPQRnodeIsInvalid(info->head));
    5509 assert(info);
    5510
    5511 info->head = node;
    5512}
    5513
    5514/** Set the tail node of the new column edge to be added. */
    5515static
    5517 NewColInformation* info, /**< The new column information */
    5518 spqr_node node /**< The tail node of the new column edge */
    5519 )
    5520{
    5521 assert(SPQRnodeIsValid(node));
    5522 assert(info);
    5523 assert(SPQRnodeIsInvalid(info->tail));
    5524
    5525 info->tail = node;
    5526}
    5527
    5528/** Set whether the new column arc should be reversed. */
    5529static
    5531 NewColInformation* info, /**< The new column information */
    5532 SCIP_Bool reversed /**< Should the new column arc be reversed? */
    5533 )
    5534{
    5535 assert(info);
    5536
    5537 info->reversed = reversed;
    5538}
    5539
    5540/** Set the member that contains the new column arc. */
    5541static
    5543 NewColInformation* info, /**< The new column information */
    5544 spqr_member member /**< The decomposition member that contains the new column arc */
    5545 )
    5546{
    5547 assert(info);
    5548
    5549 info->member = member;
    5550}
    5551
    5552/** Set the representative arc of the new column arc. */
    5553static
    5555 NewColInformation* info, /**< The new column information */
    5556 spqr_arc representative /**< The representative arc of the new column arc */
    5557 )
    5558{
    5559 assert(info);
    5560
    5561 info->representative = representative;
    5562}
    5563
    5564/** Splits a parallel member into two adjacent parallel members connected by a virtual edge pair.
    5565 *
    5566 * One member keeps the two arcs passed to this function, the other member gets all other arcs.
    5567 */
    5568static
    5570 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    5571 spqr_member parallel, /**< The parallel member */
    5572 spqr_arc arc1, /**< First arc to keep. */
    5573 spqr_arc arc2, /**< Second arc to keep. */
    5574 spqr_member* childParallel /**< Out pointer to the new child parallel member. */
    5575 )
    5576{
    5577 assert(dec);
    5578 assert(SPQRarcIsValid(arc1));
    5579 assert(SPQRarcIsValid(arc2));
    5580 assert(SPQRmemberIsValid(parallel));
    5581
    5582 SCIP_Bool childContainsTree = arcIsTree(dec, arc1) || arcIsTree(dec, arc2);
    5583 spqr_arc toParent = markerToParent(dec, parallel);
    5584 SCIP_Bool parentMoved = toParent == arc1 || toParent == arc2;
    5585 SCIP_CALL( createMember(dec, SPQR_MEMBERTYPE_PARALLEL, childParallel) );
    5586
    5587 moveArcToNewMember(dec, arc1, parallel, *childParallel);
    5588 moveArcToNewMember(dec, arc2, parallel, *childParallel);
    5589
    5590 if( parentMoved )
    5591 {
    5592 SCIP_CALL( createMarkerPair(dec, *childParallel, parallel, !childContainsTree, FALSE, FALSE) );
    5593 }
    5594 else
    5595 {
    5596 SCIP_CALL( createMarkerPair(dec, parallel, *childParallel, childContainsTree, FALSE, FALSE) );
    5597 }
    5598
    5599 return SCIP_OKAY;
    5600}
    5601
    5602/** Very elaborate function that splits a series member into multiple members based on the structure of the path arcs.
    5603 *
    5604 * The updated member reflects the structure of the updated SPQR tree after the new column arc is added.
    5605 */
    5606static
    5608 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    5609 SCIP_NETCOLADD* newCol, /**< The network matrix column addition data structure */
    5610 SPQRColReducedMember* reducedMember, /**< The reduced member of the series member to split. */
    5611 spqr_member member, /**< The series member to split. */
    5612 spqr_member* loopMember, /**< Out-pointer to a new loop member that may be created */
    5613 NewColInformation* newColInfo /**< New column information struct */
    5614 )
    5615{
    5616 assert(dec);
    5617 assert(reducedMember);
    5618 assert(SPQRmemberIsValid(member));
    5619 assert(memberIsRepresentative(dec, member));
    5620
    5621 assert(reducedMember->numPathArcs != 0);
    5622 SCIP_Bool createPathSeries = reducedMember->numPathArcs > 1;
    5623 SCIP_Bool convertOriginal = reducedMember->numPathArcs == getNumMemberArcs(dec, member) - 1;
    5624
    5625 //TODO: for now very elaborate to first get logic correct. Can probably merge some branches later...
    5626 if( !createPathSeries && !convertOriginal )
    5627 {
    5628 spqr_member parallel;
    5630 path_arc_id pathArcId = reducedMember->firstPathArc;
    5631 assert(pathArcIsValid(pathArcId));
    5632 spqr_arc marked = newCol->pathArcs[pathArcId].arc;
    5633 assert(marked != markerToParent(dec, member));//TODO: handle this case later
    5634 moveArcToNewMember(dec, marked, member, parallel);
    5635 SCIP_Bool reversed = arcIsReversedNonRigid(dec, marked);
    5636 SCIP_CALL( createMarkerPair(dec, member, parallel, TRUE, reversed, reversed) );
    5637 *loopMember = parallel;
    5638
    5639 if( reversed == reducedMember->pathBackwards )
    5640 {
    5641 setTerminalReversed(newColInfo, !reversed);
    5642 }
    5643 else
    5644 {
    5645 setTerminalReversed(newColInfo, reversed);
    5646 }
    5647
    5648 setTerminalMember(newColInfo, *loopMember);
    5649 return SCIP_OKAY;
    5650 }
    5651 if( !createPathSeries && convertOriginal )
    5652 {
    5653 //only one path arc; we are in a loop; no need to change anything
    5654 assert(getNumMemberArcs(dec, member) == 2);
    5655 assert(reducedMember->numPathArcs == 1);
    5656 *loopMember = member;
    5657 changeLoopToParallel(dec, member);
    5658
    5659 path_arc_id pathArcId = reducedMember->firstPathArc;
    5660 spqr_arc marked = newCol->pathArcs[pathArcId].arc;
    5661 //The 'reversed' field has different meaning for parallels, so we need to change orientation when converting to a parallel
    5662 arcFlipReversed(dec, marked);
    5663
    5664 setTerminalReversed(newColInfo, reducedMember->pathBackwards);
    5665 setTerminalMember(newColInfo, *loopMember);
    5666 return SCIP_OKAY;
    5667 }
    5668 if( createPathSeries && !convertOriginal )
    5669 {
    5670 spqr_member pathMember;
    5671 SCIP_CALL( createMember(dec, SPQR_MEMBERTYPE_SERIES, &pathMember) );
    5672
    5673 path_arc_id pathArcId = reducedMember->firstPathArc;
    5674 SCIP_Bool parentMoved = FALSE;
    5675 while( pathArcIsValid(pathArcId))
    5676 {
    5677 spqr_arc pathArc = newCol->pathArcs[pathArcId].arc;
    5678 pathArcId = newCol->pathArcs[pathArcId].nextMember;
    5679 if( pathArc == markerToParent(dec, member))
    5680 {
    5681 parentMoved = TRUE;
    5682 }
    5683 moveArcToNewMember(dec, pathArc, member, pathMember);
    5684 }
    5685
    5686 SCIP_CALL( createMember(dec, SPQR_MEMBERTYPE_PARALLEL, loopMember) );
    5687
    5688 if( !parentMoved )
    5689 {
    5690 SCIP_CALL( createMarkerPair(dec, member, *loopMember, TRUE, FALSE, FALSE) );
    5691 SCIP_CALL( createMarkerPair(dec, *loopMember, pathMember, TRUE, FALSE, TRUE) );
    5692 }
    5693 else
    5694 {
    5695 SCIP_CALL( createMarkerPair(dec, pathMember, *loopMember, FALSE, FALSE, TRUE) );
    5696 SCIP_CALL( createMarkerPair(dec, *loopMember, member, FALSE, FALSE, FALSE) );
    5697 }
    5698
    5699 setTerminalReversed(newColInfo, !reducedMember->pathBackwards);
    5700 setTerminalMember(newColInfo, *loopMember);
    5701 return SCIP_OKAY;
    5702 }
    5703 assert(createPathSeries && convertOriginal);
    5704 //There's one exception in this case
    5705 //if the single unmarked (column) marker is a parent or child marker to a parallel member, we add the edge there
    5706 {
    5707 spqr_member adjacentMember = SPQR_INVALID_MEMBER;
    5708 spqr_arc adjacentMarker = SPQR_INVALID_ARC;
    5709 spqr_arc memberMarker = SPQR_INVALID_ARC;
    5710 spqr_arc firstArc = getFirstMemberArc(dec, reducedMember->member);
    5711 spqr_arc arc = firstArc;
    5712 do
    5713 {
    5714 if( !newCol->arcInPath[arc] )
    5715 {
    5716 if( arc == markerToParent(dec, reducedMember->member))
    5717 {
    5718 adjacentMember = findMemberParent(dec, reducedMember->member);
    5719 adjacentMarker = markerOfParent(dec, reducedMember->member);
    5720 memberMarker = arc;
    5721 }
    5722 else if( arcIsChildMarker(dec, arc))
    5723 {
    5724 adjacentMember = findArcChildMember(dec, arc);
    5725 adjacentMarker = markerToParent(dec, adjacentMember);
    5726 memberMarker = arc;
    5727 }
    5728
    5729 break;//There is only a singular such arc
    5730 }
    5731 arc = getNextMemberArc(dec, arc);
    5732 }
    5733 while( arc != firstArc );
    5734
    5735 if( SPQRmemberIsValid(adjacentMember))
    5736 {
    5737 SPQRMemberType adjacentType = getMemberType(dec, adjacentMember);
    5738 if( adjacentType == SPQR_MEMBERTYPE_PARALLEL )
    5739 {
    5740 //Figure out if the markers are the same or opposite orientations
    5741 //If they are the same, we can proceed as normal, otherwise, we need to flip the placed edge
    5742 SCIP_Bool markersHaveSameOrientation =
    5743 arcIsReversedNonRigid(dec, adjacentMarker) == arcIsReversedNonRigid(dec, memberMarker);
    5744 setTerminalReversed(newColInfo, reducedMember->pathBackwards == markersHaveSameOrientation);
    5745 setTerminalMember(newColInfo, adjacentMember);
    5746 return SCIP_OKAY;
    5747 }
    5748 }
    5749 }
    5750
    5751 spqr_member pathMember;
    5752 SCIP_CALL( createMember(dec, SPQR_MEMBERTYPE_SERIES, &pathMember) );
    5753
    5754 path_arc_id pathArcId = reducedMember->firstPathArc;
    5755 SCIP_Bool parentMoved = FALSE;
    5756 while( pathArcIsValid(pathArcId))
    5757 {
    5758 spqr_arc pathArc = newCol->pathArcs[pathArcId].arc;
    5759 pathArcId = newCol->pathArcs[pathArcId].nextMember;
    5760 if( pathArc == markerToParent(dec, member))
    5761 {
    5762 parentMoved = TRUE;
    5763 }
    5764 moveArcToNewMember(dec, pathArc, member, pathMember);
    5765 }
    5766 if( parentMoved )
    5767 {
    5768 SCIP_CALL( createMarkerPair(dec, pathMember, member, FALSE, FALSE, FALSE) );
    5769 }
    5770 else
    5771 {
    5772 SCIP_CALL( createMarkerPair(dec, member, pathMember, TRUE, FALSE, FALSE) );
    5773 }
    5774
    5775 changeLoopToParallel(dec, member);
    5776
    5777 *loopMember = member;
    5778 setTerminalReversed(newColInfo, reducedMember->pathBackwards);
    5779 setTerminalMember(newColInfo, *loopMember);
    5780 return SCIP_OKAY;
    5781}
    5782
    5783/** Very elaborate function that splits a series member into multiple members based on the structure of the path arcs.
    5784 *
    5785 * The updated member reflects the structure of the updated SPQR tree after the new column arc is added.
    5786 * This variant is only used on series members that are part of a reduced tree that is not a single member.
    5787 */
    5788static
    5790 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    5791 SCIP_NETCOLADD* newCol, /**< The network matrix column addition data structure */
    5792 SPQRColReducedMember* reducedMember, /**< The reduced member of the series member to split. */
    5793 spqr_member member, /**< The series member to split. */
    5794 spqr_arc* pathRepresentative, /**< Out pointer pointing to the tree arc in the final series node */
    5795 spqr_arc* nonPathRepresentative, /**< Out pointer pointing to the non-tree arc in the final series node*/
    5796 spqr_arc exceptionArc1, /**< The first exception arc. Set to SPQR_INVALID_ARC to ignore */
    5797 spqr_arc exceptionArc2 /**< The second exception arc. Set to SPQR_INVALID_ARC to ignore */
    5798 )
    5799{
    5800 assert(dec);
    5801 assert(reducedMember);
    5802 assert(SPQRmemberIsValid(member));
    5803 assert(memberIsRepresentative(dec, member));
    5804
    5805 int numExceptionArcs = ( exceptionArc1 == SPQR_INVALID_ARC ? 0 : 1 ) + ( exceptionArc2 == SPQR_INVALID_ARC ? 0 : 1 );
    5806 int numNonPathArcs = getNumMemberArcs(dec, member) - reducedMember->numPathArcs - numExceptionArcs;
    5807 SCIP_Bool createPathSeries = reducedMember->numPathArcs > 1;
    5808 //If this holds, there are 2 or more non-parent marker non-path arcs
    5809 SCIP_Bool createNonPathSeries = numNonPathArcs > 1;
    5810 assert(exceptionArc1 == SPQR_INVALID_ARC || !newCol->arcInPath[exceptionArc1]);
    5811 assert(exceptionArc2 == SPQR_INVALID_ARC || !newCol->arcInPath[exceptionArc2]);
    5812
    5813 if( createPathSeries )
    5814 {
    5815 spqr_member pathMember;
    5816 SCIP_CALL( createMember(dec, SPQR_MEMBERTYPE_SERIES, &pathMember) );
    5817
    5818 path_arc_id pathArcId = reducedMember->firstPathArc;
    5819 SCIP_Bool parentMoved = FALSE;
    5820 while( pathArcIsValid(pathArcId) )
    5821 {
    5822 spqr_arc pathArc = newCol->pathArcs[pathArcId].arc;
    5823 pathArcId = newCol->pathArcs[pathArcId].nextMember;
    5824 assert(pathArc != exceptionArc1 && pathArc != exceptionArc2);
    5825 parentMoved = parentMoved || markerToParent(dec, member) == pathArc;
    5826 moveArcToNewMember(dec, pathArc, member, pathMember);
    5827 }
    5828 assert(getNumMemberArcs(dec, pathMember) >= 2);
    5829
    5830 spqr_arc ignored;
    5831 SCIP_Bool inOldReversed = TRUE;
    5832 SCIP_Bool inNewReversed = FALSE;
    5833 if( parentMoved )
    5834 {
    5835 SCIP_CALL( createMarkerPairWithReferences(dec, pathMember, member, FALSE, inNewReversed, inOldReversed,
    5836 &ignored, pathRepresentative) );
    5837 }
    5838 else
    5839 {
    5840 SCIP_CALL( createMarkerPairWithReferences(dec, member, pathMember, TRUE, inOldReversed, inNewReversed,
    5841 pathRepresentative, &ignored) );
    5842 }
    5843 }
    5844 else
    5845 {
    5846 if( pathArcIsValid(reducedMember->firstPathArc) )
    5847 {
    5848 *pathRepresentative = newCol->pathArcs[reducedMember->firstPathArc].arc;
    5849 }
    5850 else
    5851 {
    5852 *pathRepresentative = SPQR_INVALID_ARC;
    5853 }
    5854 }
    5855
    5856 if( createNonPathSeries )
    5857 {
    5858 spqr_member nonPathMember;
    5859 SCIP_CALL( createMember(dec, SPQR_MEMBERTYPE_SERIES, &nonPathMember) );
    5860
    5861 spqr_arc arc = getFirstMemberArc(dec, member);
    5862 SCIP_Bool parentMoved = FALSE;
    5863 SCIP_Bool canStop = FALSE;//hack when the first arc is moved in the below loop to prevent that we immediately terminate
    5864 do
    5865 {
    5866 spqr_arc nextArc = getNextMemberArc(dec, arc);
    5867 if( arc != *pathRepresentative && arc != exceptionArc1 && arc != exceptionArc2 )
    5868 {
    5869 parentMoved = parentMoved || markerToParent(dec, member) == arc;
    5870 moveArcToNewMember(dec, arc, member, nonPathMember);
    5871 }
    5872 else
    5873 {
    5874 canStop = TRUE;
    5875 }
    5876 arc = nextArc;
    5877 if( canStop && arc == getFirstMemberArc(dec, member))
    5878 {
    5879 break;
    5880 }
    5881 }
    5882 while( TRUE ); /*lint !e506*/
    5883 assert(getNumMemberArcs(dec, nonPathMember) >= 2);
    5884 SCIP_Bool representativeIsTree = !arcIsTree(dec, exceptionArc1);
    5885 if( SPQRarcIsValid(exceptionArc2) )
    5886 {
    5887 representativeIsTree = representativeIsTree || !arcIsTree(dec, exceptionArc2);
    5888 }
    5889 spqr_arc ignored;
    5890 SCIP_Bool inOldReversed = TRUE;
    5891 SCIP_Bool inNewReversed = FALSE;
    5892 if( parentMoved )
    5893 {
    5894 SCIP_CALL( createMarkerPairWithReferences(dec, nonPathMember, member, !representativeIsTree,
    5895 inNewReversed, inOldReversed, &ignored, nonPathRepresentative) );
    5896 }
    5897 else
    5898 {
    5899 SCIP_CALL( createMarkerPairWithReferences(dec, member, nonPathMember, representativeIsTree,
    5900 inOldReversed, inNewReversed, nonPathRepresentative, &ignored) );
    5901 }
    5902 }
    5903 else
    5904 {
    5905 *nonPathRepresentative = SPQR_INVALID_ARC;
    5906 if( numNonPathArcs != 0 )
    5907 {
    5908 spqr_arc firstArc = getFirstMemberArc(dec, member);
    5909 spqr_arc arc = firstArc;
    5910 do
    5911 {
    5912 if( arc != *pathRepresentative && arc != exceptionArc1 && arc != exceptionArc2 )
    5913 {
    5914 *nonPathRepresentative = arc;
    5915 break;
    5916 }
    5917 arc = getNextMemberArc(dec, arc);
    5918 }
    5919 while( arc != firstArc );
    5920 assert(*nonPathRepresentative != SPQR_INVALID_ARC);
    5921 }
    5922 }
    5923
    5924 return SCIP_OKAY;
    5925}
    5926
    5927/** Transforms the first member in the path of members to reflect the new column update. */
    5928static
    5930 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    5931 SCIP_NETCOLADD* newCol, /**< The network matrix column addition data structure */
    5932 reduced_member_id reducedMember, /**< The reduced member to transform */
    5933 NewColInformation* newColInfo, /**< The new column information */
    5934 spqr_arc* representativeArc, /**< Pointer to the representative of the member, needed for merging.*/
    5935 spqr_member* mergedMember /**< Pointer to the merged member */
    5936 )
    5937{
    5938 spqr_member member = newCol->reducedMembers[reducedMember].member;
    5939 SPQRMemberType type = getMemberType(dec, member);
    5940 if( type == SPQR_MEMBERTYPE_RIGID )
    5941 {
    5942 //The nodes are already created, we only need to assign the correct start/end node
    5943 switch( newCol->reducedMembers[reducedMember].pathType )
    5944 {
    5945 case INTO_HEAD:
    5946 case INTO_TAIL:
    5947 setTerminalTail(newColInfo, newCol->reducedMembers[reducedMember].rigidPathStart);
    5948 break;
    5949 case OUT_HEAD:
    5950 case OUT_TAIL:
    5951 setTerminalHead(newColInfo, newCol->reducedMembers[reducedMember].rigidPathEnd);
    5952 break;
    5953 }
    5954 *representativeArc = findArcSign(dec, newCol->reducedMembers[reducedMember].pathTargetArc).representative;
    5955 *mergedMember = member;
    5956
    5957 return SCIP_OKAY;
    5958 }
    5959 assert(type == SPQR_MEMBERTYPE_SERIES);
    5960 //Split off sets of multiple path non-path edges so that the series has exactly 3 edges
    5961
    5962 spqr_arc target = newCol->reducedMembers[reducedMember].pathTargetArc;
    5963 SPQRColReducedMember* redMem = &newCol->reducedMembers[reducedMember];
    5964 spqr_arc pathRepresentative = SPQR_INVALID_ARC;
    5965 spqr_arc nonPathRepresentative = SPQR_INVALID_ARC;
    5966 SCIP_CALL( splitSeriesMerging(dec, newCol, redMem, member, &pathRepresentative, &nonPathRepresentative, target,
    5968
    5969 assert(
    5970 target != pathRepresentative && target != nonPathRepresentative && pathRepresentative != nonPathRepresentative);
    5971 assert(SPQRarcIsValid(pathRepresentative) && SPQRarcIsValid(nonPathRepresentative) && SPQRarcIsValid(target));
    5972 assert(getNumMemberArcs(dec, member) == 3);
    5973
    5974 //Create nodes
    5978 SCIP_CALL( createNode(dec, &a) );
    5979 SCIP_CALL( createNode(dec, &b) );
    5980 SCIP_CALL( createNode(dec, &c) );
    5981
    5982 // a -- b
    5983 // \ /
    5984 // c
    5985
    5986 //Set arc nodes
    5987 //Set target from b to c,
    5988 SCIP_Bool targetReversed = arcIsReversedNonRigid(dec, target);
    5989 setArcHeadAndTail(dec, target, c, b);
    5990
    5991 MemberPathType pathType = newCol->reducedMembers[reducedMember].pathType;
    5992 assert(pathType == INTO_HEAD || pathType == OUT_HEAD);
    5993 if( arcIsReversedNonRigid(dec, pathRepresentative) == targetReversed )
    5994 {
    5995 setArcHeadAndTail(dec, pathRepresentative, a, c);
    5996 }
    5997 else
    5998 {
    5999 setArcHeadAndTail(dec, pathRepresentative, c, a);
    6000 }
    6001 if( arcIsReversedNonRigid(dec, nonPathRepresentative) == targetReversed )
    6002 {
    6003 setArcHeadAndTail(dec, nonPathRepresentative, b, a);
    6004 }
    6005 else
    6006 {
    6007 setArcHeadAndTail(dec, nonPathRepresentative, a, b);
    6008 }
    6009 //setup signed union find; all arcs are placed are not reversed. We pick an arbitrary arc as 'root' arc for this skeleton
    6010 arcSetReversed(dec, target, FALSE);
    6011 arcSetReversed(dec, pathRepresentative, FALSE);
    6012 arcSetReversed(dec, nonPathRepresentative, FALSE);
    6014 arcSetRepresentative(dec, pathRepresentative, target);
    6015 arcSetRepresentative(dec, nonPathRepresentative, target);
    6016 *representativeArc = target;
    6017
    6018 if( pathType == INTO_HEAD )
    6019 {
    6020 setTerminalTail(newColInfo, a);
    6021 }
    6022 else
    6023 {
    6024 setTerminalHead(newColInfo, a);
    6025 }
    6026
    6027 *mergedMember = member;
    6028
    6029 return SCIP_OKAY;
    6030}
    6031
    6032/** Transforms the next parallel member in the path of members and merge it into the current member. */
    6033static
    6035 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    6036 SCIP_NETCOLADD* newCol, /**< The network matrix column addition data structure */
    6037 reduced_member_id current, /**< The current reduced member id */
    6038 reduced_member_id next, /**< The next reduced member */
    6039 spqr_member nextMember, /**< The member of the next reduced member in the path */
    6040 SCIP_Bool nextIsParent, /**< Is the next reduced member the parent of the current member? */
    6041 spqr_arc* representativeArc, /**< Pointer to the representative of the member, needed for merging.*/
    6042 spqr_member* mergedMember /**< Pointer to the merged member */
    6043 )
    6044{
    6045 //Split off edges not in current subtree to form one parallel (or one edge)
    6046 spqr_member childParallel = INVALID_REDUCED_MEMBER;
    6047 spqr_arc source = newCol->reducedMembers[next].pathSourceArc;
    6048 spqr_arc target = newCol->reducedMembers[next].pathTargetArc;
    6049 if( getNumMemberArcs(dec, nextMember) > 3 )
    6050 {
    6051 SCIP_CALL( splitParallel(dec, nextMember, source, target, &childParallel) );
    6052 nextMember = childParallel;
    6053 newCol->reducedMembers[next].member = childParallel;
    6054 }
    6055 assert(getNumMemberArcs(dec, nextMember) == 3);
    6056
    6057 spqr_node sourceHead = SPQR_INVALID_NODE;
    6058 spqr_node sourceTail = SPQR_INVALID_NODE;
    6059 SCIP_CALL( createNode(dec, &sourceHead) );
    6060 SCIP_CALL( createNode(dec, &sourceTail) );
    6061
    6062 //set edge nodes and arc union-find data
    6063 {
    6064 spqr_arc firstArc = getFirstMemberArc(dec, nextMember);
    6065 spqr_arc arc = firstArc;
    6066
    6067 SCIP_Bool sourceReversed = arcIsReversedNonRigid(dec, source);
    6068 do
    6069 {
    6070 if( arcIsReversedNonRigid(dec, arc) == sourceReversed )
    6071 {
    6072 setArcHeadAndTail(dec, arc, sourceHead, sourceTail);
    6073 }
    6074 else
    6075 {
    6076 setArcHeadAndTail(dec, arc, sourceTail, sourceHead);
    6077 }
    6078 arcSetRepresentative(dec, arc, source);
    6079 arcSetReversed(dec, arc, FALSE);
    6080
    6081 arc = getNextMemberArc(dec, arc);
    6082 }
    6083 while( arc != firstArc );
    6084
    6086 }
    6087
    6088 //fix arc orientations of members; we cannot reflect for parallels.
    6089 *representativeArc = mergeArcSigns(dec, *representativeArc, source, FALSE);
    6090
    6091 spqr_member newMergedMember = SPQR_INVALID_MEMBER;
    6092 if( nextIsParent )
    6093 {
    6094 SCIP_CALL( mergeGivenMemberIntoParent(dec, *mergedMember, nextMember,
    6095 source, newCol->reducedMembers[current].pathTargetArc, TRUE,
    6096 &newMergedMember) );
    6097 }
    6098 else
    6099 {
    6100 SCIP_CALL( mergeGivenMemberIntoParent(dec, nextMember, *mergedMember,
    6101 newCol->reducedMembers[current].pathTargetArc, source, TRUE,
    6102 &newMergedMember) );
    6103 }
    6104 *mergedMember = newMergedMember;
    6105
    6106 return SCIP_OKAY;
    6107}
    6108
    6109/** Transforms the next series member in the path of members and merge it into the current member. */
    6110static
    6112 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    6113 SCIP_NETCOLADD* newCol, /**< The network matrix column addition data structure */
    6114 reduced_member_id current, /**< The current reduced member id */
    6115 reduced_member_id next, /**< The next reduced member */
    6116 spqr_member nextMember, /**< The member of the next reduced member in the path */
    6117 SCIP_Bool nextIsParent, /**< Is the next reduced member the parent of the current member? */
    6118 spqr_arc* representativeArc, /**< Pointer to the representative of the member, needed for merging.*/
    6119 spqr_member* mergedMember, /**< Pointer to the merged member */
    6120 NewColInformation* info /**< The new column information */
    6121 )
    6122{
    6123 SPQRColReducedMember* redMem = &newCol->reducedMembers[next];
    6124 spqr_arc source = redMem->pathSourceArc;
    6125 spqr_arc target = redMem->pathTargetArc;
    6126
    6127 spqr_arc pathRepresentative = SPQR_INVALID_ARC;
    6128 spqr_arc nonPathRepresentative = SPQR_INVALID_ARC;
    6129 SCIP_CALL(
    6130 splitSeriesMerging(dec, newCol, redMem, nextMember, &pathRepresentative, &nonPathRepresentative, source, target) );
    6131 //After splitting there is the following possibilities for nodes a-d:
    6132 //(a)-source-(b)-path-(c)-target-(d)-nonpath-(a)
    6133 //(a)-source-(b)-path-(c)-target-(d==a)
    6134 //(a)-source-(b)=(c)-target-(d)-nonpath-(a)
    6135 //(a)-source-(b)-path-(c)=(d) -nonpath-(a)
    6136 //Note that the given arc is always between the same nodes
    6137 assert(getNumMemberArcs(dec, nextMember) == 3 || getNumMemberArcs(dec, nextMember) == 4);
    6138 assert(pathRepresentative != source && nonPathRepresentative != source &&
    6139 ( SPQRarcIsInvalid(target) || ( target != pathRepresentative && target != nonPathRepresentative )));
    6144 SCIP_CALL( createNode(dec, &a) );
    6145 SCIP_CALL( createNode(dec, &b) );
    6146 if( SPQRarcIsValid(pathRepresentative) )
    6147 {
    6148 SCIP_CALL( createNode(dec, &c) );
    6149 }
    6150 else
    6151 {
    6152 c = b;
    6153 }
    6154 SCIP_Bool hasNonPath = SPQRarcIsValid(nonPathRepresentative);
    6155 SCIP_Bool hasTarget = SPQRarcIsValid(target);
    6156 if( hasNonPath && hasTarget )
    6157 {
    6158 SCIP_CALL( createNode(dec, &d) );
    6159 }
    6160 else
    6161 {
    6162 if( hasNonPath )
    6163 {
    6164 d = c;
    6165 }
    6166 else
    6167 {
    6168 d = a;
    6169 }
    6170 }
    6171
    6172 SCIP_Bool sourceReversed = arcIsReversedNonRigid(dec, source);
    6173 SCIP_Bool pathStartInHead = isHead(newCol->reducedMembers[current].pathType);
    6174 if( pathStartInHead )
    6175 {
    6176 setArcHeadAndTail(dec, source, b, a);
    6177 }
    6178 else
    6179 {
    6180 setArcHeadAndTail(dec, source, a, b);
    6181 }
    6182 if( SPQRarcIsValid(pathRepresentative))
    6183 {
    6184 if( (arcIsReversedNonRigid(dec, pathRepresentative) == sourceReversed) == pathStartInHead )
    6185 {
    6186 setArcHeadAndTail(dec, pathRepresentative, c, b);
    6187 }
    6188 else
    6189 {
    6190 setArcHeadAndTail(dec, pathRepresentative, b, c);
    6191 }
    6192 arcSetReversed(dec, pathRepresentative, FALSE);
    6193 arcSetRepresentative(dec, pathRepresentative, source);
    6194 }
    6195 if( hasTarget )
    6196 {
    6197 if( (arcIsReversedNonRigid(dec, target) == sourceReversed) == pathStartInHead )
    6198 {
    6199 setArcHeadAndTail(dec, target, d, c);
    6200 }
    6201 else
    6202 {
    6203 setArcHeadAndTail(dec, target, c, d);
    6204 }
    6205 arcSetReversed(dec, target, FALSE);
    6206 arcSetRepresentative(dec, target, source);
    6207 }
    6208 if( hasNonPath )
    6209 {
    6210 if( (arcIsReversedNonRigid(dec, nonPathRepresentative) == sourceReversed) == pathStartInHead )
    6211 {
    6212 setArcHeadAndTail(dec, nonPathRepresentative, a, d);
    6213 }
    6214 else
    6215 {
    6216 setArcHeadAndTail(dec, nonPathRepresentative, d, a);
    6217 }
    6218 arcSetReversed(dec, nonPathRepresentative, FALSE);
    6219 arcSetRepresentative(dec, nonPathRepresentative, source);
    6220 }
    6221
    6222 arcSetReversed(dec, source, FALSE);
    6224
    6225 //fix arc orientations of members; we cannot reflect for series
    6226
    6227 spqr_member newMergedMember = SPQR_INVALID_MEMBER;
    6228 if( nextIsParent )
    6229 {
    6230 SCIP_CALL( mergeGivenMemberIntoParent(dec, *mergedMember, nextMember,
    6231 source, newCol->reducedMembers[current].pathTargetArc, TRUE,
    6232 &newMergedMember) );
    6233 }
    6234 else
    6235 {
    6236 SCIP_CALL( mergeGivenMemberIntoParent(dec, nextMember, *mergedMember,
    6237 newCol->reducedMembers[current].pathTargetArc, source, TRUE,
    6238 &newMergedMember) );
    6239 }
    6240 *mergedMember = newMergedMember;
    6241
    6242 *representativeArc = mergeArcSigns(dec, *representativeArc, source, FALSE);
    6243 if( !hasTarget )
    6244 {
    6245 //We are in the last node; finish the path
    6247 if( isInto(newCol->reducedMembers[current].pathType))
    6248 {
    6249 setTerminalHead(info, c);
    6250 }
    6251 else
    6252 {
    6253 setTerminalTail(info, c);
    6254 }
    6255 setTerminalMember(info, *mergedMember);
    6256 setTerminalRepresentative(info, *representativeArc);
    6257 }
    6258
    6259 return SCIP_OKAY;
    6260}
    6261
    6262/** Transforms the next rigid member in the path of members and merge it into the current member. */
    6263static
    6265 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    6266 SCIP_NETCOLADD* newCol, /**< The network matrix column addition data structure */
    6267 reduced_member_id current, /**< The current reduced member id */
    6268 reduced_member_id next, /**< The next reduced member */
    6269 spqr_member nextMember, /**< The member of the next reduced member in the path */
    6270 SCIP_Bool nextIsParent, /**< Is the next reduced member the parent of the current member? */
    6271 spqr_arc* representativeArc, /**< Pointer to the representative of the member, needed for merging.*/
    6272 spqr_member* mergedMember, /**< Pointer to the merged member */
    6273 NewColInformation* info /**< The new column information */
    6274 )
    6275{
    6276 SPQRColReducedMember* redMem = &newCol->reducedMembers[next];
    6277 spqr_arc source = redMem->pathSourceArc;
    6278 spqr_arc sourceRepresentative = findArcSign(dec, source).representative;
    6279
    6280 spqr_member newMergedMember = SPQR_INVALID_MEMBER;
    6281
    6282 if( nextIsParent )
    6283 {
    6284 SCIP_CALL( mergeGivenMemberIntoParent(dec, *mergedMember, nextMember,
    6285 source, newCol->reducedMembers[current].pathTargetArc, !redMem->reverseArcs,
    6286 &newMergedMember) );
    6287 }
    6288 else
    6289 {
    6290 SCIP_CALL( mergeGivenMemberIntoParent(dec, nextMember, *mergedMember,
    6291 newCol->reducedMembers[current].pathTargetArc, source, !redMem->reverseArcs,
    6292 &newMergedMember) );
    6293 }
    6294
    6295 *mergedMember = newMergedMember;
    6296
    6297 *representativeArc = mergeArcSigns(dec, *representativeArc, sourceRepresentative, redMem->reverseArcs);
    6298
    6299 if( SPQRarcIsInvalid(redMem->pathTargetArc) )
    6300 {
    6301 //We are in the last node; finish the path
    6303 if( isInto(newCol->reducedMembers[current].pathType) )
    6304 {
    6305 if( redMem->reverseArcs )
    6306 {
    6307 setTerminalHead(info, redMem->rigidPathStart);
    6308 }
    6309 else
    6310 {
    6311 setTerminalHead(info, redMem->rigidPathEnd);
    6312 }
    6313 }
    6314 else
    6315 {
    6316 if( redMem->reverseArcs )
    6317 {
    6318 setTerminalTail(info, redMem->rigidPathEnd);
    6319 }
    6320 else
    6321 {
    6322 setTerminalTail(info, redMem->rigidPathStart);
    6323 }
    6324 }
    6325 setTerminalMember(info, *mergedMember);
    6326 setTerminalRepresentative(info, *representativeArc);
    6327 }
    6328
    6329 return SCIP_OKAY;
    6330}
    6331
    6332/** Transforms the next member in the path of members and merge it into the current member. */
    6333static
    6335 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    6336 SCIP_NETCOLADD* newCol, /**< The network matrix column addition data structure */
    6337 reduced_member_id current, /**< The current reduced member id */
    6338 reduced_member_id next, /**< The next reduced member */
    6339 spqr_arc* representativeArc, /**< Pointer to the representative of the member, needed for merging.*/
    6340 spqr_member* mergedMember, /**< Pointer to the merged member */
    6341 SCIP_Bool nextIsParent, /**< Is the next reduced member the parent of the current member? */
    6342 NewColInformation* info /**< The new column information */
    6343 )
    6344{
    6345 spqr_member nextMember = newCol->reducedMembers[next].member;
    6346 switch( getMemberType(dec, nextMember) )
    6347 {
    6349 {
    6350 SCIP_CALL( transformAndMergeRigid(dec, newCol, current, next, nextMember, nextIsParent,
    6351 representativeArc, mergedMember, info) );
    6352 break;
    6353 }
    6355 {
    6356 SCIP_CALL( transformAndMergeParallel(dec, newCol, current, next, nextMember, nextIsParent,
    6357 representativeArc, mergedMember) );
    6358 break;
    6359 }
    6361 {
    6362 SCIP_CALL( transformAndMergeSeries(dec, newCol, current, next, nextMember, nextIsParent,
    6363 representativeArc, mergedMember, info) );
    6364 break;
    6365 }
    6368 {
    6369 SCIPABORT();
    6370 return SCIP_ERROR;
    6371 }
    6372 }
    6373 return SCIP_OKAY;
    6374}
    6375
    6376/** Transforms a single component when it contains multiple reduced members. */
    6377static
    6379 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    6380 SCIP_NETCOLADD* newCol, /**< The network matrix column addition data structure */
    6381 SPQRColReducedComponent* component, /**< The component to transform */
    6382 NewColInformation* newColInfo /**< The new column information */
    6383 )
    6384{
    6385 //Realize first member
    6386 reduced_member_id firstPathMember = component->pathEndMembers[0];
    6387
    6388 spqr_arc representativeArc = SPQR_INVALID_ARC;
    6389 spqr_member mergedMember = SPQR_INVALID_MEMBER;
    6390 SCIP_CALL( transformFirstPathMember(dec, newCol, firstPathMember, newColInfo, &representativeArc, &mergedMember) );
    6391 //Iteratively call function which realizes next member and merges them together.
    6392 reduced_member_id current = firstPathMember;
    6393 reduced_member_id next = newCol->reducedMembers[current].nextPathMember;
    6394 SCIP_Bool nextIsParent = newCol->reducedMembers[current].nextPathMemberIsParent;
    6395 while( reducedMemberIsValid(next) )
    6396 {
    6397 SCIP_CALL(
    6398 transformAndMerge(dec, newCol, current, next, &representativeArc, &mergedMember, nextIsParent, newColInfo));
    6399 current = next;
    6400 next = newCol->reducedMembers[current].nextPathMember;
    6401 nextIsParent = newCol->reducedMembers[current].nextPathMemberIsParent;
    6402 }
    6403
    6404 return SCIP_OKAY;
    6405}
    6406
    6407/** Transform a single parallel member to add the new column. */
    6408static
    6410 SCIP_NETCOLADD* newCol, /**< The network matrix column addition data structure */
    6411 reduced_member_id reducedMemberId, /**< The reduced member to transform */
    6412 spqr_member member, /**< The member to transform */
    6413 NewColInformation* newColInfo /**< The new column information */
    6414 )
    6415{
    6416 SPQRColReducedMember* reducedMember = &newCol->reducedMembers[reducedMemberId];
    6417 assert(pathArcIsValid(reducedMember->firstPathArc) && reducedMember->numPathArcs == 1);
    6418 //The new arc can be placed in parallel; just add it to this member
    6419 setTerminalReversed(newColInfo, reducedMember->pathBackwards);
    6420 setTerminalMember(newColInfo, member);
    6421
    6422 return SCIP_OKAY;
    6423}
    6424
    6425/** Transform a single series member to add the new column. */
    6426static
    6428 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    6429 SCIP_NETCOLADD* newCol, /**< The network matrix column addition data structure */
    6430 reduced_member_id reducedMemberId, /**< The reduced member to transform */
    6431 spqr_member member, /**< The member to transform */
    6432 NewColInformation* newColInfo /**< The new column information */
    6433 )
    6434{
    6435 if( getNumMemberArcs(dec, member) == 1 )
    6436 {
    6437 newColInfo->member = member;
    6438 newColInfo->reversed = newCol->arcInPathReversed[getFirstMemberArc(dec, member)];
    6439 return SCIP_OKAY;
    6440 }
    6441 //Isolated single cycle
    6442 spqr_member loopMember;
    6443 SPQRColReducedMember* reducedMember = &newCol->reducedMembers[reducedMemberId];
    6444 SCIP_CALL( splitSeries(dec, newCol, reducedMember, member, &loopMember, newColInfo) );
    6445
    6446 return SCIP_OKAY;
    6447}
    6448
    6449/** Transform a single rigid member to add the new column. */
    6450static
    6452 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    6453 SCIP_NETCOLADD* newCol, /**< The network matrix column addition data structure */
    6454 reduced_member_id reducedMemberId, /**< The reduced member to transform */
    6455 spqr_member member, /**< The member to transform */
    6456 NewColInformation* newColInfo /**< The new column information */
    6457 )
    6458{
    6459 assert(dec);
    6460 assert(newCol);
    6461 assert(newColInfo);
    6462 assert(reducedMemberIsValid(reducedMemberId));
    6463
    6464 //The path is already computed, so we can simply take the start and end nodes.
    6465 //However, there is one exception, which is that an arc connecting these two nodes already exists in the member
    6466 //If so, we create a new parallel member with the new arc and this member, unless the existing arc already points
    6467 //to a parallel member
    6468 SPQRColReducedMember* reducedMember = &newCol->reducedMembers[reducedMemberId];
    6469 assert(SPQRnodeIsValid(reducedMember->rigidPathStart) && SPQRnodeIsValid(reducedMember->rigidPathEnd));
    6470 {
    6471 spqr_arc existingArcWithPath = SPQR_INVALID_ARC;
    6472 spqr_arc firstArc = getFirstNodeArc(dec, reducedMember->rigidPathStart);
    6473 spqr_arc arc = firstArc;
    6474 SCIP_Bool pathInSameDirection = FALSE;
    6475 do
    6476 {
    6477 spqr_node head = findArcHead(dec, arc);
    6478 spqr_node tail = findArcTail(dec, arc);
    6479 spqr_node other = head == reducedMember->rigidPathStart ? tail : head;
    6480 if( other == reducedMember->rigidPathEnd )
    6481 {
    6482 existingArcWithPath = arc;
    6483 pathInSameDirection = ( head == other ) != findArcSign(dec, existingArcWithPath).reversed;
    6484 break;
    6485 }
    6486 arc = getNextNodeArc(dec, arc, reducedMember->rigidPathStart);
    6487 }
    6488 while( arc != firstArc );
    6489 if( SPQRarcIsValid(existingArcWithPath) )
    6490 {
    6491 SCIP_Bool isParent = FALSE;
    6492 spqr_member adjacentMember = arcIsChildMarker(dec, existingArcWithPath) ?
    6493 findArcChildMember(dec, existingArcWithPath) : SPQR_INVALID_MEMBER;
    6494 if( existingArcWithPath == markerToParent(dec, member) )
    6495 {
    6496 adjacentMember = findMemberParent(dec, member);
    6497 isParent = TRUE;
    6498 }
    6499 if( SPQRmemberIsValid(adjacentMember) && getMemberType(dec, adjacentMember) == SPQR_MEMBERTYPE_PARALLEL )
    6500 {
    6501 spqr_arc parallelMarker = isParent ? markerOfParent(dec, member) : markerToParent(dec, adjacentMember);
    6502 SCIP_Bool markerReversed = arcIsReversedNonRigid(dec, parallelMarker);
    6503 setTerminalMember(newColInfo, adjacentMember);
    6504 setTerminalReversed(newColInfo, markerReversed == pathInSameDirection);
    6505 }
    6506 else
    6507 {
    6508 //create a new parallel and move the edge there
    6509 //This is a bit painful, because we cannot actually remove edges because of the union-find data structure
    6510 //So what we do instead, is convert the current edge to a marker edge, and 'duplicate'
    6511 //it in the new parallel member, and add the new marker there too, manually
    6512 spqr_member adjacentParallel = SPQR_INVALID_MEMBER;
    6513 SCIP_CALL( createMember(dec, SPQR_MEMBERTYPE_PARALLEL, &adjacentParallel) );
    6514 //'duplicate' a new arc in the parallel to be the current arc
    6515 spqr_arc duplicate = SPQR_INVALID_ARC;
    6516 spqr_element element = arcGetElement(dec, existingArcWithPath);
    6517 if( element != MARKER_COLUMN_ELEMENT && element != MARKER_ROW_ELEMENT )
    6518 {
    6519 if( SPQRelementIsColumn(element) )
    6520 {
    6521 SCIP_CALL( createColumnArc(dec, adjacentParallel, &duplicate, SPQRelementToColumn(element), FALSE) );
    6522 }
    6523 else
    6524 {
    6525 SCIP_CALL( createRowArc(dec, adjacentParallel, &duplicate, SPQRelementToRow(element), FALSE) );
    6526 }
    6527 }
    6528 else if( isParent )
    6529 {
    6530 SCIP_CALL( createParentMarker(dec, adjacentParallel, arcIsTree(dec, existingArcWithPath), adjacentMember,
    6531 markerOfParent(dec, member), &duplicate, FALSE) );
    6532 }
    6533 else
    6534 {
    6535 SCIP_CALL( createChildMarker(dec, adjacentParallel, adjacentMember, arcIsTree(dec, existingArcWithPath),
    6536 &duplicate, FALSE) );
    6537 dec->members[adjacentMember].parentMember = adjacentParallel;
    6538 dec->members[adjacentMember].markerOfParent = duplicate;
    6539 }
    6540 //Create the other marker edge
    6541 spqr_arc parallelMarker = SPQR_INVALID_ARC;
    6542 if( isParent )
    6543 {
    6544 SCIP_CALL( createChildMarker(dec, adjacentParallel, member, !arcIsTree(dec, existingArcWithPath),
    6545 &parallelMarker, FALSE) );
    6546 }
    6547 else
    6548 {
    6549 SCIP_CALL( createParentMarker(dec, adjacentParallel, !arcIsTree(dec, existingArcWithPath),
    6550 member, existingArcWithPath, &parallelMarker, FALSE) );
    6551 }
    6552
    6553 //Change the existing edge to a marker
    6554 if( isParent )
    6555 {
    6556 assert(markerToParent(dec, member) == existingArcWithPath);
    6557 dec->arcs[markerOfParent(dec, member)].childMember = adjacentParallel;
    6558 dec->members[member].parentMember = adjacentParallel;
    6559 dec->members[member].markerToParent = existingArcWithPath;
    6560 dec->members[member].markerOfParent = parallelMarker;
    6561 dec->arcs[existingArcWithPath].element = arcIsTree(dec, existingArcWithPath) ? MARKER_ROW_ELEMENT
    6563 dec->arcs[existingArcWithPath].childMember = adjacentParallel;
    6564 }
    6565 else
    6566 {
    6567 dec->arcs[existingArcWithPath].element = arcIsTree(dec, existingArcWithPath) ? MARKER_ROW_ELEMENT
    6569 dec->arcs[existingArcWithPath].childMember = adjacentParallel;
    6570 }
    6571
    6572 setTerminalMember(newColInfo, adjacentParallel);
    6573 setTerminalReversed(newColInfo, !pathInSameDirection);
    6574 }
    6575 return SCIP_OKAY;
    6576 }
    6577 }
    6578
    6579 setTerminalMember(newColInfo, member);
    6580 setTerminalReversed(newColInfo, FALSE);
    6581 setTerminalTail(newColInfo, reducedMember->rigidPathStart);
    6582 setTerminalHead(newColInfo, reducedMember->rigidPathEnd);
    6583 setTerminalRepresentative(newColInfo,
    6584 findArcSign(dec, newCol->pathArcs[reducedMember->firstPathArc].arc).representative);
    6585
    6586 return SCIP_OKAY;
    6587}
    6588
    6589/** Transform a component to reflect the new column. */
    6590static
    6592 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    6593 SCIP_NETCOLADD* newCol, /**< The network matrix column addition data structure */
    6594 SPQRColReducedComponent* component, /**< The component to transform */
    6595 NewColInformation* newColInfo /**< The new column information */
    6596 )
    6597{
    6598 assert(dec);
    6599 assert(newCol);
    6600 assert(component);
    6601 assert(newColInfo);
    6602
    6603 if( newCol->reducedMembers[component->root].numChildren ==
    6604 newCol->reducedMembers[component->root].numPropagatedChildren )
    6605 {
    6606 //No merging necessary, only a single component
    6607 reduced_member_id reducedMember = component->root;
    6608 assert(reducedMemberIsValid(reducedMember));
    6609 spqr_member member = newCol->reducedMembers[reducedMember].member;
    6610 SPQRMemberType type = getMemberType(dec, member);
    6611
    6612 switch( type )
    6613 {
    6615 {
    6616 SCIP_CALL( columnTransformSingleRigid(dec, newCol, reducedMember, member, newColInfo) );
    6617 break;
    6618 }
    6620 {
    6621 SCIP_CALL( columnTransformSingleParallel(newCol, reducedMember, member, newColInfo) );
    6622 break;
    6623 }
    6626 {
    6627 SCIP_CALL( columnTransformSingleSeries(dec, newCol, reducedMember, member, newColInfo) );
    6628 break;
    6629 }
    6631 default:
    6632 {
    6633 SCIPABORT();
    6634 return SCIP_ERROR;
    6635 }
    6636 }
    6637 return SCIP_OKAY;
    6638 }
    6639 // Otherwise, the reduced members form a path which can be merged into a single component of type R
    6640 SCIP_CALL( transformPath(dec, newCol, component, newColInfo) );
    6641
    6642 return SCIP_OKAY;
    6643}
    6644
    6645/** Check if the submatrix stored remains a network matrix with the new column update. */
    6646static
    6648 const SCIP_NETCOLADD* newCol /**< The network matrix column addition data structure */
    6649 )
    6650{
    6651 return newCol->remainsNetwork;
    6652}
    6653
    6654/** Add the new column to the network decomposition as an arc.
    6655 *
    6656 * Only use this function after SCIPnetcoladdCheck() has been called.
    6657 */
    6658static
    6660 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    6661 SCIP_NETCOLADD* newCol /**< The network matrix column addition data structure */
    6662 )
    6663{
    6664 assert(dec);
    6665 assert(newCol);
    6666 assert(netcoladdRemainsNetwork(newCol));
    6667
    6668 if( newCol->numReducedComponents == 0 )
    6669 {
    6670 spqr_member member;
    6672 newCol->numNewRowArcs, newCol->newColIndex, &member) );
    6673 }
    6674 else if( newCol->numReducedComponents == 1 )
    6675 {
    6677 SCIP_CALL( transformComponent(dec, newCol, &newCol->reducedComponents[0], &information) );
    6678 assert(memberIsRepresentative(dec, information.member));
    6679 if( newCol->numNewRowArcs == 0 )
    6680 {
    6681 spqr_arc colArc = SPQR_INVALID_ARC;
    6682 SCIP_CALL( createColumnArc(dec, information.member, &colArc, newCol->newColIndex, information.reversed) );
    6683 if( SPQRnodeIsValid(information.head) )
    6684 {
    6685 assert(SPQRnodeIsValid(information.tail));
    6686 assert(SPQRarcIsValid(information.representative));
    6687 setArcHeadAndTail(dec, colArc, findNode(dec, information.head), findNode(dec, information.tail));
    6688 arcSetRepresentative(dec, colArc, information.representative);
    6689 arcSetReversed(dec, colArc, information.reversed != arcIsReversedNonRigid(dec, information.representative));
    6690 }
    6691 }
    6692 else
    6693 {
    6694 spqr_member newSeries = SPQR_INVALID_MEMBER;
    6696 newCol->newColIndex, &newSeries) );
    6697 spqr_arc markerArc = SPQR_INVALID_ARC;
    6698 spqr_arc ignore = SPQR_INVALID_ARC;
    6699 SCIP_CALL( createMarkerPairWithReferences(dec, information.member, newSeries, FALSE, information.reversed, TRUE,
    6700 &markerArc, &ignore) );
    6701 if( SPQRnodeIsValid(information.head) )
    6702 {
    6703 assert(SPQRnodeIsValid(information.tail));
    6704 assert(SPQRarcIsValid(information.representative));
    6705 setArcHeadAndTail(dec, markerArc, findNode(dec, information.head), findNode(dec, information.tail));
    6706 arcSetRepresentative(dec, markerArc, information.representative);
    6707 arcSetReversed(dec, markerArc,
    6708 information.reversed != arcIsReversedNonRigid(dec, information.representative));
    6709 }
    6710 }
    6711 if( getMemberType(dec, information.member) == SPQR_MEMBERTYPE_LOOP )
    6712 {
    6713 assert(getNumMemberArcs(dec, information.member) == 2 || getNumMemberArcs(dec, information.member) == 3);
    6714 if( getNumMemberArcs(dec, information.member) == 3 )
    6715 {
    6716 changeLoopToParallel(dec, information.member);
    6717 }
    6718 }
    6719 }
    6720 else
    6721 {
    6722#ifndef NDEBUG
    6723 int numDecComponentsBefore = numConnectedComponents(dec);
    6724#endif
    6725 spqr_member newSeries = SPQR_INVALID_MEMBER;
    6727 newCol->numNewRowArcs, newCol->newColIndex, &newSeries) );
    6728 for( int i = 0; i < newCol->numReducedComponents; ++i )
    6729 {
    6731 SCIP_CALL( transformComponent(dec, newCol, &newCol->reducedComponents[i], &information) );
    6732 if( getMemberType(dec, information.member) == SPQR_MEMBERTYPE_LOOP )
    6733 {
    6734 assert(getNumMemberArcs(dec, information.member) == 1);
    6735 spqr_arc arc = getFirstMemberArc(dec, information.member);
    6736 assert(newCol->arcInPath[arc]);
    6737 moveArcToNewMember(dec, arc, information.member, newSeries);
    6738 arcSetReversed(dec, arc, !newCol->arcInPathReversed[arc]);
    6739 dec->members[information.member].type = SPQR_MEMBERTYPE_UNASSIGNED;
    6740 }
    6741 else
    6742 {
    6743 reorderComponent(dec, information.member);//reorder the subtree so that the newly series member is a parent
    6744 spqr_arc markerArc = SPQR_INVALID_ARC;
    6745 spqr_arc ignore = SPQR_INVALID_ARC;
    6746 SCIP_CALL( createMarkerPairWithReferences(dec, newSeries, information.member, TRUE, information.reversed,
    6747 TRUE, &ignore, &markerArc) );
    6748 if( SPQRnodeIsValid(information.head) )
    6749 {
    6750 assert(SPQRnodeIsValid(information.tail));
    6751 assert(SPQRarcIsValid(information.representative));
    6752 setArcHeadAndTail(dec, markerArc, findNode(dec, information.head), findNode(dec, information.tail));
    6753 arcSetRepresentative(dec, markerArc, information.representative);
    6754 arcSetReversed(dec, markerArc,
    6755 information.reversed == arcIsReversedNonRigid(dec, information.representative));
    6756 }
    6757 }
    6758 }
    6760 assert(numConnectedComponents(dec) == ( numDecComponentsBefore - newCol->numReducedComponents + 1 ));
    6761 }
    6762
    6763 return SCIP_OKAY;
    6764}
    6765
    6766/* ---------- END functions for column addition --------------------------------------------------------------------- */
    6767
    6768/* ---------- START functions for row addition ---------------------------------------------------------------------- */
    6769
    6770/** Index type for the nonzeros of the new row, e.g. the columns whose tree path must be elongated with the new row */
    6771typedef int cut_arc_id;
    6772#define INVALID_CUT_ARC (-1)
    6773
    6774/** Checks if the given cut arc is invalid (negative). */
    6775static
    6777 const cut_arc_id arc /**< The cut arc to check */
    6778 )
    6779{
    6780 return arc < 0;
    6781}
    6782
    6783/** Checks if the given cut arc is valid (nonnegative). */
    6785 const cut_arc_id arc /**< The cut arc to check */
    6786 )
    6787{
    6788 return !cutArcIsInvalid(arc);
    6789}
    6790
    6791/** Linked list node for the cut arcs.
    6792 *
    6793 * Contains links to the next cut arc in the whole decomposition and the next cut arc in the current member.
    6794 */
    6795typedef struct
    6796{
    6797 spqr_arc arc; /**< The arc id */
    6798 spqr_node arcHead; /**< The arc's head node */
    6799 spqr_node arcTail; /**< The arc's tail node */
    6800 cut_arc_id nextMember; /**< Index to next linked list node of the linked list containing the cut arcs
    6801 * of the arcs member.*/
    6802 cut_arc_id nextOverall; /**< Index to next linked list node of the linked list containing the cut arcs
    6803 * of the complete decomposition.*/
    6804 SCIP_Bool arcReversed; /**< Should the new row have reverse direction in the cut arcs path? */
    6806
    6807/** Type of the reduced member
    6808 *
    6809 * Indicates whether the member is processed, and whether it should be merged or left the same.
    6810 */
    6811typedef enum
    6812{
    6813 TYPE_UNDETERMINED = 0, /**< The type of this member has not yet been determined */
    6814 TYPE_PROPAGATED = 1, /**< The member contains cut arcs, but should not be merged */
    6815 TYPE_MERGED = 2, /**< This member should be merged into a rigid member */
    6816 TYPE_NOT_NETWORK = 3 /**< This member implies that the addition of the new row
    6817 * does not create a network matrix */
    6819
    6820/** Stores for every vertex information needed for computing articulation nodes in rigid members. */
    6821typedef struct
    6822{
    6823 int low; /**< What is the lowest discovery time vertex that can be reached from this
    6824 * subtree?*/
    6825 int discoveryTime; /**< When was the vertex first discovered? */
    6827
    6828/** Call stack data structure for performing DFS on the rigid member graphs. */
    6829typedef struct
    6830{
    6831 spqr_node node; /**< The current node of the DFS call */
    6832 spqr_arc nodeArc; /**< The current arc of the node that is being processed */
    6833} DFSCallData;
    6834
    6835/** Call stack data structure for merging the SPQR tree into a single rigid member. */
    6836typedef struct
    6837{
    6838 children_idx currentChild; /**< The index of the current child that is being merged */
    6839 reduced_member_id id; /**< The index of the current member */
    6841
    6842/** Call stack data structure that determines whether a bipartition of the nodes exists that satisfies the requirements. */
    6843typedef struct
    6844{
    6845 spqr_node node; /**< The current node of the call */
    6846 spqr_arc arc; /**< The current arc that is being processed */
    6848
    6849/** Call stack data structure for recursive algorithm to find articulation point in rigid member graphs (Tarjan). */
    6850typedef struct
    6851{
    6852 spqr_arc arc; /**< The arc that is currently being processed */
    6853 spqr_node node; /**< The node that is currently being processed */
    6854 spqr_node parent; /**< The node's parent */
    6855 SCIP_Bool isAP; /**< Is the current node an articulation point? */
    6857
    6858/** Colors assigned to the node in the partitioning algorithm.
    6859 *
    6860 * It must either be in the source or the sink partition.
    6861 */
    6862typedef enum
    6863{
    6864 UNCOLORED = 0, /**< The current node has not yet been processed */
    6865 COLOR_SOURCE = 1, /**< The current node belongs to the source partition */
    6866 COLOR_SINK = 2 /**< The current node belongs to the sink partition */
    6868
    6869/** Struct that stores the data of a single reduced member. */
    6870typedef struct
    6871{
    6872 spqr_member member; /**< The id of the decomposition member */
    6873 spqr_member rootMember; /**< The decomposition member that is the root node of the arborescence
    6874 * containing this member */
    6875 int depth; /**< The depth of this member in the arborescence */
    6876 RowReducedMemberType type; /**< The type of the member */
    6877 reduced_member_id parent; /**< The reduced member id of the parent of this reduced member */
    6878
    6879 children_idx firstChild; /**< The index of the first child in the children array. */
    6880 children_idx numChildren; /**< The number of children in the arborescence of this reduced member */
    6881 children_idx numPropagatedChildren; /**< Counts the number of children that are propagated to this reduced
    6882 * member */
    6883
    6884 cut_arc_id firstCutArc; /**< Head of the linked list containing the cut arcs */
    6885 int numCutArcs; /**< The number of cut arcs in the linked list */
    6886
    6887 spqr_arc splitArc; /**< An arc adjacent to the split node. */
    6888 SCIP_Bool splitHead; /**< Is the head or the tail of the split arc split in the realization? */
    6889 SCIP_Bool otherIsSource; /**< Is the nonsplit node of the split arc in the source or the sink
    6890 * partition? In rigid members this refers to the articulation arc. */
    6891
    6892 /* Rigid member fields */
    6893 spqr_node otherNode; /**< The other nonsplit node adjacent to the virtual edge */
    6894 spqr_node splitNode; /**< The node to be split */
    6895 SCIP_Bool allHaveCommonNode; /**< Do all cut edges share a common node? */
    6896 SCIP_Bool otherNodeSplit; /**< Is the other node a split node, too? */
    6897 SCIP_Bool willBeReversed; /**< Will all the arcs in this component be reversed? */
    6898 spqr_arc articulationArc; /**< Indicates the arc between the split node and the other ndoe, if both
    6899 * are splittable. */
    6900 spqr_node coloredNode; /**< Points to a colored node so that we can efficiently zero out colors
    6901 * by backtracking our DFS */
    6903
    6904/** Keeps track of the data relevant for each SPQR tree in the SPQR forest. */
    6905typedef struct
    6906{
    6907 int rootDepth; /**< The depth of the root node of the subtree in the arborescence */
    6908 reduced_member_id root; /**< The reduced member id of the root */
    6910
    6911/** The main datastructure that manages all the data for row-addition in network matrices */
    6912typedef struct
    6913{
    6914 SCIP_Bool remainsNetwork; /**< Does the addition of the current row give a network matrix? */
    6915
    6916 SPQRRowReducedMember* reducedMembers; /**< The array of reduced members, that form the subtree containing the
    6917 * rows of the current column.*/
    6918 int memReducedMembers; /**< Number of allocated slots in the reduced member array */
    6919 int numReducedMembers; /**< Number of used slots in the reduced member array */
    6920
    6921 SPQRRowReducedComponent* reducedComponents; /**< The array of reduced components,
    6922 * that represent the SPQR trees in the SPQR forest */
    6923 int memReducedComponents; /**< Number of allocated slots in the reduced component array */
    6924 int numReducedComponents; /**< Number of used slots in the reduced component array */
    6925
    6926 MemberInfo* memberInformation; /**< Array with member information; tracks the reduced member id that
    6927 * corresponds to every member in the decomposition. */
    6928 int memMemberInformation; /**< Number of allocated slots in the member information array */
    6929 int numMemberInformation; /**< Number of used slots in the member information array */
    6930
    6931 reduced_member_id* childrenStorage; /**< Array that stores the children of the reduced member arborescences.
    6932 * Each reduced member has a 'firstChild' field and a length, that points
    6933 * to the subarray within this array with its children. This array is
    6934 * shared here in order to minimize allocations across iterations. */
    6935 int memChildrenStorage; /**< Number of allocated slots for the children storage array */
    6936 int numChildrenStorage; /**< Number of used slots for the children storage array */
    6937
    6938 CutArcListNode* cutArcs; /**< Array containing the linked list nodes of the cut arcs */
    6939 int memCutArcs; /**< Number of allocated entries in cutArcs */
    6940 int numCutArcs; /**< Number of used entries in cutArcs */
    6941 cut_arc_id firstOverallCutArc; /**< Index of the head node of the linked list containing all cut arcs */
    6942
    6943 spqr_row newRowIndex; /**< The index of the new row to be added */
    6944
    6945 spqr_col* newColumnArcs; /**< The nonzero columns in the new row that do not yet occur in the
    6946 * decomposition */
    6947 SCIP_Bool* newColumnReversed; /**< True if the nonzero entry of the new column is -1, False otherwise */
    6948 int memColumnArcs; /**< Number of allocated slots in newColumnArcs/newColumnReversed */
    6949 int numColumnArcs; /**< Number of new columns in the row to be added */
    6950
    6951 reduced_member_id* leafMembers; /**< Array that stores the leaf members of the SPQR forest */
    6952 int numLeafMembers; /**< Number of used slots in leafMembers array */
    6953 int memLeafMembers; /**< Number of allocated slots in leafMembers array */
    6954
    6955 spqr_arc* decompositionColumnArcs; /**< For each nonzero column of the new row that is in the decomposition,
    6956 * stores the corresponding decomposition arc */
    6957 SCIP_Bool* decompositionColumnArcReversed; /**< For each nonzero column of the new row that is in the decomposition,
    6958 * stores whether the corresponding decomposition arc is reversed */
    6959 int memDecompositionColumnArcs; /**< Number of allocated slots in decompositionColumnArcs(Reversed) */
    6960 int numDecompositionColumnArcs; /**< Number of used slots in decompositionColumnArcs(Reversed) */
    6961
    6962 SCIP_Bool* isArcCut; /**< Stores for each arc, if the arc a cut arc? */
    6963 SCIP_Bool* isArcCutReversed; /**< Is the new row in reverse direction on the arcs cycle? */
    6964 int memIsArcCut; /**< The allocated size of the isArcCut(Reversed) arrays */
    6965
    6966 COLOR_STATUS* nodeColors; /**< Stores the color of each node */
    6967 int memNodeColors; /**< The allocated size of the nodeColors array */
    6968
    6969 spqr_node* articulationNodes; /**< Temp. array for storing articulation nodes of member graph-cut arcs */
    6970 int numArticulationNodes; /**< Number of used slots in articulation nodes array */
    6971 int memArticulationNodes; /**< Number of allocated slots in articulation nodes array */
    6972
    6973 ArticulationNodeInformation* articulationNodeSearchInfo; /**< Stores for each node information necessary to find
    6974 * articulation nodes. */
    6975 int memNodeSearchInfo; /**< The number of allocated entries in articulationNodeSearchInfo array*/
    6976
    6977 int* crossingPathCount; /**< Stores for each arc, how many cut arc cycles contain it */
    6978 int memCrossingPathCount; /**< The number of allocated entries for the crossingPathCount array */
    6979
    6980 DFSCallData* intersectionDFSData; /**< Call stack for computing the intersection of all cut arc paths */
    6981 int memIntersectionDFSData; /**< Number of allocated entries for intersectionDFSData */
    6982
    6983 ColorDFSCallData* colorDFSData; /**< Call stack for computing source/sink coloring */
    6984 int memColorDFSData; /**< Number of allocated entries for colorDFSData */
    6985
    6986 ArticulationPointCallStack* artDFSData; /**< Call stack for computing articulation points */
    6987 int memArtDFSData; /**< Number of allocated entries for artDFSData */
    6988
    6989 CreateReducedMembersCallstack* createReducedMembersCallstack; /**< Call stack for createReducedMembers() */
    6990 int memCreateReducedMembersCallstack; /**< Number of allocated entries for createReducedMembersCallStack */
    6991
    6992 int* intersectionPathDepth; /**< Tracks depth of each node in the intersection of all paths algorithm */
    6993 int memIntersectionPathDepth; /**< Number of allocated entries in intersectionPathDepth array */
    6994
    6995 spqr_node* intersectionPathParent; /**< Tracks the parents of each node in the intersection of all paths
    6996 * algorithm. */
    6997 int memIntersectionPathParent; /**< Number of allocated entries in intersectionPathParent array */
    6998
    6999 MergeTreeCallData* mergeTreeCallData; /**< Call stack for mergeTree */
    7000 int memMergeTreeCallData; /**< Number of allocated elements for mergeTreeCallData */
    7001
    7002 COLOR_STATUS* temporaryColorArray; /**< A temporary array used for saving some colors */
    7003 int memTemporaryColorArray; /**< The number of allocated elements in temporaryColorArray */
    7005
    7006/** Struct that contains information on how to place the new row arc in the decomposition */
    7007typedef struct
    7008{
    7009 spqr_member member; /**< The member to place the new row in */
    7010 spqr_node head; /**< The head node of the new row arc (only used for rigid members) */
    7011 spqr_node tail; /**< The tail node of the new row arc (only used for rigid members) */
    7012 spqr_arc representative; /**< The representative arc of the new row arc */
    7013 SCIP_Bool reversed; /**< Orientation of the arc w.r.t. the representative */
    7015
    7016#define NEWROWINFORMATION_EMPTY { SPQR_INVALID_MEMBER, SPQR_INVALID_NODE, SPQR_INVALID_NODE, SPQR_INVALID_ARC, FALSE }
    7017
    7018/** Saves the information of the current row and partitions it based on whether or not the given columns are
    7019 * already part of the decomposition.
    7020 */
    7021static
    7023 const SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    7024 SCIP_NETROWADD* newRow, /**< The network matrix row addition datastructure */
    7025 const spqr_row row, /**< The row to check */
    7026 const spqr_col* columns, /**< The column indices of the nonzeros in the row */
    7027 const double* columnValues, /**< The matrix entries of the nonzeros in the row */
    7028 const int numColumns /**< The number of nonzeros in the row */
    7029 )
    7030{
    7031 newRow->newRowIndex = row;
    7032
    7033 newRow->numDecompositionColumnArcs = 0;
    7034 newRow->numColumnArcs = 0;
    7035
    7036 for( int i = 0; i < numColumns; ++i )
    7037 {
    7038 spqr_arc columnArc = getDecompositionColumnArc(dec, columns[i]);
    7039 SCIP_Bool reversed = columnValues[i] < 0.0;
    7040 if( SPQRarcIsValid(columnArc) )
    7041 {//If the arc is the current decomposition: save it in the array
    7043 {
    7044 int newNumArcs = newRow->memDecompositionColumnArcs == 0 ? 8 : 2 * newRow->memDecompositionColumnArcs;
    7046 newRow->memDecompositionColumnArcs, newNumArcs) );
    7048 newRow->memDecompositionColumnArcs, newNumArcs) );
    7049 newRow->memDecompositionColumnArcs = newNumArcs;
    7050 }
    7051 newRow->decompositionColumnArcs[newRow->numDecompositionColumnArcs] = columnArc;
    7054 }
    7055 else
    7056 {
    7057 //Not in the decomposition: add it to the set of arcs which are newly added with this row.
    7058 if( newRow->numColumnArcs == newRow->memColumnArcs )
    7059 {
    7060 int newNumArcs = newRow->memColumnArcs == 0 ? 8 : 2 * newRow->memColumnArcs;
    7062 newRow->memColumnArcs, newNumArcs) );
    7064 newRow->memColumnArcs, newNumArcs) );
    7065 newRow->memColumnArcs = newNumArcs;
    7066 }
    7067 newRow->newColumnArcs[newRow->numColumnArcs] = columns[i];
    7068 newRow->newColumnReversed[newRow->numColumnArcs] = reversed;
    7069 newRow->numColumnArcs++;
    7070 }
    7071 }
    7072
    7073 return SCIP_OKAY;
    7074}
    7075
    7076/** Adds members to the reduced member tree, by starting at the given member, jumping up to the parent, repeating this
    7077 * procedure until the root has been added.
    7078 */
    7079static
    7081 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    7082 SCIP_NETROWADD* newRow, /**< The network matrix row addition datastructure */
    7083 const spqr_member firstMember /**< The member to create a reduced member for */
    7084 )
    7085{
    7086 assert(SPQRmemberIsValid(firstMember));
    7087
    7089 callstack[0].member = firstMember;
    7090 int callDepth = 0;
    7091
    7092 while( callDepth >= 0 )
    7093 {
    7094 spqr_member member = callstack[callDepth].member;
    7095 reduced_member_id reducedMember = newRow->memberInformation[member].reducedMember;
    7096
    7097 SCIP_Bool reducedValid = reducedMemberIsValid(reducedMember);
    7098 if( !reducedValid )
    7099 {
    7100 //reduced member was not yet created; we create it
    7101 reducedMember = newRow->numReducedMembers;
    7102
    7103 SPQRRowReducedMember* reducedMemberData = &newRow->reducedMembers[reducedMember];
    7104 ++newRow->numReducedMembers;
    7105
    7106 reducedMemberData->member = member;
    7107 reducedMemberData->numChildren = 0;
    7108 reducedMemberData->numCutArcs = 0;
    7109 reducedMemberData->firstCutArc = INVALID_CUT_ARC;
    7110 reducedMemberData->type = TYPE_UNDETERMINED;
    7111 reducedMemberData->numPropagatedChildren = 0;
    7112 reducedMemberData->articulationArc = SPQR_INVALID_ARC;
    7113 reducedMemberData->splitNode = SPQR_INVALID_NODE;
    7114 reducedMemberData->otherNode = SPQR_INVALID_NODE;
    7115 reducedMemberData->splitArc = SPQR_INVALID_ARC;
    7116 reducedMemberData->splitHead = FALSE;
    7117 reducedMemberData->allHaveCommonNode = FALSE;
    7118 reducedMemberData->otherNodeSplit = FALSE;
    7119 reducedMemberData->willBeReversed = FALSE;
    7120 reducedMemberData->coloredNode = SPQR_INVALID_NODE;
    7121
    7122 newRow->memberInformation[member].reducedMember = reducedMember;
    7123 assert(memberIsRepresentative(dec, member));
    7124 spqr_member parentMember = findMemberParent(dec, member);
    7125
    7126 if( SPQRmemberIsValid(parentMember) )
    7127 {
    7128 //recursive call to parent member
    7129 ++callDepth;
    7130 assert(callDepth < newRow->memCreateReducedMembersCallstack);
    7131 callstack[callDepth].member = parentMember;
    7132 continue;
    7133 }
    7134 else
    7135 {
    7136 //we found a new reduced decomposition component
    7137
    7138 reducedMemberData->parent = INVALID_REDUCED_MEMBER;
    7139 reducedMemberData->depth = 0;
    7140 reducedMemberData->rootMember = member;
    7141
    7142 assert(newRow->numReducedComponents < newRow->memReducedComponents);
    7143 newRow->reducedComponents[newRow->numReducedComponents].root = reducedMember;
    7144 ++newRow->numReducedComponents;
    7145 }
    7146 }
    7147 if( reducedValid )
    7148 {
    7149 assert(reducedMember < newRow->numReducedMembers);
    7150 //Reduced member was already created in earlier call
    7151 //update the depth of the root if appropriate
    7152 reduced_member_id* depthMinimizer = &newRow->memberInformation[newRow->reducedMembers[reducedMember].rootMember].rootDepthMinimizer;
    7153 if( reducedMemberIsInvalid(*depthMinimizer) ||
    7154 newRow->reducedMembers[reducedMember].depth < newRow->reducedMembers[*depthMinimizer].depth )
    7155 {
    7156 *depthMinimizer = reducedMember;
    7157 }
    7158 }
    7159 while( TRUE ) /*lint !e716*/
    7160 {
    7161 --callDepth;
    7162 if( callDepth < 0 )
    7163 break;
    7164 spqr_member parentMember = callstack[callDepth + 1].member;
    7165 reduced_member_id parentReducedMember = newRow->memberInformation[parentMember].reducedMember;
    7166 spqr_member currentMember = callstack[callDepth].member;
    7167 reduced_member_id currentReducedMember = newRow->memberInformation[currentMember].reducedMember;
    7168
    7169 SPQRRowReducedMember* parentReducedMemberData = &newRow->reducedMembers[parentReducedMember];
    7170 SPQRRowReducedMember* reducedMemberData = &newRow->reducedMembers[currentReducedMember];
    7171
    7172 reducedMemberData->parent = parentReducedMember;
    7173 reducedMemberData->depth = parentReducedMemberData->depth + 1;
    7174 reducedMemberData->rootMember = parentReducedMemberData->rootMember;
    7175
    7176 newRow->reducedMembers[parentReducedMember].numChildren++;
    7177 }
    7178 }
    7179
    7180 reduced_member_id returnedMember = newRow->memberInformation[callstack[0].member].reducedMember;
    7181 return returnedMember;
    7182}
    7183
    7184
    7185/** Construct the reduced decomposition, which is the smallest subtree containing all members cut arcs. */
    7186static
    7188 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    7189 SCIP_NETROWADD* newRow /**< The network matrix row addition datastructure */
    7190 )
    7191{
    7192#ifndef NDEBUG
    7193 for( int i = 0; i < newRow->memMemberInformation; ++i )
    7194 {
    7196 }
    7197#endif
    7198
    7199 newRow->numReducedComponents = 0;
    7200 newRow->numReducedMembers = 0;
    7201 if( newRow->numDecompositionColumnArcs == 0 )
    7202 {//Early return in case the reduced decomposition will be empty
    7203 return SCIP_OKAY;
    7204 }
    7205 assert(newRow->numReducedMembers == 0);
    7206 assert(newRow->numReducedComponents == 0);
    7207
    7208 int newSize = largestMemberID(dec);//Is this sufficient?
    7209 if( newSize > newRow->memReducedMembers )
    7210 {
    7211 int updatedSize = MAX(2 * newRow->memReducedMembers, newSize);
    7212 SCIP_ALLOC( BMSreallocBlockMemoryArray(dec->env, &newRow->reducedMembers, newRow->memReducedMembers, updatedSize) );
    7213 newRow->memReducedMembers = updatedSize;
    7214 }
    7215 if( newSize > newRow->memMemberInformation )
    7216 {
    7217 int updatedSize = MAX(2 * newRow->memMemberInformation, newSize);
    7218 SCIP_ALLOC( BMSreallocBlockMemoryArray(dec->env, &newRow->memberInformation, newRow->memMemberInformation, updatedSize) );
    7219 for( int i = newRow->memMemberInformation; i < updatedSize; ++i )
    7220 {
    7223 }
    7224 newRow->memMemberInformation = updatedSize;
    7225 }
    7226
    7227 int numComponents = numConnectedComponents(dec);
    7228 if( numComponents > newRow->memReducedComponents )
    7229 {
    7230 int updatedSize = MAX(2 * newRow->memReducedComponents, numComponents);
    7231 SCIP_ALLOC( BMSreallocBlockMemoryArray(dec->env, &newRow->reducedComponents, newRow->memReducedComponents, updatedSize) );
    7232 newRow->memReducedComponents = updatedSize;
    7233 }
    7234
    7235 int numMembers = getNumMembers(dec);
    7236 if( newRow->memCreateReducedMembersCallstack < numMembers )
    7237 {
    7238 int updatedSize = MAX(2 * newRow->memCreateReducedMembersCallstack, numMembers);
    7240 newRow->memCreateReducedMembersCallstack, updatedSize) );
    7241 newRow->memCreateReducedMembersCallstack = updatedSize;
    7242 }
    7243
    7244 //Create the reduced members (recursively)
    7245 for( int i = 0; i < newRow->numDecompositionColumnArcs; ++i )
    7246 {
    7247 assert(i < newRow->memDecompositionColumnArcs);
    7248 spqr_arc arc = newRow->decompositionColumnArcs[i];
    7249 spqr_member arcMember = findArcMember(dec, arc);
    7250 reduced_member_id reducedMember = createRowReducedMembersToRoot(dec, newRow, arcMember);
    7251 reduced_member_id* depthMinimizer = &newRow->memberInformation[newRow->reducedMembers[reducedMember].rootMember].rootDepthMinimizer;
    7252 if( reducedMemberIsInvalid(*depthMinimizer) )
    7253 {
    7254 *depthMinimizer = reducedMember;
    7255 }
    7256 }
    7257
    7258 //Set the reduced roots according to the root depth minimizers
    7259 for( int i = 0; i < newRow->numReducedComponents; ++i )
    7260 {
    7261 SPQRRowReducedComponent* component = &newRow->reducedComponents[i];
    7262 spqr_member rootMember = newRow->reducedMembers[component->root].member;
    7263 reduced_member_id reducedMinimizer = newRow->memberInformation[rootMember].rootDepthMinimizer;
    7264 component->rootDepth = newRow->reducedMembers[reducedMinimizer].depth;
    7265 component->root = reducedMinimizer;
    7266
    7267 //This simplifies code further down which does not need to be component-aware; just pretend that the reduced member is the new root.
    7268 newRow->reducedMembers[component->root].parent = INVALID_REDUCED_MEMBER;
    7269 assert(memberIsRepresentative(dec, rootMember));
    7270 }
    7271
    7272 //update the children array
    7273 int numTotalChildren = 0;
    7274 for( int i = 0; i < newRow->numReducedMembers; ++i )
    7275 {
    7276 SPQRRowReducedMember* reducedMember = &newRow->reducedMembers[i];
    7277 reduced_member_id minimizer = newRow->memberInformation[reducedMember->rootMember].rootDepthMinimizer;
    7278 if( reducedMember->depth >= newRow->reducedMembers[minimizer].depth )
    7279 {
    7280 reducedMember->firstChild = numTotalChildren;
    7281 numTotalChildren += reducedMember->numChildren;
    7282 reducedMember->numChildren = 0;
    7283 }
    7284 }
    7285
    7286 if( newRow->memChildrenStorage < numTotalChildren )
    7287 {
    7288 int newMemSize = MAX(newRow->memChildrenStorage * 2, numTotalChildren);
    7290 newMemSize) );
    7291 newRow->memChildrenStorage = newMemSize;
    7292 }
    7293 newRow->numChildrenStorage = numTotalChildren;
    7294
    7295 //Fill up the children array`
    7296 for( reduced_member_id reducedMember = 0; reducedMember < newRow->numReducedMembers; ++reducedMember )
    7297 {
    7298 SPQRRowReducedMember* reducedMemberData = &newRow->reducedMembers[reducedMember];
    7299 if( reducedMemberData->depth <=
    7300 newRow->reducedMembers[newRow->memberInformation[reducedMemberData->rootMember].rootDepthMinimizer].depth )
    7301 {
    7302 continue;
    7303 }
    7304 spqr_member parentMember = findMemberParent(dec, reducedMemberData->member);
    7305 reduced_member_id parentReducedMember = SPQRmemberIsValid(parentMember)
    7306 ? newRow->memberInformation[parentMember].reducedMember
    7308 if( reducedMemberIsValid(parentReducedMember) )
    7309 {
    7310 SPQRRowReducedMember* parentReducedMemberData = &newRow->reducedMembers[parentReducedMember];
    7311 newRow->childrenStorage[parentReducedMemberData->firstChild +
    7312 parentReducedMemberData->numChildren] = reducedMember;
    7313 ++parentReducedMemberData->numChildren;
    7314 }
    7315 }
    7316
    7317 //Clean up the root depth minimizers.
    7318 for( int i = 0; i < newRow->numReducedMembers; ++i )
    7319 {
    7320 SPQRRowReducedMember* reducedMember = &newRow->reducedMembers[i];
    7321 assert(reducedMember);
    7322 spqr_member rootMember = reducedMember->rootMember;
    7323 assert(rootMember >= 0);
    7324 assert(rootMember < dec->memMembers);
    7326 }
    7327
    7328 return SCIP_OKAY;
    7329}
    7330
    7331/** Marks an arc as 'cut'.
    7332 *
    7333 * This implies that its cycle in the decomposition must be elongated.
    7334 */
    7335static
    7337 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    7338 SCIP_NETROWADD* newRow, /**< The network matrix row addition datastructure */
    7339 const spqr_arc arc, /**< The arc to mark as a cut arc */
    7340 const reduced_member_id reducedMember, /**< The reduced member containing the arc */
    7341 SCIP_Bool reversed /**< Indicates if the new row entry has +1 or -1 (TRUE) for the arc */
    7342 )
    7343{
    7344 cut_arc_id cut_arc = newRow->numCutArcs;
    7345
    7346 CutArcListNode* listNode = &newRow->cutArcs[cut_arc];
    7347 listNode->arc = arc;
    7348
    7349 listNode->nextMember = newRow->reducedMembers[reducedMember].firstCutArc;
    7350 newRow->reducedMembers[reducedMember].firstCutArc = cut_arc;
    7351
    7352 listNode->nextOverall = newRow->firstOverallCutArc;
    7353 newRow->firstOverallCutArc = cut_arc;
    7354
    7355 newRow->numCutArcs++;
    7356 newRow->reducedMembers[reducedMember].numCutArcs++;
    7357 assert(newRow->numCutArcs <= newRow->memCutArcs);
    7358
    7359 assert(arc < newRow->memIsArcCut);
    7360 newRow->isArcCut[arc] = TRUE;
    7361 newRow->isArcCutReversed[arc] = reversed;
    7362
    7363 assert(memberIsRepresentative(dec, newRow->reducedMembers[reducedMember].member));
    7364 if( getMemberType(dec, newRow->reducedMembers[reducedMember].member) == SPQR_MEMBERTYPE_RIGID )
    7365 {
    7366 listNode->arcHead = findEffectiveArcHead(dec, arc);
    7367 listNode->arcTail = findEffectiveArcTail(dec, arc);
    7368 if( reversed )
    7369 {
    7370 SCIPswapInts(&listNode->arcHead, &listNode->arcTail);
    7371 }
    7372 assert(SPQRnodeIsValid(listNode->arcHead) && SPQRnodeIsValid(listNode->arcTail));
    7373 }
    7374 else
    7375 {
    7376 listNode->arcHead = SPQR_INVALID_NODE;
    7377 listNode->arcTail = SPQR_INVALID_NODE;
    7378 }
    7379
    7380 listNode->arcReversed = reversed;
    7381}
    7382
    7383/** Creates all cut arcs within the decomposition for the new row.
    7384 *
    7385 * Note this preallocates memory for cut arcs which may be created by propagation.
    7386 */
    7387static
    7389 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    7390 SCIP_NETROWADD* newRow /**< The network matrix row addition datastructure */
    7391 )
    7392{
    7393 //Allocate memory for cut arcs
    7394 spqr_arc maxArcID = largestArcID(dec);
    7395 if( maxArcID > newRow->memIsArcCut )
    7396 {
    7397 int newSize = MAX(maxArcID, 2 * newRow->memIsArcCut);
    7398 SCIP_ALLOC( BMSreallocBlockMemoryArray(dec->env, &newRow->isArcCut, newRow->memIsArcCut, newSize) );
    7399 SCIP_ALLOC( BMSreallocBlockMemoryArray(dec->env, &newRow->isArcCutReversed, newRow->memIsArcCut, newSize) );
    7400 for( int i = newRow->memIsArcCut; i < newSize; ++i )
    7401 {
    7402 newRow->isArcCut[i] = FALSE;
    7403 newRow->isArcCutReversed[i] = FALSE;
    7404 }
    7405 newRow->memIsArcCut = newSize;
    7406 }
    7407#ifndef NDEBUG
    7408 for( int i = 0; i < newRow->memIsArcCut; ++i )
    7409 {
    7410 assert(!newRow->isArcCut[i]);
    7411 assert(!newRow->isArcCutReversed[i]);
    7412 }
    7413#endif
    7414
    7415 int numNeededArcs = newRow->numDecompositionColumnArcs * 4;
    7416 if( numNeededArcs > newRow->memCutArcs )
    7417 {
    7418 int newSize = MAX(newRow->memCutArcs * 2, numNeededArcs);
    7419 SCIP_ALLOC( BMSreallocBlockMemoryArray(dec->env, &newRow->cutArcs, newRow->memCutArcs, newSize) );
    7420 newRow->memCutArcs = newSize;
    7421 }
    7422 newRow->numCutArcs = 0;
    7424 for( int i = 0; i < newRow->numDecompositionColumnArcs; ++i )
    7425 {
    7426 spqr_arc arc = newRow->decompositionColumnArcs[i];
    7427 spqr_member member = findArcMember(dec, arc);
    7428 reduced_member_id reduced_member = newRow->memberInformation[member].reducedMember;
    7429 assert(reducedMemberIsValid(reduced_member));
    7430 createCutArc(dec, newRow, arc, reduced_member, newRow->decompositionColumnArcReversed[i]);
    7431 }
    7432
    7433 return SCIP_OKAY;
    7434}
    7435
    7436/** Determines the members of the reduced decomposition which are leafs.
    7437 *
    7438 * This is used in propagation to ensure
    7439 * propagation is only checked for components which have at most one neighbour that is not propagated.
    7440 */
    7441static
    7443 const SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    7444 SCIP_NETROWADD* newRow /**< The network matrix row addition datastructure */
    7445 )
    7446{
    7447 if( newRow->numDecompositionColumnArcs > newRow->memLeafMembers )
    7448 {
    7449 int updatedSize = MAX(newRow->numDecompositionColumnArcs, 2 * newRow->memLeafMembers);
    7450 SCIP_ALLOC( BMSreallocBlockMemoryArray(dec->env, &newRow->leafMembers, newRow->memLeafMembers, updatedSize) );
    7451 newRow->memLeafMembers = updatedSize;
    7452 }
    7453 newRow->numLeafMembers = 0;
    7454
    7455 for( reduced_member_id reducedMember = 0; reducedMember < newRow->numReducedMembers; ++reducedMember )
    7456 {
    7457 if( newRow->reducedMembers[reducedMember].numChildren == 0 )
    7458 {
    7459 newRow->leafMembers[newRow->numLeafMembers] = reducedMember;
    7460 ++newRow->numLeafMembers;
    7461 }
    7462 }
    7463
    7464 return SCIP_OKAY;
    7465}
    7466
    7467/** Preallocates memory arrays necessary for searching rigid components. */
    7468static
    7470 const SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    7471 SCIP_NETROWADD* newRow /**< The network matrix row addition datastructure */
    7472 )
    7473{
    7474 int totalNumNodes = getNumNodes(dec);
    7475 int maxNumNodes = 2 * dec->numArcs;
    7476 if( maxNumNodes > newRow->memNodeColors )
    7477 {
    7478 int newSize = MAX(2 * newRow->memNodeColors, maxNumNodes);
    7479 SCIP_ALLOC( BMSreallocBlockMemoryArray(dec->env, &newRow->nodeColors, newRow->memNodeColors, newSize) );
    7480 for( int i = newRow->memNodeColors; i < newSize; ++i )
    7481 {
    7482 newRow->nodeColors[i] = UNCOLORED;
    7483 }
    7484 newRow->memNodeColors = newSize;
    7485 }
    7486
    7487 if( totalNumNodes > newRow->memArticulationNodes )
    7488 {
    7489 int newSize = MAX(2 * newRow->memArticulationNodes, totalNumNodes);
    7491 newRow->memArticulationNodes = newSize;
    7492 }
    7493 if( totalNumNodes > newRow->memNodeSearchInfo )
    7494 {
    7495 int newSize = MAX(2 * newRow->memNodeSearchInfo, totalNumNodes);
    7497 newSize) );
    7498 newRow->memNodeSearchInfo = newSize;
    7499 }
    7500 if( totalNumNodes > newRow->memCrossingPathCount )
    7501 {
    7502 int newSize = MAX(2 * newRow->memCrossingPathCount, totalNumNodes);
    7504 newRow->memCrossingPathCount = newSize;
    7505 }
    7506 if( totalNumNodes > newRow->memTemporaryColorArray )
    7507 {
    7508 int newSize = MAX(2 * newRow->memTemporaryColorArray, totalNumNodes);
    7510 newRow->memTemporaryColorArray, newSize) );
    7511 newRow->memTemporaryColorArray = newSize;
    7512 }
    7513
    7514 //TODO: see if tradeoff for performance bound by checking max # of nodes of rigid is worth it to reduce size
    7515 //of the following allocations
    7516 int largestID = largestNodeID(dec);
    7517 //TODO: only update the stack sizes of the following when needed? The preallocation may not be worth it.
    7518 if( largestID > newRow->memIntersectionDFSData )
    7519 {
    7520 int newSize = MAX(2 * newRow->memIntersectionDFSData, largestID);
    7522 newRow->memIntersectionDFSData = newSize;
    7523 }
    7524 if( largestID > newRow->memColorDFSData )
    7525 {
    7526 int newSize = MAX(2 * newRow->memColorDFSData, largestID);
    7527 SCIP_ALLOC( BMSreallocBlockMemoryArray(dec->env, &newRow->colorDFSData, newRow->memColorDFSData, newSize) );
    7528 newRow->memColorDFSData = newSize;
    7529 }
    7530 if( largestID > newRow->memArtDFSData )
    7531 {
    7532 int newSize = MAX(2 * newRow->memArtDFSData, largestID);
    7533 SCIP_ALLOC( BMSreallocBlockMemoryArray(dec->env, &newRow->artDFSData, newRow->memArtDFSData, newSize) );
    7534 newRow->memArtDFSData = newSize;
    7535 }
    7536
    7537 for( int i = 0; i < newRow->memIntersectionPathDepth; ++i )
    7538 {
    7539 newRow->intersectionPathDepth[i] = -1;
    7540 }
    7541
    7542 if( largestID > newRow->memIntersectionPathDepth )
    7543 {
    7544 int newSize = MAX(2 * newRow->memIntersectionPathDepth, largestID);
    7546 newSize) );
    7547 for( int i = newRow->memIntersectionPathDepth; i < newSize; ++i )
    7548 {
    7549 newRow->intersectionPathDepth[i] = -1;
    7550 }
    7551 newRow->memIntersectionPathDepth = newSize;
    7552 }
    7553 for( int i = 0; i < newRow->memIntersectionPathParent; ++i )
    7554 {
    7556 }
    7557 if( largestID > newRow->memIntersectionPathParent )
    7558 {
    7559 int newSize = MAX(2 * newRow->memIntersectionPathParent, largestID);
    7561 newSize) );
    7562 for( int i = newRow->memIntersectionPathParent; i < newSize; ++i )
    7563 {
    7565 }
    7566 newRow->memIntersectionPathParent = newSize;
    7567 }
    7568
    7569 return SCIP_OKAY;
    7570}
    7571
    7572/** Clears the colors for all nodes.
    7573 *
    7574 * We do DFS in reverse (reverse exploration order), as zeroing out the entire
    7575 * array is more expensive.
    7576 */
    7577static
    7579 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    7580 SCIP_NETROWADD* newRow, /**< The network matrix row addition datastructure */
    7581 const spqr_node firstRemoveNode /**< The first node that was colored in the original DFS */
    7582 )
    7583{
    7584 assert(firstRemoveNode < newRow->memNodeColors);
    7585
    7586 newRow->nodeColors[firstRemoveNode] = UNCOLORED;
    7587 ColorDFSCallData* data = newRow->colorDFSData;
    7588 if( newRow->colorDFSData == NULL )
    7589 {
    7590 return;
    7591 }
    7592
    7593 data[0].node = firstRemoveNode;
    7594 data[0].arc = getFirstNodeArc(dec, firstRemoveNode);
    7595 if( SPQRarcIsInvalid(data[0].arc) )
    7596 {
    7597 return;
    7598 }
    7599
    7600 int depth = 0;
    7601
    7602 while( depth >= 0 )
    7603 {
    7604 assert(depth < newRow->memColorDFSData);
    7605 ColorDFSCallData* callData = &data[depth];
    7606 spqr_node head = findArcHead(dec, callData->arc);
    7607 spqr_node tail = findArcTail(dec, callData->arc);
    7608 spqr_node otherNode = callData->node == head ? tail : head;
    7609 assert(otherNode < newRow->memNodeColors);
    7610 if( newRow->nodeColors[otherNode] != UNCOLORED )
    7611 {
    7612 callData->arc = getNextNodeArc(dec, callData->arc, callData->node);
    7613
    7614 newRow->nodeColors[otherNode] = UNCOLORED;
    7615 ++depth;
    7616 data[depth].node = otherNode;
    7617 data[depth].arc = getFirstNodeArc(dec, otherNode);
    7618 continue;
    7619 }
    7620
    7621 callData->arc = getNextNodeArc(dec, callData->arc, callData->node);
    7622 while( depth >= 0 && data[depth].arc == getFirstNodeArc(dec, data[depth].node) )
    7623 {
    7624 --depth;
    7625 }
    7626 }
    7627}
    7628
    7629/** Cleans up various arrays used in previous iterations.
    7630 *
    7631 * This is cheaper than reallocating empty memory.
    7632 */
    7633static
    7635 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    7636 SCIP_NETROWADD* newRow /**< The network matrix row addition datastructure */
    7637 )
    7638{
    7639 //zero out coloring information from previous check
    7640 for( int i = 0; i < newRow->numReducedMembers; ++i )
    7641 {
    7643 {
    7644 zeroOutColors(dec, newRow, newRow->reducedMembers[i].coloredNode);
    7645 }
    7646 }
    7647
    7648#ifndef NDEBUG
    7649 for( int i = 0; i < newRow->memNodeColors; ++i )
    7650 {
    7651 assert(newRow->nodeColors[i] == UNCOLORED);
    7652 }
    7653#endif
    7654
    7655 //For cut arcs: clear them from the array from previous iteration
    7656 cut_arc_id cutArcIdx = newRow->firstOverallCutArc;
    7657 while( cutArcIsValid(cutArcIdx) )
    7658 {
    7659 spqr_arc cutArc = newRow->cutArcs[cutArcIdx].arc;
    7660 cutArcIdx = newRow->cutArcs[cutArcIdx].nextOverall;
    7661 newRow->isArcCut[cutArc] = FALSE;
    7662 newRow->isArcCutReversed[cutArc] = FALSE;
    7663 }
    7664#ifndef NDEBUG
    7665 for( int i = 0; i < newRow->memIsArcCut; ++i )
    7666 {
    7667 assert(!newRow->isArcCut[i]);
    7668 assert(!newRow->isArcCutReversed[i]);
    7669 }
    7670#endif
    7671}
    7672
    7673/** Finds all the star nodes, i.e. nodes that are adjacent to all cut arcs, in a rigid member. */
    7674static
    7676 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    7677 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    7678 const reduced_member_id toCheck /**< The reduced member to check */
    7679 )
    7680{
    7681 //4 cases:
    7682 //Only a single edge; both head/tail are okay => network
    7683 //All are adjacent to a single node, but do not have it as head or tail => not network
    7684 //All are adjacent to a single node, and have it as head or tail => network
    7685 //Not all are adjacent to a single node => check articulation nodes
    7686 assert(newRow->reducedMembers[toCheck].numCutArcs > 0);//calling this function otherwise is nonsensical
    7687
    7688 cut_arc_id cutArcIdx = newRow->reducedMembers[toCheck].firstCutArc;
    7689 spqr_arc cutArc = newRow->cutArcs[cutArcIdx].arc;
    7690 spqr_node head = findArcHead(dec, cutArc);
    7691 spqr_node tail = findArcTail(dec, cutArc);
    7692
    7693 SCIP_Bool reverse = findArcSign(dec, cutArc).reversed != newRow->cutArcs[cutArcIdx].arcReversed;
    7694 spqr_node cutArcsHead = reverse ? tail : head;
    7695 spqr_node cutArcsTail = reverse ? head : tail;
    7696
    7697 if( newRow->reducedMembers[toCheck].numCutArcs == 1 )
    7698 {
    7699 newRow->reducedMembers[toCheck].articulationArc = cutArc;
    7700 newRow->reducedMembers[toCheck].splitNode = cutArcsHead;
    7701 newRow->reducedMembers[toCheck].otherNode = cutArcsTail;
    7702 newRow->reducedMembers[toCheck].otherIsSource = TRUE;
    7703 newRow->reducedMembers[toCheck].allHaveCommonNode = TRUE;
    7704 return;// Only a single cut arc
    7705 }
    7706
    7707 spqr_node intersectionNodes[2] = {head, tail};
    7708
    7709 while( cutArcIsValid(newRow->cutArcs[cutArcIdx].nextMember) )
    7710 {
    7711 cutArcIdx = newRow->cutArcs[cutArcIdx].nextMember;
    7712 cutArc = newRow->cutArcs[cutArcIdx].arc;
    7713 head = findArcHead(dec, cutArc);
    7714 tail = findArcTail(dec, cutArc);
    7715 reverse = findArcSign(dec, cutArc).reversed != newRow->cutArcs[cutArcIdx].arcReversed;
    7716 spqr_node effectiveHead = reverse ? tail : head;
    7717 spqr_node effectiveTail = reverse ? head : tail;
    7718 if( effectiveHead != cutArcsHead )
    7719 {
    7720 cutArcsHead = SPQR_INVALID_NODE;
    7721 }
    7722 if( effectiveTail != cutArcsTail )
    7723 {
    7724 cutArcsTail = SPQR_INVALID_NODE;
    7725 }
    7726
    7727 //intersection between intersectionNodes and head and tail
    7728 for( int i = 0; i < 2; ++i )
    7729 {
    7730 if( intersectionNodes[i] != head && intersectionNodes[i] != tail )
    7731 {
    7732 intersectionNodes[i] = SPQR_INVALID_NODE;
    7733 }
    7734 }
    7735 if( SPQRnodeIsInvalid(intersectionNodes[0]) && SPQRnodeIsInvalid(intersectionNodes[1]) )
    7736 {
    7737 newRow->reducedMembers[toCheck].splitNode = SPQR_INVALID_NODE;
    7738 newRow->reducedMembers[toCheck].allHaveCommonNode = FALSE;
    7739 return;//not all arcs are adjacent to a single node, need to check articulation nodes
    7740 }
    7741 }
    7742 if( SPQRnodeIsInvalid(cutArcsHead) && SPQRnodeIsInvalid(cutArcsTail) )
    7743 {
    7744 //All arcs adjacent to a single node, but not in same direction; not network
    7745 newRow->remainsNetwork = FALSE;
    7746 newRow->reducedMembers[toCheck].type = TYPE_NOT_NETWORK;
    7747 return;
    7748 }
    7749 SCIP_Bool headSplittable = SPQRnodeIsValid(cutArcsHead);
    7750 //Check if the n arcs are in a n+1 degree node; if so, the other endpoint of this non split arc is also splittable
    7751 //By virtue of the spanning tree, this arc must be a tree arc.
    7752 spqr_node splitNode = headSplittable ? cutArcsHead : cutArcsTail;
    7753 newRow->reducedMembers[toCheck].splitNode = splitNode;
    7754 newRow->reducedMembers[toCheck].otherIsSource = headSplittable;
    7755 newRow->reducedMembers[toCheck].allHaveCommonNode = TRUE;
    7756 if( newRow->reducedMembers[toCheck].numCutArcs == nodeDegree(dec, splitNode) - 1 )
    7757 {
    7758 spqr_arc firstNodeArc = getFirstNodeArc(dec, splitNode);
    7759 spqr_arc neighbourArc = firstNodeArc;
    7760 do
    7761 {
    7762 if( arcIsTree(dec, neighbourArc))
    7763 {
    7764 break;
    7765 }
    7766 neighbourArc = getNextNodeArc(dec, neighbourArc, splitNode);
    7767 } while( neighbourArc != firstNodeArc );
    7768
    7769 newRow->reducedMembers[toCheck].articulationArc = neighbourArc;
    7770 spqr_arc arcHead = findArcHead(dec, neighbourArc);
    7771 newRow->reducedMembers[toCheck].otherNode = arcHead == splitNode ? findArcTail(dec, neighbourArc) : arcHead;
    7772 }
    7773}
    7774
    7775/** Clears the colors for all nodes, but the neighbours.
    7776 *
    7777 * We do DFS in reverse (reverse exploration order), as zeroing out the entire array is more expensive.
    7778 */
    7779static
    7781 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    7782 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    7783 const spqr_node articulationNode, /**< The node whose neighbours we want to keep */
    7784 const spqr_node startRemoveNode /**< The node where DFS started */
    7785 )
    7786{
    7787 COLOR_STATUS* neighbourColors = newRow->temporaryColorArray;
    7788 assert(nodeDegree(dec, articulationNode) <= newRow->memTemporaryColorArray);
    7789 {
    7790 int i = 0;
    7791 spqr_arc artFirstArc = getFirstNodeArc(dec, articulationNode);
    7792 spqr_arc artItArc = artFirstArc;
    7793 do
    7794 {
    7795 spqr_node head = findArcHead(dec, artItArc);
    7796 spqr_node tail = findArcTail(dec, artItArc);
    7797 spqr_node otherNode = articulationNode == head ? tail : head;
    7798 neighbourColors[i] = newRow->nodeColors[otherNode];
    7799 i++;
    7800 assert(i <= nodeDegree(dec, articulationNode));
    7801 artItArc = getNextNodeArc(dec, artItArc, articulationNode);
    7802 }
    7803 while( artItArc != artFirstArc );
    7804 }
    7805 zeroOutColors(dec, newRow, startRemoveNode);
    7806
    7807 {
    7808 int i = 0;
    7809 spqr_arc artFirstArc = getFirstNodeArc(dec, articulationNode);
    7810 spqr_arc artItArc = artFirstArc;
    7811 do
    7812 {
    7813 spqr_node head = findArcHead(dec, artItArc);
    7814 spqr_node tail = findArcTail(dec, artItArc);
    7815 spqr_node otherNode = articulationNode == head ? tail : head;
    7816 newRow->nodeColors[otherNode] = neighbourColors[i];
    7817 i++;
    7818 assert(i <= nodeDegree(dec, articulationNode));
    7819 artItArc = getNextNodeArc(dec, artItArc, articulationNode);
    7820 }
    7821 while( artItArc != artFirstArc );
    7822 }
    7823}
    7824
    7825/** Find the intersection of all cut arc paths in the given rigid member.
    7826 *
    7827 * Theoretically, there is a faster algorithm using lowest common ancestor queries, but it is quite complicated.
    7828 * Thus, we stick with the 'simple' version below, which is typically also faster in practice.
    7829 */
    7830static
    7832 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    7833 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    7834 const reduced_member_id toCheck, /**< The rigid member to check */
    7835 int* const nodeNumPaths /**< Tracks for each node, how many cut arc paths cross it */
    7836 )
    7837{
    7838 int* intersectionPathDepth = newRow->intersectionPathDepth;
    7839 spqr_node* intersectionPathParent = newRow->intersectionPathParent;
    7840
    7841 //First do a dfs over the tree, storing all the tree-parents and depths for each node
    7842 //TODO: maybe cache this tree and also update it so we can prevent this DFS call?
    7843
    7844 //pick an arbitrary node as root; we just use the first cutArc here
    7845 {
    7846 spqr_node root = findArcHead(dec, newRow->cutArcs[newRow->reducedMembers[toCheck].firstCutArc].arc);
    7847 DFSCallData* pathSearchCallStack = newRow->intersectionDFSData;
    7848
    7849 assert(intersectionPathDepth[root] == -1);
    7850 assert(intersectionPathParent[root] == SPQR_INVALID_NODE);
    7851
    7852 int pathSearchCallStackSize = 0;
    7853
    7854 intersectionPathDepth[root] = 0;
    7855 intersectionPathParent[root] = SPQR_INVALID_NODE;
    7856
    7857 pathSearchCallStack[0].node = root;
    7858 pathSearchCallStack[0].nodeArc = getFirstNodeArc(dec, root);
    7859 pathSearchCallStackSize++;
    7860 while( pathSearchCallStackSize > 0 )
    7861 {
    7862 assert(pathSearchCallStackSize <= newRow->memIntersectionDFSData);
    7863 DFSCallData* dfsData = &pathSearchCallStack[pathSearchCallStackSize - 1];
    7864 //cannot be a tree arc which is its parent
    7865 if( arcIsTree(dec, dfsData->nodeArc) &&
    7866 ( pathSearchCallStackSize <= 1 ||
    7867 dfsData->nodeArc != pathSearchCallStack[pathSearchCallStackSize - 2].nodeArc ) )
    7868 {
    7869 spqr_node head = findArcHeadNoCompression(dec, dfsData->nodeArc);
    7870 spqr_node tail = findArcTailNoCompression(dec, dfsData->nodeArc);
    7871 spqr_node other = head == dfsData->node ? tail : head;
    7872 assert(other != dfsData->node);
    7873
    7874 //We go up a level: add new node to the call stack
    7875 pathSearchCallStack[pathSearchCallStackSize].node = other;
    7876 pathSearchCallStack[pathSearchCallStackSize].nodeArc = getFirstNodeArc(dec, other);
    7877 //Every time a new node is discovered/added, we update its parent and depth information
    7878 assert(intersectionPathDepth[other] == -1);
    7879 assert(intersectionPathParent[other] == SPQR_INVALID_NODE);
    7880 intersectionPathParent[other] = dfsData->node;
    7881 intersectionPathDepth[other] = pathSearchCallStackSize;
    7882 ++pathSearchCallStackSize;
    7883 continue;
    7884 }
    7885 do
    7886 {
    7887 dfsData->nodeArc = getNextNodeArc(dec, dfsData->nodeArc, dfsData->node);
    7888 if( dfsData->nodeArc == getFirstNodeArc(dec, dfsData->node) )
    7889 {
    7890 --pathSearchCallStackSize;
    7891 dfsData = &pathSearchCallStack[pathSearchCallStackSize - 1];
    7892 }
    7893 else
    7894 {
    7895 break;
    7896 }
    7897 }
    7898 while( pathSearchCallStackSize > 0 );
    7899 }
    7900 }
    7901
    7902 //For each cut arc, trace back both ends until they meet
    7903 cut_arc_id cutArc = newRow->reducedMembers[toCheck].firstCutArc;
    7904 do
    7905 {
    7906 spqr_arc arc = newRow->cutArcs[cutArc].arc;
    7907 cutArc = newRow->cutArcs[cutArc].nextMember;
    7908
    7909 //Iteratively jump up to the parents until they reach a common parent
    7910 spqr_node source = findArcHead(dec, arc);
    7911 spqr_node target = findArcTail(dec, arc);
    7912 int sourceDepth = intersectionPathDepth[source];
    7913 int targetDepth = intersectionPathDepth[target];
    7914 nodeNumPaths[source]++;
    7915 nodeNumPaths[target]++;
    7916
    7917 while( sourceDepth > targetDepth )
    7918 {
    7919 assert(source != target);
    7920 source = intersectionPathParent[source];
    7921 nodeNumPaths[source]++;
    7922 --sourceDepth;
    7923 }
    7924 while( targetDepth > sourceDepth )
    7925 {
    7926 assert(source != target);
    7927 target = intersectionPathParent[target];
    7928 nodeNumPaths[target]++;
    7929 --targetDepth;
    7930 }
    7931 while( source != target && targetDepth >= 0 )
    7932 {
    7933 source = intersectionPathParent[source];
    7934 target = intersectionPathParent[target];
    7935 nodeNumPaths[source]++;
    7936 nodeNumPaths[target]++;
    7937 --targetDepth;
    7938 }
    7939 //In all the above, the lowest common ancestor is increased twice, so we correct for it ad-hoc
    7940 nodeNumPaths[source]--;
    7941 assert(SPQRnodeIsValid(source) && SPQRnodeIsValid(target));
    7942 assert(source == target);
    7943 }
    7944 while( cutArcIsValid(cutArc));
    7945}
    7946
    7947/** Add a node to array of articulation nodes. */
    7948static
    7950 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    7951 spqr_node articulationNode /**< The node to add */
    7952 )
    7953{
    7954#ifndef NDEBUG
    7955 for( int i = 0; i < newRow->numArticulationNodes; ++i )
    7956 {
    7957 assert(newRow->articulationNodes[i] != articulationNode);
    7958 }
    7959#endif
    7960 newRow->articulationNodes[newRow->numArticulationNodes] = articulationNode;
    7961 ++newRow->numArticulationNodes;
    7962}
    7963
    7964/** Find all the articulation points of the rigid member graph where the cut arcs are removed.
    7965 *
    7966 * Articulation points are nodes whose removal disconnects the remaining graph.
    7967 */
    7968static
    7970 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    7971 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    7972 ArticulationNodeInformation* nodeInfo, /**< Stores information about the found articulation nodes */
    7973 reduced_member_id reducedMember /**< The reduced member to find the articulation nodes for */
    7974 )
    7975{
    7976 const SCIP_Bool* arcRemoved = newRow->isArcCut;
    7977
    7978 int rootChildren = 0;
    7979 spqr_node root_node = findArcHead(dec, getFirstMemberArc(dec, newRow->reducedMembers[reducedMember].member));
    7980
    7981 ArticulationPointCallStack* callStack = newRow->artDFSData;
    7982
    7983 int depth = 0;
    7984 int time = 1;
    7985
    7986 callStack[depth].arc = getFirstNodeArc(dec, root_node);
    7987 callStack[depth].node = root_node;
    7988 callStack[depth].parent = SPQR_INVALID_NODE;
    7989 callStack[depth].isAP = FALSE;
    7990
    7991 nodeInfo[root_node].low = time;
    7992 nodeInfo[root_node].discoveryTime = time;
    7993
    7994 while( depth >= 0 )
    7995 {
    7996 if( !arcRemoved[callStack[depth].arc] )
    7997 {
    7998 spqr_node node = callStack[depth].node;
    7999 spqr_node head = findArcHead(dec, callStack[depth].arc);
    8000 spqr_node tail = findArcTail(dec, callStack[depth].arc);
    8001 spqr_node otherNode = node == head ? tail : head;
    8002 if( otherNode != callStack[depth].parent )
    8003 {
    8004 if( nodeInfo[otherNode].discoveryTime == 0 )
    8005 {
    8006 if( depth == 0 )
    8007 {
    8008 rootChildren++;
    8009 }
    8010 //recursive call
    8011 ++depth;
    8012 assert(depth < newRow->memArtDFSData);
    8013 callStack[depth].parent = node;
    8014 callStack[depth].node = otherNode;
    8015 callStack[depth].arc = getFirstNodeArc(dec, otherNode);
    8016 callStack[depth].isAP = FALSE;
    8017
    8018 ++time;
    8019 nodeInfo[otherNode].low = time;
    8020 nodeInfo[otherNode].discoveryTime = time;
    8021 continue;
    8022 }
    8023 else
    8024 {
    8025 nodeInfo[node].low = MIN(nodeInfo[node].low, nodeInfo[otherNode].discoveryTime);
    8026 }
    8027 }
    8028 }
    8029
    8030 while( TRUE ) /*lint !e716*/
    8031 {
    8032 callStack[depth].arc = getNextNodeArc(dec, callStack[depth].arc, callStack[depth].node);
    8033 if( callStack[depth].arc != getFirstNodeArc(dec, callStack[depth].node)) break;
    8034 --depth;
    8035 if( depth < 0 ) break;
    8036
    8037 spqr_node current_node = callStack[depth].node;
    8038 spqr_node other_node = callStack[depth + 1].node;
    8039 nodeInfo[current_node].low = MIN(nodeInfo[current_node].low, nodeInfo[other_node].low);
    8040 if( depth != 0 &&
    8041 !callStack[depth].isAP &&
    8042 nodeInfo[current_node].discoveryTime <= nodeInfo[other_node].low )
    8043 {
    8044 addArticulationNode(newRow, current_node);
    8045 callStack[depth].isAP = TRUE;
    8046 }
    8047 }
    8048 }
    8049 if( rootChildren > 1 )
    8050 {
    8051 addArticulationNode(newRow, root_node);
    8052 }
    8053}
    8054
    8055/** For a given articulation node, partitions the rigid member's graph where it is removed into a SOURCE and SINK
    8056 * partition.
    8057 *
    8058 * All cut arcs must point (after reversal) from the source partition to the sink partition. This is akin
    8059 * to finding a 2-coloring, and uses a DFS to do so. This function specifically executes the DFS/recursive part.
    8060 */
    8061static
    8063 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    8064 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    8065 spqr_node articulationNode, /**< The articulation node to obtain the coloring for */
    8066 spqr_node firstProcessNode, /**< The first node to process for the DFS */
    8067 COLOR_STATUS firstColor, /**< The partition that the first node lies in. */
    8068 SCIP_Bool* isGood /**< Returns whether the coloring was consistent */
    8069 )
    8070{
    8071 const SCIP_Bool* isArcCut = newRow->isArcCut;
    8072 COLOR_STATUS* nodeColors = newRow->nodeColors;
    8073 ColorDFSCallData* data = newRow->colorDFSData;
    8074
    8075 data[0].node = firstProcessNode;
    8076 data[0].arc = getFirstNodeArc(dec, firstProcessNode);
    8077 newRow->nodeColors[firstProcessNode] = firstColor;
    8078
    8079 int depth = 0;
    8080 while( depth >= 0 )
    8081 {
    8082 assert(depth < newRow->memColorDFSData);
    8083 assert(newRow->nodeColors[articulationNode] == UNCOLORED);
    8084
    8085 ColorDFSCallData* callData = &data[depth];
    8086 spqr_node head = findArcHead(dec, callData->arc);
    8087 spqr_node tail = findArcTail(dec, callData->arc);
    8088 spqr_node otherNode = callData->node == head ? tail : head;
    8089 COLOR_STATUS currentColor = nodeColors[callData->node];
    8090 COLOR_STATUS otherColor = nodeColors[otherNode];
    8091 //Checks the direction of the arc; in the rest of the algorithm, we just need to check partition
    8092 if( isArcCut[callData->arc] && currentColor != otherColor )
    8093 {
    8094 SCIP_Bool otherIsTail = callData->node == head;
    8095 SCIP_Bool arcReversed = findArcSign(dec, callData->arc).reversed != newRow->isArcCutReversed[callData->arc];
    8096 SCIP_Bool good = ( currentColor == COLOR_SOURCE ) == ( otherIsTail == arcReversed );
    8097 if( !good )
    8098 {
    8099 *isGood = FALSE;
    8100 break;
    8101 }
    8102 }
    8103 if( otherNode != articulationNode )
    8104 {
    8105 if( otherColor == UNCOLORED )
    8106 {
    8107 if( isArcCut[callData->arc] )
    8108 {
    8109 nodeColors[otherNode] = currentColor == COLOR_SOURCE ? COLOR_SINK : COLOR_SOURCE;//reverse the colors
    8110 }
    8111 else
    8112 {
    8113 nodeColors[otherNode] = currentColor;
    8114 }
    8115 callData->arc = getNextNodeArc(dec, callData->arc, callData->node);
    8116
    8117 depth++;
    8118 assert(depth < newRow->memColorDFSData);
    8119 data[depth].node = otherNode;
    8120 data[depth].arc = getFirstNodeArc(dec, otherNode);
    8121 continue;
    8122 }
    8123 if( isArcCut[callData->arc] != ( currentColor != otherColor ) )
    8124 {
    8125 *isGood = FALSE;
    8126 break;
    8127 }
    8128 }
    8129 callData->arc = getNextNodeArc(dec, callData->arc, callData->node);
    8130 while( depth >= 0 && data[depth].arc == getFirstNodeArc(dec, data[depth].node) )
    8131 {
    8132 --depth;
    8133 }
    8134 }
    8135}
    8136
    8137/** For a given articulation node, partitions the rigid member's graph where it is removed into a SOURCE and SINK
    8138 * partition.
    8139 *
    8140 * All cut arcs must point (after reversal) from the source partition to the sink partition. This is akin
    8141 * to finding a 2-coloring, and uses a DFS to do so.
    8142 */
    8143static
    8145 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    8146 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    8147 const reduced_member_id reducedMember, /**< The rigid member whose graph to color */
    8148 const spqr_node node, /**< The articulation node to obtain the coloring for */
    8149 SCIP_Bool* const isGood /**< Returns whether the coloring was consistent */
    8150 )
    8151{
    8152 //we should only perform this function if there's more than one cut arc
    8153 assert(newRow->reducedMembers[reducedMember].numCutArcs > 1);
    8154#ifndef NDEBUG
    8155 {
    8156 spqr_member member = newRow->reducedMembers[reducedMember].member;
    8157 spqr_arc firstArc = getFirstMemberArc(dec, member);
    8158 spqr_arc memberArc = firstArc;
    8159 do
    8160 {
    8161 assert(newRow->nodeColors[findArcHeadNoCompression(dec, memberArc)] == UNCOLORED);
    8162 assert(newRow->nodeColors[findArcTailNoCompression(dec, memberArc)] == UNCOLORED);
    8163 memberArc = getNextMemberArc(dec, memberArc);
    8164 }
    8165 while( firstArc != memberArc );
    8166 }
    8167#endif
    8168
    8169 spqr_node firstProcessNode;
    8170 COLOR_STATUS firstColor;
    8171 {
    8172 cut_arc_id cutArc = newRow->reducedMembers[reducedMember].firstCutArc;
    8173 spqr_arc arc = newRow->cutArcs[cutArc].arc;
    8174 assert(SPQRarcIsValid(arc));
    8175 spqr_node head = findArcHead(dec, arc);
    8176 spqr_node tail = findArcTail(dec, arc);
    8177 if( findArcSign(dec, arc).reversed != newRow->cutArcs[cutArc].arcReversed )
    8178 {
    8179 spqr_node temp = head;
    8180 head = tail;
    8181 tail = temp;
    8182 }
    8183 if( tail != node )
    8184 {
    8185 firstProcessNode = tail;
    8186 firstColor = COLOR_SOURCE;
    8187 }
    8188 else
    8189 {
    8190 assert(head != node);
    8191 firstProcessNode = head;
    8192 firstColor = COLOR_SINK;
    8193 }
    8194 }
    8195 assert(SPQRnodeIsValid(firstProcessNode) && firstProcessNode != node);
    8196 *isGood = TRUE;
    8197 newRow->reducedMembers[reducedMember].coloredNode = firstProcessNode;
    8198 rigidConnectedColoringRecursive(dec, newRow, node, firstProcessNode, firstColor, isGood);
    8199
    8200 // Need to zero all colors for next attempts if we failed
    8201 if( !( *isGood ) )
    8202 {
    8203 zeroOutColors(dec, newRow, firstProcessNode);
    8204 newRow->reducedMembers[reducedMember].coloredNode = SPQR_INVALID_NODE;
    8205 }
    8206 else
    8207 {
    8208 //Otherwise, we zero out all colors but the ones which we need
    8209 zeroOutColorsExceptNeighbourhood(dec, newRow, node, firstProcessNode);
    8210 newRow->reducedMembers[reducedMember].coloredNode = node;
    8211 }
    8212}
    8213
    8214/** Given a coloring for an articulation node, we can prove that a neighbouring node is splittable if and only if it is
    8215 * the unique node in the neighbourhood of the articulation node within the SOURCE or SINK partition. In this function,
    8216 * we check for a splittable articulation node if such an adjacent node exists, and return it if possible.
    8217 */
    8218static
    8220 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    8221 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    8222 const spqr_node articulationNode, /**< The articulation whose neighbours are to be checked */
    8223 spqr_arc* const adjacentSplittingArc/**< The arc connecting the two splittable nodes. */
    8224 )
    8225{
    8226 spqr_node firstSideCandidate = SPQR_INVALID_NODE;
    8227 spqr_node secondSideCandidate = SPQR_INVALID_NODE;
    8228 spqr_arc firstSideArc = SPQR_INVALID_ARC;
    8229 spqr_arc secondSideArc = SPQR_INVALID_ARC;
    8230 int numFirstSide = 0;
    8231 int numSecondSide = 0;
    8232
    8233 spqr_arc firstArc = getFirstNodeArc(dec, articulationNode);
    8234 spqr_arc moveArc = firstArc;
    8235 do
    8236 {
    8237 spqr_node head = findArcHead(dec, moveArc);
    8238 spqr_node tail = findArcTail(dec, moveArc);
    8239 spqr_node otherNode = articulationNode == head ? tail : head;
    8240 assert(newRow->nodeColors[otherNode] != UNCOLORED);
    8241 if(( newRow->nodeColors[otherNode] == COLOR_SOURCE ) != newRow->isArcCut[moveArc] )
    8242 {
    8243 if( numFirstSide == 0 && arcIsTree(dec, moveArc))
    8244 {
    8245 firstSideCandidate = otherNode;
    8246 firstSideArc = moveArc;
    8247 }
    8248 else if( numFirstSide > 0 )
    8249 {
    8250 firstSideCandidate = SPQR_INVALID_NODE;
    8251 }
    8252 ++numFirstSide;
    8253 }
    8254 else
    8255 {
    8256 if( numSecondSide == 0 && arcIsTree(dec, moveArc))
    8257 {
    8258 secondSideCandidate = otherNode;
    8259 secondSideArc = moveArc;
    8260 }
    8261 else if( numSecondSide > 0 )
    8262 {
    8263 secondSideCandidate = SPQR_INVALID_NODE;
    8264 }
    8265 ++numSecondSide;
    8266 }
    8267 moveArc = getNextNodeArc(dec, moveArc, articulationNode);
    8268 }
    8269 while( moveArc != firstArc );
    8270
    8271 if( numFirstSide == 1 )
    8272 {
    8273 *adjacentSplittingArc = firstSideArc;
    8274 return firstSideCandidate;
    8275 }
    8276 else if( numSecondSide == 1 )
    8277 {
    8278 *adjacentSplittingArc = secondSideArc;
    8279 return secondSideCandidate;
    8280 }
    8281 return SPQR_INVALID_NODE;
    8282}
    8283
    8284/** Find all the splittable articulation points that lie on the intersection of all cut arc cycles.
    8285 *
    8286 * firstNode and secondNode can be set to limit the nodes that this function checks to the given nodes.
    8287 */
    8288static
    8290 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    8291 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    8292 const reduced_member_id toCheck, /**< The rigid member to check */
    8293 spqr_node firstNode, /**< Optional: the first given node that should be checked */
    8294 spqr_node secondNode /**< Optional: the second given node that should be checked */
    8295 )
    8296{
    8297 assert(newRow->reducedMembers[toCheck].numCutArcs > 1);
    8298
    8299 int totalNumNodes = getNumNodes(dec);
    8300 int* nodeNumPaths = newRow->crossingPathCount;
    8301
    8302 for( int i = 0; i < totalNumNodes; ++i )
    8303 {
    8304 nodeNumPaths[i] = 0;
    8305 }
    8306
    8307 intersectionOfAllPaths(dec, newRow, toCheck, nodeNumPaths);
    8308
    8309 newRow->numArticulationNodes = 0;
    8310
    8312 //TODO: ugly; we clean up over all decomposition nodes for every component
    8313 //clean up can not easily be done in the search, unfortunately
    8314 for( int i = 0; i < totalNumNodes; ++i )
    8315 {
    8316 artNodeInfo[i].low = 0;
    8317 artNodeInfo[i].discoveryTime = 0;
    8318 }
    8319
    8320 articulationPoints(dec, newRow, artNodeInfo, toCheck);
    8321
    8322 int numCutArcs = newRow->reducedMembers[toCheck].numCutArcs;
    8323 for( int i = 0; i < newRow->numArticulationNodes; i++ )
    8324 {
    8325 spqr_node articulationNode = newRow->articulationNodes[i];
    8326 assert(nodeIsRepresentative(dec, articulationNode));
    8327 SCIP_Bool isOnPath = nodeNumPaths[articulationNode] == numCutArcs;
    8328 if( isOnPath &&
    8329 (( SPQRnodeIsInvalid(firstNode) && SPQRnodeIsInvalid(secondNode)) || articulationNode == firstNode ||
    8330 articulationNode == secondNode ) )
    8331 {
    8332 SCIP_Bool isGood = TRUE;
    8333 rigidConnectedColoring(dec, newRow, toCheck, articulationNode, &isGood);
    8334 if( !isGood )
    8335 {
    8336 continue;
    8337 }
    8338 newRow->reducedMembers[toCheck].splitNode = articulationNode;
    8339
    8340 //Once we have found one node, we can (possibly) find another by looking at the coloring of the neighbourhood of it.
    8341
    8342 spqr_arc adjacentSplittingArc = SPQR_INVALID_ARC;
    8343 spqr_node adjacentSplittingNode = checkNeighbourColoringArticulationNode(dec, newRow, articulationNode,
    8344 &adjacentSplittingArc);
    8345
    8346 //If the neighbour-coloring works, we still need to check that the adjacent node
    8347 //is also an articulation node
    8348 if( SPQRnodeIsValid(adjacentSplittingNode) &&
    8349 (( SPQRnodeIsInvalid(firstNode) && SPQRnodeIsInvalid(secondNode)) || adjacentSplittingNode == firstNode ||
    8350 adjacentSplittingNode == secondNode ) )
    8351 {
    8352 SCIP_Bool isArticulationNode = FALSE;
    8353 for( int j = 0; j < newRow->numArticulationNodes; ++j )
    8354 {
    8355 if( newRow->articulationNodes[j] == adjacentSplittingNode )
    8356 {
    8357 isArticulationNode = TRUE;
    8358 break;
    8359 }
    8360 }
    8361 if( isArticulationNode )
    8362 {
    8363 newRow->reducedMembers[toCheck].articulationArc = adjacentSplittingArc;
    8364 newRow->reducedMembers[toCheck].otherNode = adjacentSplittingNode;
    8365 newRow->reducedMembers[toCheck].otherIsSource =
    8366 newRow->nodeColors[adjacentSplittingNode] == COLOR_SOURCE;
    8367
    8368 //Cleaning up the colors
    8369 {
    8370 spqr_arc firstNodeArc = getFirstNodeArc(dec, articulationNode);
    8371 spqr_arc itArc = firstNodeArc;
    8372 do
    8373 {
    8374 spqr_node head = findArcHead(dec, itArc);
    8375 spqr_node tail = findArcTail(dec, itArc);
    8376 spqr_node otherNode = articulationNode == head ? tail : head;
    8377 newRow->nodeColors[otherNode] = UNCOLORED;
    8378 itArc = getNextNodeArc(dec, itArc, articulationNode);
    8379 }
    8380 while( itArc != firstNodeArc );
    8381 }
    8382 }
    8383 }
    8384 return;
    8385 }
    8386 }
    8387
    8388 newRow->reducedMembers[toCheck].type = TYPE_NOT_NETWORK;
    8389 newRow->remainsNetwork = FALSE;
    8390}
    8391
    8392/** Checks if a leaf parallel member can be propagated away from the reduced decomposition. */
    8393static
    8395 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    8396 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    8397 const reduced_member_id toCheckMember, /**< The parallel leaf member to check */
    8398 const spqr_arc markerToOther, /**< Marker to the non-leaf member */
    8399 const reduced_member_id otherMember, /**< The connected non-leaf member */
    8400 const spqr_arc markerToCheck /**< Marker from the non-leaf to the leaf parallel member */
    8401 )
    8402{
    8403 SPQRRowReducedMember* member = &newRow->reducedMembers[toCheckMember];
    8404 assert(cutArcIsValid(member->firstCutArc));
    8405
    8406 SCIP_Bool good = TRUE;
    8407 SCIP_Bool isReversed = TRUE;
    8408 int countedCutArcs = 0;
    8409 for( cut_arc_id cutArc = member->firstCutArc; cutArcIsValid(cutArc);
    8410 cutArc = newRow->cutArcs[cutArc].nextMember )
    8411 {
    8412 spqr_arc arc = newRow->cutArcs[cutArc].arc;
    8413 SCIP_Bool arcIsReversed = arcIsReversedNonRigid(dec, arc) != newRow->cutArcs[cutArc].arcReversed;
    8414 if( countedCutArcs == 0 )
    8415 {
    8416 isReversed = arcIsReversed;
    8417 }
    8418 else if( arcIsReversed != isReversed )
    8419 {
    8420 good = FALSE;
    8421 break;
    8422 }
    8423 ++countedCutArcs;
    8424 }
    8425 if( !good )
    8426 {
    8427 member->type = TYPE_NOT_NETWORK;
    8428 newRow->remainsNetwork = FALSE;
    8429 return;
    8430 }
    8431 //we can only propagate if the marker arc is a tree arc and all other arcs are cut
    8432 if( !arcIsTree(dec, markerToOther) ||
    8433 countedCutArcs != ( getNumMemberArcs(dec, newRow->reducedMembers[toCheckMember].member) - 1 ) )
    8434 {
    8435 //In all other cases, the bond can be split so that the result will be okay!
    8436 newRow->reducedMembers[toCheckMember].type = TYPE_MERGED;
    8437 }
    8438 else
    8439 {
    8440 SCIP_Bool markerIsReversed = arcIsReversedNonRigid(dec, markerToOther);
    8441 createCutArc(dec, newRow, markerToCheck, otherMember, markerIsReversed != isReversed);
    8442 newRow->reducedMembers[toCheckMember].type = TYPE_PROPAGATED;
    8443 }
    8444}
    8445
    8446/** Checks if a leaf series member can be propagated away from the reduced decomposition. */
    8447static
    8449 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    8450 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    8451 const reduced_member_id toCheckMember, /**< The series leaf member to check */
    8452 const spqr_arc markerToOther, /**< Marker to the non-leaf member */
    8453 const reduced_member_id otherMember, /**< The connected non-leaf member */
    8454 const spqr_arc markerToCheck /**< Marker from the non-leaf to the leaf series member */
    8455 )
    8456{
    8457 //Propagation only calls this function if the arc is tree already, so we do not check it here.
    8458 assert(arcIsTree(dec, markerToOther));
    8459 assert(newRow->reducedMembers[toCheckMember].numCutArcs == 1);
    8460 assert(cutArcIsValid(newRow->reducedMembers[toCheckMember].firstCutArc));
    8461 spqr_arc cutArc = newRow->reducedMembers[toCheckMember].firstCutArc;
    8462 spqr_arc arc = newRow->cutArcs[cutArc].arc;
    8463 newRow->reducedMembers[toCheckMember].type = TYPE_PROPAGATED;
    8464 createCutArc(dec, newRow, markerToCheck, otherMember,
    8465 ( arcIsReversedNonRigid(dec, arc) == arcIsReversedNonRigid(dec, markerToOther)) !=
    8466 newRow->cutArcs[cutArc].arcReversed);
    8467}
    8468
    8469/** Checks if a leaf rigid member can be propagated away from the reduced decomposition. */
    8470static
    8472 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    8473 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    8474 const reduced_member_id toCheckMember, /**< The rigid leaf member to check */
    8475 const spqr_arc markerToOther, /**< Marker to the non-leaf member */
    8476 const reduced_member_id otherMember, /**< The connected non-leaf member */
    8477 const spqr_arc markerToCheck /**< Marker from the non-leaf to the rigid leaf member */
    8478 )
    8479{
    8480 //Checking for propagation only makes sense if there is at least one cut arc
    8481 assert(newRow->reducedMembers[toCheckMember].numCutArcs > 0);
    8482
    8483 rigidFindStarNodes(dec, newRow, toCheckMember);
    8484 if( !newRow->remainsNetwork )
    8485 {
    8486 return;
    8487 }
    8488 spqr_node markerHead = findArcHead(dec, markerToOther);
    8489 spqr_node markerTail = findArcTail(dec, markerToOther);
    8490 if( findArcSign(dec, markerToOther).reversed )
    8491 {
    8492 spqr_node temp = markerHead;
    8493 markerHead = markerTail;
    8494 markerTail = temp;
    8495 }
    8496 if( SPQRnodeIsInvalid(newRow->reducedMembers[toCheckMember].splitNode) )
    8497 {
    8498 //not a star => attempt to find splittable nodes using articulation node algorithms
    8499 //We save some work by telling the methods that only the marker nodes should be checked
    8500 rigidGetSplittableArticulationPointsOnPath(dec, newRow, toCheckMember, markerHead, markerTail);
    8501 }
    8502 if( !newRow->remainsNetwork )
    8503 {
    8504 return;
    8505 }
    8506
    8507 if( SPQRarcIsValid(newRow->reducedMembers[toCheckMember].articulationArc) &&
    8508 newRow->reducedMembers[toCheckMember].articulationArc == markerToOther )
    8509 {
    8510 newRow->reducedMembers[toCheckMember].type = TYPE_PROPAGATED;
    8511 SCIP_Bool reverse = ( markerHead == newRow->reducedMembers[toCheckMember].splitNode ) !=
    8512 newRow->reducedMembers[toCheckMember].otherIsSource;
    8513
    8514 createCutArc(dec, newRow, markerToCheck, otherMember, reverse);
    8515 }
    8516 else if( newRow->reducedMembers[toCheckMember].splitNode == markerHead ||
    8517 newRow->reducedMembers[toCheckMember].splitNode == markerTail )
    8518 {
    8519 newRow->reducedMembers[toCheckMember].type = TYPE_MERGED;
    8520 }
    8521 else if( SPQRarcIsValid(newRow->reducedMembers[toCheckMember].articulationArc) &&
    8522 ( newRow->reducedMembers[toCheckMember].otherNode == markerHead ||
    8523 newRow->reducedMembers[toCheckMember].otherNode == markerTail ) )
    8524 {
    8525 newRow->reducedMembers[toCheckMember].type = TYPE_MERGED;
    8526 }
    8527 else
    8528 {
    8529 //Found source or sinks, but not adjacent to the marker
    8530 newRow->reducedMembers[toCheckMember].type = TYPE_NOT_NETWORK;
    8531 newRow->remainsNetwork = FALSE;
    8532 }
    8533}
    8534
    8535/** Checks if a leaf member can be propagated away from the reduced decomposition. */
    8536static
    8538 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    8539 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    8540 const reduced_member_id toCheckMember, /**< The leaf member to check */
    8541 const spqr_arc markerToOther, /**< Marker to the non-leaf member */
    8542 const reduced_member_id otherMember, /**< The connected non-leaf member */
    8543 const spqr_arc markerToCheck /**< Marker from the non-leaf to the leaf member */
    8544 )
    8545{
    8546 assert(newRow->reducedMembers[toCheckMember].type == TYPE_UNDETERMINED);
    8547 switch( getMemberType(dec, newRow->reducedMembers[toCheckMember].member) )
    8548 {
    8550 {
    8551 determineRigidType(dec, newRow, toCheckMember, markerToOther, otherMember, markerToCheck);
    8552 break;
    8553 }
    8556 {
    8557 determineParallelType(dec, newRow, toCheckMember, markerToOther, otherMember, markerToCheck);
    8558 break;
    8559 }
    8561 {
    8562 determineSeriesType(dec, newRow, toCheckMember, markerToOther, otherMember, markerToCheck);
    8563 break;
    8564 }
    8566 default:
    8567 newRow->reducedMembers[toCheckMember].type = TYPE_NOT_NETWORK;
    8568 SCIPABORT();
    8569 }
    8570
    8571 return newRow->reducedMembers[toCheckMember].type;
    8572}
    8573
    8574/** Propagates away all leaf members that are propagatable to shrink the reduced decomposition. */
    8575static
    8577 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    8578 SCIP_NETROWADD* newRow /**< The network matrix row addition data structure */
    8579 )
    8580{
    8581 int leafArrayIndex = 0;
    8582
    8583 reduced_member_id leaf;
    8584 reduced_member_id next;
    8585
    8586 while( leafArrayIndex != newRow->numLeafMembers )
    8587 {
    8588 leaf = newRow->leafMembers[leafArrayIndex];
    8589 //next is invalid if the member is not in the reduced decomposition.
    8590 next = newRow->reducedMembers[leaf].parent;
    8591 spqr_arc parentMarker = markerToParent(dec, newRow->reducedMembers[leaf].member);
    8592 if( next != INVALID_REDUCED_MEMBER && arcIsTree(dec, parentMarker) )
    8593 {
    8594 assert(reducedMemberIsValid(next));
    8595 assert(SPQRarcIsValid(parentMarker));
    8596 RowReducedMemberType type = determineType(dec, newRow, leaf, parentMarker, next,
    8597 markerOfParent(dec, newRow->reducedMembers[leaf].member));
    8598 if( type == TYPE_PROPAGATED )
    8599 {
    8600 ++newRow->reducedMembers[next].numPropagatedChildren;
    8601 if( newRow->reducedMembers[next].numPropagatedChildren == newRow->reducedMembers[next].numChildren )
    8602 {
    8603 newRow->leafMembers[leafArrayIndex] = next;
    8604 }
    8605 else
    8606 {
    8607 ++leafArrayIndex;
    8608 }
    8609 }
    8610 else if( type == TYPE_NOT_NETWORK )
    8611 {
    8612 return;
    8613 }
    8614 else
    8615 {
    8616 assert(type == TYPE_MERGED);
    8617 ++leafArrayIndex;
    8618 }
    8619 }
    8620 else
    8621 {
    8622 ++leafArrayIndex;
    8623 }
    8624 }
    8625
    8626 for( int j = 0; j < newRow->numReducedComponents; ++j )
    8627 {
    8628 //The reduced root might be a leaf as well: we propagate it last
    8629 reduced_member_id root = newRow->reducedComponents[j].root;
    8630
    8631 while( TRUE ) /*lint !e716*/
    8632 {
    8633 if( newRow->reducedMembers[root].numPropagatedChildren == newRow->reducedMembers[root].numChildren - 1 )
    8634 {
    8635 //TODO: bit ugly, have to do a linear search for the child
    8637 spqr_arc markerToChild = SPQR_INVALID_ARC;
    8638 for( children_idx i = newRow->reducedMembers[root].firstChild;
    8639 i < newRow->reducedMembers[root].firstChild + newRow->reducedMembers[root].numChildren; ++i )
    8640 {
    8641 reduced_member_id childReduced = newRow->childrenStorage[i];
    8642 if( newRow->reducedMembers[childReduced].type != TYPE_PROPAGATED )
    8643 {
    8644 child = childReduced;
    8645 markerToChild = markerOfParent(dec, newRow->reducedMembers[child].member);
    8646 break;
    8647 }
    8648 }
    8649 assert(SPQRmemberIsValid(newRow->reducedMembers[child].member));
    8650 assert(SPQRarcIsValid(markerToChild));
    8651 if( !arcIsTree(dec, markerToChild) )
    8652 {
    8653 break;
    8654 }
    8655 RowReducedMemberType type = determineType(dec, newRow, root, markerToChild, child,
    8656 markerToParent(dec, newRow->reducedMembers[child].member));
    8657 if( type == TYPE_PROPAGATED )
    8658 {
    8659 root = child;
    8660 }
    8661 else if( type == TYPE_NOT_NETWORK )
    8662 {
    8663 return;
    8664 }
    8665 else
    8666 {
    8667 break;
    8668 }
    8669 }
    8670 else
    8671 {
    8672 break;
    8673 }
    8674 }
    8675 newRow->reducedComponents[j].root = root;
    8677 }
    8678}
    8679
    8680/** A data structure representing a node pair. */
    8681typedef struct
    8682{
    8685} Nodes;
    8686
    8687/** Computes the intersection nodes of all markers that point to reduced tree members.
    8688 *
    8689 * These are the only nodes that may become Y-splittable, after propagation.
    8690 */
    8691static
    8693 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    8694 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    8695 const reduced_member_id toCheck /**< The rigid member to check */
    8696 )
    8697{
    8698 Nodes pair;
    8699 pair.first = SPQR_INVALID_NODE;
    8701
    8702 //take union of children's arcs nodes to find one or two candidates
    8703 for( children_idx i = newRow->reducedMembers[toCheck].firstChild;
    8704 i < newRow->reducedMembers[toCheck].firstChild + newRow->reducedMembers[toCheck].numChildren; ++i )
    8705 {
    8706 reduced_member_id reducedChild = newRow->childrenStorage[i];
    8707 if( newRow->reducedMembers[reducedChild].type != TYPE_PROPAGATED )
    8708 {
    8709 spqr_arc arc = markerOfParent(dec, newRow->reducedMembers[reducedChild].member);
    8710 spqr_node head = findArcHead(dec, arc);
    8711 spqr_node tail = findArcTail(dec, arc);
    8712 if( SPQRnodeIsInvalid(pair.first) && SPQRnodeIsInvalid(pair.second) )
    8713 {
    8714 pair.first = head;
    8715 pair.second = tail;
    8716 }
    8717 else
    8718 {
    8719 if( pair.first != head && pair.first != tail )
    8720 {
    8721 pair.first = SPQR_INVALID_NODE;
    8722 }
    8723 if( pair.second != head && pair.second != tail )
    8724 {
    8726 }
    8727 }
    8728 if( SPQRnodeIsInvalid(pair.first) && SPQRnodeIsInvalid(pair.second) )
    8729 {
    8730 return pair;
    8731 }
    8732 }
    8733 }
    8734 if( reducedMemberIsValid(newRow->reducedMembers[toCheck].parent) &&
    8735 newRow->reducedMembers[newRow->reducedMembers[toCheck].parent].type != TYPE_PROPAGATED )
    8736 {
    8737 spqr_arc arc = markerToParent(dec, newRow->reducedMembers[toCheck].member);
    8738 spqr_node head = findArcHead(dec, arc);
    8739 spqr_node tail = findArcTail(dec, arc);
    8740 if( SPQRnodeIsInvalid(pair.first) && SPQRnodeIsInvalid(pair.second) )
    8741 {
    8742 pair.first = head;
    8743 pair.second = tail;
    8744 }
    8745 else
    8746 {
    8747 if( pair.first != head && pair.first != tail )
    8748 {
    8749 pair.first = SPQR_INVALID_NODE;
    8750 }
    8751 if( pair.second != head && pair.second != tail )
    8752 {
    8754 }
    8755 }
    8756 }
    8757 return pair;
    8758}
    8759
    8760/** Allocates memory for various procedures that need to do tree-search for rigid members (e.g. DFS or BFS). */
    8761static
    8763 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    8764 SCIP_NETROWADD* newRow /**< The network matrix row addition data structure */
    8765 )
    8766{
    8767 int necessarySpace = newRow->numReducedMembers;
    8768 if( necessarySpace > newRow->memMergeTreeCallData )
    8769 {
    8770 int updatedSize = MAX(2 * newRow->memMergeTreeCallData, necessarySpace);
    8772 updatedSize) );
    8773 newRow->memMergeTreeCallData = updatedSize;
    8774 }
    8775 return SCIP_OKAY;
    8776}
    8777
    8778/** Determine the type of a rigid member when it is the only member in the reduced decomposition. */
    8779static
    8781 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    8782 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    8783 reduced_member_id reducedMember /**< The rigid member to determine the type for */
    8784 )
    8785{
    8786 //Checking for propagation only makes sense if there is at least one cut arc
    8787 assert(newRow->reducedMembers[reducedMember].numCutArcs > 0);
    8788
    8789 rigidFindStarNodes(dec, newRow, reducedMember);
    8790 if( !newRow->remainsNetwork )
    8791 {
    8792 return;
    8793 }
    8794
    8795 if( SPQRnodeIsInvalid(newRow->reducedMembers[reducedMember].splitNode) )
    8796 {
    8797 //not a star => attempt to find splittable nodes using articulation node algorithms
    8799 }
    8800 if( SPQRnodeIsValid(newRow->reducedMembers[reducedMember].splitNode) )
    8801 {
    8802 newRow->reducedMembers[reducedMember].type = TYPE_MERGED;
    8803 }
    8804 else
    8805 {
    8806 newRow->reducedMembers[reducedMember].type = TYPE_NOT_NETWORK;
    8807 newRow->remainsNetwork = FALSE;
    8808 }
    8809}
    8810
    8811/** Determine the type of a parallel member when it is the only member in the reduced decomposition. */
    8812static
    8814 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    8815 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    8816 reduced_member_id reducedMember /**< The parallel member to determine the type for */
    8817 )
    8818{
    8819 SPQRRowReducedMember* redMember = &newRow->reducedMembers[reducedMember];
    8820 assert(cutArcIsValid(redMember->firstCutArc));
    8821
    8822 SCIP_Bool good = TRUE;
    8823 SCIP_Bool isReversed = TRUE;
    8824 int countedCutArcs = 0;
    8825 for( cut_arc_id cutArc = redMember->firstCutArc; cutArcIsValid(cutArc);
    8826 cutArc = newRow->cutArcs[cutArc].nextMember )
    8827 {
    8828 spqr_arc arc = newRow->cutArcs[cutArc].arc;
    8829 SCIP_Bool arcIsReversed = arcIsReversedNonRigid(dec, arc) != newRow->cutArcs[cutArc].arcReversed;
    8830 if( countedCutArcs == 0 )
    8831 {
    8832 isReversed = arcIsReversed;
    8833 }
    8834 else if( arcIsReversed != isReversed )
    8835 {
    8836 good = FALSE;
    8837 break;
    8838 }
    8839 ++countedCutArcs;
    8840 }
    8841 if( !good )
    8842 {
    8843 redMember->type = TYPE_NOT_NETWORK;
    8844 newRow->remainsNetwork = FALSE;
    8845 }
    8846 else
    8847 {
    8848 redMember->type = TYPE_MERGED;
    8849 }
    8850}
    8851
    8852/** Determine the type of a series member when it is the only member in the reduced decomposition. */
    8853static
    8855 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    8856 reduced_member_id reducedMember /**< The series member to determine the type for */
    8857 )
    8858{
    8859 assert(newRow->reducedMembers[reducedMember].numCutArcs == 1);
    8860 assert(cutArcIsValid(newRow->reducedMembers[reducedMember].firstCutArc));
    8861 newRow->reducedMembers[reducedMember].type = TYPE_MERGED;
    8862}
    8863
    8864/** Sets the given split nodes; performs bookkeeping so that we have an easier time updating the graph in many
    8865 * edge cases.
    8866 *
    8867 * Algorithmically speaking, does nothing important.
    8868 */
    8869static
    8871 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    8872 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    8873 reduced_member_id id, /**< The reduced member that we compute the split node for */
    8874 spqr_node candidateOne, /**< The first candidate node */
    8875 spqr_node candidateTwo /**< The second candidate node */
    8876 )
    8877{
    8879 {
    8880 return SPQR_INVALID_NODE;
    8881 }
    8882 spqr_node splitNode = newRow->reducedMembers[id].splitNode;
    8883 if( splitNode == candidateOne || splitNode == candidateTwo )
    8884 {
    8885 if( newRow->reducedMembers[id].allHaveCommonNode )
    8886 {
    8887 spqr_arc firstNodeArc = getFirstNodeArc(dec, splitNode);
    8888 spqr_arc iterArc = firstNodeArc;
    8890 do
    8891 {
    8892 spqr_node head = findArcHead(dec, iterArc);
    8893 spqr_node other = head == splitNode ? findArcTail(dec, iterArc) : head;
    8894 newRow->nodeColors[other] = color;
    8895 iterArc = getNextNodeArc(dec, iterArc, splitNode);
    8896 }
    8897 while( iterArc != firstNodeArc );
    8898 newRow->reducedMembers[id].coloredNode = splitNode;
    8899 }
    8900 return splitNode;
    8901 }
    8902 splitNode = newRow->reducedMembers[id].otherNode;
    8903 if( SPQRnodeIsInvalid(splitNode) || ( splitNode != candidateOne && splitNode != candidateTwo ) )
    8904 {
    8905 return SPQR_INVALID_NODE;
    8906 }
    8907 assert(SPQRarcIsValid(newRow->reducedMembers[id].articulationArc));
    8908 if( newRow->reducedMembers[id].allHaveCommonNode )
    8909 {
    8910 spqr_arc firstNodeArc = getFirstNodeArc(dec, splitNode);
    8911 spqr_arc iterArc = firstNodeArc;
    8912 COLOR_STATUS color;
    8913 if( newRow->reducedMembers[id].numCutArcs == 1 )
    8914 {
    8915 color = newRow->reducedMembers[id].otherIsSource ? COLOR_SINK : COLOR_SOURCE;
    8916 }
    8917 else
    8918 {
    8919 color = newRow->reducedMembers[id].otherIsSource ? COLOR_SOURCE : COLOR_SINK;
    8920 }
    8921 do
    8922 {
    8923 spqr_node head = findArcHead(dec, iterArc);
    8924 spqr_node other = head == splitNode ? findArcTail(dec, iterArc) : head;
    8925 newRow->nodeColors[other] = color;
    8926 iterArc = getNextNodeArc(dec, iterArc, splitNode);
    8927 }
    8928 while( iterArc != firstNodeArc );
    8929 newRow->nodeColors[newRow->reducedMembers[id].splitNode] = newRow->reducedMembers[id].otherIsSource ? COLOR_SINK
    8930 : COLOR_SOURCE;
    8931 }
    8932 else
    8933 {
    8934 COLOR_STATUS splitColor = newRow->nodeColors[splitNode];
    8935 spqr_arc firstNodeArc = getFirstNodeArc(dec, splitNode);
    8936 spqr_arc iterArc = firstNodeArc;
    8937 do
    8938 {
    8939 spqr_node head = findArcHead(dec, iterArc);
    8940 spqr_node other = head == splitNode ? findArcTail(dec, iterArc) : head;
    8941 newRow->nodeColors[other] = splitColor;
    8942 iterArc = getNextNodeArc(dec, iterArc, splitNode);
    8943 }
    8944 while( iterArc != firstNodeArc );
    8945 newRow->nodeColors[newRow->reducedMembers[id].splitNode] = splitColor == COLOR_SOURCE ? COLOR_SINK : COLOR_SOURCE;
    8946 newRow->nodeColors[splitNode] = UNCOLORED;
    8947 }
    8948
    8949 newRow->reducedMembers[id].coloredNode = splitNode;
    8950 return splitNode;
    8951}
    8952
    8953/** After propagation, determines the split type of the first leaf node of the reduced decomposition.
    8954 *
    8955 * The leaf nodes of the decomposition after propagation can only be of type P or R.
    8956 */
    8957static
    8959 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    8960 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    8961 reduced_member_id reducedId /**< The member to determine the split type for */
    8962 )
    8963{
    8964 spqr_member member = newRow->reducedMembers[reducedId].member;
    8965 SPQRMemberType type = getMemberType(dec, member);
    8966 assert(type == SPQR_MEMBERTYPE_PARALLEL || type == SPQR_MEMBERTYPE_RIGID);
    8967 assert(cutArcIsValid(newRow->reducedMembers[reducedId].firstCutArc));
    8968 SPQRRowReducedMember* redMember = &newRow->reducedMembers[reducedId];
    8969
    8970 if( type == SPQR_MEMBERTYPE_PARALLEL )
    8971 {
    8972 //TODO: duplicate-ish
    8973
    8974 SCIP_Bool good = TRUE;
    8975 SCIP_Bool isReversed = TRUE;
    8976 int countedCutArcs = 0;
    8977 for( cut_arc_id cutArc = redMember->firstCutArc; cutArcIsValid(cutArc);
    8978 cutArc = newRow->cutArcs[cutArc].nextMember )
    8979 {
    8980 spqr_arc arc = newRow->cutArcs[cutArc].arc;
    8981 SCIP_Bool arcIsReversed = arcIsReversedNonRigid(dec, arc) != newRow->cutArcs[cutArc].arcReversed;
    8982 if( countedCutArcs == 0 )
    8983 {
    8984 isReversed = arcIsReversed;
    8985 }
    8986 else if( arcIsReversed != isReversed )
    8987 {
    8988 good = FALSE;
    8989 break;
    8990 }
    8991 ++countedCutArcs;
    8992 }
    8993 if( !good )
    8994 {
    8995 redMember->type = TYPE_NOT_NETWORK;
    8996 newRow->remainsNetwork = FALSE;
    8997 }
    8998 else
    8999 {
    9000 spqr_arc marker = markerToParent(dec, member);
    9001 redMember->type = TYPE_MERGED;
    9002 redMember->splitArc = marker;
    9003 redMember->splitHead = TRUE;
    9004 redMember->otherIsSource = arcIsReversedNonRigid(dec, marker) == isReversed;
    9005 }
    9006 return;
    9007 }
    9008 assert(type == SPQR_MEMBERTYPE_RIGID);
    9009
    9010 spqr_arc marker = markerToParent(dec, member);
    9011 spqr_node markerHead = findArcHead(dec, marker);
    9012 spqr_node markerTail = findArcTail(dec, marker);
    9013 if( findArcSign(dec, marker).reversed )
    9014 {
    9015 spqr_node temp = markerHead;
    9016 markerHead = markerTail;
    9017 markerTail = temp;
    9018 }
    9019
    9020 if( !SPQRnodeIsValid(newRow->reducedMembers[reducedId].splitNode) )
    9021 {
    9022 //Checking for propagation only makes sense if there is at least one cut arc
    9023 assert(newRow->reducedMembers[reducedId].numCutArcs > 0);
    9024
    9025 rigidFindStarNodes(dec, newRow, reducedId);
    9026 if( !newRow->remainsNetwork )
    9027 {
    9028 return;
    9029 }
    9030
    9031 if( SPQRnodeIsInvalid(newRow->reducedMembers[reducedId].splitNode) )
    9032 {
    9033 //not a star => attempt to find splittable nodes using articulation node algorithms
    9034 //We save some work by telling the methods that only the marker nodes should be checked
    9035 rigidGetSplittableArticulationPointsOnPath(dec, newRow, reducedId, markerHead, markerTail);
    9036 }
    9037 if( !newRow->remainsNetwork )
    9038 {
    9039 return;
    9040 }
    9041 if( SPQRnodeIsInvalid(newRow->reducedMembers[reducedId].splitNode) )
    9042 {
    9043 redMember->type = TYPE_NOT_NETWORK;
    9044 newRow->remainsNetwork = FALSE;
    9045 return;
    9046 }
    9047 }
    9048
    9049 spqr_node splitNode = newRow->reducedMembers[reducedId].splitNode;
    9050#ifndef NDEBUG
    9051 spqr_node otherNode = newRow->reducedMembers[reducedId].otherNode;
    9052#endif
    9053 //We cannot have both splittable (should have been propagated)
    9054 assert(!(( splitNode == markerTail || splitNode == markerHead ) &&
    9055 ( otherNode == markerTail || otherNode == markerHead )));
    9056
    9057 splitNode = determineAndColorSplitNode(dec, newRow, reducedId, markerHead, markerTail);
    9058 if( SPQRnodeIsInvalid(splitNode) )
    9059 {
    9060 redMember->type = TYPE_NOT_NETWORK;
    9061 newRow->remainsNetwork = FALSE;
    9062 return;
    9063 }
    9064 assert(splitNode == markerHead || splitNode == markerTail);
    9065
    9066 newRow->reducedMembers[reducedId].splitNode = splitNode;
    9067 newRow->reducedMembers[reducedId].willBeReversed = FALSE;
    9068 redMember->type = TYPE_MERGED;
    9069}
    9070
    9071/** A data structure that tells us if the head or tail of a marked arc is split, and if the other node is in the
    9072 * source or the sink partition.
    9073 */
    9074typedef struct
    9075{
    9076 SCIP_Bool headSplit; /**< Is the head or tail of the marked arc split?*/
    9077 SCIP_Bool otherIsSource; /**< Is the non-split node in the source or sink partition? */
    9079
    9080/** Get the split orientation for a given rigid member and marked arc. */
    9081static
    9083 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    9084 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    9085 reduced_member_id reducedId, /**< The member to determine the split orientation for */
    9086 spqr_arc arcToNext /**< The marked arc to determine the orientation for */
    9087 )
    9088{
    9089 assert(findArcMemberNoCompression(dec, arcToNext) == newRow->reducedMembers[reducedId].member);
    9090 assert(SPQRnodeIsValid(newRow->reducedMembers[reducedId].splitNode));
    9091
    9092 SplitOrientation orientation;
    9093 if( newRow->reducedMembers[reducedId].numCutArcs == 0 )
    9094 {
    9095 spqr_node splitNode = newRow->reducedMembers[reducedId].splitNode;
    9096 spqr_node head = findEffectiveArcHead(dec, arcToNext);
    9097
    9098 assert(head == splitNode || splitNode == findEffectiveArcTailNoCompression(dec, arcToNext));
    9099
    9100 orientation.headSplit = newRow->reducedMembers[reducedId].willBeReversed == ( head != splitNode );
    9101 orientation.otherIsSource = newRow->reducedMembers[reducedId].otherIsSource;
    9102 return orientation;
    9103 }
    9104 spqr_node splitNode = newRow->reducedMembers[reducedId].splitNode;
    9105 spqr_node arcHead = findArcHead(dec, arcToNext);
    9106 spqr_node arcTail = findArcTail(dec, arcToNext);
    9107 if( findArcSign(dec, arcToNext).reversed )
    9108 {
    9109 spqr_node temp = arcHead;
    9110 arcHead = arcTail;
    9111 arcTail = temp;
    9112 }
    9113 assert(arcHead == splitNode || arcTail == splitNode);
    9114 spqr_node other = arcHead == splitNode ? arcTail : arcHead;
    9115
    9116 assert(newRow->nodeColors[other] == COLOR_SOURCE || newRow->nodeColors[other] == COLOR_SINK);
    9117
    9118 if( newRow->reducedMembers[reducedId].willBeReversed )
    9119 {
    9120 orientation.headSplit = arcHead != splitNode;
    9121 orientation.otherIsSource = newRow->nodeColors[other] != COLOR_SOURCE;
    9122 }
    9123 else
    9124 {
    9125 orientation.headSplit = arcHead == splitNode;
    9126 orientation.otherIsSource = newRow->nodeColors[other] == COLOR_SOURCE;
    9127 }
    9128 return orientation;
    9129}
    9130
    9131/** Get the split orientation for a given parallel member and marked arc. */
    9132static
    9134 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    9135 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    9136 reduced_member_id reducedId, /**< The member to determine the split orientation for */
    9137 spqr_arc arcToNext /**< The marked arc to determine the orientaiton for */
    9138 )
    9139{
    9140 assert(findArcMemberNoCompression(dec, arcToNext) == newRow->reducedMembers[reducedId].member);
    9141 assert(SPQRarcIsValid(newRow->reducedMembers[reducedId].splitArc) && SPQRarcIsValid(arcToNext));
    9142
    9143 SplitOrientation orientation;
    9144 orientation.otherIsSource = newRow->reducedMembers[reducedId].otherIsSource;
    9145 if( arcIsReversedNonRigid(dec, arcToNext) == arcIsReversedNonRigid(dec, newRow->reducedMembers[reducedId].splitArc))
    9146 {
    9147 orientation.headSplit = newRow->reducedMembers[reducedId].splitHead;
    9148 }
    9149 else
    9150 {
    9151 orientation.headSplit = !newRow->reducedMembers[reducedId].splitHead;
    9152 }
    9153 return orientation;
    9154}
    9155
    9156/** Get the split orientation for a given series member and marked arc. */
    9157static
    9159 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    9160 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    9161 reduced_member_id reducedId, /**< The member to determine the split orientation for */
    9162 spqr_arc arcToNext /**< The marked arc to determine the orientaiton for */
    9163 )
    9164{
    9165 assert(findArcMemberNoCompression(dec, arcToNext) == newRow->reducedMembers[reducedId].member);
    9166 assert(SPQRarcIsValid(newRow->reducedMembers[reducedId].splitArc) && SPQRarcIsValid(arcToNext));
    9167
    9168 SplitOrientation orientation;
    9169 orientation.otherIsSource = newRow->reducedMembers[reducedId].otherIsSource;
    9170 if( arcIsReversedNonRigid(dec, arcToNext) == arcIsReversedNonRigid(dec, newRow->reducedMembers[reducedId].splitArc))
    9171 {
    9172 orientation.headSplit = !newRow->reducedMembers[reducedId].splitHead;
    9173 }
    9174 else
    9175 {
    9176 orientation.headSplit = newRow->reducedMembers[reducedId].splitHead;
    9177 }
    9178 return orientation;
    9179}
    9180
    9181/** Get the split orientation for a given member and marked arc. */
    9182static
    9184 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    9185 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    9186 reduced_member_id reducedId, /**< The member to determine the split orientation for */
    9187 spqr_arc arcToNext /**< The marked arc to determine the orientaiton for */
    9188 )
    9189{
    9190 switch( getMemberType(dec, newRow->reducedMembers[reducedId].member) )
    9191 {
    9193 return getRelativeOrientationRigid(dec, newRow, reducedId, arcToNext);
    9195 return getRelativeOrientationParallel(dec, newRow, reducedId, arcToNext);
    9197 return getRelativeOrientationSeries(dec, newRow, reducedId, arcToNext);
    9200 default:
    9201 {
    9202 SCIPABORT();
    9203 SplitOrientation orientation; /*lint !e527*/
    9204 orientation.headSplit = FALSE; /*lint !e527*/
    9205 orientation.otherIsSource = FALSE;
    9206 return orientation;
    9207 }
    9208 }
    9209}
    9210
    9211/** Determine the split type of a series node when the SPQR tree is not a singular member. */
    9212static
    9214 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    9215 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    9216 reduced_member_id reducedId, /**< The member to determine the split orientation for */
    9217 spqr_arc marker, /**< The marker to the previous member whose type was already determined */
    9218 SplitOrientation previousOrientation /**< The orientation to the previous member */
    9219 )
    9220{
    9221 int numAdjacentMembers =
    9222 newRow->reducedMembers[reducedId].numChildren - newRow->reducedMembers[reducedId].numPropagatedChildren;
    9223 if( reducedMemberIsValid(newRow->reducedMembers[reducedId].parent) &&
    9224 newRow->reducedMembers[newRow->reducedMembers[reducedId].parent].type != TYPE_PROPAGATED )
    9225 {
    9226 ++numAdjacentMembers;
    9227 }
    9228 assert(numAdjacentMembers > 1);
    9229 if( numAdjacentMembers > 2 )
    9230 {
    9231 newRow->remainsNetwork = FALSE;
    9232 newRow->reducedMembers[reducedId].type = TYPE_NOT_NETWORK;
    9233 return;
    9234 }
    9235 cut_arc_id cutArc = newRow->reducedMembers[reducedId].firstCutArc;
    9236 if( cutArcIsValid(cutArc) )
    9237 {
    9238 spqr_arc arc = newRow->cutArcs[cutArc].arc;
    9239 SCIP_Bool good = ((( arcIsReversedNonRigid(dec, arc) == arcIsReversedNonRigid(dec, marker)) ==
    9240 newRow->cutArcs[cutArc].arcReversed ) == previousOrientation.headSplit ) ==
    9241 previousOrientation.otherIsSource;
    9242 if( !good )
    9243 {
    9244 newRow->remainsNetwork = FALSE;
    9245 newRow->reducedMembers[reducedId].type = TYPE_NOT_NETWORK;
    9246 return;
    9247 }
    9248 newRow->reducedMembers[reducedId].splitArc = marker;
    9249 newRow->reducedMembers[reducedId].splitHead = previousOrientation.headSplit;
    9250 newRow->reducedMembers[reducedId].otherIsSource = !previousOrientation.otherIsSource;
    9251 newRow->reducedMembers[reducedId].type = TYPE_MERGED;
    9252 return;
    9253 }
    9254
    9255 newRow->reducedMembers[reducedId].splitArc = marker;
    9256 newRow->reducedMembers[reducedId].splitHead = previousOrientation.headSplit;
    9257 newRow->reducedMembers[reducedId].otherIsSource = previousOrientation.otherIsSource;
    9258 newRow->reducedMembers[reducedId].type = TYPE_MERGED;
    9259}
    9260
    9261/** Determine the split type of a parallel node when the SPQR tree is not a singular member. */
    9262static
    9264 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    9265 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    9266 reduced_member_id reducedId, /**< The member to determine the split orientation for */
    9267 spqr_arc marker, /**< The marker to the previous member whose type was already determined */
    9268 SplitOrientation previousOrientation /**< The orientation to the previous member */
    9269 )
    9270{
    9271 SPQRRowReducedMember* redMember = &newRow->reducedMembers[reducedId];
    9272
    9273 SCIP_Bool good = TRUE;
    9274 SCIP_Bool isReversed = TRUE;
    9275 int countedCutArcs = 0;
    9276 for( cut_arc_id cutArc = redMember->firstCutArc; cutArcIsValid(cutArc);
    9277 cutArc = newRow->cutArcs[cutArc].nextMember )
    9278 {
    9279 spqr_arc arc = newRow->cutArcs[cutArc].arc;
    9280 SCIP_Bool arcIsReversed = arcIsReversedNonRigid(dec, arc) != newRow->cutArcs[cutArc].arcReversed;
    9281 if( countedCutArcs == 0 )
    9282 {
    9283 isReversed = arcIsReversed;
    9284 }
    9285 else if( arcIsReversed != isReversed )
    9286 {
    9287 good = FALSE;
    9288 break;
    9289 }
    9290 ++countedCutArcs;
    9291 }
    9292 if( !good )
    9293 {
    9294 redMember->type = TYPE_NOT_NETWORK;
    9295 newRow->remainsNetwork = FALSE;
    9296 return;
    9297 }
    9298 if( countedCutArcs == 0 )
    9299 {
    9300 redMember->splitArc = marker;
    9301 redMember->splitHead = previousOrientation.headSplit;
    9302 redMember->otherIsSource = previousOrientation.otherIsSource;
    9303 redMember->type = TYPE_MERGED;
    9304 return;
    9305 }
    9306 SCIP_Bool isHeadSourceOrTailTarget = previousOrientation.headSplit == previousOrientation.otherIsSource;
    9307 SCIP_Bool isOkay = isHeadSourceOrTailTarget == ( isReversed == arcIsReversedNonRigid(dec, marker));
    9308 if( !isOkay )
    9309 {
    9310 redMember->type = TYPE_NOT_NETWORK;
    9311 newRow->remainsNetwork = FALSE;
    9312 return;
    9313 }
    9314 redMember->splitArc = marker;
    9315 redMember->splitHead = previousOrientation.headSplit;
    9316 redMember->otherIsSource = previousOrientation.otherIsSource;
    9317 redMember->type = TYPE_MERGED;
    9318}
    9319
    9320/** Determine the split type of a rigid node when the SPQR tree is not a singular member. */
    9321static
    9323 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    9324 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    9325 reduced_member_id reducedId, /**< The reduced member to determine the split orientation for */
    9326 spqr_member member, /**< The member belonging to the reduced member */
    9327 spqr_arc marker, /**< The marker to the previous member whose type was already determined */
    9328 SplitOrientation previousOrientation /**< The orientation to the previous member */
    9329 )
    9330{
    9331 assert(dec);
    9332 assert(newRow);
    9333 assert(getMemberType(dec, member) == SPQR_MEMBERTYPE_RIGID);
    9334
    9335 Nodes nodes = rigidDetermineCandidateNodesFromAdjacentComponents(dec, newRow, reducedId);
    9336 if( SPQRnodeIsInvalid(nodes.first) && SPQRnodeIsInvalid(nodes.second) )
    9337 {
    9338 newRow->remainsNetwork = FALSE;
    9339 newRow->reducedMembers[reducedId].type = TYPE_NOT_NETWORK;
    9340 return;
    9341 }
    9342 if( SPQRnodeIsInvalid(nodes.first) && SPQRnodeIsValid(nodes.second) )
    9343 {
    9344 nodes.first = nodes.second;
    9345 nodes.second = SPQR_INVALID_NODE;
    9346 }
    9347
    9348 spqr_node markerHead = findArcHead(dec, marker);
    9349 spqr_node markerTail = findArcTail(dec, marker);
    9350 if( findArcSign(dec, marker).reversed )
    9351 {
    9352 spqr_node temp = markerHead;
    9353 markerHead = markerTail;
    9354 markerTail = temp;
    9355 }
    9356
    9357 if( newRow->reducedMembers[reducedId].numCutArcs == 0 )
    9358 {
    9359 assert(SPQRnodeIsInvalid(nodes.second));//There must be at least two adjacent components
    9360 if( nodes.first != markerHead && nodes.first != markerTail )
    9361 {
    9362 newRow->remainsNetwork = FALSE;
    9363 newRow->reducedMembers[reducedId].type = TYPE_NOT_NETWORK;
    9364 return;
    9365 }
    9366 SCIP_Bool reverse = previousOrientation.headSplit == ( nodes.first == markerTail );
    9367 newRow->reducedMembers[reducedId].splitNode = nodes.first;
    9368 newRow->reducedMembers[reducedId].otherIsSource = previousOrientation.otherIsSource;
    9369 newRow->reducedMembers[reducedId].willBeReversed = reverse;
    9370 newRow->reducedMembers[reducedId].type = TYPE_MERGED;
    9371 return;
    9372 }
    9373 if( !SPQRnodeIsValid(newRow->reducedMembers[reducedId].splitNode) )
    9374 {
    9375 //Checking for propagation only makes sense if there is at least one cut arc
    9376 assert(newRow->reducedMembers[reducedId].numCutArcs > 0);
    9377
    9378 rigidFindStarNodes(dec, newRow, reducedId);
    9379 if( !newRow->remainsNetwork )
    9380 {
    9381 return;
    9382 }
    9383
    9384 if( SPQRnodeIsInvalid(newRow->reducedMembers[reducedId].splitNode) )
    9385 {
    9386 //not a star => attempt to find splittable nodes using articulation node algorithms
    9387 //We save some work by telling the methods that only the marker nodes should be checked
    9388 rigidGetSplittableArticulationPointsOnPath(dec, newRow, reducedId, nodes.first, nodes.second);
    9389 }
    9390 if( !newRow->remainsNetwork )
    9391 {
    9392 return;
    9393 }
    9394 if( SPQRnodeIsInvalid(newRow->reducedMembers[reducedId].splitNode) )
    9395 {
    9396 newRow->remainsNetwork = FALSE;
    9397 newRow->reducedMembers[reducedId].type = TYPE_NOT_NETWORK;
    9398 return;
    9399 }
    9400 }
    9401 spqr_node splitNode = determineAndColorSplitNode(dec, newRow, reducedId, nodes.first, nodes.second);
    9402
    9403 if( SPQRnodeIsInvalid(splitNode) )
    9404 {
    9405 newRow->remainsNetwork = FALSE;
    9406 newRow->reducedMembers[reducedId].type = TYPE_NOT_NETWORK;
    9407 return;
    9408 }
    9409 assert(splitNode == nodes.first || splitNode == nodes.second);
    9410 assert(splitNode == markerHead || splitNode == markerTail);
    9411
    9412 spqr_node otherNode = splitNode == markerHead ? markerTail : markerHead;
    9413 SCIP_Bool headsMatch = previousOrientation.headSplit == ( splitNode == markerHead );
    9414
    9415 COLOR_STATUS otherColor = newRow->nodeColors[otherNode];
    9416 assert(otherColor == COLOR_SOURCE || otherColor == COLOR_SINK);
    9417 SCIP_Bool otherIsSource = otherColor == COLOR_SOURCE;
    9418
    9419 SCIP_Bool good = headsMatch == ( previousOrientation.otherIsSource == otherIsSource );
    9420
    9421 if( !good )
    9422 {
    9423 newRow->remainsNetwork = FALSE;
    9424 newRow->reducedMembers[reducedId].type = TYPE_NOT_NETWORK;
    9425 return;
    9426 }
    9427
    9428 newRow->reducedMembers[reducedId].splitNode = splitNode;
    9429 newRow->reducedMembers[reducedId].willBeReversed = !headsMatch;
    9430 newRow->reducedMembers[reducedId].type = TYPE_MERGED;
    9431}
    9432
    9433/** Determine the split type of a node when the SPQR tree is not a singular member.
    9434 *
    9435 * This function is used for all the nodes that are not first in the given ordering.
    9436 */
    9437static
    9439 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    9440 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    9441 reduced_member_id current, /**< The current node, whose type has already been determined */
    9442 reduced_member_id next, /**< The next node to determine the type of, adjacent to the current node */
    9443 SCIP_Bool currentIsParent /**< Is the current node a parent of the next node? */
    9444 )
    9445{
    9446 spqr_member member = newRow->reducedMembers[next].member;
    9447 SPQRMemberType type = getMemberType(dec, member);
    9448 spqr_arc nextArc = currentIsParent ? markerToParent(dec, member) : markerOfParent(dec,
    9449 newRow->reducedMembers[current].member);
    9450 spqr_arc currentArc = currentIsParent ? markerOfParent(dec, member) : markerToParent(dec,
    9451 newRow->reducedMembers[current].member);
    9452 SplitOrientation orientation = getRelativeOrientation(dec, newRow, current, currentArc);
    9453 assert(type == SPQR_MEMBERTYPE_PARALLEL || type == SPQR_MEMBERTYPE_RIGID || type == SPQR_MEMBERTYPE_SERIES);
    9454 switch( type )
    9455 {
    9457 {
    9458 determineSplitTypeRigid(dec, newRow, next, member, nextArc, orientation);
    9459 break;
    9460 }
    9462 {
    9463 determineSplitTypeParallel(dec, newRow, next, nextArc, orientation);
    9464 break;
    9465 }
    9467 {
    9468 determineSplitTypeSeries(dec, newRow, next, nextArc, orientation);
    9469 break;
    9470 }
    9471
    9474 default:
    9475 newRow->remainsNetwork = FALSE;
    9476 SCIPABORT();
    9477 }
    9478}
    9479
    9480/** For the given root reduced member of a component, determine if the component is updateable/transformable. */
    9481static
    9483 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    9484 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    9485 reduced_member_id root /**< The root of the given component */
    9486 )
    9487{
    9488 assert(newRow->numReducedMembers <= newRow->memMergeTreeCallData);
    9489 if( newRow->reducedMembers[root].numPropagatedChildren == newRow->reducedMembers[root].numChildren )
    9490 {
    9491 //Determine single component;
    9492 if( newRow->reducedMembers[root].type == TYPE_UNDETERMINED )
    9493 {
    9494 spqr_member member = newRow->reducedMembers[root].member;
    9495 switch( getMemberType(dec, member) )
    9496 {
    9498 determineSingleRowRigidType(dec, newRow, root);
    9499 break;
    9501 determineSingleParallelType(dec, newRow, root);
    9502 break;
    9505 determineSingleSeriesType( newRow, root);
    9506 break;
    9508 default:
    9509 newRow->remainsNetwork = FALSE;
    9510 SCIPABORT();
    9511 }
    9512 }
    9513 return;
    9514 }
    9515
    9516 //Go to a leaf. We need to start in a leaf to avoid the ambiguity of choosing an orientation
    9517 //in members which have no cut arcs; otherwise, we might choose the wrong one
    9518 reduced_member_id leaf = root;
    9519 while( newRow->reducedMembers[leaf].numChildren != newRow->reducedMembers[leaf].numPropagatedChildren )
    9520 {
    9521 for( int i = 0; i < newRow->reducedMembers[leaf].numChildren; ++i )
    9522 {
    9523 children_idx idx = newRow->reducedMembers[leaf].firstChild + i;
    9524 reduced_member_id child = newRow->childrenStorage[idx];
    9525 if( newRow->reducedMembers[child].type != TYPE_PROPAGATED )
    9526 {
    9527 leaf = child;
    9528 break;
    9529 }
    9530 }
    9531 }
    9532 determineSplitTypeFirstLeaf(dec, newRow, leaf);
    9533
    9534 if( !newRow->remainsNetwork )
    9535 {
    9536 return;
    9537 }
    9538 reduced_member_id baseNode = leaf;
    9539 reduced_member_id nextNode = newRow->reducedMembers[baseNode].parent;
    9540
    9541 while( reducedMemberIsValid(nextNode) )
    9542 {
    9543 //check this node
    9544 determineSplitTypeNext(dec, newRow, baseNode, nextNode, FALSE);
    9545 if( !newRow->remainsNetwork )
    9546 {
    9547 return;
    9548 }
    9549 //Add other nodes in the subtree
    9550 //use a while loop to avoid recursion; we may get stack overflows for large graphs
    9551 MergeTreeCallData* data = newRow->mergeTreeCallData;
    9552
    9553 data[0].id = nextNode;
    9554 data[0].currentChild = newRow->reducedMembers[nextNode].firstChild ;
    9555 int depth = 0;
    9556 while( depth >= 0 )
    9557 {
    9558 reduced_member_id id = data[depth].id;
    9559 children_idx childidx = data[depth].currentChild;
    9560 if( childidx == newRow->reducedMembers[id].firstChild + newRow->reducedMembers[id].numChildren )
    9561 {
    9562 --depth;
    9563 continue;
    9564 }
    9565 reduced_member_id currentchild = newRow->childrenStorage[childidx];
    9566 data[depth].currentChild += 1;
    9567 //skip this child if we already processed it or it is not merged
    9568 if( currentchild == baseNode || newRow->reducedMembers[currentchild].type == TYPE_PROPAGATED )
    9569 {
    9570 continue;
    9571 }
    9572 determineSplitTypeNext(dec,newRow,id,currentchild,TRUE);
    9573 if( !newRow->remainsNetwork )
    9574 {
    9575 return;
    9576 }
    9577 //recursively process the child
    9578 depth += 1;
    9579 assert(depth < newRow->memMergeTreeCallData);
    9580 data[depth].id = currentchild;
    9581 data[depth].currentChild = newRow->reducedMembers[currentchild].firstChild;
    9582 }
    9583 //Move up one layer
    9584 baseNode = nextNode;
    9585 nextNode = newRow->reducedMembers[nextNode].parent;
    9586 }
    9587}
    9588
    9589/** Empty the new member information array. */
    9590static
    9592 SCIP_NETROWADD* newRow /**< The network matrix row addition data structure */
    9593 )
    9594{
    9595 //This loop is at the end as memberInformation is also used to assign the cut arcs during propagation
    9596 //Clean up the memberInformation array
    9597 for( int i = 0; i < newRow->numReducedMembers; ++i )
    9598 {
    9600 }
    9601#ifndef NDEBUG
    9602 for( int i = 0; i < newRow->memMemberInformation; ++i )
    9603 {
    9605 }
    9606#endif
    9607}
    9608
    9609/** Transforms a rigid arc by putting it in series with the new column arc.
    9610 *
    9611 * We need to do some magic to keep our the internal datastructures consistent in this case.
    9612 */
    9613static
    9615 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    9616 const spqr_member member, /**< The rigid member that contains the arc that is moved */
    9617 const spqr_arc arc, /**< The arc that is moved to a new series member */
    9618 const SCIP_Bool reverseArcDirection,/**< Is the given arc reversed? */
    9619 NewRowInformation* const newRowInfo /**< Stores information on how to add the new row */
    9620 )
    9621{
    9622 //If a cycle already exists, just expand it with the new arc.
    9623 spqr_member markerCycleMember = SPQR_INVALID_MEMBER;
    9624 spqr_arc markerCycleArc = SPQR_INVALID_ARC;
    9625 SCIP_Bool isParent = arc == markerToParent(dec, member);
    9626 spqr_member adjacentMember = SPQR_INVALID_MEMBER;
    9627 if( isParent )
    9628 {
    9629 adjacentMember = findMemberParent(dec, member);
    9630 if( getMemberType(dec, adjacentMember) == SPQR_MEMBERTYPE_SERIES )
    9631 {
    9632 markerCycleMember = adjacentMember;
    9633 markerCycleArc = markerOfParent(dec, member);
    9634 }
    9635 }
    9636 else if( arcIsChildMarker(dec, arc) )
    9637 {
    9638 adjacentMember = findArcChildMember(dec, arc);
    9639 if( getMemberType(dec, adjacentMember) == SPQR_MEMBERTYPE_SERIES )
    9640 {
    9641 markerCycleMember = adjacentMember;
    9642 markerCycleArc = markerToParent(dec, adjacentMember);
    9643 }
    9644 }
    9645 if( markerCycleMember != SPQR_INVALID_MEMBER )
    9646 {
    9647 newRowInfo->member = markerCycleMember;
    9648 if( arcIsReversedNonRigid(dec, markerCycleArc) )
    9649 {
    9650 newRowInfo->reversed = reverseArcDirection;
    9651 }
    9652 else
    9653 {
    9654 newRowInfo->reversed = !reverseArcDirection;
    9655 }
    9656
    9657 return SCIP_OKAY;
    9658 }
    9659
    9660 //Otherwise, we create a new cycle
    9661 spqr_member newCycle;
    9662 SCIP_CALL( createMember(dec, SPQR_MEMBERTYPE_SERIES, &newCycle) );
    9663 //We would like to move the edge but unfortunately cannot do so without destroying the arc union-find datastructure.
    9664 //Thus, we 'convert' the arc into a marker and add the new series
    9665
    9666 spqr_arc duplicate = SPQR_INVALID_ARC;
    9667 spqr_element element = arcGetElement(dec, arc);
    9668 if( element != MARKER_COLUMN_ELEMENT && element != MARKER_ROW_ELEMENT )
    9669 {
    9670 if( SPQRelementIsColumn(element) )
    9671 {
    9672 SCIP_CALL( createColumnArc(dec, newCycle, &duplicate, SPQRelementToColumn(element), TRUE) );
    9673 }
    9674 else
    9675 {
    9676 SCIP_CALL( createRowArc(dec, newCycle, &duplicate, SPQRelementToRow(element), TRUE) );
    9677 }
    9678 }
    9679 else if( isParent )
    9680 {
    9681 //create parent marker
    9682 SCIP_CALL( createParentMarker(dec, newCycle, arcIsTree(dec, arc), adjacentMember,
    9683 markerOfParent(dec, member), &duplicate, TRUE) );
    9684 }
    9685 else
    9686 {
    9687 //create child marker
    9688 SCIP_CALL( createChildMarker(dec, newCycle, adjacentMember, arcIsTree(dec, arc), &duplicate, TRUE) );
    9689 dec->members[adjacentMember].parentMember = newCycle;
    9690 dec->members[adjacentMember].markerOfParent = duplicate;
    9691 }
    9692 //Create the other marker edge
    9693 spqr_arc cycleMarker = SPQR_INVALID_ARC;
    9694 if( isParent )
    9695 {
    9696 SCIP_CALL( createChildMarker(dec, newCycle, member, !arcIsTree(dec, arc),
    9697 &cycleMarker, FALSE) );
    9698 }
    9699 else
    9700 {
    9701 SCIP_CALL( createParentMarker(dec, newCycle, !arcIsTree(dec, arc),
    9702 member, arc, &cycleMarker, FALSE) );
    9703 }
    9704 //Change the existing edge to a marker
    9705 if( isParent )
    9706 {
    9707 assert(markerToParent(dec, member) == arc);
    9708 dec->arcs[markerOfParent(dec, member)].childMember = newCycle;
    9709 dec->members[member].parentMember = newCycle;
    9710 dec->members[member].markerToParent = arc;
    9711 dec->members[member].markerOfParent = cycleMarker;
    9714 }
    9715 else
    9716 {
    9718 dec->arcs[arc].childMember = newCycle;
    9719 }
    9720 newRowInfo->member = newCycle;
    9721 newRowInfo->reversed = !reverseArcDirection;
    9722
    9723 return SCIP_OKAY;
    9724}
    9725
    9726/** Updates a single rigid member to reflect the new row. */
    9727static
    9729 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    9730 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    9731 const reduced_member_id reducedMember, /**< The reduced member to transform */
    9732 const spqr_member member, /**< The member belonging to the reduced member */
    9733 NewRowInformation* const newRowInfo /**< Stores information about the new row placement */
    9734 )
    9735{
    9736 if( SPQRarcIsValid(newRow->reducedMembers[reducedMember].articulationArc) )
    9737 {
    9738 spqr_arc arc = newRow->reducedMembers[reducedMember].articulationArc;
    9739 //Cut arc is propagated into a cycle with new arc
    9740 assert(newRow->reducedMembers[reducedMember].splitNode == findEffectiveArcHeadNoCompression(dec, arc) ||
    9741 newRow->reducedMembers[reducedMember].splitNode == findEffectiveArcTailNoCompression(dec, arc));
    9742
    9743 SCIP_Bool reversed;
    9744
    9745 if( newRow->isArcCut[arc] )
    9746 {
    9747 reversed = ( newRow->reducedMembers[reducedMember].splitNode == findEffectiveArcHead(dec, arc)) ==
    9748 newRow->reducedMembers[reducedMember].otherIsSource;
    9749 }
    9750 else
    9751 {
    9752 reversed = ( newRow->reducedMembers[reducedMember].splitNode == findEffectiveArcHead(dec, arc)) !=
    9753 newRow->reducedMembers[reducedMember].otherIsSource;
    9754 }
    9755
    9756 SCIP_CALL( rigidTransformArcIntoCycle(dec, member, newRow->reducedMembers[reducedMember].articulationArc,
    9757 reversed, newRowInfo) );
    9758
    9759 return SCIP_OKAY;
    9760 }
    9761 //Single splittable node
    9762 assert(SPQRnodeIsValid(newRow->reducedMembers[reducedMember].splitNode));
    9763
    9764 spqr_node splitNode = newRow->reducedMembers[reducedMember].splitNode;
    9765 if( newRow->reducedMembers[reducedMember].allHaveCommonNode )
    9766 {
    9767 //Create a new node; move all cut arcs end of split node to it and add new arc between new node and split node
    9768 spqr_node newNode = SPQR_INVALID_NODE;
    9769 SCIP_CALL( createNode(dec, &newNode) );
    9770
    9771 cut_arc_id cutArcIdx = newRow->reducedMembers[reducedMember].firstCutArc;
    9772 do
    9773 {
    9774 spqr_arc cutArc = newRow->cutArcs[cutArcIdx].arc;
    9775 spqr_node arcHead = findArcHead(dec, cutArc);
    9776 if( arcHead == splitNode )
    9777 {
    9778 changeArcHead(dec, cutArc, arcHead, newNode);
    9779 }
    9780 else
    9781 {
    9782 changeArcTail(dec, cutArc, findArcTail(dec, cutArc), newNode);
    9783 }
    9784
    9785 cutArcIdx = newRow->cutArcs[cutArcIdx].nextMember;
    9786 }
    9787 while( cutArcIsValid(cutArcIdx) );
    9788
    9789 newRowInfo->member = member;
    9790 if( newRow->reducedMembers[reducedMember].otherIsSource )
    9791 {
    9792 newRowInfo->head = newNode;
    9793 newRowInfo->tail = splitNode;
    9794 }
    9795 else
    9796 {
    9797 newRowInfo->head = splitNode;
    9798 newRowInfo->tail = newNode;
    9799 }
    9800 newRowInfo->representative = findArcSign(dec,
    9801 newRow->cutArcs[newRow->reducedMembers[reducedMember].firstCutArc].arc).representative;
    9802 newRowInfo->reversed = FALSE;
    9803
    9804 return SCIP_OKAY;
    9805 }
    9806 //Articulation point was split (based on coloring)
    9807
    9808 spqr_node newNode = SPQR_INVALID_NODE;
    9809 SCIP_CALL( createNode(dec, &newNode) );
    9810
    9811 spqr_arc firstNodeArc = getFirstNodeArc(dec, splitNode);
    9812 spqr_arc iterArc = firstNodeArc;
    9813
    9814 do
    9815 {
    9816 SCIP_Bool isCut = newRow->isArcCut[iterArc];
    9817 spqr_node otherHead = findArcHead(dec, iterArc);
    9818 spqr_node otherTail = findArcTail(dec, iterArc);
    9819 spqr_node otherEnd = otherHead == splitNode ? otherTail : otherHead;
    9820 SCIP_Bool isMoveColor = newRow->nodeColors[otherEnd] == COLOR_SOURCE;
    9821 spqr_arc nextArc = getNextNodeArc(dec, iterArc, splitNode);//Need to do this before we modify the arc :)
    9822
    9823 SCIP_Bool changeArcEnd = isCut == isMoveColor;
    9824 if( changeArcEnd )
    9825 {
    9826 if( otherHead == splitNode )
    9827 {
    9828 changeArcHead(dec, iterArc, otherHead, newNode);
    9829 }
    9830 else
    9831 {
    9832 changeArcTail(dec, iterArc, otherTail, newNode);
    9833 }
    9834 }
    9835 newRow->nodeColors[otherEnd] = UNCOLORED;//Clean up
    9836
    9837 //Ugly hack to make sure we can iterate neighbourhood whilst changing arc ends.
    9838 spqr_arc previousArc = iterArc;
    9839 iterArc = nextArc;
    9840 if( iterArc == firstNodeArc )
    9841 {
    9842 break;
    9843 }
    9844 if( changeArcEnd && previousArc == firstNodeArc )
    9845 {
    9846 firstNodeArc = iterArc;
    9847 }
    9848 }
    9849 while( TRUE ); /*lint !e506*/
    9850 newRow->reducedMembers[reducedMember].coloredNode = SPQR_INVALID_NODE;
    9851
    9852 newRowInfo->member = member;
    9853 newRowInfo->head = newNode;
    9854 newRowInfo->tail = splitNode;
    9855 newRowInfo->representative = findArcSign(dec,
    9856 newRow->cutArcs[newRow->reducedMembers[reducedMember].firstCutArc].arc).representative;
    9857 newRowInfo->reversed = FALSE;
    9858
    9859 return SCIP_OKAY;
    9860}
    9861
    9862/** Splits a single parallel member into two adjacent ones, where the cut arcs and non-cut arcs get their own member. */
    9863static
    9865 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    9866 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    9867 const reduced_member_id reducedMember, /**< The reduced member to transform */
    9868 const spqr_member member, /**< The member belonging to the reduced member */
    9869 NewRowInformation* const newRowInfo /**< Stores information about the new row placement */
    9870 )
    9871{
    9872 assert(newRow->reducedMembers[reducedMember].numCutArcs > 0);
    9873
    9874 int numCutArcs = newRow->reducedMembers[reducedMember].numCutArcs;
    9875 int numParallelArcs = getNumMemberArcs(dec, member);
    9876
    9877 SCIP_Bool createCutParallel = numCutArcs > 1;
    9878 SCIP_Bool convertOriginalParallel = ( numCutArcs + 1 ) == numParallelArcs;
    9879
    9880 //Do linear search to find non-marked arc
    9881 spqr_arc treeArc = getFirstMemberArc(dec, member);
    9882 do
    9883 {
    9884 if( arcIsTree(dec, treeArc))
    9885 {
    9886 break;
    9887 }
    9888 treeArc = getNextMemberArc(dec, treeArc);
    9889 }
    9890 while( treeArc != getFirstMemberArc(dec, member) );
    9891 assert(arcIsTree(dec, treeArc));
    9892
    9893 SCIP_Bool treeReversed = arcIsReversedNonRigid(dec, treeArc);
    9894
    9895 assert(!( !createCutParallel &&
    9896 convertOriginalParallel ));//This can only happen if the parallel member is actually a loop, which means it is mislabeled
    9897 if( createCutParallel )
    9898 {
    9899 if( convertOriginalParallel )
    9900 {
    9901 spqr_member adjacentMember = SPQR_INVALID_MEMBER;
    9902 spqr_arc adjacentArc = SPQR_INVALID_ARC;
    9903 if( treeArc == markerToParent(dec, member) )
    9904 {
    9905 adjacentMember = findMemberParent(dec, member);
    9906 adjacentArc = markerOfParent(dec, member);
    9907 }
    9908 else if( arcIsChildMarker(dec, treeArc) )
    9909 {
    9910 adjacentMember = findArcChildMember(dec, treeArc);
    9911 adjacentArc = markerToParent(dec, adjacentMember);
    9912 assert(markerOfParent(dec, adjacentMember) == treeArc);
    9913 }
    9914 cut_arc_id firstCut = newRow->reducedMembers[reducedMember].firstCutArc;
    9915 SCIP_Bool firstReversed =
    9916 newRow->cutArcs[firstCut].arcReversed != arcIsReversedNonRigid(dec, newRow->cutArcs[firstCut].arc);
    9917
    9918 if( SPQRmemberIsValid(adjacentMember) && getMemberType(dec, adjacentMember) == SPQR_MEMBERTYPE_SERIES )
    9919 {
    9920 newRowInfo->member = adjacentMember;
    9921 if( arcIsReversedNonRigid(dec, treeArc) == arcIsReversedNonRigid(dec, adjacentArc) )
    9922 {
    9923 newRowInfo->reversed = !firstReversed;
    9924 }
    9925 else
    9926 {
    9927 newRowInfo->reversed = firstReversed;
    9928 }
    9929 return SCIP_OKAY;
    9930 }
    9931 spqr_member cutMember = SPQR_INVALID_MEMBER;
    9932 SCIP_CALL( createMember(dec, SPQR_MEMBERTYPE_PARALLEL, &cutMember) );
    9933
    9934 cut_arc_id cutArcIdx = newRow->reducedMembers[reducedMember].firstCutArc;
    9935 assert(cutArcIsValid(cutArcIdx));
    9936 SCIP_Bool parentCut = FALSE;
    9937
    9938 while( cutArcIsValid(cutArcIdx) )
    9939 {
    9940 spqr_arc cutArc = newRow->cutArcs[cutArcIdx].arc;
    9941 cutArcIdx = newRow->cutArcs[cutArcIdx].nextMember;
    9942 moveArcToNewMember(dec, cutArc, member, cutMember);
    9943 if( cutArc == markerToParent(dec, member) )
    9944 {
    9945 parentCut = TRUE;
    9946 }
    9947 }
    9948 if( parentCut )
    9949 {
    9950 SCIP_CALL( createMarkerPair(dec, cutMember, member, TRUE, FALSE, TRUE) );
    9951 }
    9952 else
    9953 {
    9954 SCIP_CALL( createMarkerPair(dec, member, cutMember, FALSE, TRUE, FALSE) );
    9955 }
    9956 changeLoopToSeries(dec, member);
    9957 newRowInfo->member = member;
    9958 if( treeReversed )
    9959 {
    9960 newRowInfo->reversed = firstReversed == arcIsReversedNonRigid(dec, treeArc);
    9961 }
    9962 else
    9963 {
    9964 newRowInfo->reversed = firstReversed != arcIsReversedNonRigid(dec, treeArc);
    9965 }
    9966 }
    9967 else
    9968 {
    9969 spqr_member cutMember = SPQR_INVALID_MEMBER;
    9970 SCIP_CALL( createMember(dec, SPQR_MEMBERTYPE_PARALLEL, &cutMember) );
    9971
    9972 cut_arc_id cutArcIdx = newRow->reducedMembers[reducedMember].firstCutArc;
    9973 assert(cutArcIsValid(cutArcIdx));
    9974 SCIP_Bool parentCut = FALSE;
    9975
    9976 while( cutArcIsValid(cutArcIdx) )
    9977 {
    9978 spqr_arc cutArc = newRow->cutArcs[cutArcIdx].arc;
    9979 cutArcIdx = newRow->cutArcs[cutArcIdx].nextMember;
    9980 moveArcToNewMember(dec, cutArc, member, cutMember);
    9981 if( cutArc == markerToParent(dec, member) )
    9982 {
    9983 parentCut = TRUE;
    9984 }
    9985 }
    9986 spqr_member newSeries;
    9987 SCIP_CALL( createMember(dec, SPQR_MEMBERTYPE_SERIES, &newSeries) );
    9988 if( parentCut )
    9989 {
    9990 SCIP_CALL( createMarkerPair(dec, newSeries, member, TRUE, FALSE, FALSE) );
    9991 SCIP_CALL( createMarkerPair(dec, cutMember, newSeries, TRUE, FALSE, TRUE) );
    9992 }
    9993 else
    9994 {
    9995 SCIP_CALL( createMarkerPair(dec, member, newSeries, FALSE, FALSE, FALSE) );
    9996 SCIP_CALL( createMarkerPair(dec, newSeries, cutMember, FALSE, TRUE, FALSE) );
    9997 }
    9998 newRowInfo->member = newSeries;
    9999 cut_arc_id firstCut = newRow->reducedMembers[reducedMember].firstCutArc;
    10000 SCIP_Bool firstReversed =
    10001 newRow->cutArcs[firstCut].arcReversed != arcIsReversedNonRigid(dec, newRow->cutArcs[firstCut].arc);
    10002
    10003 newRowInfo->reversed = firstReversed;
    10004 }
    10005
    10006 return SCIP_OKAY;
    10007 }
    10008
    10009 assert(!createCutParallel && !convertOriginalParallel);
    10010 assert(numCutArcs == 1);
    10011#ifndef NDEBUG
    10012 spqr_arc arc = newRow->cutArcs[newRow->reducedMembers[reducedMember].firstCutArc].arc;
    10013 spqr_member adjacentMember = SPQR_INVALID_MEMBER;
    10014 if( arc == markerToParent(dec, member) )
    10015 {
    10016 adjacentMember = findMemberParent(dec, member);
    10017 }
    10018 else if( arcIsChildMarker(dec, arc) )
    10019 {
    10020 adjacentMember = findArcChildMember(dec, arc);
    10021 }
    10022 if( SPQRmemberIsValid(adjacentMember) )
    10023 {
    10024 assert(getMemberType(dec, adjacentMember) != SPQR_MEMBERTYPE_SERIES);
    10025 }
    10026#endif
    10027 spqr_member newSeries;
    10028 SCIP_CALL( createMember(dec, SPQR_MEMBERTYPE_SERIES, &newSeries) );
    10029 cut_arc_id cutArcIdx = newRow->reducedMembers[reducedMember].firstCutArc;
    10030 assert(cutArcIsValid(cutArcIdx));
    10031 SCIP_Bool parentCut = FALSE;
    10032
    10033 while( cutArcIsValid(cutArcIdx) )
    10034 {
    10035 spqr_arc cutArc = newRow->cutArcs[cutArcIdx].arc;
    10036 cutArcIdx = newRow->cutArcs[cutArcIdx].nextMember;
    10037 moveArcToNewMember(dec, cutArc, member, newSeries);
    10038 if( cutArc == markerToParent(dec, member) )
    10039 {
    10040 parentCut = TRUE;
    10041 }
    10042 }
    10043 if( parentCut )
    10044 {
    10045 SCIP_CALL( createMarkerPair(dec, newSeries, member, TRUE, TRUE, FALSE) );
    10046 }
    10047 else
    10048 {
    10049 SCIP_CALL( createMarkerPair(dec, member, newSeries, FALSE, FALSE, TRUE) );
    10050 }
    10051 newRowInfo->member = newSeries;
    10052 cut_arc_id cutArcId = newRow->reducedMembers[reducedMember].firstCutArc;
    10053 newRowInfo->reversed =
    10054 newRow->cutArcs[cutArcId].arcReversed == arcIsReversedNonRigid(dec, newRow->cutArcs[cutArcId].arc);
    10055
    10056 return SCIP_OKAY;
    10057}
    10058
    10059/** Updates a single rigid member to reflect the new row. */
    10060static
    10062 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    10063 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    10064 const reduced_member_id reducedMember, /**< The reduced member to transform */
    10065 const spqr_member member, /**< The member belonging to the reduced member */
    10066 NewRowInformation* info /**< Stores information about the new row placement */
    10067 )
    10068{
    10069 SCIP_CALL( splitParallelRowAddition(dec, newRow, reducedMember, member, info) );
    10070 return SCIP_OKAY;
    10071}
    10072
    10073/** Split a series member into multiple series members for merging. */
    10074static
    10076 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    10077 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    10078 const reduced_member_id reducedMember, /**< The reduced series member */
    10079 const spqr_member member, /**< The member belonging to the reduced member */
    10080 spqr_member* const mergingMember, /**< The member that contains the arcs that are to be merged */
    10081 SCIP_Bool* const isCut, /**< Array that contains whether each arc is Cut */
    10082 spqr_arc* representativeEdge /**< Pointer to the representative arc for the split off arcs */
    10083 )
    10084{
    10085 assert(getNumMemberArcs(dec, member) >= 3);
    10086 *isCut = newRow->reducedMembers[reducedMember].numCutArcs > 0;
    10087
    10088 if( getNumMemberArcs(dec, member) == 3 )
    10089 {
    10090 spqr_arc splitArc = newRow->reducedMembers[reducedMember].splitArc;
    10091 spqr_arc otherArc = SPQR_INVALID_ARC;
    10092 for( children_idx i = newRow->reducedMembers[reducedMember].firstChild;
    10093 i <
    10094 newRow->reducedMembers[reducedMember].firstChild + newRow->reducedMembers[reducedMember].numChildren; ++i )
    10095 {
    10096 reduced_member_id child = newRow->childrenStorage[i];
    10097 if( newRow->reducedMembers[child].type == TYPE_MERGED )
    10098 {
    10099 spqr_arc testArc = markerOfParent(dec, findMember(dec, newRow->reducedMembers[child].member));
    10100 if( testArc != splitArc )
    10101 {
    10102 otherArc = testArc;
    10103 break;
    10104 }
    10105 }
    10106 }
    10107 if( SPQRarcIsInvalid(otherArc) )
    10108 {
    10109#ifndef NDEBUG
    10110 reduced_member_id parent = newRow->reducedMembers[reducedMember].parent;
    10111#endif
    10112 assert(newRow->reducedMembers[parent].type == TYPE_MERGED ||
    10113 newRow->reducedMembers[parent].type == TYPE_PROPAGATED);
    10114 assert(reducedMemberIsValid(parent) && newRow->reducedMembers[parent].type == TYPE_MERGED);
    10115 otherArc = markerToParent(dec, member);
    10116 }
    10117 spqr_arc firstArc = getFirstMemberArc(dec, member);
    10118 spqr_arc arc = firstArc;
    10119 do
    10120 {
    10121 if( arc != splitArc && arc != otherArc )
    10122 {
    10123 *representativeEdge = arc;
    10124 break;
    10125 }
    10126 arc = getNextMemberArc(dec, arc);
    10127 }
    10128 while( arc != firstArc );
    10129 *mergingMember = member;
    10130 return SCIP_OKAY;
    10131 }
    10132 //Split off the relevant part of the series member
    10133 spqr_member mergingSeries = SPQR_INVALID_MEMBER;
    10134 SCIP_CALL( createMember(dec, SPQR_MEMBERTYPE_SERIES, &mergingSeries) );
    10135 //Move all marker arcs which point to another component in the reduced decomposition to the new member
    10136 //This should be exactly 2, as with 3 the result is not network anymore
    10137 //move all mergeable children and parent arcs to the mergingMember
    10138
    10139 SCIP_Bool coTreeToMergingMember = FALSE;
    10140 SCIP_Bool parentToMergingMember = FALSE;
    10141 for( children_idx i = newRow->reducedMembers[reducedMember].firstChild;
    10142 i < newRow->reducedMembers[reducedMember].firstChild + newRow->reducedMembers[reducedMember].numChildren; ++i )
    10143 {
    10144 reduced_member_id child = newRow->childrenStorage[i];
    10145 assert(
    10146 newRow->reducedMembers[child].type == TYPE_MERGED || newRow->reducedMembers[child].type == TYPE_PROPAGATED);
    10147 if( newRow->reducedMembers[child].type == TYPE_MERGED )
    10148 {
    10149 spqr_arc moveArc = markerOfParent(dec, findMember(dec, newRow->reducedMembers[child].member));
    10150 moveArcToNewMember(dec, moveArc, member, mergingSeries);
    10151 if( !arcIsTree(dec, moveArc) )
    10152 {
    10153 coTreeToMergingMember = TRUE;
    10154 }
    10155 }
    10156 }
    10157
    10158 reduced_member_id parent = newRow->reducedMembers[reducedMember].parent;
    10159 assert(reducedMemberIsInvalid(parent) || ( newRow->reducedMembers[parent].type == TYPE_MERGED ||
    10160 newRow->reducedMembers[parent].type == TYPE_PROPAGATED ));
    10161
    10162 if( reducedMemberIsValid(parent) &&
    10163 newRow->reducedMembers[parent].type == TYPE_MERGED )
    10164 {
    10165 spqr_arc moveArc = markerToParent(dec, member);
    10166 moveArcToNewMember(dec, moveArc, member, mergingSeries);
    10167 parentToMergingMember = TRUE;
    10168 if( !arcIsTree(dec, moveArc) )
    10169 {
    10170 coTreeToMergingMember = TRUE;
    10171 }
    10172 }
    10173 spqr_arc ignoreArc = SPQR_INVALID_ARC;
    10174 if( parentToMergingMember )
    10175 {
    10176 SCIP_CALL( createMarkerPairWithReferences(dec, mergingSeries, member, coTreeToMergingMember, TRUE, FALSE,
    10177 representativeEdge, &ignoreArc) );
    10178 }
    10179 else
    10180 {
    10181 SCIP_CALL(
    10182 createMarkerPairWithReferences(dec, member, mergingSeries, !coTreeToMergingMember, FALSE, TRUE, &ignoreArc,
    10183 representativeEdge) );
    10184 }
    10185
    10186 *mergingMember = mergingSeries;
    10187 assert(getNumMemberArcs(dec, mergingSeries) == 3);
    10188 assert(getNumMemberArcs(dec, member) >= 3);
    10189
    10190 return SCIP_OKAY;
    10191}
    10192
    10193/** Split a parallel member into multiple parallel members for merging. */
    10194static
    10196 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    10197 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    10198 reduced_member_id reducedMember, /**< The reduced parallel member */
    10199 spqr_member member, /**< The member belonging to the reduced member */
    10200 spqr_member* const pMergeMember, /**< The member that contains the arcs that are to be merged */
    10201 spqr_arc* const cutRepresentative /**< Pointer to the representative arc for all cut arcs */
    10202 )
    10203{
    10204 //When merging, we cannot have propagated members;
    10205 assert(newRow->reducedMembers[reducedMember].numCutArcs < ( getNumMemberArcs(dec, member) - 1 ));
    10206
    10207 int numMergeableAdjacent =
    10208 newRow->reducedMembers[reducedMember].numChildren - newRow->reducedMembers[reducedMember].numPropagatedChildren;
    10209 if( reducedMemberIsValid(newRow->reducedMembers[reducedMember].parent) &&
    10210 newRow->reducedMembers[newRow->reducedMembers[reducedMember].parent].type == TYPE_MERGED )
    10211 {
    10212 numMergeableAdjacent++;
    10213 }
    10214
    10215 int numCutArcs = newRow->reducedMembers[reducedMember].numCutArcs;
    10216 //All arcs which are not in the mergeable decomposition or cut
    10217 int numBaseSplitAwayArcs = getNumMemberArcs(dec, member) - numMergeableAdjacent - numCutArcs;
    10218
    10219 SCIP_Bool createCutParallel = numCutArcs > 1;
    10220 SCIP_Bool keepOriginalParallel = numBaseSplitAwayArcs <= 1;
    10221
    10222 spqr_member cutMember = SPQR_INVALID_MEMBER;
    10223 //The below cases can probably be aggregated in some way, but for now we first focus on the correct logic
    10224 if( createCutParallel && keepOriginalParallel )
    10225 {
    10226 SCIP_Bool parentCut = FALSE;
    10227 SCIP_CALL( createMember(dec, SPQR_MEMBERTYPE_PARALLEL, &cutMember) );
    10228
    10229 cut_arc_id cutArcIdx = newRow->reducedMembers[reducedMember].firstCutArc;
    10230 assert(cutArcIsValid(cutArcIdx));
    10231
    10232 while( cutArcIsValid(cutArcIdx) )
    10233 {
    10234 spqr_arc cutArc = newRow->cutArcs[cutArcIdx].arc;
    10235 cutArcIdx = newRow->cutArcs[cutArcIdx].nextMember;
    10236 moveArcToNewMember(dec, cutArc, member, cutMember);
    10237 if( cutArc == markerToParent(dec, member) )
    10238 {
    10239 parentCut = TRUE;
    10240 }
    10241 }
    10242 spqr_arc ignoreArc = SPQR_INVALID_ARC;
    10243 if( parentCut )
    10244 {
    10245 SCIP_CALL(
    10246 createMarkerPairWithReferences(dec, cutMember, member, TRUE, FALSE, FALSE, &ignoreArc, cutRepresentative) );
    10247 }
    10248 else
    10249 {
    10250 SCIP_CALL(
    10251 createMarkerPairWithReferences(dec, member, cutMember, FALSE, FALSE, FALSE, cutRepresentative, &ignoreArc) );
    10252 }
    10253
    10254 *pMergeMember = member;
    10255 }
    10256 else if( createCutParallel )
    10257 {
    10258 assert(!keepOriginalParallel);
    10259
    10260 SCIP_Bool parentCut = FALSE;
    10261 SCIP_CALL( createMember(dec, SPQR_MEMBERTYPE_PARALLEL, &cutMember) );
    10262
    10263 cut_arc_id cutArcIdx = newRow->reducedMembers[reducedMember].firstCutArc;
    10264 assert(cutArcIsValid(cutArcIdx));
    10265
    10266 while( cutArcIsValid(cutArcIdx) )
    10267 {
    10268 spqr_arc cutArc = newRow->cutArcs[cutArcIdx].arc;
    10269 cutArcIdx = newRow->cutArcs[cutArcIdx].nextMember;
    10270 moveArcToNewMember(dec, cutArc, member, cutMember);
    10271 if( cutArc == markerToParent(dec, member) )
    10272 {
    10273 parentCut = TRUE;
    10274 }
    10275 }
    10276 spqr_arc ignoreArc = SPQR_INVALID_ARC;
    10277 if( parentCut )
    10278 {
    10279 SCIP_CALL(
    10280 createMarkerPairWithReferences(dec, cutMember, member, TRUE, FALSE, FALSE, &ignoreArc, cutRepresentative) );
    10281 }
    10282 else
    10283 {
    10284 SCIP_CALL(
    10285 createMarkerPairWithReferences(dec, member, cutMember, FALSE, FALSE, FALSE, cutRepresentative, &ignoreArc) );
    10286 }
    10287
    10288 spqr_arc noCutRepresentative = SPQR_INVALID_ARC;
    10289 spqr_member mergingMember = member;
    10290 SCIP_Bool parentToMergingMember = FALSE;
    10291 SCIP_Bool treeToMergingMember = FALSE;
    10292 SCIP_CALL( createMember(dec, SPQR_MEMBERTYPE_PARALLEL, &mergingMember) );
    10293 //move all mergeable children and parent arcs to the mergingMember
    10294 for( children_idx i = newRow->reducedMembers[reducedMember].firstChild;
    10295 i < newRow->reducedMembers[reducedMember].firstChild +
    10296 newRow->reducedMembers[reducedMember].numChildren;
    10297 ++i )
    10298 {
    10299 reduced_member_id child = newRow->childrenStorage[i];
    10300 assert(
    10301 newRow->reducedMembers[child].type == TYPE_MERGED || newRow->reducedMembers[child].type == TYPE_PROPAGATED);
    10302 if( newRow->reducedMembers[child].type == TYPE_MERGED )
    10303 {
    10304 spqr_arc moveArc = markerOfParent(dec, findMember(dec, newRow->reducedMembers[child].member));
    10305 moveArcToNewMember(dec, moveArc, member, mergingMember);
    10306 if( arcIsTree(dec, moveArc) )
    10307 {
    10308 treeToMergingMember = TRUE;
    10309 }
    10310 }
    10311 }
    10312 reduced_member_id parent = newRow->reducedMembers[reducedMember].parent;
    10313 if( reducedMemberIsValid(parent) &&
    10314 newRow->reducedMembers[parent].type == TYPE_MERGED )
    10315 {
    10316 spqr_arc moveArc = markerToParent(dec, member);
    10317 moveArcToNewMember(dec, moveArc, member, mergingMember);
    10318 parentToMergingMember = TRUE;
    10319 if( arcIsTree(dec, moveArc) )
    10320 {
    10321 treeToMergingMember = TRUE;
    10322 }
    10323 }
    10324 //If there is only one cut arc, we also move it.
    10325 if( SPQRarcIsValid(*cutRepresentative) )
    10326 {
    10327 if( *cutRepresentative == markerToParent(dec, member) )
    10328 {
    10329 parentToMergingMember = TRUE;
    10330 }
    10331 moveArcToNewMember(dec, *cutRepresentative, member, mergingMember);
    10332 }
    10333 spqr_arc ignoreArgument = SPQR_INVALID_ARC;
    10334 if( parentToMergingMember || parentCut )
    10335 {
    10336 SCIP_CALL( createMarkerPairWithReferences(dec, mergingMember, member, !treeToMergingMember, FALSE, FALSE,
    10337 &ignoreArgument, &noCutRepresentative) );
    10338 }
    10339 else
    10340 {
    10341 SCIP_CALL( createMarkerPairWithReferences(dec, member, mergingMember, treeToMergingMember, FALSE, FALSE,
    10342 &noCutRepresentative, &ignoreArgument) );
    10343 }
    10344 *pMergeMember = mergingMember;
    10345 }
    10346 else if( keepOriginalParallel )
    10347 {
    10348 assert(!createCutParallel);
    10349 if( cutArcIsValid(newRow->reducedMembers[reducedMember].firstCutArc) )
    10350 {
    10351 *cutRepresentative = newRow->cutArcs[newRow->reducedMembers[reducedMember].firstCutArc].arc;
    10352 }
    10353 *pMergeMember = member;
    10354 }
    10355 else
    10356 {
    10357 assert(!keepOriginalParallel && !createCutParallel);
    10358
    10359 if( cutArcIsValid(newRow->reducedMembers[reducedMember].firstCutArc) )
    10360 {
    10361 *cutRepresentative = newRow->cutArcs[newRow->reducedMembers[reducedMember].firstCutArc].arc;
    10362 }
    10363
    10364 spqr_arc noCutRepresentative = SPQR_INVALID_ARC;
    10365 spqr_member mergingMember = member;
    10366 SCIP_Bool parentToMergingMember = FALSE;
    10367 SCIP_Bool treeToMergingMember = FALSE;
    10368 SCIP_CALL( createMember(dec, SPQR_MEMBERTYPE_PARALLEL, &mergingMember) );
    10369 //move all mergeable children and parent arcs to the mergingMember
    10370 for( children_idx i = newRow->reducedMembers[reducedMember].firstChild;
    10371 i < newRow->reducedMembers[reducedMember].firstChild +
    10372 newRow->reducedMembers[reducedMember].numChildren;
    10373 ++i )
    10374 {
    10375 reduced_member_id child = newRow->childrenStorage[i];
    10376 assert(
    10377 newRow->reducedMembers[child].type == TYPE_MERGED || newRow->reducedMembers[child].type == TYPE_PROPAGATED);
    10378 if( newRow->reducedMembers[child].type == TYPE_MERGED )
    10379 {
    10380 spqr_arc moveArc = markerOfParent(dec, findMember(dec, newRow->reducedMembers[child].member));
    10381 moveArcToNewMember(dec, moveArc, member, mergingMember);
    10382 if( arcIsTree(dec, moveArc) )
    10383 {
    10384 treeToMergingMember = TRUE;
    10385 }
    10386 }
    10387 }
    10388 reduced_member_id parent = newRow->reducedMembers[reducedMember].parent;
    10389 if( reducedMemberIsValid(parent) &&
    10390 newRow->reducedMembers[parent].type == TYPE_MERGED )
    10391 {
    10392 spqr_arc moveArc = markerToParent(dec, member);
    10393 moveArcToNewMember(dec, moveArc, member, mergingMember);
    10394 parentToMergingMember = TRUE;
    10395 if( arcIsTree(dec, moveArc) )
    10396 {
    10397 treeToMergingMember = TRUE;
    10398 }
    10399 }
    10400 //If there is only one cut arc, we also move it.
    10401 if( SPQRarcIsValid(*cutRepresentative) )
    10402 {
    10403 if( *cutRepresentative == markerToParent(dec, member) )
    10404 {
    10405 parentToMergingMember = TRUE;
    10406 }
    10407 moveArcToNewMember(dec, *cutRepresentative, member, mergingMember);
    10408 }
    10409 spqr_arc ignoreArgument = SPQR_INVALID_ARC;
    10410 if( parentToMergingMember )
    10411 {
    10412 SCIP_CALL( createMarkerPairWithReferences(dec, mergingMember, member, !treeToMergingMember, FALSE, FALSE,
    10413 &ignoreArgument, &noCutRepresentative) );
    10414 }
    10415 else
    10416 {
    10417 SCIP_CALL( createMarkerPairWithReferences(dec, member, mergingMember, treeToMergingMember, FALSE, FALSE,
    10418 &noCutRepresentative, &ignoreArgument) );
    10419 }
    10420 *pMergeMember = mergingMember;
    10421 }
    10422
    10423 return SCIP_OKAY;
    10424}
    10425
    10426/** Update the first leaf to reflect the addition of the new row */
    10427static
    10429 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    10430 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    10431 reduced_member_id leaf, /**< The leaf to split the first node for */
    10432 NewRowInformation* const newRowInfo /**< Stores how to add the new row */
    10433 )
    10434{
    10435 assert(cutArcIsValid(newRow->reducedMembers[leaf].firstCutArc));
    10436 assert(newRow->reducedMembers[leaf].numCutArcs > 0);
    10437 spqr_member member = newRow->reducedMembers[leaf].member;
    10438 if( getMemberType(dec, member) == SPQR_MEMBERTYPE_PARALLEL )
    10439 {
    10440 spqr_member mergeMember = SPQR_INVALID_MEMBER;
    10441 spqr_arc cutRepresentative = SPQR_INVALID_ARC;
    10442 SCIP_CALL( splitParallelMerging(dec, newRow, leaf, member, &mergeMember, &cutRepresentative) );
    10443 newRow->reducedMembers[leaf].member = mergeMember;
    10444
    10445 spqr_node firstNode = SPQR_INVALID_NODE;
    10446 spqr_node secondNode = SPQR_INVALID_NODE;
    10447 spqr_node thirdNode = SPQR_INVALID_NODE;
    10448 SCIP_CALL( createNode(dec, &firstNode) );
    10449 SCIP_CALL( createNode(dec, &secondNode) );
    10450 SCIP_CALL( createNode(dec, &thirdNode) );
    10451
    10452 spqr_arc splitArc = newRow->reducedMembers[leaf].splitArc;
    10453 assert(findArcMemberNoCompression(dec, splitArc) == mergeMember);
    10454 SCIP_Bool splitArcReversed = arcIsReversedNonRigid(dec, splitArc);
    10455 SCIP_Bool splitHead = newRow->reducedMembers[leaf].splitHead;
    10456 spqr_node splitArcHead = splitArcReversed ? secondNode : firstNode;
    10457 spqr_node splitArcTail = splitArcReversed ? firstNode : secondNode;
    10458 spqr_node splitNode = splitHead ? splitArcHead : splitArcTail;
    10459 spqr_node otherNode = splitHead ? splitArcTail : splitArcHead;
    10460
    10461 spqr_arc first_arc = getFirstMemberArc(dec, mergeMember);
    10462 spqr_arc arc = first_arc;
    10463
    10464 do
    10465 {
    10466 if( arc != cutRepresentative )
    10467 {
    10468 if( arcIsReversedNonRigid(dec, arc) )
    10469 {
    10470 setArcHeadAndTail(dec, arc, secondNode, firstNode);
    10471 }
    10472 else
    10473 {
    10474 setArcHeadAndTail(dec, arc, firstNode, secondNode);
    10475 }
    10476 }
    10477 else
    10478 {
    10479 if( (arcIsReversedNonRigid(dec, arc) == splitArcReversed) == splitHead )
    10480 {
    10481 setArcHeadAndTail(dec, arc, thirdNode, otherNode);
    10482 }
    10483 else
    10484 {
    10485 setArcHeadAndTail(dec, arc, otherNode, thirdNode);
    10486 }
    10487 }
    10488 arcSetReversed(dec, arc, FALSE);
    10489 if( arc == splitArc )
    10490 {
    10492 }
    10493 else
    10494 {
    10495 arcSetRepresentative(dec, arc, splitArc);
    10496 }
    10497 arc = getNextMemberArc(dec, arc);
    10498 }
    10499 while( arc != first_arc );
    10500
    10501 updateMemberType(dec, mergeMember, SPQR_MEMBERTYPE_RIGID);
    10502 newRowInfo->member = mergeMember;
    10503 if( newRow->reducedMembers[leaf].otherIsSource )
    10504 {
    10505 newRowInfo->head = thirdNode;
    10506 newRowInfo->tail = splitNode;
    10507 }
    10508 else
    10509 {
    10510 newRowInfo->head = splitNode;
    10511 newRowInfo->tail = thirdNode;
    10512 }
    10513
    10514 newRowInfo->reversed = FALSE;
    10515 newRowInfo->representative = splitArc;
    10516
    10517 return SCIP_OKAY;
    10518 }
    10519 assert(getMemberType(dec, member) == SPQR_MEMBERTYPE_RIGID);
    10520
    10521 spqr_node newNode = SPQR_INVALID_NODE;//Sink node
    10522 SCIP_CALL( createNode(dec, &newNode) );
    10523
    10524 spqr_node splitNode = newRow->reducedMembers[leaf].splitNode;
    10525
    10526 spqr_arc firstNodeArc = getFirstNodeArc(dec, splitNode);
    10527 spqr_arc iterArc = firstNodeArc;
    10528 do
    10529 {
    10530 spqr_node otherHead = findArcHead(dec, iterArc);
    10531 spqr_node otherTail = findArcTail(dec, iterArc);
    10532 spqr_node otherEnd = otherHead == splitNode ? otherTail : otherHead;
    10533 spqr_arc nextArc = getNextNodeArc(dec, iterArc, splitNode);//Need to do this before we modify the arc
    10534
    10535 SCIP_Bool isCut = newRow->isArcCut[iterArc];
    10536 SCIP_Bool isMoveColor = newRow->nodeColors[otherEnd] == COLOR_SOURCE;
    10537 SCIP_Bool changeArcEnd = isCut == isMoveColor;
    10538 if( changeArcEnd )
    10539 {
    10540 if( otherHead == splitNode )
    10541 {
    10542 changeArcHead(dec, iterArc, otherHead, newNode);
    10543 }
    10544 else
    10545 {
    10546 changeArcTail(dec, iterArc, otherTail, newNode);
    10547 }
    10548 }
    10549 //Ugly hack to make sure we can iterate neighbourhood whilst changing arc ends.
    10550 newRow->nodeColors[otherEnd] = UNCOLORED;
    10551 spqr_arc previousArc = iterArc;
    10552 iterArc = nextArc;
    10553 if( iterArc == firstNodeArc )
    10554 {
    10555 break;
    10556 }
    10557 if( changeArcEnd && previousArc == firstNodeArc )
    10558 {
    10559 firstNodeArc = iterArc;
    10560 }
    10561 }
    10562 while( TRUE ); /*lint !e506*/
    10563 newRowInfo->head = newNode;
    10564 newRowInfo->tail = splitNode;
    10565 newRowInfo->member = member;
    10566 newRowInfo->reversed = FALSE;
    10567 newRowInfo->representative = findArcSign(dec, iterArc).representative;
    10568
    10569 return SCIP_OKAY;
    10570}
    10571
    10572/** Merge an (updated) member into its parent.
    10573 *
    10574 * This function is mainly there to prevent duplication.
    10575 */
    10576static
    10578 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    10579 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    10580 spqr_member member, /**< The member to merge */
    10581 spqr_member parent, /**< The member's parent */
    10582 spqr_arc parentToChild, /**< The marker pointing from the parent to child */
    10583 spqr_arc childToParent, /**< The marker pointing from the child to the parent */
    10584 SCIP_Bool headToHead, /**< Should the marker heads be identified with one another? */
    10585 spqr_node parentNode, /**< A node in the parent that is not adjacent to the marker */
    10586 spqr_node childNode, /**< A node in the child that is not adjacent to the marker */
    10587 spqr_member* mergedMember, /**< Pointer to the member that contains both members after merging */
    10588 spqr_node* arcNodeOne, /**< The first identified node of the two marker arcs */
    10589 spqr_node* arcNodeTwo, /**< The second identified node of the two marker arcs */
    10590 spqr_node* thirdNode /**< The node that parentNode and childNode are identified into */
    10591 )
    10592{
    10593 assert(dec);
    10594 assert(SPQRmemberIsValid(member));
    10595 assert(memberIsRepresentative(dec, member));
    10596 assert(SPQRmemberIsValid(parent));
    10597 assert(memberIsRepresentative(dec, parent));
    10598 assert(findMemberParentNoCompression(dec, member) == parent);
    10599 assert(markerOfParent(dec, member) == parentToChild);
    10600 assert(markerToParent(dec, member) == childToParent);
    10601
    10602 removeArcFromMemberArcList(dec, parentToChild, parent);
    10603 removeArcFromMemberArcList(dec, childToParent, member);
    10604
    10605 int parentTail = findEffectiveArcTail(dec, parentToChild);
    10606 int parentHead = findEffectiveArcHead(dec, parentToChild);
    10607 int childTail = findEffectiveArcTail(dec, childToParent);
    10608 int childHead = findEffectiveArcHead(dec, childToParent);
    10609 spqr_node parentArcNodes[2] = { parentTail, parentHead };
    10610 spqr_node childArcNodes[2] = { childTail, childHead };
    10611
    10612 clearArcHeadAndTail(dec, parentToChild);
    10613 clearArcHeadAndTail(dec, childToParent);
    10614
    10615 spqr_node first = childArcNodes[headToHead ? 0 : 1];
    10616 spqr_node second = childArcNodes[headToHead ? 1 : 0];
    10617 {
    10618 spqr_node newNode = mergeNodes(dec, parentArcNodes[0], first);
    10619 spqr_node toRemoveFrom = newNode == first ? parentArcNodes[0] : first;
    10620 mergeNodeArcList(dec, newNode, toRemoveFrom);
    10621 *arcNodeOne = newNode;
    10622 newRow->nodeColors[toRemoveFrom] = UNCOLORED;
    10623 }
    10624 {
    10625 spqr_node newNode = mergeNodes(dec, parentArcNodes[1], second);
    10626 spqr_node toRemoveFrom = newNode == second ? parentArcNodes[1] : second;
    10627 mergeNodeArcList(dec, newNode, toRemoveFrom);
    10628 *arcNodeTwo = newNode;
    10629 newRow->nodeColors[toRemoveFrom] = UNCOLORED;
    10630 }
    10631 {
    10632 spqr_node newNode = mergeNodes(dec, parentNode, childNode);
    10633 spqr_node toRemoveFrom = newNode == childNode ? parentNode : childNode;
    10634 mergeNodeArcList(dec, newNode, toRemoveFrom);
    10635 *thirdNode = newNode;
    10636 newRow->nodeColors[toRemoveFrom] = UNCOLORED;
    10637 }
    10638
    10639 spqr_member newMember = mergeMembers(dec, member, parent);
    10640 spqr_member toRemoveFrom = newMember == member ? parent : member;
    10641 mergeMemberArcList(dec, newMember, toRemoveFrom);
    10642 if( toRemoveFrom == parent )
    10643 {
    10644 updateMemberParentInformation(dec, newMember, toRemoveFrom);
    10645 }
    10646 updateMemberType(dec, newMember, SPQR_MEMBERTYPE_RIGID);
    10647 *mergedMember = newMember;
    10648
    10649 return SCIP_OKAY;
    10650}
    10651
    10652/** Update a series member to reflect the addition of the new row, and merge it into the previous members that were
    10653 * updated.
    10654 */
    10655static
    10657 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    10658 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    10659 reduced_member_id smallMember, /**< The reduced series member */
    10660 SCIP_Bool largeIsParent, /**< Whether the large member containing previously updated members is
    10661 * the parent of this member */
    10662 NewRowInformation* const newRowInfo, /**< Stores the information on how to add the new row */
    10663 spqr_member member /**< The member belonging to the reduced series member */
    10664 )
    10665{
    10666 SCIP_Bool isCut = FALSE;
    10667 spqr_member mergingMember = SPQR_INVALID_MEMBER;
    10668 spqr_arc nonVirtualArc = SPQR_INVALID_ARC;
    10669
    10670 SCIP_CALL( splitSeriesMergingRowAddition(dec, newRow, smallMember, member, &mergingMember, &isCut, &nonVirtualArc) );
    10671 assert(getNumMemberArcs(dec, mergingMember) == 3);
    10672
    10673 //create the split series. There's two possible configurations, based on whether it contains a cut edge or not
    10678 SCIP_CALL( createNode(dec, &a) );
    10679 SCIP_CALL( createNode(dec, &b) );
    10680 SCIP_CALL( createNode(dec, &c) );
    10681 SCIP_CALL( createNode(dec, &d) );
    10682
    10683 spqr_arc splitArc = newRow->reducedMembers[smallMember].splitArc;
    10684
    10685 {
    10686 SCIP_Bool splitHead = newRow->reducedMembers[smallMember].splitHead;
    10687 spqr_arc firstArc = getFirstMemberArc(dec, mergingMember);
    10688 spqr_arc arc = firstArc;
    10689 SCIP_Bool splitReversed = arcIsReversedNonRigid(dec, splitArc);
    10690 do
    10691 {
    10692 if( arc == splitArc )
    10693 {
    10694 if( splitHead )
    10695 {
    10696 setArcHeadAndTail(dec, splitArc, b, a);
    10697 }
    10698 else
    10699 {
    10700 setArcHeadAndTail(dec, splitArc, a, b);
    10701 }
    10702 }
    10703 else if( arc == nonVirtualArc )
    10704 {
    10705 if( (arcIsReversedNonRigid(dec, arc) == splitReversed) == splitHead )
    10706 {
    10707 setArcHeadAndTail(dec, arc, a, d);
    10708 }
    10709 else
    10710 {
    10711 setArcHeadAndTail(dec, arc, d, a);
    10712 }
    10713 }
    10714 else
    10715 {
    10716 spqr_node otherNode = cutArcIsValid(newRow->reducedMembers[smallMember].firstCutArc) ? c : b;
    10717 if( (arcIsReversedNonRigid(dec, arc) == splitReversed) == splitHead )
    10718 {
    10719 setArcHeadAndTail(dec, arc, d, otherNode);
    10720 }
    10721 else
    10722 {
    10723 setArcHeadAndTail(dec, arc, otherNode, d);
    10724 }
    10725 }
    10726 arcSetReversed(dec, arc, FALSE);
    10727 arcSetRepresentative(dec, arc, splitArc);
    10728 arc = getNextMemberArc(dec, arc);
    10729 }
    10730 while( arc != firstArc );
    10731 arcSetRepresentative(dec, splitArc, SPQR_INVALID_ARC);
    10732 }
    10733
    10734 spqr_member otherMember = newRowInfo->member;
    10735 spqr_arc otherMarker = largeIsParent ? markerOfParent(dec, mergingMember) : markerToParent(dec, otherMember);
    10736
    10737 assert(nodeIsRepresentative(dec, newRowInfo->tail));
    10738 assert(nodeIsRepresentative(dec, newRowInfo->head));
    10739 spqr_node splitNode = newRow->reducedMembers[smallMember].splitHead ? findEffectiveArcHead(dec, otherMarker)
    10740 : findEffectiveArcTail(dec, otherMarker);
    10741
    10742 spqr_node otherNode = splitNode == newRowInfo->head ? newRowInfo->tail : newRowInfo->head;
    10743 assert(splitNode == newRowInfo->head || splitNode == newRowInfo->tail);
    10744 newRowInfo->representative = mergeArcSigns(dec, newRowInfo->representative, splitArc, FALSE);
    10745
    10746 spqr_member mergedMember = SPQR_INVALID_MEMBER;
    10747 spqr_node arcNodeOne;
    10748 spqr_node arcNodeTwo;
    10749 spqr_node thirdNode;
    10750 if( largeIsParent )
    10751 {
    10752 SCIP_CALL( mergeSplitMemberIntoParent(dec, newRow, mergingMember, otherMember, otherMarker, splitArc, TRUE,
    10753 otherNode, c, &mergedMember,
    10754 &arcNodeOne,
    10755 &arcNodeTwo,
    10756 &thirdNode) );
    10757 }
    10758 else
    10759 {
    10760 SCIP_CALL( mergeSplitMemberIntoParent(dec, newRow, otherMember, mergingMember, splitArc, otherMarker, TRUE,
    10761 c, otherNode, &mergedMember,
    10762 &arcNodeOne,
    10763 &arcNodeTwo,
    10764 &thirdNode) );
    10765 }
    10766 newRow->reducedMembers[smallMember].member = mergedMember;
    10767
    10768 newRowInfo->member = mergedMember;
    10769 SCIP_Bool splitIsReferenceHead = newRow->reducedMembers[smallMember].splitHead;
    10770 SCIP_Bool splitIsNewRowHead = splitNode == newRowInfo->head;
    10771 if( !splitIsReferenceHead && !splitIsNewRowHead )
    10772 {
    10773 newRowInfo->head = thirdNode;
    10774 newRowInfo->tail = arcNodeOne;
    10775 }
    10776 else if( !splitIsReferenceHead && splitIsNewRowHead )
    10777 {
    10778 newRowInfo->head = arcNodeOne;
    10779 newRowInfo->tail = thirdNode;
    10780 }
    10781 else if( splitIsReferenceHead && !splitIsNewRowHead )
    10782 {
    10783 newRowInfo->head = thirdNode;
    10784 newRowInfo->tail = arcNodeTwo;
    10785 }
    10786 else if( splitIsReferenceHead && splitIsNewRowHead )
    10787 {
    10788 newRowInfo->head = arcNodeTwo;
    10789 newRowInfo->tail = thirdNode;
    10790 }
    10791
    10792 return SCIP_OKAY;
    10793}
    10794
    10795/** Update a parallel member to reflect the addition of the new row, and merge it into the previous members that were
    10796 * updated.
    10797 */
    10798static
    10800 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    10801 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    10802 reduced_member_id smallMember, /**< The reduced parallel member */
    10803 SCIP_Bool largeIsParent, /**< Whether the large member containing previously updated members is
    10804 * the parent of this member */
    10805 NewRowInformation* const newRowInfo, /**< Stores the information on how to add the new row */
    10806 spqr_member member /**< The member belonging to the reduced parallel member */
    10807 )
    10808{
    10809 spqr_member mergeMember = SPQR_INVALID_MEMBER;
    10810 spqr_arc cutRepresentative = SPQR_INVALID_ARC;
    10811 SCIP_CALL( splitParallelMerging(dec, newRow, smallMember, member, &mergeMember, &cutRepresentative) );
    10812 newRow->reducedMembers[smallMember].member = mergeMember;
    10813
    10814 spqr_node firstNode = SPQR_INVALID_NODE;
    10815 spqr_node secondNode = SPQR_INVALID_NODE;
    10816 spqr_node thirdNode = SPQR_INVALID_NODE;
    10817 SCIP_CALL( createNode(dec, &firstNode) );
    10818 SCIP_CALL( createNode(dec, &secondNode) );
    10819 SCIP_CALL( createNode(dec, &thirdNode) );
    10820
    10821 spqr_arc splitArc = newRow->reducedMembers[smallMember].splitArc;
    10822 assert(findArcMemberNoCompression(dec, splitArc) == mergeMember);
    10823 SCIP_Bool splitArcReversed = arcIsReversedNonRigid(dec, splitArc);
    10824 SCIP_Bool splitHead = newRow->reducedMembers[smallMember].splitHead;
    10825
    10826 spqr_node splitArcHead = splitArcReversed ? secondNode : firstNode;
    10827 spqr_node splitArcTail = splitArcReversed ? firstNode : secondNode;
    10828 spqr_node otherNode = splitHead ? splitArcTail : splitArcHead;
    10829
    10830 spqr_arc first_arc = getFirstMemberArc(dec, mergeMember);
    10831 spqr_arc arc = first_arc;
    10832
    10833 do
    10834 {
    10835 if( arc != cutRepresentative )
    10836 {
    10837 if( arcIsReversedNonRigid(dec, arc) )
    10838 {
    10839 setArcHeadAndTail(dec, arc, secondNode, firstNode);
    10840 }
    10841 else
    10842 {
    10843 setArcHeadAndTail(dec, arc, firstNode, secondNode);
    10844 }
    10845 }
    10846 else
    10847 {
    10848 if( (arcIsReversedNonRigid(dec, arc) == splitArcReversed) == splitHead )
    10849 {
    10850 setArcHeadAndTail(dec, arc, thirdNode, otherNode);
    10851 }
    10852 else
    10853 {
    10854 setArcHeadAndTail(dec, arc, otherNode, thirdNode);
    10855 }
    10856 }
    10857 arcSetReversed(dec, arc, FALSE);
    10858 arcSetRepresentative(dec, arc, splitArc);
    10859 arc = getNextMemberArc(dec, arc);
    10860 }
    10861 while( arc != first_arc );
    10862 arcSetRepresentative(dec, splitArc, SPQR_INVALID_ARC);
    10863
    10864 spqr_member otherMember = newRowInfo->member;
    10865 spqr_arc otherMarker = largeIsParent ? markerOfParent(dec, mergeMember) : markerToParent(dec, otherMember);
    10866
    10867 assert(nodeIsRepresentative(dec, newRowInfo->tail));
    10868 assert(nodeIsRepresentative(dec, newRowInfo->head));
    10869 spqr_node largeSplitNode = newRow->reducedMembers[smallMember].splitHead ? findEffectiveArcHead(dec, otherMarker)
    10870 : findEffectiveArcTail(dec, otherMarker);
    10871
    10872 spqr_node largeOtherNode =
    10873 largeSplitNode == newRowInfo->head ? newRowInfo->tail : newRowInfo->head;
    10874 assert(largeSplitNode == newRowInfo->head || largeSplitNode == newRowInfo->tail);
    10875
    10876 newRowInfo->representative = mergeArcSigns(dec, newRowInfo->representative, splitArc, FALSE);
    10877
    10878 spqr_member mergedMember = SPQR_INVALID_MEMBER;
    10879 spqr_node arcNodeOne;
    10880 spqr_node arcNodeTwo;
    10881 spqr_node mergeNodeThree;
    10882 if( largeIsParent )
    10883 {
    10884 SCIP_CALL( mergeSplitMemberIntoParent(dec, newRow, mergeMember, otherMember, otherMarker, splitArc, TRUE,
    10885 largeOtherNode, thirdNode, &mergedMember,
    10886 &arcNodeOne,
    10887 &arcNodeTwo,
    10888 &mergeNodeThree) );
    10889 }
    10890 else
    10891 {
    10892 SCIP_CALL( mergeSplitMemberIntoParent(dec, newRow, otherMember, mergeMember, splitArc, otherMarker, TRUE,
    10893 thirdNode, largeOtherNode, &mergedMember,
    10894 &arcNodeOne,
    10895 &arcNodeTwo,
    10896 &mergeNodeThree) );
    10897 }
    10898
    10899 newRowInfo->member = mergedMember;
    10900
    10901 SCIP_Bool splitIsReferenceHead = newRow->reducedMembers[smallMember].splitHead;
    10902 SCIP_Bool splitIsNewRowHead = largeSplitNode == newRowInfo->head;
    10903 if( !splitIsReferenceHead && !splitIsNewRowHead )
    10904 {
    10905 newRowInfo->head = mergeNodeThree;
    10906 newRowInfo->tail = arcNodeOne;
    10907 }
    10908 else if( !splitIsReferenceHead && splitIsNewRowHead )
    10909 {
    10910 newRowInfo->head = arcNodeOne;
    10911 newRowInfo->tail = mergeNodeThree;
    10912 }
    10913 else if( splitIsReferenceHead && !splitIsNewRowHead )
    10914 {
    10915 newRowInfo->head = mergeNodeThree;
    10916 newRowInfo->tail = arcNodeTwo;
    10917 }
    10918 else if( splitIsReferenceHead && splitIsNewRowHead )
    10919 {
    10920 newRowInfo->head = arcNodeTwo;
    10921 newRowInfo->tail = mergeNodeThree;
    10922 }
    10923
    10924 return SCIP_OKAY;
    10925}
    10926
    10927/** Update a rigid member to reflect the addition of the new row, and merge it into the previous members that were
    10928 * updated.
    10929 */
    10930static
    10932 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    10933 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    10934 reduced_member_id smallMember, /**< The reduced rigid member */
    10935 SCIP_Bool largeIsParent, /**< Whether the large member containing previously updated members is
    10936 * the parent of this member */
    10937 NewRowInformation* const newRowInfo, /**< Stores the information on how to add the new row */
    10938 spqr_member member /**< The member belonging to the reduced rigid member */
    10939 )
    10940{
    10941 spqr_node newNode = SPQR_INVALID_NODE;//Sink node
    10942 SCIP_CALL( createNode(dec, &newNode) );
    10943
    10944 spqr_member smallMemberMember = member;
    10945 spqr_member largeMemberMember = newRowInfo->member;
    10946
    10947 spqr_arc smallMarker = largeIsParent ? markerToParent(dec, smallMemberMember) : markerOfParent(dec,
    10948 largeMemberMember);
    10949 spqr_arc largeMarker = largeIsParent ? markerOfParent(dec, smallMemberMember) : markerToParent(dec,
    10950 largeMemberMember);
    10951
    10952 spqr_node splitNode = newRow->reducedMembers[smallMember].splitNode;
    10953 spqr_node smallOtherNode = newNode;
    10954
    10955 if( newRow->reducedMembers[smallMember].numCutArcs != 0 )
    10956 {
    10957 spqr_arc firstNodeArc = getFirstNodeArc(dec, splitNode);
    10958 spqr_arc iterArc = firstNodeArc;
    10959 do
    10960 {
    10961 spqr_node otherHead = findArcHead(dec, iterArc);
    10962 spqr_node otherTail = findArcTail(dec, iterArc);
    10963 spqr_node otherEnd = otherHead == splitNode ? otherTail : otherHead;
    10964 spqr_arc nextArc = getNextNodeArc(dec, iterArc, splitNode);//Need to do this before we modify the arc
    10965
    10966 SCIP_Bool isCut = newRow->isArcCut[iterArc];
    10967 SCIP_Bool isMoveColor = newRow->nodeColors[otherEnd] == COLOR_SOURCE;
    10968 SCIP_Bool changeArcEnd = isCut == isMoveColor;
    10969 if( changeArcEnd )
    10970 {
    10971 if( otherHead == splitNode )
    10972 {
    10973 changeArcHead(dec, iterArc, otherHead, newNode);
    10974 }
    10975 else
    10976 {
    10977 changeArcTail(dec, iterArc, otherTail, newNode);
    10978 }
    10979 if( iterArc == smallMarker )
    10980 {
    10981 smallOtherNode = splitNode;
    10982 }
    10983 }
    10984 newRow->nodeColors[otherEnd] = UNCOLORED;
    10985 //Ugly hack to make sure we can iterate neighbourhood whilst changing arc ends.
    10986 spqr_arc previousArc = iterArc;
    10987 iterArc = nextArc;
    10988 if( iterArc == firstNodeArc )
    10989 {
    10990 break;
    10991 }
    10992 if( changeArcEnd && previousArc == firstNodeArc )
    10993 {
    10994 firstNodeArc = iterArc;
    10995 }
    10996 }
    10997 while( TRUE ); /*lint !e506*/
    10998 }
    10999
    11000 spqr_arc representative = findArcSign(dec, smallMarker).representative;
    11001
    11002 newRowInfo->representative = mergeArcSigns(dec, newRowInfo->representative, representative,
    11003 newRow->reducedMembers[smallMember].willBeReversed);
    11004
    11005 spqr_node largeMarkerHead = findArcHead(dec, largeMarker);
    11006 spqr_node largeMarkerTail = findArcTail(dec, largeMarker);
    11007 if( findArcSign(dec, largeMarker).reversed )
    11008 {
    11009 spqr_node temp = largeMarkerHead;
    11010 largeMarkerHead = largeMarkerTail;
    11011 largeMarkerTail = temp;
    11012 }
    11013 assert(newRowInfo->head == largeMarkerHead || newRowInfo->head == largeMarkerTail ||
    11014 newRowInfo->tail == largeMarkerHead || newRowInfo->tail == largeMarkerTail);
    11015 spqr_node largeOtherNode = ( newRowInfo->head == largeMarkerHead || newRowInfo->head == largeMarkerTail )
    11016 ? newRowInfo->tail : newRowInfo->head;
    11017
    11018 spqr_member mergedMember = SPQR_INVALID_MEMBER;
    11019 spqr_node arcNodeOne;
    11020 spqr_node arcNodeTwo;
    11021 spqr_node mergeNodeThree;
    11022 if( largeIsParent )
    11023 {
    11024 SCIP_CALL(
    11025 mergeSplitMemberIntoParent(dec, newRow, smallMemberMember, largeMemberMember, largeMarker, smallMarker, TRUE,
    11026 largeOtherNode, smallOtherNode, &mergedMember,
    11027 &arcNodeOne,
    11028 &arcNodeTwo,
    11029 &mergeNodeThree) );
    11030 }
    11031 else
    11032 {
    11033 SCIP_CALL(
    11034 mergeSplitMemberIntoParent(dec, newRow, largeMemberMember, smallMemberMember, smallMarker, largeMarker, TRUE,
    11035 smallOtherNode, largeOtherNode, &mergedMember,
    11036 &arcNodeOne,
    11037 &arcNodeTwo,
    11038 &mergeNodeThree) );
    11039 }
    11040 newRowInfo->member = mergedMember;
    11041
    11042 SCIP_Bool otherIsHead = largeOtherNode == newRowInfo->head;
    11043 SCIP_Bool adjacentToMarkerHead = ( newRowInfo->tail == largeMarkerHead ||
    11044 newRowInfo->head == largeMarkerHead );
    11045 if( adjacentToMarkerHead )
    11046 {
    11047 if( otherIsHead )
    11048 {
    11049 newRowInfo->head = mergeNodeThree;
    11050 newRowInfo->tail = arcNodeTwo;
    11051 }
    11052 else
    11053 {
    11054 newRowInfo->head = arcNodeTwo;
    11055 newRowInfo->tail = mergeNodeThree;
    11056 }
    11057 }
    11058 else
    11059 {
    11060 if( otherIsHead )
    11061 {
    11062 newRowInfo->head = mergeNodeThree;
    11063 newRowInfo->tail = arcNodeOne;
    11064 }
    11065 else
    11066 {
    11067 newRowInfo->head = arcNodeOne;
    11068 newRowInfo->tail = mergeNodeThree;
    11069 }
    11070 }
    11071
    11072 return SCIP_OKAY;
    11073}
    11074
    11075/** Update a member to reflect the addition of the new row, and merge it into the previous members that were updated. */
    11076static
    11078 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    11079 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    11080 reduced_member_id smallMember, /**< The reduced rigid member */
    11081 SCIP_Bool largeIsParent, /**< Whether the large member containing previously updated members is
    11082 * the parent of this member */
    11083 NewRowInformation* const newRowInfo /**< Stores the information on how to add the new row */
    11084 )
    11085{
    11086 spqr_member member = newRow->reducedMembers[smallMember].member;
    11087 switch( getMemberType(dec, member))
    11088 {
    11090 {
    11091 SCIP_CALL( splitAndMergeRigid(dec, newRow, smallMember, largeIsParent, newRowInfo, member) );
    11092 break;
    11093 }
    11095 {
    11096 SCIP_CALL( splitAndMergeParallel(dec, newRow, smallMember, largeIsParent, newRowInfo, member) );
    11097 break;
    11098 }
    11100 {
    11101 SCIP_CALL( splitAndMergeSeries(dec, newRow, smallMember, largeIsParent, newRowInfo, member) );
    11102 break;
    11103 }
    11106 default:
    11107 {
    11108 newRow->remainsNetwork = FALSE;
    11109 SCIPABORT();
    11110 return SCIP_ERROR;
    11111 }
    11112 }
    11113 return SCIP_OKAY;
    11114}
    11115
    11116/** Update an SPQR tree with multiple members to reflect the addition of a new row,
    11117 * merging it into one big rigid node.
    11118 */
    11119static
    11121 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    11122 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    11123 reduced_member_id root, /**< The root node of the SPQR tree that is to be merged */
    11124 NewRowInformation* const newRowInfo /**< Stores the information on how to add the new row */
    11125 )
    11126{
    11127 //We use the same ordering as when finding
    11128 //go to a leaf. We need to start in a leaf to avoid the ambiguity of choosing an orientation
    11129 //in members which have no cut arcs; otherwise, we might choose the wrong one
    11130 reduced_member_id leaf = root;
    11131 while( newRow->reducedMembers[leaf].numChildren != newRow->reducedMembers[leaf].numPropagatedChildren )
    11132 {
    11133 for( int i = 0; i < newRow->reducedMembers[leaf].numChildren; ++i )
    11134 {
    11135 children_idx idx = newRow->reducedMembers[leaf].firstChild + i;
    11136 reduced_member_id child = newRow->childrenStorage[idx];
    11137 if( newRow->reducedMembers[child].type != TYPE_PROPAGATED )
    11138 {
    11139 leaf = child;
    11140 break;
    11141 }
    11142 }
    11143 }
    11144 SCIP_CALL( splitFirstLeaf(dec, newRow, leaf, newRowInfo) );
    11145
    11146 reduced_member_id baseNode = leaf;
    11147 reduced_member_id nextNode = newRow->reducedMembers[baseNode].parent;
    11148
    11149 while( reducedMemberIsValid(nextNode) )
    11150 {
    11151 //check this node
    11152 SCIP_CALL( splitAndMerge(dec, newRow, nextNode, FALSE, newRowInfo) );
    11153
    11154 //Recursively merge the children
    11155 //use a while loop to avoid recursion; we may get stack overflows for large graphs
    11156 MergeTreeCallData * data = newRow->mergeTreeCallData;
    11157
    11158 data[0].id = nextNode;
    11159 data[0].currentChild = newRow->reducedMembers[nextNode].firstChild ;
    11160 int depth = 0;
    11161 while( depth >= 0 )
    11162 {
    11163 reduced_member_id id = data[depth].id;
    11164 children_idx childidx = data[depth].currentChild;
    11165 if( childidx == newRow->reducedMembers[id].firstChild + newRow->reducedMembers[id].numChildren )
    11166 {
    11167 --depth;
    11168 continue;
    11169 }
    11170 reduced_member_id currentchild = newRow->childrenStorage[childidx];
    11171 data[depth].currentChild += 1;
    11172 //skip this child if we already processed it or it is not merged
    11173 if( currentchild == baseNode || newRow->reducedMembers[currentchild].type == TYPE_PROPAGATED )
    11174 {
    11175 continue;
    11176 }
    11177 SCIP_CALL( splitAndMerge(dec, newRow, currentchild, TRUE, newRowInfo) );
    11178
    11179 //recursively process the child
    11180 depth += 1;
    11181 assert(depth < newRow->memMergeTreeCallData);
    11182 data[depth].id = currentchild;
    11183 data[depth].currentChild = newRow->reducedMembers[currentchild].firstChild;
    11184 }
    11185 //Move up one layer
    11186 baseNode = nextNode;
    11187 nextNode = newRow->reducedMembers[nextNode].parent;
    11188 }
    11189
    11190 return SCIP_OKAY;
    11191}
    11192
    11193/** Update an SPQR tree (a single component of the SPQR forest) to reflect addition of a new row. */
    11194static
    11196 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    11197 SCIP_NETROWADD* newRow, /**< The network matrix row addition data structure */
    11198 SPQRRowReducedComponent* component, /**< The component to transform */
    11199 NewRowInformation* const newRowInfo /**< Stores the information on how to add the new row */
    11200 )
    11201{
    11202 assert(component);
    11203 if( newRow->reducedMembers[component->root].numChildren ==
    11204 newRow->reducedMembers[component->root].numPropagatedChildren )
    11205 {
    11206 //No merging necessary, only a single component
    11207 reduced_member_id reducedMember = component->root;
    11208 assert(reducedMemberIsValid(reducedMember));
    11209 spqr_member member = newRow->reducedMembers[reducedMember].member;
    11210 SPQRMemberType type = getMemberType(dec, member);
    11211
    11212 switch( type )
    11213 {
    11215 SCIP_CALL( transformSingleRigid(dec, newRow, reducedMember, member, newRowInfo) );
    11216 break;
    11218 {
    11219 SCIP_CALL( transformSingleParallel(dec, newRow, reducedMember, member, newRowInfo) );
    11220 break;
    11221 }
    11224 {
    11225 newRowInfo->member = member;
    11226 cut_arc_id cutArc = newRow->reducedMembers[reducedMember].firstCutArc;
    11227 spqr_arc arc = newRow->cutArcs[cutArc].arc;
    11228 newRowInfo->reversed = arcIsReversedNonRigid(dec, arc) == newRow->cutArcs[cutArc].arcReversed;
    11229 if( type == SPQR_MEMBERTYPE_LOOP )
    11230 {
    11231 if( getNumMemberArcs(dec, member) == 2 )
    11232 {
    11233 changeLoopToSeries(dec, member);
    11234 }
    11235 }
    11236 break;
    11237 }
    11239 default:
    11240 {
    11241 SCIPABORT();
    11242 return SCIP_ERROR;
    11243 }
    11244 }
    11245
    11246 return SCIP_OKAY;
    11247 }
    11248
    11249 SCIP_CALL( mergeTree(dec, newRow, component->root, newRowInfo) );
    11250
    11251 return SCIP_OKAY;
    11252}
    11253
    11254/** Create the network row addition data structure. */
    11255static
    11257 BMS_BLKMEM* blkmem, /**< Block memory */
    11258 SCIP_NETROWADD** prowadd /**< Pointer to store the new row addition struct at */
    11259 )
    11260{
    11261 assert(blkmem);
    11262 SCIP_ALLOC( BMSallocBlockMemory(blkmem, prowadd) );
    11263 SCIP_NETROWADD* newRow = *prowadd;
    11264
    11265 newRow->remainsNetwork = TRUE;
    11266
    11267 newRow->reducedMembers = NULL;
    11268 newRow->memReducedMembers = 0;
    11269 newRow->numReducedMembers = 0;
    11270
    11271 newRow->reducedComponents = NULL;
    11272 newRow->memReducedComponents = 0;
    11273 newRow->numReducedComponents = 0;
    11274
    11275 newRow->memberInformation = NULL;
    11276 newRow->memMemberInformation = 0;
    11277 newRow->numMemberInformation = 0;
    11278
    11279 newRow->cutArcs = NULL;
    11280 newRow->memCutArcs = 0;
    11281 newRow->numCutArcs = 0;
    11283
    11284 newRow->childrenStorage = NULL;
    11285 newRow->memChildrenStorage = 0;
    11286 newRow->numChildrenStorage = 0;
    11287
    11288 newRow->newRowIndex = SPQR_INVALID_ROW;
    11289
    11290 newRow->newColumnArcs = NULL;
    11291 newRow->newColumnReversed = NULL;
    11292 newRow->memColumnArcs = 0;
    11293 newRow->numColumnArcs = 0;
    11294
    11295 newRow->leafMembers = NULL;
    11296 newRow->numLeafMembers = 0;
    11297 newRow->memLeafMembers = 0;
    11298
    11299 newRow->decompositionColumnArcs = NULL;
    11301 newRow->memDecompositionColumnArcs = 0;
    11302 newRow->numDecompositionColumnArcs = 0;
    11303
    11304 newRow->isArcCut = NULL;
    11305 newRow->isArcCutReversed = NULL;
    11306 newRow->memIsArcCut = 0;
    11307
    11308 newRow->nodeColors = NULL;
    11309 newRow->memNodeColors = 0;
    11310
    11311 newRow->articulationNodes = NULL;
    11312 newRow->memArticulationNodes = 0;
    11313 newRow->numArticulationNodes = 0;
    11314
    11316 newRow->memNodeSearchInfo = 0;
    11317
    11318 newRow->crossingPathCount = NULL;
    11319 newRow->memCrossingPathCount = 0;
    11320
    11321 newRow->intersectionDFSData = NULL;
    11322 newRow->memIntersectionDFSData = 0;
    11323
    11324 newRow->colorDFSData = NULL;
    11325 newRow->memColorDFSData = 0;
    11326
    11327 newRow->artDFSData = NULL;
    11328 newRow->memArtDFSData = 0;
    11329
    11332
    11333 newRow->intersectionPathDepth = NULL;
    11334 newRow->memIntersectionPathDepth = 0;
    11335
    11336 newRow->intersectionPathParent = NULL;
    11337 newRow->memIntersectionPathParent = 0;
    11338
    11339 newRow->mergeTreeCallData = NULL;
    11340 newRow->memMergeTreeCallData = 0;
    11341
    11342 newRow->temporaryColorArray = NULL;
    11343 newRow->memTemporaryColorArray = 0;
    11344
    11345 return SCIP_OKAY;
    11346}
    11347
    11348/** Frees the network row addition data structure. */
    11349static
    11351 BMS_BLKMEM* blkmem, /**< Block memory */
    11352 SCIP_NETROWADD** prowadd /**< Pointer to row addition struct to be freed */
    11353 )
    11354{
    11355 assert(*prowadd);
    11356
    11357 SCIP_NETROWADD* newRow = *prowadd;
    11358
    11361 BMSfreeBlockMemoryArray(blkmem, &newRow->artDFSData, newRow->memArtDFSData);
    11362 BMSfreeBlockMemoryArray(blkmem, &newRow->colorDFSData, newRow->memColorDFSData);
    11370 BMSfreeBlockMemoryArray(blkmem, &newRow->nodeColors, newRow->memNodeColors);
    11371 BMSfreeBlockMemoryArray(blkmem, &newRow->isArcCut, newRow->memIsArcCut);
    11372 BMSfreeBlockMemoryArray(blkmem, &newRow->isArcCutReversed, newRow->memIsArcCut);
    11375 BMSfreeBlockMemoryArray(blkmem, &newRow->newColumnArcs, newRow->memColumnArcs);
    11376 BMSfreeBlockMemoryArray(blkmem, &newRow->newColumnReversed, newRow->memColumnArcs);
    11378 BMSfreeBlockMemoryArray(blkmem, &newRow->cutArcs, newRow->memCutArcs);
    11381 BMSfreeBlockMemoryArray(blkmem, &newRow->reducedMembers, newRow->memReducedMembers);
    11382 BMSfreeBlockMemoryArray(blkmem, &newRow->leafMembers, newRow->memLeafMembers);
    11383 BMSfreeBlockMemory(blkmem, prowadd);
    11384}
    11385
    11386/** Checks if the given row can be added to the network decomposition. */
    11387static
    11389 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    11390 SCIP_NETROWADD* rowadd, /**< The network matrix row addition data structure */
    11391 int row, /**< The row to be checked */
    11392 const int* nonzcols, /**< The column indices of the row's nonzero values */
    11393 const double* nonzvals, /**< The matrix entries of the row's nonzeroes */
    11394 int nnonzs /**< The number of nonzeroes in the row */
    11395 )
    11396{
    11397 assert(dec);
    11398 assert(rowadd);
    11399 assert(nnonzs == 0 || nonzcols);
    11400
    11401 /* A row can only be added once */
    11402 if( netMatDecDataContainsRow(dec,row) )
    11403 {
    11404 return SCIP_INVALIDDATA;
    11405 }
    11406
    11407 rowadd->remainsNetwork = TRUE;
    11408 cleanUpPreviousIteration(dec, rowadd);
    11409
    11410 SCIP_CALL( newRowUpdateRowInformation(dec, rowadd, row, nonzcols, nonzvals, nnonzs) );
    11413
    11414 SCIP_CALL( determineLeafReducedMembers(dec, rowadd) );
    11415 SCIP_CALL( allocateRigidSearchMemory(dec, rowadd) );
    11416 SCIP_CALL( allocateTreeSearchMemory(dec, rowadd) );
    11417 //Check for each component if the cut arcs propagate through a row tree marker to a cut arc in another component
    11418 //From the leafs inward.
    11419 propagateComponents(dec, rowadd);
    11420 //It can happen that we are not graphic by some of the checked components.
    11421 //In that case, further checking may lead to errors as some invariants that the code assumes will be broken.
    11422 if( rowadd->remainsNetwork )
    11423 {
    11424 for( int i = 0; i < rowadd->numReducedComponents; ++i )
    11425 {
    11426 determineMergeableTypes(dec, rowadd, rowadd->reducedComponents[i].root);
    11427 //exit early if one is not graphic
    11428 if( !rowadd->remainsNetwork )
    11429 {
    11430 break;
    11431 }
    11432 }
    11433 }
    11434
    11436
    11437 return SCIP_OKAY;
    11438}
    11439
    11440/** Adds the last checked row to the network decomposition. */
    11441static
    11443 SCIP_NETMATDECDATA* dec, /**< The network matrix decomposition */
    11444 SCIP_NETROWADD* rowadd /**< The network matrix row addition data structure */
    11445 )
    11446{
    11447 assert(rowadd->remainsNetwork);
    11448 if( rowadd->numReducedComponents == 0 )
    11449 {
    11450 spqr_member newMember = SPQR_INVALID_MEMBER;
    11452 rowadd->numColumnArcs, rowadd->newRowIndex, &newMember) );
    11453 }
    11454 else if( rowadd->numReducedComponents == 1 )
    11455 {
    11457 SCIP_CALL( transformComponentRowAddition(dec, rowadd, &rowadd->reducedComponents[0], &information) );
    11458
    11459 if( rowadd->numColumnArcs == 0 )
    11460 {
    11461 spqr_arc rowArc = SPQR_INVALID_ARC;
    11462 SCIP_CALL( createRowArc(dec, information.member, &rowArc, rowadd->newRowIndex, information.reversed) );
    11463 if( SPQRnodeIsValid(information.head))
    11464 {
    11465 assert(SPQRnodeIsValid(information.tail));
    11466 assert(SPQRarcIsValid(information.representative));
    11467 setArcHeadAndTail(dec, rowArc, findNode(dec, information.head), findNode(dec, information.tail));
    11468 arcSetRepresentative(dec, rowArc, information.representative);
    11469 arcSetReversed(dec, rowArc, information.reversed != arcIsReversedNonRigid(dec, information.representative));
    11470 }
    11471 }
    11472 else
    11473 {
    11474 spqr_member new_row_parallel = SPQR_INVALID_MEMBER;
    11476 rowadd->newRowIndex, &new_row_parallel) );
    11477 spqr_arc markerArc = SPQR_INVALID_ARC;
    11478 spqr_arc ignore = SPQR_INVALID_ARC;
    11479 SCIP_CALL( createMarkerPairWithReferences(dec, information.member, new_row_parallel, TRUE,
    11480 information.reversed, FALSE,
    11481 &markerArc, &ignore) );
    11482 if( SPQRnodeIsValid(information.head))
    11483 {
    11484 assert(SPQRnodeIsValid(information.tail));
    11485 assert(SPQRarcIsValid(information.representative));
    11486 setArcHeadAndTail(dec, markerArc, findNode(dec, information.head), findNode(dec, information.tail));
    11487 arcSetRepresentative(dec, markerArc, information.representative);
    11488 arcSetReversed(dec, markerArc,
    11489 information.reversed != arcIsReversedNonRigid(dec, information.representative));
    11490 }
    11491 }
    11492 if( getMemberType(dec, information.member) == SPQR_MEMBERTYPE_LOOP )
    11493 {
    11494 assert(getNumMemberArcs(dec, information.member) == 2 || getNumMemberArcs(dec, information.member) == 3);
    11495 if( getNumMemberArcs(dec, information.member) == 3 )
    11496 {
    11497 changeLoopToSeries(dec, information.member);
    11498 }
    11499 }
    11500 }
    11501 else
    11502 {
    11503#ifndef NDEBUG
    11504 int numDecComponentsBefore = numConnectedComponents(dec);
    11505#endif
    11506 spqr_member new_row_parallel = SPQR_INVALID_MEMBER;
    11508 rowadd->newRowIndex, &new_row_parallel) );
    11509 for( int i = 0; i < rowadd->numReducedComponents; ++i )
    11510 {
    11512
    11513 SCIP_CALL( transformComponentRowAddition(dec, rowadd, &rowadd->reducedComponents[i], &information) );
    11514 if( getMemberType(dec, information.member) == SPQR_MEMBERTYPE_LOOP )
    11515 {
    11516 assert(getNumMemberArcs(dec, information.member) == 1);
    11517 spqr_arc arc = getFirstMemberArc(dec, information.member);
    11518 assert(rowadd->isArcCut[arc]);
    11519 moveArcToNewMember(dec, arc, information.member, new_row_parallel);
    11520 arcSetReversed(dec, arc, rowadd->isArcCutReversed[arc]);
    11521 dec->members[information.member].type = SPQR_MEMBERTYPE_UNASSIGNED;
    11522 }
    11523 else
    11524 {
    11525 reorderComponent(dec, information.member);//Make sure the new component is the root of the local decomposition tree
    11526 spqr_arc markerArc = SPQR_INVALID_ARC;
    11527 spqr_arc ignore = SPQR_INVALID_ARC;
    11528 SCIP_CALL( createMarkerPairWithReferences(dec, new_row_parallel, information.member, FALSE,
    11529 FALSE, information.reversed,
    11530 &ignore, &markerArc) );
    11531 if( SPQRnodeIsValid(information.head))
    11532 {
    11533 assert(SPQRnodeIsValid(information.tail));
    11534 assert(SPQRarcIsValid(information.representative));
    11535 setArcHeadAndTail(dec, markerArc, findNode(dec, information.head), findNode(dec, information.tail));
    11536 arcSetRepresentative(dec, markerArc, information.representative);
    11537 arcSetReversed(dec, markerArc,
    11538 information.reversed != arcIsReversedNonRigid(dec, information.representative));
    11539 }
    11540 }
    11541 }
    11543 assert(numConnectedComponents(dec) == ( numDecComponentsBefore - rowadd->numReducedComponents + 1 ));
    11544 }
    11545
    11546 return SCIP_OKAY;
    11547}
    11548
    11549/** Returns whether the last checked row can be added to the network decomposition. */
    11550static
    11552 const SCIP_NETROWADD* rowadd /**< The network matrix row addition data structure */
    11553 )
    11554{
    11555 return rowadd->remainsNetwork;
    11556}
    11557
    11558/** A generic data structure that stores a decomposition and can perform both column and row additions. */
    11560{
    11564};
    11565
    11567 BMS_BLKMEM* blkmem, /**< Block memory */
    11568 SCIP_NETMATDEC** pdec, /**< buffer to store pointer to created decomposition */
    11569 int nrows, /**< The maximal number of rows that the decomposition can expect */
    11570 int ncols /**< The maximal number of columns that the decomposition can expect */
    11571 )
    11572{
    11573 SCIP_ALLOC( BMSallocBlockMemory(blkmem,pdec) );
    11574 SCIP_NETMATDEC* dec = *pdec;
    11575
    11576 dec->dec = NULL;
    11577 SCIP_CALL( netMatDecDataCreate(blkmem, &dec->dec, nrows, ncols) );
    11578 dec->rowadd = NULL;
    11579 dec->coladd = NULL;
    11580
    11581 return SCIP_OKAY;
    11582}
    11583
    11585 SCIP_NETMATDEC** pdec /**< pointer to the network matrix decomposition to freed */
    11586 )
    11587{
    11588 SCIP_NETMATDEC* dec = *pdec;
    11589 BMS_BLKMEM* blkmem = dec->dec->env;
    11590
    11591 if( dec->coladd != NULL )
    11592 {
    11593 netcoladdFree(blkmem, &dec->coladd);
    11594 }
    11595 if( dec->rowadd != NULL )
    11596 {
    11597 netrowaddFree(blkmem, &dec->rowadd);
    11598 }
    11599 netMatDecDataFree(&dec->dec);
    11600 BMSfreeBlockMemory(blkmem,pdec);
    11601}
    11602
    11604 SCIP_NETMATDEC* dec, /**< Network matrix decomposition */
    11605 int column, /**< The column to add */
    11606 int* nonzrows, /**< The column's nonzero row indices */
    11607 double* nonzvals, /**< The column's nonzero entries */
    11608 int nnonzs, /**< The number of nonzeros in the column */
    11609 SCIP_Bool* success /**< Buffer to store whether the column was added */
    11610 )
    11611{
    11612 if( dec->coladd == NULL )
    11613 {
    11614 SCIP_CALL( netcoladdCreate(dec->dec->env, &dec->coladd) );
    11615 }
    11616
    11617 SCIP_CALL( netcoladdCheck(dec->dec, dec->coladd, column, nonzrows, nonzvals, nnonzs) );
    11618 *success = netcoladdRemainsNetwork(dec->coladd);
    11619 if( *success )
    11620 {
    11621 SCIP_CALL( netcoladdAdd(dec->dec, dec->coladd) );
    11622 }
    11623
    11624 return SCIP_OKAY;
    11625}
    11626
    11628 SCIP_NETMATDEC* dec, /**< Network matrix decomposition */
    11629 int row, /**< The row to add */
    11630 int* nonzcols, /**< The row's nonzero column indices */
    11631 double* nonzvals, /**< The row's nonzero entries */
    11632 int nnonzs, /**< The number of nonzeros in the row */
    11633 SCIP_Bool* success /**< Buffer to store whether the row was added */
    11634 )
    11635{
    11636 if( dec->rowadd == NULL )
    11637 {
    11638 SCIP_CALL( netrowaddCreate(dec->dec->env, &dec->rowadd) );
    11639 }
    11640
    11641 SCIP_CALL( netrowaddCheck(dec->dec, dec->rowadd, row, nonzcols, nonzvals, nnonzs) );
    11642 *success = netrowaddRemainsNetwork(dec->rowadd);
    11643 if( *success )
    11644 {
    11645 SCIP_CALL( netrowaddAdd(dec->dec, dec->rowadd) );
    11646 }
    11647
    11648 return SCIP_OKAY;
    11649}
    11650
    11652 SCIP_NETMATDEC* dec, /**< The network matrix decomposition */
    11653 int row /**< The row index that is checked */
    11654 )
    11655{
    11656 return netMatDecDataContainsRow(dec->dec, row);
    11657}
    11658
    11660 SCIP_NETMATDEC* dec, /**< The network matrix decomposition */
    11661 int column /**< The column index that is checked */
    11662 )
    11663{
    11664 return netMatDecDataContainsColumn(dec->dec, column);
    11665}
    11666
    11668 SCIP_NETMATDEC* dec, /**< The network matrix decomposition */
    11669 int* componentrows, /**< Pointer to the array of rows to delete */
    11670 int nrows, /**< The number of rows to delete */
    11671 int* componentcols, /**< Pointer to the array of columns to delete */
    11672 int ncols /**< The number of columns to delete */
    11673 )
    11674{
    11675 netMatDecDataRemoveComponent(dec->dec, componentrows, nrows, componentcols, ncols);
    11676}
    11677
    11679 SCIP_NETMATDEC* dec /**< The network matrix decomposition */
    11680 )
    11681{
    11682 return netMatDecDataIsMinimal(dec->dec);
    11683}
    11684
    11686 BMS_BUFMEM* bufmem, /**< Buffer memory */
    11687 SCIP_NETMATDEC* dec, /**< The network matrix decomposition */
    11688 int column, /**< The column to check */
    11689 int* nonzrowidx, /**< Array with the column's nonzero row indices */
    11690 double* nonzvals, /**< Array with the column's nonzero values */
    11691 int nnonzs, /**< Number of nonzeros in the column */
    11692 int* pathrowstorage, /**< A buffer to hold the computed path's rows. Should have size equal or
    11693 * greater than the number of rows in the decomposition. */
    11694 SCIP_Bool* pathsignstorage /**< A buffer to store the computed path's row signs. Should have size
    11695 * equal or greater than the number of rows in the decomposition. */
    11696 )
    11697{
    11698 return netMatDecDataVerifyCycle(bufmem, dec->dec, column, nonzrowidx, nonzvals, nnonzs, pathrowstorage, pathsignstorage);
    11699}
    11700
    11702 SCIP_NETMATDEC* dec, /**< The network matrix decomposition */
    11703 BMS_BLKMEM * blkmem, /**< The block memory to use for the created digraph */
    11704 SCIP_DIGRAPH** pdigraph, /**< Pointer to the pointer to store the created digraph */
    11705 SCIP_Bool createrowarcs /**< Should the row arcs be added to the created digraph? */
    11706 )
    11707{
    11708 return netMatDecDataCreateDiGraph(dec->dec, blkmem, pdigraph, createrowarcs);
    11709}
    SCIP_VAR * a
    Definition: circlepacking.c:66
    SCIP_VAR ** b
    Definition: circlepacking.c:65
    #define NULL
    Definition: def.h:248
    #define SCIP_Bool
    Definition: def.h:91
    #define MIN(x, y)
    Definition: def.h:224
    #define SCIP_ALLOC(x)
    Definition: def.h:366
    #define TRUE
    Definition: def.h:93
    #define FALSE
    Definition: def.h:94
    #define MAX(x, y)
    Definition: def.h:220
    #define SCIPABORT()
    Definition: def.h:327
    #define SCIP_CALL(x)
    Definition: def.h:355
    SCIP_RETCODE SCIPdigraphAddArc(SCIP_DIGRAPH *digraph, int startnode, int endnode, void *data)
    Definition: misc.c:7739
    SCIP_Bool SCIPnetmatdecVerifyCycle(BMS_BUFMEM *bufmem, SCIP_NETMATDEC *dec, int column, int *nonzrowidx, double *nonzvals, int nnonzs, int *pathrowstorage, SCIP_Bool *pathsignstorage)
    Definition: network.c:11685
    SCIP_RETCODE SCIPnetmatdecCreateDiGraph(SCIP_NETMATDEC *dec, BMS_BLKMEM *blkmem, SCIP_DIGRAPH **pdigraph, SCIP_Bool createrowarcs)
    Definition: network.c:11701
    SCIP_Bool SCIPnetmatdecContainsRow(SCIP_NETMATDEC *dec, int row)
    Definition: network.c:11651
    void SCIPnetmatdecRemoveComponent(SCIP_NETMATDEC *dec, int *componentrows, int nrows, int *componentcols, int ncols)
    Definition: network.c:11667
    SCIP_Bool SCIPnetmatdecContainsColumn(SCIP_NETMATDEC *dec, int column)
    Definition: network.c:11659
    SCIP_RETCODE SCIPnetmatdecTryAddRow(SCIP_NETMATDEC *dec, int row, int *nonzcols, double *nonzvals, int nnonzs, SCIP_Bool *success)
    Definition: network.c:11627
    SCIP_RETCODE SCIPnetmatdecCreate(BMS_BLKMEM *blkmem, SCIP_NETMATDEC **pdec, int nrows, int ncols)
    Definition: network.c:11566
    SCIP_RETCODE SCIPnetmatdecTryAddCol(SCIP_NETMATDEC *dec, int column, int *nonzrows, double *nonzvals, int nnonzs, SCIP_Bool *success)
    Definition: network.c:11603
    SCIP_Bool SCIPnetmatdecIsMinimal(SCIP_NETMATDEC *dec)
    Definition: network.c:11678
    void SCIPnetmatdecFree(SCIP_NETMATDEC **pdec)
    Definition: network.c:11584
    void SCIPswapInts(int *value1, int *value2)
    Definition: misc.c:10485
    void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
    memory allocation routines
    #define BMSfreeBlockMemory(mem, ptr)
    Definition: memory.h:465
    #define BMSallocBlockMemory(mem, ptr)
    Definition: memory.h:451
    #define BMSfreeBufferMemoryArray(mem, ptr)
    Definition: memory.h:742
    #define BMSallocBlockMemoryArray(mem, ptr, num)
    Definition: memory.h:454
    #define BMSfreeBlockMemoryArray(mem, ptr, num)
    Definition: memory.h:467
    #define BMSreallocBlockMemoryArray(mem, ptr, oldnum, newnum)
    Definition: memory.h:458
    #define BMSallocClearBlockMemoryArray(mem, ptr, num)
    Definition: memory.h:455
    #define BMSallocBufferMemoryArray(mem, ptr, num)
    Definition: memory.h:731
    struct BMS_BlkMem BMS_BLKMEM
    Definition: memory.h:437
    SCIP_RETCODE SCIPdigraphCreate(SCIP_DIGRAPH **digraph, BMS_BLKMEM *blkmem, int nnodes)
    Definition: misc.c:7454
    internal miscellaneous methods
    static SCIP_RETCODE splitAndMergeRigid(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, reduced_member_id smallMember, SCIP_Bool largeIsParent, NewRowInformation *const newRowInfo, spqr_member member)
    Definition: network.c:10931
    static reduced_member_id createReducedMembersToRoot(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol, const spqr_member firstMember)
    Definition: network.c:3820
    static spqr_node findNode(SCIP_NETMATDECDATA *dec, spqr_node node)
    Definition: network.c:456
    static spqr_arc getPreviousNodeArc(SCIP_NETMATDECDATA *dec, spqr_arc arc, spqr_node node)
    Definition: network.c:669
    static SCIP_RETCODE transformPath(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol, SPQRColReducedComponent *component, NewColInformation *newColInfo)
    Definition: network.c:6378
    static void mergeMemberArcList(SCIP_NETMATDECDATA *dec, spqr_member toMergeInto, spqr_member toRemove)
    Definition: network.c:2683
    static SCIP_Bool SPQRelementIsRow(spqr_element element)
    Definition: network.c:194
    int spqr_matrix_size
    Definition: network.c:137
    static SplitOrientation getRelativeOrientationRigid(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, reduced_member_id reducedId, spqr_arc arcToNext)
    Definition: network.c:9082
    static SCIP_Bool SPQRcolIsValid(spqr_col col)
    Definition: network.c:178
    static void setTerminalMember(NewColInformation *info, spqr_member member)
    Definition: network.c:5542
    static SCIP_RETCODE netrowaddCheck(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *rowadd, int row, const int *nonzcols, const double *nonzvals, int nnonzs)
    Definition: network.c:11388
    static void netMatDecDataRemoveComponent(SCIP_NETMATDECDATA *dec, const int *componentRows, int numRows, const int *componentCols, int numCols)
    Definition: network.c:2847
    static SCIP_RETCODE splitParallelMerging(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, reduced_member_id reducedMember, spqr_member member, spqr_member *const pMergeMember, spqr_arc *const cutRepresentative)
    Definition: network.c:10195
    int spqr_arc
    Definition: network.c:312
    static SCIP_Bool nodeIsRepresentative(const SCIP_NETMATDECDATA *dec, spqr_node node)
    Definition: network.c:440
    static SCIP_Bool SPQRnodeIsValid(spqr_node node)
    Definition: network.c:298
    static SCIP_RETCODE splitParallel(SCIP_NETMATDECDATA *dec, spqr_member parallel, spqr_arc arc1, spqr_arc arc2, spqr_member *childParallel)
    Definition: network.c:5569
    static void determinePathTypes(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol, SPQRColReducedComponent *component)
    Definition: network.c:5055
    static void articulationPoints(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, ArticulationNodeInformation *nodeInfo, reduced_member_id reducedMember)
    Definition: network.c:7969
    ReducedMemberType
    Definition: network.c:3507
    @ REDUCEDMEMBER_TYPE_NOT_NETWORK
    Definition: network.c:3513
    @ REDUCEDMEMBER_TYPE_MERGED
    Definition: network.c:3512
    @ REDUCEDMEMBER_TYPE_UNASSIGNED
    Definition: network.c:3508
    @ REDUCEDMEMBER_TYPE_CYCLE
    Definition: network.c:3509
    static SCIP_RETCODE newColUpdateColInformation(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol, spqr_col column, const spqr_row *nonzeroRows, const double *nonzeroValues, int numNonzeros)
    Definition: network.c:4206
    static SCIP_Bool cutArcIsInvalid(const cut_arc_id arc)
    Definition: network.c:6776
    static void determineSingleSeriesType(SCIP_NETROWADD *newRow, reduced_member_id reducedMember)
    Definition: network.c:8854
    #define INVALID_PATH_ARC
    Definition: network.c:3439
    static void moveArcToNewMember(SCIP_NETMATDECDATA *dec, spqr_arc arc, spqr_member oldMember, spqr_member newMember)
    Definition: network.c:2641
    static SCIP_Bool SPQRarcIsValid(spqr_arc arc)
    Definition: network.c:326
    static SCIP_Bool SPQRmemberIsInvalid(spqr_member member)
    Definition: network.c:264
    static int decompositionGetFundamentalCycleRows(const SCIP_NETMATDECDATA *dec, spqr_col column, spqr_row *output, SCIP_Bool *computedSignStorage)
    Definition: network.c:2241
    static spqr_member findArcChildMember(SCIP_NETMATDECDATA *dec, spqr_arc arc)
    Definition: network.c:1031
    RowReducedMemberType
    Definition: network.c:6812
    @ TYPE_MERGED
    Definition: network.c:6815
    @ TYPE_PROPAGATED
    Definition: network.c:6814
    @ TYPE_NOT_NETWORK
    Definition: network.c:6816
    @ TYPE_UNDETERMINED
    Definition: network.c:6813
    static SCIP_RETCODE netMatDecDataCreateDiGraph(SCIP_NETMATDECDATA *dec, BMS_BLKMEM *blkmem, SCIP_DIGRAPH **pdigraph, SCIP_Bool createrowarcs)
    Definition: network.c:3111
    static ReducedMemberType checkLeaf(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol, reduced_member_id leaf, spqr_arc toParent, reduced_member_id parent, spqr_arc toChild)
    Definition: network.c:5177
    static void determineSingleParallelType(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, reduced_member_id reducedMember)
    Definition: network.c:8813
    static spqr_element SPQRrowToElement(spqr_row row)
    Definition: network.c:222
    static SCIP_RETCODE createMarkerPair(SCIP_NETMATDECDATA *dec, spqr_member parentMember, spqr_member childMember, SCIP_Bool parentIsTree, SCIP_Bool childMarkerReversed, SCIP_Bool parentMarkerReversed)
    Definition: network.c:2598
    static void cleanUpPreviousIteration(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow)
    Definition: network.c:7634
    static void determineMergeableTypes(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, reduced_member_id root)
    Definition: network.c:9482
    static SCIP_Bool pathArcIsValid(const path_arc_id arc)
    Definition: network.c:3452
    static void determineSplitTypeRigid(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, reduced_member_id reducedId, spqr_member member, spqr_arc marker, SplitOrientation previousOrientation)
    Definition: network.c:9322
    static void rigidGetSplittableArticulationPointsOnPath(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, const reduced_member_id toCheck, spqr_node firstNode, spqr_node secondNode)
    Definition: network.c:8289
    #define SPQR_INVALID_ARC
    Definition: network.c:313
    static SCIP_RETCODE createConnectedSeries(SCIP_NETMATDECDATA *dec, spqr_row *rows, SCIP_Bool *reversed, int numRows, spqr_col col, spqr_member *pMember)
    Definition: network.c:2122
    #define MARKER_ROW_ELEMENT
    Definition: network.c:188
    static SCIP_RETCODE createStandaloneParallel(SCIP_NETMATDECDATA *dec, spqr_col *columns, SCIP_Bool *reversed, int num_columns, spqr_row row, spqr_member *pMember)
    Definition: network.c:2026
    int spqr_node
    Definition: network.c:284
    static void zeroOutColors(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, const spqr_node firstRemoveNode)
    Definition: network.c:7578
    static SCIP_RETCODE transformComponentRowAddition(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, SPQRRowReducedComponent *component, NewRowInformation *const newRowInfo)
    Definition: network.c:11195
    static SCIP_RETCODE allocateTreeSearchMemory(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow)
    Definition: network.c:8762
    int reduced_member_id
    Definition: network.c:3479
    #define SPQR_INVALID_COL
    Definition: network.c:143
    static spqr_member findMemberParent(SCIP_NETMATDECDATA *dec, spqr_member member)
    Definition: network.c:985
    static SCIP_RETCODE splitAndMergeParallel(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, reduced_member_id smallMember, SCIP_Bool largeIsParent, NewRowInformation *const newRowInfo, spqr_member member)
    Definition: network.c:10799
    static SCIP_RETCODE createPathArcs(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol)
    Definition: network.c:4151
    static SCIP_RETCODE columnTransformSingleRigid(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol, reduced_member_id reducedMemberId, spqr_member member, NewColInformation *newColInfo)
    Definition: network.c:6451
    static spqr_member findArcMemberNoCompression(const SCIP_NETMATDECDATA *dec, spqr_arc arc)
    Definition: network.c:967
    static void determineSplitTypeNext(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, reduced_member_id current, reduced_member_id next, SCIP_Bool currentIsParent)
    Definition: network.c:9438
    static spqr_arc markerOfParent(const SCIP_NETMATDECDATA *dec, spqr_member member)
    Definition: network.c:1970
    static SCIP_RETCODE splitSeriesMergingRowAddition(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, const reduced_member_id reducedMember, const spqr_member member, spqr_member *const mergingMember, SCIP_Bool *const isCut, spqr_arc *representativeEdge)
    Definition: network.c:10075
    static SCIP_RETCODE splitSeries(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol, SPQRColReducedMember *reducedMember, spqr_member member, spqr_member *loopMember, NewColInformation *newColInfo)
    Definition: network.c:5607
    static spqr_member findMember(SCIP_NETMATDECDATA *dec, spqr_member member)
    Definition: network.c:855
    static spqr_arc markerToParent(const SCIP_NETMATDECDATA *dec, spqr_member member)
    Definition: network.c:1935
    static void mergeNodeArcList(SCIP_NETMATDECDATA *dec, spqr_node toMergeInto, spqr_node toRemove)
    Definition: network.c:698
    static void updateMemberType(const SCIP_NETMATDECDATA *dec, spqr_member member, SPQRMemberType type)
    Definition: network.c:1919
    static void determineSingleRigidType(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol, reduced_member_id reducedMember)
    Definition: network.c:4353
    #define NEWROWINFORMATION_EMPTY
    Definition: network.c:7016
    static int numConnectedComponents(const SCIP_NETMATDECDATA *dec)
    Definition: network.c:2545
    static void determinePathRigidType(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol, reduced_member_id reducedMember, MemberPathType previousType, spqr_arc source, spqr_arc target)
    Definition: network.c:4669
    static void addArcToMemberArcList(SCIP_NETMATDECDATA *dec, spqr_arc arc, spqr_member member)
    Definition: network.c:1576
    static void arcFlipReversed(SCIP_NETMATDECDATA *dec, spqr_arc arc)
    Definition: network.c:754
    static spqr_node findEffectiveArcTailNoCompression(const SCIP_NETMATDECDATA *dec, spqr_arc arc)
    Definition: network.c:1262
    #define INVALID_REDUCED_MEMBER
    Definition: network.c:3480
    static void determineRigidPath(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol, SPQRColReducedMember *redMem)
    Definition: network.c:4289
    static void removeArcFromNodeArcList(SCIP_NETMATDECDATA *dec, spqr_arc arc, spqr_node node, SCIP_Bool nodeIsHead)
    Definition: network.c:1746
    #define SPQR_INVALID_MEMBER
    Definition: network.c:260
    static spqr_member findArcChildMemberNoCompression(const SCIP_NETMATDECDATA *dec, spqr_arc arc)
    Definition: network.c:1050
    static SCIP_Bool netMatDecDataVerifyCycle(BMS_BUFMEM *bufmem, const SCIP_NETMATDECDATA *dec, int column, const int *nonzrowidx, const double *nonzvals, int num_rows, int *pathrowstorage, SCIP_Bool *pathsignstorage)
    Definition: network.c:2432
    static SCIP_RETCODE rigidTransformArcIntoCycle(SCIP_NETMATDECDATA *dec, const spqr_member member, const spqr_arc arc, const SCIP_Bool reverseArcDirection, NewRowInformation *const newRowInfo)
    Definition: network.c:9614
    static int nodeDegree(SCIP_NETMATDECDATA *dec, spqr_node node)
    Definition: network.c:1890
    static int getNumMembers(const SCIP_NETMATDECDATA *dec)
    Definition: network.c:2011
    static SCIP_RETCODE splitFirstLeaf(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, reduced_member_id leaf, NewRowInformation *const newRowInfo)
    Definition: network.c:10428
    static void setTerminalRepresentative(NewColInformation *info, spqr_arc representative)
    Definition: network.c:5554
    static spqr_member findMemberNoCompression(const SCIP_NETMATDECDATA *dec, spqr_member member)
    Definition: network.c:892
    static void decreaseNumConnectedComponents(SCIP_NETMATDECDATA *dec, int by)
    Definition: network.c:2779
    static SplitOrientation getRelativeOrientationParallel(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, reduced_member_id reducedId, spqr_arc arcToNext)
    Definition: network.c:9133
    static void cleanUpMemberInformation(SCIP_NETCOLADD *newCol)
    Definition: network.c:4079
    static SCIP_RETCODE netcoladdCreate(BMS_BLKMEM *blkmem, SCIP_NETCOLADD **pcoladd)
    Definition: network.c:3725
    static spqr_node findEffectiveArcHead(SCIP_NETMATDECDATA *dec, spqr_arc arc)
    Definition: network.c:1201
    static spqr_element arcGetElement(const SCIP_NETMATDECDATA *dec, spqr_arc arc)
    Definition: network.c:1343
    static SCIP_Bool SPQRrowIsValid(spqr_row row)
    Definition: network.c:169
    static spqr_node mergeNodes(SCIP_NETMATDECDATA *dec, spqr_node first, spqr_node second)
    Definition: network.c:808
    static spqr_arc getFirstNodeArc(const SCIP_NETMATDECDATA *dec, spqr_node node)
    Definition: network.c:596
    static SCIP_RETCODE transformComponent(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol, SPQRColReducedComponent *component, NewColInformation *newColInfo)
    Definition: network.c:6591
    static void netrowaddFree(BMS_BLKMEM *blkmem, SCIP_NETROWADD **prowadd)
    Definition: network.c:11350
    static void setTerminalTail(NewColInformation *info, spqr_node node)
    Definition: network.c:5516
    static void setArcHeadAndTail(SCIP_NETMATDECDATA *dec, spqr_arc arc, spqr_node head, spqr_node tail)
    Definition: network.c:1832
    static SCIP_RETCODE columnTransformSingleParallel(SCIP_NETCOLADD *newCol, reduced_member_id reducedMemberId, spqr_member member, NewColInformation *newColInfo)
    Definition: network.c:6409
    static spqr_arc getNextNodeArcNoCompression(const SCIP_NETMATDECDATA *dec, spqr_arc arc, spqr_node node)
    Definition: network.c:614
    #define INVALID_CUT_ARC
    Definition: network.c:6772
    static SCIP_Bool isHead(MemberPathType type)
    Definition: network.c:3537
    static void addArcToNodeArcList(SCIP_NETMATDECDATA *dec, spqr_arc arc, spqr_node node, SCIP_Bool nodeIsHead)
    Definition: network.c:1784
    static void setDecompositionRowArc(SCIP_NETMATDECDATA *dec, spqr_row row, spqr_arc arc)
    Definition: network.c:1398
    int cut_arc_id
    Definition: network.c:6771
    static SCIP_RETCODE createStandaloneSeries(SCIP_NETMATDECDATA *dec, spqr_row *rows, SCIP_Bool *reversed, int numRows, spqr_col col, spqr_member *pMember)
    Definition: network.c:2090
    static void updateMemberParentInformation(SCIP_NETMATDECDATA *dec, const spqr_member newMember, const spqr_member toRemove)
    Definition: network.c:1950
    static void netcoladdFree(BMS_BLKMEM *blkmem, SCIP_NETCOLADD **pcoladd)
    Definition: network.c:3789
    static SCIP_Bool SPQRmemberIsValid(spqr_member member)
    Definition: network.c:272
    static SCIP_RETCODE createMarkerPairWithReferences(SCIP_NETMATDECDATA *dec, spqr_member parentMember, spqr_member childMember, SCIP_Bool parentIsTree, SCIP_Bool childMarkerReversed, SCIP_Bool parentMarkerReversed, spqr_arc *parentToChild, spqr_arc *childToParent)
    Definition: network.c:2619
    static SPQRMemberType getMemberType(const SCIP_NETMATDECDATA *dec, spqr_member member)
    Definition: network.c:1904
    static void determinePathSeriesType(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol, reduced_member_id reducedMember, spqr_member member, MemberPathType previousType, spqr_arc source, spqr_arc target)
    Definition: network.c:4473
    static SCIP_RETCODE columnTransformSingleSeries(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol, reduced_member_id reducedMemberId, spqr_member member, NewColInformation *newColInfo)
    Definition: network.c:6427
    static SCIP_RETCODE netrowaddAdd(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *rowadd)
    Definition: network.c:11442
    static spqr_node findArcHead(SCIP_NETMATDECDATA *dec, spqr_arc arc)
    Definition: network.c:540
    int children_idx
    Definition: network.c:3501
    static void reorderComponent(SCIP_NETMATDECDATA *dec, spqr_member newRoot)
    Definition: network.c:2792
    static SCIP_RETCODE transformSingleParallel(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, const reduced_member_id reducedMember, const spqr_member member, NewRowInformation *info)
    Definition: network.c:10061
    static SCIP_Bool arcIsChildMarker(const SCIP_NETMATDECDATA *dec, spqr_arc arc)
    Definition: network.c:1065
    static SplitOrientation getRelativeOrientationSeries(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, reduced_member_id reducedId, spqr_arc arcToNext)
    Definition: network.c:9158
    static spqr_node findArcTailNoCompression(const SCIP_NETMATDECDATA *dec, spqr_arc arc)
    Definition: network.c:578
    static SCIP_RETCODE mergeGivenMemberIntoParent(SCIP_NETMATDECDATA *dec, spqr_member member, spqr_member parent, spqr_arc parentToChild, spqr_arc childToParent, SCIP_Bool headToHead, spqr_member *mergedMember)
    Definition: network.c:3052
    static SCIP_Bool isInto(MemberPathType type)
    Definition: network.c:3528
    static void changeLoopToSeries(SCIP_NETMATDECDATA *dec, spqr_member member)
    Definition: network.c:2711
    static spqr_node largestNodeID(const SCIP_NETMATDECDATA *dec)
    Definition: network.c:2536
    static void removeArcFromMemberArcList(SCIP_NETMATDECDATA *dec, spqr_arc arc, spqr_member member)
    Definition: network.c:2149
    static SCIP_RETCODE netrowaddCreate(BMS_BLKMEM *blkmem, SCIP_NETROWADD **prowadd)
    Definition: network.c:11256
    static spqr_member findArcMember(SCIP_NETMATDECDATA *dec, spqr_arc arc)
    Definition: network.c:951
    MemberPathType
    Definition: network.c:3519
    @ OUT_HEAD
    Definition: network.c:3522
    @ INTO_TAIL
    Definition: network.c:3521
    @ OUT_TAIL
    Definition: network.c:3523
    @ INTO_HEAD
    Definition: network.c:3520
    int spqr_member
    Definition: network.c:259
    static SCIP_Bool reducedMemberIsValid(const reduced_member_id id)
    Definition: network.c:3493
    static SplitOrientation getRelativeOrientation(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, reduced_member_id reducedId, spqr_arc arcToNext)
    Definition: network.c:9183
    static spqr_node findArcTail(SCIP_NETMATDECDATA *dec, spqr_arc arc)
    Definition: network.c:520
    static spqr_member findMemberParentNoCompression(const SCIP_NETMATDECDATA *dec, spqr_member member)
    Definition: network.c:1011
    static void determineSingleComponentType(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol, reduced_member_id reducedMember)
    Definition: network.c:4374
    static spqr_node findArcHeadNoCompression(const SCIP_NETMATDECDATA *dec, spqr_arc arc)
    Definition: network.c:560
    static SCIP_RETCODE transformFirstPathMember(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol, reduced_member_id reducedMember, NewColInformation *newColInfo, spqr_arc *representativeArc, spqr_member *mergedMember)
    Definition: network.c:5929
    static void changeLoopToParallel(SCIP_NETMATDECDATA *dec, spqr_member member)
    Definition: network.c:2729
    static SCIP_RETCODE transformAndMergeSeries(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol, reduced_member_id current, reduced_member_id next, spqr_member nextMember, SCIP_Bool nextIsParent, spqr_arc *representativeArc, spqr_member *mergedMember, NewColInformation *info)
    Definition: network.c:6111
    static SCIP_RETCODE createColumnArc(SCIP_NETMATDECDATA *dec, spqr_member member, spqr_arc *pArc, spqr_col column, SCIP_Bool reversed)
    Definition: network.c:1674
    static SCIP_Bool netrowaddRemainsNetwork(const SCIP_NETROWADD *rowadd)
    Definition: network.c:11551
    static void process_arc(spqr_row *cyclearcs, int *num_cycle_arcs, FindCycleCall *callStack, int *callStackSize, spqr_arc arc, const SCIP_NETMATDECDATA *dec, SCIP_Bool *cycledir, SCIP_Bool arcIsReversed)
    Definition: network.c:2191
    static void propagateComponents(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow)
    Definition: network.c:8576
    static SCIP_Bool reducedMemberIsInvalid(const reduced_member_id id)
    Definition: network.c:3484
    static void zeroOutColorsExceptNeighbourhood(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, const spqr_node articulationNode, const spqr_node startRemoveNode)
    Definition: network.c:7780
    static void determineRigidType(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, const reduced_member_id toCheckMember, const spqr_arc markerToOther, const reduced_member_id otherMember, const spqr_arc markerToCheck)
    Definition: network.c:8471
    static spqr_element SPQRcolumnToElement(spqr_col column)
    Definition: network.c:242
    static SCIP_Bool memberIsRepresentative(const SCIP_NETMATDECDATA *dec, spqr_member member)
    Definition: network.c:841
    static SCIP_RETCODE createMember(SCIP_NETMATDECDATA *dec, SPQRMemberType type, spqr_member *pMember)
    Definition: network.c:1692
    static SCIP_Bool netMatDecDataContainsColumn(SCIP_NETMATDECDATA *dec, int column)
    Definition: network.c:1370
    #define SPQR_INVALID_ROW
    Definition: network.c:142
    static void createCutArc(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, const spqr_arc arc, const reduced_member_id reducedMember, SCIP_Bool reversed)
    Definition: network.c:7336
    static spqr_node findNodeNoCompression(const SCIP_NETMATDECDATA *dec, spqr_node node)
    Definition: network.c:493
    static void determinePathParallelType(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol, reduced_member_id reducedMember, spqr_member member, MemberPathType previousType, spqr_arc source, spqr_arc target)
    Definition: network.c:4599
    static void setTerminalReversed(NewColInformation *info, SCIP_Bool reversed)
    Definition: network.c:5530
    static spqr_node findEffectiveArcTail(SCIP_NETMATDECDATA *dec, spqr_arc arc)
    Definition: network.c:1219
    static SCIP_RETCODE createReducedDecompositionCutArcs(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow)
    Definition: network.c:7388
    static SCIP_RETCODE createRowArc(SCIP_NETMATDECDATA *dec, spqr_member member, spqr_arc *pArc, spqr_row row, SCIP_Bool reversed)
    Definition: network.c:1656
    static Nodes rigidDetermineCandidateNodesFromAdjacentComponents(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, const reduced_member_id toCheck)
    Definition: network.c:8692
    #define NEWCOLINFORMATION_EMPTY
    Definition: network.c:5498
    static SCIP_RETCODE netMatDecDataCreate(BMS_BLKMEM *blkmem, SCIP_NETMATDECDATA **pdec, int nrows, int ncols)
    Definition: network.c:1439
    spqr_matrix_size spqr_col
    Definition: network.c:139
    static void determineSingleRowRigidType(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, reduced_member_id reducedMember)
    Definition: network.c:8780
    static void addArticulationNode(SCIP_NETROWADD *newRow, spqr_node articulationNode)
    Definition: network.c:7949
    static void determineSeriesType(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, const reduced_member_id toCheckMember, const spqr_arc markerToOther, const reduced_member_id otherMember, const spqr_arc markerToCheck)
    Definition: network.c:8448
    static SCIP_RETCODE createArc(SCIP_NETMATDECDATA *dec, spqr_member member, SCIP_Bool reversed, spqr_arc *pArc)
    Definition: network.c:1604
    static void createPathArc(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol, const spqr_arc arc, const reduced_member_id reducedMember, SCIP_Bool reversed)
    Definition: network.c:4099
    int path_arc_id
    Definition: network.c:3438
    static void netMatDecDataFree(SCIP_NETMATDECDATA **pdec)
    Definition: network.c:1513
    static void arcSetRepresentative(SCIP_NETMATDECDATA *dec, spqr_arc arc, spqr_arc representative)
    Definition: network.c:789
    static SCIP_RETCODE constructRowReducedDecomposition(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow)
    Definition: network.c:7187
    static SCIP_RETCODE createChildMarker(SCIP_NETMATDECDATA *dec, spqr_member member, spqr_member child, SCIP_Bool isTree, spqr_arc *pArc, SCIP_Bool reversed)
    Definition: network.c:2554
    static SCIP_RETCODE transformAndMerge(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol, reduced_member_id current, reduced_member_id next, spqr_arc *representativeArc, spqr_member *mergedMember, SCIP_Bool nextIsParent, NewColInformation *info)
    Definition: network.c:6334
    static spqr_node findEffectiveArcHeadNoCompression(const SCIP_NETMATDECDATA *dec, spqr_arc arc)
    Definition: network.c:1240
    #define SPQR_INVALID_NODE
    Definition: network.c:285
    static void determineSplitTypeParallel(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, reduced_member_id reducedId, spqr_arc marker, SplitOrientation previousOrientation)
    Definition: network.c:9263
    static spqr_arc getNextMemberArc(const SCIP_NETMATDECDATA *dec, spqr_arc arc)
    Definition: network.c:1546
    static spqr_node determineAndColorSplitNode(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, reduced_member_id id, spqr_node candidateOne, spqr_node candidateTwo)
    Definition: network.c:8870
    static int getNumMemberArcs(const SCIP_NETMATDECDATA *dec, spqr_member member)
    Definition: network.c:1985
    #define MARKER_COLUMN_ELEMENT
    Definition: network.c:189
    static spqr_member mergeMembers(SCIP_NETMATDECDATA *dec, spqr_member first, spqr_member second)
    Definition: network.c:920
    static SCIP_RETCODE createParentMarker(SCIP_NETMATDECDATA *dec, spqr_member member, SCIP_Bool isTree, spqr_member parent, spqr_arc parentMarker, spqr_arc *arc, SCIP_Bool reversed)
    Definition: network.c:2574
    static SCIP_RETCODE mergeTree(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, reduced_member_id root, NewRowInformation *const newRowInfo)
    Definition: network.c:11120
    static spqr_member largestMemberID(const SCIP_NETMATDECDATA *dec)
    Definition: network.c:2518
    static void rigidConnectedColoring(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, const reduced_member_id reducedMember, const spqr_node node, SCIP_Bool *const isGood)
    Definition: network.c:8144
    static void changeArcHead(SCIP_NETMATDECDATA *dec, spqr_arc arc, spqr_node oldHead, spqr_node newHead)
    Definition: network.c:1858
    static SCIP_RETCODE createConnectedParallel(SCIP_NETMATDECDATA *dec, spqr_col *columns, SCIP_Bool *reversed, int num_columns, spqr_row row, spqr_member *pMember)
    Definition: network.c:2059
    static SCIP_RETCODE determineLeafReducedMembers(const SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow)
    Definition: network.c:7442
    static spqr_arc mergeArcSigns(SCIP_NETMATDECDATA *dec, spqr_arc first, spqr_arc second, SCIP_Bool reflectRelative)
    Definition: network.c:1285
    int spqr_element
    Definition: network.c:190
    static SCIP_Bool SPQRarcIsInvalid(spqr_arc arc)
    Definition: network.c:317
    static int getNumNodes(const SCIP_NETMATDECDATA *dec)
    Definition: network.c:2000
    static void rigidConnectedColoringRecursive(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, spqr_node articulationNode, spqr_node firstProcessNode, COLOR_STATUS firstColor, SCIP_Bool *isGood)
    Definition: network.c:8062
    static void checkRigidLeaf(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol, reduced_member_id leaf, spqr_arc toParent, reduced_member_id parent, spqr_arc toChild)
    Definition: network.c:5144
    static SCIP_RETCODE transformSingleRigid(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, const reduced_member_id reducedMember, const spqr_member member, NewRowInformation *const newRowInfo)
    Definition: network.c:9728
    static SCIP_Bool pathArcIsInvalid(const path_arc_id arc)
    Definition: network.c:3443
    static void intersectionOfAllPaths(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, const reduced_member_id toCheck, int *const nodeNumPaths)
    Definition: network.c:7831
    static void determineComponentTypes(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol, SPQRColReducedComponent *component)
    Definition: network.c:5412
    static SCIP_Bool SPQRnodeIsInvalid(spqr_node node)
    Definition: network.c:289
    static spqr_row SPQRelementToRow(spqr_element element)
    Definition: network.c:212
    static void arcSetReversed(SCIP_NETMATDECDATA *dec, spqr_arc arc, SCIP_Bool reversed)
    Definition: network.c:768
    static SCIP_Bool netMatDecDataIsMinimal(const SCIP_NETMATDECDATA *dec)
    Definition: network.c:2749
    static void clearArcHeadAndTail(SCIP_NETMATDECDATA *dec, spqr_arc arc)
    Definition: network.c:1845
    static SCIP_Bool arcIsReversedNonRigid(const SCIP_NETMATDECDATA *dec, spqr_arc arc)
    Definition: network.c:1329
    static SCIP_RETCODE transformAndMergeRigid(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol, reduced_member_id current, reduced_member_id next, spqr_member nextMember, SCIP_Bool nextIsParent, spqr_arc *representativeArc, spqr_member *mergedMember, NewColInformation *info)
    Definition: network.c:6264
    static SCIP_RETCODE newRowUpdateRowInformation(const SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, const spqr_row row, const spqr_col *columns, const double *columnValues, const int numColumns)
    Definition: network.c:7022
    static void propagateCycles(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol)
    Definition: network.c:5277
    static spqr_node checkNeighbourColoringArticulationNode(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, const spqr_node articulationNode, spqr_arc *const adjacentSplittingArc)
    Definition: network.c:8219
    static ArcSign findArcSign(SCIP_NETMATDECDATA *dec, spqr_arc arc)
    Definition: network.c:1121
    static SCIP_RETCODE createNode(SCIP_NETMATDECDATA *dec, spqr_node *pNode)
    Definition: network.c:1724
    static SCIP_RETCODE allocateRigidSearchMemory(const SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow)
    Definition: network.c:7469
    static SCIP_RETCODE netcoladdCheck(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *coladd, int column, const int *nonzrows, const double *nonzvals, int nnonzs)
    Definition: network.c:5439
    static SCIP_Bool netMatDecDataContainsRow(SCIP_NETMATDECDATA *dec, int row)
    Definition: network.c:1357
    static SCIP_Bool netcoladdRemainsNetwork(const SCIP_NETCOLADD *newCol)
    Definition: network.c:6647
    static spqr_arc getFirstMemberArc(const SCIP_NETMATDECDATA *dec, spqr_member member)
    Definition: network.c:1532
    static void determineParallelType(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, const reduced_member_id toCheckMember, const spqr_arc markerToOther, const reduced_member_id otherMember, const spqr_arc markerToCheck)
    Definition: network.c:8394
    static void changeArcTail(SCIP_NETMATDECDATA *dec, spqr_arc arc, spqr_node oldTail, spqr_node newTail)
    Definition: network.c:1874
    static SCIP_RETCODE splitAndMergeSeries(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, reduced_member_id smallMember, SCIP_Bool largeIsParent, NewRowInformation *const newRowInfo, spqr_member member)
    Definition: network.c:10656
    static spqr_arc getPreviousMemberArc(const SCIP_NETMATDECDATA *dec, spqr_arc arc)
    Definition: network.c:1561
    static spqr_arc getDecompositionColumnArc(const SCIP_NETMATDECDATA *dec, spqr_col col)
    Definition: network.c:1413
    static void cleanupPreviousIteration(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol)
    Definition: network.c:3675
    spqr_matrix_size spqr_row
    Definition: network.c:138
    static spqr_arc getNextNodeArc(SCIP_NETMATDECDATA *dec, spqr_arc arc, spqr_node node)
    Definition: network.c:641
    static spqr_arc getDecompositionRowArc(const SCIP_NETMATDECDATA *dec, spqr_row row)
    Definition: network.c:1426
    static ArcSign findArcSignNoCompression(const SCIP_NETMATDECDATA *dec, spqr_arc arc)
    Definition: network.c:1172
    static SCIP_Bool SPQRelementIsColumn(spqr_element element)
    Definition: network.c:203
    static SCIP_RETCODE netcoladdAdd(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol)
    Definition: network.c:6659
    static SCIP_RETCODE computeLeafMembers(const SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol)
    Definition: network.c:4262
    static void determineSplitTypeFirstLeaf(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, reduced_member_id reducedId)
    Definition: network.c:8958
    static reduced_member_id createRowReducedMembersToRoot(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, const spqr_member firstMember)
    Definition: network.c:7080
    static void rigidFindStarNodes(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, const reduced_member_id toCheck)
    Definition: network.c:7675
    static RowReducedMemberType determineType(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, const reduced_member_id toCheckMember, const spqr_arc markerToOther, const reduced_member_id otherMember, const spqr_arc markerToCheck)
    Definition: network.c:8537
    static spqr_col SPQRelementToColumn(spqr_element element)
    Definition: network.c:232
    static SCIP_Bool cutArcIsValid(const cut_arc_id arc)
    Definition: network.c:6784
    COLOR_STATUS
    Definition: network.c:6863
    @ COLOR_SOURCE
    Definition: network.c:6865
    @ COLOR_SINK
    Definition: network.c:6866
    @ UNCOLORED
    Definition: network.c:6864
    static SCIP_RETCODE transformAndMergeParallel(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol, reduced_member_id current, reduced_member_id next, spqr_member nextMember, SCIP_Bool nextIsParent, spqr_arc *representativeArc, spqr_member *mergedMember)
    Definition: network.c:6034
    static SCIP_RETCODE splitSeriesMerging(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol, SPQRColReducedMember *reducedMember, spqr_member member, spqr_arc *pathRepresentative, spqr_arc *nonPathRepresentative, spqr_arc exceptionArc1, spqr_arc exceptionArc2)
    Definition: network.c:5789
    static SCIP_Bool SPQRrowIsInvalid(spqr_row row)
    Definition: network.c:151
    static void setDecompositionColumnArc(SCIP_NETMATDECDATA *dec, spqr_col col, spqr_arc arc)
    Definition: network.c:1383
    static void cleanUpRowMemberInformation(SCIP_NETROWADD *newRow)
    Definition: network.c:9591
    static SCIP_RETCODE mergeSplitMemberIntoParent(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, spqr_member member, spqr_member parent, spqr_arc parentToChild, spqr_arc childToParent, SCIP_Bool headToHead, spqr_node parentNode, spqr_node childNode, spqr_member *mergedMember, spqr_node *arcNodeOne, spqr_node *arcNodeTwo, spqr_node *thirdNode)
    Definition: network.c:10577
    static SCIP_RETCODE splitParallelRowAddition(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, const reduced_member_id reducedMember, const spqr_member member, NewRowInformation *const newRowInfo)
    Definition: network.c:9864
    static SCIP_Bool arcIsRepresentative(const SCIP_NETMATDECDATA *dec, spqr_arc arc)
    Definition: network.c:1105
    static void determinePathMemberType(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol, reduced_member_id reducedMember, spqr_member member, MemberPathType previousType, spqr_arc source, spqr_arc target)
    Definition: network.c:5008
    static spqr_arc largestArcID(const SCIP_NETMATDECDATA *dec)
    Definition: network.c:2527
    static SCIP_Bool arcIsTree(const SCIP_NETMATDECDATA *dec, spqr_arc arc)
    Definition: network.c:1079
    static void determineSplitTypeSeries(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, reduced_member_id reducedId, spqr_arc marker, SplitOrientation previousOrientation)
    Definition: network.c:9213
    static void setTerminalHead(NewColInformation *info, spqr_node node)
    Definition: network.c:5502
    static SCIP_RETCODE constructReducedDecomposition(SCIP_NETMATDECDATA *dec, SCIP_NETCOLADD *newCol)
    Definition: network.c:3932
    static SCIP_Bool SPQRcolIsInvalid(spqr_col col)
    Definition: network.c:160
    static SCIP_RETCODE splitAndMerge(SCIP_NETMATDECDATA *dec, SCIP_NETROWADD *newRow, reduced_member_id smallMember, SCIP_Bool largeIsParent, NewRowInformation *const newRowInfo)
    Definition: network.c:11077
    SPQRMemberType
    Definition: network.c:335
    @ SPQR_MEMBERTYPE_RIGID
    Definition: network.c:336
    @ SPQR_MEMBERTYPE_PARALLEL
    Definition: network.c:337
    @ SPQR_MEMBERTYPE_SERIES
    Definition: network.c:338
    @ SPQR_MEMBERTYPE_UNASSIGNED
    Definition: network.c:340
    @ SPQR_MEMBERTYPE_LOOP
    Definition: network.c:339
    #define SCIPerrorMessage
    Definition: pub_message.h:64
    public data structures and miscellaneous methods
    Methods for detecting network matrices.
    SCIP callable library.
    SCIP_Bool reversed
    Definition: network.c:1095
    spqr_arc representative
    Definition: network.c:1094
    spqr_arc arc
    Definition: network.c:6846
    spqr_node node
    Definition: network.c:6845
    spqr_node arcHead
    Definition: network.c:6798
    cut_arc_id nextMember
    Definition: network.c:6800
    SCIP_Bool arcReversed
    Definition: network.c:6804
    spqr_node arcTail
    Definition: network.c:6799
    cut_arc_id nextOverall
    Definition: network.c:6802
    spqr_arc arc
    Definition: network.c:6797
    spqr_node node
    Definition: network.c:6831
    spqr_arc nodeArc
    Definition: network.c:6832
    spqr_arc arc
    Definition: network.c:2182
    SCIP_Bool reversed
    Definition: network.c:2183
    reduced_member_id reducedMember
    Definition: network.c:3597
    reduced_member_id rootDepthMinimizer
    Definition: network.c:3598
    children_idx currentChild
    Definition: network.c:6838
    reduced_member_id id
    Definition: network.c:6839
    spqr_arc representative
    Definition: network.c:5494
    spqr_node tail
    Definition: network.c:5493
    SCIP_Bool reversed
    Definition: network.c:5495
    spqr_node head
    Definition: network.c:5492
    spqr_member member
    Definition: network.c:5491
    spqr_node head
    Definition: network.c:7010
    spqr_node tail
    Definition: network.c:7011
    SCIP_Bool reversed
    Definition: network.c:7013
    spqr_member member
    Definition: network.c:7009
    spqr_arc representative
    Definition: network.c:7012
    spqr_node first
    Definition: network.c:8683
    spqr_node second
    Definition: network.c:8684
    path_arc_id nextOverall
    Definition: network.c:3470
    spqr_arc arc
    Definition: network.c:3466
    spqr_node arcHead
    Definition: network.c:3467
    spqr_node arcTail
    Definition: network.c:3468
    path_arc_id nextMember
    Definition: network.c:3469
    SCIP_Bool reversed
    Definition: network.c:3471
    int * nodeInPathDegree
    Definition: network.c:3641
    SPQRColReducedMember * reducedMembers
    Definition: network.c:3613
    int memChildrenStorage
    Definition: network.c:3632
    int numReducedMembers
    Definition: network.c:3616
    int numDecompositionRowArcs
    Definition: network.c:3666
    int memLeafMembers
    Definition: network.c:3670
    spqr_col newColIndex
    Definition: network.c:3652
    int memMemberInformation
    Definition: network.c:3625
    spqr_member * leafMembers
    Definition: network.c:3668
    SCIP_Bool * arcInPath
    Definition: network.c:3645
    int numChildrenStorage
    Definition: network.c:3633
    int memReducedMembers
    Definition: network.c:3615
    PathArcListNode * pathArcs
    Definition: network.c:3635
    MemberInfo * memberInformation
    Definition: network.c:3623
    SCIP_Bool * arcInPathReversed
    Definition: network.c:3646
    int memCreateReducedMembersCallStack
    Definition: network.c:3650
    int memArcsInPath
    Definition: network.c:3647
    SCIP_Bool remainsNetwork
    Definition: network.c:3611
    int memNewRowArcs
    Definition: network.c:3658
    int memDecompositionRowArcs
    Definition: network.c:3665
    int * nodeOutPathDegree
    Definition: network.c:3642
    int memReducedComponents
    Definition: network.c:3620
    int numNewRowArcs
    Definition: network.c:3659
    CreateReducedMembersCallstack * createReducedMembersCallStack
    Definition: network.c:3649
    path_arc_id firstOverallPathArc
    Definition: network.c:3639
    SCIP_Bool * decompositionArcReversed
    Definition: network.c:3663
    spqr_arc * decompositionRowArcs
    Definition: network.c:3661
    int memNodePathDegree
    Definition: network.c:3643
    int numMemberInformation
    Definition: network.c:3626
    int numLeafMembers
    Definition: network.c:3669
    SCIP_Bool * newRowArcReversed
    Definition: network.c:3656
    SPQRColReducedComponent * reducedComponents
    Definition: network.c:3618
    reduced_member_id * childrenStorage
    Definition: network.c:3628
    int numReducedComponents
    Definition: network.c:3621
    spqr_row * newRowArcs
    Definition: network.c:3654
    SPQRNetworkDecompositionArc * arcs
    Definition: network.c:413
    spqr_arc * columnArcs
    Definition: network.c:428
    SPQRNetworkDecompositionMember * members
    Definition: network.c:418
    spqr_arc firstFreeArc
    Definition: network.c:414
    BMS_BLKMEM * env
    Definition: network.c:430
    SPQRNetworkDecompositionNode * nodes
    Definition: network.c:422
    int numConnectedComponents
    Definition: network.c:432
    spqr_arc * rowArcs
    Definition: network.c:425
    int memCreateReducedMembersCallstack
    Definition: network.c:6990
    ArticulationNodeInformation * articulationNodeSearchInfo
    Definition: network.c:6973
    int memMergeTreeCallData
    Definition: network.c:7000
    int * crossingPathCount
    Definition: network.c:6977
    COLOR_STATUS * temporaryColorArray
    Definition: network.c:7002
    SCIP_Bool * isArcCut
    Definition: network.c:6962
    MemberInfo * memberInformation
    Definition: network.c:6926
    spqr_col * newColumnArcs
    Definition: network.c:6945
    int memArtDFSData
    Definition: network.c:6987
    SCIP_Bool * newColumnReversed
    Definition: network.c:6947
    int numArticulationNodes
    Definition: network.c:6970
    reduced_member_id * childrenStorage
    Definition: network.c:6931
    int memReducedComponents
    Definition: network.c:6923
    int memLeafMembers
    Definition: network.c:6953
    SCIP_Bool * decompositionColumnArcReversed
    Definition: network.c:6957
    int memDecompositionColumnArcs
    Definition: network.c:6959
    int memMemberInformation
    Definition: network.c:6928
    ColorDFSCallData * colorDFSData
    Definition: network.c:6983
    ArticulationPointCallStack * artDFSData
    Definition: network.c:6986
    DFSCallData * intersectionDFSData
    Definition: network.c:6980
    int memReducedMembers
    Definition: network.c:6918
    spqr_row newRowIndex
    Definition: network.c:6943
    int memIntersectionDFSData
    Definition: network.c:6981
    int memTemporaryColorArray
    Definition: network.c:7003
    SPQRRowReducedMember * reducedMembers
    Definition: network.c:6916
    int * intersectionPathDepth
    Definition: network.c:6992
    spqr_arc * decompositionColumnArcs
    Definition: network.c:6955
    int numReducedMembers
    Definition: network.c:6919
    int numLeafMembers
    Definition: network.c:6952
    COLOR_STATUS * nodeColors
    Definition: network.c:6966
    int numChildrenStorage
    Definition: network.c:6936
    int numMemberInformation
    Definition: network.c:6929
    int numColumnArcs
    Definition: network.c:6949
    int memColumnArcs
    Definition: network.c:6948
    int memNodeColors
    Definition: network.c:6967
    int memNodeSearchInfo
    Definition: network.c:6975
    int memIntersectionPathParent
    Definition: network.c:6997
    int memIntersectionPathDepth
    Definition: network.c:6993
    SPQRRowReducedComponent * reducedComponents
    Definition: network.c:6921
    CutArcListNode * cutArcs
    Definition: network.c:6938
    SCIP_Bool * isArcCutReversed
    Definition: network.c:6963
    spqr_node * articulationNodes
    Definition: network.c:6969
    int memCrossingPathCount
    Definition: network.c:6978
    int memArticulationNodes
    Definition: network.c:6971
    int memChildrenStorage
    Definition: network.c:6935
    MergeTreeCallData * mergeTreeCallData
    Definition: network.c:6999
    int numDecompositionColumnArcs
    Definition: network.c:6960
    cut_arc_id firstOverallCutArc
    Definition: network.c:6941
    SCIP_Bool remainsNetwork
    Definition: network.c:6914
    int numReducedComponents
    Definition: network.c:6924
    CreateReducedMembersCallstack * createReducedMembersCallstack
    Definition: network.c:6989
    int memColorDFSData
    Definition: network.c:6984
    reduced_member_id * leafMembers
    Definition: network.c:6951
    spqr_node * intersectionPathParent
    Definition: network.c:6995
    SCIP_NETROWADD * rowadd
    Definition: network.c:11562
    SCIP_NETMATDECDATA * dec
    Definition: network.c:11561
    SCIP_NETCOLADD * coladd
    Definition: network.c:11563
    reduced_member_id pathEndMembers[2]
    Definition: network.c:3590
    reduced_member_id root
    Definition: network.c:3588
    reduced_member_id nextPathMember
    Definition: network.c:3576
    SCIP_Bool reverseArcs
    Definition: network.c:3563
    children_idx firstChild
    Definition: network.c:3557
    spqr_node rigidPathEnd
    Definition: network.c:3565
    spqr_member member
    Definition: network.c:3551
    spqr_member rootMember
    Definition: network.c:3552
    reduced_member_id parent
    Definition: network.c:3555
    ReducedMemberType type
    Definition: network.c:3554
    path_arc_id firstPathArc
    Definition: network.c:3560
    children_idx numChildren
    Definition: network.c:3558
    spqr_arc pathTargetArc
    Definition: network.c:3581
    SCIP_Bool pathBackwards
    Definition: network.c:3567
    MemberPathType pathType
    Definition: network.c:3575
    spqr_arc pathSourceArc
    Definition: network.c:3580
    SCIP_Bool nextPathMemberIsParent
    Definition: network.c:3578
    spqr_node rigidPathStart
    Definition: network.c:3564
    SPQRNetworkDecompositionArcListNode arcListNode
    Definition: network.c:369
    SPQRNetworkDecompositionArcListNode headArcListNode
    Definition: network.c:367
    SPQRNetworkDecompositionArcListNode tailArcListNode
    Definition: network.c:368
    spqr_member representativeMember
    Definition: network.c:390
    reduced_member_id root
    Definition: network.c:6908
    RowReducedMemberType type
    Definition: network.c:6876
    children_idx numPropagatedChildren
    Definition: network.c:6881
    SCIP_Bool splitHead
    Definition: network.c:6888
    SCIP_Bool allHaveCommonNode
    Definition: network.c:6895
    spqr_node coloredNode
    Definition: network.c:6900
    SCIP_Bool willBeReversed
    Definition: network.c:6897
    children_idx numChildren
    Definition: network.c:6880
    spqr_member member
    Definition: network.c:6872
    cut_arc_id firstCutArc
    Definition: network.c:6884
    spqr_node splitNode
    Definition: network.c:6894
    SCIP_Bool otherNodeSplit
    Definition: network.c:6896
    spqr_member rootMember
    Definition: network.c:6873
    SCIP_Bool otherIsSource
    Definition: network.c:6889
    reduced_member_id parent
    Definition: network.c:6877
    spqr_arc articulationArc
    Definition: network.c:6898
    spqr_node otherNode
    Definition: network.c:6893
    children_idx firstChild
    Definition: network.c:6879
    SCIP_Bool otherIsSource
    Definition: network.c:9077
    SCIP_Bool headSplit
    Definition: network.c:9076
    @ SCIP_INVALIDDATA
    Definition: type_retcode.h:52
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    @ SCIP_ERROR
    Definition: type_retcode.h:43
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63