gravatar
deba@inf.elte.hu
deba@inf.elte.hu
Uniforming primal scale to 2 (#314)
0 2 0
default
2 files changed with 44 insertions and 25 deletions:
↑ Collapse diff ↑
Ignore white space 48 line context
... ...
@@ -637,82 +637,81 @@
637 637
  ///
638 638
  /// The maximum weighted fractional matching is a relaxation of the
639 639
  /// maximum weighted matching problem where the odd set constraints
640 640
  /// are omitted.
641 641
  /// It can be formulated with the following linear program.
642 642
  /// \f[ \sum_{e \in \delta(u)}x_e \le 1 \quad \forall u\in V\f]
643 643
  /// \f[x_e \ge 0\quad \forall e\in E\f]
644 644
  /// \f[\max \sum_{e\in E}x_ew_e\f]
645 645
  /// where \f$\delta(X)\f$ is the set of edges incident to a node in
646 646
  /// \f$X\f$. The result must be the union of a matching with one
647 647
  /// value edges and a set of odd length cycles with half value edges.
648 648
  ///
649 649
  /// The algorithm calculates an optimal fractional matching and a
650 650
  /// proof of the optimality. The solution of the dual problem can be
651 651
  /// used to check the result of the algorithm. The dual linear
652 652
  /// problem is the following.
653 653
  /// \f[ y_u + y_v \ge w_{uv} \quad \forall uv\in E\f]
654 654
  /// \f[y_u \ge 0 \quad \forall u \in V\f]
655 655
  /// \f[\min \sum_{u \in V}y_u \f]
656 656
  ///
657 657
  /// The algorithm can be executed with the run() function.
658 658
  /// After it the matching (the primal solution) and the dual solution
659 659
  /// can be obtained using the query functions.
660 660
  ///
661
  /// If the value type is integer, then the primal and the dual
662
  /// solutions are multiplied by
663
  /// \ref MaxWeightedFractionalMatching::primalScale "2" and
664
  /// \ref MaxWeightedFractionalMatching::dualScale "4" respectively.
661
  /// The primal solution is multiplied by
662
  /// \ref MaxWeightedFractionalMatching::primalScale "2".
663
  /// If the value type is integer, then the dual
664
  /// solution is scaled by
665
  /// \ref MaxWeightedFractionalMatching::dualScale "4".
665 666
  ///
666 667
  /// \tparam GR The undirected graph type the algorithm runs on.
667 668
  /// \tparam WM The type edge weight map. The default type is
668 669
  /// \ref concepts::Graph::EdgeMap "GR::EdgeMap<int>".
669 670
#ifdef DOXYGEN
670 671
  template <typename GR, typename WM>
671 672
#else
672 673
  template <typename GR,
673 674
            typename WM = typename GR::template EdgeMap<int> >
674 675
#endif
675 676
  class MaxWeightedFractionalMatching {
676 677
  public:
677 678

	
678 679
    /// The graph type of the algorithm
679 680
    typedef GR Graph;
680 681
    /// The type of the edge weight map
681 682
    typedef WM WeightMap;
682 683
    /// The value type of the edge weights
683 684
    typedef typename WeightMap::Value Value;
684 685

	
685 686
    /// The type of the matching map
686 687
    typedef typename Graph::template NodeMap<typename Graph::Arc>
687 688
    MatchingMap;
688 689

	
689 690
    /// \brief Scaling factor for primal solution
690 691
    ///
691
    /// Scaling factor for primal solution. It is equal to 2 or 1
692
    /// according to the value type.
693
    static const int primalScale =
694
      std::numeric_limits<Value>::is_integer ? 2 : 1;
692
    /// Scaling factor for primal solution.
693
    static const int primalScale = 2;
695 694

	
696 695
    /// \brief Scaling factor for dual solution
697 696
    ///
698 697
    /// Scaling factor for dual solution. It is equal to 4 or 1
699 698
    /// according to the value type.
700 699
    static const int dualScale =
701 700
      std::numeric_limits<Value>::is_integer ? 4 : 1;
702 701

	
703 702
  private:
704 703

	
705 704
    TEMPLATE_GRAPH_TYPEDEFS(Graph);
706 705

	
707 706
    typedef typename Graph::template NodeMap<Value> NodePotential;
708 707

	
709 708
    const Graph& _graph;
710 709
    const WeightMap& _weight;
711 710

	
712 711
    MatchingMap* _matching;
713 712
    NodePotential* _node_potential;
714 713

	
715 714
    int _node_num;
716 715
    bool _allow_loops;
717 716

	
718 717
    enum Status {
... ...
@@ -1308,52 +1307,51 @@
1308 1307
    }
1309 1308

	
1310 1309
    /// \brief Return the number of covered nodes in the matching.
1311 1310
    ///
1312 1311
    /// This function returns the number of covered nodes in the matching.
1313 1312
    ///
1314 1313
    /// \pre Either run() or start() must be called before using this function.
1315 1314
    int matchingSize() const {
1316 1315
      int num = 0;
1317 1316
      for (NodeIt n(_graph); n != INVALID; ++n) {
1318 1317
        if ((*_matching)[n] != INVALID) {
1319 1318
          ++num;
1320 1319
        }
1321 1320
      }
1322 1321
      return num;
1323 1322
    }
1324 1323

	
1325 1324
    /// \brief Return \c true if the given edge is in the matching.
1326 1325
    ///
1327 1326
    /// This function returns \c true if the given edge is in the
1328 1327
    /// found matching. The result is scaled by \ref primalScale
1329 1328
    /// "primal scale".
1330 1329
    ///
1331 1330
    /// \pre Either run() or start() must be called before using this function.
1332
    Value matching(const Edge& edge) const {
1333
      return Value(edge == (*_matching)[_graph.u(edge)] ? 1 : 0)
1334
        * primalScale / 2 + Value(edge == (*_matching)[_graph.v(edge)] ? 1 : 0)
1335
        * primalScale / 2;
1331
    int matching(const Edge& edge) const {
1332
      return (edge == (*_matching)[_graph.u(edge)] ? 1 : 0)
1333
        + (edge == (*_matching)[_graph.v(edge)] ? 1 : 0);
1336 1334
    }
1337 1335

	
1338 1336
    /// \brief Return the fractional matching arc (or edge) incident
1339 1337
    /// to the given node.
1340 1338
    ///
1341 1339
    /// This function returns one of the fractional matching arc (or
1342 1340
    /// edge) incident to the given node in the found matching or \c
1343 1341
    /// INVALID if the node is not covered by the matching or if the
1344 1342
    /// node is on an odd length cycle then it is the successor edge
1345 1343
    /// on the cycle.
1346 1344
    ///
1347 1345
    /// \pre Either run() or start() must be called before using this function.
1348 1346
    Arc matching(const Node& node) const {
1349 1347
      return (*_matching)[node];
1350 1348
    }
1351 1349

	
1352 1350
    /// \brief Return a const reference to the matching map.
1353 1351
    ///
1354 1352
    /// This function returns a const reference to a node map that stores
1355 1353
    /// the matching arc (or edge) incident to each node.
1356 1354
    const MatchingMap& matchingMap() const {
1357 1355
      return *_matching;
1358 1356
    }
1359 1357

	
... ...
@@ -1402,83 +1400,82 @@
1402 1400
  /// matching algorithm. The implementation uses priority queues and
1403 1401
  /// provides \f$O(nm\log n)\f$ time complexity.
1404 1402
  ///
1405 1403
  /// The maximum weighted fractional perfect matching is a relaxation
1406 1404
  /// of the maximum weighted perfect matching problem where the odd
1407 1405
  /// set constraints are omitted.
1408 1406
  /// It can be formulated with the following linear program.
1409 1407
  /// \f[ \sum_{e \in \delta(u)}x_e = 1 \quad \forall u\in V\f]
1410 1408
  /// \f[x_e \ge 0\quad \forall e\in E\f]
1411 1409
  /// \f[\max \sum_{e\in E}x_ew_e\f]
1412 1410
  /// where \f$\delta(X)\f$ is the set of edges incident to a node in
1413 1411
  /// \f$X\f$. The result must be the union of a matching with one
1414 1412
  /// value edges and a set of odd length cycles with half value edges.
1415 1413
  ///
1416 1414
  /// The algorithm calculates an optimal fractional matching and a
1417 1415
  /// proof of the optimality. The solution of the dual problem can be
1418 1416
  /// used to check the result of the algorithm. The dual linear
1419 1417
  /// problem is the following.
1420 1418
  /// \f[ y_u + y_v \ge w_{uv} \quad \forall uv\in E\f]
1421 1419
  /// \f[\min \sum_{u \in V}y_u \f]
1422 1420
  ///
1423 1421
  /// The algorithm can be executed with the run() function.
1424 1422
  /// After it the matching (the primal solution) and the dual solution
1425 1423
  /// can be obtained using the query functions.
1426

	
1427
  /// If the value type is integer, then the primal and the dual
1428
  /// solutions are multiplied by
1429
  /// \ref MaxWeightedPerfectFractionalMatching::primalScale "2" and
1430
  /// \ref MaxWeightedPerfectFractionalMatching::dualScale "4" respectively.
1424
  ///
1425
  /// The primal solution is multiplied by
1426
  /// \ref MaxWeightedPerfectFractionalMatching::primalScale "2".
1427
  /// If the value type is integer, then the dual
1428
  /// solution is scaled by
1429
  /// \ref MaxWeightedPerfectFractionalMatching::dualScale "4".
1431 1430
  ///
1432 1431
  /// \tparam GR The undirected graph type the algorithm runs on.
1433 1432
  /// \tparam WM The type edge weight map. The default type is
1434 1433
  /// \ref concepts::Graph::EdgeMap "GR::EdgeMap<int>".
1435 1434
#ifdef DOXYGEN
1436 1435
  template <typename GR, typename WM>
1437 1436
#else
1438 1437
  template <typename GR,
1439 1438
            typename WM = typename GR::template EdgeMap<int> >
1440 1439
#endif
1441 1440
  class MaxWeightedPerfectFractionalMatching {
1442 1441
  public:
1443 1442

	
1444 1443
    /// The graph type of the algorithm
1445 1444
    typedef GR Graph;
1446 1445
    /// The type of the edge weight map
1447 1446
    typedef WM WeightMap;
1448 1447
    /// The value type of the edge weights
1449 1448
    typedef typename WeightMap::Value Value;
1450 1449

	
1451 1450
    /// The type of the matching map
1452 1451
    typedef typename Graph::template NodeMap<typename Graph::Arc>
1453 1452
    MatchingMap;
1454 1453

	
1455 1454
    /// \brief Scaling factor for primal solution
1456 1455
    ///
1457
    /// Scaling factor for primal solution. It is equal to 2 or 1
1458
    /// according to the value type.
1459
    static const int primalScale =
1460
      std::numeric_limits<Value>::is_integer ? 2 : 1;
1456
    /// Scaling factor for primal solution.
1457
    static const int primalScale = 2;
1461 1458

	
1462 1459
    /// \brief Scaling factor for dual solution
1463 1460
    ///
1464 1461
    /// Scaling factor for dual solution. It is equal to 4 or 1
1465 1462
    /// according to the value type.
1466 1463
    static const int dualScale =
1467 1464
      std::numeric_limits<Value>::is_integer ? 4 : 1;
1468 1465

	
1469 1466
  private:
1470 1467

	
1471 1468
    TEMPLATE_GRAPH_TYPEDEFS(Graph);
1472 1469

	
1473 1470
    typedef typename Graph::template NodeMap<Value> NodePotential;
1474 1471

	
1475 1472
    const Graph& _graph;
1476 1473
    const WeightMap& _weight;
1477 1474

	
1478 1475
    MatchingMap* _matching;
1479 1476
    NodePotential* _node_potential;
1480 1477

	
1481 1478
    int _node_num;
1482 1479
    bool _allow_loops;
1483 1480

	
1484 1481
    enum Status {
... ...
@@ -2043,52 +2040,51 @@
2043 2040
    }
2044 2041

	
2045 2042
    /// \brief Return the number of covered nodes in the matching.
2046 2043
    ///
2047 2044
    /// This function returns the number of covered nodes in the matching.
2048 2045
    ///
2049 2046
    /// \pre Either run() or start() must be called before using this function.
2050 2047
    int matchingSize() const {
2051 2048
      int num = 0;
2052 2049
      for (NodeIt n(_graph); n != INVALID; ++n) {
2053 2050
        if ((*_matching)[n] != INVALID) {
2054 2051
          ++num;
2055 2052
        }
2056 2053
      }
2057 2054
      return num;
2058 2055
    }
2059 2056

	
2060 2057
    /// \brief Return \c true if the given edge is in the matching.
2061 2058
    ///
2062 2059
    /// This function returns \c true if the given edge is in the
2063 2060
    /// found matching. The result is scaled by \ref primalScale
2064 2061
    /// "primal scale".
2065 2062
    ///
2066 2063
    /// \pre Either run() or start() must be called before using this function.
2067
    Value matching(const Edge& edge) const {
2068
      return Value(edge == (*_matching)[_graph.u(edge)] ? 1 : 0)
2069
        * primalScale / 2 + Value(edge == (*_matching)[_graph.v(edge)] ? 1 : 0)
2070
        * primalScale / 2;
2064
    int matching(const Edge& edge) const {
2065
      return (edge == (*_matching)[_graph.u(edge)] ? 1 : 0)
2066
        + (edge == (*_matching)[_graph.v(edge)] ? 1 : 0);
2071 2067
    }
2072 2068

	
2073 2069
    /// \brief Return the fractional matching arc (or edge) incident
2074 2070
    /// to the given node.
2075 2071
    ///
2076 2072
    /// This function returns one of the fractional matching arc (or
2077 2073
    /// edge) incident to the given node in the found matching or \c
2078 2074
    /// INVALID if the node is not covered by the matching or if the
2079 2075
    /// node is on an odd length cycle then it is the successor edge
2080 2076
    /// on the cycle.
2081 2077
    ///
2082 2078
    /// \pre Either run() or start() must be called before using this function.
2083 2079
    Arc matching(const Node& node) const {
2084 2080
      return (*_matching)[node];
2085 2081
    }
2086 2082

	
2087 2083
    /// \brief Return a const reference to the matching map.
2088 2084
    ///
2089 2085
    /// This function returns a const reference to a node map that stores
2090 2086
    /// the matching arc (or edge) incident to each node.
2091 2087
    const MatchingMap& matchingMap() const {
2092 2088
      return *_matching;
2093 2089
    }
2094 2090

	
Ignore white space 6 line context
... ...
@@ -215,96 +215,107 @@
215 215
  const_mat_test.dualValue();
216 216
  const_mat_test.nodeValue(n);
217 217
}
218 218

	
219 219
void checkFractionalMatching(const SmartGraph& graph,
220 220
                             const MaxFractionalMatching<SmartGraph>& mfm,
221 221
                             bool allow_loops = true) {
222 222
  int pv = 0;
223 223
  for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
224 224
    int indeg = 0;
225 225
    for (InArcIt a(graph, n); a != INVALID; ++a) {
226 226
      if (mfm.matching(graph.source(a)) == a) {
227 227
        ++indeg;
228 228
      }
229 229
    }
230 230
    if (mfm.matching(n) != INVALID) {
231 231
      check(indeg == 1, "Invalid matching");
232 232
      ++pv;
233 233
    } else {
234 234
      check(indeg == 0, "Invalid matching");
235 235
    }
236 236
  }
237 237
  check(pv == mfm.matchingSize(), "Wrong matching size");
238 238

	
239
  for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) {
240
    check((e == mfm.matching(graph.u(e)) ? 1 : 0) +
241
          (e == mfm.matching(graph.v(e)) ? 1 : 0) == 
242
          mfm.matching(e), "Invalid matching");
243
  }
244

	
239 245
  SmartGraph::NodeMap<bool> processed(graph, false);
240 246
  for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
241 247
    if (processed[n]) continue;
242 248
    processed[n] = true;
243 249
    if (mfm.matching(n) == INVALID) continue;
244 250
    int num = 1;
245 251
    Node v = graph.target(mfm.matching(n));
246 252
    while (v != n) {
247 253
      processed[v] = true;
248 254
      ++num;
249 255
      v = graph.target(mfm.matching(v));
250 256
    }
251 257
    check(num == 2 || num % 2 == 1, "Wrong cycle size");
252 258
    check(allow_loops || num != 1, "Wrong cycle size");
253 259
  }
254 260

	
255 261
  int anum = 0, bnum = 0;
256 262
  SmartGraph::NodeMap<bool> neighbours(graph, false);
257 263
  for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
258 264
    if (!mfm.barrier(n)) continue;
259 265
    ++anum;
260 266
    for (SmartGraph::InArcIt a(graph, n); a != INVALID; ++a) {
261 267
      Node u = graph.source(a);
262 268
      if (!allow_loops && u == n) continue;
263 269
      if (!neighbours[u]) {
264 270
        neighbours[u] = true;
265 271
        ++bnum;
266 272
      }
267 273
    }
268 274
  }
269 275
  check(anum - bnum + mfm.matchingSize() == countNodes(graph),
270 276
        "Wrong barrier");
271 277
}
272 278

	
273 279
void checkPerfectFractionalMatching(const SmartGraph& graph,
274 280
                             const MaxFractionalMatching<SmartGraph>& mfm,
275 281
                             bool perfect, bool allow_loops = true) {
276 282
  if (perfect) {
277 283
    for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
278 284
      int indeg = 0;
279 285
      for (InArcIt a(graph, n); a != INVALID; ++a) {
280 286
        if (mfm.matching(graph.source(a)) == a) {
281 287
          ++indeg;
282 288
        }
283 289
      }
284 290
      check(mfm.matching(n) != INVALID, "Invalid matching");
285 291
      check(indeg == 1, "Invalid matching");
286 292
    }
293
    for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) {
294
      check((e == mfm.matching(graph.u(e)) ? 1 : 0) +
295
            (e == mfm.matching(graph.v(e)) ? 1 : 0) == 
296
            mfm.matching(e), "Invalid matching");
297
    }
287 298
  } else {
288 299
    int anum = 0, bnum = 0;
289 300
    SmartGraph::NodeMap<bool> neighbours(graph, false);
290 301
    for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
291 302
      if (!mfm.barrier(n)) continue;
292 303
      ++anum;
293 304
      for (SmartGraph::InArcIt a(graph, n); a != INVALID; ++a) {
294 305
        Node u = graph.source(a);
295 306
        if (!allow_loops && u == n) continue;
296 307
        if (!neighbours[u]) {
297 308
          neighbours[u] = true;
298 309
          ++bnum;
299 310
        }
300 311
      }
301 312
    }
302 313
    check(anum - bnum > 0, "Wrong barrier");
303 314
  }
304 315
}
305 316

	
306 317
void checkWeightedFractionalMatching(const SmartGraph& graph,
307 318
                   const SmartGraph::EdgeMap<int>& weight,
308 319
                   const MaxWeightedFractionalMatching<SmartGraph>& mwfm,
309 320
                   bool allow_loops = true) {
310 321
  for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) {
... ...
@@ -316,48 +327,54 @@
316 327
    check(rw == 0 || !mwfm.matching(e),
317 328
          "Non-zero reduced weight on matching edge");
318 329
  }
319 330

	
320 331
  int pv = 0;
321 332
  for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
322 333
    int indeg = 0;
323 334
    for (InArcIt a(graph, n); a != INVALID; ++a) {
324 335
      if (mwfm.matching(graph.source(a)) == a) {
325 336
        ++indeg;
326 337
      }
327 338
    }
328 339
    check(indeg <= 1, "Invalid matching");
329 340
    if (mwfm.matching(n) != INVALID) {
330 341
      check(mwfm.nodeValue(n) >= 0, "Invalid node value");
331 342
      check(indeg == 1, "Invalid matching");
332 343
      pv += weight[mwfm.matching(n)];
333 344
      SmartGraph::Node o = graph.target(mwfm.matching(n));
334 345
    } else {
335 346
      check(mwfm.nodeValue(n) == 0, "Invalid matching");
336 347
      check(indeg == 0, "Invalid matching");
337 348
    }
338 349
  }
339 350

	
351
  for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) {
352
    check((e == mwfm.matching(graph.u(e)) ? 1 : 0) +
353
          (e == mwfm.matching(graph.v(e)) ? 1 : 0) == 
354
          mwfm.matching(e), "Invalid matching");
355
  }
356

	
340 357
  int dv = 0;
341 358
  for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
342 359
    dv += mwfm.nodeValue(n);
343 360
  }
344 361

	
345 362
  check(pv * mwfm.dualScale == dv * 2, "Wrong duality");
346 363

	
347 364
  SmartGraph::NodeMap<bool> processed(graph, false);
348 365
  for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
349 366
    if (processed[n]) continue;
350 367
    processed[n] = true;
351 368
    if (mwfm.matching(n) == INVALID) continue;
352 369
    int num = 1;
353 370
    Node v = graph.target(mwfm.matching(n));
354 371
    while (v != n) {
355 372
      processed[v] = true;
356 373
      ++num;
357 374
      v = graph.target(mwfm.matching(v));
358 375
    }
359 376
    check(num == 2 || num % 2 == 1, "Wrong cycle size");
360 377
    check(allow_loops || num != 1, "Wrong cycle size");
361 378
  }
362 379

	
363 380
  return;
... ...
@@ -370,48 +387,54 @@
370 387
  for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) {
371 388
    if (graph.u(e) == graph.v(e) && !allow_loops) continue;
372 389
    int rw = mwpfm.nodeValue(graph.u(e)) + mwpfm.nodeValue(graph.v(e))
373 390
      - weight[e] * mwpfm.dualScale;
374 391

	
375 392
    check(rw >= 0, "Negative reduced weight");
376 393
    check(rw == 0 || !mwpfm.matching(e),
377 394
          "Non-zero reduced weight on matching edge");
378 395
  }
379 396

	
380 397
  int pv = 0;
381 398
  for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
382 399
    int indeg = 0;
383 400
    for (InArcIt a(graph, n); a != INVALID; ++a) {
384 401
      if (mwpfm.matching(graph.source(a)) == a) {
385 402
        ++indeg;
386 403
      }
387 404
    }
388 405
    check(mwpfm.matching(n) != INVALID, "Invalid perfect matching");
389 406
    check(indeg == 1, "Invalid perfect matching");
390 407
    pv += weight[mwpfm.matching(n)];
391 408
    SmartGraph::Node o = graph.target(mwpfm.matching(n));
392 409
  }
393 410

	
411
  for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) {
412
    check((e == mwpfm.matching(graph.u(e)) ? 1 : 0) +
413
          (e == mwpfm.matching(graph.v(e)) ? 1 : 0) == 
414
          mwpfm.matching(e), "Invalid matching");
415
  }
416

	
394 417
  int dv = 0;
395 418
  for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
396 419
    dv += mwpfm.nodeValue(n);
397 420
  }
398 421

	
399 422
  check(pv * mwpfm.dualScale == dv * 2, "Wrong duality");
400 423

	
401 424
  SmartGraph::NodeMap<bool> processed(graph, false);
402 425
  for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
403 426
    if (processed[n]) continue;
404 427
    processed[n] = true;
405 428
    if (mwpfm.matching(n) == INVALID) continue;
406 429
    int num = 1;
407 430
    Node v = graph.target(mwpfm.matching(n));
408 431
    while (v != n) {
409 432
      processed[v] = true;
410 433
      ++num;
411 434
      v = graph.target(mwpfm.matching(v));
412 435
    }
413 436
    check(num == 2 || num % 2 == 1, "Wrong cycle size");
414 437
    check(allow_loops || num != 1, "Wrong cycle size");
415 438
  }
416 439

	
417 440
  return;
0 comments (0 inline)