games_dice 0.2.4 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/.travis.yml +0 -6
- data/Rakefile +12 -2
- data/ext/games_dice/extconf.rb +3 -0
- data/ext/games_dice/games_dice.c +12 -0
- data/ext/games_dice/probabilities.c +765 -0
- data/ext/games_dice/probabilities.h +47 -0
- data/games_dice.gemspec +3 -2
- data/lib/games_dice.rb +5 -1
- data/lib/games_dice/bunch.rb +2 -67
- data/lib/games_dice/probabilities.rb +138 -7
- data/lib/games_dice/version.rb +1 -1
- data/spec/helpers.rb +2 -2
- data/spec/probability_spec.rb +220 -144
- metadata +28 -8
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/Rakefile
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
require "bundler/gem_tasks"
|
|
2
2
|
require "rspec/core/rake_task"
|
|
3
|
+
require 'rake/extensiontask'
|
|
3
4
|
require "yard"
|
|
4
5
|
|
|
5
|
-
task :default => [:test]
|
|
6
|
-
|
|
7
6
|
desc "GamesDice unit tests"
|
|
8
7
|
RSpec::Core::RakeTask.new(:test) do |t|
|
|
9
8
|
t.pattern = "spec/*_spec.rb"
|
|
@@ -13,3 +12,14 @@ end
|
|
|
13
12
|
YARD::Rake::YardocTask.new do |t|
|
|
14
13
|
t.files = ['lib/**/*.rb']
|
|
15
14
|
end
|
|
15
|
+
|
|
16
|
+
gemspec = Gem::Specification.load('games_dice.gemspec')
|
|
17
|
+
Rake::ExtensionTask.new do |ext|
|
|
18
|
+
ext.name = 'games_dice'
|
|
19
|
+
ext.source_pattern = "*.{c,h}"
|
|
20
|
+
ext.ext_dir = 'ext/games_dice'
|
|
21
|
+
ext.lib_dir = 'lib/games_dice'
|
|
22
|
+
ext.gem_spec = gemspec
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
task :default => [:compile, :test]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// ext/games_dice/games_dice.c
|
|
2
|
+
|
|
3
|
+
#include <ruby.h>
|
|
4
|
+
#include "probabilities.h"
|
|
5
|
+
|
|
6
|
+
// To hold the module object
|
|
7
|
+
VALUE GamesDice = Qnil;
|
|
8
|
+
|
|
9
|
+
void Init_games_dice() {
|
|
10
|
+
GamesDice = rb_define_module("GamesDice");
|
|
11
|
+
init_probabilities_class( GamesDice );
|
|
12
|
+
}
|
|
@@ -0,0 +1,765 @@
|
|
|
1
|
+
// ext/games_dice/probabilities.c
|
|
2
|
+
|
|
3
|
+
#include "probabilities.h"
|
|
4
|
+
|
|
5
|
+
// Ruby 1.8.7 compatibility patch
|
|
6
|
+
#ifndef DBL2NUM
|
|
7
|
+
#define DBL2NUM( dbl_val ) rb_float_new( dbl_val )
|
|
8
|
+
#endif
|
|
9
|
+
|
|
10
|
+
VALUE Probabilities = Qnil;
|
|
11
|
+
|
|
12
|
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
13
|
+
//
|
|
14
|
+
// General utils
|
|
15
|
+
//
|
|
16
|
+
|
|
17
|
+
static inline int max( int *a, int n ) {
|
|
18
|
+
int m = -1000000000;
|
|
19
|
+
int i;
|
|
20
|
+
for ( i=0; i < n; i++ ) {
|
|
21
|
+
m = a[i] > m ? a[i] : m;
|
|
22
|
+
}
|
|
23
|
+
return m;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
static inline int min( int *a, int n ) {
|
|
27
|
+
int m = 1000000000;
|
|
28
|
+
int i;
|
|
29
|
+
for ( i=0; i < n; i++ ) {
|
|
30
|
+
m = a[i] < m ? a[i] : m;
|
|
31
|
+
}
|
|
32
|
+
return m;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
36
|
+
//
|
|
37
|
+
// Quick factorials, that fit into unsigned longs . . . the size of this structure sets the
|
|
38
|
+
// maximum possible n in repeat_n_sum_k calculations
|
|
39
|
+
//
|
|
40
|
+
|
|
41
|
+
// There is no point calculating these, a cache of them is just fine.
|
|
42
|
+
static double nfact[171] = {
|
|
43
|
+
1.0, 1.0, 2.0, 6.0,
|
|
44
|
+
24.0, 120.0, 720.0, 5040.0,
|
|
45
|
+
40320.0, 362880.0, 3628800.0, 39916800.0,
|
|
46
|
+
479001600.0, 6227020800.0, 87178291200.0, 1307674368000.0,
|
|
47
|
+
20922789888000.0, 355687428096000.0, 6402373705728000.0, 121645100408832000.0,
|
|
48
|
+
2432902008176640000.0, 51090942171709440000.0, 1124000727777607700000.0, 25852016738884980000000.0,
|
|
49
|
+
620448401733239400000000.0, 15511210043330986000000000.0, 403291461126605650000000000.0, 10888869450418352000000000000.0,
|
|
50
|
+
304888344611713870000000000000.0, 8841761993739702000000000000000.0, 2.6525285981219107e+32, 8.222838654177922e+33,
|
|
51
|
+
2.631308369336935e+35, 8.683317618811886e+36, 2.9523279903960416e+38, 1.0333147966386145e+40,
|
|
52
|
+
3.7199332678990125e+41, 1.3763753091226346e+43, 5.230226174666011e+44, 2.0397882081197444e+46,
|
|
53
|
+
8.159152832478977e+47, 3.345252661316381e+49, 1.40500611775288e+51, 6.041526306337383e+52,
|
|
54
|
+
2.658271574788449e+54, 1.1962222086548019e+56, 5.502622159812089e+57, 2.5862324151116818e+59,
|
|
55
|
+
1.2413915592536073e+61, 6.082818640342675e+62, 3.0414093201713376e+64, 1.5511187532873822e+66,
|
|
56
|
+
8.065817517094388e+67, 4.2748832840600255e+69, 2.308436973392414e+71, 1.2696403353658276e+73,
|
|
57
|
+
7.109985878048635e+74, 4.0526919504877214e+76, 2.3505613312828785e+78, 1.3868311854568984e+80,
|
|
58
|
+
8.32098711274139e+81, 5.075802138772248e+83, 3.146997326038794e+85, 1.98260831540444e+87,
|
|
59
|
+
1.2688693218588417e+89, 8.247650592082472e+90, 5.443449390774431e+92, 3.647111091818868e+94,
|
|
60
|
+
2.4800355424368305e+96, 1.711224524281413e+98, 1.1978571669969892e+100, 8.504785885678623e+101,
|
|
61
|
+
6.1234458376886085e+103, 4.4701154615126844e+105, 3.307885441519386e+107, 2.48091408113954e+109,
|
|
62
|
+
1.8854947016660504e+111, 1.4518309202828587e+113, 1.1324281178206297e+115, 8.946182130782976e+116,
|
|
63
|
+
7.156945704626381e+118, 5.797126020747368e+120, 4.753643337012842e+122, 3.945523969720659e+124,
|
|
64
|
+
3.314240134565353e+126, 2.81710411438055e+128, 2.4227095383672734e+130, 2.107757298379528e+132,
|
|
65
|
+
1.8548264225739844e+134, 1.650795516090846e+136, 1.4857159644817615e+138, 1.352001527678403e+140,
|
|
66
|
+
1.2438414054641308e+142, 1.1567725070816416e+144, 1.087366156656743e+146, 1.032997848823906e+148,
|
|
67
|
+
9.916779348709496e+149, 9.619275968248212e+151, 9.426890448883248e+153, 9.332621544394415e+155,
|
|
68
|
+
9.332621544394415e+157, 9.42594775983836e+159, 9.614466715035127e+161, 9.90290071648618e+163,
|
|
69
|
+
1.0299016745145628e+166, 1.081396758240291e+168, 1.1462805637347084e+170, 1.226520203196138e+172,
|
|
70
|
+
1.324641819451829e+174, 1.4438595832024937e+176, 1.588245541522743e+178, 1.7629525510902446e+180,
|
|
71
|
+
1.974506857221074e+182, 2.2311927486598138e+184, 2.5435597334721877e+186, 2.925093693493016e+188,
|
|
72
|
+
3.393108684451898e+190, 3.969937160808721e+192, 4.684525849754291e+194, 5.574585761207606e+196,
|
|
73
|
+
6.689502913449127e+198, 8.094298525273444e+200, 9.875044200833601e+202, 1.214630436702533e+205,
|
|
74
|
+
1.506141741511141e+207, 1.882677176888926e+209, 2.372173242880047e+211, 3.0126600184576594e+213,
|
|
75
|
+
3.856204823625804e+215, 4.974504222477287e+217, 6.466855489220474e+219, 8.47158069087882e+221,
|
|
76
|
+
1.1182486511960043e+224, 1.4872707060906857e+226, 1.9929427461615188e+228, 2.6904727073180504e+230,
|
|
77
|
+
3.659042881952549e+232, 5.012888748274992e+234, 6.917786472619489e+236, 9.615723196941089e+238,
|
|
78
|
+
1.3462012475717526e+241, 1.898143759076171e+243, 2.695364137888163e+245, 3.854370717180073e+247,
|
|
79
|
+
5.5502938327393044e+249, 8.047926057471992e+251, 1.1749972043909107e+254, 1.727245890454639e+256,
|
|
80
|
+
2.5563239178728654e+258, 3.80892263763057e+260, 5.713383956445855e+262, 8.62720977423324e+264,
|
|
81
|
+
1.3113358856834524e+267, 2.0063439050956823e+269, 3.0897696138473508e+271, 4.789142901463394e+273,
|
|
82
|
+
7.471062926282894e+275, 1.1729568794264145e+278, 1.853271869493735e+280, 2.9467022724950384e+282,
|
|
83
|
+
4.7147236359920616e+284, 7.590705053947219e+286, 1.2296942187394494e+289, 2.0044015765453026e+291,
|
|
84
|
+
3.287218585534296e+293, 5.423910666131589e+295, 9.003691705778438e+297, 1.503616514864999e+300,
|
|
85
|
+
2.5260757449731984e+302, 4.269068009004705e+304, 7.257415615307999e+306 };
|
|
86
|
+
|
|
87
|
+
static double num_arrangements( int *args, int nargs ) {
|
|
88
|
+
int sum = 0;
|
|
89
|
+
double div_by = 1.0;
|
|
90
|
+
int i;
|
|
91
|
+
for ( i = 0; i < nargs; i++ ) {
|
|
92
|
+
sum += args[i];
|
|
93
|
+
if ( sum > 170 ) {
|
|
94
|
+
rb_raise( rb_eRuntimeError, "Too many dice to calculate numbers of arrangements" );
|
|
95
|
+
}
|
|
96
|
+
div_by *= nfact[ args[i] ];
|
|
97
|
+
}
|
|
98
|
+
return nfact[ sum ] / div_by;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
102
|
+
//
|
|
103
|
+
// Probability List basics - create, delete, copy
|
|
104
|
+
//
|
|
105
|
+
|
|
106
|
+
static ProbabilityList *create_probability_list() {
|
|
107
|
+
ProbabilityList *pl;
|
|
108
|
+
pl = malloc (sizeof(ProbabilityList));
|
|
109
|
+
if ( pl == NULL ) {
|
|
110
|
+
rb_raise(rb_eRuntimeError, "Could not allocate memory for Probabilities");
|
|
111
|
+
}
|
|
112
|
+
pl->probs = NULL;
|
|
113
|
+
pl->cumulative = NULL;
|
|
114
|
+
pl->slots = 0;
|
|
115
|
+
pl->offset = 0;
|
|
116
|
+
return pl;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
static void destroy_probability_list( ProbabilityList *pl ) {
|
|
120
|
+
xfree( pl->cumulative );
|
|
121
|
+
xfree( pl->probs );
|
|
122
|
+
xfree( pl );
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
static double *alloc_probs( ProbabilityList *pl, int slots ) {
|
|
127
|
+
if ( slots < 1 || slots > 1000000 ) {
|
|
128
|
+
rb_raise(rb_eArgError, "Bad number of probability slots");
|
|
129
|
+
}
|
|
130
|
+
pl->slots = slots;
|
|
131
|
+
|
|
132
|
+
double *pr = ALLOC_N( double, slots );
|
|
133
|
+
pl->probs = pr;
|
|
134
|
+
|
|
135
|
+
pl->cumulative = ALLOC_N( double, slots );
|
|
136
|
+
|
|
137
|
+
return pr;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
static double calc_cumulative( ProbabilityList *pl ) {
|
|
141
|
+
double *c = pl->cumulative;
|
|
142
|
+
double *pr = pl->probs;
|
|
143
|
+
int i;
|
|
144
|
+
double t = 0.0;
|
|
145
|
+
for(i=0; i < pl->slots; i++) {
|
|
146
|
+
t += pr[i];
|
|
147
|
+
c[i] = t;
|
|
148
|
+
}
|
|
149
|
+
return t;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
static double *alloc_probs_iv( ProbabilityList *pl, int slots, double iv ) {
|
|
153
|
+
if ( iv < 0.0 || iv > 1.0 ) {
|
|
154
|
+
rb_raise(rb_eArgError, "Bad single probability value");
|
|
155
|
+
}
|
|
156
|
+
double *pr = alloc_probs( pl, slots );
|
|
157
|
+
int i;
|
|
158
|
+
for(i=0; i<slots; i++) {
|
|
159
|
+
pr[i] = iv;
|
|
160
|
+
}
|
|
161
|
+
calc_cumulative( pl );
|
|
162
|
+
return pr;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
static ProbabilityList *copy_probability_list( ProbabilityList *orig ) {
|
|
166
|
+
ProbabilityList *pl = create_probability_list();
|
|
167
|
+
double *pr = alloc_probs( pl, orig->slots );
|
|
168
|
+
pl->offset = orig->offset;
|
|
169
|
+
memcpy( pr, orig->probs, orig->slots * sizeof(double) );
|
|
170
|
+
memcpy( pl->cumulative, orig->cumulative, orig->slots * sizeof(double) );
|
|
171
|
+
return pl;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
static inline ProbabilityList *new_basic_pl( int nslots, double iv, int o ) {
|
|
175
|
+
ProbabilityList *pl = create_probability_list();
|
|
176
|
+
alloc_probs_iv( pl, nslots, iv );
|
|
177
|
+
pl->offset = o;
|
|
178
|
+
return pl;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
182
|
+
//
|
|
183
|
+
// Probability List core "native" methods
|
|
184
|
+
//
|
|
185
|
+
|
|
186
|
+
static inline int pl_min( ProbabilityList *pl ) {
|
|
187
|
+
return pl->offset;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
static inline int pl_max( ProbabilityList *pl ) {
|
|
191
|
+
return pl->offset + pl->slots - 1;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
static ProbabilityList *pl_add_distributions( ProbabilityList *pl_a, ProbabilityList *pl_b ) {
|
|
195
|
+
int s = pl_a->slots + pl_b->slots - 1;
|
|
196
|
+
int o = pl_a->offset + pl_b->offset;
|
|
197
|
+
int i,j;
|
|
198
|
+
|
|
199
|
+
ProbabilityList *pl = create_probability_list();
|
|
200
|
+
pl->offset = o;
|
|
201
|
+
double *pr = alloc_probs_iv( pl, s, 0.0 );
|
|
202
|
+
for ( i=0; i < pl_a->slots; i++ ) { for ( j=0; j < pl_b->slots; j++ ) {
|
|
203
|
+
pr[ i + j ] += (pl_a->probs)[i] * (pl_b->probs)[j];
|
|
204
|
+
} }
|
|
205
|
+
calc_cumulative( pl );
|
|
206
|
+
return pl;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
static ProbabilityList *pl_add_distributions_mult( int mul_a, ProbabilityList *pl_a, int mul_b, ProbabilityList *pl_b ) {
|
|
210
|
+
int pts[4] = {
|
|
211
|
+
mul_a * pl_min( pl_a ) + mul_b * pl_min( pl_b ),
|
|
212
|
+
mul_a * pl_max( pl_a ) + mul_b * pl_min( pl_b ),
|
|
213
|
+
mul_a * pl_min( pl_a ) + mul_b * pl_max( pl_b ),
|
|
214
|
+
mul_a * pl_max( pl_a ) + mul_b * pl_max( pl_b ) };
|
|
215
|
+
|
|
216
|
+
int combined_min = min( pts, 4 );
|
|
217
|
+
int combined_max = max( pts, 4 );
|
|
218
|
+
int s = 1 + combined_max - combined_min;
|
|
219
|
+
|
|
220
|
+
ProbabilityList *pl = create_probability_list();
|
|
221
|
+
pl->offset = combined_min;
|
|
222
|
+
double *pr = alloc_probs_iv( pl, s, 0.0 );
|
|
223
|
+
int i,j;
|
|
224
|
+
for ( i=0; i < pl_a->slots; i++ ) { for ( j=0; j < pl_b->slots; j++ ) {
|
|
225
|
+
int k = mul_a * (i + pl_a->offset) + mul_b * (j + pl_b->offset) - combined_min;
|
|
226
|
+
pr[ i + j ] += (pl_a->probs)[i] * (pl_b->probs)[j];
|
|
227
|
+
} }
|
|
228
|
+
calc_cumulative( pl );
|
|
229
|
+
return pl;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
static inline double pl_p_eql( ProbabilityList *pl, int target ) {
|
|
233
|
+
int idx = target - pl->offset;
|
|
234
|
+
if ( idx < 0 || idx >= pl->slots ) {
|
|
235
|
+
return 0.0;
|
|
236
|
+
}
|
|
237
|
+
return (pl->probs)[idx];
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
static inline double pl_p_gt( ProbabilityList *pl, int target ) {
|
|
241
|
+
return 1.0 - pl_p_le( pl, target );
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
static inline double pl_p_lt( ProbabilityList *pl, int target ) {
|
|
245
|
+
return pl_p_le( pl, target - 1 );
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
static inline double pl_p_le( ProbabilityList *pl, int target ) {
|
|
249
|
+
int idx = target - pl->offset;
|
|
250
|
+
if ( idx < 0 ) {
|
|
251
|
+
return 0.0;
|
|
252
|
+
}
|
|
253
|
+
if ( idx >= pl->slots - 1 ) {
|
|
254
|
+
return 1.0;
|
|
255
|
+
}
|
|
256
|
+
return (pl->cumulative)[idx];
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
static inline double pl_p_ge( ProbabilityList *pl, int target ) {
|
|
260
|
+
return 1.0 - pl_p_le( pl, target - 1 );
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
static inline double pl_expected( ProbabilityList *pl ) {
|
|
264
|
+
double t = 0.0;
|
|
265
|
+
int o = pl->offset;
|
|
266
|
+
int s = pl->slots;
|
|
267
|
+
double *pr = pl->probs;
|
|
268
|
+
int i;
|
|
269
|
+
for ( i = 0; i < s ; i++ ) {
|
|
270
|
+
t += ( i + o ) * pr[i];
|
|
271
|
+
}
|
|
272
|
+
return t;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
static ProbabilityList *pl_given_ge( ProbabilityList *pl, int target ) {
|
|
276
|
+
int m = pl_min( pl );
|
|
277
|
+
if ( m > target ) {
|
|
278
|
+
target = m;
|
|
279
|
+
}
|
|
280
|
+
double p = pl_p_ge( pl, target );
|
|
281
|
+
if ( p <= 0.0 ) {
|
|
282
|
+
rb_raise( rb_eRuntimeError, "Cannot calculate given probabilities, divide by zero" );
|
|
283
|
+
}
|
|
284
|
+
double mult = 1.0/p;
|
|
285
|
+
int s = pl->slots + pl->offset - target;
|
|
286
|
+
double *pr = pl->probs;
|
|
287
|
+
|
|
288
|
+
ProbabilityList *new_pl = create_probability_list();
|
|
289
|
+
new_pl->offset = target;
|
|
290
|
+
double *new_pr = alloc_probs( new_pl, s );
|
|
291
|
+
int o = target - pl->offset;
|
|
292
|
+
int i;
|
|
293
|
+
for ( i = 0; i < s; i++ ) {
|
|
294
|
+
new_pr[i] = pr[o + i] * mult;
|
|
295
|
+
}
|
|
296
|
+
calc_cumulative( new_pl );
|
|
297
|
+
return new_pl;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
static ProbabilityList *pl_given_le( ProbabilityList *pl, int target ) {
|
|
301
|
+
int m = pl_max( pl );
|
|
302
|
+
if ( m < target ) {
|
|
303
|
+
target = m;
|
|
304
|
+
}
|
|
305
|
+
double p = pl_p_le( pl, target );
|
|
306
|
+
if ( p <= 0.0 ) {
|
|
307
|
+
rb_raise( rb_eRuntimeError, "Cannot calculate given probabilities, divide by zero" );
|
|
308
|
+
}
|
|
309
|
+
double mult = 1.0/p;
|
|
310
|
+
int s = target - pl->offset + 1;
|
|
311
|
+
double *pr = pl->probs;
|
|
312
|
+
|
|
313
|
+
ProbabilityList *new_pl = create_probability_list();
|
|
314
|
+
new_pl->offset = pl->offset;
|
|
315
|
+
double *new_pr = alloc_probs( new_pl, s );
|
|
316
|
+
int i;
|
|
317
|
+
for ( i = 0; i < s; i++ ) {
|
|
318
|
+
new_pr[i] = pr[i] * mult;
|
|
319
|
+
}
|
|
320
|
+
calc_cumulative( new_pl );
|
|
321
|
+
return new_pl;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
static ProbabilityList *pl_repeat_sum( ProbabilityList *pl, int n ) {
|
|
325
|
+
if ( n < 1 ) {
|
|
326
|
+
rb_raise( rb_eRuntimeError, "Cannot calculate repeat_sum when n < 1" );
|
|
327
|
+
}
|
|
328
|
+
if ( n * pl->slots - n > 1000000 ) {
|
|
329
|
+
rb_raise( rb_eRuntimeError, "Too many probability slots" );
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
ProbabilityList *pd_power = copy_probability_list( pl );
|
|
333
|
+
ProbabilityList *pd_result = NULL;
|
|
334
|
+
ProbabilityList *pd_next = NULL;
|
|
335
|
+
int power = 1;
|
|
336
|
+
while ( 1 ) {
|
|
337
|
+
if ( power & n ) {
|
|
338
|
+
if ( pd_result ) {
|
|
339
|
+
pd_next = pl_add_distributions( pd_result, pd_power );
|
|
340
|
+
destroy_probability_list( pd_result );
|
|
341
|
+
pd_result = pd_next;
|
|
342
|
+
} else {
|
|
343
|
+
pd_result = copy_probability_list( pd_power );
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
power = power << 1;
|
|
347
|
+
if ( power > n ) break;
|
|
348
|
+
pd_next = pl_add_distributions( pd_power, pd_power );
|
|
349
|
+
destroy_probability_list( pd_power );
|
|
350
|
+
pd_power = pd_next;
|
|
351
|
+
}
|
|
352
|
+
destroy_probability_list( pd_power );
|
|
353
|
+
|
|
354
|
+
return pd_result;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// Assigns { p_rejected, p_maybe, p_kept } to buffer
|
|
358
|
+
static void calc_p_table( ProbabilityList *pl, int q, int kbest, double *buffer ) {
|
|
359
|
+
if ( kbest ) {
|
|
360
|
+
buffer[2] = pl_p_gt( pl, q );
|
|
361
|
+
buffer[1] = pl_p_eql( pl, q );
|
|
362
|
+
buffer[0] = pl_p_lt( pl, q );
|
|
363
|
+
} else {
|
|
364
|
+
buffer[2] = pl_p_lt( pl, q );
|
|
365
|
+
buffer[1] = pl_p_eql( pl, q );
|
|
366
|
+
buffer[0] = pl_p_gt( pl, q );
|
|
367
|
+
}
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Assigns a list of pl variants to a buffer
|
|
372
|
+
static void calc_keep_distributions( ProbabilityList *pl, int k, int q, int kbest, ProbabilityList **pl_array ) {
|
|
373
|
+
// Init array
|
|
374
|
+
int n;
|
|
375
|
+
for ( n=0; n<k; n++) { pl_array[n] = NULL; }
|
|
376
|
+
pl_array[0] = new_basic_pl( 1, 1.0, q * k );
|
|
377
|
+
ProbabilityList *pl_kd;
|
|
378
|
+
|
|
379
|
+
if ( kbest ) {
|
|
380
|
+
if ( pl_p_gt( pl, q ) > 0.0 && k > 1 ) {
|
|
381
|
+
pl_kd = pl_given_ge( pl, q + 1 );
|
|
382
|
+
for ( n = 1; n < k; n++ ) {
|
|
383
|
+
pl_array[n] = pl_repeat_sum( pl_kd, n );
|
|
384
|
+
(pl_array[n])->offset += q * ( k - n );
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
} else {
|
|
388
|
+
if ( pl_p_lt( pl, q ) > 0.0 && k > 1 ) {
|
|
389
|
+
pl_kd = pl_given_le( pl, q - 1 );
|
|
390
|
+
for ( n = 1; n < k; n++ ) {
|
|
391
|
+
pl_array[n] = pl_repeat_sum( pl_kd, n );
|
|
392
|
+
(pl_array[n])->offset += q * ( k - n );
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
static inline void clear_pl_array( int k, ProbabilityList **pl_array ) {
|
|
401
|
+
int n;
|
|
402
|
+
for ( n=0; n<k; n++) {
|
|
403
|
+
if ( pl_array[n] != NULL ) {
|
|
404
|
+
destroy_probability_list( pl_array[n] );
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
static ProbabilityList *pl_repeat_n_sum_k( ProbabilityList *pl, int n, int k, int kbest ) {
|
|
411
|
+
if ( n < 1 ) {
|
|
412
|
+
rb_raise( rb_eRuntimeError, "Cannot calculate repeat_n_sum_k when n < 1" );
|
|
413
|
+
}
|
|
414
|
+
if ( k < 1 ) {
|
|
415
|
+
rb_raise( rb_eRuntimeError, "Cannot calculate repeat_sum_k when k < 1" );
|
|
416
|
+
}
|
|
417
|
+
if ( k >= n ) {
|
|
418
|
+
return pl_repeat_sum( pl, n );
|
|
419
|
+
}
|
|
420
|
+
if ( k * pl->slots - k >= 1000000 ) {
|
|
421
|
+
rb_raise( rb_eRuntimeError, "Too many probability slots" );
|
|
422
|
+
}
|
|
423
|
+
if ( n > 170 ) {
|
|
424
|
+
rb_raise( rb_eRuntimeError, "Too many dice to calculate combinations" );
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// Init target
|
|
428
|
+
ProbabilityList *pl_result = create_probability_list();
|
|
429
|
+
double *pr = alloc_probs_iv( pl_result, 1 + k * (pl->slots - 1), 0.0 );
|
|
430
|
+
pl_result->offset = pl->offset * k;
|
|
431
|
+
|
|
432
|
+
// Table of probabilities ( reject, maybe, keep ) for each "pivot point"
|
|
433
|
+
double p_table[3];
|
|
434
|
+
int keep_combos[3];
|
|
435
|
+
// Table of distributions for each count of > pivot point (vs == pivot point)
|
|
436
|
+
ProbabilityList *keep_distributions[171];
|
|
437
|
+
ProbabilityList *kd;
|
|
438
|
+
|
|
439
|
+
int d = n - k;
|
|
440
|
+
int i, j, q, dn, kn, mn, kdq;
|
|
441
|
+
double p_sequence;
|
|
442
|
+
|
|
443
|
+
for ( i = 0; i < pl->slots; i++ ) {
|
|
444
|
+
if ( ! pl->probs[i] > 0.0 ) continue;
|
|
445
|
+
|
|
446
|
+
q = i + pl->offset;
|
|
447
|
+
calc_keep_distributions( pl, k, q, kbest, keep_distributions );
|
|
448
|
+
calc_p_table( pl, q, kbest, p_table );
|
|
449
|
+
|
|
450
|
+
for ( kn = 0; kn < k; kn++ ) {
|
|
451
|
+
// Construct keepers. maybes, discards (just counts of these) . . .
|
|
452
|
+
if ( kn > 0 && ! ( p_table[2] > 0.0 ) ) continue;
|
|
453
|
+
|
|
454
|
+
for ( dn = 0; dn <= d; dn++ ) {
|
|
455
|
+
mn = (k - kn) + ( d - dn );
|
|
456
|
+
if ( dn > 0 && ! ( p_table[0] > 0.0 ) ) continue;
|
|
457
|
+
p_sequence = 1.0;
|
|
458
|
+
for ( j = 0; j < dn; j++ ) { p_sequence *= p_table[0]; }
|
|
459
|
+
for ( j = 0; j < mn; j++ ) { p_sequence *= p_table[1]; }
|
|
460
|
+
for ( j = 0; j < kn; j++ ) { p_sequence *= p_table[2]; }
|
|
461
|
+
keep_combos[0] = dn;
|
|
462
|
+
keep_combos[1] = mn;
|
|
463
|
+
keep_combos[2] = kn;
|
|
464
|
+
p_sequence *= num_arrangements( keep_combos, 3 );
|
|
465
|
+
kd = keep_distributions[ kn ];
|
|
466
|
+
|
|
467
|
+
for ( j = 0; j < kd->slots; j++ ) {
|
|
468
|
+
kdq = j + kd->offset;
|
|
469
|
+
pr[ kdq - pl_result->offset ] += p_sequence * kd->probs[ j ];
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
clear_pl_array( k, keep_distributions );
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
calc_cumulative( pl_result );
|
|
477
|
+
return pl_result;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
483
|
+
//
|
|
484
|
+
// Ruby integration
|
|
485
|
+
//
|
|
486
|
+
|
|
487
|
+
static inline VALUE pl_as_ruby_class( ProbabilityList *pl, VALUE klass ) {
|
|
488
|
+
return Data_Wrap_Struct( klass, 0, destroy_probability_list, pl );
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
static VALUE pl_alloc(VALUE klass) {
|
|
492
|
+
return pl_as_ruby_class( create_probability_list(), klass );
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
inline static ProbabilityList *get_probability_list( VALUE obj ) {
|
|
496
|
+
ProbabilityList *pl;
|
|
497
|
+
Data_Get_Struct( obj, ProbabilityList, pl );
|
|
498
|
+
return pl;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
static void assert_value_wraps_pl( VALUE obj ) {
|
|
502
|
+
if ( TYPE(obj) != T_DATA ||
|
|
503
|
+
RDATA(obj)->dfree != (RUBY_DATA_FUNC)destroy_probability_list) {
|
|
504
|
+
rb_raise( rb_eTypeError, "Expected a Probabilities object, but got something else" );
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// Validate key/value from hash, and adjust object properties as required
|
|
509
|
+
int validate_key_value( VALUE key, VALUE val, VALUE obj ) {
|
|
510
|
+
int k = NUM2INT( key );
|
|
511
|
+
double v = NUM2DBL( val );
|
|
512
|
+
ProbabilityList *pl = get_probability_list( obj );
|
|
513
|
+
if ( k < pl->offset ) {
|
|
514
|
+
if ( pl->slots < 1 ) {
|
|
515
|
+
pl->slots = 1;
|
|
516
|
+
} else {
|
|
517
|
+
pl->slots = pl->slots - k + pl->offset;
|
|
518
|
+
}
|
|
519
|
+
pl->offset = k;
|
|
520
|
+
} else if ( k - pl->offset >= pl->slots ) {
|
|
521
|
+
pl->slots = 1 + k - pl->offset;
|
|
522
|
+
}
|
|
523
|
+
return ST_CONTINUE;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
// Copy key/value from hash
|
|
527
|
+
int copy_key_value( VALUE key, VALUE val, VALUE obj ) {
|
|
528
|
+
int k = NUM2INT( key );
|
|
529
|
+
double v = NUM2DBL( val );
|
|
530
|
+
ProbabilityList *pl = get_probability_list( obj );
|
|
531
|
+
pl->probs[ k - pl->offset ] = v;
|
|
532
|
+
return ST_CONTINUE;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
536
|
+
//
|
|
537
|
+
// Ruby class and instance methods for Probabilities
|
|
538
|
+
//
|
|
539
|
+
|
|
540
|
+
static VALUE probabilities_initialize( VALUE self, VALUE arr, VALUE offset ) {
|
|
541
|
+
int o = NUM2INT(offset);
|
|
542
|
+
Check_Type( arr, T_ARRAY );
|
|
543
|
+
int s = FIX2INT( rb_funcall( arr, rb_intern("count"), 0 ) );
|
|
544
|
+
ProbabilityList *pl = get_probability_list( self );
|
|
545
|
+
pl->offset = o;
|
|
546
|
+
int i;
|
|
547
|
+
double *pr = alloc_probs( pl, s );
|
|
548
|
+
for(i=0; i<s; i++) {
|
|
549
|
+
double p_item = NUM2DBL( rb_ary_entry( arr, i ) );
|
|
550
|
+
if ( p_item < 0.0 ) {
|
|
551
|
+
rb_raise( rb_eArgError, "Negative probability not allowed" );
|
|
552
|
+
} else if ( p_item > 1.0 ) {
|
|
553
|
+
rb_raise( rb_eArgError, "Probability must be in range 0.0..1.0" );
|
|
554
|
+
}
|
|
555
|
+
pr[i] = p_item;
|
|
556
|
+
}
|
|
557
|
+
double error = calc_cumulative( pl ) - 1.0;
|
|
558
|
+
if ( error < -1.0e-8 ) {
|
|
559
|
+
rb_raise( rb_eArgError, "Total probabilities are less than 1.0" );
|
|
560
|
+
} else if ( error > 1.0e-8 ) {
|
|
561
|
+
rb_raise( rb_eArgError, "Total probabilities are greater than 1.0" );
|
|
562
|
+
}
|
|
563
|
+
return self;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
static VALUE probabilities_initialize_copy( VALUE copy, VALUE orig ) {
|
|
568
|
+
if (copy == orig) return copy;
|
|
569
|
+
ProbabilityList *pl_copy = get_probability_list( copy );
|
|
570
|
+
ProbabilityList *pl_orig = get_probability_list( orig );
|
|
571
|
+
|
|
572
|
+
double *pr = alloc_probs( pl_copy, pl_orig->slots );
|
|
573
|
+
pl_copy->offset = pl_orig->offset;
|
|
574
|
+
memcpy( pr, pl_orig->probs, pl_orig->slots * sizeof(double) );
|
|
575
|
+
memcpy( pl_copy->cumulative, pl_orig->cumulative, pl_orig->slots * sizeof(double) );;
|
|
576
|
+
|
|
577
|
+
return copy;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
VALUE probabilities_to_h( VALUE self ) {
|
|
581
|
+
ProbabilityList *pl = get_probability_list( self );
|
|
582
|
+
VALUE h = rb_hash_new();
|
|
583
|
+
double *pr = pl->probs;
|
|
584
|
+
int s = pl->slots;
|
|
585
|
+
int o = pl->offset;
|
|
586
|
+
int i;
|
|
587
|
+
for(i=0; i<s; i++) {
|
|
588
|
+
if ( pr[i] > 0.0 ) {
|
|
589
|
+
rb_hash_aset( h, INT2FIX( o + i ), DBL2NUM( pr[i] ) );
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
return h;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
VALUE probabilities_min( VALUE self ) {
|
|
596
|
+
return INT2NUM( pl_min( get_probability_list( self ) ) );
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
VALUE probabilities_max( VALUE self ) {
|
|
600
|
+
return INT2NUM( pl_max( get_probability_list( self ) ) );
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
VALUE probabilites_p_eql( VALUE self, VALUE target ) {
|
|
604
|
+
return DBL2NUM( pl_p_eql( get_probability_list( self ), NUM2INT(target) ) );
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
VALUE probabilites_p_gt( VALUE self, VALUE target ) {
|
|
608
|
+
return DBL2NUM( pl_p_gt( get_probability_list( self ), NUM2INT(target) ) );
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
VALUE probabilites_p_ge( VALUE self, VALUE target ) {
|
|
612
|
+
return DBL2NUM( pl_p_ge( get_probability_list( self ), NUM2INT(target) ) );
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
VALUE probabilites_p_le( VALUE self, VALUE target ) {
|
|
616
|
+
return DBL2NUM( pl_p_le( get_probability_list( self ), NUM2INT(target) ) );
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
VALUE probabilites_p_lt( VALUE self, VALUE target ) {
|
|
620
|
+
return DBL2NUM( pl_p_lt( get_probability_list( self ), NUM2INT(target) ) );
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
VALUE probabilites_expected( VALUE self ) {
|
|
624
|
+
return DBL2NUM( pl_expected( get_probability_list( self ) ) );
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
VALUE probabilities_given_ge( VALUE self, VALUE target ) {
|
|
628
|
+
int t = NUM2INT(target);
|
|
629
|
+
ProbabilityList *pl = get_probability_list( self );
|
|
630
|
+
return pl_as_ruby_class( pl_given_ge( pl, t ), Probabilities );
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
VALUE probabilities_given_le( VALUE self, VALUE target ) {
|
|
634
|
+
int t = NUM2INT(target);
|
|
635
|
+
ProbabilityList *pl = get_probability_list( self );
|
|
636
|
+
return pl_as_ruby_class( pl_given_le( pl, t ), Probabilities );
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
VALUE probabilities_repeat_sum( VALUE self, VALUE nsum ) {
|
|
640
|
+
int n = NUM2INT(nsum);
|
|
641
|
+
ProbabilityList *pl = get_probability_list( self );
|
|
642
|
+
return pl_as_ruby_class( pl_repeat_sum( pl, n ), Probabilities );
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
static VALUE probabilities_repeat_n_sum_k( int argc, VALUE* argv, VALUE self ) {
|
|
646
|
+
VALUE nsum, nkeepers, kmode;
|
|
647
|
+
rb_scan_args( argc, argv, "21", &nsum, &nkeepers, &kmode );
|
|
648
|
+
int keep_best = 1;
|
|
649
|
+
if (NIL_P(kmode)) {
|
|
650
|
+
keep_best = 1;
|
|
651
|
+
} else if ( rb_intern("keep_worst") == SYM2ID(kmode) ) {
|
|
652
|
+
keep_best = 0;
|
|
653
|
+
} else if ( rb_intern("keep_best") != SYM2ID(kmode) ) {
|
|
654
|
+
rb_raise( rb_eArgError, "Keep mode not recognised" );
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
int n = NUM2INT(nsum);
|
|
658
|
+
int k = NUM2INT(nkeepers);
|
|
659
|
+
ProbabilityList *pl = get_probability_list( self );
|
|
660
|
+
return pl_as_ruby_class( pl_repeat_n_sum_k( pl, n, k, keep_best ), Probabilities );
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
VALUE probabilities_each( VALUE self ) {
|
|
664
|
+
ProbabilityList *pl = get_probability_list( self );
|
|
665
|
+
int i;
|
|
666
|
+
double *pr = pl->probs;
|
|
667
|
+
int o = pl->offset;
|
|
668
|
+
for ( i = 0; i < pl->slots; i++ ) {
|
|
669
|
+
if ( pr[i] > 0.0 ) {
|
|
670
|
+
VALUE a = rb_ary_new2( 2 );
|
|
671
|
+
rb_ary_store( a, 0, INT2NUM( i + o ));
|
|
672
|
+
rb_ary_store( a, 1, DBL2NUM( pr[i] ));
|
|
673
|
+
rb_yield( a );
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
return self;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
VALUE probabilities_for_fair_die( VALUE self, VALUE sides ) {
|
|
680
|
+
int s = NUM2INT( sides );
|
|
681
|
+
if ( s < 1 ) {
|
|
682
|
+
rb_raise( rb_eArgError, "Number of sides should be 1 or more" );
|
|
683
|
+
}
|
|
684
|
+
if ( s > 100000 ) {
|
|
685
|
+
rb_raise( rb_eArgError, "Number of sides should be less than 100001" );
|
|
686
|
+
}
|
|
687
|
+
VALUE obj = pl_alloc( Probabilities );
|
|
688
|
+
ProbabilityList *pl = get_probability_list( obj );
|
|
689
|
+
pl->offset = 1;
|
|
690
|
+
alloc_probs_iv( pl, s, 1.0/s );
|
|
691
|
+
return obj;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
VALUE probabilities_from_h( VALUE self, VALUE hash ) {
|
|
695
|
+
rb_check_hash_type( hash );
|
|
696
|
+
|
|
697
|
+
VALUE obj = pl_alloc( Probabilities );
|
|
698
|
+
ProbabilityList *pl = get_probability_list( obj );
|
|
699
|
+
// Set these up so that they get adjusted during hash iteration
|
|
700
|
+
pl->offset = 2000000000;
|
|
701
|
+
pl->slots = 0;
|
|
702
|
+
// First iteration establish min/max and validate all key/values
|
|
703
|
+
rb_hash_foreach( hash, validate_key_value, obj );
|
|
704
|
+
|
|
705
|
+
double *pr = alloc_probs_iv( pl, pl->slots, 0.0 );
|
|
706
|
+
// Second iteration copy key/value pairs into structure
|
|
707
|
+
rb_hash_foreach( hash, copy_key_value, obj );
|
|
708
|
+
|
|
709
|
+
double error = calc_cumulative( pl ) - 1.0;
|
|
710
|
+
if ( error < -1.0e-8 ) {
|
|
711
|
+
rb_raise( rb_eArgError, "Total probabilities are less than 1.0" );
|
|
712
|
+
} else if ( error > 1.0e-8 ) {
|
|
713
|
+
rb_raise( rb_eArgError, "Total probabilities are greater than 1.0" );
|
|
714
|
+
}
|
|
715
|
+
return obj;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
VALUE probabilities_add_distributions( VALUE self, VALUE gdpa, VALUE gdpb ) {
|
|
719
|
+
assert_value_wraps_pl( gdpa );
|
|
720
|
+
assert_value_wraps_pl( gdpb );
|
|
721
|
+
ProbabilityList *pl_a = get_probability_list( gdpa );
|
|
722
|
+
ProbabilityList *pl_b = get_probability_list( gdpb );
|
|
723
|
+
return pl_as_ruby_class( pl_add_distributions( pl_a, pl_b ), Probabilities );
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
VALUE probabilities_add_distributions_mult( VALUE self, VALUE m_a, VALUE gdpa, VALUE m_b, VALUE gdpb ) {
|
|
727
|
+
assert_value_wraps_pl( gdpa );
|
|
728
|
+
assert_value_wraps_pl( gdpb );
|
|
729
|
+
int mul_a = NUM2INT( m_a );
|
|
730
|
+
ProbabilityList *pl_a = get_probability_list( gdpa );
|
|
731
|
+
int mul_b = NUM2INT( m_b );
|
|
732
|
+
ProbabilityList *pl_b = get_probability_list( gdpb );
|
|
733
|
+
return pl_as_ruby_class( pl_add_distributions_mult( mul_a, pl_a, mul_b, pl_b ), Probabilities );
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
737
|
+
//
|
|
738
|
+
// Setup Probabilities class for Ruby interpretter
|
|
739
|
+
//
|
|
740
|
+
|
|
741
|
+
void init_probabilities_class( VALUE ParentModule ) {
|
|
742
|
+
Probabilities = rb_define_class_under( ParentModule, "Probabilities", rb_cObject );
|
|
743
|
+
rb_define_alloc_func( Probabilities, pl_alloc );
|
|
744
|
+
rb_define_method( Probabilities, "initialize", probabilities_initialize, 2 );
|
|
745
|
+
rb_define_method( Probabilities, "initialize_copy", probabilities_initialize_copy, 1 );
|
|
746
|
+
rb_define_method( Probabilities, "to_h", probabilities_to_h, 0 );
|
|
747
|
+
rb_define_method( Probabilities, "min", probabilities_min, 0 );
|
|
748
|
+
rb_define_method( Probabilities, "max", probabilities_max, 0 );
|
|
749
|
+
rb_define_method( Probabilities, "p_eql", probabilites_p_eql, 1 );
|
|
750
|
+
rb_define_method( Probabilities, "p_gt", probabilites_p_gt, 1 );
|
|
751
|
+
rb_define_method( Probabilities, "p_ge", probabilites_p_ge, 1 );
|
|
752
|
+
rb_define_method( Probabilities, "p_le", probabilites_p_le, 1 );
|
|
753
|
+
rb_define_method( Probabilities, "p_lt", probabilites_p_lt, 1 );
|
|
754
|
+
rb_define_method( Probabilities, "expected", probabilites_expected, 0 );
|
|
755
|
+
rb_define_method( Probabilities, "each", probabilities_each, 0 );
|
|
756
|
+
rb_define_method( Probabilities, "given_ge", probabilities_given_ge, 1 );
|
|
757
|
+
rb_define_method( Probabilities, "given_le", probabilities_given_le, 1 );
|
|
758
|
+
rb_define_method( Probabilities, "repeat_sum", probabilities_repeat_sum, 1 );
|
|
759
|
+
rb_define_method( Probabilities, "repeat_n_sum_k", probabilities_repeat_n_sum_k, -1 );
|
|
760
|
+
rb_define_singleton_method( Probabilities, "for_fair_die", probabilities_for_fair_die, 1 );
|
|
761
|
+
rb_define_singleton_method( Probabilities, "add_distributions", probabilities_add_distributions, 2 );
|
|
762
|
+
rb_define_singleton_method( Probabilities, "add_distributions_mult", probabilities_add_distributions_mult, 4 );
|
|
763
|
+
rb_define_singleton_method( Probabilities, "from_h", probabilities_from_h, 1 );
|
|
764
|
+
return;
|
|
765
|
+
}
|