or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-optimization.mdconfiguration.mdconstraints-boundaries.mdcore-optimization.mdfitness-functions.mdindex.mdlogging-analysis.mdsamplers-adaptation.md

logging-analysis.mddocs/

0

# Logging and Analysis

1

2

Comprehensive data collection, visualization, and analysis tools for monitoring and understanding CMA-ES optimization behavior and performance.

3

4

## Data Logging with CMADataLogger

5

6

The CMADataLogger class provides comprehensive data collection during optimization with automatic file management and data persistence.

7

8

## Core Logging Functions

9

10

```python { .api }

11

# Main logging and plotting functions available in cma module

12

import cma

13

14

def disp(iteration=None):

15

"""

16

Display current optimization state and progress.

17

18

Parameters:

19

-----------

20

iteration : int, optional

21

Iteration number to display (default: current).

22

"""

23

pass

24

25

def plot(name_prefix='outcmaes', **kwargs):

26

"""

27

Plot CMA-ES data from logged files.

28

29

Parameters:

30

-----------

31

name_prefix : str, optional

32

File prefix for data files to plot (default 'outcmaes').

33

**kwargs : dict

34

Additional plotting options.

35

"""

36

pass

37

38

def plot_zip(name_prefix='outcmaes', **kwargs):

39

"""

40

Plot multiple CMA-ES runs from zipped data files.

41

42

Parameters:

43

-----------

44

name_prefix : str, optional

45

File prefix pattern for multiple runs.

46

"""

47

pass

48

```

49

50

### CMADataLogger Class

51

52

```python { .api }

53

class CMADataLogger:

54

"""

55

Data logger for CMAEvolutionStrategy with automatic file management.

56

57

Logs optimization data to files and provides loading, visualization,

58

and analysis capabilities. Data is written to disk in real-time and

59

can be reloaded for post-processing and analysis.

60

"""

61

62

default_prefix = 'outcmaes/' # Default file prefix

63

64

def __init__(self, name_prefix=None, modulo=1, append=False, expensive_modulo=1):

65

"""

66

Initialize CMA-ES data logger.

67

68

Parameters:

69

-----------

70

name_prefix : str, optional

71

File name prefix for all data files. If None, uses default 'outcmaes/'.

72

Can be a directory path ending with '/' for organized storage.

73

74

modulo : int, optional

75

Log data every modulo iterations (default 1 = every iteration).

76

77

append : bool, optional

78

Whether to append to existing files (default False = overwrite).

79

80

expensive_modulo : int, optional

81

Frequency for expensive operations like eigendecomposition logging

82

(default 1). Set higher for large dimensions to reduce overhead.

83

84

Examples:

85

---------

86

>>> import cma

87

>>>

88

>>> # Basic logging

89

>>> logger = cma.CMADataLogger()

90

>>> es = cma.CMAEvolutionStrategy([0, 0, 0], 0.5)

91

>>> logger.register(es) # Connect logger to optimizer

92

>>>

93

>>> while not es.stop():

94

... solutions = es.ask()

95

... fitness_values = [sum(x**2) for x in solutions]

96

... es.tell(solutions, fitness_values)

97

... logger.add() # Log current state

98

>>>

99

>>> # Custom file prefix

100

>>> logger = cma.CMADataLogger('my_experiment/run_001')

101

>>>

102

>>> # Reduced logging frequency for large problems

103

>>> logger = cma.CMADataLogger(modulo=10, expensive_modulo=50)

104

"""

105

pass

106

107

def register(self, es, append=None, modulo=None):

108

"""

109

Register evolution strategy for automatic logging.

110

111

Parameters:

112

-----------

113

es : CMAEvolutionStrategy

114

Evolution strategy instance to log.

115

116

append : bool, optional

117

Override constructor append setting.

118

119

modulo : int, optional

120

Override constructor modulo setting.

121

122

Returns:

123

--------

124

CMADataLogger

125

Self for method chaining.

126

127

Examples:

128

---------

129

>>> import cma

130

>>>

131

>>> es = cma.CMAEvolutionStrategy([0, 0, 0], 0.5)

132

>>> logger = cma.CMADataLogger().register(es)

133

>>>

134

>>> # Method chaining

135

>>> logger = cma.CMADataLogger('experiment1/').register(es, modulo=5)

136

"""

137

pass

138

139

def add(self, es=None, more_data=[], modulo=None):

140

"""

141

Add current evolution strategy state to log.

142

143

Parameters:

144

-----------

145

es : CMAEvolutionStrategy, optional

146

Evolution strategy to log. If None, uses registered ES.

147

148

more_data : list, optional

149

Additional data columns to append to fit file.

150

151

modulo : int, optional

152

Override default logging frequency.

153

154

Examples:

155

---------

156

>>> import cma

157

>>>

158

>>> es = cma.CMAEvolutionStrategy([0, 0, 0], 0.5)

159

>>> logger = cma.CMADataLogger().register(es)

160

>>>

161

>>> while not es.stop():

162

... solutions = es.ask()

163

... fitness_values = [sum(x**2) for x in solutions]

164

... es.tell(solutions, fitness_values)

165

...

166

... # Log with additional data

167

... custom_metric = es.sigma * es.result.evaluations

168

... logger.add(more_data=[custom_metric])

169

"""

170

pass

171

172

def load(self, filenameprefix=None):

173

"""

174

Load logged data from files.

175

176

Parameters:

177

-----------

178

filenameprefix : str, optional

179

File prefix to load. If None, uses instance prefix.

180

181

Returns:

182

--------

183

CMADataLogger

184

Self with loaded data in attributes.

185

186

Examples:

187

---------

188

>>> import cma

189

>>>

190

>>> # Load previously logged data

191

>>> logger = cma.CMADataLogger().load()

192

>>>

193

>>> # Load specific experiment

194

>>> logger = cma.CMADataLogger().load('experiment1/run_005')

195

>>>

196

>>> # Access loaded data

197

>>> print(f"Iterations: {len(logger.f)}")

198

>>> print(f"Final fitness: {logger.f[-1, 5]}")

199

>>> print(f"Final mean: {logger.xmean[-1]}")

200

"""

201

pass

202

203

def save_to(self, filenameprefix):

204

"""

205

Save current data to different file location.

206

207

Parameters:

208

-----------

209

filenameprefix : str

210

New file prefix for saving data.

211

"""

212

pass

213

214

@property

215

def data(self):

216

"""

217

Dictionary of loaded data arrays.

218

219

Returns:

220

--------

221

dict

222

Data dictionary with keys: 'xmean', 'xrecent', 'std', 'f', 'D', 'corrspec'

223

corresponding to mean solutions, recent best, standard deviations,

224

fitness values, axis lengths, and correlation spectrum.

225

"""

226

pass

227

```

228

229

### Logged Data Structure

230

231

```python { .api }

232

# Data files and their contents

233

data_files = {

234

'fit': """

235

Fitness and evaluation data (outcmaesfit.dat):

236

Columns: [iteration, evaluations, sigma, axis_ratio, best_fitness,

237

median_fitness, worst_fitness, further_data...]

238

239

Example access:

240

>>> logger = cma.CMADataLogger().load()

241

>>> iterations = logger.f[:, 0]

242

>>> evaluations = logger.f[:, 1]

243

>>> best_fitness = logger.f[:, 4]

244

>>> median_fitness = logger.f[:, 5]

245

""",

246

247

'xmean': """

248

Mean solution evolution (outcmaesxmean.dat):

249

Columns: [iteration, evaluations, sigma, axis_ratio, mean_x1, mean_x2, ...]

250

251

Example access:

252

>>> logger = cma.CMADataLogger().load()

253

>>> mean_solutions = logger.xmean[:, 4:] # Skip iteration info

254

>>> final_mean = logger.xmean[-1, 4:] # Final mean solution

255

""",

256

257

'xrecentbest': """

258

Recent best solutions (outcmaesxrecentbest.dat):

259

Columns: [iteration, evaluations, sigma, axis_ratio, x1, x2, ...]

260

261

Example access:

262

>>> logger = cma.CMADataLogger().load()

263

>>> recent_best = logger.xrecent[:, 4:] # Recent best solutions

264

>>> best_solution = logger.xrecent[-1, 4:] # Final best solution

265

""",

266

267

'stddev': """

268

Standard deviations (outcmaesstddev.dat):

269

Columns: [iteration, evaluations, sigma, max_std/min_std, std1, std2, ...]

270

271

Example access:

272

>>> logger = cma.CMADataLogger().load()

273

>>> std_devs = logger.std[:, 4:] # Standard deviations per coordinate

274

>>> condition_estimate = logger.std[:, 3] # Max/min std ratio

275

""",

276

277

'axlen': """

278

Principal axis lengths (outcmaesaxlen.dat):

279

Columns: [iteration, evaluations, sigma, condition, len1, len2, ...]

280

Principal axes ordered by length (largest first).

281

282

Example access:

283

>>> logger = cma.CMADataLogger().load()

284

>>> axis_lengths = logger.D[:, 4:] # Principal axis lengths

285

>>> condition_numbers = logger.D[:, 3] # Condition numbers

286

""",

287

288

'axlencorr': """

289

Correlation between consecutive axis length vectors (outcmaesaxlencorr.dat):

290

Indicates stability of principal directions.

291

"""

292

}

293

294

# Example: Comprehensive data access

295

def access_logged_data_example():

296

"""Example of accessing all types of logged data."""

297

298

import cma

299

import numpy as np

300

301

# Run optimization with logging

302

es = cma.CMAEvolutionStrategy(5 * [0.5], 0.3)

303

logger = cma.CMADataLogger('example_run/').register(es)

304

305

while not es.stop():

306

solutions = es.ask()

307

fitness_values = [sum((x - np.array([1, 2, 3, 4, 5]))**2) for x in solutions]

308

es.tell(solutions, fitness_values)

309

logger.add()

310

311

if es.countiter % 50 == 0:

312

es.disp()

313

314

# Reload and analyze data

315

logger.load()

316

317

# Fitness evolution

318

iterations = logger.f[:, 0]

319

evaluations = logger.f[:, 1]

320

best_fitness = logger.f[:, 4]

321

median_fitness = logger.f[:, 5]

322

323

print(f"Optimization completed in {iterations[-1]} iterations")

324

print(f"Total evaluations: {evaluations[-1]}")

325

print(f"Final best fitness: {best_fitness[-1]:.2e}")

326

327

# Solution evolution

328

mean_evolution = logger.xmean[:, 4:]

329

final_mean = mean_evolution[-1]

330

target_solution = np.array([1, 2, 3, 4, 5])

331

332

print(f"Final mean solution: {final_mean}")

333

print(f"Distance to target: {np.linalg.norm(final_mean - target_solution):.4f}")

334

335

# Step-size and conditioning evolution

336

sigmas = logger.f[:, 2]

337

axis_ratios = logger.f[:, 3]

338

339

print(f"Initial sigma: {sigmas[0]:.4f}")

340

print(f"Final sigma: {sigmas[-1]:.4f}")

341

print(f"Final axis ratio (condition): {axis_ratios[-1]:.2e}")

342

343

# Standard deviation evolution per coordinate

344

std_evolution = logger.std[:, 4:]

345

final_stds = std_evolution[-1]

346

347

print(f"Final standard deviations: {final_stds}")

348

349

return logger

350

351

# access_logged_data_example()

352

```

353

354

## Visualization and Plotting

355

356

Comprehensive plotting capabilities for understanding optimization dynamics and diagnosing convergence issues.

357

358

### Main Plotting Functions

359

360

```python { .api }

361

def plot(filenameprefix=None, fig=None, iteridx=None, **kwargs):

362

"""

363

Plot logged CMA-ES data with comprehensive visualization.

364

365

Parameters:

366

-----------

367

filenameprefix : str, optional

368

File prefix of logged data. If None, uses default 'outcmaes'.

369

370

fig : matplotlib.figure.Figure, optional

371

Figure to plot into. If None, creates new figure.

372

373

iteridx : slice or array-like, optional

374

Iteration indices to plot (e.g., slice(100, 500) for iterations 100-500).

375

376

**kwargs : dict

377

Additional plotting options:

378

- iabscissa : int (0=iteration, 1=evaluation count for x-axis)

379

- plot_mean : bool (whether to plot mean solution evolution)

380

- foffset : float (offset for fitness values to handle zero/negative values)

381

- x_opt : array-like (known optimum for reference)

382

- fontsize : int (font size for labels)

383

- xsemilog : bool (semi-log x-axis)

384

385

Returns:

386

--------

387

matplotlib.figure.Figure

388

Figure with CMA-ES diagnostic plots.

389

390

Examples:

391

---------

392

>>> import cma

393

>>>

394

>>> # Run optimization with default logging

395

>>> x, es = cma.fmin2(cma.ff.sphere, [1, 2, 3], 0.5)

396

>>>

397

>>> # Plot results

398

>>> fig = cma.plot() # Plot data from default location

399

>>>

400

>>> # Plot specific experiment

401

>>> fig = cma.plot('my_experiment/run_001')

402

>>>

403

>>> # Plot subset of iterations

404

>>> fig = cma.plot(iteridx=slice(50, 200)) # Iterations 50-200

405

>>>

406

>>> # Plot with evaluation count on x-axis

407

>>> fig = cma.plot(iabscissa=1)

408

>>>

409

>>> # Plot with known optimum reference

410

>>> fig = cma.plot(x_opt=[0, 0, 0]) # Show distance to [0,0,0]

411

"""

412

pass

413

414

def plot_zip(filenameprefix=None, **kwargs):

415

"""

416

Plot data from compressed (.zip) CMA-ES log files.

417

418

Useful for plotting archived optimization runs without extracting files.

419

420

Parameters:

421

-----------

422

filenameprefix : str, optional

423

Prefix of zip file containing logged data.

424

425

**kwargs : dict

426

Same options as plot() function.

427

428

Examples:

429

---------

430

>>> import cma

431

>>>

432

>>> # Plot from compressed log files

433

>>> fig = cma.plot_zip('archived_runs/experiment_001.zip')

434

"""

435

pass

436

437

def disp(filenameprefix=None):

438

"""

439

Display text summary of logged CMA-ES data.

440

441

Parameters:

442

-----------

443

filenameprefix : str, optional

444

File prefix of logged data to display.

445

446

Examples:

447

---------

448

>>> import cma

449

>>>

450

>>> # Display summary of default logged data

451

>>> cma.disp()

452

>>>

453

>>> # Display specific experiment

454

>>> cma.disp('experiments/run_042')

455

"""

456

pass

457

```

458

459

### CMADataLogger Plotting Methods

460

461

```python { .api }

462

class CMADataLogger:

463

"""Extended plotting capabilities of CMADataLogger."""

464

465

def plot(self, fig=None, iabscissa=0, iteridx=None, **kwargs):

466

"""

467

Create comprehensive diagnostic plots for CMA-ES optimization.

468

469

Generates multi-panel plot showing:

470

1. Fitness evolution (best, median, worst)

471

2. Step-size (sigma) evolution

472

3. Principal axis lengths (eigenvalues of C)

473

4. Standard deviations per coordinate

474

5. Mean solution evolution (optional)

475

6. Recent best solution evolution (optional)

476

477

Parameters:

478

-----------

479

fig : matplotlib.figure.Figure, optional

480

Figure to plot into. Creates new if None.

481

482

iabscissa : int, optional

483

X-axis type: 0=iterations (default), 1=evaluation count.

484

485

iteridx : slice or array, optional

486

Iteration range to plot (e.g., slice(100, 500)).

487

488

**kwargs : dict

489

Additional options:

490

- plot_mean : bool (plot mean evolution, default False)

491

- foffset : float (fitness offset for log scale, default 1e-19)

492

- x_opt : array (known optimum for reference)

493

- fontsize : int (font size, default 7)

494

- xsemilog : bool (semi-log x-axis, default False)

495

- downsample_to : int (max points to plot, default 1e7)

496

497

Examples:

498

---------

499

>>> import cma

500

>>>

501

>>> # Run optimization

502

>>> es = cma.CMAEvolutionStrategy([1, 2, 3], 0.5)

503

>>> logger = cma.CMADataLogger().register(es)

504

>>>

505

>>> while not es.stop():

506

... solutions = es.ask()

507

... fitness_values = [sum(x**2) for x in solutions]

508

... es.tell(solutions, fitness_values)

509

... logger.add()

510

>>>

511

>>> # Create diagnostic plots

512

>>> fig = logger.plot()

513

>>>

514

>>> # Plot with custom options

515

>>> fig = logger.plot(

516

... plot_mean=True, # Show mean evolution

517

... x_opt=[0, 0, 0], # Reference optimum

518

... iabscissa=1, # X-axis: evaluation count

519

... iteridx=slice(50, None) # Skip first 50 iterations

520

... )

521

"""

522

pass

523

524

def disp(self):

525

"""

526

Display text summary of logged optimization data.

527

528

Shows:

529

- Problem dimension and optimization settings

530

- Iteration and evaluation count

531

- Best, worst, and current fitness values

532

- Convergence indicators

533

- Step-size and conditioning information

534

535

Examples:

536

---------

537

>>> logger = cma.CMADataLogger().load()

538

>>> logger.disp()

539

Loaded data from outcmaes* files

540

Dimension: 5

541

Iterations: 150

542

Evaluations: 1350

543

Best fitness: 1.23e-08

544

Final sigma: 0.0045

545

Condition number: 2.34e+03

546

"""

547

pass

548

```

549

550

### Plotting Usage Patterns

551

552

```python { .api }

553

import cma

554

import numpy as np

555

import matplotlib.pyplot as plt

556

557

# Pattern 1: Real-time plotting during optimization

558

def realtime_plotting_example():

559

"""Example of real-time plotting during optimization."""

560

561

es = cma.CMAEvolutionStrategy(5 * [0.5], 0.3, {'verb_disp': 0})

562

logger = cma.CMADataLogger().register(es)

563

564

# Create figure for real-time updates

565

plt.ion() # Interactive mode

566

fig, axes = plt.subplots(2, 2, figsize=(10, 8))

567

568

iteration = 0

569

while not es.stop() and iteration < 200:

570

solutions = es.ask()

571

fitness_values = [sum((x - 1)**2) for x in solutions]

572

es.tell(solutions, fitness_values)

573

logger.add()

574

575

# Update plots every 10 iterations

576

if iteration % 10 == 0:

577

plt.clf() # Clear figure

578

579

# Create updated diagnostic plots

580

logger.plot(fig=fig)

581

plt.draw()

582

plt.pause(0.1) # Brief pause for display

583

584

iteration += 1

585

586

plt.ioff() # Turn off interactive mode

587

plt.show()

588

589

return logger

590

591

# Pattern 2: Custom plotting with logged data

592

def custom_plotting_example():

593

"""Create custom plots using logged CMA-ES data."""

594

595

# Load logged data

596

logger = cma.CMADataLogger().load()

597

598

# Custom multi-panel plot

599

fig, axes = plt.subplots(3, 2, figsize=(12, 10))

600

601

# 1. Fitness convergence

602

axes[0, 0].semilogy(logger.f[:, 0], logger.f[:, 4], 'b-', label='Best')

603

axes[0, 0].semilogy(logger.f[:, 0], logger.f[:, 5], 'r--', label='Median')

604

axes[0, 0].set_xlabel('Iteration')

605

axes[0, 0].set_ylabel('Fitness')

606

axes[0, 0].legend()

607

axes[0, 0].set_title('Fitness Evolution')

608

609

# 2. Step-size evolution

610

axes[0, 1].semilogy(logger.f[:, 0], logger.f[:, 2])

611

axes[0, 1].set_xlabel('Iteration')

612

axes[0, 1].set_ylabel('Sigma')

613

axes[0, 1].set_title('Step-size Evolution')

614

615

# 3. Condition number evolution

616

axes[1, 0].semilogy(logger.f[:, 0], logger.f[:, 3])

617

axes[1, 0].set_xlabel('Iteration')

618

axes[1, 0].set_ylabel('Axis Ratio')

619

axes[1, 0].set_title('Condition Number')

620

621

# 4. Standard deviations by coordinate

622

for i in range(min(5, logger.std.shape[1] - 4)): # Plot first 5 coordinates

623

axes[1, 1].semilogy(logger.std[:, 0], logger.std[:, 4 + i],

624

label=f'x[{i}]')

625

axes[1, 1].set_xlabel('Iteration')

626

axes[1, 1].set_ylabel('Standard Deviation')

627

axes[1, 1].legend()

628

axes[1, 1].set_title('Standard Deviations')

629

630

# 5. Principal axis lengths (if available)

631

if hasattr(logger, 'D') and logger.D is not None:

632

for i in range(min(3, logger.D.shape[1] - 4)):

633

axes[2, 0].semilogy(logger.D[:, 0], logger.D[:, 4 + i],

634

label=f'Axis {i+1}')

635

axes[2, 0].set_xlabel('Iteration')

636

axes[2, 0].set_ylabel('Axis Length')

637

axes[2, 0].legend()

638

axes[2, 0].set_title('Principal Axis Lengths')

639

640

# 6. Solution trajectory (2D projection)

641

if logger.xmean.shape[1] >= 6: # At least 2D problem

642

axes[2, 1].plot(logger.xmean[:, 4], logger.xmean[:, 5], 'b-o', markersize=2)

643

axes[2, 1].plot(logger.xmean[0, 4], logger.xmean[0, 5], 'go', markersize=8, label='Start')

644

axes[2, 1].plot(logger.xmean[-1, 4], logger.xmean[-1, 5], 'ro', markersize=8, label='End')

645

axes[2, 1].set_xlabel('x[0]')

646

axes[2, 1].set_ylabel('x[1]')

647

axes[2, 1].legend()

648

axes[2, 1].set_title('Solution Trajectory (2D)')

649

650

plt.tight_layout()

651

plt.show()

652

653

return fig

654

655

# Pattern 3: Comparative plotting of multiple runs

656

def comparative_plotting_example():

657

"""Compare multiple optimization runs."""

658

659

# Simulate multiple runs (in practice, load from different files)

660

run_data = {}

661

662

for run_id, sigma0 in enumerate([0.1, 0.3, 1.0]):

663

logger = cma.CMADataLogger(f'temp_run_{run_id}/')

664

es = cma.CMAEvolutionStrategy(3 * [0.5], sigma0, {'verbose': -9})

665

logger.register(es)

666

667

while not es.stop():

668

solutions = es.ask()

669

fitness_values = [sum(x**2) for x in solutions]

670

es.tell(solutions, fitness_values)

671

logger.add()

672

673

logger.load()

674

run_data[f'sigma_{sigma0}'] = logger

675

676

# Comparative plot

677

plt.figure(figsize=(12, 8))

678

679

# Subplot 1: Fitness comparison

680

plt.subplot(2, 2, 1)

681

for label, logger in run_data.items():

682

plt.semilogy(logger.f[:, 1], logger.f[:, 4], label=label) # evals vs best fitness

683

plt.xlabel('Evaluations')

684

plt.ylabel('Best Fitness')

685

plt.legend()

686

plt.title('Fitness Convergence Comparison')

687

688

# Subplot 2: Step-size comparison

689

plt.subplot(2, 2, 2)

690

for label, logger in run_data.items():

691

plt.semilogy(logger.f[:, 0], logger.f[:, 2], label=label) # iteration vs sigma

692

plt.xlabel('Iteration')

693

plt.ylabel('Sigma')

694

plt.legend()

695

plt.title('Step-size Evolution Comparison')

696

697

# Subplot 3: Convergence speed

698

plt.subplot(2, 2, 3)

699

convergence_evals = []

700

sigma_values = []

701

702

for label, logger in run_data.items():

703

# Find evaluation where fitness < 1e-6

704

converged_idx = np.where(logger.f[:, 4] < 1e-6)[0]

705

if len(converged_idx) > 0:

706

convergence_evals.append(logger.f[converged_idx[0], 1])

707

sigma_values.append(float(label.split('_')[1]))

708

else:

709

convergence_evals.append(logger.f[-1, 1]) # Final evaluation

710

sigma_values.append(float(label.split('_')[1]))

711

712

plt.bar([f'σ={s}' for s in sigma_values], convergence_evals)

713

plt.xlabel('Initial Step-size')

714

plt.ylabel('Evaluations to Convergence')

715

plt.title('Convergence Speed')

716

717

# Subplot 4: Final condition numbers

718

plt.subplot(2, 2, 4)

719

final_conditions = [logger.f[-1, 3] for logger in run_data.values()]

720

plt.bar([f'σ={s}' for s in sigma_values], final_conditions)

721

plt.xlabel('Initial Step-size')

722

plt.ylabel('Final Condition Number')

723

plt.yscale('log')

724

plt.title('Final Conditioning')

725

726

plt.tight_layout()

727

plt.show()

728

729

return run_data

730

731

# Pattern 4: Publication-quality plots

732

def publication_quality_plots():

733

"""Create publication-quality plots from CMA-ES data."""

734

735

# Load data

736

logger = cma.CMADataLogger().load()

737

738

# Set publication style

739

plt.style.use('classic')

740

plt.rcParams.update({

741

'font.size': 12,

742

'font.family': 'serif',

743

'axes.linewidth': 1.5,

744

'axes.grid': True,

745

'grid.alpha': 0.3,

746

'lines.linewidth': 2,

747

'figure.dpi': 300

748

})

749

750

fig, ax = plt.subplots(figsize=(8, 6))

751

752

# Plot fitness evolution with confidence bands (if multiple runs available)

753

iterations = logger.f[:, 0]

754

best_fitness = logger.f[:, 4]

755

median_fitness = logger.f[:, 5]

756

757

ax.semilogy(iterations, best_fitness, 'b-', linewidth=2, label='Best fitness')

758

ax.semilogy(iterations, median_fitness, 'r--', linewidth=2, label='Median fitness')

759

760

ax.set_xlabel('Iteration')

761

ax.set_ylabel('Function value')

762

ax.legend(loc='upper right')

763

ax.grid(True, alpha=0.3)

764

ax.set_title('CMA-ES Convergence on Sphere Function')

765

766

# Add annotations

767

if len(best_fitness) > 0:

768

# Mark significant milestones

769

target_values = [1e-2, 1e-6, 1e-10]

770

for target in target_values:

771

achieved_idx = np.where(best_fitness <= target)[0]

772

if len(achieved_idx) > 0:

773

iter_achieved = iterations[achieved_idx[0]]

774

ax.annotate(f'10^{{{int(np.log10(target))}}} at iter {iter_achieved}',

775

xy=(iter_achieved, target),

776

xytext=(iter_achieved + 20, target * 10),

777

arrowprops=dict(arrowstyle='->', color='gray'))

778

779

plt.tight_layout()

780

plt.savefig('cmaes_convergence.pdf', dpi=300, bbox_inches='tight')

781

plt.show()

782

783

return fig

784

785

# Run plotting examples (comment out as needed)

786

# realtime_plotting_example()

787

# custom_plotting_example()

788

# comparative_plotting_example()

789

# publication_quality_plots()

790

```

791

792

## Analysis and Diagnostics

793

794

Advanced analysis tools for understanding optimization behavior and diagnosing convergence issues.

795

796

### Convergence Analysis

797

798

```python { .api }

799

def convergence_analysis(logger_or_prefix=None):

800

"""

801

Comprehensive convergence analysis of CMA-ES optimization.

802

803

Parameters:

804

-----------

805

logger_or_prefix : CMADataLogger or str, optional

806

Logger instance or file prefix. If None, loads default data.

807

808

Returns:

809

--------

810

dict

811

Analysis results including convergence rates, bottlenecks, and diagnostics.

812

813

Examples:

814

---------

815

>>> import cma

816

>>>

817

>>> # Run optimization

818

>>> x, es = cma.fmin2(cma.ff.elli, [1, 2, 3], 0.5)

819

>>>

820

>>> # Analyze convergence

821

>>> analysis = convergence_analysis()

822

>>>

823

>>> print(f"Linear convergence rate: {analysis['linear_rate']:.3f}")

824

>>> print(f"Bottleneck phase: {analysis['bottleneck_phase']}")

825

>>> print(f"Final condition: {analysis['final_condition']:.2e}")

826

"""

827

828

# Load data if needed

829

if isinstance(logger_or_prefix, str):

830

logger = cma.CMADataLogger().load(logger_or_prefix)

831

elif logger_or_prefix is None:

832

logger = cma.CMADataLogger().load()

833

else:

834

logger = logger_or_prefix

835

836

analysis = {}

837

838

# Basic statistics

839

analysis['total_iterations'] = int(logger.f[-1, 0])

840

analysis['total_evaluations'] = int(logger.f[-1, 1])

841

analysis['initial_fitness'] = logger.f[0, 4]

842

analysis['final_fitness'] = logger.f[-1, 4]

843

analysis['fitness_improvement'] = np.log10(analysis['initial_fitness'] / analysis['final_fitness'])

844

845

# Convergence rate analysis

846

log_fitness = np.log(logger.f[:, 4])

847

iterations = logger.f[:, 0]

848

849

# Linear convergence rate (slope of log(fitness) vs iteration)

850

if len(log_fitness) > 10:

851

# Use latter half for stable convergence rate

852

start_idx = len(log_fitness) // 2

853

coeffs = np.polyfit(iterations[start_idx:], log_fitness[start_idx:], 1)

854

analysis['linear_rate'] = -coeffs[0] # Negative because we want decrease

855

else:

856

analysis['linear_rate'] = 0

857

858

# Identify convergence phases

859

fitness_diff = np.diff(log_fitness)

860

861

# Find where improvement slows down significantly

862

slow_improvement = fitness_diff > -1e-3 # Very slow improvement

863

if np.any(slow_improvement):

864

analysis['bottleneck_start'] = int(iterations[np.where(slow_improvement)[0][0]])

865

else:

866

analysis['bottleneck_start'] = None

867

868

# Step-size analysis

869

sigmas = logger.f[:, 2]

870

analysis['initial_sigma'] = sigmas[0]

871

analysis['final_sigma'] = sigmas[-1]

872

analysis['sigma_reduction'] = sigmas[0] / sigmas[-1]

873

874

# Conditioning analysis

875

axis_ratios = logger.f[:, 3]

876

analysis['initial_condition'] = axis_ratios[0]

877

analysis['final_condition'] = axis_ratios[-1]

878

analysis['max_condition'] = np.max(axis_ratios)

879

880

# Stagnation detection

881

fitness_window = 20 # Window for stagnation check

882

if len(logger.f) > fitness_window:

883

recent_fitness = logger.f[-fitness_window:, 4]

884

fitness_variation = (np.max(recent_fitness) - np.min(recent_fitness)) / np.mean(recent_fitness)

885

analysis['recent_stagnation'] = fitness_variation < 1e-12

886

else:

887

analysis['recent_stagnation'] = False

888

889

# Efficiency metrics

890

analysis['evaluations_per_iteration'] = analysis['total_evaluations'] / analysis['total_iterations']

891

if analysis['fitness_improvement'] > 0:

892

analysis['evals_per_order_magnitude'] = analysis['total_evaluations'] / analysis['fitness_improvement']

893

else:

894

analysis['evals_per_order_magnitude'] = float('inf')

895

896

return analysis

897

898

def diagnostic_summary(logger_or_prefix=None):

899

"""

900

Generate diagnostic summary for CMA-ES optimization.

901

902

Identifies common issues and provides recommendations.

903

"""

904

905

analysis = convergence_analysis(logger_or_prefix)

906

907

print("CMA-ES Diagnostic Summary")

908

print("=" * 40)

909

910

# Basic performance

911

print(f"Total iterations: {analysis['total_iterations']}")

912

print(f"Total evaluations: {analysis['total_evaluations']}")

913

print(f"Fitness improvement: {analysis['fitness_improvement']:.1f} orders of magnitude")

914

print(f"Convergence rate: {analysis['linear_rate']:.3f} (log units per iteration)")

915

916

# Efficiency assessment

917

print(f"\nEfficiency Metrics:")

918

print(f" Evaluations per iteration: {analysis['evaluations_per_iteration']:.1f}")

919

if analysis['evals_per_order_magnitude'] < float('inf'):

920

print(f" Evaluations per order of magnitude: {analysis['evals_per_order_magnitude']:.0f}")

921

922

# Conditioning assessment

923

print(f"\nConditioning Analysis:")

924

print(f" Initial condition number: {analysis['initial_condition']:.2e}")

925

print(f" Final condition number: {analysis['final_condition']:.2e}")

926

print(f" Maximum condition number: {analysis['max_condition']:.2e}")

927

928

# Issue detection and recommendations

929

print(f"\nDiagnostic Findings:")

930

931

issues = []

932

recommendations = []

933

934

# Check for poor conditioning

935

if analysis['final_condition'] > 1e12:

936

issues.append("Very high condition number (> 1e12)")

937

recommendations.append("Consider coordinate scaling or preconditioning")

938

939

# Check for stagnation

940

if analysis['recent_stagnation']:

941

issues.append("Recent fitness stagnation detected")

942

recommendations.append("May need restart or different termination criteria")

943

944

# Check convergence rate

945

if analysis['linear_rate'] < 0.01:

946

issues.append("Slow convergence rate (< 0.01)")

947

recommendations.append("Consider larger population or different step-size")

948

949

# Check step-size reduction

950

if analysis['sigma_reduction'] > 1e6:

951

issues.append("Excessive step-size reduction")

952

recommendations.append("Initial step-size may have been too large")

953

954

# Check efficiency

955

expected_evals = analysis['total_iterations'] * (4 + 3 * np.log(5)) # Rough estimate for 5D

956

if analysis['total_evaluations'] > 2 * expected_evals:

957

issues.append("Higher than expected evaluation count")

958

recommendations.append("Check for expensive function evaluations or large population")

959

960

if not issues:

961

print(" No significant issues detected - optimization appears healthy")

962

else:

963

for i, issue in enumerate(issues):

964

print(f" Issue {i+1}: {issue}")

965

966

print(f"\nRecommendations:")

967

for i, rec in enumerate(recommendations):

968

print(f" {i+1}. {rec}")

969

970

return analysis

971

972

# Example usage

973

def run_diagnostic_example():

974

"""Example of comprehensive diagnostic analysis."""

975

976

import cma

977

978

# Run optimization with logging

979

def objective(x):

980

# Ill-conditioned ellipsoid

981

scales = [10**(i/2) for i in range(len(x))]

982

return sum(s * xi**2 for s, xi in zip(scales, x))

983

984

x, es = cma.fmin2(objective, 5 * [1], 0.5,

985

options={'maxfevals': 5000, 'verbose': -1})

986

987

# Run diagnostics

988

analysis = diagnostic_summary()

989

990

# Custom analysis

991

print(f"\nCustom Analysis:")

992

logger = cma.CMADataLogger().load()

993

994

# Check for premature convergence

995

final_sigma = logger.f[-1, 2]

996

dimension = 5

997

if final_sigma < 1e-12:

998

print(" Warning: Very small final step-size - possible premature convergence")

999

1000

# Check population diversity

1001

if hasattr(logger, 'std') and logger.std is not None:

1002

final_stds = logger.std[-1, 4:]

1003

std_ratio = np.max(final_stds) / np.min(final_stds)

1004

print(f" Final coordinate std ratio: {std_ratio:.2e}")

1005

1006

if std_ratio > 1e6:

1007

print(" Warning: Very different coordinate scales - consider rescaling")

1008

1009

return analysis

1010

1011

# run_diagnostic_example()

1012

```

1013

1014

### Performance Metrics and Benchmarking

1015

1016

```python { .api }

1017

def performance_metrics(results_list):

1018

"""

1019

Compute standard performance metrics for optimization results.

1020

1021

Parameters:

1022

-----------

1023

results_list : list

1024

List of (x_best, es) tuples from multiple optimization runs.

1025

1026

Returns:

1027

--------

1028

dict

1029

Performance metrics including success rates, efficiency measures.

1030

"""

1031

1032

metrics = {

1033

'success_rate': 0,

1034

'mean_evaluations': 0,

1035

'median_evaluations': 0,

1036

'mean_final_fitness': 0,

1037

'evaluation_counts': [],

1038

'final_fitness_values': [],

1039

'successful_runs': 0,

1040

'total_runs': len(results_list)

1041

}

1042

1043

success_threshold = 1e-8

1044

1045

for x_best, es in results_list:

1046

final_fitness = es.result.fbest

1047

evaluations = es.result.evaluations

1048

1049

metrics['evaluation_counts'].append(evaluations)

1050

metrics['final_fitness_values'].append(final_fitness)

1051

1052

if final_fitness < success_threshold:

1053

metrics['successful_runs'] += 1

1054

1055

# Compute derived metrics

1056

metrics['success_rate'] = metrics['successful_runs'] / metrics['total_runs']

1057

metrics['mean_evaluations'] = np.mean(metrics['evaluation_counts'])

1058

metrics['median_evaluations'] = np.median(metrics['evaluation_counts'])

1059

metrics['mean_final_fitness'] = np.mean(metrics['final_fitness_values'])

1060

1061

# Success-conditional metrics

1062

successful_evals = [evals for evals, (_, es) in zip(metrics['evaluation_counts'], results_list)

1063

if es.result.fbest < success_threshold]

1064

1065

if successful_evals:

1066

metrics['mean_successful_evaluations'] = np.mean(successful_evals)

1067

metrics['median_successful_evaluations'] = np.median(successful_evals)

1068

else:

1069

metrics['mean_successful_evaluations'] = None

1070

metrics['median_successful_evaluations'] = None

1071

1072

return metrics

1073

1074

def benchmark_suite_analysis():

1075

"""Run CMA-ES on standard benchmark suite and analyze performance."""

1076

1077

import cma

1078

1079

# Test functions

1080

test_functions = {

1081

'sphere': lambda x: sum(x**2),

1082

'ellipsoid': lambda x: sum(10**(6*i/(len(x)-1)) * xi**2 for i, xi in enumerate(x)),

1083

'rosenbrock': lambda x: sum(100*(x[i+1] - x[i]**2)**2 + (1 - x[i])**2 for i in range(len(x)-1)),

1084

'rastrigin': lambda x: sum(xi**2 - 10*np.cos(2*np.pi*xi) + 10 for xi in x)

1085

}

1086

1087

dimensions = [2, 5, 10]

1088

repetitions = 5

1089

1090

results = {}

1091

1092

for func_name, func in test_functions.items():

1093

results[func_name] = {}

1094

1095

for dim in dimensions:

1096

print(f"Testing {func_name} in {dim}D...")

1097

1098

run_results = []

1099

1100

for rep in range(repetitions):

1101

try:

1102

x, es = cma.fmin2(func, dim * [0.5], 0.3,

1103

options={'maxfevals': 1000 * dim**2, 'verbose': -9})

1104

run_results.append((x, es))

1105

except Exception as e:

1106

print(f" Run {rep} failed: {e}")

1107

1108

if run_results:

1109

metrics = performance_metrics(run_results)

1110

results[func_name][dim] = metrics

1111

1112

# Print summary

1113

print("\nBenchmark Results Summary")

1114

print("=" * 50)

1115

1116

for func_name in results:

1117

print(f"\nFunction: {func_name}")

1118

print("Dim Success% Mean Evals Median Evals Mean Final")

1119

print("-" * 55)

1120

1121

for dim in sorted(results[func_name].keys()):

1122

m = results[func_name][dim]

1123

print(f"{dim:3d} {m['success_rate']:5.1%} {m['mean_evaluations']:8.0f} "

1124

f"{m['median_evaluations']:8.0f} {m['mean_final_fitness']:8.2e}")

1125

1126

return results

1127

1128

# benchmark_suite_analysis()

1129

```

1130

1131

This comprehensive logging and analysis documentation provides:

1132

1133

1. **CMADataLogger** - Complete data logging capabilities with file management

1134

2. **Data Structure** - Detailed explanation of logged data files and access patterns

1135

3. **Visualization** - Comprehensive plotting functions and customization options

1136

4. **Real-time Monitoring** - Live plotting and monitoring during optimization

1137

5. **Analysis Tools** - Convergence analysis, diagnostics, and performance metrics

1138

6. **Benchmarking** - Tools for systematic performance evaluation

1139

1140

The documentation enables users to fully monitor, analyze, and understand CMA-ES optimization behavior for both research and practical applications.