@@ -164,6 +164,19 @@ cdef double kahan_sum(double *darr, np.npy_intp n):
164
164
sum = t
165
165
return sum
166
166
167
+ cdef inline void compute_complex (double * rv_r , double * rv_i , double loc_r ,
168
+ double loc_i , double var_r , double var_i , double rho ) nogil :
169
+ cdef double scale_c , scale_i , scale_r
170
+
171
+ scale_c = sqrt (1 - rho * rho )
172
+ scale_r = sqrt (var_r )
173
+ scale_i = sqrt (var_i )
174
+
175
+ rv_i [0 ] = loc_i + scale_i * (rho * rv_r [0 ] + scale_c * rv_i [0 ])
176
+ rv_r [0 ] = loc_r + scale_r * rv_r [0 ]
177
+
178
+
179
+
167
180
cdef object _ensure_string (object s ):
168
181
try :
169
182
return '' .join (map (chr , s ))
@@ -1782,9 +1795,14 @@ cdef class RandomState:
1782
1795
1783
1796
>>> s = np.random.complex_normal(size=1000)
1784
1797
"""
1785
- cdef np .ndarray ogamma , orelation , oloc
1798
+ if method != u'zig' or method != u'bm' :
1799
+ raise ValueError ("method must be either 'bm' or 'zig'" )
1800
+ cdef np .ndarray ogamma , orelation , oloc , randoms , v_real , v_imag , rho
1801
+ cdef double * randoms_data
1786
1802
cdef double fgamma_r , fgamma_i , frelation_r , frelation_i , frho , f_v_real , f_v_imag , \
1787
- floc_r , floc_i , f_real , f_imag
1803
+ floc_r , floc_i , f_real , f_imag , i_r_scale , r_scale , i_scale , f_rho
1804
+ cdef np .npy_intp i , j , n
1805
+ cdef np .broadcast it
1788
1806
1789
1807
oloc = < np .ndarray > np .PyArray_FROM_OTF (loc , np .NPY_COMPLEX128 , np .NPY_ALIGNED )
1790
1808
ogamma = < np .ndarray > np .PyArray_FROM_OTF (gamma , np .NPY_COMPLEX128 , np .NPY_ALIGNED )
@@ -1813,37 +1831,53 @@ cdef class RandomState:
1813
1831
raise ValueError ('Im(relation) ** 2 > Re(gamma ** 2 - relation** 2)' )
1814
1832
1815
1833
if size is None :
1816
- f_real , f_imag = self .standard_normal (size = 2 , method = method )
1817
-
1834
+ if method == u'zig' :
1835
+ random_gauss_zig_double_fill (& self .rng_state , 1 , & f_real )
1836
+ random_gauss_zig_double_fill (& self .rng_state , 1 , & f_imag )
1837
+ else :
1838
+ random_gauss_fill (& self .rng_state , 1 , & f_real )
1839
+ random_gauss_fill (& self .rng_state , 1 , & f_imag )
1840
+
1818
1841
f_imag *= sqrt (1 - f_rho * f_rho )
1819
1842
f_imag += f_rho * f_real
1820
1843
f_real *= sqrt (0.5 * f_v_real )
1821
1844
f_imag *= sqrt (0.5 * f_v_imag )
1822
1845
1823
- return PyComplex_FromDoubles (f_real , f_imag )
1846
+ return PyComplex_FromDoubles (floc_r + f_real , floc_i + f_imag )
1824
1847
1825
- if np .PyArray_IsAnyScalar (size ):
1826
- size = (size ,)
1827
- else :
1828
- size = tuple (size )
1848
+ randoms = < np .ndarray > np .empty (size , np .complex128 )
1849
+ randoms_data = < double * > np .PyArray_DATA (randoms )
1850
+ n = np .PyArray_SIZE (randoms )
1829
1851
1830
- norms = self .standard_normal (size = size + (2 ,), method = method )
1831
- real = norms [...,0 ]
1832
- imag = norms [...,1 ]
1852
+ i_r_scale = sqrt (1 - f_rho * f_rho )
1853
+ r_scale = sqrt (0.5 * f_v_real )
1854
+ i_scale = sqrt (0.5 * f_v_imag )
1855
+ j = 0
1856
+ with self .lock , nogil :
1857
+ if method == u'zig' :
1858
+ for i in range (n ):
1859
+ random_gauss_zig_double_fill (& self .rng_state , 1 , & f_real )
1860
+ random_gauss_zig_double_fill (& self .rng_state , 1 , & f_imag )
1861
+ randoms_data [j + 1 ] = floc_i + i_scale * (f_rho * f_real + i_r_scale * f_imag )
1862
+ randoms_data [j ] = floc_r + r_scale * f_real
1863
+ j += 2
1864
+ else :
1865
+ for i in range (n ):
1866
+ random_gauss_fill (& self .rng_state , 1 , & f_real )
1867
+ random_gauss_fill (& self .rng_state , 1 , & f_imag )
1868
+ randoms_data [j + 1 ] = floc_i + i_scale * (f_rho * f_real + i_r_scale * f_imag )
1869
+ randoms_data [j ] = floc_r + r_scale * f_real
1870
+ j += 2
1833
1871
1834
- imag *= sqrt (1 - f_rho * f_rho )
1835
- imag += f_rho * real
1836
- real *= sqrt (0.5 * f_v_real )
1837
- imag *= sqrt (0.5 * f_v_imag )
1838
1872
1839
- return floc_r + real + ( floc_i + imag ) * ( 0 + 1.0j )
1873
+ return randoms
1840
1874
1841
1875
gpc = ogamma + orelation
1842
1876
gmc = ogamma - orelation
1843
- v_real = 0.5 * np .real (gpc )
1877
+ v_real = < np . ndarray > ( 0.5 * np .real (gpc ) )
1844
1878
if np .any (np .less (v_real , 0 )):
1845
1879
raise ValueError ('Re(gamma + relation) < 0' )
1846
- v_imag = 0.5 * np .real (gmc )
1880
+ v_imag = < np . ndarray > ( 0.5 * np .real (gmc ) )
1847
1881
if np .any (np .less (v_imag , 0 )):
1848
1882
raise ValueError ('Re(gamma - relation) < 0' )
1849
1883
if np .any (np .not_equal (np .imag (ogamma ), 0 )):
@@ -1856,23 +1890,34 @@ cdef class RandomState:
1856
1890
if np .any (cov .flat [~ idx ] != 0 ) or np .any (np .abs (rho ) > 1 ):
1857
1891
raise ValueError ('Im(relation) ** 2 > Re(gamma ** 2 - relation ** 2)' )
1858
1892
1859
- if size is None :
1860
- size = np .broadcast (loc , gpc ).shape
1861
- elif np .PyArray_IsAnyScalar (size ):
1862
- size = (size ,)
1893
+ if size is not None :
1894
+ randoms = < np .ndarray > np .empty (size , np .complex128 )
1863
1895
else :
1864
- size = tuple (size )
1896
+ it = np .PyArray_MultiIterNew4 (oloc , v_real , v_imag , rho )
1897
+ randoms = < np .ndarray > np .empty (it .shape , np .complex128 )
1865
1898
1866
- norms = self .standard_normal (size + (2 ,), method = method )
1867
- real = norms [...,0 ]
1868
- imag = norms [...,1 ]
1899
+ randoms_data = < double * > np .PyArray_DATA (randoms )
1900
+ n = np .PyArray_SIZE (randoms )
1869
1901
1870
- imag *= np .sqrt (1 - rho ** 2 )
1871
- imag += rho * real
1872
- real *= np .sqrt (v_real )
1873
- imag *= np .sqrt (v_imag )
1874
-
1875
- return oloc + real + (0 + 1.0j ) * imag
1902
+ it = np .PyArray_MultiIterNew5 (randoms , oloc , v_real , v_imag , rho )
1903
+ with self .lock , nogil :
1904
+ if method == u'zig' :
1905
+ random_gauss_zig_double_fill (& self .rng_state , 2 * n , randoms_data )
1906
+ else :
1907
+ random_gauss_fill (& self .rng_state , 2 * n , randoms_data )
1908
+ with nogil :
1909
+ j = 0
1910
+ for i in range (n ):
1911
+ floc_r = (< double * > np .PyArray_MultiIter_DATA (it , 1 ))[0 ]
1912
+ floc_i = (< double * > np .PyArray_MultiIter_DATA (it , 1 ))[1 ]
1913
+ f_v_real = (< double * > np .PyArray_MultiIter_DATA (it , 2 ))[0 ]
1914
+ f_v_imag = (< double * > np .PyArray_MultiIter_DATA (it , 3 ))[0 ]
1915
+ f_rho = (< double * > np .PyArray_MultiIter_DATA (it , 4 ))[0 ]
1916
+ compute_complex (& randoms_data [j ], & randoms_data [j + 1 ], floc_r , floc_i , f_v_real , f_v_imag , f_rho )
1917
+ j += 2
1918
+ np .PyArray_MultiIter_NEXT (it )
1919
+
1920
+ return randoms
1876
1921
1877
1922
def beta (self , a , b , size = None ):
1878
1923
"""
0 commit comments