1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
|
#ifndef ATOMIC_MATRIX
#define ATOMIC_MATRIX
#include "tbb/concurrent_vector.h"
#include "tbb/atomic.h"
#include "SalmonMath.hpp"
#include <vector>
template <typename T>
class AtomicMatrix {
public:
AtomicMatrix(size_t nRow, size_t nCol, T alpha, bool logSpace = true) :
storage_(nRow * nCol, logSpace ? std::log(alpha) : alpha),
rowsums_(nRow, logSpace ? std::log(nCol * alpha) : nCol * alpha),
nRow_(nRow),
nCol_(nCol),
alpha_(alpha),
logSpace_(logSpace) {
}
void incrementUnnormalized(size_t rowInd, size_t colInd, T amt) {
using salmon::math::logAdd;
size_t k = rowInd * nCol_ + colInd;
if (logSpace_) {
T oldVal = storage_[k];
T retVal = oldVal;
T newVal = logAdd(oldVal, amt);
do {
oldVal = retVal;
newVal = logAdd(oldVal, amt);
retVal = storage_[k].compare_and_swap(newVal, oldVal);
} while (retVal != oldVal);
} else {
T oldVal = storage_[k];
T retVal = oldVal;
T newVal = oldVal + amt;
do {
oldVal = retVal;
newVal = oldVal + amt;
retVal = storage_[k].compare_and_swap(newVal, oldVal);
} while (retVal != oldVal);
}
}
void computeRowSums() {
for (size_t rowInd = 0; rowInd < nRow_; ++rowInd) {
T rowSum = salmon::math::LOG_0;
for (size_t colInd = 0; colInd < nCol_; ++colInd) {
size_t k = rowInd * nCol_ + colInd;
rowSum = logAdd(rowSum, storage_[k]);
}
rowsums_[rowInd] = rowSum;
}
}
void increment(size_t rowInd, size_t colInd, T amt) {
using salmon::math::logAdd;
size_t k = rowInd * nCol_ + colInd;
if (logSpace_) {
T oldVal = storage_[k];
T retVal = oldVal;
T newVal = logAdd(oldVal, amt);
do {
oldVal = retVal;
newVal = logAdd(oldVal, amt);
retVal = storage_[k].compare_and_swap(newVal, oldVal);
} while (retVal != oldVal);
oldVal = rowsums_[rowInd];
retVal = oldVal;
newVal = logAdd(oldVal, amt);
do {
oldVal = retVal;
newVal = logAdd(oldVal, amt);
retVal = rowsums_[rowInd].compare_and_swap(newVal, oldVal);
} while (retVal != oldVal);
} else {
T oldVal = storage_[k];
T retVal = oldVal;
T newVal = oldVal + amt;
do {
oldVal = retVal;
newVal = oldVal + amt;
retVal = storage_[k].compare_and_swap(newVal, oldVal);
} while (retVal != oldVal);
oldVal = rowsums_[rowInd];
retVal = oldVal;
newVal = oldVal + amt;
do {
oldVal = retVal;
newVal = oldVal + amt;
retVal = rowsums_[rowInd].compare_and_swap(newVal, oldVal);
} while (retVal != oldVal);
}
}
T operator()(size_t rowInd, size_t colInd, bool normalized = true) {
size_t k = rowInd * nCol_ + colInd;
if (logSpace_) {
return storage_[k] - rowsums_[rowInd];
} else {
return storage_[k] / rowsums_[rowInd];
}
}
private:
std::vector<tbb::atomic<T>> storage_;
std::vector<tbb::atomic<T>> rowsums_;
size_t nRow_, nCol_;
T alpha_;
bool logSpace_;
};
#endif // ATOMIC_MATRIX
|