Skip to content

Commit e80620d

Browse files
authored
Fix discrete_distribution and add Windows workaround (#15)
Visual Studio 2012 lacks the iterator constructor for discrete_distribution. This made me realize that the iterator constructor is actually supposed to take doubles, not the result_type. So I fixed the 'weights' signature and added a workaround that uses the initializer_list constructor.
1 parent 463c978 commit e80620d

File tree

5 files changed

+42
-22
lines changed

5 files changed

+42
-22
lines changed

doc/modules/random.rst

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,14 +97,14 @@ The discrete distribution is constructed with an array of :math:`N` weights:
9797
the probability that an index in the range :math:`[1, N]` will be selected.
9898
::
9999

100-
integer(C_INT), dimension(4), parameter :: weights = [1, 1, 2, 4]
100+
real(C_DOUBLE), dimension(4), parameter :: weights &
101+
= [.125d0, .125d0, .25d0, .5d0]
101102
integer(C_INT), dimension(1024) :: sampled
102103
call discrete_distribution(weights, Engine(), sampled)
103104

104-
In the above example, ``1`` and ``2`` will be present in the ``sampled`` array
105-
about the same number of times since those indices have equal weight; ``3``
106-
will be present about twice as often as ``1`` and ``4`` will be present about
107-
four times as often.
105+
In the above example, ``1`` and ``2`` will are expected to each occupy an
106+
eighth of the ``sampled`` array, approximately a quarter of the ``sampled``
107+
array's values will be ``3``, and about a half will be ``4``.
108108

109109
.. note:: The C++ distribution returns values in :math:`[0, N)`, so in
110110
accordance with Flibcpp's :ref:`indexing convention <conventions_indexing>`

include/flc_random.i

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@
1111

1212
%{
1313
#include <random>
14+
#if defined(_MSC_VER) && _MSC_VER < 1900
15+
// Visual studio 2012's standard library lacks iterator constructors for
16+
// std::discrete_distribution
17+
#define FLC_MISSING_DISCRETE_ITER
18+
#endif
1419
%}
1520

1621
/* -------------------------------------------------------------------------
@@ -54,8 +59,7 @@ static inline void flc_generate(D dist, G& g, T* data, size_t size) {
5459
%}
5560

5661
%apply (const SWIGTYPE *DATA, size_t SIZE) {
57-
(const int32_t *WEIGHTS, size_t WEIGHTSIZE),
58-
(const int64_t *WEIGHTS, size_t WEIGHTSIZE) };
62+
(const double *WEIGHTS, size_t WEIGHTSIZE) };
5963

6064
%inline %{
6165
template<class T, class G>
@@ -80,9 +84,14 @@ static void normal_distribution(T mean, T stddev,
8084
}
8185

8286
template<class T, class G>
83-
static void discrete_distribution(const T* WEIGHTS, size_t WEIGHTSIZE,
87+
static void discrete_distribution(const double* WEIGHTS, size_t WEIGHTSIZE,
8488
G& engine, T* DATA, size_t DATASIZE) {
89+
#ifndef FLC_MISSING_DISCRETE_ITER
8590
std::discrete_distribution<T> dist(WEIGHTS, WEIGHTS + WEIGHTSIZE);
91+
#else
92+
std::discrete_distribution<T> dist(
93+
std::initializer_list<double>(WEIGHTS, WEIGHTS + WEIGHTSIZE));
94+
#endif
8695
T* const end = DATA + DATASIZE;
8796
while (DATA != end) {
8897
*DATA++ = dist(engine) + 1; // Note: transform to Fortran 1-offset

src/flc_random.f90

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -548,29 +548,29 @@ subroutine normal_distribution(mean, stddev, engine, data)
548548

549549
subroutine swigf_discrete_distribution__SWIG_1(weights, engine, data)
550550
use, intrinsic :: ISO_C_BINDING
551-
integer(C_INT32_T), dimension(:), intent(in), target :: weights
551+
real(C_DOUBLE), dimension(:), intent(in), target :: weights
552552
class(MersenneEngine4), intent(in) :: engine
553553
integer(C_INT32_T), dimension(:), target :: data
554554
type(SwigArrayWrapper) :: farg1
555555
type(SwigClassWrapper) :: farg3
556556
type(SwigArrayWrapper) :: farg4
557557

558-
call SWIGTM_fin_int32_t_Sb__SB_(weights, farg1)
558+
call SWIGTM_fin_double_Sb__SB_(weights, farg1)
559559
farg3 = engine%swigdata
560560
call SWIGTM_fin_int32_t_Sb__SB_(data, farg4)
561561
call swigc_discrete_distribution__SWIG_1(farg1, farg3, farg4)
562562
end subroutine
563563

564564
subroutine swigf_discrete_distribution__SWIG_2(weights, engine, data)
565565
use, intrinsic :: ISO_C_BINDING
566-
integer(C_INT64_T), dimension(:), intent(in), target :: weights
566+
real(C_DOUBLE), dimension(:), intent(in), target :: weights
567567
class(MersenneEngine4), intent(in) :: engine
568568
integer(C_INT64_T), dimension(:), target :: data
569569
type(SwigArrayWrapper) :: farg1
570570
type(SwigClassWrapper) :: farg3
571571
type(SwigArrayWrapper) :: farg4
572572

573-
call SWIGTM_fin_int64_t_Sb__SB_(weights, farg1)
573+
call SWIGTM_fin_double_Sb__SB_(weights, farg1)
574574
farg3 = engine%swigdata
575575
call SWIGTM_fin_int64_t_Sb__SB_(data, farg4)
576576
call swigc_discrete_distribution__SWIG_2(farg1, farg3, farg4)

src/flc_randomFORTRAN_wrap.cxx

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,11 @@ enum AssignmentType {
257257

258258

259259
#include <random>
260+
#if defined(_MSC_VER) && _MSC_VER < 1900
261+
// Visual studio 2012's standard library lacks iterator constructors for
262+
// std::discrete_distribution
263+
#define FLC_MISSING_DISCRETE_ITER
264+
#endif
260265

261266

262267
template<class D, class G, class T>
@@ -290,9 +295,14 @@ static void normal_distribution(T mean, T stddev,
290295
}
291296

292297
template<class T, class G>
293-
static void discrete_distribution(const T* WEIGHTS, size_t WEIGHTSIZE,
298+
static void discrete_distribution(const double* WEIGHTS, size_t WEIGHTSIZE,
294299
G& engine, T* DATA, size_t DATASIZE) {
300+
#ifndef FLC_MISSING_DISCRETE_ITER
295301
std::discrete_distribution<T> dist(WEIGHTS, WEIGHTS + WEIGHTSIZE);
302+
#else
303+
std::discrete_distribution<T> dist(
304+
std::initializer_list<double>(WEIGHTS, WEIGHTS + WEIGHTSIZE));
305+
#endif
296306
T* const end = DATA + DATASIZE;
297307
while (DATA != end) {
298308
*DATA++ = dist(engine) + 1; // Note: transform to Fortran 1-offset
@@ -685,37 +695,37 @@ SWIGEXPORT void _wrap_normal_distribution(double const *farg1, double const *far
685695

686696

687697
SWIGEXPORT void _wrap_discrete_distribution__SWIG_1(SwigArrayWrapper *farg1, SwigClassWrapper *farg3, SwigArrayWrapper *farg4) {
688-
int32_t *arg1 = (int32_t *) 0 ;
698+
double *arg1 = (double *) 0 ;
689699
size_t arg2 ;
690700
std::mt19937 *arg3 = 0 ;
691701
int32_t *arg4 = (int32_t *) 0 ;
692702
size_t arg5 ;
693703

694-
arg1 = (int32_t *)farg1->data;
704+
arg1 = (double *)farg1->data;
695705
arg2 = farg1->size;
696-
SWIG_check_nonnull(*farg3, "std::mt19937 &", "MersenneEngine4", "discrete_distribution< int32_t,std::mt19937 >(int32_t const *,size_t,std::mt19937 &,int32_t *,size_t)", return );
706+
SWIG_check_nonnull(*farg3, "std::mt19937 &", "MersenneEngine4", "discrete_distribution< int32_t,std::mt19937 >(double const *,size_t,std::mt19937 &,int32_t *,size_t)", return );
697707
arg3 = (std::mt19937 *)farg3->cptr;
698708
arg4 = (int32_t *)farg4->data;
699709
arg5 = farg4->size;
700-
discrete_distribution< int32_t,std::mt19937 >((int32_t const *)arg1,arg2,*arg3,arg4,arg5);
710+
discrete_distribution< int32_t,std::mt19937 >((double const *)arg1,arg2,*arg3,arg4,arg5);
701711
SWIG_free_rvalue< std::mt19937, SWIGPOLICY_std_mt19937 >(*farg3);
702712
}
703713

704714

705715
SWIGEXPORT void _wrap_discrete_distribution__SWIG_2(SwigArrayWrapper *farg1, SwigClassWrapper *farg3, SwigArrayWrapper *farg4) {
706-
int64_t *arg1 = (int64_t *) 0 ;
716+
double *arg1 = (double *) 0 ;
707717
size_t arg2 ;
708718
std::mt19937 *arg3 = 0 ;
709719
int64_t *arg4 = (int64_t *) 0 ;
710720
size_t arg5 ;
711721

712-
arg1 = (int64_t *)farg1->data;
722+
arg1 = (double *)farg1->data;
713723
arg2 = farg1->size;
714-
SWIG_check_nonnull(*farg3, "std::mt19937 &", "MersenneEngine4", "discrete_distribution< int64_t,std::mt19937 >(int64_t const *,size_t,std::mt19937 &,int64_t *,size_t)", return );
724+
SWIG_check_nonnull(*farg3, "std::mt19937 &", "MersenneEngine4", "discrete_distribution< int64_t,std::mt19937 >(double const *,size_t,std::mt19937 &,int64_t *,size_t)", return );
715725
arg3 = (std::mt19937 *)farg3->cptr;
716726
arg4 = (int64_t *)farg4->data;
717727
arg5 = farg4->size;
718-
discrete_distribution< int64_t,std::mt19937 >((int64_t const *)arg1,arg2,*arg3,arg4,arg5);
728+
discrete_distribution< int64_t,std::mt19937 >((double const *)arg1,arg2,*arg3,arg4,arg5);
719729
SWIG_free_rvalue< std::mt19937, SWIGPOLICY_std_mt19937 >(*farg3);
720730
}
721731

test/test_random.F90

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ subroutine test_discrete_distribution()
110110
use, intrinsic :: ISO_C_BINDING
111111
use flc_random, only : Engine => MersenneEngine4, discrete_distribution
112112
implicit none
113-
integer(C_INT), dimension(4), parameter :: weights = [1, 1, 2, 4]
113+
real(C_DOUBLE), dimension(4), parameter :: weights &
114+
= [.125d0, .125d0, .25d0, .5d0]
114115
integer(C_INT), dimension(1024) :: sampled
115116
integer(C_INT), dimension(4) :: tallied = 0
116117
integer(C_INT), dimension(4), parameter :: gold_result = [130, 127, 267, 500]

0 commit comments

Comments
 (0)