Skip to content

Commit 61e625c

Browse files
feat(Distribution): Generic Double Distribution factory
1 parent f3385f1 commit 61e625c

5 files changed

Lines changed: 197 additions & 31 deletions

File tree

include/geode/stochastic/sampling/direct/double_sampler.hpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ namespace geode
3535

3636
namespace geode
3737
{
38+
struct opengeode_stochastic_stochastic_api DistributionDescription
39+
{
40+
std::string name;
41+
DistributionType distribution_type;
42+
43+
double min_value{};
44+
double max_value{};
45+
std::optional< double > mean{};
46+
std::optional< double > standard_deviation{};
47+
};
3848

3949
struct opengeode_stochastic_stochastic_api DoubleSampler
4050
{
@@ -43,6 +53,9 @@ namespace geode
4353
Gaussian,
4454
TruncatedGaussian >;
4555

56+
static Distribution create_distribution(
57+
const DistributionDescription& desc );
58+
4659
static double sample( RandomEngine& engine, const Distribution& dist );
4760
};
4861

include/geode/stochastic/sampling/distributions.hpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,16 @@
2727

2828
#include <optional>
2929

30+
#include <geode/basic/named_type.hpp>
31+
3032
namespace geode
3133
{
34+
struct DistributionTag
35+
{
36+
};
37+
38+
using DistributionType = NamedType< std::string, DistributionTag >;
39+
3240
template < typename Type >
3341
struct UniformClosed
3442
{
@@ -37,6 +45,16 @@ namespace geode
3745

3846
Type min_value{ static_cast< Type >( 0 ) };
3947
Type max_value{ static_cast< Type >( 1 ) };
48+
49+
[[nodiscard]] static DistributionType distribution_type_static()
50+
{
51+
return DistributionType{ "UniformClosed" };
52+
}
53+
54+
[[nodiscard]] DistributionType distribution_type() const
55+
{
56+
return distribution_type_static();
57+
}
4058
};
4159

4260
template < typename Type >
@@ -47,6 +65,16 @@ namespace geode
4765

4866
Type min_value{ static_cast< Type >( 0 ) };
4967
Type max_value{ static_cast< Type >( 1 ) };
68+
69+
[[nodiscard]] static DistributionType distribution_type_static()
70+
{
71+
return DistributionType{ "UniformClosedOpen" };
72+
}
73+
74+
[[nodiscard]] DistributionType distribution_type() const
75+
{
76+
return distribution_type_static();
77+
}
5078
};
5179

5280
struct opengeode_stochastic_stochastic_api Gaussian
@@ -56,6 +84,16 @@ namespace geode
5684

5785
double mean{ 0. };
5886
double standard_deviation{ 1. };
87+
88+
[[nodiscard]] static DistributionType distribution_type_static()
89+
{
90+
return DistributionType{ "Gaussian" };
91+
}
92+
93+
[[nodiscard]] DistributionType distribution_type() const
94+
{
95+
return distribution_type_static();
96+
}
5997
};
6098

6199
struct opengeode_stochastic_stochastic_api TruncatedGaussian
@@ -69,6 +107,16 @@ namespace geode
69107

70108
std::optional< double > min_value;
71109
std::optional< double > max_value;
110+
111+
[[nodiscard]] static DistributionType distribution_type_static()
112+
{
113+
return DistributionType{ "TruncatedGaussian" };
114+
}
115+
116+
[[nodiscard]] DistributionType distribution_type() const
117+
{
118+
return distribution_type_static();
119+
}
72120
};
73121

74122
} // namespace geode

src/geode/stochastic/sampling/direct/double_sampler.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,69 @@
2828

2929
namespace geode
3030
{
31+
struct DistributionTypeHasher
32+
{
33+
std::size_t operator()( const DistributionType& d ) const noexcept
34+
{
35+
// Use the underlying string from NamedType
36+
return absl::Hash< std::string >{}( d.get() );
37+
}
38+
};
39+
40+
using DistributionFactory = std::function< DoubleSampler::Distribution(
41+
const DistributionDescription& ) >;
42+
43+
static absl::flat_hash_map< DistributionType, // key type
44+
DistributionFactory, // value type
45+
DistributionTypeHasher // custom hasher
46+
>
47+
distribution_registry = {
48+
{ UniformClosed< double >::distribution_type_static(),
49+
[]( const DistributionDescription& d ) {
50+
UniformClosed< double > dist;
51+
dist.min_value = d.min_value;
52+
dist.max_value = d.max_value;
53+
return dist;
54+
} },
55+
{ UniformClosedOpen< double >::distribution_type_static(),
56+
[]( const DistributionDescription& d ) {
57+
UniformClosedOpen< double > dist;
58+
dist.min_value = d.min_value;
59+
dist.max_value = d.max_value;
60+
return dist;
61+
} },
62+
{ Gaussian::distribution_type_static(),
63+
[]( const DistributionDescription& d ) {
64+
Gaussian dist;
65+
dist.mean =
66+
d.mean.value_or( ( d.max_value - d.min_value ) / 2.0 );
67+
dist.standard_deviation = d.standard_deviation.value_or(
68+
( d.max_value - d.min_value ) / 6.0 );
69+
return dist;
70+
} },
71+
{ TruncatedGaussian::distribution_type_static(),
72+
[]( const DistributionDescription& d ) {
73+
TruncatedGaussian dist;
74+
dist.mean =
75+
d.mean.value_or( ( d.max_value - d.min_value ) / 2.0 );
76+
dist.standard_deviation = d.standard_deviation.value_or(
77+
( d.max_value - d.min_value ) / 6.0 );
78+
dist.min_value = d.min_value;
79+
dist.max_value = d.max_value;
80+
return dist;
81+
} }
82+
};
83+
84+
DoubleSampler::Distribution DoubleSampler::create_distribution(
85+
const DistributionDescription& desc )
86+
{
87+
auto it = distribution_registry.find( desc.distribution_type );
88+
if( it == distribution_registry.end() )
89+
throw geode::OpenGeodeException( absl::StrCat(
90+
"Unknown distribution type: ", desc.distribution_type.get() ) );
91+
return it->second( desc );
92+
}
93+
3194
double DoubleSampler::sample(
3295
RandomEngine& engine, const Distribution& dist )
3396
{

tests/stochastic/sampling/direct/test-double-sampler.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,43 @@ void test_double_sampler( geode::RandomEngine& engine )
6969
value != 1000., "[Gaussian] - value did not changed." );
7070
}
7171

72+
// Test function: create a uniform closed distribution from description
73+
void test_create_uniform_closed( geode::RandomEngine& engine )
74+
{
75+
geode::DistributionDescription desc;
76+
desc.name = "uniform_closed";
77+
desc.distribution_type =
78+
geode::UniformClosed< double >::distribution_type_static();
79+
desc.min_value = 2.;
80+
desc.max_value = 5.;
81+
82+
auto dist = geode::DoubleSampler::create_distribution( desc );
83+
double value = geode::DoubleSampler::sample( engine, dist );
84+
OPENGEODE_EXCEPTION(
85+
value >= 2. && value <= 5., "[UniformClosed] - value out of bounds" );
86+
}
87+
88+
// Test function: create a truncated Gaussian distribution from description
89+
void test_create_truncated_gaussian( geode::RandomEngine& engine )
90+
{
91+
geode::DistributionDescription desc;
92+
desc.name = "truncated_gaussian";
93+
desc.distribution_type =
94+
geode::TruncatedGaussian::distribution_type_static();
95+
desc.min_value = -2.;
96+
desc.max_value = 2.;
97+
desc.mean = 0.0;
98+
desc.standard_deviation = 1.0;
99+
100+
auto dist = geode::DoubleSampler::create_distribution( desc );
101+
for( int i = 0; i < 100; ++i )
102+
{
103+
double value = geode::DoubleSampler::sample( engine, dist );
104+
OPENGEODE_EXCEPTION( value >= -2. && value <= 2.,
105+
"[TruncatedGaussian] - value out of bounds" );
106+
}
107+
}
108+
72109
int main()
73110
{
74111
try
@@ -78,6 +115,9 @@ int main()
78115

79116
test_double_sampler( random_engine );
80117

118+
test_create_uniform_closed( random_engine );
119+
test_create_truncated_gaussian( random_engine );
120+
81121
geode::Logger::info( "TEST SUCCESS" );
82122
return 0;
83123
}

tests/stochastic/sampling/mcmc/test-mh-fractures.cpp

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
*
2222
*/
2323
#include <geode/geometry/point.hpp>
24+
#include <geode/stochastic/sampling/direct/double_sampler.hpp>
2425
#include <geode/stochastic/sampling/direct/object_set_sampler/segment_set_sampler.hpp>
2526
#include <geode/stochastic/sampling/mcmc/helpers/simulation_runner.hpp>
2627
#include <geode/stochastic/sampling/mcmc/metropolis_hasting_sampler.hpp>
@@ -37,17 +38,8 @@ namespace
3738
{
3839
std::string name;
3940

40-
// length
41-
std::string length_distribution_type;
42-
double minimal_length;
43-
double maximal_length;
44-
double mean_length;
45-
46-
// azimuth
47-
std::string azimuth_distribution_type;
48-
double minimal_azimuth;
49-
double maximal_azimuth;
50-
double mean_azimuth;
41+
geode::DistributionDescription length;
42+
geode::DistributionDescription azimuth;
5143

5244
// positionning
5345
double p20;
@@ -89,14 +81,12 @@ namespace
8981
const auto set_id = this->object_sets_.add_set( set_desc.name );
9082
name_to_uuid[set_desc.name] = set_id;
9183

92-
geode::UniformClosed< double > length_distribution;
93-
length_distribution.min_value = set_desc.minimal_length;
94-
length_distribution.max_value = set_desc.maximal_length;
95-
96-
geode::UniformClosed< double > azimuth_distribution;
97-
azimuth_distribution.min_value = set_desc.minimal_azimuth;
98-
azimuth_distribution.max_value = set_desc.maximal_azimuth;
99-
84+
auto length_distribution =
85+
geode::DoubleSampler::create_distribution(
86+
set_desc.length );
87+
auto azimuth_distribution =
88+
geode::DoubleSampler::create_distribution(
89+
set_desc.azimuth );
10090
this->set_samplers_.push_back(
10191
std::make_unique< geode::UniformSegmentSetSampler >(
10292
box_, length_distribution, azimuth_distribution ) );
@@ -175,12 +165,16 @@ namespace
175165
setA.name = "A";
176166

177167
// length
178-
setA.minimal_length = 1;
179-
setA.maximal_length = 10.;
168+
setA.length.distribution_type =
169+
geode::UniformClosed< double >::distribution_type_static();
170+
setA.length.min_value = 1;
171+
setA.length.max_value = 10.;
180172

181173
// azimuth
182-
setA.minimal_azimuth = 1;
183-
setA.maximal_azimuth = 10;
174+
setA.azimuth.distribution_type =
175+
geode::UniformClosed< double >::distribution_type_static();
176+
setA.azimuth.min_value = 1;
177+
setA.azimuth.max_value = 10.;
184178

185179
// positionning
186180
setA.p20 = 0.1;
@@ -219,12 +213,16 @@ namespace
219213
setA.name = "A";
220214

221215
// length
222-
setA.minimal_length = 1;
223-
setA.maximal_length = 10.;
216+
setA.length.distribution_type =
217+
geode::UniformClosed< double >::distribution_type_static();
218+
setA.length.min_value = 1;
219+
setA.length.max_value = 10.;
224220

225221
// azimuth
226-
setA.minimal_azimuth = 1;
227-
setA.maximal_azimuth = 10;
222+
setA.azimuth.distribution_type =
223+
geode::UniformClosed< double >::distribution_type_static();
224+
setA.azimuth.min_value = 1;
225+
setA.azimuth.max_value = 10.;
228226

229227
// positionning
230228
setA.p20 = 0.1;
@@ -235,12 +233,16 @@ namespace
235233
setB.name = "B";
236234

237235
// length
238-
setB.minimal_length = 1;
239-
setB.maximal_length = 10.;
236+
setB.length.distribution_type =
237+
geode::UniformClosed< double >::distribution_type_static();
238+
setB.length.min_value = 1;
239+
setB.length.max_value = 10.;
240240

241241
// azimuth
242-
setB.minimal_azimuth = 90;
243-
setB.maximal_azimuth = 100;
242+
setB.azimuth.distribution_type =
243+
geode::UniformClosed< double >::distribution_type_static();
244+
setB.azimuth.min_value = 90.;
245+
setB.azimuth.max_value = 100.;
244246

245247
// positionning
246248
setB.p20 = 0.1;

0 commit comments

Comments
 (0)