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
... ...
@@ -553,3 +553,3 @@
553 553
/**
554
@defgroup approx Approximation Algorithms
554
@defgroup approx_algs Approximation Algorithms
555 555
@ingroup algs
... ...
@@ -559,2 +559,6 @@
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
*/
Ignore white space 6 line context
... ...
@@ -299,3 +299,16 @@
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
}
Show white space 6 line context
... ...
@@ -92,2 +92,3 @@
92 92
	lemon/grid_graph.h \
93
	lemon/grosso_locatelli_pullan_mc.h \
93 94
	lemon/hartmann_orlin_mmc.h \
Ignore white space 6 line context
... ...
@@ -33,2 +33,3 @@
33 33
  matching_test
34
  max_clique_test
34 35
  min_cost_arborescence_test
Ignore white space 6 line context
... ...
@@ -35,2 +35,3 @@
35 35
	test/matching_test \
36
	test/max_clique_test \
36 37
	test/min_cost_arborescence_test \
... ...
@@ -86,2 +87,3 @@
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
0 comments (0 inline)