or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

algorithm-primitives.mdarray-operations.mdcore-opencl.mdindex.mdmathematical-functions.mdmemory-management.mdopengl-interop.mdrandom-number-generation.mdtools-and-utilities.md

random-number-generation.mddocs/

0

# Random Number Generation

1

2

High-quality parallel random number generation using cryptographically secure algorithms (Philox, Threefry) suitable for Monte Carlo simulations, stochastic computations, and statistical sampling with excellent statistical properties and performance.

3

4

## Capabilities

5

6

### Random Number Generators

7

8

Cryptographically secure parallel random number generators based on counter-based algorithms.

9

10

```python { .api }

11

class Random123GeneratorBase:

12

"""

13

Base class for Random123 family generators (Philox, Threefry).

14

15

Attributes:

16

- context (Context): OpenCL context

17

- dtype: Output data type

18

"""

19

20

class PhiloxGenerator(Random123GeneratorBase):

21

"""

22

Philox random number generator with excellent statistical properties.

23

24

The Philox generator uses a Feistel-like cipher structure and provides

25

high-quality random numbers suitable for parallel Monte Carlo simulations.

26

"""

27

28

def __init__(self, context, dtype=np.float32):

29

"""

30

Create Philox random number generator.

31

32

Parameters:

33

- context (Context): OpenCL context

34

- dtype: Output data type (float32, float64, int32, int64)

35

"""

36

37

def fill_uniform(self, queue, ary, luxury=None):

38

"""

39

Fill array with uniform random numbers in [0, 1).

40

41

Parameters:

42

- queue (CommandQueue): Command queue

43

- ary (Array): Target array to fill

44

- luxury (int, optional): Quality level (higher = better quality)

45

"""

46

47

def uniform(self, queue, shape, dtype=None, luxury=None):

48

"""

49

Generate uniform random array.

50

51

Parameters:

52

- queue (CommandQueue): Command queue

53

- shape (tuple[int, ...]): Array shape

54

- dtype: Data type (uses generator default if None)

55

- luxury (int, optional): Quality level

56

57

Returns:

58

Array: Array of uniform random numbers in [0, 1)

59

"""

60

61

class ThreefryGenerator(Random123GeneratorBase):

62

"""

63

Threefry random number generator based on the Threefish cipher.

64

65

The Threefry generator provides high-quality random numbers with

66

strong cryptographic properties and excellent parallel performance.

67

"""

68

69

def __init__(self, context, dtype=np.float32):

70

"""

71

Create Threefry random number generator.

72

73

Parameters:

74

- context (Context): OpenCL context

75

- dtype: Output data type

76

"""

77

78

def fill_uniform(self, queue, ary, luxury=None):

79

"""

80

Fill array with uniform random numbers in [0, 1).

81

82

Parameters:

83

- queue (CommandQueue): Command queue

84

- ary (Array): Target array to fill

85

- luxury (int, optional): Quality level

86

"""

87

88

def uniform(self, queue, shape, dtype=None, luxury=None):

89

"""

90

Generate uniform random array.

91

92

Parameters:

93

- queue (CommandQueue): Command queue

94

- shape (tuple[int, ...]): Array shape

95

- dtype: Data type

96

- luxury (int, optional): Quality level

97

98

Returns:

99

Array: Array of uniform random numbers in [0, 1)

100

"""

101

```

102

103

### High-level Random Functions

104

105

Convenient functions for generating random arrays with various distributions.

106

107

```python { .api }

108

def rand(queue, shape, dtype=float, luxury=None, generator=None):

109

"""

110

Generate uniform random array in [0, 1).

111

112

Parameters:

113

- queue (CommandQueue): Command queue

114

- shape (int | tuple[int, ...]): Array shape

115

- dtype: Data type (float32, float64)

116

- luxury (int, optional): Quality level for generator

117

- generator (Random123GeneratorBase, optional): Specific generator to use

118

119

Returns:

120

Array: Array of uniform random numbers

121

"""

122

123

def fill_rand(result, queue=None, luxury=None, generator=None):

124

"""

125

Fill existing array with uniform random numbers.

126

127

Parameters:

128

- result (Array): Target array to fill

129

- queue (CommandQueue, optional): Command queue

130

- luxury (int, optional): Quality level

131

- generator (Random123GeneratorBase, optional): Specific generator to use

132

"""

133

```

134

135

## Usage Examples

136

137

### Basic Random Number Generation

138

139

```python

140

import pyopencl as cl

141

import pyopencl.array as cl_array

142

from pyopencl.clrandom import PhiloxGenerator, ThreefryGenerator

143

import pyopencl.clrandom as clrand

144

import numpy as np

145

146

# Setup

147

ctx = cl.create_some_context()

148

queue = cl.CommandQueue(ctx)

149

150

# Generate uniform random numbers using convenience function

151

uniform_data = clrand.rand(queue, (10000,), dtype=np.float32)

152

print(f"Random data shape: {uniform_data.shape}")

153

print(f"Random samples: {uniform_data.get()[:5]}")

154

print(f"Range: [{uniform_data.get().min():.3f}, {uniform_data.get().max():.3f}]")

155

156

# Fill existing array with random data

157

existing_array = cl_array.empty(queue, (5000,), dtype=np.float32)

158

clrand.fill_rand(existing_array, queue)

159

print(f"Filled array samples: {existing_array.get()[:5]}")

160

```

161

162

### Using Specific Generators

163

164

```python

165

import pyopencl as cl

166

import pyopencl.array as cl_array

167

from pyopencl.clrandom import PhiloxGenerator, ThreefryGenerator

168

import numpy as np

169

170

# Setup

171

ctx = cl.create_some_context()

172

queue = cl.CommandQueue(ctx)

173

174

# Create Philox generator

175

philox_gen = PhiloxGenerator(ctx, dtype=np.float32)

176

177

# Generate random array

178

philox_data = philox_gen.uniform(queue, (10000,))

179

print(f"Philox generator data: {philox_data.get()[:5]}")

180

181

# Create Threefry generator

182

threefry_gen = ThreefryGenerator(ctx, dtype=np.float32)

183

184

# Generate random array

185

threefry_data = threefry_gen.uniform(queue, (10000,))

186

print(f"Threefry generator data: {threefry_data.get()[:5]}")

187

188

# Fill existing array

189

target_array = cl_array.empty(queue, (8000,), dtype=np.float32)

190

philox_gen.fill_uniform(queue, target_array)

191

print(f"Filled with Philox: {target_array.get()[:5]}")

192

```

193

194

### Monte Carlo Simulation Example

195

196

```python

197

import pyopencl as cl

198

import pyopencl.array as cl_array

199

from pyopencl.clrandom import PhiloxGenerator

200

from pyopencl.elementwise import ElementwiseKernel

201

import numpy as np

202

203

# Setup

204

ctx = cl.create_some_context()

205

queue = cl.CommandQueue(ctx)

206

207

# Monte Carlo estimation of π using random points in unit square

208

n_samples = 1000000

209

210

# Create generator

211

generator = PhiloxGenerator(ctx, dtype=np.float32)

212

213

# Generate random points

214

x_coords = generator.uniform(queue, (n_samples,))

215

y_coords = generator.uniform(queue, (n_samples,))

216

217

# Create kernel to check if points are inside unit circle

218

inside_circle_kernel = ElementwiseKernel(ctx,

219

"__global float *x, __global float *y, __global int *inside",

220

"inside[i] = (x[i]*x[i] + y[i]*y[i] <= 1.0f) ? 1 : 0",

221

"check_inside_circle")

222

223

# Count points inside circle

224

inside_flags = cl_array.empty(queue, (n_samples,), dtype=np.int32)

225

inside_circle_kernel(x_coords, y_coords, inside_flags)

226

227

# Estimate π

228

points_inside = cl_array.sum(inside_flags).get()

229

pi_estimate = 4.0 * points_inside / n_samples

230

231

print(f"Samples: {n_samples}")

232

print(f"Points inside circle: {points_inside}")

233

print(f"π estimate: {pi_estimate}")

234

print(f"Error: {abs(pi_estimate - np.pi):.6f}")

235

```

236

237

### Statistical Quality Testing

238

239

```python

240

import pyopencl as cl

241

import pyopencl.array as cl_array

242

from pyopencl.clrandom import PhiloxGenerator, ThreefryGenerator

243

import numpy as np

244

import matplotlib.pyplot as plt

245

246

# Setup

247

ctx = cl.create_some_context()

248

queue = cl.CommandQueue(ctx)

249

250

# Generate large sample for statistical testing

251

n_samples = 100000

252

253

# Test both generators

254

philox_gen = PhiloxGenerator(ctx, dtype=np.float32)

255

threefry_gen = ThreefryGenerator(ctx, dtype=np.float32)

256

257

philox_data = philox_gen.uniform(queue, (n_samples,)).get()

258

threefry_data = threefry_gen.uniform(queue, (n_samples,)).get()

259

260

# Statistical tests

261

print("Statistical Analysis:")

262

print(f"Philox - Mean: {np.mean(philox_data):.6f} (expected: 0.5)")

263

print(f"Philox - Std: {np.std(philox_data):.6f} (expected: {1/np.sqrt(12):.6f})")

264

print(f"Threefry - Mean: {np.mean(threefry_data):.6f}")

265

print(f"Threefry - Std: {np.std(threefry_data):.6f}")

266

267

# Histogram comparison

268

bins = np.linspace(0, 1, 50)

269

philox_hist, _ = np.histogram(philox_data, bins)

270

threefry_hist, _ = np.histogram(threefry_data, bins)

271

272

print(f"Philox histogram uniformity (chi-square): {np.var(philox_hist):.2f}")

273

print(f"Threefry histogram uniformity (chi-square): {np.var(threefry_hist):.2f}")

274

```

275

276

### Generating Different Random Distributions

277

278

```python

279

import pyopencl as cl

280

import pyopencl.array as cl_array

281

from pyopencl.clrandom import PhiloxGenerator

282

from pyopencl.elementwise import ElementwiseKernel

283

import pyopencl.clmath as clmath

284

import numpy as np

285

286

# Setup

287

ctx = cl.create_some_context()

288

queue = cl.CommandQueue(ctx)

289

generator = PhiloxGenerator(ctx, dtype=np.float32)

290

291

# Generate uniform random numbers as base

292

uniform1 = generator.uniform(queue, (10000,))

293

uniform2 = generator.uniform(queue, (10000,))

294

295

# Box-Muller transform for normal distribution

296

normal_kernel = ElementwiseKernel(ctx,

297

"__global float *u1, __global float *u2, __global float *n1, __global float *n2",

298

"""

299

float r = sqrt(-2.0f * log(u1[i]));

300

float theta = 2.0f * M_PI * u2[i];

301

n1[i] = r * cos(theta);

302

n2[i] = r * sin(theta);

303

""",

304

"box_muller_transform")

305

306

normal1 = cl_array.empty_like(uniform1)

307

normal2 = cl_array.empty_like(uniform2)

308

normal_kernel(uniform1, uniform2, normal1, normal2)

309

310

print(f"Normal distribution samples: {normal1.get()[:5]}")

311

print(f"Normal mean: {cl_array.sum(normal1).get() / normal1.size:.6f}")

312

313

# Exponential distribution: -log(1-u)

314

exponential = -clmath.log(1.0 - uniform1)

315

print(f"Exponential samples: {exponential.get()[:5]}")

316

317

# Integer random numbers in range [0, max_val)

318

max_val = 100

319

uniform_int_base = generator.uniform(queue, (10000,))

320

int_kernel = ElementwiseKernel(ctx,

321

"__global float *u, __global int *result, int max_val",

322

"result[i] = (int)(u[i] * max_val)",

323

"uniform_int")

324

325

random_ints = cl_array.empty(queue, (10000,), dtype=np.int32)

326

int_kernel(uniform_int_base, random_ints, np.int32(max_val))

327

print(f"Random integers [0, {max_val}): {random_ints.get()[:10]}")

328

```

329

330

### Performance Comparison

331

332

```python

333

import pyopencl as cl

334

import pyopencl.array as cl_array

335

from pyopencl.clrandom import PhiloxGenerator, ThreefryGenerator

336

import numpy as np

337

import time

338

339

# Setup

340

ctx = cl.create_some_context()

341

queue = cl.CommandQueue(ctx)

342

343

# Large array for performance testing

344

n_samples = 10000000

345

n_iterations = 5

346

347

# Test Philox generator

348

philox_gen = PhiloxGenerator(ctx, dtype=np.float32)

349

philox_times = []

350

351

for i in range(n_iterations):

352

start_time = time.time()

353

data = philox_gen.uniform(queue, (n_samples,))

354

queue.finish()

355

end_time = time.time()

356

philox_times.append(end_time - start_time)

357

358

# Test Threefry generator

359

threefry_gen = ThreefryGenerator(ctx, dtype=np.float32)

360

threefry_times = []

361

362

for i in range(n_iterations):

363

start_time = time.time()

364

data = threefry_gen.uniform(queue, (n_samples,))

365

queue.finish()

366

end_time = time.time()

367

threefry_times.append(end_time - start_time)

368

369

# Compare with NumPy

370

numpy_times = []

371

for i in range(n_iterations):

372

start_time = time.time()

373

data = np.random.random(n_samples).astype(np.float32)

374

end_time = time.time()

375

numpy_times.append(end_time - start_time)

376

377

print(f"Performance Comparison ({n_samples:,} samples):")

378

print(f"Philox (GPU): {np.mean(philox_times):.4f}s ± {np.std(philox_times):.4f}s")

379

print(f"Threefry (GPU): {np.mean(threefry_times):.4f}s ± {np.std(threefry_times):.4f}s")

380

print(f"NumPy (CPU): {np.mean(numpy_times):.4f}s ± {np.std(numpy_times):.4f}s")

381

382

# Throughput

383

philox_throughput = n_samples / np.mean(philox_times) / 1e6

384

threefry_throughput = n_samples / np.mean(threefry_times) / 1e6

385

numpy_throughput = n_samples / np.mean(numpy_times) / 1e6

386

387

print(f"Throughput (Million samples/sec):")

388

print(f"Philox: {philox_throughput:.1f}")

389

print(f"Threefry: {threefry_throughput:.1f}")

390

print(f"NumPy: {numpy_throughput:.1f}")

391

```

392

393

## Generator Properties

394

395

### Quality Levels (Luxury)

396

397

The `luxury` parameter controls the quality vs. speed tradeoff:

398

399

- **luxury=None** (default): Standard quality, good for most applications

400

- **luxury=1**: Higher quality, slightly slower generation

401

- **luxury=2**: Highest quality, best statistical properties

402

403

Higher luxury levels provide better statistical properties but may reduce performance.

404

405

### Statistical Properties

406

407

Both Philox and Threefry generators provide:

408

- Period: 2^128 or larger

409

- Excellent statistical properties (pass BigCrush tests)

410

- Strong cryptographic properties

411

- Parallel generation without correlation

412

- Reproducible sequences with same seeds

413

414

### Memory Usage

415

416

Random number generation is memory-efficient:

417

- Generators store minimal state

418

- Memory usage scales with output array size

419

- No significant memory overhead compared to computation arrays