Skip to content

Commit 1a4db0b

Browse files
add stauus convergence test
1 parent 4b58453 commit 1a4db0b

4 files changed

Lines changed: 158 additions & 3 deletions

File tree

include/geode/stochastic/sampling/mcmc/proposal/proposal_kernel.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@ namespace geode
9191
return p / total;
9292
} );
9393
cumulative_probs_.back() = 1.0;
94-
Logger::info( " PROPOSAL: " );
9594
}
9695

9796
private:

tests/stochastic/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,15 @@ add_geode_test(
112112
${PROJECT_NAME}::stochastic
113113
)
114114

115+
add_geode_test(
116+
SOURCE "sampling/mcmc/test-mh-strauss-statistics-and-convergence.cpp"
117+
DEPENDENCIES
118+
OpenGeode::basic
119+
OpenGeode::geometry
120+
${PROJECT_NAME}::stochastic
121+
)
122+
123+
115124
add_geode_test(
116125
SOURCE "sampling/test-random-engine.cpp"
117126
DEPENDENCIES

tests/stochastic/sampling/mcmc/test-mh-poisson-statistics-and-convergence.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,14 +131,12 @@ int main()
131131
{
132132
geode::StochasticLibrary::initialize();
133133

134-
geode::StochasticLibrary::initialize();
135134
double domain_length{ 10. };
136135
double poisson_density_lambda{ 0.5 };
137136
std::array< double, 7 > birth_ratio{ 0.1, 0.2, 0.3, 0.4, 0.5, 0.6,
138137
0.8 };
139138
for( const auto b : birth_ratio )
140139
{
141-
geode::Logger::info( b );
142140
test_dynamic_independence(
143141
domain_length, poisson_density_lambda, b );
144142
}
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/*
2+
* Copyright (c) 2019 - 2025 Geode-solutions
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in
12+
* all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
* SOFTWARE.
21+
*
22+
*/
23+
#include <geode/geometry/point.hpp>
24+
#include <geode/stochastic/sampling/mcmc/metropolis_hasting_sampler.hpp>
25+
#include <geode/stochastic/sampling/mcmc/models/components/intensity_term.hpp>
26+
#include <geode/stochastic/sampling/mcmc/models/components/pairwise_term.hpp>
27+
#include <geode/stochastic/sampling/mcmc/models/gibbs_energy.hpp>
28+
#include <geode/stochastic/sampling/mcmc/proposal/classical_proposals.hpp>
29+
#include <geode/stochastic/sampling/mcmc/proposal/marked_object_sampler/uniform_marked_point_sampler.hpp>
30+
namespace
31+
{
32+
33+
void test_convergence( double domain_length,
34+
double poisson_density,
35+
double gamma,
36+
double nb_points,
37+
double nb_paires )
38+
{
39+
geode::RandomEngine engine;
40+
engine.set_seed( "@mh-test@" );
41+
42+
geode::Point2D min_point{ { 0., 0. } };
43+
geode::Point2D max_point{ { domain_length, domain_length } };
44+
45+
geode::BoundingBox2D box;
46+
box.add_point( min_point );
47+
box.add_point( max_point );
48+
49+
double area = domain_length * domain_length;
50+
51+
geode::UniformMarkedPointSampler< 2 > sampler( box, std::nullopt );
52+
53+
geode::GibbsEnergy< geode::Point2D > energy;
54+
energy.add_energy_term(
55+
std::make_unique< geode::IntensityTerm< geode::Point2D > >(
56+
poisson_density ) );
57+
58+
auto interaction_fn =
59+
[]( const geode::MarkedObject< geode::Point2D >& a,
60+
const geode::MarkedObject< geode::Point2D >& b ) {
61+
auto dx = a.geometry().value( 0 ) - b.geometry().value( 0 );
62+
auto dy = a.geometry().value( 1 ) - b.geometry().value( 1 );
63+
auto dist_sq = dx * dx + dy * dy;
64+
return dist_sq < 2;
65+
};
66+
67+
geode::PairwiseTerm< geode::Point2D, decltype( interaction_fn ) > term(
68+
gamma, interaction_fn );
69+
energy.add_energy_term( std::make_unique<
70+
geode::PairwiseTerm< geode::Point2D, decltype( interaction_fn ) > >(
71+
gamma, interaction_fn ) );
72+
73+
auto kernel1 =
74+
geode::create_birth_death_change_kernel< geode::Point2D >(
75+
sampler, 0.33, 0.33 );
76+
geode::MetropolisHastings< geode::Point2D > mh(
77+
energy, std::move( kernel1 ) );
78+
79+
geode::Configuration< geode::Point2D > state;
80+
81+
constexpr geode::index_t burn_in{ 5000 };
82+
constexpr geode::index_t N{ 100000 };
83+
84+
// Burn-in
85+
for( const auto i : geode::Range{ burn_in } )
86+
{
87+
geode_unused( i );
88+
mh.step( state, engine );
89+
}
90+
91+
// Sampling
92+
double sum_points = 0.0;
93+
double sum_paires = 0.0;
94+
for( const auto i : geode::Range{ N } )
95+
{
96+
mh.step( state, engine );
97+
auto stats = energy.ordered_energy_term_statistics( state );
98+
sum_points += stats[0];
99+
sum_paires += stats[1];
100+
}
101+
102+
double mean_points = sum_points / N;
103+
double mean_paires = sum_paires / N;
104+
105+
geode::Logger::info( "[MH test] mean points = ", mean_points,
106+
" and mean paires = ", mean_paires, " (expected ", nb_points, " ; ",
107+
nb_paires, ") " );
108+
109+
OPENGEODE_EXCEPTION( std::abs( mean_points - nb_points ) < 1,
110+
"[MH test] unexpected nb points." );
111+
112+
// ------------------------------------------------------------
113+
// Variance test: Poisson => Var(N) ≈ E[N]
114+
// ------------------------------------------------------------
115+
if( nb_paires == 0 )
116+
{
117+
OPENGEODE_EXCEPTION(
118+
mean_paires == 0, "[MH test] unexpected nb paires." );
119+
}
120+
else
121+
{
122+
OPENGEODE_EXCEPTION( std::abs( mean_paires - nb_paires ) < 3,
123+
"[MH test] unexpected nb paires." );
124+
}
125+
}
126+
} // namespace
127+
128+
int main()
129+
{
130+
try
131+
{
132+
geode::StochasticLibrary::initialize();
133+
134+
double domain_length{ 10. };
135+
double poisson_density_lambda{ 0.5 };
136+
std::array< double, 3 > gamma{ 0, 0.5, 1. };
137+
138+
test_convergence( domain_length, poisson_density_lambda, 0., 15, 0 );
139+
test_convergence( domain_length, poisson_density_lambda, 1., 50, 70 );
140+
test_convergence( domain_length, poisson_density_lambda, 0.5, 24, 10 );
141+
142+
geode::Logger::info( "MH STATISTICS AND CONVERGENCE TEST SUCCESS" );
143+
return 0;
144+
}
145+
catch( ... )
146+
{
147+
return geode::geode_lippincott();
148+
}
149+
}

0 commit comments

Comments
 (0)