lemon/bits/array_map.h
author Peter Kovacs <kpeter@inf.elte.hu>
Fri, 03 Apr 2009 18:59:15 +0200
changeset 600 6ac5d9ae1d3d
parent 440 88ed40ad0d4f
child 609 4137ef9aacc6
permissions -rw-r--r--
Support real types + numerical stability fix in NS (#254)

- Real types are supported by appropriate inicialization.
- A feature of the XTI spanning tree structure is removed to ensure
numerical stability (could cause problems using integer types).
The node potentials are updated always on the lower subtree,
in order to prevent overflow problems.
The former method isn't notably faster during to our tests.
alpar@209
     1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
deba@57
     2
 *
alpar@209
     3
 * This file is a part of LEMON, a generic C++ optimization library.
deba@57
     4
 *
alpar@440
     5
 * Copyright (C) 2003-2009
deba@57
     6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
deba@57
     7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
deba@57
     8
 *
deba@57
     9
 * Permission to use, modify and distribute this software is granted
deba@57
    10
 * provided that this copyright notice appears in all copies. For
deba@57
    11
 * precise terms see the accompanying LICENSE file.
deba@57
    12
 *
deba@57
    13
 * This software is provided "AS IS" with no warranty of any kind,
deba@57
    14
 * express or implied, and with no claim as to its suitability for any
deba@57
    15
 * purpose.
deba@57
    16
 *
deba@57
    17
 */
deba@57
    18
deba@57
    19
#ifndef LEMON_BITS_ARRAY_MAP_H
deba@57
    20
#define LEMON_BITS_ARRAY_MAP_H
deba@57
    21
deba@57
    22
#include <memory>
deba@57
    23
deba@57
    24
#include <lemon/bits/traits.h>
deba@57
    25
#include <lemon/bits/alteration_notifier.h>
deba@57
    26
#include <lemon/concept_check.h>
deba@57
    27
#include <lemon/concepts/maps.h>
deba@57
    28
kpeter@314
    29
// \ingroup graphbits
kpeter@314
    30
// \file
kpeter@314
    31
// \brief Graph map based on the array storage.
deba@57
    32
deba@57
    33
namespace lemon {
deba@57
    34
kpeter@314
    35
  // \ingroup graphbits
kpeter@314
    36
  //
kpeter@314
    37
  // \brief Graph map based on the array storage.
kpeter@314
    38
  //
kpeter@361
    39
  // The ArrayMap template class is graph map structure that automatically
kpeter@361
    40
  // updates the map when a key is added to or erased from the graph.
kpeter@361
    41
  // This map uses the allocators to implement the container functionality.
kpeter@314
    42
  //
kpeter@361
    43
  // The template parameters are the Graph, the current Item type and
kpeter@314
    44
  // the Value type of the map.
deba@57
    45
  template <typename _Graph, typename _Item, typename _Value>
alpar@209
    46
  class ArrayMap
deba@57
    47
    : public ItemSetTraits<_Graph, _Item>::ItemNotifier::ObserverBase {
deba@57
    48
  public:
kpeter@361
    49
    // The graph type.
deba@57
    50
    typedef _Graph Graph;
kpeter@361
    51
    // The item type.
deba@57
    52
    typedef _Item Item;
kpeter@314
    53
    // The reference map tag.
deba@57
    54
    typedef True ReferenceMapTag;
deba@57
    55
kpeter@361
    56
    // The key type of the map.
deba@57
    57
    typedef _Item Key;
kpeter@314
    58
    // The value type of the map.
deba@57
    59
    typedef _Value Value;
deba@57
    60
kpeter@314
    61
    // The const reference type of the map.
deba@57
    62
    typedef const _Value& ConstReference;
kpeter@314
    63
    // The reference type of the map.
deba@57
    64
    typedef _Value& Reference;
deba@57
    65
kpeter@314
    66
    // The notifier type.
deba@57
    67
    typedef typename ItemSetTraits<_Graph, _Item>::ItemNotifier Notifier;
deba@57
    68
kpeter@314
    69
    // The MapBase of the Map which imlements the core regisitry function.
deba@57
    70
    typedef typename Notifier::ObserverBase Parent;
alpar@209
    71
deba@57
    72
  private:
deba@57
    73
    typedef std::allocator<Value> Allocator;
deba@57
    74
deba@57
    75
  public:
deba@57
    76
kpeter@314
    77
    // \brief Graph initialized map constructor.
kpeter@314
    78
    //
kpeter@314
    79
    // Graph initialized map constructor.
deba@57
    80
    explicit ArrayMap(const Graph& graph) {
deba@57
    81
      Parent::attach(graph.notifier(Item()));
deba@57
    82
      allocate_memory();
deba@57
    83
      Notifier* nf = Parent::notifier();
deba@57
    84
      Item it;
deba@57
    85
      for (nf->first(it); it != INVALID; nf->next(it)) {
alpar@209
    86
        int id = nf->id(it);;
alpar@209
    87
        allocator.construct(&(values[id]), Value());
alpar@209
    88
      }
deba@57
    89
    }
deba@57
    90
kpeter@314
    91
    // \brief Constructor to use default value to initialize the map.
kpeter@314
    92
    //
kpeter@314
    93
    // It constructs a map and initialize all of the the map.
deba@57
    94
    ArrayMap(const Graph& graph, const Value& value) {
deba@57
    95
      Parent::attach(graph.notifier(Item()));
deba@57
    96
      allocate_memory();
deba@57
    97
      Notifier* nf = Parent::notifier();
deba@57
    98
      Item it;
deba@57
    99
      for (nf->first(it); it != INVALID; nf->next(it)) {
alpar@209
   100
        int id = nf->id(it);;
alpar@209
   101
        allocator.construct(&(values[id]), value);
alpar@209
   102
      }
deba@57
   103
    }
deba@57
   104
kpeter@263
   105
  private:
kpeter@314
   106
    // \brief Constructor to copy a map of the same map type.
kpeter@314
   107
    //
kpeter@314
   108
    // Constructor to copy a map of the same map type.
deba@57
   109
    ArrayMap(const ArrayMap& copy) : Parent() {
deba@57
   110
      if (copy.attached()) {
alpar@209
   111
        attach(*copy.notifier());
deba@57
   112
      }
deba@57
   113
      capacity = copy.capacity;
deba@57
   114
      if (capacity == 0) return;
deba@57
   115
      values = allocator.allocate(capacity);
deba@57
   116
      Notifier* nf = Parent::notifier();
deba@57
   117
      Item it;
deba@57
   118
      for (nf->first(it); it != INVALID; nf->next(it)) {
alpar@209
   119
        int id = nf->id(it);;
alpar@209
   120
        allocator.construct(&(values[id]), copy.values[id]);
deba@57
   121
      }
deba@57
   122
    }
deba@57
   123
kpeter@314
   124
    // \brief Assign operator.
kpeter@314
   125
    //
kpeter@314
   126
    // This operator assigns for each item in the map the
kpeter@314
   127
    // value mapped to the same item in the copied map.
kpeter@314
   128
    // The parameter map should be indiced with the same
kpeter@314
   129
    // itemset because this assign operator does not change
kpeter@314
   130
    // the container of the map.
deba@57
   131
    ArrayMap& operator=(const ArrayMap& cmap) {
deba@57
   132
      return operator=<ArrayMap>(cmap);
deba@57
   133
    }
deba@57
   134
deba@57
   135
kpeter@314
   136
    // \brief Template assign operator.
kpeter@314
   137
    //
kpeter@519
   138
    // The given parameter should conform to the ReadMap
kpeter@314
   139
    // concecpt and could be indiced by the current item set of
kpeter@314
   140
    // the NodeMap. In this case the value for each item
kpeter@314
   141
    // is assigned by the value of the given ReadMap.
deba@57
   142
    template <typename CMap>
deba@57
   143
    ArrayMap& operator=(const CMap& cmap) {
deba@57
   144
      checkConcept<concepts::ReadMap<Key, _Value>, CMap>();
deba@57
   145
      const typename Parent::Notifier* nf = Parent::notifier();
deba@57
   146
      Item it;
deba@57
   147
      for (nf->first(it); it != INVALID; nf->next(it)) {
deba@57
   148
        set(it, cmap[it]);
deba@57
   149
      }
deba@57
   150
      return *this;
deba@57
   151
    }
deba@57
   152
kpeter@263
   153
  public:
kpeter@314
   154
    // \brief The destructor of the map.
kpeter@314
   155
    //
kpeter@314
   156
    // The destructor of the map.
alpar@209
   157
    virtual ~ArrayMap() {
deba@57
   158
      if (attached()) {
alpar@209
   159
        clear();
alpar@209
   160
        detach();
deba@57
   161
      }
deba@57
   162
    }
alpar@209
   163
deba@57
   164
  protected:
deba@57
   165
deba@57
   166
    using Parent::attach;
deba@57
   167
    using Parent::detach;
deba@57
   168
    using Parent::attached;
deba@57
   169
deba@57
   170
  public:
deba@57
   171
kpeter@314
   172
    // \brief The subscript operator.
kpeter@314
   173
    //
kpeter@314
   174
    // The subscript operator. The map can be subscripted by the
kpeter@314
   175
    // actual keys of the graph.
deba@57
   176
    Value& operator[](const Key& key) {
deba@57
   177
      int id = Parent::notifier()->id(key);
deba@57
   178
      return values[id];
alpar@209
   179
    }
alpar@209
   180
kpeter@314
   181
    // \brief The const subscript operator.
kpeter@314
   182
    //
kpeter@314
   183
    // The const subscript operator. The map can be subscripted by the
kpeter@314
   184
    // actual keys of the graph.
deba@57
   185
    const Value& operator[](const Key& key) const {
deba@57
   186
      int id = Parent::notifier()->id(key);
deba@57
   187
      return values[id];
deba@57
   188
    }
deba@57
   189
kpeter@314
   190
    // \brief Setter function of the map.
kpeter@314
   191
    //
kpeter@314
   192
    // Setter function of the map. Equivalent with map[key] = val.
kpeter@314
   193
    // This is a compatibility feature with the not dereferable maps.
deba@57
   194
    void set(const Key& key, const Value& val) {
deba@57
   195
      (*this)[key] = val;
deba@57
   196
    }
deba@57
   197
deba@57
   198
  protected:
deba@57
   199
kpeter@314
   200
    // \brief Adds a new key to the map.
kpeter@314
   201
    //
kpeter@361
   202
    // It adds a new key to the map. It is called by the observer notifier
kpeter@314
   203
    // and it overrides the add() member function of the observer base.
deba@57
   204
    virtual void add(const Key& key) {
deba@57
   205
      Notifier* nf = Parent::notifier();
deba@57
   206
      int id = nf->id(key);
deba@57
   207
      if (id >= capacity) {
alpar@209
   208
        int new_capacity = (capacity == 0 ? 1 : capacity);
alpar@209
   209
        while (new_capacity <= id) {
alpar@209
   210
          new_capacity <<= 1;
alpar@209
   211
        }
alpar@209
   212
        Value* new_values = allocator.allocate(new_capacity);
alpar@209
   213
        Item it;
alpar@209
   214
        for (nf->first(it); it != INVALID; nf->next(it)) {
alpar@209
   215
          int jd = nf->id(it);;
alpar@209
   216
          if (id != jd) {
alpar@209
   217
            allocator.construct(&(new_values[jd]), values[jd]);
alpar@209
   218
            allocator.destroy(&(values[jd]));
alpar@209
   219
          }
alpar@209
   220
        }
alpar@209
   221
        if (capacity != 0) allocator.deallocate(values, capacity);
alpar@209
   222
        values = new_values;
alpar@209
   223
        capacity = new_capacity;
deba@57
   224
      }
deba@57
   225
      allocator.construct(&(values[id]), Value());
deba@57
   226
    }
deba@57
   227
kpeter@314
   228
    // \brief Adds more new keys to the map.
kpeter@314
   229
    //
kpeter@361
   230
    // It adds more new keys to the map. It is called by the observer notifier
kpeter@314
   231
    // and it overrides the add() member function of the observer base.
deba@57
   232
    virtual void add(const std::vector<Key>& keys) {
deba@57
   233
      Notifier* nf = Parent::notifier();
deba@57
   234
      int max_id = -1;
deba@57
   235
      for (int i = 0; i < int(keys.size()); ++i) {
alpar@209
   236
        int id = nf->id(keys[i]);
alpar@209
   237
        if (id > max_id) {
alpar@209
   238
          max_id = id;
alpar@209
   239
        }
deba@57
   240
      }
deba@57
   241
      if (max_id >= capacity) {
alpar@209
   242
        int new_capacity = (capacity == 0 ? 1 : capacity);
alpar@209
   243
        while (new_capacity <= max_id) {
alpar@209
   244
          new_capacity <<= 1;
alpar@209
   245
        }
alpar@209
   246
        Value* new_values = allocator.allocate(new_capacity);
alpar@209
   247
        Item it;
alpar@209
   248
        for (nf->first(it); it != INVALID; nf->next(it)) {
alpar@209
   249
          int id = nf->id(it);
alpar@209
   250
          bool found = false;
alpar@209
   251
          for (int i = 0; i < int(keys.size()); ++i) {
alpar@209
   252
            int jd = nf->id(keys[i]);
alpar@209
   253
            if (id == jd) {
alpar@209
   254
              found = true;
alpar@209
   255
              break;
alpar@209
   256
            }
alpar@209
   257
          }
alpar@209
   258
          if (found) continue;
alpar@209
   259
          allocator.construct(&(new_values[id]), values[id]);
alpar@209
   260
          allocator.destroy(&(values[id]));
alpar@209
   261
        }
alpar@209
   262
        if (capacity != 0) allocator.deallocate(values, capacity);
alpar@209
   263
        values = new_values;
alpar@209
   264
        capacity = new_capacity;
deba@57
   265
      }
deba@57
   266
      for (int i = 0; i < int(keys.size()); ++i) {
alpar@209
   267
        int id = nf->id(keys[i]);
alpar@209
   268
        allocator.construct(&(values[id]), Value());
deba@57
   269
      }
deba@57
   270
    }
alpar@209
   271
kpeter@314
   272
    // \brief Erase a key from the map.
kpeter@314
   273
    //
kpeter@361
   274
    // Erase a key from the map. It is called by the observer notifier
kpeter@314
   275
    // and it overrides the erase() member function of the observer base.
deba@57
   276
    virtual void erase(const Key& key) {
deba@57
   277
      int id = Parent::notifier()->id(key);
deba@57
   278
      allocator.destroy(&(values[id]));
deba@57
   279
    }
deba@57
   280
kpeter@314
   281
    // \brief Erase more keys from the map.
kpeter@314
   282
    //
kpeter@361
   283
    // Erase more keys from the map. It is called by the observer notifier
kpeter@314
   284
    // and it overrides the erase() member function of the observer base.
deba@57
   285
    virtual void erase(const std::vector<Key>& keys) {
deba@57
   286
      for (int i = 0; i < int(keys.size()); ++i) {
alpar@209
   287
        int id = Parent::notifier()->id(keys[i]);
alpar@209
   288
        allocator.destroy(&(values[id]));
deba@57
   289
      }
deba@57
   290
    }
deba@57
   291
kpeter@361
   292
    // \brief Builds the map.
kpeter@314
   293
    //
kpeter@361
   294
    // It builds the map. It is called by the observer notifier
kpeter@314
   295
    // and it overrides the build() member function of the observer base.
deba@57
   296
    virtual void build() {
deba@57
   297
      Notifier* nf = Parent::notifier();
deba@57
   298
      allocate_memory();
deba@57
   299
      Item it;
deba@57
   300
      for (nf->first(it); it != INVALID; nf->next(it)) {
alpar@209
   301
        int id = nf->id(it);;
alpar@209
   302
        allocator.construct(&(values[id]), Value());
alpar@209
   303
      }
deba@57
   304
    }
deba@57
   305
kpeter@314
   306
    // \brief Clear the map.
kpeter@314
   307
    //
kpeter@361
   308
    // It erase all items from the map. It is called by the observer notifier
kpeter@314
   309
    // and it overrides the clear() member function of the observer base.
alpar@209
   310
    virtual void clear() {
deba@57
   311
      Notifier* nf = Parent::notifier();
deba@57
   312
      if (capacity != 0) {
alpar@209
   313
        Item it;
alpar@209
   314
        for (nf->first(it); it != INVALID; nf->next(it)) {
alpar@209
   315
          int id = nf->id(it);
alpar@209
   316
          allocator.destroy(&(values[id]));
alpar@209
   317
        }
alpar@209
   318
        allocator.deallocate(values, capacity);
alpar@209
   319
        capacity = 0;
deba@57
   320
      }
deba@57
   321
    }
deba@57
   322
deba@57
   323
  private:
alpar@209
   324
deba@57
   325
    void allocate_memory() {
deba@57
   326
      int max_id = Parent::notifier()->maxId();
deba@57
   327
      if (max_id == -1) {
alpar@209
   328
        capacity = 0;
alpar@209
   329
        values = 0;
alpar@209
   330
        return;
deba@57
   331
      }
deba@57
   332
      capacity = 1;
deba@57
   333
      while (capacity <= max_id) {
alpar@209
   334
        capacity <<= 1;
deba@57
   335
      }
alpar@209
   336
      values = allocator.allocate(capacity);
alpar@209
   337
    }
deba@57
   338
deba@57
   339
    int capacity;
deba@57
   340
    Value* values;
deba@57
   341
    Allocator allocator;
deba@57
   342
alpar@209
   343
  };
deba@57
   344
deba@57
   345
}
deba@57
   346
alpar@209
   347
#endif