You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

212 lines
9.4 KiB

#include "BucketPriorityQueue.h"
#include "storm/utility/macros.h"
#include "storm/adapters/RationalFunctionAdapter.h"
#include <cmath>
namespace storm {
namespace storage {
template<typename PriorityType>
BucketPriorityQueue<PriorityType>::BucketPriorityQueue(size_t nrBuckets, double lowerValue, double ratio, bool higher) : buckets(nrBuckets), currentBucket(nrBuckets), nrUnsortedItems(0), lowerValue(lowerValue), higher(higher), logBase(std::log(ratio)), nrBuckets(nrBuckets) {
compare = ([](PriorityTypePointer a, PriorityTypePointer b) {
return *a < *b;
});
}
template<typename PriorityType>
void BucketPriorityQueue<PriorityType>::fix() {
if (currentBucket < nrBuckets && nrUnsortedItems > buckets[currentBucket].size() / 10) {
// Sort current bucket
std::make_heap(buckets[currentBucket].begin(), buckets[currentBucket].end(), compare);
nrUnsortedItems = 0;
}
}
template<typename PriorityType>
bool BucketPriorityQueue<PriorityType>::empty() const {
return currentBucket == nrBuckets && immediateBucket.empty();
}
template<typename PriorityType>
size_t BucketPriorityQueue<PriorityType>::size() const {
size_t size = immediateBucket.size();
for (size_t i = currentBucket; currentBucket < nrBuckets; ++i) {
size += buckets[i].size();
}
return size;
}
template<typename PriorityType>
typename BucketPriorityQueue<PriorityType>::PriorityTypePointer const& BucketPriorityQueue<PriorityType>::top() const {
if (!immediateBucket.empty()) {
return immediateBucket.back();
}
STORM_LOG_ASSERT(!empty(), "BucketPriorityQueue is empty");
return buckets[currentBucket].front();
}
template<typename PriorityType>
void BucketPriorityQueue<PriorityType>::push(PriorityTypePointer const& item) {
if (item->isExpand()) {
immediateBucket.push_back(item);
return;
}
size_t bucket = getBucket(item->getPriority());
if (bucket < currentBucket) {
currentBucket = bucket;
nrUnsortedItems = 0;
}
buckets[bucket].push_back(item);
if (bucket == currentBucket) {
// Inserted in first bucket
if (AUTOSORT) {
std::push_heap(buckets[currentBucket].begin(), buckets[currentBucket].end(), compare);
} else {
++nrUnsortedItems;
}
}
}
template<typename PriorityType>
void BucketPriorityQueue<PriorityType>::update(PriorityTypePointer const& item, double oldPriority) {
STORM_LOG_ASSERT(!item->isExpand(), "Item is marked for expansion");
size_t newBucket = getBucket(item->getPriority());
size_t oldBucket = getBucket(oldPriority);
if (oldBucket == newBucket) {
if (currentBucket < newBucket) {
// No change as the bucket is not sorted yet
} else {
if (AUTOSORT) {
// Sort first bucket
fix();
} else {
++nrUnsortedItems;
}
}
} else {
// Move to new bucket
STORM_LOG_ASSERT(newBucket < oldBucket, "Will update item "<< item->getId() << " from " << oldBucket << " to higher bucket " << newBucket);
if (newBucket < currentBucket) {
currentBucket = newBucket;
nrUnsortedItems = 0;
}
// Remove old entry by swap-and-pop
if (buckets[oldBucket].size() >= 2) {
// Find old index by linear search
// Notice: using a map to remember index was not efficient
size_t oldIndex = 0;
for ( ; oldIndex < buckets[oldBucket].size(); ++oldIndex) {
if (buckets[oldBucket][oldIndex]->getId() == item->getId()) {
break;
}
}
STORM_LOG_ASSERT(oldIndex < buckets[oldBucket].size(), "Id " << item->getId() << " not found");
std::iter_swap(buckets[oldBucket].begin() + oldIndex, buckets[oldBucket].end() - 1);
}
buckets[oldBucket].pop_back();
// Insert new element
buckets[newBucket].push_back(item);
if (newBucket == currentBucket) {
if (AUTOSORT) {
// Sort in first bucket
std::push_heap(buckets[currentBucket].begin(), buckets[currentBucket].end(), compare);
} else {
++nrUnsortedItems;
}
}
}
}
template<typename PriorityType>
typename BucketPriorityQueue<PriorityType>::PriorityTypePointer BucketPriorityQueue<PriorityType>::pop() {
if (!immediateBucket.empty()) {
PriorityTypePointer item = immediateBucket.back();
immediateBucket.pop_back();
return item;
}
STORM_LOG_ASSERT(!empty(), "BucketPriorityQueue is empty");
std::pop_heap(buckets[currentBucket].begin(), buckets[currentBucket].end(), compare);
PriorityTypePointer item = buckets[currentBucket].back();
buckets[currentBucket].pop_back();
if (buckets[currentBucket].empty()) {
// Find next bucket with elements
for ( ; currentBucket < nrBuckets; ++currentBucket) {
if (!buckets[currentBucket].empty()) {
nrUnsortedItems = buckets[currentBucket].size();
if (AUTOSORT) {
fix();
}
break;
}
}
}
return item;
}
template<typename PriorityType>
size_t BucketPriorityQueue<PriorityType>::getBucket(double priority) const {
STORM_LOG_ASSERT(priority >= lowerValue, "Priority " << priority << " is too low");
// For possible values greater 1
double tmpBucket = std::log(priority - lowerValue) / logBase;
tmpBucket += buckets.size() / 2;
if (tmpBucket < 0) {
tmpBucket = 0;
}
size_t newBucket = static_cast<size_t>(tmpBucket);
// For values ensured to be lower 1
if (newBucket >= nrBuckets) {
newBucket = nrBuckets - 1;
}
if (!higher) {
newBucket = nrBuckets-1 - newBucket;
}
STORM_LOG_ASSERT(newBucket < nrBuckets, "Priority " << priority << " is too high");
return newBucket;
}
template<typename PriorityType>
void BucketPriorityQueue<PriorityType>::print(std::ostream& out) const {
out << "Bucket priority queue with size " << buckets.size() << ", lower value: " << lowerValue << " and logBase: " << logBase << std::endl;
out << "Immediate bucket: ";
for (auto item : immediateBucket) {
out << item->getId() << ", ";
}
out << std::endl;
out << "Current bucket (" << currentBucket << ") has " << nrUnsortedItems << " unsorted items" << std::endl;
for (size_t bucket = 0; bucket < buckets.size(); ++bucket) {
if (!buckets[bucket].empty()) {
out << "Bucket " << bucket << ":" << std::endl;
for (auto item : buckets[bucket]) {
out << "\t" << item->getId() << ": " << item->getPriority() << std::endl;
}
}
}
}
template<typename PriorityType>
void BucketPriorityQueue<PriorityType>::printSizes(std::ostream& out) const {
out << "Bucket sizes: " << immediateBucket.size() << " | ";
for (size_t bucket = 0; bucket < buckets.size(); ++bucket) {
out << buckets[bucket].size() << " ";
}
std::cout << std::endl;
}
// Template instantiations
template class BucketPriorityQueue<storm::builder::DFTExplorationHeuristic<double>>;
template class BucketPriorityQueue<storm::builder::DFTExplorationHeuristicDepth<double>>;
template class BucketPriorityQueue<storm::builder::DFTExplorationHeuristicProbability<double>>;
template class BucketPriorityQueue<storm::builder::DFTExplorationHeuristicBoundDifference<double>>;
#ifdef STORM_HAVE_CARL
template class BucketPriorityQueue<storm::builder::DFTExplorationHeuristic<storm::RationalFunction>>;
template class BucketPriorityQueue<storm::builder::DFTExplorationHeuristicDepth<storm::RationalFunction>>;
template class BucketPriorityQueue<storm::builder::DFTExplorationHeuristicProbability<storm::RationalFunction>>;
template class BucketPriorityQueue<storm::builder::DFTExplorationHeuristicBoundDifference<storm::RationalFunction>>;
#endif
}
}