gravatar
kpeter (Peter Kovacs)
kpeter@inf.elte.hu
Add a heuristic algorithm for the max clique problem (#380)
0 5 2
default
7 files changed with 879 insertions and 2 deletions:
↑ Collapse diff ↑
Ignore white space 6 line context
1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2
 *
3
 * This file is a part of LEMON, a generic C++ optimization library.
4
 *
5
 * Copyright (C) 2003-2010
6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8
 *
9
 * Permission to use, modify and distribute this software is granted
10
 * provided that this copyright notice appears in all copies. For
11
 * precise terms see the accompanying LICENSE file.
12
 *
13
 * This software is provided "AS IS" with no warranty of any kind,
14
 * express or implied, and with no claim as to its suitability for any
15
 * purpose.
16
 *
17
 */
18

	
19
#ifndef LEMON_GROSSO_LOCATELLI_PULLAN_MC_H
20
#define LEMON_GROSSO_LOCATELLI_PULLAN_MC_H
21

	
22
/// \ingroup approx_algs
23
///
24
/// \file
25
/// \brief The iterated local search algorithm of Grosso, Locatelli, and Pullan
26
/// for the maximum clique problem
27

	
28
#include <vector>
29
#include <limits>
30
#include <lemon/core.h>
31
#include <lemon/random.h>
32

	
33
namespace lemon {
34

	
35
  /// \addtogroup approx_algs
36
  /// @{
37

	
38
  /// \brief Implementation of the iterated local search algorithm of Grosso,
39
  /// Locatelli, and Pullan for the maximum clique problem
40
  ///
41
  /// \ref GrossoLocatelliPullanMc implements the iterated local search
42
  /// algorithm of Grosso, Locatelli, and Pullan for solving the \e maximum
43
  /// \e clique \e problem \ref grosso08maxclique.
44
  /// It is to find the largest complete subgraph (\e clique) in an
45
  /// undirected graph, i.e., the largest set of nodes where each
46
  /// pair of nodes is connected.
47
  ///
48
  /// This class provides a simple but highly efficient and robust heuristic
49
  /// method that quickly finds a large clique, but not necessarily the
50
  /// largest one.
51
  ///
52
  /// \tparam GR The undirected graph type the algorithm runs on.
53
  ///
54
  /// \note %GrossoLocatelliPullanMc provides three different node selection
55
  /// rules, from which the most powerful one is used by default.
56
  /// For more information, see \ref SelectionRule.
57
  template <typename GR>
58
  class GrossoLocatelliPullanMc
59
  {
60
  public:
61

	
62
    /// \brief Constants for specifying the node selection rule.
63
    ///
64
    /// Enum type containing constants for specifying the node selection rule
65
    /// for the \ref run() function.
66
    ///
67
    /// During the algorithm, nodes are selected for addition to the current
68
    /// clique according to the applied rule.
69
    /// In general, the PENALTY_BASED rule turned out to be the most powerful
70
    /// and the most robust, thus it is the default option.
71
    /// However, another selection rule can be specified using the \ref run()
72
    /// function with the proper parameter.
73
    enum SelectionRule {
74

	
75
      /// A node is selected randomly without any evaluation at each step.
76
      RANDOM,
77

	
78
      /// A node of maximum degree is selected randomly at each step.
79
      DEGREE_BASED,
80

	
81
      /// A node of minimum penalty is selected randomly at each step.
82
      /// The node penalties are updated adaptively after each stage of the
83
      /// search process.
84
      PENALTY_BASED
85
    };
86

	
87
  private:
88

	
89
    TEMPLATE_GRAPH_TYPEDEFS(GR);
90

	
91
    typedef std::vector<int> IntVector;
92
    typedef std::vector<char> BoolVector;
93
    typedef std::vector<BoolVector> BoolMatrix;
94
    // Note: vector<char> is used instead of vector<bool> for efficiency reasons
95

	
96
    const GR &_graph;
97
    IntNodeMap _id;
98

	
99
    // Internal matrix representation of the graph
100
    BoolMatrix _gr;
101
    int _n;
102

	
103
    // The current clique
104
    BoolVector _clique;
105
    int _size;
106

	
107
    // The best clique found so far
108
    BoolVector _best_clique;
109
    int _best_size;
110

	
111
    // The "distances" of the nodes from the current clique.
112
    // _delta[u] is the number of nodes in the clique that are
113
    // not connected with u.
114
    IntVector _delta;
115

	
116
    // The current tabu set
117
    BoolVector _tabu;
118

	
119
    // Random number generator
120
    Random _rnd;
121

	
122
  private:
123

	
124
    // Implementation of the RANDOM node selection rule.
125
    class RandomSelectionRule
126
    {
127
    private:
128

	
129
      // References to the algorithm instance
130
      const BoolVector &_clique;
131
      const IntVector  &_delta;
132
      const BoolVector &_tabu;
133
      Random &_rnd;
134

	
135
      // Pivot rule data
136
      int _n;
137

	
138
    public:
139

	
140
      // Constructor
141
      RandomSelectionRule(GrossoLocatelliPullanMc &mc) :
142
        _clique(mc._clique), _delta(mc._delta), _tabu(mc._tabu),
143
        _rnd(mc._rnd), _n(mc._n)
144
      {}
145

	
146
      // Return a node index for a feasible add move or -1 if no one exists
147
      int nextFeasibleAddNode() const {
148
        int start_node = _rnd[_n];
149
        for (int i = start_node; i != _n; i++) {
150
          if (_delta[i] == 0 && !_tabu[i]) return i;
151
        }
152
        for (int i = 0; i != start_node; i++) {
153
          if (_delta[i] == 0 && !_tabu[i]) return i;
154
        }
155
        return -1;
156
      }
157

	
158
      // Return a node index for a feasible swap move or -1 if no one exists
159
      int nextFeasibleSwapNode() const {
160
        int start_node = _rnd[_n];
161
        for (int i = start_node; i != _n; i++) {
162
          if (!_clique[i] && _delta[i] == 1 && !_tabu[i]) return i;
163
        }
164
        for (int i = 0; i != start_node; i++) {
165
          if (!_clique[i] && _delta[i] == 1 && !_tabu[i]) return i;
166
        }
167
        return -1;
168
      }
169

	
170
      // Return a node index for an add move or -1 if no one exists
171
      int nextAddNode() const {
172
        int start_node = _rnd[_n];
173
        for (int i = start_node; i != _n; i++) {
174
          if (_delta[i] == 0) return i;
175
        }
176
        for (int i = 0; i != start_node; i++) {
177
          if (_delta[i] == 0) return i;
178
        }
179
        return -1;
180
      }
181

	
182
      // Update internal data structures between stages (if necessary)
183
      void update() {}
184

	
185
    }; //class RandomSelectionRule
186

	
187

	
188
    // Implementation of the DEGREE_BASED node selection rule.
189
    class DegreeBasedSelectionRule
190
    {
191
    private:
192

	
193
      // References to the algorithm instance
194
      const BoolVector &_clique;
195
      const IntVector  &_delta;
196
      const BoolVector &_tabu;
197
      Random &_rnd;
198

	
199
      // Pivot rule data
200
      int _n;
201
      IntVector _deg;
202

	
203
    public:
204

	
205
      // Constructor
206
      DegreeBasedSelectionRule(GrossoLocatelliPullanMc &mc) :
207
        _clique(mc._clique), _delta(mc._delta), _tabu(mc._tabu),
208
        _rnd(mc._rnd), _n(mc._n), _deg(_n)
209
      {
210
        for (int i = 0; i != _n; i++) {
211
          int d = 0;
212
          BoolVector &row = mc._gr[i];
213
          for (int j = 0; j != _n; j++) {
214
            if (row[j]) d++;
215
          }
216
          _deg[i] = d;
217
        }
218
      }
219

	
220
      // Return a node index for a feasible add move or -1 if no one exists
221
      int nextFeasibleAddNode() const {
222
        int start_node = _rnd[_n];
223
        int node = -1, max_deg = -1;
224
        for (int i = start_node; i != _n; i++) {
225
          if (_delta[i] == 0 && !_tabu[i] && _deg[i] > max_deg) {
226
            node = i;
227
            max_deg = _deg[i];
228
          }
229
        }
230
        for (int i = 0; i != start_node; i++) {
231
          if (_delta[i] == 0 && !_tabu[i] && _deg[i] > max_deg) {
232
            node = i;
233
            max_deg = _deg[i];
234
          }
235
        }
236
        return node;
237
      }
238

	
239
      // Return a node index for a feasible swap move or -1 if no one exists
240
      int nextFeasibleSwapNode() const {
241
        int start_node = _rnd[_n];
242
        int node = -1, max_deg = -1;
243
        for (int i = start_node; i != _n; i++) {
244
          if (!_clique[i] && _delta[i] == 1 && !_tabu[i] &&
245
              _deg[i] > max_deg) {
246
            node = i;
247
            max_deg = _deg[i];
248
          }
249
        }
250
        for (int i = 0; i != start_node; i++) {
251
          if (!_clique[i] && _delta[i] == 1 && !_tabu[i] &&
252
              _deg[i] > max_deg) {
253
            node = i;
254
            max_deg = _deg[i];
255
          }
256
        }
257
        return node;
258
      }
259

	
260
      // Return a node index for an add move or -1 if no one exists
261
      int nextAddNode() const {
262
        int start_node = _rnd[_n];
263
        int node = -1, max_deg = -1;
264
        for (int i = start_node; i != _n; i++) {
265
          if (_delta[i] == 0 && _deg[i] > max_deg) {
266
            node = i;
267
            max_deg = _deg[i];
268
          }
269
        }
270
        for (int i = 0; i != start_node; i++) {
271
          if (_delta[i] == 0 && _deg[i] > max_deg) {
272
            node = i;
273
            max_deg = _deg[i];
274
          }
275
        }
276
        return node;
277
      }
278

	
279
      // Update internal data structures between stages (if necessary)
280
      void update() {}
281

	
282
    }; //class DegreeBasedSelectionRule
283

	
284

	
285
    // Implementation of the PENALTY_BASED node selection rule.
286
    class PenaltyBasedSelectionRule
287
    {
288
    private:
289

	
290
      // References to the algorithm instance
291
      const BoolVector &_clique;
292
      const IntVector  &_delta;
293
      const BoolVector &_tabu;
294
      Random &_rnd;
295

	
296
      // Pivot rule data
297
      int _n;
298
      IntVector _penalty;
299

	
300
    public:
301

	
302
      // Constructor
303
      PenaltyBasedSelectionRule(GrossoLocatelliPullanMc &mc) :
304
        _clique(mc._clique), _delta(mc._delta), _tabu(mc._tabu),
305
        _rnd(mc._rnd), _n(mc._n), _penalty(_n, 0)
306
      {}
307

	
308
      // Return a node index for a feasible add move or -1 if no one exists
309
      int nextFeasibleAddNode() const {
310
        int start_node = _rnd[_n];
311
        int node = -1, min_p = std::numeric_limits<int>::max();
312
        for (int i = start_node; i != _n; i++) {
313
          if (_delta[i] == 0 && !_tabu[i] && _penalty[i] < min_p) {
314
            node = i;
315
            min_p = _penalty[i];
316
          }
317
        }
318
        for (int i = 0; i != start_node; i++) {
319
          if (_delta[i] == 0 && !_tabu[i] && _penalty[i] < min_p) {
320
            node = i;
321
            min_p = _penalty[i];
322
          }
323
        }
324
        return node;
325
      }
326

	
327
      // Return a node index for a feasible swap move or -1 if no one exists
328
      int nextFeasibleSwapNode() const {
329
        int start_node = _rnd[_n];
330
        int node = -1, min_p = std::numeric_limits<int>::max();
331
        for (int i = start_node; i != _n; i++) {
332
          if (!_clique[i] && _delta[i] == 1 && !_tabu[i] &&
333
              _penalty[i] < min_p) {
334
            node = i;
335
            min_p = _penalty[i];
336
          }
337
        }
338
        for (int i = 0; i != start_node; i++) {
339
          if (!_clique[i] && _delta[i] == 1 && !_tabu[i] &&
340
              _penalty[i] < min_p) {
341
            node = i;
342
            min_p = _penalty[i];
343
          }
344
        }
345
        return node;
346
      }
347

	
348
      // Return a node index for an add move or -1 if no one exists
349
      int nextAddNode() const {
350
        int start_node = _rnd[_n];
351
        int node = -1, min_p = std::numeric_limits<int>::max();
352
        for (int i = start_node; i != _n; i++) {
353
          if (_delta[i] == 0 && _penalty[i] < min_p) {
354
            node = i;
355
            min_p = _penalty[i];
356
          }
357
        }
358
        for (int i = 0; i != start_node; i++) {
359
          if (_delta[i] == 0 && _penalty[i] < min_p) {
360
            node = i;
361
            min_p = _penalty[i];
362
          }
363
        }
364
        return node;
365
      }
366

	
367
      // Update internal data structures between stages (if necessary)
368
      void update() {}
369

	
370
    }; //class PenaltyBasedSelectionRule
371

	
372
  public:
373

	
374
    /// \brief Constructor.
375
    ///
376
    /// Constructor.
377
    /// The global \ref rnd "random number generator instance" is used
378
    /// during the algorithm.
379
    ///
380
    /// \param graph The undirected graph the algorithm runs on.
381
    GrossoLocatelliPullanMc(const GR& graph) :
382
      _graph(graph), _id(_graph), _rnd(rnd)
383
    {}
384

	
385
    /// \brief Constructor with random seed.
386
    ///
387
    /// Constructor with random seed.
388
    ///
389
    /// \param graph The undirected graph the algorithm runs on.
390
    /// \param seed Seed value for the internal random number generator
391
    /// that is used during the algorithm.
392
    GrossoLocatelliPullanMc(const GR& graph, int seed) :
393
      _graph(graph), _id(_graph), _rnd(seed)
394
    {}
395

	
396
    /// \brief Constructor with random number generator.
397
    ///
398
    /// Constructor with random number generator.
399
    ///
400
    /// \param graph The undirected graph the algorithm runs on.
401
    /// \param random A random number generator that is used during the
402
    /// algorithm.
403
    GrossoLocatelliPullanMc(const GR& graph, const Random& random) :
404
      _graph(graph), _id(_graph), _rnd(random)
405
    {}
406

	
407
    /// \name Execution Control
408
    /// @{
409

	
410
    /// \brief Runs the algorithm.
411
    ///
412
    /// This function runs the algorithm.
413
    ///
414
    /// \param step_num The maximum number of node selections (steps)
415
    /// during the search process.
416
    /// This parameter controls the running time and the success of the
417
    /// algorithm. For larger values, the algorithm runs slower but it more
418
    /// likely finds larger cliques. For smaller values, the algorithm is
419
    /// faster but probably gives worse results.
420
    /// \param rule The node selection rule. For more information, see
421
    /// \ref SelectionRule.
422
    ///
423
    /// \return The size of the found clique.
424
    int run(int step_num = 100000,
425
            SelectionRule rule = PENALTY_BASED)
426
    {
427
      init();
428
      switch (rule) {
429
        case RANDOM:
430
          return start<RandomSelectionRule>(step_num);
431
        case DEGREE_BASED:
432
          return start<DegreeBasedSelectionRule>(step_num);
433
        case PENALTY_BASED:
434
          return start<PenaltyBasedSelectionRule>(step_num);
435
      }
436
      return 0; // avoid warning
437
    }
438

	
439
    /// @}
440

	
441
    /// \name Query Functions
442
    /// @{
443

	
444
    /// \brief The size of the found clique
445
    ///
446
    /// This function returns the size of the found clique.
447
    ///
448
    /// \pre run() must be called before using this function.
449
    int cliqueSize() const {
450
      return _best_size;
451
    }
452

	
453
    /// \brief Gives back the found clique in a \c bool node map
454
    ///
455
    /// This function gives back the characteristic vector of the found
456
    /// clique in the given node map.
457
    /// It must be a \ref concepts::WriteMap "writable" node map with
458
    /// \c bool (or convertible) value type.
459
    ///
460
    /// \pre run() must be called before using this function.
461
    template <typename CliqueMap>
462
    void cliqueMap(CliqueMap &map) const {
463
      for (NodeIt n(_graph); n != INVALID; ++n) {
464
        map[n] = static_cast<bool>(_best_clique[_id[n]]);
465
      }
466
    }
467

	
468
    /// \brief Iterator to list the nodes of the found clique
469
    ///
470
    /// This iterator class lists the nodes of the found clique.
471
    /// Before using it, you must allocate a GrossoLocatelliPullanMc instance
472
    /// and call its \ref GrossoLocatelliPullanMc::run() "run()" method.
473
    ///
474
    /// The following example prints out the IDs of the nodes in the found
475
    /// clique.
476
    /// \code
477
    ///   GrossoLocatelliPullanMc<Graph> mc(g);
478
    ///   mc.run();
479
    ///   for (GrossoLocatelliPullanMc<Graph>::CliqueNodeIt n(mc);
480
    ///        n != INVALID; ++n)
481
    ///   {
482
    ///     std::cout << g.id(n) << std::endl;
483
    ///   }
484
    /// \endcode
485
    class CliqueNodeIt
486
    {
487
    private:
488
      NodeIt _it;
489
      BoolNodeMap _map;
490

	
491
    public:
492

	
493
      /// Constructor
494

	
495
      /// Constructor.
496
      /// \param mc The algorithm instance.
497
      CliqueNodeIt(const GrossoLocatelliPullanMc &mc)
498
       : _map(mc._graph)
499
      {
500
        mc.cliqueMap(_map);
501
        for (_it = NodeIt(mc._graph); _it != INVALID && !_map[_it]; ++_it) ;
502
      }
503

	
504
      /// Conversion to \c Node
505
      operator Node() const { return _it; }
506

	
507
      bool operator==(Invalid) const { return _it == INVALID; }
508
      bool operator!=(Invalid) const { return _it != INVALID; }
509

	
510
      /// Next node
511
      CliqueNodeIt &operator++() {
512
        for (++_it; _it != INVALID && !_map[_it]; ++_it) ;
513
        return *this;
514
      }
515

	
516
      /// Postfix incrementation
517

	
518
      /// Postfix incrementation.
519
      ///
520
      /// \warning This incrementation returns a \c Node, not a
521
      /// \c CliqueNodeIt as one may expect.
522
      typename GR::Node operator++(int) {
523
        Node n=*this;
524
        ++(*this);
525
        return n;
526
      }
527

	
528
    };
529

	
530
    /// @}
531

	
532
  private:
533

	
534
    // Adds a node to the current clique
535
    void addCliqueNode(int u) {
536
      if (_clique[u]) return;
537
      _clique[u] = true;
538
      _size++;
539
      BoolVector &row = _gr[u];
540
      for (int i = 0; i != _n; i++) {
541
        if (!row[i]) _delta[i]++;
542
      }
543
    }
544

	
545
    // Removes a node from the current clique
546
    void delCliqueNode(int u) {
547
      if (!_clique[u]) return;
548
      _clique[u] = false;
549
      _size--;
550
      BoolVector &row = _gr[u];
551
      for (int i = 0; i != _n; i++) {
552
        if (!row[i]) _delta[i]--;
553
      }
554
    }
555

	
556
    // Initialize data structures
557
    void init() {
558
      _n = countNodes(_graph);
559
      int ui = 0;
560
      for (NodeIt u(_graph); u != INVALID; ++u) {
561
        _id[u] = ui++;
562
      }
563
      _gr.clear();
564
      _gr.resize(_n, BoolVector(_n, false));
565
      ui = 0;
566
      for (NodeIt u(_graph); u != INVALID; ++u) {
567
        for (IncEdgeIt e(_graph, u); e != INVALID; ++e) {
568
          int vi = _id[_graph.runningNode(e)];
569
          _gr[ui][vi] = true;
570
          _gr[vi][ui] = true;
571
        }
572
        ++ui;
573
      }
574

	
575
      _clique.clear();
576
      _clique.resize(_n, false);
577
      _size = 0;
578
      _best_clique.clear();
579
      _best_clique.resize(_n, false);
580
      _best_size = 0;
581
      _delta.clear();
582
      _delta.resize(_n, 0);
583
      _tabu.clear();
584
      _tabu.resize(_n, false);
585
    }
586

	
587
    // Executes the algorithm
588
    template <typename SelectionRuleImpl>
589
    int start(int max_select) {
590
      // Options for the restart rule
591
      const bool delta_based_restart = true;
592
      const int restart_delta_limit = 4;
593

	
594
      if (_n == 0) return 0;
595
      if (_n == 1) {
596
        _best_clique[0] = true;
597
        _best_size = 1;
598
        return _best_size;
599
      }
600

	
601
      // Iterated local search
602
      SelectionRuleImpl sel_method(*this);
603
      int select = 0;
604
      IntVector restart_nodes;
605

	
606
      while (select < max_select) {
607

	
608
        // Perturbation/restart
609
        if (delta_based_restart) {
610
          restart_nodes.clear();
611
          for (int i = 0; i != _n; i++) {
612
            if (_delta[i] >= restart_delta_limit)
613
              restart_nodes.push_back(i);
614
          }
615
        }
616
        int rs_node = -1;
617
        if (restart_nodes.size() > 0) {
618
          rs_node = restart_nodes[_rnd[restart_nodes.size()]];
619
        } else {
620
          rs_node = _rnd[_n];
621
        }
622
        BoolVector &row = _gr[rs_node];
623
        for (int i = 0; i != _n; i++) {
624
          if (_clique[i] && !row[i]) delCliqueNode(i);
625
        }
626
        addCliqueNode(rs_node);
627

	
628
        // Local search
629
        _tabu.clear();
630
        _tabu.resize(_n, false);
631
        bool tabu_empty = true;
632
        int max_swap = _size;
633
        while (select < max_select) {
634
          select++;
635
          int u;
636
          if ((u = sel_method.nextFeasibleAddNode()) != -1) {
637
            // Feasible add move
638
            addCliqueNode(u);
639
            if (tabu_empty) max_swap = _size;
640
          }
641
          else if ((u = sel_method.nextFeasibleSwapNode()) != -1) {
642
            // Feasible swap move
643
            int v = -1;
644
            BoolVector &row = _gr[u];
645
            for (int i = 0; i != _n; i++) {
646
              if (_clique[i] && !row[i]) {
647
                v = i;
648
                break;
649
              }
650
            }
651
            addCliqueNode(u);
652
            delCliqueNode(v);
653
            _tabu[v] = true;
654
            tabu_empty = false;
655
            if (--max_swap <= 0) break;
656
          }
657
          else if ((u = sel_method.nextAddNode()) != -1) {
658
            // Non-feasible add move
659
            addCliqueNode(u);
660
          }
661
          else break;
662
        }
663
        if (_size > _best_size) {
664
          _best_clique = _clique;
665
          _best_size = _size;
666
          if (_best_size == _n) return _best_size;
667
        }
668
        sel_method.update();
669
      }
670

	
671
      return _best_size;
672
    }
673

	
674
  }; //class GrossoLocatelliPullanMc
675

	
676
  ///@}
677

	
678
} //namespace lemon
679

	
680
#endif //LEMON_GROSSO_LOCATELLI_PULLAN_MC_H
Ignore white space 6 line context
1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2
 *
3
 * This file is a part of LEMON, a generic C++ optimization library.
4
 *
5
 * Copyright (C) 2003-2010
6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8
 *
9
 * Permission to use, modify and distribute this software is granted
10
 * provided that this copyright notice appears in all copies. For
11
 * precise terms see the accompanying LICENSE file.
12
 *
13
 * This software is provided "AS IS" with no warranty of any kind,
14
 * express or implied, and with no claim as to its suitability for any
15
 * purpose.
16
 *
17
 */
18

	
19
#include <sstream>
20
#include <lemon/list_graph.h>
21
#include <lemon/full_graph.h>
22
#include <lemon/grid_graph.h>
23
#include <lemon/lgf_reader.h>
24
#include <lemon/grosso_locatelli_pullan_mc.h>
25

	
26
#include "test_tools.h"
27

	
28
using namespace lemon;
29

	
30
char test_lgf[] =
31
  "@nodes\n"
32
  "label max_clique\n"
33
  "1     0\n"
34
  "2     0\n"
35
  "3     0\n"
36
  "4     1\n"
37
  "5     1\n"
38
  "6     1\n"
39
  "7     1\n"
40
  "@edges\n"
41
  "    label\n"
42
  "1 2     1\n"
43
  "1 3     2\n"
44
  "1 4     3\n"
45
  "1 6     4\n"
46
  "2 3     5\n"
47
  "2 5     6\n"
48
  "2 7     7\n"
49
  "3 4     8\n"
50
  "3 5     9\n"
51
  "4 5    10\n"
52
  "4 6    11\n"
53
  "4 7    12\n"
54
  "5 6    13\n"
55
  "5 7    14\n"
56
  "6 7    15\n";
57
      
58

	
59
// Check with general graphs
60
template <typename Param>
61
void checkMaxCliqueGeneral(int max_sel, Param rule) {
62
  typedef ListGraph GR;
63
  typedef GrossoLocatelliPullanMc<GR> McAlg;
64
  typedef McAlg::CliqueNodeIt CliqueIt;
65
  
66
  // Basic tests
67
  {
68
    GR g;
69
    GR::NodeMap<bool> map(g);
70
    McAlg mc(g);
71
    check(mc.run(max_sel, rule) == 0, "Wrong clique size");
72
    check(mc.cliqueSize() == 0, "Wrong clique size");
73
    check(CliqueIt(mc) == INVALID, "Wrong CliqueNodeIt");
74

	
75
    GR::Node u = g.addNode();
76
    check(mc.run(max_sel, rule) == 1, "Wrong clique size");
77
    check(mc.cliqueSize() == 1, "Wrong clique size");
78
    mc.cliqueMap(map);
79
    check(map[u], "Wrong clique map");
80
    CliqueIt it1(mc);
81
    check(static_cast<GR::Node>(it1) == u && ++it1 == INVALID,
82
          "Wrong CliqueNodeIt");
83
    
84
    GR::Node v = g.addNode();
85
    check(mc.run(max_sel, rule) == 1, "Wrong clique size");
86
    check(mc.cliqueSize() == 1, "Wrong clique size");
87
    mc.cliqueMap(map);
88
    check((map[u] && !map[v]) || (map[v] && !map[u]), "Wrong clique map");
89
    CliqueIt it2(mc);
90
    check(it2 != INVALID && ++it2 == INVALID, "Wrong CliqueNodeIt");
91

	
92
    g.addEdge(u, v);
93
    check(mc.run(max_sel, rule) == 2, "Wrong clique size");
94
    check(mc.cliqueSize() == 2, "Wrong clique size");
95
    mc.cliqueMap(map);
96
    check(map[u] && map[v], "Wrong clique map");
97
    CliqueIt it3(mc);
98
    check(it3 != INVALID && ++it3 != INVALID && ++it3 == INVALID,
99
          "Wrong CliqueNodeIt");
100
  }
101

	
102
  // Test graph
103
  {
104
    GR g;
105
    GR::NodeMap<bool> max_clique(g);
106
    GR::NodeMap<bool> map(g);
107
    std::istringstream input(test_lgf);
108
    graphReader(g, input)
109
      .nodeMap("max_clique", max_clique)
110
      .run();
111
    
112
    McAlg mc(g);
113
    check(mc.run(max_sel, rule) == 4, "Wrong clique size");
114
    check(mc.cliqueSize() == 4, "Wrong clique size");
115
    mc.cliqueMap(map);
116
    for (GR::NodeIt n(g); n != INVALID; ++n) {
117
      check(map[n] == max_clique[n], "Wrong clique map");
118
    }
119
    int cnt = 0;
120
    for (CliqueIt n(mc); n != INVALID; ++n) {
121
      cnt++;
122
      check(map[n] && max_clique[n], "Wrong CliqueNodeIt");
123
    }
124
    check(cnt == 4, "Wrong CliqueNodeIt");
125
  }
126
}
127

	
128
// Check with full graphs
129
template <typename Param>
130
void checkMaxCliqueFullGraph(int max_sel, Param rule) {
131
  typedef FullGraph GR;
132
  typedef GrossoLocatelliPullanMc<FullGraph> McAlg;
133
  typedef McAlg::CliqueNodeIt CliqueIt;
134
  
135
  for (int size = 0; size <= 40; size = size * 3 + 1) {
136
    GR g(size);
137
    GR::NodeMap<bool> map(g);
138
    McAlg mc(g);
139
    check(mc.run(max_sel, rule) == size, "Wrong clique size");
140
    check(mc.cliqueSize() == size, "Wrong clique size");
141
    mc.cliqueMap(map);
142
    for (GR::NodeIt n(g); n != INVALID; ++n) {
143
      check(map[n], "Wrong clique map");
144
    }
145
    int cnt = 0;
146
    for (CliqueIt n(mc); n != INVALID; ++n) cnt++;
147
    check(cnt == size, "Wrong CliqueNodeIt");
148
  }
149
}
150

	
151
// Check with grid graphs
152
template <typename Param>
153
void checkMaxCliqueGridGraph(int max_sel, Param rule) {
154
  GridGraph g(5, 7);
155
  GridGraph::NodeMap<char> map(g);
156
  GrossoLocatelliPullanMc<GridGraph> mc(g);
157
  check(mc.run(max_sel, rule) == 2, "Wrong clique size");
158
  check(mc.cliqueSize() == 2, "Wrong clique size");
159
}
160

	
161

	
162
int main() {
163
  checkMaxCliqueGeneral(50, GrossoLocatelliPullanMc<ListGraph>::RANDOM);
164
  checkMaxCliqueGeneral(50, GrossoLocatelliPullanMc<ListGraph>::DEGREE_BASED);
165
  checkMaxCliqueGeneral(50, GrossoLocatelliPullanMc<ListGraph>::PENALTY_BASED);
166

	
167
  checkMaxCliqueFullGraph(50, GrossoLocatelliPullanMc<FullGraph>::RANDOM);
168
  checkMaxCliqueFullGraph(50, GrossoLocatelliPullanMc<FullGraph>::DEGREE_BASED);
169
  checkMaxCliqueFullGraph(50, GrossoLocatelliPullanMc<FullGraph>::PENALTY_BASED);
170
                       
171
  checkMaxCliqueGridGraph(50, GrossoLocatelliPullanMc<GridGraph>::RANDOM);
172
  checkMaxCliqueGridGraph(50, GrossoLocatelliPullanMc<GridGraph>::DEGREE_BASED);
173
  checkMaxCliqueGridGraph(50, GrossoLocatelliPullanMc<GridGraph>::PENALTY_BASED);
174
                       
175
  return 0;
176
}
Ignore white space 6 line context
... ...
@@ -542,30 +542,34 @@
542 542
@defgroup planar Planarity Embedding and Drawing
543 543
@ingroup algs
544 544
\brief Algorithms for planarity checking, embedding and drawing
545 545

	
546 546
This group contains the algorithms for planarity checking,
547 547
embedding and drawing.
548 548

	
549 549
\image html planar.png
550 550
\image latex planar.eps "Plane graph" width=\textwidth
551 551
*/
552 552

	
553 553
/**
554
@defgroup approx Approximation Algorithms
554
@defgroup approx_algs Approximation Algorithms
555 555
@ingroup algs
556 556
\brief Approximation algorithms.
557 557

	
558 558
This group contains the approximation and heuristic algorithms
559 559
implemented in LEMON.
560

	
561
<b>Maximum Clique Problem</b>
562
  - \ref GrossoLocatelliPullanMc An efficient heuristic algorithm of
563
    Grosso, Locatelli, and Pullan.
560 564
*/
561 565

	
562 566
/**
563 567
@defgroup auxalg Auxiliary Algorithms
564 568
@ingroup algs
565 569
\brief Auxiliary algorithms implemented in LEMON.
566 570

	
567 571
This group contains some algorithms implemented in LEMON
568 572
in order to make it easier to implement complex algorithms.
569 573
*/
570 574

	
571 575
/**
Ignore white space 6 line context
... ...
@@ -288,14 +288,27 @@
288 288
  title =        {Linear Programming and Extensions},
289 289
  publisher =    {Princeton University Press},
290 290
  year =         1963
291 291
}
292 292

	
293 293
@mastersthesis{kellyoneill91netsimplex,
294 294
  author =       {Damian J. Kelly and Garrett M. O'Neill},
295 295
  title =        {The Minimum Cost Flow Problem and The Network
296 296
                  Simplex Method},
297 297
  school =       {University College},
298 298
  address =      {Dublin, Ireland},
299 299
  year =         1991,
300
  month =        sep,
300
  month =        sep
301 301
}
302

	
303
%%%%% Other algorithms %%%%%
304

	
305
@article{grosso08maxclique,
306
  author =       {Andrea Grosso and Marco Locatelli and Wayne Pullan},
307
  title =        {Simple ingredients leading to very efficient
308
                  heuristics for the maximum clique problem},
309
  journal =      {Journal of Heuristics},
310
  year =         2008,
311
  volume =       14,
312
  number =       6,
313
  pages =        {587--612}
314
}
Ignore white space 6 line context
... ...
@@ -81,24 +81,25 @@
81 81
	lemon/dimacs.h \
82 82
	lemon/edge_set.h \
83 83
	lemon/elevator.h \
84 84
	lemon/error.h \
85 85
	lemon/euler.h \
86 86
	lemon/fib_heap.h \
87 87
	lemon/fractional_matching.h \
88 88
	lemon/full_graph.h \
89 89
	lemon/glpk.h \
90 90
	lemon/gomory_hu.h \
91 91
	lemon/graph_to_eps.h \
92 92
	lemon/grid_graph.h \
93
	lemon/grosso_locatelli_pullan_mc.h \
93 94
	lemon/hartmann_orlin_mmc.h \
94 95
	lemon/howard_mmc.h \
95 96
	lemon/hypercube_graph.h \
96 97
	lemon/karp_mmc.h \
97 98
	lemon/kruskal.h \
98 99
	lemon/hao_orlin.h \
99 100
	lemon/lgf_reader.h \
100 101
	lemon/lgf_writer.h \
101 102
	lemon/list_graph.h \
102 103
	lemon/lp.h \
103 104
	lemon/lp_base.h \
104 105
	lemon/lp_skeleton.h \
Ignore white space 24 line context
... ...
@@ -22,24 +22,25 @@
22 22
  error_test
23 23
  euler_test
24 24
  fractional_matching_test
25 25
  gomory_hu_test
26 26
  graph_copy_test
27 27
  graph_test
28 28
  graph_utils_test
29 29
  hao_orlin_test
30 30
  heap_test
31 31
  kruskal_test
32 32
  maps_test
33 33
  matching_test
34
  max_clique_test
34 35
  min_cost_arborescence_test
35 36
  min_cost_flow_test
36 37
  min_mean_cycle_test
37 38
  path_test
38 39
  planarity_test
39 40
  preflow_test
40 41
  radix_sort_test
41 42
  random_test
42 43
  suurballe_test
43 44
  time_measure_test
44 45
  unionfind_test
45 46
)
Ignore white space 6 line context
... ...
@@ -24,24 +24,25 @@
24 24
	test/error_test \
25 25
	test/euler_test \
26 26
	test/fractional_matching_test \
27 27
	test/gomory_hu_test \
28 28
	test/graph_copy_test \
29 29
	test/graph_test \
30 30
	test/graph_utils_test \
31 31
	test/hao_orlin_test \
32 32
	test/heap_test \
33 33
	test/kruskal_test \
34 34
	test/maps_test \
35 35
	test/matching_test \
36
	test/max_clique_test \
36 37
	test/min_cost_arborescence_test \
37 38
	test/min_cost_flow_test \
38 39
	test/min_mean_cycle_test \
39 40
	test/path_test \
40 41
	test/planarity_test \
41 42
	test/preflow_test \
42 43
	test/radix_sort_test \
43 44
	test/random_test \
44 45
	test/suurballe_test \
45 46
	test/test_tools_fail \
46 47
	test/test_tools_pass \
47 48
	test/time_measure_test \
... ...
@@ -75,24 +76,25 @@
75 76
test_fractional_matching_test_SOURCES = test/fractional_matching_test.cc
76 77
test_gomory_hu_test_SOURCES = test/gomory_hu_test.cc
77 78
test_graph_copy_test_SOURCES = test/graph_copy_test.cc
78 79
test_graph_test_SOURCES = test/graph_test.cc
79 80
test_graph_utils_test_SOURCES = test/graph_utils_test.cc
80 81
test_heap_test_SOURCES = test/heap_test.cc
81 82
test_kruskal_test_SOURCES = test/kruskal_test.cc
82 83
test_hao_orlin_test_SOURCES = test/hao_orlin_test.cc
83 84
test_lp_test_SOURCES = test/lp_test.cc
84 85
test_maps_test_SOURCES = test/maps_test.cc
85 86
test_mip_test_SOURCES = test/mip_test.cc
86 87
test_matching_test_SOURCES = test/matching_test.cc
88
test_max_clique_test_SOURCES = test/max_clique_test.cc
87 89
test_min_cost_arborescence_test_SOURCES = test/min_cost_arborescence_test.cc
88 90
test_min_cost_flow_test_SOURCES = test/min_cost_flow_test.cc
89 91
test_min_mean_cycle_test_SOURCES = test/min_mean_cycle_test.cc
90 92
test_path_test_SOURCES = test/path_test.cc
91 93
test_planarity_test_SOURCES = test/planarity_test.cc
92 94
test_preflow_test_SOURCES = test/preflow_test.cc
93 95
test_radix_sort_test_SOURCES = test/radix_sort_test.cc
94 96
test_suurballe_test_SOURCES = test/suurballe_test.cc
95 97
test_random_test_SOURCES = test/random_test.cc
96 98
test_test_tools_fail_SOURCES = test/test_tools_fail.cc
97 99
test_test_tools_pass_SOURCES = test/test_tools_pass.cc
98 100
test_time_measure_test_SOURCES = test/time_measure_test.cc
0 comments (0 inline)