1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
|
/* ========================================================================== */
/* === Source/Mongoose_BoundaryHeap.cpp ===================================== */
/* ========================================================================== */
/* -----------------------------------------------------------------------------
* Mongoose Graph Partitioning Library Copyright (C) 2017-2018,
* Scott P. Kolodziej, Nuri S. Yeralan, Timothy A. Davis, William W. Hager
* Mongoose is licensed under Version 3 of the GNU General Public License.
* Mongoose is also available under other licenses; contact authors for details.
* -------------------------------------------------------------------------- */
#include "Mongoose_BoundaryHeap.hpp"
#include "Mongoose_CutCost.hpp"
#include "Mongoose_Debug.hpp"
#include "Mongoose_Internal.hpp"
#include "Mongoose_Logger.hpp"
namespace Mongoose
{
//-----------------------------------------------------------------------------
// This function inserts the specified vertex into the graph
//-----------------------------------------------------------------------------
void bhLoad(EdgeCutProblem *graph, const EdgeCut_Options *options)
{
/* Load the boundary heaps. */
Int n = graph->n;
Int *Gp = graph->p;
Int *Gi = graph->i;
double *Gx = graph->x;
double *Gw = graph->w;
bool *partition = graph->partition;
double *gains = graph->vertexGains;
Int *externalDegree = graph->externalDegree;
/* Keep track of the cut cost. */
CutCost cost;
cost.heuCost = 0.0;
cost.cutCost = 0.0;
cost.W[0] = 0.0;
cost.W[1] = 0.0;
cost.imbalance = 0.0;
/* Compute the gains & discover if the vertex is on the boundary. */
for (Int k = 0; k < n; k++)
{
bool kPartition = partition[k];
cost.W[kPartition] += (Gw) ? Gw[k] : 1;
double gain = 0.0;
Int exD = 0;
for (Int p = Gp[k]; p < Gp[k + 1]; p++)
{
double edgeWeight = (Gx) ? Gx[p] : 1;
bool onSameSide = (kPartition == partition[Gi[p]]);
gain += (onSameSide ? -edgeWeight : edgeWeight);
if (!onSameSide)
{
exD++;
cost.cutCost += edgeWeight;
}
}
gains[k] = gain;
externalDegree[k] = exD;
if (exD > 0)
bhInsert(graph, k);
}
/* Save the cut cost to the graph. */
graph->cutCost = cost.cutCost;
graph->W0 = cost.W[0];
graph->W1 = cost.W[1];
double targetSplit = options->target_split;
ASSERT(targetSplit > 0);
ASSERT(targetSplit <= 0.5);
graph->imbalance = targetSplit - std::min(graph->W0, graph->W1) / graph->W;
graph->heuCost = (graph->cutCost
+ (fabs(graph->imbalance) > options->soft_split_tolerance
? fabs(graph->imbalance) * graph->H
: 0.0));
}
//-----------------------------------------------------------------------------
// This function inserts the specified vertex into the graph's boundary heap
//-----------------------------------------------------------------------------
void bhInsert(EdgeCutProblem *graph, Int vertex)
{
/* Unpack structures */
Int vp = graph->partition[vertex];
Int *bhHeap = graph->bhHeap[vp];
Int size = graph->bhSize[vp];
double *gains = graph->vertexGains;
bhHeap[size] = vertex;
graph->BH_putIndex(vertex, size);
heapifyUp(graph, bhHeap, gains, vertex, size, gains[vertex]);
/* Save the size. */
graph->bhSize[vp] = size + 1;
}
//-----------------------------------------------------------------------------
// Removes the specified vertex from its heap.
// To do this, we swap the last element in the heap with the element we
// want to remove. Then we heapify up and heapify down.
//-----------------------------------------------------------------------------
void bhRemove(EdgeCutProblem *graph, const EdgeCut_Options *options, Int vertex, double gain,
bool partition, Int bhPosition)
{
(void)options; // Unused variable
(void)gain; // Unused variable
double *gains = graph->vertexGains;
Int *bhIndex = graph->bhIndex;
Int *bhHeap = graph->bhHeap[partition];
Int size = (--graph->bhSize[partition]);
/* If we removed the last position in the heap, there's nothing to do. */
if (bhPosition == size)
{
bhIndex[vertex] = 0;
return;
}
/* Replace the vertex with the last element in the heap. */
Int v = bhHeap[bhPosition] = bhHeap[size];
graph->BH_putIndex(v, bhPosition);
/* Finish the delete of "vertex" from the heap. */
bhIndex[vertex] = 0;
/* Bubble up then bubble down with a reread of v because it may have
* changed during heapifyUp. */
heapifyUp(graph, bhHeap, gains, v, bhPosition, gains[v]);
v = bhHeap[bhPosition];
heapifyDown(graph, bhHeap, size, gains, v, bhPosition, gains[v]);
}
//-----------------------------------------------------------------------------
// Starting at a position, this function will heapify from a vertex upwards
//-----------------------------------------------------------------------------
void heapifyUp(EdgeCutProblem *graph, Int *bhHeap, double *gains, Int vertex,
Int position, double gain)
{
if (position == 0)
return;
Int posParent = graph->BH_getParent(position);
Int pVertex = bhHeap[posParent];
double pGain = gains[pVertex];
/* If we need to swap this vertex with the parent then: */
if (pGain < gain)
{
bhHeap[posParent] = vertex;
bhHeap[position] = pVertex;
graph->BH_putIndex(vertex, posParent);
graph->BH_putIndex(pVertex, position);
heapifyUp(graph, bhHeap, gains, vertex, posParent, gain);
}
}
//-----------------------------------------------------------------------------
// Starting at a position, this function will heapify from a vertex downwards
//-----------------------------------------------------------------------------
void heapifyDown(EdgeCutProblem *graph, Int *bhHeap, Int size, double *gains, Int vertex,
Int position, double gain)
{
if (position >= size)
return;
Int lp = graph->BH_getLeftChild(position);
Int rp = graph->BH_getRightChild(position);
Int lv = (lp < size ? bhHeap[lp] : -1);
Int rv = (rp < size ? bhHeap[rp] : -1);
double lg = (lv >= 0 ? gains[lv] : -INFINITY);
double rg = (rv >= 0 ? gains[rv] : -INFINITY);
if (gain < lg || gain < rg)
{
if (lg > rg)
{
bhHeap[position] = lv;
graph->BH_putIndex(lv, position);
bhHeap[lp] = vertex;
graph->BH_putIndex(vertex, lp);
heapifyDown(graph, bhHeap, size, gains, vertex, lp, gain);
}
else
{
bhHeap[position] = rv;
graph->BH_putIndex(rv, position);
bhHeap[rp] = vertex;
graph->BH_putIndex(vertex, rp);
heapifyDown(graph, bhHeap, size, gains, vertex, rp, gain);
}
}
}
} // end namespace Mongoose
|