-
Notifications
You must be signed in to change notification settings - Fork 5
/
multispot5.cc
2401 lines (1921 loc) · 78.6 KB
/
multispot5.cc
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include <cstdlib>
#include <cerrno>
#include <cstring>
#include <stack>
#include <algorithm>
#include <climits>
#include <iomanip>
#include <map>
#include <memory>
#include <cvd/image_io.h>
#include <cvd/image_convert.h>
#include <cvd/morphology.h>
#include <cvd/connected_components.h>
#include <cvd/draw.h>
#include <cvd/vector_image_ref.h>
#include <cvd/byte.h>
// #include <cvd/random.h>
#include <cvd/timer.h>
#include <gvars3/instances.h>
#include <TooN/functions/derivatives.h>
#include <TooN/determinant.h>
#include <TooN/SymEigen.h>
#include <TooN/optimization/conjugate_gradient.h>
#include "conjugate_gradient_only.h"
#include "forward_algorithm.h"
#include "numerical_derivatives.h"
#include "storm.h"
#include "storm_imagery.h"
#include "debug.h"
#include "sampled_multispot.h"
#include "mt19937.h"
#include "utility.h"
#include "multispot5.h"
#define LOGVERSION_MAJOR 1
#define LOGVERSION_MINOR 2
//For benchmarking...
#define TIME(X)
//#define TIME(X) X
using namespace std;
using namespace CVD;
using namespace GVars3;
using namespace TooN;
///Empty destructor
UserInterfaceCallback::~UserInterfaceCallback(){}
///User interface callback class which does nothing.
class NullUICallback: public UserInterfaceCallback
{
void per_spot(int, int, int, int){};
void per_modification(int, int, int){};
void per_pass(int, int, const std::vector<TooN::Vector<4> >&){};
void perhaps_stop(){};
};
///Factory function to generate an instance of NullGraphics
///@ingroup gStorm
auto_ptr<UserInterfaceCallback> null_ui()
{
return auto_ptr<UserInterfaceCallback>(new NullUICallback);
}
//Declare the graphics classes.
//These provide all the debug drawing operations so that the code can run in GUI and
//headless mode easily and without macros.
FitSpotsGraphics::~FitSpotsGraphics(){}
///Graphics class which does absoloutely nothing
///@ingroup gStorm
class NullGraphics: public FitSpotsGraphics
{
public:
virtual void init(CVD::ImageRef){}
virtual void draw_krap(const std::vector<TooN::Vector<4> >&, const CVD::Image<CVD::byte>&, const BBox&, int, TooN::Vector<4>){}
virtual void swap(){}
virtual void draw_pixels(const std::vector<CVD::ImageRef>&, float, float, float, float){}
virtual void draw_bbox(const BBox&){}
virtual void glDrawCross(const TooN::Vector<2>&, int){}
virtual ~NullGraphics(){}
};
///Factory function to generate an instance of NullGraphics
///@ingroup gStorm
auto_ptr<FitSpotsGraphics> null_graphics()
{
return auto_ptr<FitSpotsGraphics>(new NullGraphics);
}
///There are two sensible ways of storing the state vector of spot positions.
///This function converts between them. See also spots_to_vector.
///@param s list of spots to convert
///@ingroup gUtility
Vector<> spots_to_Vector(const vector<Vector<4> >& s)
{
Vector<> r(s.size()*4);
for(unsigned int i=0; i < s.size(); i++)
{
r[i*4+0] = s[i][0];
r[i*4+1] = s[i][1];
r[i*4+2] = s[i][2];
r[i*4+3] = s[i][3];
}
return r;
}
///There are two sensible ways of storing the state vector of spot positions.
///This function converts between them. See also spots_to_Vector.
///@param s list of spots to convert
///@ingroup gUtility
vector<Vector<4> > spots_to_vector(const Vector<>& s)
{
vector<Vector<4> > r(s.size()/4);
for(unsigned int i=0; i < r.size(); i++)
r[i] = s.slice<Dynamic, 4>(i*4, 4);
return r;
}
///Normalize an image for display purposes.
///@ingroup gUtility
Image<CVD::byte> scale_to_bytes(const Image<float>& im, float lo, float hi)
{
Image<CVD::byte> out(im.size());
for(int r=0; r < out.size().y-0; r++)
for(int c=0; c < out.size().x-0; c++)
out[r][c] = (int)floor((im[r][c]-lo)*255/(hi-lo));
return out;
}
///Normalize an image for display purposes.
///@ingroup gUtility
Image<CVD::byte> scale_to_bytes(const Image<float>& im)
{
float lo = *min_element(im.begin(), im.end());
float hi = *max_element(im.begin(), im.end());
Image<CVD::byte> out(im.size());
for(int r=0; r < out.size().y-0; r++)
for(int c=0; c < out.size().x-0; c++)
out[r][c] = (int)floor((im[r][c]-lo)*255/(hi-lo));
return out;
}
///Average the input image stack for display purposes
///@ingroup gUtility
Image<float> average_image(const vector<Image<float> >& ims)
{
assert_same_size(ims);
Image<float> r(ims[0].size(), 0);
for(unsigned int i=0; i < ims.size(); i++)
transform(r.begin(), r.end(), ims[i].begin(), r.begin(), plus<float>());
transform(r.begin(), r.end(), r.begin(), bind2nd(multiplies<float>(), 1./ims.size()));
return r;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
///Closure hoding the data required do use GibbsSampler2
///See FitSpots for naming of variables.
///@ingroup gStorm
class DataForMCMC
{
protected:
const vector<ImageRef>& pixels;
const vector<vector<double> >& pixel_intensities;//[frame][pixel]
const double mu_brightness, sigma_brightness, mu_blur, sigma_blur;
const double variance;
const int samples, sample_iterations;
const Matrix<3> A;
const Vector<3> pi;
MT19937& rng;
public:
MT19937& get_rng()const
{
return rng;
}
public:
DataForMCMC(const vector<ImageRef>& pixels_,
const vector<vector<double> >& pixel_intensities_,
double mu_brightness_,
double sigma_brightness_,
double mu_blur_,
double sigma_blur_,
double variance_,
int samples_,
int sample_iterations_,
Matrix<3> A_,
Vector<3> pi_,
MT19937& rng_)
:pixels(pixels_),
pixel_intensities(pixel_intensities_),
mu_brightness(mu_brightness_),
sigma_brightness(sigma_brightness_),
mu_blur(mu_blur_),
sigma_blur(sigma_blur_),
variance(variance_),
samples(samples_),
sample_iterations(sample_iterations_),
A(A_),
pi(pi_),
rng(rng_)
{}
};
///Class implementing the Kahan summation algorithm
///to allow accurate summation of very large numbers of
///doubles.
///@ingroup gUtility
class Kahan{
private:
double y; ///< Input with the compensation removed. Temporary working space.
double c; ///< Running compenstation for low-order bits.
double t; ///< y + sum, which loses low order bits of y. Temporary working space.
public:
double sum; ///< running sum
Kahan()
:c(0),sum(0)
{}
/// Add a number to the running sum
/// @param i Number to add
void add(double i)
{
//y = input -c
y = i;
y-= c;
//t = sum + y
t = sum;
t += y;
//c = (t - sum) - y
//c = ((sum + y) - sum) - y)
c = t;
c -= sum;
c -= y;
sum = t;
}
};
///Class for computing the negitve free energy using thermodynamic integration.
class NegativeFreeEnergy: public DataForMCMC
{
public:
///@param d Necessary data
NegativeFreeEnergy(const DataForMCMC& d)
:DataForMCMC(d)
{
}
///Give the noise variance given a sample number and growth parameters
///@param sample Sample number
///@param samples Total number of samples
///@param base_sigma Starting value of sigme
///@param scale_pow Exponent scaling
double variance_from_sample(double sample, double samples, double base_sigma, double scale_pow) const
{
double scale = pow(1.25, sample * 1. / samples * scale_pow);
double sigma = base_sigma * scale;
double new_variance = sq(sigma);
return new_variance;
}
///Estimate free energy using the Slow Growth Thermodynamic Integration method given in
///Probalistic Inference Using Markov Chain Monte Carlo Methods, Radford. M. Neal, 1993
///Except using a 5 point stencil instead of forward differenceing in Eq 6.30
///@param spots list of spots
///@param spot_pixels Mask around each spot to use to save on computation
double compute_with_mask(const Vector<>& spots, const vector<vector<int> >& spot_pixels) const
{
//Estimate free energy using the Slow Growth Thermodynamic Integration method given in
//Probalistic Inference Using Markov Chain Monte Carlo Methods, Radford. M. Neal, 1993
//Except using a 5 point stencil instead of forward differenceing in Eq 6.30
double base_sigma = sqrt(variance); // should be 1
double scale_pow = 100.0;
const unsigned int nspots = spots.size()/4;
const unsigned int nframes = pixel_intensities.size();
const unsigned int npixels = pixels.size();
assert(spots.size() %4 == 0);
assert(spot_pixels.size() == nspots);
//Compute the intensities and derivatives for all spot
vector<vector<double> > spot_intensity; //[spot][pixel]
for(unsigned int i=0; i < nspots; i++)
spot_intensity.push_back(compute_spot_intensity(pixels, spots.slice<Dynamic,4>(i*4,4)));
GibbsSampler2 sampler(pixel_intensities, spot_intensity, spots_to_vector(spots), spot_pixels, A, pi, variance, sample_iterations);
double sum = 0;
Kahan ksum;
for(int sample=0; sample < samples; sample++)
{
//Compute the positions of the surrounding steps
double var1 = variance_from_sample(sample-2, samples, base_sigma, scale_pow);
double var2 = variance_from_sample(sample-1, samples, base_sigma, scale_pow);
double var3 = variance_from_sample(sample+1, samples, base_sigma, scale_pow);
double var4 = variance_from_sample(sample+2, samples, base_sigma, scale_pow);
//Take a sample
sampler.set_variance(var2);
sampler.next(DataForMCMC::get_rng());
//Compute the SSD. This is fixed regardless of sigma.
double err_sum=0;
for(unsigned int frame=0; frame < nframes; frame++)
for(unsigned int pixel=0; pixel < npixels; pixel++)
err_sum -= sq(pixel_intensities[frame][pixel] - sampler.sample_intensities()[frame][pixel]);
//Compute the derivative using a five point stencil
//This could be done in a better but less clear way
double e1 = err_sum / (2*var1) - npixels*nframes*::log(2*M_PI*var1)/2;
double e2 = err_sum / (2*var2) - npixels*nframes*::log(2*M_PI*var2)/2;
double e3 = err_sum / (2*var3) - npixels*nframes*::log(2*M_PI*var3)/2;
double e4 = err_sum / (2*var4) - npixels*nframes*::log(2*M_PI*var4)/2;
sum += (-e1 + 8*e2 - 8*e3 + e4)/12;
ksum.add(-e1/12);
ksum.add(8*e2/12);
ksum.add(-8*e3/12);
ksum.add(e4/12);
}
double log_final = (log(variance_from_sample(samples, samples, base_sigma, scale_pow)*2*M_PI)/2) * npixels * nframes;
double priors=0;
for(unsigned int i=0; i < nspots; i++)
{
priors += log_log_normal(spots[i*4+0], mu_brightness, sigma_brightness);
priors += log_log_normal(spots[i*4+1], mu_blur, sigma_blur);
}
/*cout << "Thermo:\n";
cout << "sum: " << sum -log_final << endl;
cout << "kah: " << ksum.sum -log_final << endl;
cout << "priors: " << priors + sum -log_final << endl;
cout << " kah: " << priors + ksum.sum -log_final << endl;
*/
//cout << log_final << endl;
//cout << sum + log_final << endl;
sampler.set_variance(variance);
return -(sum+priors - log_final);
}
///Estimate free energy using the Slow Growth Thermodynamic Integration method given in
///Probalistic Inference Using Markov Chain Monte Carlo Methods, Radford. M. Neal, 1993
///Except using a 5 point stencil instead of forward differenceing in Eq 6.30
///@param spots list of spots
double operator()(const Vector<>& spots) const
{
double base_sigma = sqrt(variance); // should be 1
double scale_pow = 100.0;
const unsigned int nspots = spots.size()/4;
const unsigned int nframes = pixel_intensities.size();
const unsigned int npixels = pixels.size();
assert(spots.size() %4 == 0);
//Compute the intensities and derivatives for all spot
vector<vector<double> > spot_intensity; //[spot][pixel]
for(unsigned int i=0; i < nspots; i++)
spot_intensity.push_back(compute_spot_intensity(pixels, spots.slice<Dynamic,4>(i*4,4)));
GibbsSampler sampler(pixel_intensities, spot_intensity, spots_to_vector(spots), A, pi, variance, sample_iterations);
double sum = 0;
Kahan ksum;
for(int sample=0; sample < samples; sample++)
{
//Compute the positions of the surrounding steps
double var1 = variance_from_sample(sample-2, samples, base_sigma, scale_pow);
double var2 = variance_from_sample(sample-1, samples, base_sigma, scale_pow);
double var3 = variance_from_sample(sample+1, samples, base_sigma, scale_pow);
double var4 = variance_from_sample(sample+2, samples, base_sigma, scale_pow);
//Take a sample
sampler.set_variance(var2);
sampler.next(DataForMCMC::get_rng());
//Compute the SSD. This is fixed regardless of sigma.
double err_sum=0;
for(unsigned int frame=0; frame < nframes; frame++)
for(unsigned int pixel=0; pixel < npixels; pixel++)
err_sum -= sq(pixel_intensities[frame][pixel] - sampler.sample_intensities()[frame][pixel]);
//Compute the derivative using a five point stencil
//This could be done in a better but less clear way
double e1 = err_sum / (2*var1) - npixels*nframes*::log(2*M_PI*var1)/2;
double e2 = err_sum / (2*var2) - npixels*nframes*::log(2*M_PI*var2)/2;
double e3 = err_sum / (2*var3) - npixels*nframes*::log(2*M_PI*var3)/2;
double e4 = err_sum / (2*var4) - npixels*nframes*::log(2*M_PI*var4)/2;
sum += (-e1 + 8*e2 - 8*e3 + e4)/12;
ksum.add(-e1/12);
ksum.add(8*e2/12);
ksum.add(-8*e3/12);
ksum.add(e4/12);
}
double log_final = (log(variance_from_sample(samples, samples, base_sigma, scale_pow)*2*M_PI)/2) * npixels * nframes;
double priors=0;
for(unsigned int i=0; i < nspots; i++)
{
priors += log_log_normal(spots[i*4+0], mu_brightness, sigma_brightness);
priors += log_log_normal(spots[i*4+1], mu_blur, sigma_blur);
}
/*cout << "Thermo:\n";
cout << "sum: " << sum -log_final << endl;
cout << "kah: " << ksum.sum -log_final << endl;
cout << "priors: " << priors + sum -log_final << endl;
cout << " kah: " << priors + ksum.sum -log_final << endl;
*/
//cout << log_final << endl;
//cout << sum + log_final << endl;
sampler.set_variance(variance);
return -(sum+priors - log_final);
}
};
/// Class for sorting a list of indexes to an array of spots lexicographically
/// according to the 2D positions of the spots.
///
///@param Cmp comparator function to specify less or greater
///@param First most significant position index
///@ingroup gMultiSpot
template<class Cmp, int First> struct IndexLexicographicPosition{
const vector<Vector<4> >& spots; ///< Keep around the array of spots for later comprison
/// @param s Vector to sort indices of
IndexLexicographicPosition(const vector<Vector<4> >& s)
:spots(s)
{}
static const int Second = First==2?3:2; ///< Second most siginifcant position index for sorting
/// Compare two indexes into the array of spots
bool operator()(int a, int b)
{
Cmp cmp;
if(cmp(spots[a][First], spots[b][First]))
return true;
else if(spots[a][First] == spots[b][First])
return cmp(spots[a][Second], spots[b][Second]);
else
return false;
}
};
///Closure holding image data generated using samples drawn from the model.
///NB this is used with one spot removed (i.e. set to dark). As a result, the data
///is treated as the background when considering that spot in isolation.
///See FitSpots for naming of variables.
///@ingroup gStorm
struct SampledBackgroundData
{
const vector<vector<vector<double> > >& sample_intensities_without_spot; //[sample][frame][pixel]
const vector<vector<double> >& pixel_intensities; //[frame][pixel]
const vector<ImageRef> pixels;
double mu_brightness, sigma_brightness, mu_blur, sigma_blur;
const Matrix<3> A;
const Vector<3> pi;
double variance;
const vector<int> O;
SampledBackgroundData(
const vector<vector<vector<double> > >& sample_intensities_without_spot_,
const vector<vector<double> >& pixel_intensities_,
const vector<ImageRef> pixels_,
double mu_brightness_,
double sigma_brightness_,
double mu_blur_,
double sigma_blur_,
const Matrix<3> A_,
const Vector<3> pi_,
double variance_)
:sample_intensities_without_spot(sample_intensities_without_spot_),
pixel_intensities(pixel_intensities_),
pixels(pixels_),
mu_brightness(mu_brightness_),
sigma_brightness(sigma_brightness_),
mu_blur(mu_blur_),
sigma_blur(sigma_blur_),
A(A_),
pi(pi_),
variance(variance_),
O(sequence(pixel_intensities.size()))
{
}
};
//!@cond Doxygen_Suppress
//Do not use.
struct SpotProbabilityWithSampledBackgroundFAKE: public SampledBackgroundData
{
SpotProbabilityWithSampledBackgroundFAKE(const SampledBackgroundData& d)
:SampledBackgroundData(d)
{
}
//Compute the probability of spot
double operator()(const Vector<4>& spot) const
{
vector<double> spot_intensities = compute_spot_intensity(pixels, spot);
double sum_log_prob = 0;
for(unsigned int s=0; s < sample_intensities_without_spot.size(); s++)
{
SpotWithBackground B(sample_intensities_without_spot[s], spot_intensities, pixel_intensities, variance);
double log_prob = forward_algorithm(A, pi, B, O);
double logprior = log_log_normal(spot[0], mu_brightness, sigma_brightness) +
log_log_normal(spot[1], mu_blur, sigma_blur);
//cout << setprecision(10) <<fixed << "Prob : " << log_prob + logprior << endl;
sum_log_prob += log_prob + logprior;
}
double average_log_prob = sum_log_prob / sample_intensities_without_spot.size();
// cout << "Ave Prob : " << average_log_prob << endl;
if(spot[0] < 0 || spot[1] < 0)
return 1e100;
return average_log_prob;
}
};
//@endcond
///Compute the derivative of the negative log probability with respect
///to the parameters of one spot, given some samples of the other spots.
///@ingroup gStorm
struct SpotNegProbabilityDiffWithSampledBackground: public SampledBackgroundData
{
///@param d Necessary data for construction
SpotNegProbabilityDiffWithSampledBackground(const SampledBackgroundData& d)
:SampledBackgroundData(d)
{
}
///Compute the probability of spot
///@param spot Spot position
Vector<4> operator()(const Vector<4>& spot) const
{
if(spot[0] <= 0 || spot[1] <= 0)
return Ones * std::numeric_limits<double>::quiet_NaN();
vector<pair<double, Vector<4> > > spot_intensities = compute_spot_intensity_derivatives(pixels, spot);
Vector<4> sum_diff_log = Zeros;
for(unsigned int s=0; s < sample_intensities_without_spot.size(); s++)
{
SpotWithBackground B(sample_intensities_without_spot[s], spot_intensities, pixel_intensities, variance);
pair<double, Vector<4> > r = forward_algorithm_deriv(A, pi, B, O);
sum_diff_log += r.second;
}
Vector<4> diff_log = sum_diff_log / sample_intensities_without_spot.size();
//Compute the log probability of the prior
Vector<4> logprior_deriv = makeVector(diff_log_log_normal(spot[0], mu_brightness, sigma_brightness),
diff_log_log_normal(spot[1], mu_blur, sigma_blur), 0, 0);
return -(diff_log + logprior_deriv);
}
};
///Class for computing the Hessian of the negative free energy.
///@ingroup gStorm
class FreeEnergyHessian: public DataForMCMC
{
public:
///Constructor
///@param d All data required
FreeEnergyHessian(const DataForMCMC& d)
:DataForMCMC(d)
{
}
///Compute the Hessian
///@param spots All spot positions
///@param spot spot to compute hessian for
Matrix<4> hessian(const vector<Vector<4> >& spots, int spot) const
{
cout << "----Computing pure MCMC hessian\n";
const unsigned int nspots = spots.size();
const unsigned int nframes = pixel_intensities.size();
const unsigned int npixels = pixels.size();
cout << spot << " " << nspots << " " << nframes << " " << npixels << endl;
vector<vector<double> > spot_intensity; //[spot][pixel]
for(unsigned int i=0; i < nspots; i++)
spot_intensity.push_back(compute_spot_intensity(pixels, spots[i]));
vector<tuple<double, Vector<4>, Matrix<4> > > spot_hess_etc = compute_spot_intensity_hessian(pixels, spots[spot]);
GibbsSampler sampler(pixel_intensities, spot_intensity, spots, A, pi, variance, sample_iterations);
//Compute derivative of log probability, summed (ie integrated)
Matrix<4> sum_hess1 = Zeros(spots.size());
Matrix<4> sum_hess2 = Zeros(spots.size());
Vector<4> sum_deriv = Zeros(spots.size());
for(int sample=0; sample < samples; sample++)
{
sampler.next(rng);
//Compute d log P(data | x, model) / d model, for a given sample
//And the hessian
Matrix<4> hess = Zeros(spots.size());
Vector<4> deriv = Zeros(spots.size());
for(unsigned int frame=0; frame < nframes; frame++)
{
for(unsigned int pixel=0; pixel < npixels; pixel++)
{
double e = pixel_intensities[frame][pixel] - sampler.sample_intensities()[frame][pixel];
//Build up the derivative
if(sampler.sample()[spot][frame] == 0)
{
hess += e * get<2>(spot_hess_etc[pixel]) - get<1>(spot_hess_etc[pixel]).as_col() * get<1>(spot_hess_etc[pixel]).as_row();
deriv += e * get<1>(spot_hess_etc[pixel]);
}
}
}
hess[0][0] += hess_log_log_normal(spots[spot][0], mu_brightness, sigma_brightness);
hess[1][1] += hess_log_log_normal(spots[spot][1], mu_blur, sigma_blur);
sum_hess1 += hess;
deriv[0] += diff_log_log_normal(spots[spot][0], mu_brightness, sigma_brightness);
deriv[1] += diff_log_log_normal(spots[spot][1], mu_blur, sigma_blur);
sum_hess2 += deriv.as_col() * deriv.as_row();
sum_deriv = sum_deriv + deriv;
}
sum_hess1 /= (samples * variance);
sum_hess2 /= (samples * variance);
sum_deriv /= (samples * variance);
cout << sum_hess1 << endl;
cout << sum_hess2 << endl;
cout << sum_deriv.as_col() * sum_deriv.as_row() << endl;
cout << "......." << sum_deriv << endl;
//Put in the prior
//The derivative prior parts cancel out.
//Rather sensibly this means that the second derivatives can be
//computed without reference to the prior, and then the prior can
//be added in later, i.e.: P(data, parameters) = P(data|parameter) P(parameters)
//The second derivatives have been constructed to be diagonal
DiagonalMatrix<4> hess_prior = Zeros(spots.size());
cout << "sum of parts = \n" << sum_hess1 + sum_hess2 - sum_deriv.as_col() * sum_deriv.as_row() << endl;
//TooN cannot currently add DiagonalMatrix to Matrix!!
//sum_hess.diagonal_slice() += hess_prior.diagonal_slice();
cout << "++++Done Computing pure MCMC hessian\n";
return sum_hess1 + sum_hess2 - sum_deriv.as_col() * sum_deriv.as_row();
}
};
///Comparator functor for the first element of a std::pair
struct LessSecond
{
///Comparison function
///@param a
///@param b
template<class A, class B> bool operator()(const pair<A,B>& a, const pair<A,B>& b) const
{
return a.second < b.second;
}
};
//!@cond Doxygen_Suppress
struct NthDeriv{
const SpotNegProbabilityDiffWithSampledBackground& compute_deriv;
int i;
NthDeriv(const SpotNegProbabilityDiffWithSampledBackground& c, int ii)
:compute_deriv(c),i(ii)
{}
double operator()(const Vector<4>& f) const
{
return compute_deriv(f)[i];
}
};
//!@endcond
///Compute the Hessian of the log probability. The background is sampled rather sparsely, and the
///spot in question is sampled much more densely using FFBS.
///@param spot Spot parameters
///@param d Background brightness (from other spots)
///@param bs_iterations Exter backward sampling iterations
///@param rng Random number generator
///@returns the Hessian of the log probability around the spot
Matrix<4> sampled_background_spot_hessian_ffbs(const Vector<4>& spot, const SampledBackgroundData& d, int bs_iterations, MT19937& rng)
{
vector<tuple<double, Vector<4>, Matrix<4> > > spot_hess_etc = compute_spot_intensity_hessian(d.pixels, spot);
vector<double> spot_intensities = compute_spot_intensity(d.pixels, spot);
Matrix<4> sum_hess_log = Zeros;
Matrix<4> sum_diff2_log = Zeros;
vector<State> current_sample;
const unsigned int nframes = d.pixel_intensities.size();
const unsigned int npixels = d.pixels.size();
Matrix<4> sum_hess = Zeros;
Vector<4> sum_deriv = Zeros;
vector<pair<Matrix<4>, Vector<4> > > hess_and_deriv_part(nframes);
for(unsigned int s=0; s < d.sample_intensities_without_spot.size(); s++)
{
SpotWithBackground B(d.sample_intensities_without_spot[s], spot_intensities, d.pixel_intensities, d.variance);
//Compute what the per-frame hess and deriv parts are
//if the spot is on in a frame.
for(unsigned int frame=0; frame < nframes; frame++)
{
Matrix<4> hess = Zeros;
Vector<4> deriv = Zeros;
for(unsigned int pixel=0; pixel < npixels; pixel++)
{
double e = d.pixel_intensities[frame][pixel] - (d.sample_intensities_without_spot[s][frame][pixel] + spot_intensities[pixel]);
//Build up the derivative
hess += e * get<2>(spot_hess_etc[pixel]) - get<1>(spot_hess_etc[pixel]).as_col() * get<1>(spot_hess_etc[pixel]).as_row();
deriv += e * get<1>(spot_hess_etc[pixel]);
}
hess_and_deriv_part[frame] = make_pair(hess, deriv);
}
//Forward filtering
std::vector<array<double, 3> > delta = forward_algorithm_delta(d.A, d.pi, B, d.O);
for(int i=0; i < bs_iterations; i++)
{
current_sample = backward_sampling<3,State>(d.A, delta, rng);
Matrix<4> hess = Zeros;
Vector<4> deriv = Zeros;
for(unsigned int frame=0; frame < nframes; frame++)
if(current_sample[frame] == 0)
{
hess += hess_and_deriv_part[frame].first;
deriv += hess_and_deriv_part[frame].second;
}
sum_hess += hess + deriv.as_col() * deriv.as_row();
sum_deriv += deriv;
}
}
sum_hess /= (bs_iterations * d.sample_intensities_without_spot.size() * d.variance);
sum_deriv /= (bs_iterations * d.sample_intensities_without_spot.size() * d.variance);
sum_hess -= sum_deriv.as_col() * sum_deriv.as_row();
sum_hess[0][0] += hess_log_log_normal(spot[0], d.mu_brightness, d.sigma_brightness);
sum_hess[1][1] += hess_log_log_normal(spot[1], d.mu_blur, d.sigma_blur);
sum_deriv[0] += diff_log_log_normal(spot[0], d.mu_brightness, d.sigma_brightness);
sum_deriv[1] += diff_log_log_normal(spot[1], d.mu_blur, d.sigma_blur);
//cout << "Turboderiv:" << sum_deriv << endl;
//cout << "Turbohess:\n" << sum_hess << endl;
return sum_hess;
}
///Debugging function. Not mathematically correct. Do not use.
Matrix<4> sampled_background_spot_hessian2(const Vector<4>& spot, const SampledBackgroundData& d)
{
vector<tuple<double, Vector<4>, Matrix<4> > > spot_intensities = compute_spot_intensity_hessian(d.pixels, spot);
Matrix<4> sum_hess_log = Zeros;
Matrix<4> sum_diff2_log = Zeros;
for(unsigned int s=0; s < d.sample_intensities_without_spot.size(); s++)
{
SpotWithBackground B(d.sample_intensities_without_spot[s], spot_intensities, d.pixel_intensities, d.variance);
double prob;
Vector<4> diff;
Matrix<4> hess;
tie(prob, diff, hess) = forward_algorithm_hessian(d.A, d.pi, B, d.O);
sum_hess_log += hess;
diff += makeVector(diff_log_log_normal(spot[0], d.mu_brightness, d.sigma_brightness), diff_log_log_normal(spot[1], d.mu_blur, d.sigma_blur), 0, 0);
sum_diff2_log += diff.as_col() * diff.as_row();
}
Matrix<4> hess_log = sum_hess_log / d.sample_intensities_without_spot.size();
Matrix<4> diff2_log = sum_diff2_log / d.sample_intensities_without_spot.size();
//Add in the prior
hess_log[0][0] += hess_log_log_normal(spot[0], d.mu_brightness, d.sigma_brightness);
hess_log[1][1] += hess_log_log_normal(spot[1], d.mu_blur, d.sigma_blur);
return hess_log + diff2_log;
}
///Debugging function. Not mathematically correct. Do not use.
Matrix<4> sampled_background_spot_hessian_FAKE(const Vector<4>& spot, const SampledBackgroundData& d)
{
vector<tuple<double, Vector<4>, Matrix<4> > > spot_intensities = compute_spot_intensity_hessian(d.pixels, spot);
Matrix<4> sum_hess_log = Zeros;
for(unsigned int s=0; s < d.sample_intensities_without_spot.size(); s++)
{
SpotWithBackground B(d.sample_intensities_without_spot[s], spot_intensities, d.pixel_intensities, d.variance);
double prob;
Vector<4> diff;
Matrix<4> hess;
tie(prob, diff, hess) = forward_algorithm_hessian(d.A, d.pi, B, d.O);
sum_hess_log += hess;
}
Matrix<4> hess_log = sum_hess_log / d.sample_intensities_without_spot.size();
//Add in the prior
hess_log[0][0] += hess_log_log_normal(spot[0], d.mu_brightness, d.sigma_brightness);
hess_log[1][1] += hess_log_log_normal(spot[1], d.mu_blur, d.sigma_blur);
return hess_log;
}
///Which pixels belong to a given spot?
///Find the indices of those pixels
///@ingroup gStorm
void get_spot_pixels(const vector<ImageRef>& pixels, const Vector<4>& spot, vector<int>& out)
{
//Go out to three sigma
vector<ImageRef> pix = getDisc(spot[1]*6 + 1);
out.resize(0);
ImageRef offset = ir_rounded(spot.slice<2,2>());
for(unsigned int j=0; j < pix.size(); j++)
{
int pos = lower_bound(pixels.begin(), pixels.end(), pix[j] + offset) - pixels.begin();
if(pos != (int)pixels.size() && pixels[pos] == pix[j] + offset)
out.push_back(pos);
}
if(out.size() == 0)
{
cout << "********************************\n";
cout << "********************************\n";
cout << "********************************\n";
cout << "********************************\n";
cout << "********************************\n";
cout << "Oe noes!11one\n";
cout << pix.size() << endl;
}
}
///Tokenize a line
///@ingroup gUtility
vector<string> split(const string& line)
{
vector<string> v;
istringstream i(line);
string s;
while(!i.eof())
{
i >> s;
if(i.fail())
break;
v.push_back(s);
}
return v;
}
///Generic version of itoa.
///How many times has this been reimplemented??
///@param x Value to convert to string
///@ingroup gUtility
template<class C> inline string xtoa(const C& x)
{
ostringstream os;
os << x;
return os.str();
}
///Inverse of xtoa()
///How many times has this been reimplemented??
///@param s String to convert
///@param msg Mesage to print on error
///@ingroup gUtility
template<class C> inline C atox(const string& s, const string& msg)
{
C c;
istringstream i(s);
i >> c;
if(i.fail())
throw LogFileParseError("Error parsing " + msg + ". Text is `" + s + "'.");
return c;
}
/**Parser for multispot 5 log files.
Log files are mostly line oriented and contain various records
The main records are:
Iteraton: \#ITNUM
MAIN: \<list of spot parameters>
Pass: \#PASSNUM
MT19937 \<random number generator state>
PASS\#PASSNUM: \<list of spot parameters>
ENDCHECKPOINT
Note that MAIN is redundant since it will be the same as the following PASS 1 (or the first pass
computed if restoring from a checkpoint).
Data should only be considered valid after ENDCHECKPOINT has been read
Iteration is written once per iteration, not once per pass. (FIXME)
Which moron invented this file format???
Note that the file format hasn't beren fixed, so that the output can easily be compared to the
output of the historic version which is known to be good.
The version history of the log file:
1.0 Original log file.
1.1 Add in build time/date/commit.
1.2 Fixed optimization routine.
@param in Stream to parse file from
@ingroup gStorm
*/
StateParameters parse_log_file(istream& in)
{
//A line read from the file
string line;