Tomographer  v5.2
Tomographer C++ Framework Documentation
mhrw.h
Go to the documentation of this file.
1 /* This file is part of the Tomographer project, which is distributed under the
2  * terms of the MIT license.
3  *
4  * The MIT License (MIT)
5  *
6  * Copyright (c) 2016 ETH Zurich, Institute for Theoretical Physics, Philippe Faist
7  * Copyright (c) 2017 Caltech, Institute for Quantum Information and Matter, Philippe Faist
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a copy
10  * of this software and associated documentation files (the "Software"), to deal
11  * in the Software without restriction, including without limitation the rights
12  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13  * copies of the Software, and to permit persons to whom the Software is
14  * furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be included in
17  * all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25  * SOFTWARE.
26  */
27 
28 #ifndef _TOMOGRAPHER_MHRW_H
29 #define _TOMOGRAPHER_MHRW_H
30 
31 #include <cstddef>
32 
33 #include <limits>
34 #include <random>
35 #include <iomanip>
36 #include <type_traits>
37 
39 #include <tomographer/tools/fmt.h>
41 #include <tomographer/tools/statusprovider.h>
42 #include <tomographer/multiproc.h>
45 
46 
47 
54 namespace Tomographer {
55 
56 
57 
58 
59 
60 enum {
74 };
75 
76 
77 
78 // note: const implies static linkage, see http://stackoverflow.com/q/2268749/1694896
79 //
81 constexpr const double MHRWAcceptanceRatioRecommendedMin = 0.2;
83 constexpr const double MHRWAcceptanceRatioRecommendedMax = 0.4;
84 
85 
92 template<typename StepRealType_ = double>
93 struct TOMOGRAPHER_EXPORT MHWalkerParamsStepSize
94 {
95  typedef StepRealType_ StepRealType;
96 
97  MHWalkerParamsStepSize() : step_size() { }
98  MHWalkerParamsStepSize(StepRealType step_size_) : step_size(step_size_) { }
99 
100  StepRealType step_size;
101 };
102 
103 template<typename StepRealType>
104 inline std::ostream & operator<<(std::ostream & stream, MHWalkerParamsStepSize<StepRealType> p)
105 {
106  return stream << "step_size=" << p.step_size;
107 }
108 
109 
119 template<typename MHWalkerParams_ = MHWalkerParamsStepSize<double>, typename CountIntType_ = int >
120 struct TOMOGRAPHER_EXPORT MHRWParams
121 {
122  typedef MHWalkerParams_ MHWalkerParams;
123  typedef CountIntType_ CountIntType;
124 
125  explicit MHRWParams()
126  : mhwalker_params(), n_sweep(0), n_therm(0), n_run(0)
127  {
128  }
129  template<typename MHWalkerParamsInit>
130  MHRWParams(MHWalkerParamsInit && mhwalker_params_,
131  CountIntType n_sweep_, CountIntType n_therm_, CountIntType n_run_)
132  : mhwalker_params(std::forward<MHWalkerParamsInit>(mhwalker_params_)),
133  n_sweep(n_sweep_), n_therm(n_therm_), n_run(n_run_)
134  {
135  }
136 
137  template<typename MHWalkerParamsOtherType, typename CountIntOtherType>
139  : mhwalker_params(copy.mhwalker_params),
140  n_sweep(copy.n_sweep), n_therm(copy.n_therm), n_run(copy.n_run)
141  {
142  }
143 
146  MHWalkerParams mhwalker_params;
147 
150  CountIntType n_sweep;
151 
154  CountIntType n_therm;
155 
158  CountIntType n_run;
159 };
160 
161 
162 
163 template<typename CountIntType, typename MHWalkerParams>
164 inline std::ostream & operator<<(std::ostream & str, const MHRWParams<MHWalkerParams,CountIntType> & p)
165 {
166  str << "MHRWParams(" << p.mhwalker_params << ";n_sweep=" << p.n_sweep
167  << ",n_therm=" << p.n_therm << ",n_run=" << p.n_run << ")";
168  return str;
169 }
170 
171 
172 
191 
199 
204 
209 
214 
215 
219 
223 };
224 
225 
226 
227 
232 template<typename MHRWControllerType_>
234 {
235  typedef MHRWControllerType_ MHRWControllerType;
236  enum { AdjustmentStrategy = MHRWControllerType::AdjustmentStrategy };
237 
238 private:
239  constexpr static bool _enabled_callback(bool IsThermalizing, bool IsAfterSample)
240  {
241  return
242  ( ((AdjustmentStrategy & MHRWControllerAdjustWhileThermalizing) && IsThermalizing) ||
243  ((AdjustmentStrategy & MHRWControllerAdjustWhileRunning) && !IsThermalizing) )
244  &&
245  ( ((AdjustmentStrategy & MHRWControllerAdjustEverySample) && IsAfterSample) ||
246  ((AdjustmentStrategy & MHRWControllerAdjustEveryIteration) && !IsAfterSample) )
247  ;
248  }
249 
250 public:
251 
252  template<typename... Args>
253  static inline void invokeInit(MHRWControllerType & x, Args && ... args) {
254  x.init(std::forward<Args>(args)...) ;
255  }
256 
257  template<typename MHRWParamsType, typename MHWalker, typename CountIntType, typename MHRandomWalkType>
258  static inline bool invokeAllowDoneThermalization(MHRWControllerType & x,
259  const MHRWParamsType & params, // ensure this is const
260  const MHWalker & mhwalker,
261  CountIntType iter_k,
262  const MHRandomWalkType & mhrw)
263  {
264  return x.allowDoneThermalization(params, mhwalker, iter_k, mhrw);
265  }
266 
267  template<typename MHRWParamsType, typename MHWalker, typename CountIntType, typename MHRandomWalkType>
268  static inline bool invokeAllowDoneRuns(MHRWControllerType & x,
269  const MHRWParamsType & params, // ensure this is const
270  const MHWalker & mhwalker,
271  CountIntType iter_k,
272  const MHRandomWalkType & mhrw)
273  {
274  return x.allowDoneRuns(params, mhwalker, iter_k, mhrw);
275  }
276 
277 
278  template<bool IsThermalizing, bool IsAfterSample, typename ... Args>
279  static inline
281  invokeAdjustParams(MHRWControllerType & x, Args && ... args)
282  {
283  x.template adjustParams<IsThermalizing, IsAfterSample>(std::forward<Args>(args)...);
284  }
285  template<bool IsThermalizing, bool IsAfterSample, typename ... Args>
286  static inline
288  invokeAdjustParams(MHRWControllerType & , Args && ... )
289  {
290  // callback disabled
291  }
292 
293 };
294 
295 
296 
297 
298 namespace tomo_internal {
299 
300 template<unsigned int AdjustmentStrategy, unsigned int OtherAdjustmentStrategy>
301 struct controller_flags_compatible {
302  static constexpr bool value =
303  // adjustments are done on different stages of the random walk
304  ((AdjustmentStrategy & OtherAdjustmentStrategy & MHRWControllerAdjustRWStageMASK) == 0) ;
305 };
306 
307 
308 template<bool RestOk, unsigned int ProcessedAdjustmentStrategyFlags,
309  typename... MHRWControllerTypes>
310 struct controllers_compatible_helper;
311 
312 template<bool RestOk, unsigned int ProcessedAdjustmentStrategyFlags, typename MHRWControllerAType,
313  typename... MHRWControllerRestTypes>
314 struct controllers_compatible_helper<RestOk, ProcessedAdjustmentStrategyFlags, MHRWControllerAType,
315  MHRWControllerRestTypes...>
316  : controllers_compatible_helper<
317  RestOk && controller_flags_compatible<MHRWControllerAType::AdjustmentStrategy,
318  ProcessedAdjustmentStrategyFlags>::value ,
319  ProcessedAdjustmentStrategyFlags | MHRWControllerAType::AdjustmentStrategy,
320  MHRWControllerRestTypes...
321  > { };
322 
323 template<bool RestOk, unsigned int ProcessedAdjustmentStrategyFlags>
324 struct controllers_compatible_helper<RestOk, ProcessedAdjustmentStrategyFlags> {
325  static constexpr bool value = RestOk;
326  static constexpr unsigned int CombinedAdjustmentStrategy = ProcessedAdjustmentStrategyFlags;
327 };
328 
329 
330 template<typename... MHRWControllerTypes>
331 struct controllers_compatible : controllers_compatible_helper<true, 0, MHRWControllerTypes...> { };
332 
333 } // namespace tomo_internal
334 
335 
336 
337 
338 
339 
340 
356 template<typename ... MHRWControllerTypes>
357 class TOMOGRAPHER_EXPORT MHRWMultipleControllers
358 {
359 public:
360 
361  typedef std::tuple<MHRWControllerTypes...> TupleType;
362  typedef std::tuple<MHRWControllerTypes&...> TupleRefType;
363 
364  static constexpr int NumControllers = sizeof...(MHRWControllerTypes) ;
365 
367 
368 private:
369  TupleRefType controllers;
370 
371 public:
372  enum {
373  AdjustmentStrategy =
374  tomo_internal::controllers_compatible<MHRWControllerTypes...>::CombinedAdjustmentStrategy
375  };
376 
377 
378  MHRWMultipleControllers(MHRWControllerTypes&... controllers_)
379  : controllers(controllers_...)
380  {
381  }
382 
383 
384  template<int I>
385  inline const typename std::tuple_element<I, TupleRefType>::type getController() const
386  {
387  return std::get<I>(controllers) ;
388  }
389 
390 
391  template<typename MHRWParamsType, typename MHWalker, typename MHRandomWalkType,
392  int I = 0, TOMOGRAPHER_ENABLED_IF_TMPL(I < NumControllers)>
393  inline void init(MHRWParamsType & params, const MHWalker & mhwalker,
394  const MHRandomWalkType & mhrw)
395  {
396  std::get<I>(controllers).init(params, mhwalker, mhrw);
397  init<MHRWParamsType, MHWalker, MHRandomWalkType, I+1>(params, mhwalker, mhrw);
398  }
399  template<typename MHRWParamsType, typename MHWalker, typename MHRandomWalkType,
400  int I = 0, TOMOGRAPHER_ENABLED_IF_TMPL(I == NumControllers)>
401  inline void init(const MHRWParamsType &, const MHWalker &, const MHRandomWalkType &) const
402  {
403  }
404 
405  template<typename MHRWParamsType, typename MHWalker, typename MHRandomWalkType,
406  int I = 0, TOMOGRAPHER_ENABLED_IF_TMPL(I < NumControllers)>
407  inline void thermalizingDone(MHRWParamsType & params, const MHWalker & mhwalker,
408  const MHRandomWalkType & mhrw)
409  {
410  std::get<I>(controllers).thermalizingDone(params, mhwalker, mhrw);
411  thermalizingDone<MHRWParamsType, MHWalker, MHRandomWalkType, I+1>(params, mhwalker, mhrw);
412  }
413  template<typename MHRWParamsType, typename MHWalker, typename MHRandomWalkType,
414  int I = 0, TOMOGRAPHER_ENABLED_IF_TMPL(I == NumControllers)>
415  inline void thermalizingDone(const MHRWParamsType & , const MHWalker & ,
416  const MHRandomWalkType & ) const
417  {
418  }
419 
420  template<typename MHRWParamsType, typename MHWalker, typename MHRandomWalkType,
421  int I = 0, TOMOGRAPHER_ENABLED_IF_TMPL(I < NumControllers)>
422  inline void done(MHRWParamsType & params, const MHWalker & mhwalker,
423  const MHRandomWalkType & mhrw)
424  {
425  std::get<I>(controllers).done(params, mhwalker, mhrw);
426  done<MHRWParamsType, MHWalker, MHRandomWalkType, I+1>(params, mhwalker, mhrw);
427  }
428  template<typename MHRWParamsType, typename MHWalker, typename MHRandomWalkType,
429  int I = 0, TOMOGRAPHER_ENABLED_IF_TMPL(I == NumControllers)>
430  inline void done(const MHRWParamsType & , const MHWalker & ,
431  const MHRandomWalkType & ) const
432  {
433  }
434 
435  template<bool IsThermalizing, bool IsAfterSample,
436  typename MHRWParamsType, typename CountIntType,
437  typename MHWalker, typename MHRandomWalkType,
438  int I = 0, TOMOGRAPHER_ENABLED_IF_TMPL(I < NumControllers)>
439  inline void adjustParams(MHRWParamsType & params, const MHWalker & mhwalker,
440  CountIntType iter_k, const MHRandomWalkType & mhrw)
441  {
442  // only one of the calls to adjustParmas() should actually go through; we've checked
443  // this above with a static_assert
445  ::template invokeAdjustParams<IsThermalizing,IsAfterSample>(
446  std::get<I>(controllers), params, mhwalker, iter_k, mhrw
447  );
448  adjustParams<IsThermalizing,IsAfterSample,MHRWParamsType,CountIntType,MHWalker,MHRandomWalkType,I+1>(
449  params, mhwalker, iter_k, mhrw
450  );
451  }
452  template<bool IsThermalizing, bool IsAfterSample,
453  typename MHRWParamsType, typename CountIntType,
454  typename MHWalker, typename MHRandomWalkType,
455  int I = 0, TOMOGRAPHER_ENABLED_IF_TMPL(I == NumControllers)>
456  inline void adjustParams(const MHRWParamsType &, const MHWalker &,
457  CountIntType , const MHRandomWalkType &) const
458  {
459  }
460 
461  template<typename MHRWParamsType, typename MHWalker, typename CountIntType, typename MHRandomWalkType,
462  int I = 0, TOMOGRAPHER_ENABLED_IF_TMPL(I < NumControllers)>
463  inline bool allowDoneThermalization(const MHRWParamsType & params, const MHWalker & mhwalker,
464  CountIntType iter_k, const MHRandomWalkType & mhrw)
465  {
466  return std::get<I>(controllers).allowDoneThermalization(params, mhwalker, iter_k, mhrw) &&
467  allowDoneThermalization<MHRWParamsType,MHWalker,CountIntType,MHRandomWalkType,I+1>(
468  params, mhwalker, iter_k, mhrw
469  ) ;
470  }
471  template<typename MHRWParamsType, typename MHWalker, typename CountIntType, typename MHRandomWalkType,
472  int I = 0, TOMOGRAPHER_ENABLED_IF_TMPL(I == NumControllers)>
473  inline bool allowDoneThermalization(const MHRWParamsType & , const MHWalker & ,
474  CountIntType , const MHRandomWalkType & ) const
475  {
476  return true;
477  }
478 
479  template<typename MHRWParamsType, typename MHWalker, typename CountIntType, typename MHRandomWalkType,
480  int I = 0, TOMOGRAPHER_ENABLED_IF_TMPL(I < NumControllers)>
481  inline bool allowDoneRuns(const MHRWParamsType & params, const MHWalker & mhwalker,
482  CountIntType iter_k, const MHRandomWalkType & mhrw)
483  {
484  return std::get<I>(controllers).allowDoneRuns(params, mhwalker, iter_k, mhrw) &&
485  allowDoneRuns<MHRWParamsType,MHWalker,CountIntType,MHRandomWalkType,I+1>(
486  params, mhwalker, iter_k, mhrw
487  ) ;
488  }
489  template<typename MHRWParamsType, typename MHWalker, typename CountIntType, typename MHRandomWalkType,
490  int I = 0, TOMOGRAPHER_ENABLED_IF_TMPL(I == NumControllers)>
491  inline bool allowDoneRuns(const MHRWParamsType & , const MHWalker & ,
492  CountIntType , const MHRandomWalkType & ) const
493  {
494  return true;
495  }
496 };
497 template<typename ... MHRWControllerTypes>
498 constexpr int MHRWMultipleControllers<MHRWControllerTypes...>::NumControllers;
499 
500 
506 template<typename... MHRWControllerTypes>
507 inline MHRWMultipleControllers<MHRWControllerTypes...>
508 mkMHRWMultipleControllers(MHRWControllerTypes & ... controllers)
509 {
510  return MHRWMultipleControllers<MHRWControllerTypes...>( controllers ... ) ;
511 }
512 
513 
514 
522 
523 
524 
525 
526 
527 
528 
529 namespace tomo_internal {
530 // const_type_helper: a single typedef member, 'type', which is declared as 'T' or 'const
531 // T' depending on whether use_const=false or true
532 template<typename T, bool use_const>
533 struct const_type_helper {
534  typedef T type;
535 };
536 template<typename T>
537 struct const_type_helper<T, true> {
538  typedef const T type;
539 };
540 
541 template<typename MHWalker, bool has_FnValueType>
542 struct helper_FnValueType_or_dummy {
543  typedef typename MHWalker::FnValueType type;
544 };
545 template<typename MHWalker>
546 struct helper_FnValueType_or_dummy<MHWalker,false> {
547  typedef int type; // dummy
548 };
549 } // namespace tomo_internal
550 
551 
598 template<typename Rng_, typename MHWalker_, typename MHRWStatsCollector_,
599  typename MHRWController_ = MHRWNoController,
600  typename LoggerType_ = Logger::VacuumLogger,
601  typename CountIntType_ = int>
602 class TOMOGRAPHER_EXPORT MHRandomWalk
603  : public virtual Tools::NeedOwnOperatorNew<typename MHWalker_::PointType>::ProviderType
604 {
605 public:
607  typedef Rng_ Rng;
609  typedef MHWalker_ MHWalker;
611  typedef MHRWStatsCollector_ MHRWStatsCollector;
613  typedef LoggerType_ LoggerType;
616  typedef CountIntType_ CountIntType;
617 
619  typedef typename MHWalker::PointType PointType;
621  typedef typename MHWalker::WalkerParams MHWalkerParams;
622 
625 
627  typedef MHRWController_ MHRWController;
628  enum { MHRWControllerStrategy = MHRWController::AdjustmentStrategy };
629 
632 
634 #ifndef TOMOGRAPHER_PARSED_BY_DOXYGEN
635  typedef typename tomo_internal::helper_FnValueType_or_dummy<
636  MHWalker,(int)MHWalker::UseFnSyntaxType!=(int)MHUseFnRelativeValue
637  >::type FnValueType;
638 #else
639  typedef _FnValueType FnValueType;
640 #endif
641 
642  enum {
644  UseFnSyntaxType = MHWalker::UseFnSyntaxType
645  };
646 
647 private:
648  // declare const if no adjustments are to be made. This expands to "MHRWParamsType _n;"
649  // or "const MHRWParamsType _n;"
650  typename tomo_internal::const_type_helper<
651  MHRWParamsType,
652  (int)MHRWControllerStrategy==(int)MHRWControllerDoNotAdjust
653  >::type _n;
654 
655  Rng & _rng;
656  MHWalker & _mhwalker;
657  MHRWStatsCollector & _stats;
658  MHRWController & _mhrw_controller;
659 
661 
663  PointType curpt;
667  FnValueType curptval;
668 
673  CountIntType num_accepted;
677  CountIntType num_live_points;
678 
679 
680 public:
681 
683  MHRandomWalk(MHWalkerParams mhwalker_params, CountIntType n_sweep, CountIntType n_therm, CountIntType n_run,
684  MHWalker & mhwalker, MHRWStatsCollector & stats, MHRWController & mhrw_controller,
685  Rng & rng, LoggerType & logger_)
686  : _n(mhwalker_params, n_sweep, n_therm, n_run),
687  _rng(rng),
688  _mhwalker(mhwalker),
689  _stats(stats),
690  _mhrw_controller(mhrw_controller),
691  _logger(TOMO_ORIGIN, logger_),
692  curpt(),
693  curptval(),
694  num_accepted(0),
695  num_live_points(0)
696  {
697  _logger.debug([&](std::ostream & stream) {
698  stream << "constructor(). n_sweep=" << n_sweep << ", mhwalker_params=" << mhwalker_params
699  << "n_therm=" << n_therm << ", n_run=" << n_run;
700  });
701  }
703  template<typename MHRWParamsTypeInit>
704  MHRandomWalk(MHRWParamsTypeInit&& n_rw,
705  MHWalker & mhwalker, MHRWStatsCollector & stats, MHRWController & mhrw_controller,
706  Rng & rng, LoggerType & logger_)
707  : _n(std::forward<MHRWParamsTypeInit>(n_rw)),
708  _rng(rng),
709  _mhwalker(mhwalker),
710  _stats(stats),
711  _mhrw_controller(mhrw_controller),
712  _logger(TOMO_ORIGIN, logger_),
713  curpt(),
714  curptval(),
715  num_accepted(0),
716  num_live_points(0)
717  {
718  _logger.debug([&](std::ostream & s) { s << "constructor(). mhrw parameters = " << _n; });
719  }
720 
721  MHRandomWalk(const MHRandomWalk & other) = delete;
722 
723 
725  inline const MHRWStatsCollector & statsCollector() const { return _stats; }
726 
728  inline const MHRWController & mhrwController() const { return _mhrw_controller; }
729 
730 
732  inline MHRWParamsType mhrwParams() const { return _n; }
733 
735  inline MHWalkerParams mhWalkerParams() const { return _n.mhwalker_params; }
736 
738  inline CountIntType nSweep() const { return _n.n_sweep; }
740  inline CountIntType nTherm() const { return _n.n_therm; }
742  inline CountIntType nRun() const { return _n.n_run; }
743 
744 
748  inline bool hasAcceptanceRatio() const
749  {
750  return (num_live_points > 0);
751  }
754  template<typename RatioType = double>
755  inline RatioType acceptanceRatio() const
756  {
757  return RatioType(num_accepted) / RatioType(num_live_points);
758  }
759 
760 
765  inline const PointType & getCurrentPoint() const
766  {
767  return curpt;
768  }
769 
777  inline const FnValueType & getCurrentPointValue() const
778  {
779  return curptval;
780  }
781 
787  inline void setCurrentPoint(const PointType& pt)
788  {
789  curpt = pt;
790  curptval = _get_ptval(curpt);
791  _logger.longdebug([&](std::ostream & s) {
792  s << "setCurrentPoint: set internal state. Value = " << curptval << "; Point =\n" << pt << "\n";
793  });
794  }
795 
796 
797 private:
798 
801  inline void _init()
802  {
803  num_accepted = 0;
804  num_live_points = 0;
805 
806  // starting point
807  curpt = _mhwalker.startPoint();
808  curptval = _get_ptval(curpt);
809 
810  _mhwalker.init();
811  _stats.init();
812 
813  _mhrw_controller.init(_n, _mhwalker, *this);
814 
815  _logger.longdebug("_init() done.");
816  }
819  inline void _thermalizing_done()
820  {
821  _mhwalker.thermalizingDone();
822  _stats.thermalizingDone();
823 
824  _mhrw_controller.thermalizingDone(_n, _mhwalker, *this);
825 
826  _logger.longdebug("_thermalizing_done() done.");
827  }
830  inline void _done()
831  {
832  _mhwalker.done();
833  _stats.done();
834 
835  _mhrw_controller.done(_n, _mhwalker, *this);
836 
837  _logger.longdebug("_done() done.");
838  }
839 
847  template<bool IsThermalizing>
848  inline void _move(CountIntType k, bool is_live_iter)
849  {
850  _logger.longdebug("_move()");
851  // The reason `mhwalker_params` is passed to jump_fn instead of leaving jump_fn itself
852  // handle the step size, is that we might in the future want to dynamically adapt the
853  // step size according to the acceptance ratio. That would have to be done in this
854  // class.
855  const PointType newpt = _mhwalker.jumpFn(curpt, _n.mhwalker_params);
856 
857  const FnValueType newptval = _get_ptval(newpt);
858 
859  const double a = _get_a_value(newpt, newptval, curpt, curptval);
860 
861  // accept move?
862  bool accept = ( a >= 1.0 ? true : bool( _rng()-_rng.min() <= a*(_rng.max()-_rng.min()) ) ) ;
863 
864  // track acceptance ratio, except if we are thermalizing
865  if (!IsThermalizing) {
866  num_accepted += accept ? 1 : 0;
867  ++num_live_points;
868  }
869 
870  _stats.rawMove(k, IsThermalizing, is_live_iter, accept, a, newpt, newptval, curpt, curptval, *this);
871 
872  _logger.longdebug([&](std::ostream & stream) {
873  stream << (IsThermalizing?"T":"#") << std::setw(3) << k << ": " << (accept?"AC":"RJ") << " "
874  << std::setprecision(4)
875  << "a=" << std::setw(5) << a << ", newptval=" << std::setw(5) << newptval
876  << ", curptval=" << std::setw(5) << curptval << ", accept_ratio="
877  << (!IsThermalizing ? Tools::fmts("%.2g", this->acceptanceRatio()) : std::string("N/A"))
878  << Tools::streamIfPossible(curpt, "\ncurpt = ", "", "");
879  });
880 
881  if (accept) {
882  // update the internal state of the random walk
883  curpt = newpt;
884  curptval = newptval;
885  }
886  _logger.longdebug("_move() done.");
887  }
888 
893  inline void _process_sample(CountIntType k, CountIntType n)
894  {
895  _stats.processSample(k, n, curpt, curptval, *this);
896  _logger.longdebug("_process_sample() done.");
897  }
898 
899 
900  //
901  // utilities for getting the fn value at a specific point, and comparing & getting the
902  // "a"-value for the jump
903  //
904 
905 #ifdef TOMOGRAPHER_PARSED_BY_DOXYGEN
906 
912  inline FnValueType _get_ptval(PointType curpt) const { }
926  inline double _get_a_value(PointType newpt, FnValueType newptval,
927  PointType curpt, FnValueType curptval) const { }
928 #else
929  // the actual implementation:
930 
931  // Case UseFnSyntaxType==MHUseFnValue
932  template<typename PtType, TOMOGRAPHER_ENABLED_IF_TMPL(UseFnSyntaxType == MHUseFnValue)>
933  inline FnValueType _get_ptval(PtType && curpt) const
934  {
935  return _mhwalker.fnVal(curpt);
936  }
937  template<typename PtType1, typename PtType2, TOMOGRAPHER_ENABLED_IF_TMPL(UseFnSyntaxType == MHUseFnValue)>
938  inline double _get_a_value(PtType1 && /*newpt*/, FnValueType newptval,
939  PtType2 && /*curpt*/, FnValueType curptval) const
940  {
941  return ((double)newptval) / curptval;
942  }
943 
944  // Case UseFnSyntaxType==MHUseFnLogValue
945  template<typename PtType, TOMOGRAPHER_ENABLED_IF_TMPL(UseFnSyntaxType == MHUseFnLogValue)>
946  inline FnValueType _get_ptval(PtType && curpt) const
947  {
948  return _mhwalker.fnLogVal(curpt);
949  }
950  template<typename PtType1, typename PtType2, TOMOGRAPHER_ENABLED_IF_TMPL(UseFnSyntaxType == MHUseFnLogValue)>
951  inline double _get_a_value(PtType1 && /*newpt*/, FnValueType newptval,
952  PtType2 && /*curpt*/, FnValueType curptval) const
953  {
954  using namespace std;
955  return (newptval > curptval) ? 1.0 : exp(double(newptval - curptval));
956  }
957 
958  // case UseFnSyntaxType==MHUseFnRelativeValue
959  template<typename PtType, TOMOGRAPHER_ENABLED_IF_TMPL(UseFnSyntaxType == MHUseFnRelativeValue)>
960  inline FnValueType _get_ptval(PtType && /*curpt*/) const
961  {
962  return 0;
963  }
964  template<typename PtType1, typename PtType2, TOMOGRAPHER_ENABLED_IF_TMPL(UseFnSyntaxType == MHUseFnRelativeValue)>
965  inline double _get_a_value(PtType1 && newpt, FnValueType /*newptval*/,
966  PtType2 && curpt, FnValueType /*curptval*/) const
967  {
968  using namespace std;
969  return _mhwalker.fnRelVal(std::forward<PtType1>(newpt), std::forward<PtType2>(curpt));
970  }
971 
972 #endif
973 
974 
975  // adjustments
976  template<bool IsThermalizing>
977  inline void _controller_adjust_afteriter(CountIntType iter_k)
978  {
979  MHRWControllerInvokerType::template invokeAdjustParams<IsThermalizing, false>(
980  _mhrw_controller, _n, _mhwalker, iter_k, *this
981  );
982  }
983  inline void _controller_adjust_aftersample(CountIntType iter_k)
984  {
985  MHRWControllerInvokerType::template invokeAdjustParams<false, true>(
986  _mhrw_controller, _n, _mhwalker, iter_k, *this
987  );
988  }
989  inline bool _controller_allow_therm_done(CountIntType iter_k)
990  {
991  return MHRWControllerInvokerType::template invokeAllowDoneThermalization(
992  _mhrw_controller, _n, _mhwalker, iter_k, *this
993  );
994  }
995  inline bool _controller_allow_runs_done(CountIntType iter_k)
996  {
997  return MHRWControllerInvokerType::template invokeAllowDoneRuns(
998  _mhrw_controller, _n, _mhwalker, iter_k, *this
999  );
1000  }
1001 
1002 public:
1003 
1010  void run()
1011  {
1012  _init();
1013 
1014  // make sure that the iteration counter will not overflow.
1015  if (Tomographer::Tools::multiplicationWillOverflow(_n.n_sweep, _n.n_therm) ||
1016  Tomographer::Tools::multiplicationWillOverflow(_n.n_sweep, _n.n_run)) {
1017  std::string msg = streamstr(
1018  "Error: integer type " << boost::core::demangle(typeid(CountIntType).name())
1019  << " cannot be used to represent number of iterations, will overflow with given params "
1020  << _n
1021  );
1022  _logger.error([&](std::ostream & stream) {
1023  stream << msg;
1024  });
1025  // this is an error, cannot continue.
1026  throw std::runtime_error(msg);
1027  }
1028 
1029  CountIntType k;
1030 
1031  _logger.longdebug([&](std::ostream & s) {
1032  s << "Starting random walk, parameters are = " << _n;
1033  });
1034 
1035  // keep the this expression explicit in the condition, because it may be updated by
1036  // the controller. (The compiler should optimize the const value anyway if no
1037  // controller is set because _n is declared const in that case.)
1038  for ( k = 0 ; (k < (_n.n_sweep * _n.n_therm)) || !_controller_allow_therm_done(k) ; ++k ) {
1039  _move<true>(k, false);
1040  _controller_adjust_afteriter<true>(k);
1041  }
1042 
1043  _thermalizing_done();
1044 
1045  _logger.longdebug("Thermalizing done, starting live runs.");
1046 
1047  CountIntType n = 0; // number of live samples
1048 
1049  // keep the this expression explicit in the condition, because it may be updated by
1050  // the controller. (The compiler should optimize the const value anyway if no
1051  // controller is set because _n is declared const in that case.)
1052  for (k = 0 ; (k < (_n.n_sweep * _n.n_run)) || !_controller_allow_runs_done(k) ; ++k) {
1053 
1054  bool is_live_iter = ((k+1) % _n.n_sweep == 0);
1055 
1056  // calculate a candidate jump point and see if we accept the move
1057  _move<false>(k, is_live_iter);
1058  _controller_adjust_afteriter<false>(k);
1059 
1060  if (is_live_iter) {
1061  _process_sample(k, n);
1062  ++n;
1063  _controller_adjust_aftersample(k);
1064  }
1065 
1066  }
1067 
1068  _done();
1069 
1070  _logger.longdebug("Random walk completed.");
1071 
1072  return;
1073  }
1074 };
1075 
1076 
1077 
1078 
1079 
1080 
1081 
1082 
1083 
1084 
1085 
1086 
1087 
1088 
1098 template<typename MHRWParamsType>
1099 struct TOMOGRAPHER_EXPORT MHRWStatusReport : public MultiProc::TaskStatusReport
1100 {
1101  typedef typename MHRWParamsType::CountIntType IterCountIntType;
1102 
1104  MHRWStatusReport(double fdone = 0.0, const std::string & msg = std::string(),
1105  IterCountIntType kstep_ = 0, MHRWParamsType mhrw_params_ = MHRWParamsType(),
1106  double acceptance_ratio_ = 0.0)
1107  : MultiProc::TaskStatusReport(fdone, msg),
1108  kstep(kstep_),
1109  mhrw_params(mhrw_params_),
1110  acceptance_ratio(acceptance_ratio_),
1111  n_total_iters(mhrw_params.n_sweep*(mhrw_params.n_therm + mhrw_params.n_run))
1112  {
1113  }
1114 
1116  IterCountIntType kstep;
1117 
1126  MHRWParamsType mhrw_params;
1127 
1132 
1139  IterCountIntType n_total_iters;
1140 
1141  template<typename MHRandomWalkType, typename MHRWStatsCollectorType, typename MHRWControllerType>
1142  static inline MHRWStatusReport
1143  createFromRandWalkStatInfo(IterCountIntType k, bool is_thermalizing,
1144  const MHRandomWalkType & rw,
1145  const MHRWStatsCollectorType & stats_collector,
1146  const MHRWControllerType & mhrw_controller) {
1147  // prepare & provide status report
1148  IterCountIntType totiters = rw.nSweep()*(rw.nTherm()+rw.nRun());
1149  // k restarts at zero after thermalization, so account for that:
1150  IterCountIntType kreal = is_thermalizing ? k : k + rw.nSweep()*rw.nTherm();
1151  double fdone = ( is_thermalizing ? (double)k : (double)k + rw.nSweep()*rw.nTherm() ) / (double)totiters;
1152  double accept_ratio = std::numeric_limits<double>::quiet_NaN();
1153  bool warn_accept_ratio = false;
1154  std::string accept_ratio_msg;
1155  if (rw.hasAcceptanceRatio()) {
1156  accept_ratio = rw.acceptanceRatio();
1157  warn_accept_ratio = (accept_ratio > MHRWAcceptanceRatioRecommendedMax ||
1158  accept_ratio < MHRWAcceptanceRatioRecommendedMin);
1159  accept_ratio_msg = std::string(" [") + (warn_accept_ratio ? "!!** " : "") +
1160  std::string("accept ratio=") + Tools::fmts("%.2f", accept_ratio) +
1161  (warn_accept_ratio ? " **!!" : "") + "]";
1162  }
1163  //
1164  // "therm. sweep NNN/NNN [+rn:NNN]: XX.XX% done"
1165  // "run sweep NNN/NNN [+th:NNN]: XX.XX% done [accept ratio=0.25]"
1166  //
1167  std::string msg;
1168  if (is_thermalizing) {
1169  msg = "therm. sweep " + std::to_string(k / rw.nSweep()) + "/" + std::to_string(rw.nTherm())
1170  + " [+rn:" + std::to_string(rw.nRun()) + "]";
1171  } else {
1172  msg = "run sweep " + std::to_string(k / rw.nSweep()) + "/" + std::to_string(rw.nRun())
1173  + " [+th:" + std::to_string(rw.nTherm()) + "]";
1174  }
1175  msg += " : " + Tools::fmts("%5.2f", fdone*100.0) + "% done";
1176  if (accept_ratio_msg.size()) {
1177  msg += accept_ratio_msg;
1178  }
1179  // std::string msg = Tools::fmts(
1180  // "%s %lu/(%lu=%lu*(%lu+%lu)) : %5.2f%% done %s",
1181  // ( ! is_thermalizing
1182  // ? "iteration"
1183  // : "[therm.] "),
1184  // (unsigned long)kreal, (unsigned long)totiters, (unsigned long)rw.nSweep(),
1185  // (unsigned long)rw.nTherm(), (unsigned long)rw.nRun(),
1186  // fdone*100.0,
1187  // accept_ratio_msg.c_str()
1188  // );
1189  const std::string nlindent = "\n ";
1192  if (s.size()) {
1193  msg += nlindent;
1194  for (std::size_t j = 0; j < s.size(); ++j) {
1195  if (s[j] == '\n') {
1196  msg += nlindent;
1197  } else {
1198  msg += s[j];
1199  }
1200  }
1201  }
1202  }
1205  if (s.size()) {
1206  msg += nlindent;
1207  for (std::size_t j = 0; j < s.size(); ++j) {
1208  if (s[j] == '\n') {
1209  msg += nlindent;
1210  } else {
1211  msg += s[j];
1212  }
1213  }
1214  }
1215  }
1216  return MHRWStatusReport(fdone, msg, kreal, rw.mhrwParams(), accept_ratio);
1217  }
1218 
1219 };
1220 
1221 
1222 
1223 
1224 
1225 
1226 
1227 
1228 
1229 
1230 //
1231 // Specialize Tomographer::Tools::StatusProvider for our MHRWMultipleControllers
1232 //
1233 
1234 
1235 namespace Tools {
1236 
1240 template<typename... Args>
1241 struct TOMOGRAPHER_EXPORT StatusProvider<MHRWMultipleControllers<Args... > >
1242 {
1243  typedef MHRWMultipleControllers<Args... > MHRWControllerType;
1245 
1246  static constexpr int NumControllers = MHRWControllerType::NumControllers;
1247 
1248  static constexpr bool CanProvideStatusLine = true;
1249 
1250  template<int I = 0, typename std::enable_if<(I < NumControllers), bool>::type dummy = true>
1251  static inline std::string getStatusLine(const MHRWControllerType * ctrl)
1252  {
1253  typedef typename std::tuple_element<I, typename MHRWControllerType::TupleType>::type
1254  ThisController;
1255  return
1257  ? StatusQuery<ThisController>::getStatusLine(& ctrl->template getController<I>())
1258  : std::string()),
1259  getStatusLine<I+1>(ctrl) );
1260  };
1261 
1262  template<int I = 0, typename std::enable_if<(I == NumControllers), bool>::type dummy = true>
1263  static inline std::string getStatusLine(const MHRWControllerType * )
1264  {
1265  return std::string();
1266  }
1267 
1268 private:
1269  static inline std::string _joinnl(std::string a, std::string b) {
1270  if (a.size() && b.size()) {
1271  return std::move(a) + "\n" + std::move(b);
1272  }
1273  return std::move(a) + std::move(b); // one of these guys is empty
1274  }
1275 };
1276 // static members:
1277 template<typename... Args>
1278 constexpr int StatusProvider<MHRWMultipleControllers<Args... > >::NumControllers;
1279 template<typename... Args>
1280 constexpr bool StatusProvider<MHRWMultipleControllers<Args... > >::CanProvideStatusLine;
1281 
1282 
1283 } // namespace Tools
1284 
1285 
1286 
1287 
1288 
1289 
1290 
1291 
1292 } // namespace Tomographer
1293 
1294 
1295 
1296 
1297 #endif
A Metropolis-Hastings Random Walk.
Definition: mhrw.h:602
Utilities for formatting strings.
MHRWMultipleControllers MHRWNoController
A MHRWController Interface which does not adjust anything.
Definition: mhrw.h:521
MHRWMultipleControllers< MHRWControllerTypes... > mkMHRWMultipleControllers(MHRWControllerTypes &... controllers)
Convenience function to create a MHRWMultipleControllers (using template argument deduction) ...
Definition: mhrw.h:508
Mask out bits which decide at which random walk stage (thermalizing and/or running) adjustments are p...
Definition: mhrw.h:203
Adjustments are enabled during both thermalization and live (running) sweeps.
Definition: mhrw.h:197
IterCountIntType kstep
the current iteration number
Definition: mhrw.h:1116
const MHRWStatsCollector & statsCollector() const
Access the stats collector.
Definition: mhrw.h:725
Adjustemnts should be performed after each individual iteration.
Definition: mhrw.h:206
double acceptance_ratio
the current acceptance ratio of the random walk (see Tomographer::MHRandomWalk::acceptanceRatio() ) ...
Definition: mhrw.h:1131
Base namespace for the Tomographer project.
Definition: densellh.h:45
MHRWStatusReport(double fdone=0.0, const std::string &msg=std::string(), IterCountIntType kstep_=0, MHRWParamsType mhrw_params_=MHRWParamsType(), double acceptance_ratio_=0.0)
Constructor which initializes all fields.
Definition: mhrw.h:1104
CountIntType nTherm() const
Number of thermalizing sweeps.
Definition: mhrw.h:740
CountIntType_ CountIntType
The type used for counting numbers of iterations (see, e.g. nSweep() or MHRWParams) ...
Definition: mhrw.h:616
void error(const char *fmt,...)
Generate a log message with level Logger::ERROR (printf-like syntax)
Definition: loggers.h:1824
MHWalker::PointType PointType
The type of a point in the random walk.
Definition: mhrw.h:619
T exp(T... args)
Adjustments are enabled during thermalization sweeps.
Definition: mhrw.h:193
An MHWalkerParams type which just stores a step size.
Definition: mhrw.h:93
const FnValueType & getCurrentPointValue() const
Access the current function value of the random walk.
Definition: mhrw.h:777
T to_string(T... args)
Provide appropriate operator new() definitions for a structure which has a member of the given stored...
CountIntType n_run
Number of live sweeps.
Definition: mhrw.h:158
Logger that discards all messages.
Definition: loggers.h:1149
STL namespace.
constexpr const double MHRWAcceptanceRatioRecommendedMax
Maximal recommended acceptance ratio.
Definition: mhrw.h:83
MHRWStatsCollector_ MHRWStatsCollector
The stats collector type (see MHRWStatsCollector Interface)
Definition: mhrw.h:611
MHWalker::WalkerParams MHWalkerParams
The parameters type of the MHWalker implememtation, typically just a double storing the step size of ...
Definition: mhrw.h:621
constexpr bool multiplicationWillOverflow(IntType a, IntType b)
Test whether a multiplication of two integers will cause an overflow/underflow for that integer type...
Definition: cxxutil.h:453
MHWalker_ MHWalker
The random walker type which knows about the state space and jump function.
Definition: mhrw.h:609
CountIntType n_therm
Number of thermalization sweeps.
Definition: mhrw.h:154
MHRandomWalk(MHWalkerParams mhwalker_params, CountIntType n_sweep, CountIntType n_therm, CountIntType n_run, MHWalker &mhwalker, MHRWStatsCollector &stats, MHRWController &mhrw_controller, Rng &rng, LoggerType &logger_)
Simple constructor, initializes the given fields.
Definition: mhrw.h:683
constexpr const double MHRWAcceptanceRatioRecommendedMin
Minimal recommended acceptance ratio.
Definition: mhrw.h:81
#define TOMO_ORIGIN
Use this as argument for a Tomographer::Logger::LocalLogger constructor .
Definition: loggers.h:1528
MHRandomWalk(MHRWParamsTypeInit &&n_rw, MHWalker &mhwalker, MHRWStatsCollector &stats, MHRWController &mhrw_controller, Rng &rng, LoggerType &logger_)
Simple constructor, initializes the given fields.
Definition: mhrw.h:704
const MHRWController & mhrwController() const
Access the random walk controller.
Definition: mhrw.h:728
Adjustemnts should be performed only while thermalizing, after each individual iteration.
Definition: mhrw.h:217
MHWalkerParams mhWalkerParams() const
Get the MHWalker parameters.
Definition: mhrw.h:735
T setw(T... args)
Query status from different objects.
STL class.
void debug(const char *fmt,...)
Generate a log message with level Logger::DEBUG (printf-like syntax)
Definition: loggers.h:1803
IterCountIntType n_total_iters
the total number of iterations required for this random walk
Definition: mhrw.h:1139
Provides the logarithm MH function value at each point (see Role of UseFnSyntaxType) ...
Definition: mhrw.h:68
CountIntType n_sweep
The number of individual updates to collect together in a "sweep".
Definition: mhrw.h:150
#define TOMO_STATIC_ASSERT_EXPR(...)
Tool for static assertions without message.
Definition: cxxdefs.h:77
MHRWParamsType mhrwParams() const
The parameters of the random walk.
Definition: mhrw.h:732
Never adjust the parameters of the random walk.
Definition: mhrw.h:190
MHRWController_ MHRWController
The type which will take care of dynamically adjusting the parameters of the random walk...
Definition: mhrw.h:627
MHRWControllerAdjustmentStrategy
Describe how frequently the parameters of the random walk should be dynamically adjusted.
Definition: mhrw.h:188
Provides the MH function value at each point (see Role of UseFnSyntaxType)
Definition: mhrw.h:64
MHRWControllerInvoker< MHRWController > MHRWControllerInvokerType
The MHRWControllerInvoker for our random walk controller, for convenience.
Definition: mhrw.h:631
Mask out bits which decide at which frequency (after each iteration and/or after each sample) adjustm...
Definition: mhrw.h:213
_Unspecified streamIfPossible(const T &obj)
Utility to stream an object, but only if "<<" overload exists.
Definition: fmt.h:311
A MHRWController Interface which combines several independent random walk controllers.
Definition: mhrw.h:357
bool hasAcceptanceRatio() const
Query whether we have any statistics about acceptance ratio. This is false, for example, during the thermalizing runs.
Definition: mhrw.h:748
_FnValueType FnValueType
The type of the Metropolis-Hastings function value. (See class documentation)
Definition: mhrw.h:639
Some C++ utilities, with a tad of C++11 tricks.
Basic status report class.
Definition: multiproc.h:66
void setCurrentPoint(const PointType &pt)
Force manual state of random walk.
Definition: mhrw.h:787
T move(T... args)
CountIntType nRun() const
Number of live run sweeps.
Definition: mhrw.h:742
CountIntType nSweep() const
Number of iterations in a sweep.
Definition: mhrw.h:738
void longdebug(const char *fmt,...)
Generate a log message with level Logger::LONGDEBUG (printf-like syntax)
Definition: loggers.h:1796
Managing the need for specific overrides to operator new() for some types (especially Eigen types) ...
T size(T... args)
Status Report structure representing the status of a MHRandomWalk.
Definition: mhrw.h:1099
std::string fmts(const char *fmt,...)
printf- format to a std::string
Definition: fmt.h:128
Template, specializable class to provide status reports for different objects.
const PointType & getCurrentPoint() const
Access the current state of the random walk.
Definition: mhrw.h:765
Some common definitions for multiprocessing interfaces.
Specify the parameters of a Metropolis-Hastings random walk.
Definition: mhrw.h:120
LoggerType_ LoggerType
The logger type which will be provided by user to constructor (see Logging and Loggers) ...
Definition: mhrw.h:613
Adjustemnts should be performed after a sample is taken (during live runs only)
Definition: mhrw.h:208
void run()
Run the random walk. (pun intended)
Definition: mhrw.h:1010
MHRWParams< MHWalkerParams, CountIntType > MHRWParamsType
The struct which can hold the parameters of this random walk.
Definition: mhrw.h:624
Adjustments are enabled during live (running) sweeps.
Definition: mhrw.h:195
VarValueDecoder< T >::RetType value(const Var &var)
Access the value of the given variable, as a C++ type.
Definition: ezmatio.h:878
Adjustemnts should be performed all the time, after each individual iteration.
Definition: mhrw.h:221
Provides directly the ratio of the function values for two consecutive points of the MH random walk (...
Definition: mhrw.h:73
T quiet_NaN(T... args)
RatioType acceptanceRatio() const
Return the acceptance ratio so far.
Definition: mhrw.h:755
#define streamstr(tokens)
Utility macro to format stream tokens to a std::string.
Definition: fmt.h:149
Helper class to invoke a MHRWController Interface &#39;s callbacks.
Definition: mhrw.h:233
T setprecision(T... args)
Rng_ Rng
Random number generator type (see C++ std::random)
Definition: mhrw.h:607
MHRWParamsType mhrw_params
the parameters of the random walk
Definition: mhrw.h:1126
Binning Analysis in a Metropolis-Hastings random walk.
STL class.
MHWalkerParams mhwalker_params
The parameters of the mh-walker, typically just the step size of the random walk. ...
Definition: mhrw.h:146
Utilities for logging messages.