|
|
|
@ -9,6 +9,20 @@
|
|
|
|
|
|
|
|
|
|
typedef std::map<NodeID, Path *> PathViaMap;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* This is a wrapper around Tannotation* which also stores a cache of GetAnnotation() and GetNode()
|
|
|
|
|
* to remove the need dereference the Tannotation* pointer when sorting/inseting/erasing in MultiCommodityFlow::Dijkstra::AnnoSet
|
|
|
|
|
*/
|
|
|
|
|
template<typename Tannotation>
|
|
|
|
|
class AnnoSetItem {
|
|
|
|
|
public:
|
|
|
|
|
Tannotation *anno_ptr;
|
|
|
|
|
typename Tannotation::AnnotationValueType cached_annotation;
|
|
|
|
|
NodeID node_id;
|
|
|
|
|
|
|
|
|
|
AnnoSetItem(Tannotation *anno) : anno_ptr(anno), cached_annotation(anno->GetAnnotation()), node_id(anno->GetNode()) {}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Distance-based annotation for use in the Dijkstra algorithm. This is close
|
|
|
|
|
* to the original meaning of "annotation" in this context. Paths are rated
|
|
|
|
@ -16,6 +30,7 @@ typedef std::map<NodeID, Path *> PathViaMap;
|
|
|
|
|
*/
|
|
|
|
|
class DistanceAnnotation : public Path {
|
|
|
|
|
public:
|
|
|
|
|
typedef uint AnnotationValueType;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Constructor.
|
|
|
|
@ -41,7 +56,7 @@ public:
|
|
|
|
|
* Comparator for std containers.
|
|
|
|
|
*/
|
|
|
|
|
struct Comparator {
|
|
|
|
|
bool operator()(const DistanceAnnotation *x, const DistanceAnnotation *y) const;
|
|
|
|
|
bool operator()(const AnnoSetItem<DistanceAnnotation> &x, const AnnoSetItem<DistanceAnnotation> &y) const;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@ -53,8 +68,8 @@ public:
|
|
|
|
|
*/
|
|
|
|
|
class CapacityAnnotation : public Path {
|
|
|
|
|
int cached_annotation;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
typedef int AnnotationValueType;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Constructor.
|
|
|
|
@ -83,7 +98,7 @@ public:
|
|
|
|
|
* Comparator for std containers.
|
|
|
|
|
*/
|
|
|
|
|
struct Comparator {
|
|
|
|
|
bool operator()(const CapacityAnnotation *x, const CapacityAnnotation *y) const;
|
|
|
|
|
bool operator()(const AnnoSetItem<CapacityAnnotation> &x, const AnnoSetItem<CapacityAnnotation> &y) const;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@ -246,6 +261,91 @@ bool CapacityAnnotation::IsBetter(const CapacityAnnotation *base, uint cap,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Storage for AnnoSetAllocator instances
|
|
|
|
|
*/
|
|
|
|
|
struct AnnoSetAllocatorStore {
|
|
|
|
|
std::vector<void *> used_blocks;
|
|
|
|
|
void *current_block;
|
|
|
|
|
size_t next_position;
|
|
|
|
|
void *last_freed;
|
|
|
|
|
|
|
|
|
|
AnnoSetAllocatorStore() : current_block(NULL), next_position(0), last_freed(NULL) {}
|
|
|
|
|
|
|
|
|
|
~AnnoSetAllocatorStore()
|
|
|
|
|
{
|
|
|
|
|
for (std::vector<void *>::iterator i = used_blocks.begin(); i != used_blocks.end(); ++i) {
|
|
|
|
|
free(*i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Custom allocator specifically for use with MultiCommodityFlow::Dijkstra::AnnoSet
|
|
|
|
|
* This allocates RB-set nodes in contiguous blocks, and frees all allocated nodes when destructed
|
|
|
|
|
* If a node is deallocated, it is returned in the next allocation, this is so that the same node
|
|
|
|
|
* can be re-used across a call to Path::Fork
|
|
|
|
|
*/
|
|
|
|
|
template<class Ttype>
|
|
|
|
|
struct AnnoSetAllocator {
|
|
|
|
|
static const size_t block_size = 1024;
|
|
|
|
|
|
|
|
|
|
AnnoSetAllocatorStore &store;
|
|
|
|
|
|
|
|
|
|
void NewBlock()
|
|
|
|
|
{
|
|
|
|
|
store.current_block = MallocT<Ttype>(block_size);
|
|
|
|
|
store.next_position = 0;
|
|
|
|
|
store.used_blocks.push_back(store.current_block);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef Ttype value_type;
|
|
|
|
|
|
|
|
|
|
template<typename Tother>
|
|
|
|
|
struct rebind {
|
|
|
|
|
typedef AnnoSetAllocator<Tother> other;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
AnnoSetAllocator(AnnoSetAllocatorStore &store) : store(store) {}
|
|
|
|
|
|
|
|
|
|
template<typename Tother>
|
|
|
|
|
AnnoSetAllocator(const AnnoSetAllocator<Tother> &other) : store(other.store) {}
|
|
|
|
|
|
|
|
|
|
Ttype* allocate(size_t n)
|
|
|
|
|
{
|
|
|
|
|
if (store.current_block == NULL) NewBlock();
|
|
|
|
|
|
|
|
|
|
assert(n == 1);
|
|
|
|
|
if (store.last_freed != NULL) {
|
|
|
|
|
Ttype* out = static_cast<Ttype*>(store.last_freed);
|
|
|
|
|
store.last_freed = NULL;
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (store.next_position == block_size) NewBlock();
|
|
|
|
|
|
|
|
|
|
Ttype* next = static_cast<Ttype*>(store.current_block) + store.next_position;
|
|
|
|
|
store.next_position++;
|
|
|
|
|
return next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void deallocate(Ttype* p, size_t n)
|
|
|
|
|
{
|
|
|
|
|
store.last_freed = p;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Annotation wrapper class which also stores an iterator to the AnnoSet node which points to this annotation
|
|
|
|
|
* This is to enable erasing the AnnoSet node when calling Path::Fork without having to search the set
|
|
|
|
|
*/
|
|
|
|
|
template<class Tannotation>
|
|
|
|
|
struct AnnosWrapper : public Tannotation {
|
|
|
|
|
typename std::set<AnnoSetItem<Tannotation>, typename Tannotation::Comparator, AnnoSetAllocator<AnnoSetItem<Tannotation> > >::iterator self_iter;
|
|
|
|
|
|
|
|
|
|
AnnosWrapper(NodeID n, bool source = false) : Tannotation(n, source) {}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A slightly modified Dijkstra algorithm. Grades the paths not necessarily by
|
|
|
|
|
* distance, but by the value Tannotation computes. It uses the max_saturation
|
|
|
|
@ -258,21 +358,23 @@ bool CapacityAnnotation::IsBetter(const CapacityAnnotation *base, uint cap,
|
|
|
|
|
template<class Tannotation, class Tedge_iterator>
|
|
|
|
|
void MultiCommodityFlow::Dijkstra(NodeID source_node, PathVector &paths)
|
|
|
|
|
{
|
|
|
|
|
typedef std::set<Tannotation *, typename Tannotation::Comparator> AnnoSet;
|
|
|
|
|
typedef std::set<AnnoSetItem<Tannotation>, typename Tannotation::Comparator, AnnoSetAllocator<AnnoSetItem<Tannotation> > > AnnoSet;
|
|
|
|
|
Tedge_iterator iter(this->job);
|
|
|
|
|
uint size = this->job.Size();
|
|
|
|
|
AnnoSet annos;
|
|
|
|
|
AnnoSetAllocatorStore annos_store;
|
|
|
|
|
AnnoSet annos = AnnoSet(typename Tannotation::Comparator(), AnnoSetAllocator<Tannotation *>(annos_store));
|
|
|
|
|
paths.resize(size, NULL);
|
|
|
|
|
for (NodeID node = 0; node < size; ++node) {
|
|
|
|
|
Tannotation *anno = new Tannotation(node, node == source_node);
|
|
|
|
|
AnnosWrapper<Tannotation> *anno = new AnnosWrapper<Tannotation>(node, node == source_node);
|
|
|
|
|
anno->UpdateAnnotation();
|
|
|
|
|
annos.insert(anno);
|
|
|
|
|
anno->self_iter = annos.insert(AnnoSetItem<Tannotation>(anno)).first;
|
|
|
|
|
paths[node] = anno;
|
|
|
|
|
}
|
|
|
|
|
while (!annos.empty()) {
|
|
|
|
|
typename AnnoSet::iterator i = annos.begin();
|
|
|
|
|
Tannotation *source = *i;
|
|
|
|
|
AnnosWrapper<Tannotation> *source = static_cast<AnnosWrapper<Tannotation> *>(i->anno_ptr);
|
|
|
|
|
annos.erase(i);
|
|
|
|
|
source->self_iter = annos.end();
|
|
|
|
|
NodeID from = source->GetNode();
|
|
|
|
|
iter.SetNode(source_node, from);
|
|
|
|
|
for (NodeID to = iter.Next(); to != INVALID_NODE; to = iter.Next()) {
|
|
|
|
@ -286,12 +388,12 @@ void MultiCommodityFlow::Dijkstra(NodeID source_node, PathVector &paths)
|
|
|
|
|
}
|
|
|
|
|
/* punish in-between stops a little */
|
|
|
|
|
uint distance = DistanceMaxPlusManhattan(this->job[from].XY(), this->job[to].XY()) + 1;
|
|
|
|
|
Tannotation *dest = static_cast<Tannotation *>(paths[to]);
|
|
|
|
|
AnnosWrapper<Tannotation> *dest = static_cast<AnnosWrapper<Tannotation> *>(paths[to]);
|
|
|
|
|
if (dest->IsBetter(source, capacity, capacity - edge.Flow(), distance)) {
|
|
|
|
|
annos.erase(dest);
|
|
|
|
|
if (dest->self_iter != annos.end()) annos.erase(dest->self_iter);
|
|
|
|
|
dest->Fork(source, capacity, capacity - edge.Flow(), distance);
|
|
|
|
|
dest->UpdateAnnotation();
|
|
|
|
|
annos.insert(dest);
|
|
|
|
|
dest->self_iter = annos.insert(AnnoSetItem<Tannotation>(dest)).first;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -579,11 +681,11 @@ bool Greater(T x_anno, T y_anno, NodeID x, NodeID y)
|
|
|
|
|
* @param y Second capacity annotation.
|
|
|
|
|
* @return If x is better than y.
|
|
|
|
|
*/
|
|
|
|
|
bool CapacityAnnotation::Comparator::operator()(const CapacityAnnotation *x,
|
|
|
|
|
const CapacityAnnotation *y) const
|
|
|
|
|
bool CapacityAnnotation::Comparator::operator()(const AnnoSetItem<CapacityAnnotation> &x,
|
|
|
|
|
const AnnoSetItem<CapacityAnnotation> &y) const
|
|
|
|
|
{
|
|
|
|
|
return x != y && Greater<int>(x->GetAnnotation(), y->GetAnnotation(),
|
|
|
|
|
x->GetNode(), y->GetNode());
|
|
|
|
|
return x.anno_ptr != y.anno_ptr && Greater<int>(x.cached_annotation, y.cached_annotation,
|
|
|
|
|
x.node_id, y.node_id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -592,9 +694,9 @@ bool CapacityAnnotation::Comparator::operator()(const CapacityAnnotation *x,
|
|
|
|
|
* @param y Second distance annotation.
|
|
|
|
|
* @return If x is better than y.
|
|
|
|
|
*/
|
|
|
|
|
bool DistanceAnnotation::Comparator::operator()(const DistanceAnnotation *x,
|
|
|
|
|
const DistanceAnnotation *y) const
|
|
|
|
|
bool DistanceAnnotation::Comparator::operator()(const AnnoSetItem<DistanceAnnotation> &x,
|
|
|
|
|
const AnnoSetItem<DistanceAnnotation> &y) const
|
|
|
|
|
{
|
|
|
|
|
return x != y && !Greater<uint>(x->GetAnnotation(), y->GetAnnotation(),
|
|
|
|
|
x->GetNode(), y->GetNode());
|
|
|
|
|
return x.anno_ptr != y.anno_ptr && !Greater<uint>(x.cached_annotation, y.cached_annotation,
|
|
|
|
|
x.node_id, y.node_id);
|
|
|
|
|
}
|
|
|
|
|