Browse code

added checkpoint versioning

Tom Sherman authored on 23/08/2018 19:29:47
Showing8 changed files

... ...
@@ -1,6 +1,8 @@
1 1
 #ifndef __COGAPS_ARCHIVE_H__
2 2
 #define __COGAPS_ARCHIVE_H__
3 3
 
4
+#include "GapsAssert.h"
5
+
4 6
 #include <fstream>
5 7
 #include <stdint.h>
6 8
 
... ...
@@ -9,8 +11,8 @@
9 11
 #define ARCHIVE_WRITE (std::ios::out | std::ios::trunc)
10 12
 
11 13
 // magic number written to beginning of archive files
12
-// needs to be updated everytime to method of checkpointing changes
13
-#define ARCHIVE_MAGIC_NUM 0xCE45D32A
14
+// needs to be updated everytime the method of checkpointing changes
15
+#define ARCHIVE_MAGIC_NUM 0xCE45D32B // v3.3.22
14 16
 
15 17
 class Archive
16 18
 {
... ...
@@ -21,10 +23,28 @@ private:
21 23
 public:
22 24
 
23 25
     Archive(const std::string &path, std::ios_base::openmode flags)
24
-        : mStream(path.c_str(), std::ios::binary | flags)
25
-    {}
26
+        :
27
+    mStream(path.c_str(), std::ios::binary | flags)
28
+    {
29
+        if (flags == ARCHIVE_WRITE)
30
+        {
31
+            *this << static_cast<uint32_t>(ARCHIVE_MAGIC_NUM);
32
+        }
33
+        else // read
34
+        {
35
+            uint32_t magic = 0;
36
+            *this >> magic;
37
+            if (magic != ARCHIVE_MAGIC_NUM)
38
+            {
39
+                GAPS_ERROR("incompatible checkpoint file\n");
40
+            }            
41
+        }
42
+    }
26 43
 
27
-    void close() {mStream.close();}
44
+    void close()
45
+    {
46
+        mStream.close();
47
+    }
28 48
 
29 49
     template<typename T>
30 50
     friend Archive& writeToArchive(Archive &ar, T val)
... ...
@@ -3,6 +3,40 @@
3 3
 
4 4
 #include <vector>
5 5
 
6
+////////////////////////////////// HELPER //////////////////////////////////////
7
+
8
+// used with std::lower_bound
9
+static bool compareAtomLower(const Atom &lhs, uint64_t pos)
10
+{
11
+    return lhs.pos < pos;
12
+}
13
+
14
+// used with std::binary_search
15
+static bool compareAtom(const Atom &lhs, const Atom &rhs)
16
+{
17
+    return lhs.pos < rhs.pos;
18
+}
19
+
20
+// check if a position in contained in a vector of atoms
21
+static bool vecContains(const std::vector<Atom> &vec, uint64_t pos)
22
+{
23
+    Atom temp(pos, 0.f);
24
+    return std::binary_search(vec.begin(), vec.end(), temp, compareAtom);
25
+}
26
+
27
+// used in debug mode to check if vector is always sorted
28
+static bool isSorted(const std::vector<Atom> &vec)
29
+{
30
+    for (unsigned i = 1; i < vec.size(); ++i)
31
+    {
32
+        if (vec[i].pos <= vec[i-1].pos)
33
+        {
34
+            return false;
35
+        }
36
+    }
37
+    return true;
38
+}
39
+
6 40
 ////////////////////////////////// ATOM ////////////////////////////////////////
7 41
 
8 42
 Atom::Atom() : pos(0), mass(0.f) {}
... ...
@@ -46,7 +80,7 @@ bool AtomNeighborhood::hasRight()
46 80
 
47 81
 ////////////////////////////// ATOMIC DOMAIN ///////////////////////////////////
48 82
 
49
-AtomicDomain::AtomicDomain(unsigned nBins)
83
+AtomicDomain::AtomicDomain(uint64_t nBins)
50 84
 {
51 85
     uint64_t binLength = std::numeric_limits<uint64_t>::max() / nBins;
52 86
     mDomainLength = binLength * nBins;
... ...
@@ -55,12 +89,15 @@ AtomicDomain::AtomicDomain(unsigned nBins)
55 89
 Atom* AtomicDomain::front()
56 90
 {
57 91
     GAPS_ASSERT(size() > 0);
92
+
58 93
     return &(mAtoms.front());
59 94
 }
60 95
 
61 96
 Atom* AtomicDomain::randomAtom()
62 97
 {
63 98
     GAPS_ASSERT(size() > 0);
99
+    GAPS_ASSERT(isSorted(mAtoms));
100
+
64 101
     unsigned index = mRng.uniform32(0, mAtoms.size() - 1);
65 102
     return &(mAtoms[index]);
66 103
 }
... ...
@@ -68,6 +105,7 @@ Atom* AtomicDomain::randomAtom()
68 105
 AtomNeighborhood AtomicDomain::randomAtomWithNeighbors()
69 106
 {
70 107
     GAPS_ASSERT(size() > 0);
108
+
71 109
     unsigned index = mRng.uniform32(0, mAtoms.size() - 1);
72 110
     Atom* left = (index == 0) ? NULL : &(mAtoms[index - 1]);
73 111
     Atom* right = (index == mAtoms.size() - 1) ? NULL : &(mAtoms[index + 1]);
... ...
@@ -77,32 +115,12 @@ AtomNeighborhood AtomicDomain::randomAtomWithNeighbors()
77 115
 AtomNeighborhood AtomicDomain::randomAtomWithRightNeighbor()
78 116
 {
79 117
     GAPS_ASSERT(size() > 0);
118
+
80 119
     unsigned index = mRng.uniform32(0, mAtoms.size() - 1);
81 120
     Atom* right = (index == mAtoms.size() - 1) ? NULL : &(mAtoms[index + 1]);
82 121
     return AtomNeighborhood(NULL, &(mAtoms[index]), right);
83 122
 }
84 123
 
85
-static bool compareAtomLower(const Atom &lhs, uint64_t pos)
86
-{
87
-    return lhs.pos < pos;
88
-}
89
-
90
-static bool compareAtomUpper(uint64_t pos, const Atom &lhs)
91
-{
92
-    return lhs.pos < pos;
93
-}
94
-
95
-static bool compareAtom(const Atom &lhs, const Atom &rhs)
96
-{
97
-    return lhs.pos < rhs.pos;
98
-}
99
-
100
-static bool vecContains(const std::vector<Atom> &vec, uint64_t pos)
101
-{
102
-    Atom temp(pos, 0.f);
103
-    return std::binary_search(vec.begin(), vec.end(), temp, compareAtom);
104
-}
105
-
106 124
 uint64_t AtomicDomain::randomFreePosition() const
107 125
 {
108 126
     uint64_t pos = mRng.uniform64(0, mDomainLength);
... ...
@@ -149,6 +167,8 @@ void AtomicDomain::resetCache(unsigned n)
149 167
 void AtomicDomain::erase(uint64_t pos)
150 168
 {
151 169
     GAPS_ASSERT(size() > 0);
170
+    GAPS_ASSERT(vecContains(mAtoms, pos));
171
+
152 172
     std::vector<Atom>::iterator it;
153 173
     it = std::lower_bound(mAtoms.begin(), mAtoms.end(), pos, compareAtomLower);
154 174
     mAtoms.erase(it);
... ...
@@ -191,7 +211,7 @@ Archive& operator<<(Archive &ar, AtomicDomain &domain)
191 211
 Archive& operator>>(Archive &ar, AtomicDomain &domain)
192 212
 {
193 213
     Atom temp;
194
-    unsigned size = 0;
214
+    uint64_t size = 0;
195 215
     ar >> domain.mDomainLength >> domain.mRng >> size;
196 216
     for (unsigned i = 0; i < size; ++i)
197 217
     {
... ...
@@ -36,7 +36,7 @@ class AtomicDomain
36 36
 {
37 37
 public:
38 38
 
39
-    AtomicDomain(unsigned nBins);
39
+    AtomicDomain(uint64_t nBins);
40 40
 
41 41
     // access atoms
42 42
     Atom* front();
... ...
@@ -64,7 +64,7 @@ private:
64 64
     // size of atomic domain to ensure all bins are equal length
65 65
     uint64_t mDomainLength;
66 66
 
67
-    // domain storage, specialized hash map
67
+    // domain storage, sorted vector
68 68
     std::vector<Atom> mAtoms;
69 69
 
70 70
     // holds cache of operations
... ...
@@ -48,4 +48,4 @@
48 48
     #define DEBUG_PING   
49 49
 #endif
50 50
 
51
-#endif
52 51
\ No newline at end of file
52
+#endif // __COGAPS_GAPS_ASSERT_H__
53 53
\ No newline at end of file
... ...
@@ -253,37 +253,6 @@ void GibbsSampler<T, MatA, MatB>::setMatrix(const Matrix &mat)
253 253
     mMatrix = mat;
254 254
 }
255 255
 
256
-template <class T, class MatA, class MatB>
257
-void GibbsSampler<T, MatA, MatB>::update(unsigned nSteps, unsigned nCores)
258
-{
259
-    unsigned n = 0;
260
-    while (n < nSteps)
261
-    {
262
-        // populate queue, prepare domain for this queue
263
-        //mQueue.populate(mDomain, nSteps - n);
264
-        mQueue.populate(mDomain, 1);
265
-        mDomain.resetCache(mQueue.size());
266
-        n += mQueue.size();
267
-        
268
-        // update average queue count
269
-        #ifdef GAPS_DEBUG
270
-        mNumQueues += 1.f;
271
-        mAvgQueue *= (mNumQueues - 1.f) / mNumQueues;
272
-        mAvgQueue += mQueue.size() / mNumQueues;
273
-        #endif
274
-
275
-        // process all proposed updates
276
-        #pragma omp parallel for num_threads(nCores)
277
-        for (unsigned i = 0; i < mQueue.size(); ++i)
278
-        {
279
-            processProposal(&mQueue[i]);
280
-        }
281
-
282
-        mDomain.flushCache();
283
-        mQueue.clear();
284
-    }
285
-}
286
-
287 256
 template <class T, class MatA, class MatB>
288 257
 unsigned GibbsSampler<T, MatA, MatB>::dataRows() const
289 258
 {
... ...
@@ -308,50 +277,45 @@ uint64_t GibbsSampler<T, MatA, MatB>::nAtoms() const
308 277
     return mDomain.size();
309 278
 }
310 279
 
311
-#ifdef GAPS_DEBUG
312 280
 template <class T, class MatA, class MatB>
313
-float GibbsSampler<T, MatA, MatB>::getAvgQueue() const
314
-{
315
-    return mAvgQueue;
316
-}
317
-
318
-template <class T, class MatA, class MatB>
319
-bool GibbsSampler<T, MatA, MatB>::internallyConsistent()
281
+T* GibbsSampler<T, MatA, MatB>::impl()
320 282
 {
321
-    return true;
283
+    return static_cast<T*>(this);
322 284
 }
323
-#endif
324 285
 
325 286
 template <class T, class MatA, class MatB>
326
-Archive& operator<<(Archive &ar, GibbsSampler<T, MatA, MatB> &sampler)
287
+void GibbsSampler<T, MatA, MatB>::update(unsigned nSteps, unsigned nCores)
327 288
 {
328
-    ar << sampler.mMatrix << sampler.mAPMatrix << sampler.mQueue <<
329
-        sampler.mDomain << sampler.mLambda << sampler.mMaxGibbsMass <<
330
-        sampler.mAnnealingTemp << sampler.mNumRows << sampler.mNumCols <<
331
-        sampler.mBinSize << sampler.mAvgQueue << sampler.mNumQueues;
332
-    return ar;
333
-}
289
+    unsigned n = 0;
290
+    while (n < nSteps)
291
+    {
292
+        // populate queue, prepare domain for this queue
293
+        mQueue.populate(mDomain, nSteps - n);
294
+        mDomain.resetCache(mQueue.size());
295
+        n += mQueue.size();
296
+        
297
+        // update average queue count
298
+        #ifdef GAPS_DEBUG
299
+        mNumQueues += 1.f;
300
+        mAvgQueue *= (mNumQueues - 1.f) / mNumQueues;
301
+        mAvgQueue += mQueue.size() / mNumQueues;
302
+        #endif
334 303
 
335
-template <class T, class MatA, class MatB>
336
-Archive& operator>>(Archive &ar, GibbsSampler<T, MatA, MatB> &sampler)
337
-{
338
-    ar >> sampler.mMatrix >> sampler.mAPMatrix >> sampler.mQueue >>
339
-        sampler.mDomain >> sampler.mLambda >> sampler.mMaxGibbsMass >>
340
-        sampler.mAnnealingTemp >> sampler.mNumRows >> sampler.mNumCols >>
341
-        sampler.mBinSize >> sampler.mAvgQueue >> sampler.mNumQueues;
342
-    return ar;
343
-}
304
+        // process all proposed updates
305
+        #pragma omp parallel for num_threads(nCores)
306
+        for (unsigned i = 0; i < mQueue.size(); ++i)
307
+        {
308
+            processProposal(&mQueue[i]);
309
+        }
344 310
 
345
-template <class T, class MatA, class MatB>
346
-T* GibbsSampler<T, MatA, MatB>::impl()
347
-{
348
-    return static_cast<T*>(this);
311
+        mDomain.flushCache();
312
+        mQueue.clear();
313
+    }
349 314
 }
350 315
 
351 316
 template <class T, class MatA, class MatB>
352 317
 void GibbsSampler<T, MatA, MatB>::processProposal(AtomicProposal *prop)
353 318
 {
354
-    unsigned r1 = 0, c1 = 0, r2 = 0, c2 = 0;
355 319
     switch (prop->type)
356 320
     {
357 321
         case 'B':
... ...
@@ -413,8 +377,9 @@ void GibbsSampler<T, MatA, MatB>::death(AtomicProposal *prop)
413 377
     unsigned col = impl()->getCol(prop->atom1->pos);
414 378
 
415 379
     // kill off atom
416
-    mMatrix(row, col) = gaps::max(mMatrix(row, col) - prop->atom1->mass, 0.f);
417
-    impl()->updateAPMatrix(row, col, -1.f * prop->atom1->mass);
380
+    float newVal = gaps::max(mMatrix(row, col) - prop->atom1->mass, 0.f);
381
+    impl()->updateAPMatrix(row, col, newVal - mMatrix(row, col));
382
+    mMatrix(row, col) = newVal;
418 383
 
419 384
     // calculate rebirth mass
420 385
     float rebirthMass = prop->atom1->mass;
... ...
@@ -459,13 +424,13 @@ void GibbsSampler<T, MatA, MatB>::move(AtomicProposal *prop)
459 424
         r2, c2, prop->atom1->mass);
460 425
     if (deltaLL * mAnnealingTemp > std::log(prop->rng.uniform()))
461 426
     {
462
-        //mDomain.cacheMove(prop->atom1->pos, prop->moveDest, prop->atom1->mass);
463
-        prop->atom1->pos = prop->moveDest; // temporary for vector domain
427
+        prop->atom1->pos = prop->moveDest;
464 428
 
465
-        mMatrix(r1, c1) = gaps::max(mMatrix(r1, c1) - prop->atom1->mass, 0.f);
466
-        mMatrix(r2, c2) += prop->atom1->mass;
429
+        float newVal = gaps::max(mMatrix(r1, c1) - prop->atom1->mass, 0.f);
430
+        impl()->updateAPMatrix(r1, c1, newVal - mMatrix(r1, c1));
431
+        mMatrix(r1, c1) = newVal;
467 432
 
468
-        impl()->updateAPMatrix(r1, c1, -1.f * prop->atom1->mass);
433
+        mMatrix(r2, c2) += prop->atom1->mass;
469 434
         impl()->updateAPMatrix(r2, c2, prop->atom1->mass);
470 435
     }
471 436
 }
... ...
@@ -565,10 +530,15 @@ float d1, unsigned r1, unsigned c1, unsigned r2, unsigned c2)
565 530
         mQueue.rejectDeath();
566 531
     }
567 532
 
568
-    mMatrix(r1, c1) += d1;
569
-    mMatrix(r2, c2) += d2;
570
-    impl()->updateAPMatrix(r1, c1, d1);
571
-    impl()->updateAPMatrix(r2, c2, d2);
533
+    // ensure matrix values don't go negative (truncation error at fault)
534
+    float v1 = gaps::max(mMatrix(r1, c1) + d1, 0.f);
535
+    impl()->updateAPMatrix(r1, c1, v1 - mMatrix(r1, c1));
536
+    mMatrix(r1, c1) = v1;
537
+
538
+
539
+    float v2 = gaps::max(mMatrix(r2, c2) + d2, 0.f);
540
+    impl()->updateAPMatrix(r2, c2, v2 - mMatrix(r2, c2));
541
+    mMatrix(r2, c2) = v2;
572 542
 }
573 543
 
574 544
 template <class T, class MatA, class MatB>
... ...
@@ -618,4 +588,36 @@ float m1, float m2, GapsRng *rng)
618 588
     return std::pair<float, bool>(0.f, false);
619 589
 }
620 590
 
621
-#endif
591
+#ifdef GAPS_DEBUG
592
+template <class T, class MatA, class MatB>
593
+float GibbsSampler<T, MatA, MatB>::getAvgQueue() const
594
+{
595
+    return mAvgQueue;
596
+}
597
+
598
+template <class T, class MatA, class MatB>
599
+bool GibbsSampler<T, MatA, MatB>::internallyConsistent()
600
+{
601
+    return true;
602
+}
603
+#endif // GAPS_DEBUG
604
+
605
+template <class T, class MatA, class MatB>
606
+Archive& operator<<(Archive &ar, GibbsSampler<T, MatA, MatB> &s)
607
+{
608
+    ar << s.mMatrix << s.mAPMatrix << s.mQueue << s.mDomain << s.mLambda
609
+        << s.mMaxGibbsMass << s.mAnnealingTemp << s.mNumRows << s.mNumCols
610
+        << s.mBinSize << s.mAvgQueue << s.mNumQueues;
611
+    return ar;
612
+}
613
+
614
+template <class T, class MatA, class MatB>
615
+Archive& operator>>(Archive &ar, GibbsSampler<T, MatA, MatB> &s)
616
+{
617
+    ar >> s.mMatrix >> s.mAPMatrix >> s.mQueue >> s.mDomain >> s.mLambda
618
+        >> s.mMaxGibbsMass >> s.mAnnealingTemp >> s.mNumRows >> s.mNumCols
619
+        >> s.mBinSize >> s.mAvgQueue >> s.mNumQueues;
620
+    return ar;
621
+}
622
+
623
+#endif // __COGAPS_GIBBS_SAMPLER_H__
... ...
@@ -2,12 +2,38 @@
2 2
 #include "ProposalQueue.h"
3 3
 #include "math/Random.h"
4 4
 
5
+//////////////////////////////// AtomicProposal ////////////////////////////////
6
+
7
+// birth
8
+AtomicProposal::AtomicProposal(char t, uint64_t pos)
9
+    : type(t), birthPos(pos), moveDest(0), atom1(NULL), atom2(NULL)
10
+{}
11
+    
12
+// death
13
+AtomicProposal::AtomicProposal(char t, Atom *atom)
14
+    : type(t), birthPos(0), moveDest(0), atom1(atom), atom2(NULL)
15
+{}
16
+
17
+// move
18
+AtomicProposal::AtomicProposal(char t, Atom *atom, uint64_t dest)
19
+    : type(t), birthPos(0), moveDest(dest), atom1(atom), atom2(NULL)
20
+{}
21
+
22
+// exchange
23
+AtomicProposal::AtomicProposal(char t, Atom *a1, Atom *a2)
24
+    : type(t), birthPos(0), moveDest(0), atom1(a1), atom2(a2)
25
+{}
26
+
27
+
28
+//////////////////////////////// ProposalQueue /////////////////////////////////
29
+
5 30
 ProposalQueue::ProposalQueue(unsigned primaryDimSize, unsigned secondaryDimSize)
6 31
     :
7 32
 mMinAtoms(0), mMaxAtoms(0), mNumBins(primaryDimSize * secondaryDimSize),
8 33
 mBinLength(std::numeric_limits<uint64_t>::max() / mNumBins),
9 34
 mSecondaryDimLength(mBinLength * secondaryDimSize),
10
-mDomainLength(mBinLength * mNumBins), mSecondaryDimSize(secondaryDimSize)
35
+mDomainLength(mBinLength * mNumBins), mSecondaryDimSize(secondaryDimSize),
36
+mAlpha(0.f), mU1(0.f), mU2(0.f), mUseCachedRng(false)
11 37
 {
12 38
     mUsedIndices.setDimensionSize(primaryDimSize);
13 39
 }
... ...
@@ -19,6 +45,9 @@ void ProposalQueue::setAlpha(float alpha)
19 45
 
20 46
 void ProposalQueue::populate(AtomicDomain &domain, unsigned limit)
21 47
 {
48
+    GAPS_ASSERT(mMinAtoms == mMaxAtoms);
49
+    GAPS_ASSERT(mMaxAtoms == domain.size());
50
+
22 51
     unsigned nIter = 0;
23 52
     bool success = true;
24 53
     while (nIter++ < limit && success)
... ...
@@ -33,10 +62,11 @@ void ProposalQueue::populate(AtomicDomain &domain, unsigned limit)
33 62
 
34 63
 void ProposalQueue::clear()
35 64
 {
65
+    GAPS_ASSERT(mMinAtoms == mMaxAtoms);
66
+
36 67
     mQueue.clear();
37 68
     mUsedPositions.clear();
38 69
     mUsedIndices.clear();
39
-    GAPS_ASSERT(mMinAtoms == mMaxAtoms);
40 70
 }
41 71
 
42 72
 unsigned ProposalQueue::size() const
... ...
@@ -46,6 +76,9 @@ unsigned ProposalQueue::size() const
46 76
 
47 77
 AtomicProposal& ProposalQueue::operator[](int n)
48 78
 {
79
+    GAPS_ASSERT(mQueue.size() > 0);
80
+    GAPS_ASSERT(n < mQueue.size());
81
+
49 82
     return mQueue[n];
50 83
 }
51 84
 
... ...
@@ -130,7 +163,8 @@ unsigned ProposalQueue::secondaryIndex(uint64_t pos) const
130 163
 }
131 164
 
132 165
 // TODO add atoms with empty mass? fill in mass in gibbssampler?
133
-// inserting invalidates previous pointers
166
+// inserting invalidates previous pointers, but not inserting
167
+// prevents them from being selected for death
134 168
 bool ProposalQueue::birth(AtomicDomain &domain)
135 169
 {
136 170
     uint64_t pos = domain.randomFreePosition();
... ...
@@ -198,7 +232,7 @@ bool ProposalQueue::move(AtomicDomain &domain)
198 232
 bool ProposalQueue::exchange(AtomicDomain &domain)
199 233
 {
200 234
     AtomNeighborhood hood = domain.randomAtomWithRightNeighbor();
201
-    Atom* a1 = hood.center;    
235
+    Atom* a1 = hood.center;
202 236
     Atom* a2 = hood.hasRight() ? hood.right : domain.front();
203 237
 
204 238
     if (hood.hasRight()) // has neighbor
... ...
@@ -242,20 +276,18 @@ bool ProposalQueue::exchange(AtomicDomain &domain)
242 276
     return true;
243 277
 }
244 278
 
245
-Archive& operator<<(Archive &ar, ProposalQueue &queue)
279
+Archive& operator<<(Archive &ar, ProposalQueue &q)
246 280
 {
247
-    ar << queue.mMinAtoms << queue.mMaxAtoms << queue.mNumBins
248
-        << queue.mBinLength << queue.mSecondaryDimLength << queue.mDomainLength
249
-        << queue.mSecondaryDimSize << queue.mAlpha << queue.mRng
250
-        << queue.mU1 << queue.mU2 << queue.mUseCachedRng;
281
+    ar << q.mMinAtoms << q.mMaxAtoms << q.mNumBins << q.mBinLength
282
+        << q.mSecondaryDimLength << q.mDomainLength << q.mSecondaryDimSize
283
+        << q.mAlpha << q.mRng;
251 284
     return ar;
252 285
 }
253 286
 
254
-Archive& operator>>(Archive &ar, ProposalQueue &queue)
287
+Archive& operator>>(Archive &ar, ProposalQueue &q)
255 288
 {
256
-    ar >> queue.mMinAtoms >> queue.mMaxAtoms >> queue.mNumBins
257
-        >> queue.mBinLength >> queue.mSecondaryDimLength >> queue.mDomainLength
258
-        >> queue.mSecondaryDimSize >> queue.mAlpha >> queue.mRng
259
-        >> queue.mU1 >> queue.mU2 >> queue.mUseCachedRng;
289
+    ar >> q.mMinAtoms >> q.mMaxAtoms >> q.mNumBins >> q.mBinLength
290
+        >> q.mSecondaryDimLength >> q.mDomainLength >> q.mSecondaryDimSize
291
+        >> q.mAlpha >> q.mRng;
260 292
     return ar;
261 293
 }
... ...
@@ -21,25 +21,10 @@ struct AtomicProposal
21 21
 
22 22
     mutable GapsRng rng;
23 23
 
24
-    // birth
25
-    AtomicProposal(char t, uint64_t pos)
26
-        : type(t), birthPos(pos), moveDest(0), atom1(NULL), atom2(NULL)
27
-    {}
28
-        
29
-    // death
30
-    AtomicProposal(char t, Atom *atom)
31
-        : type(t), birthPos(0), moveDest(0), atom1(atom), atom2(NULL)
32
-    {}
33
-
34
-    // move
35
-    AtomicProposal(char t, Atom *atom, uint64_t dest)
36
-        : type(t), birthPos(0), moveDest(dest), atom1(atom), atom2(NULL)
37
-    {}
38
-
39
-    // exchange
40
-    AtomicProposal(char t, Atom *a1, Atom *a2)
41
-        : type(t), birthPos(0), moveDest(0), atom1(a1), atom2(a2)
42
-    {}
24
+    AtomicProposal(char t, uint64_t pos); // birth
25
+    AtomicProposal(char t, Atom *atom); // death
26
+    AtomicProposal(char t, Atom *atom, uint64_t dest); // move
27
+    AtomicProposal(char t, Atom *a1, Atom *a2); // exchange
43 28
 };
44 29
 
45 30
 class ProposalQueue
... ...
@@ -226,8 +226,8 @@ things like hardware and data size. The best approach is to play around with
226 226
 different values and see how it effects the estimated time.
227 227
 
228 228
 ```{r}
229
-CoGAPS(SimpSim.data, nIterations=10000, outputFrequency=5000, nThreads=1)
230
-CoGAPS(SimpSim.data, nIterations=10000, outputFrequency=5000, nThreads=4)
229
+CoGAPS(SimpSim.data, nIterations=10000, outputFrequency=5000, nThreads=1, seed=5)
230
+CoGAPS(SimpSim.data, nIterations=10000, outputFrequency=5000, nThreads=4, seed=5)
231 231
 ```
232 232
 
233 233
 Note this method relies on CoGAPS being compiled with OpenMP support, use