3030#include < geode/stochastic/spatial/object_sets.hpp>
3131namespace
3232{
33- struct PoissonSetDescription
33+ struct SetDescription
3434 {
3535 std::string name;
36- double density;
37- double target_count;
38-
3936 double birth_ratio{ 1.0 };
4037 double death_ratio{ 1.0 };
4138 double change_ratio{ 1.0 };
4239 };
4340
41+ struct PoissonDensityDescription
42+ {
43+ std::string set_name;
44+ double density;
45+ double target_count;
46+ };
47+
4448 class PoissonSimulationRunner
4549 : public geode::SimulationRunner< geode::Point2D >
4650 {
4751 public:
48- PoissonSimulationRunner ( const geode::BoundingBox2D& box )
49- : box_( box ){};
52+ PoissonSimulationRunner ( const geode::BoundingBox2D& box ) : box_( box )
53+ {
54+ }
5055
51- void add_set_descriptor ( const PoissonSetDescription & descriptor )
56+ void add_set_descriptor ( const SetDescription & descriptor )
5257 {
5358 set_descriptors_.push_back ( descriptor );
5459 }
5560
61+ void add_density_descriptor (
62+ const PoissonDensityDescription& descriptor )
63+ {
64+ density_descriptors_.push_back ( descriptor );
65+ }
66+
5667 void initialize () override
5768 {
5869 auto proposal_kernel =
5970 std::make_unique< geode::ProposalKernel< geode::Point2D > >();
6071
61- for ( const auto & descriptor : set_descriptors_ )
72+ // Mapping set names -> UUID
73+ std::unordered_map< std::string, geode::uuid > name_to_uuid;
74+
75+ // Step 1: create object sets and samplers
76+ for ( const auto & set_desc : set_descriptors_ )
6277 {
63- const auto set_id =
64- this -> object_sets_ . add_set ( descriptor. name ) ;
78+ const auto set_id = this -> object_sets_ . add_set ( set_desc. name );
79+ name_to_uuid[set_desc. name ] = set_id ;
6580
6681 this ->set_samplers_ .push_back (
6782 std::make_unique< geode::UniformPointSetSampler< 2 > >(
6883 box_ ) );
6984
70- // density energy term
85+ geode::add_birth_death_change_moves ( this ->set_samplers_ .back (),
86+ *proposal_kernel, set_id, set_desc.birth_ratio ,
87+ set_desc.death_ratio , set_desc.change_ratio );
88+ }
89+
90+ // Step 2: create energy terms
91+ for ( const auto & energy_desc : density_descriptors_ )
92+ {
93+ const auto set_id = name_to_uuid.at ( energy_desc.set_name );
94+
7195 this ->ordered_energy_terms_ .push_back (
7296 this ->energy_terms_collection_ .add_energy_term (
7397 std::make_unique<
7498 geode::DensityTerm< geode::Point2D > >(
75- absl::StrCat ( descriptor. name , " _density" ),
76- descriptor .density ,
99+ absl::StrCat ( energy_desc. set_name , " _density" ),
100+ energy_desc .density ,
77101 absl::flat_hash_set< geode::uuid >{ set_id } ) ) );
78102
79- // target statistics
80103 this ->ordered_target_statistics_ .push_back (
81- descriptor.target_count );
82-
83- // proposal moves
84- geode::add_birth_death_change_moves ( this ->set_samplers_ .back (),
85- *proposal_kernel, set_id, descriptor.birth_ratio ,
86- descriptor.death_ratio , descriptor.change_ratio );
104+ energy_desc.target_count );
87105 }
106+
88107 this ->mh_sampler_ =
89108 std::make_unique< geode::MetropolisHastings< geode::Point2D > >(
90109 this ->energy_terms_collection_ ,
@@ -102,33 +121,37 @@ namespace
102121
103122 const auto expected_means =
104123 this ->ordered_target_statistics_ [stat_id];
124+
105125 const auto target_vs_mean_error =
106126 std::abs (
107127 statistic_monitoring.means [stat_id] - expected_means )
108128 / expected_means;
129+
109130 OPENGEODE_EXCEPTION ( target_vs_mean_error < 0.02 ,
110131 " [MH test] statistic value " ,
111132 statistic_monitoring.means [stat_id],
112133 " for energy term: " , term.name ().data (),
113- " not close to enought to expected value " , expected_means,
134+ " not close enough to expected value " , expected_means,
114135 " --> error : " , target_vs_mean_error );
115136
116137 const auto target_vs_variance_error =
117138 std::abs ( statistic_monitoring.variances [stat_id]
118139 - expected_means )
119140 / expected_means;
141+
120142 OPENGEODE_EXCEPTION ( target_vs_variance_error < 0.15 ,
121- " [MH test] The variance of the staistic value " ,
143+ " [MH test] variance of statistic " ,
122144 statistic_monitoring.variances [stat_id],
123145 " for energy term: " , term.name ().data (),
124- " is not close to enought to expected value " ,
125- expected_means, " --> error : " , target_vs_variance_error );
146+ " not close enough to expected value " , expected_means ,
147+ " --> error : " , target_vs_variance_error );
126148 }
127149 }
128150
129151 private:
130152 geode::BoundingBox2D box_;
131- std::vector< PoissonSetDescription > set_descriptors_;
153+ std::vector< SetDescription > set_descriptors_;
154+ std::vector< PoissonDensityDescription > density_descriptors_;
132155 };
133156
134157 void test_single_type_poisson ()
@@ -144,27 +167,36 @@ namespace
144167
145168 std::array< double , 4 > birth_ratio{ 0.1 , 0.5 , 2 ., 4 . };
146169 std::array< double , 4 > change_ratio{ 0 ., 1 ., 1 ., 0 . };
170+
147171 for ( const auto config : geode::Range{ birth_ratio.size () } )
148172 {
149- PoissonSetDescription setA;
173+ // --- Set description
174+ SetDescription setA;
150175 setA.name = " A" ;
151- setA.density = 0.3 ;
152- setA.target_count = 30.0 ;
153176 setA.birth_ratio = birth_ratio[config];
154177 setA.death_ratio = 1.0 ;
155178 setA.change_ratio = change_ratio[config];
156179
180+ // --- Energy term description
181+ PoissonDensityDescription densityA;
182+ densityA.set_name = " A" ;
183+ densityA.density = 0.3 ;
184+ densityA.target_count = 30.0 ;
185+
157186 PoissonSimulationRunner runner ( box );
158187 runner.add_set_descriptor ( setA );
188+ runner.add_density_descriptor ( densityA );
159189 runner.initialize ();
160190
161191 constexpr geode::index_t steps = 1000 ;
162192 constexpr geode::index_t nb_realizations = 1000 ;
193+
163194 runner.run ( engine, steps );
164195 auto statistic_monitoring = runner.run_print_and_monitor (
165196 " poisson_statistics" , engine, steps, nb_realizations );
166197 runner.check_statistics ( statistic_monitoring );
167198 }
199+
168200 geode::Logger::info ( " --> SUCCESS!" );
169201 }
170202
@@ -179,48 +211,34 @@ namespace
179211 box.add_point ( geode::Point2D{ { 0.0 , 0.0 } } );
180212 box.add_point ( geode::Point2D{ { 10.0 , 10.0 } } );
181213
182- std::array< double , 4 > birth_ratio{ 0.1 , 0.5 , 2 ., 4 . };
183- std::array< double , 4 > change_ratio{ 0 ., 1 ., 1 ., 0 . };
184- for ( const auto config : geode::Range{ birth_ratio.size () } )
185- {
186- PoissonSetDescription set01;
187- set01.name = " set01" ;
188- set01.density = 0.1 ;
189- set01.target_count = 10.0 ;
190- set01.birth_ratio = 1 .;
191- set01.death_ratio = 3 .;
192- set01.change_ratio = 1 .;
193-
194- PoissonSetDescription set02;
195- set02.name = " set02" ;
196- set02.density = 0.4 ;
197- set02.target_count = 40.0 ;
198- set02.birth_ratio = 3 .;
199- set02.death_ratio = 0.5 ;
200- set02.change_ratio = 1 .;
201-
202- PoissonSetDescription set03;
203- set03.name = " set03" ;
204- set03.density = 0.3 ;
205- set03.target_count = 30.0 ;
206- set03.birth_ratio = 4 .;
207- set03.death_ratio = 1 .;
208- set03.change_ratio = 1 .;
214+ // --- Set descriptions
215+ SetDescription set01{ " set01" , 2.0 , 3.0 , 1.0 };
216+ SetDescription set02{ " set02" , 3.0 , 0.5 , 1.0 };
217+ SetDescription set03{ " set03" , 4.0 , 1.0 , 1.0 };
209218
210- PoissonSimulationRunner runner ( box );
211- runner. add_set_descriptor ( set01 ) ;
212- runner. add_set_descriptor ( set02 ) ;
213- runner. add_set_descriptor ( set03 ) ;
219+ // --- Energy term descriptions
220+ PoissonDensityDescription density01{ " set01 " , 0.1 , 10.0 } ;
221+ PoissonDensityDescription density02{ " set02 " , 0.4 , 40.0 } ;
222+ PoissonDensityDescription density03{ " set03 " , 0.3 , 30.0 } ;
214223
215- runner.initialize ();
224+ PoissonSimulationRunner runner ( box );
225+ runner.add_set_descriptor ( set01 );
226+ runner.add_set_descriptor ( set02 );
227+ runner.add_set_descriptor ( set03 );
216228
217- constexpr geode::index_t steps = 1000 ;
218- constexpr geode::index_t nb_realizations = 1000 ;
229+ runner.add_density_descriptor ( density01 );
230+ runner.add_density_descriptor ( density02 );
231+ runner.add_density_descriptor ( density03 );
232+
233+ runner.initialize ();
234+
235+ constexpr geode::index_t steps = 1000 ;
236+ constexpr geode::index_t nb_realizations = 1000 ;
237+
238+ auto statistic_monitoring = runner.run_print_and_monitor (
239+ " poisson_statistics" , engine, steps, nb_realizations );
240+ runner.check_statistics ( statistic_monitoring );
219241
220- auto statistic_monitoring = runner.run_print_and_monitor (
221- " poisson_statistics" , engine, steps, nb_realizations );
222- runner.check_statistics ( statistic_monitoring );
223- }
224242 geode::Logger::info ( " --> SUCCESS!" );
225243 }
226244} // namespace
0 commit comments