or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-gp.mdgp-operations.mdindex.mdlazy.mdmeasure.mdmulti-output.mdobservations.mdrandom.md

measure.mddocs/

0

# Measure and Model Management

1

2

Advanced model organization using measures to manage collections of Gaussian processes. Measures provide centralized management of GP relationships, naming, conditioning operations, and sampling across multiple processes simultaneously.

3

4

## Capabilities

5

6

### Measure Construction and Management

7

8

Create and manage measures that serve as containers for collections of related Gaussian processes with shared operations and naming.

9

10

```python { .api }

11

class Measure:

12

def __init__(self):

13

"""Initialize a new measure."""

14

15

ps: List[GP] # List of processes in the measure

16

means: LazyVector # Lazy vector of mean functions

17

kernels: LazyMatrix # Lazy matrix of kernel functions

18

default: ClassVar[Optional[Measure]] # Global default measure

19

```

20

21

### Context Management

22

23

Use measures as context managers to temporarily set default measure for GP construction within a scope.

24

25

```python { .api }

26

class Measure:

27

def __enter__(self) -> Measure:

28

"""Enter context manager, setting as default measure."""

29

30

def __exit__(self, exc_type, exc_val, exc_tb):

31

"""Exit context manager, restoring previous default."""

32

```

33

34

### GP Naming and Identification

35

36

Manage GP names and retrieve GPs by name or names by GP for better organization and debugging.

37

38

```python { .api }

39

class Measure:

40

def __getitem__(self, key):

41

"""

42

Get GP by name or get name by GP.

43

44

Parameters:

45

- key: GP name (str) or GP object

46

47

Returns:

48

- GP or str: GP object if key is name, name if key is GP

49

"""

50

51

def name(self, p, name):

52

"""

53

Assign name to a GP.

54

55

Parameters:

56

- p: Gaussian process to name

57

- name: Name to assign

58

"""

59

```

60

61

### GP Construction and Management

62

63

Add new Gaussian processes to the measure with specified means and kernels, or manage existing processes.

64

65

```python { .api }

66

class Measure:

67

def add_independent_gp(self, p, mean, kernel):

68

"""

69

Add independent GP to the measure.

70

71

Parameters:

72

- p: GP object to add

73

- mean: Mean function for the GP

74

- kernel: Kernel function for the GP

75

"""

76

77

def add_gp(self, mean, kernel, left_rule, right_rule=None):

78

"""

79

Add GP with custom kernel rules.

80

81

Parameters:

82

- mean: Mean function

83

- kernel: Kernel function

84

- left_rule: Left kernel rule

85

- right_rule: Optional right kernel rule

86

87

Returns:

88

- GP: The added process

89

"""

90

91

def __call__(self, p):

92

"""

93

Apply measure to GP or FDD.

94

95

Parameters:

96

- p: GP or FDD to apply measure to

97

98

Returns:

99

- Applied measure result

100

"""

101

```

102

103

### GP Operations Within Measures

104

105

Perform operations between GPs within the same measure, including summation, multiplication, and transformations.

106

107

```python { .api }

108

class Measure:

109

def sum(self, p_sum, p1, p2):

110

"""

111

Perform sum operation between two GPs.

112

113

Parameters:

114

- p_sum: Resulting sum GP

115

- p1: First GP operand

116

- p2: Second GP operand

117

"""

118

119

def mul(self, p_mul, p1, p2):

120

"""

121

Perform multiplication between two GPs.

122

123

Parameters:

124

- p_mul: Resulting product GP

125

- p1: First GP operand

126

- p2: Second GP operand

127

"""

128

129

def shift(self, p_shifted, p, shift):

130

"""

131

Shift GP inputs.

132

133

Parameters:

134

- p_shifted: Resulting shifted GP

135

- p: Source GP

136

- shift: Shift amount

137

"""

138

139

def stretch(self, p_stretched, p, stretch):

140

"""

141

Stretch GP inputs.

142

143

Parameters:

144

- p_stretched: Resulting stretched GP

145

- p: Source GP

146

- stretch: Stretch factor

147

"""

148

149

def select(self, p_selected, p, *dims):

150

"""

151

Select dimensions from GP.

152

153

Parameters:

154

- p_selected: Resulting GP

155

- p: Source GP

156

- *dims: Dimensions to select

157

"""

158

159

def transform(self, p_transformed, p, f):

160

"""

161

Transform GP inputs.

162

163

Parameters:

164

- p_transformed: Resulting transformed GP

165

- p: Source GP

166

- f: Transformation function

167

"""

168

169

def diff(self, p_diff, p, dim=0):

170

"""

171

Differentiate GP.

172

173

Parameters:

174

- p_diff: Resulting derivative GP

175

- p: Source GP

176

- dim: Dimension to differentiate

177

"""

178

179

def cross(self, p_cross, *ps):

180

"""

181

Create cross product of GPs.

182

183

Parameters:

184

- p_cross: Resulting cross product GP

185

- *ps: GPs to combine

186

"""

187

```

188

189

### Conditioning Operations

190

191

Condition the entire measure on observations, creating posterior measures with updated beliefs across all processes.

192

193

```python { .api }

194

class Measure:

195

def condition(self, obs):

196

"""

197

Condition measure on observations.

198

199

Parameters:

200

- obs: Observations object

201

202

Returns:

203

- Measure: Posterior measure

204

"""

205

206

def __or__(self, *args):

207

"""Shorthand for condition() using | operator."""

208

```

209

210

### Sampling Operations

211

212

Sample from multiple processes simultaneously, maintaining correlations and relationships between processes within the measure.

213

214

```python { .api }

215

class Measure:

216

def sample(self, state, n, *fdds):

217

"""

218

Sample from multiple processes with random state.

219

220

Parameters:

221

- state: Random state for sampling

222

- n: Number of samples

223

- *fdds: FDDs to sample from

224

225

Returns:

226

- Tuple: (new_state, samples)

227

"""

228

229

def sample(self, n, *fdds):

230

"""

231

Sample from multiple processes without explicit state.

232

233

Parameters:

234

- n: Number of samples

235

- *fdds: FDDs to sample from

236

237

Returns:

238

- Samples from the processes

239

"""

240

241

def sample(self, *fdds):

242

"""

243

Sample single realization from processes.

244

245

Parameters:

246

- *fdds: FDDs to sample from

247

248

Returns:

249

- Single sample from the processes

250

"""

251

```

252

253

### Probability Computations

254

255

Compute log probability densities for observations under the measure, useful for model comparison and hyperparameter optimization.

256

257

```python { .api }

258

class Measure:

259

def logpdf(self, *pairs):

260

"""

261

Compute log probability density for observation pairs.

262

263

Parameters:

264

- *pairs: (FDD, values) pairs

265

266

Returns:

267

- Log probability density

268

"""

269

270

def logpdf(self, obs):

271

"""

272

Compute log probability density for observations.

273

274

Parameters:

275

- obs: Observations object

276

277

Returns:

278

- Log probability density

279

"""

280

```

281

282

## Usage Examples

283

284

### Basic Measure Usage

285

286

```python

287

import stheno

288

import numpy as np

289

290

# Create measure

291

measure = stheno.Measure()

292

293

# Use as context manager

294

with measure:

295

gp1 = stheno.GP(kernel=stheno.EQ(), name="signal")

296

gp2 = stheno.GP(kernel=stheno.Matern52(), name="noise")

297

298

# Access GPs by name

299

signal_gp = measure["signal"]

300

noise_gp = measure["noise"]

301

302

print(f"Signal GP: {measure[signal_gp]}") # Get name from GP

303

```

304

305

### Managing Multiple Related Processes

306

307

```python

308

# Create measure for climate model

309

climate = stheno.Measure()

310

311

with climate:

312

# Temperature process

313

temp = stheno.GP(

314

kernel=stheno.EQ().stretch(2.0) * stheno.Matern52().stretch(0.5),

315

name="temperature"

316

)

317

318

# Humidity correlated with temperature

319

humidity = 0.8 * temp + stheno.GP(kernel=stheno.EQ(), name="humidity_residual")

320

climate.name(humidity, "humidity")

321

322

# Pressure with seasonal component

323

pressure = stheno.GP(kernel=stheno.EQ().stretch(10.0), name="pressure")

324

325

# Work with the model

326

x = np.linspace(0, 365, 100) # Days in year

327

temp_fdd = temp(x)

328

humidity_fdd = humidity(x)

329

pressure_fdd = pressure(x)

330

```

331

332

### Conditioning Entire Measures

333

334

```python

335

# Generate observations

336

temp_obs = temp_fdd.sample()

337

humidity_obs = humidity_fdd.sample()

338

339

# Condition entire measure on all observations

340

posterior_climate = climate.condition(

341

stheno.Observations(temp_fdd, temp_obs),

342

stheno.Observations(humidity_fdd, humidity_obs)

343

)

344

345

# All processes now conditioned

346

posterior_temp = posterior_climate["temperature"]

347

posterior_humidity = posterior_climate["humidity"]

348

posterior_pressure = posterior_climate["pressure"]

349

```

350

351

### Multi-Process Sampling

352

353

```python

354

# Sample from multiple processes simultaneously

355

x_pred = np.linspace(0, 365, 50)

356

357

# Individual FDDs

358

temp_pred = posterior_temp(x_pred)

359

humidity_pred = posterior_humidity(x_pred)

360

pressure_pred = posterior_pressure(x_pred)

361

362

# Joint sampling maintains correlations

363

samples = climate.sample(5, temp_pred, humidity_pred, pressure_pred)

364

365

# Access individual process samples

366

temp_samples = samples[0] # First process samples

367

humidity_samples = samples[1] # Second process samples

368

pressure_samples = samples[2] # Third process samples

369

```

370

371

### Model Comparison with LogPDF

372

373

```python

374

# Create competing models

375

model1 = stheno.Measure()

376

model2 = stheno.Measure()

377

378

with model1:

379

gp1 = stheno.GP(kernel=stheno.EQ())

380

381

with model2:

382

gp2 = stheno.GP(kernel=stheno.Matern52())

383

384

# Test data

385

x_test = np.linspace(0, 1, 20)

386

y_test = np.sin(x_test) + 0.1 * np.random.randn(len(x_test))

387

388

# Compute log marginal likelihoods

389

fdd1 = gp1(x_test, noise=0.1)

390

fdd2 = gp2(x_test, noise=0.1)

391

392

logpdf1 = model1.logpdf(fdd1, y_test)

393

logpdf2 = model2.logpdf(fdd2, y_test)

394

395

print(f"Model 1 log likelihood: {logpdf1}")

396

print(f"Model 2 log likelihood: {logpdf2}")

397

print(f"Model {'1' if logpdf1 > logpdf2 else '2'} is preferred")

398

```

399

400

### Advanced Measure Operations

401

402

```python

403

# Create measure with custom operations

404

advanced_measure = stheno.Measure()

405

406

# Manually add GPs with custom kernel relationships

407

gp_base = stheno.GP()

408

gp_derived = stheno.GP()

409

410

# Add to measure with custom rules

411

advanced_measure.add_independent_gp(gp_base, stheno.ZeroMean(), stheno.EQ())

412

413

# Create derived process through measure operations

414

advanced_measure.sum(gp_derived, gp_base, gp_base) # gp_derived = 2 * gp_base

415

416

# Use derived relationships

417

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

418

base_samples = gp_base(x).sample()

419

derived_samples = gp_derived(x).sample()

420

421

print(f"Derived should be ~2x base: {np.allclose(derived_samples, 2 * base_samples)}")

422

```