or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

coefficient-utils.mdcontinuous-dwt.mdindex.mdmulti-level-dwt.mdmultiresolution-analysis.mdsingle-level-dwt.mdstationary-dwt.mdthresholding.mdwavelet-packets.mdwavelets.md

coefficient-utils.mddocs/

0

# Coefficient Manipulation

1

2

Utilities for converting between different coefficient representations, packing/unpacking coefficients, and working with coefficient arrays for efficient processing and storage.

3

4

## Capabilities

5

6

### Coefficient Array Conversion

7

8

Functions for converting between coefficient lists and single arrays for efficient processing.

9

10

```python { .api }

11

def coeffs_to_array(coeffs, padding: int = 0, axes=None):

12

"""

13

Pack wavelet coefficients into a single array.

14

15

Parameters:

16

- coeffs: Coefficient list from wavedec, wavedec2, or wavedecn

17

- padding: Additional padding between coefficient arrays

18

- axes: Axes information (for nD coefficients)

19

20

Returns:

21

(coeff_arr, coeff_slices) tuple where:

22

- coeff_arr: 1D array containing all coefficients

23

- coeff_slices: List of slice objects for extracting individual coefficients

24

"""

25

26

def array_to_coeffs(arr, coeff_slices, output_format: str = 'wavedecn'):

27

"""

28

Unpack single array back to coefficient format.

29

30

Parameters:

31

- arr: 1D coefficient array from coeffs_to_array

32

- coeff_slices: Slice information from coeffs_to_array

33

- output_format: Output format ('wavedec', 'wavedec2', 'wavedecn')

34

35

Returns:

36

Coefficient list in specified format

37

"""

38

```

39

40

#### Usage Examples

41

42

```python

43

import pywt

44

import numpy as np

45

import matplotlib.pyplot as plt

46

47

# Create test signal and perform multilevel DWT

48

np.random.seed(42)

49

signal = np.sin(2 * np.pi * 5 * np.linspace(0, 1, 1024)) + 0.3 * np.random.randn(1024)

50

coeffs = pywt.wavedec(signal, 'db4', level=6)

51

52

print(f"Original coefficient format: {len(coeffs)} arrays")

53

print(f"Coefficient array lengths: {[len(c) for c in coeffs]}")

54

print(f"Total coefficients: {sum(len(c) for c in coeffs)}")

55

56

# Pack coefficients into single array

57

coeff_arr, coeff_slices = pywt.coeffs_to_array(coeffs, padding=0)

58

print(f"\nPacked array shape: {coeff_arr.shape}")

59

print(f"Number of slices: {len(coeff_slices)}")

60

61

# Show slice information

62

for i, slice_info in enumerate(coeff_slices):

63

coeff_type = "Approximation" if i == 0 else f"Detail {len(coeffs)-i}"

64

print(f"{coeff_type:>15}: {slice_info}")

65

66

# Verify packing/unpacking

67

reconstructed_coeffs = pywt.array_to_coeffs(coeff_arr, coeff_slices, 'wavedec')

68

print(f"\nReconstruction verification:")

69

for i, (orig, recon) in enumerate(zip(coeffs, reconstructed_coeffs)):

70

error = np.max(np.abs(orig - recon))

71

print(f"Coefficient {i}: max error = {error:.2e}")

72

73

# Demonstrate coefficient processing in array format

74

def process_coeffs_in_array(coeff_arr, coeff_slices, processing_func):

75

"""Process coefficients while in array format."""

76

processed_arr = coeff_arr.copy()

77

78

# Skip approximation coefficients (first slice)

79

for i in range(1, len(coeff_slices)):

80

slice_obj = coeff_slices[i]

81

detail_coeffs = processed_arr[slice_obj]

82

processed_arr[slice_obj] = processing_func(detail_coeffs)

83

84

return processed_arr

85

86

# Example: Soft thresholding in array format

87

def soft_threshold(x, threshold=0.1):

88

return np.sign(x) * np.maximum(np.abs(x) - threshold, 0)

89

90

processed_arr = process_coeffs_in_array(coeff_arr, coeff_slices,

91

lambda x: soft_threshold(x, 0.05))

92

93

# Convert back and reconstruct

94

processed_coeffs = pywt.array_to_coeffs(processed_arr, coeff_slices, 'wavedec')

95

reconstructed_signal = pywt.waverec(processed_coeffs, 'db4')

96

97

# Visualization

98

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

99

100

plt.subplot(3, 1, 1)

101

plt.plot(signal, 'b-', label='Original signal')

102

plt.title('Original Signal')

103

plt.legend()

104

plt.grid(True)

105

106

plt.subplot(3, 1, 2)

107

plt.plot(coeff_arr, 'g-', label='Packed coefficients')

108

plt.title('Coefficients in Array Format')

109

plt.xlabel('Coefficient Index')

110

plt.legend()

111

plt.grid(True)

112

113

# Mark boundaries between coefficient types

114

boundary_indices = [0]

115

for slice_obj in coeff_slices:

116

boundary_indices.append(slice_obj.stop)

117

118

for boundary in boundary_indices[1:-1]:

119

plt.axvline(x=boundary, color='r', linestyle='--', alpha=0.7)

120

121

plt.subplot(3, 1, 3)

122

plt.plot(signal, 'b-', alpha=0.7, label='Original')

123

plt.plot(reconstructed_signal, 'r-', label='Processed & reconstructed')

124

plt.title('Processed Signal (Soft Thresholding)')

125

plt.legend()

126

plt.grid(True)

127

128

plt.tight_layout()

129

plt.show()

130

131

print(f"Processing SNR improvement: {10 * np.log10(np.var(signal) / np.var(signal - reconstructed_signal)):.2f} dB")

132

```

133

134

### Coefficient Raveling

135

136

Functions for converting coefficients to 1D arrays while preserving shape information.

137

138

```python { .api }

139

def ravel_coeffs(coeffs, axes=None):

140

"""

141

Ravel coefficients to 1D array with shape preservation.

142

143

Parameters:

144

- coeffs: Coefficient list from multilevel decomposition

145

- axes: Axes information (for nD coefficients)

146

147

Returns:

148

(coeff_arr, coeff_slices, coeff_shapes) tuple where:

149

- coeff_arr: 1D raveled coefficient array

150

- coeff_slices: Slice information for extraction

151

- coeff_shapes: Original shapes of coefficient arrays

152

"""

153

154

def unravel_coeffs(arr, coeff_slices, coeff_shapes, output_format: str = 'wavedecn'):

155

"""

156

Unravel 1D array back to coefficient format with proper shapes.

157

158

Parameters:

159

- arr: 1D raveled coefficient array

160

- coeff_slices: Slice information from ravel_coeffs

161

- coeff_shapes: Shape information from ravel_coeffs

162

- output_format: Output format specification

163

164

Returns:

165

Coefficient list with proper shapes

166

"""

167

```

168

169

#### Usage Examples

170

171

```python

172

import pywt

173

import numpy as np

174

175

# 2D image example

176

image = np.random.randn(128, 128)

177

coeffs_2d = pywt.wavedec2(image, 'db2', level=4)

178

179

print("2D Coefficient Structure:")

180

print(f"Approximation shape: {coeffs_2d[0].shape}")

181

for i, (cH, cV, cD) in enumerate(coeffs_2d[1:]):

182

level = len(coeffs_2d) - 1 - i

183

print(f"Level {level} details: H{cH.shape}, V{cV.shape}, D{cD.shape}")

184

185

# Ravel all coefficients

186

coeff_arr, coeff_slices, coeff_shapes = pywt.ravel_coeffs(coeffs_2d)

187

print(f"\nRaveled array shape: {coeff_arr.shape}")

188

print(f"Number of coefficient groups: {len(coeff_slices)}")

189

print(f"Coefficient shapes: {coeff_shapes}")

190

191

# Process in raveled format (e.g., apply ML model)

192

def simulate_ml_processing(arr):

193

"""Simulate machine learning processing of coefficients."""

194

# Example: Apply learned transform (simulated with random matrix)

195

np.random.seed(123)

196

# In practice, this would be a trained model

197

transform_matrix = np.eye(len(arr)) + 0.01 * np.random.randn(len(arr), len(arr))

198

return transform_matrix @ arr

199

200

processed_arr = simulate_ml_processing(coeff_arr)

201

202

# Unravel back to coefficient format

203

processed_coeffs = pywt.unravel_coeffs(processed_arr, coeff_slices, coeff_shapes, 'wavedec2')

204

processed_image = pywt.waverec2(processed_coeffs, 'db2')

205

206

print(f"\nImage reconstruction error: {np.max(np.abs(image - processed_image)):.6f}")

207

208

# 3D volume example

209

volume = np.random.randn(32, 32, 32)

210

coeffs_3d = pywt.wavedecn(volume, 'haar', level=3)

211

212

print(f"\n3D Volume Processing:")

213

print(f"Original volume shape: {volume.shape}")

214

print(f"Number of 3D coefficient groups: {len(coeffs_3d)}")

215

216

# Ravel 3D coefficients

217

coeff_arr_3d, coeff_slices_3d, coeff_shapes_3d = pywt.ravel_coeffs(coeffs_3d)

218

print(f"3D raveled array shape: {coeff_arr_3d.shape}")

219

220

# Simple processing: scale down high-frequency components

221

processed_arr_3d = coeff_arr_3d.copy()

222

# Assume first group is approximation, rest are details

223

total_coeffs = len(coeff_arr_3d)

224

approx_end = coeff_slices_3d[1].start if len(coeff_slices_3d) > 1 else total_coeffs

225

processed_arr_3d[approx_end:] *= 0.8 # Reduce detail coefficients

226

227

# Unravel and reconstruct

228

processed_coeffs_3d = pywt.unravel_coeffs(processed_arr_3d, coeff_slices_3d, coeff_shapes_3d, 'wavedecn')

229

processed_volume = pywt.waverecn(processed_coeffs_3d, 'haar')

230

231

print(f"3D volume reconstruction error: {np.max(np.abs(volume - processed_volume)):.6f}")

232

```

233

234

### Coefficient Shape Analysis

235

236

Utilities for analyzing coefficient structures without computing transforms.

237

238

```python { .api }

239

def wavedecn_shapes(shape, wavelet, mode: str = 'symmetric', level: int = None, axes=None):

240

"""

241

Get shapes of coefficient arrays without computing the transform.

242

243

Parameters:

244

- shape: Input data shape

245

- wavelet: Wavelet specification

246

- mode: Signal extension mode

247

- level: Decomposition level (default: maximum possible)

248

- axes: Axes for transform (default: all axes)

249

250

Returns:

251

List of coefficient shapes that would result from wavedecn

252

"""

253

254

def wavedecn_size(shapes):

255

"""

256

Calculate total number of coefficients from shapes.

257

258

Parameters:

259

- shapes: List of coefficient shapes from wavedecn_shapes

260

261

Returns:

262

Total number of coefficients

263

"""

264

```

265

266

#### Usage Examples

267

268

```python

269

import pywt

270

import numpy as np

271

272

# Analyze coefficient structures for different input sizes

273

input_shapes = [(1024,), (512, 512), (64, 64, 64), (32, 32, 32, 100)]

274

wavelet = 'db4'

275

276

print("Coefficient Structure Analysis:")

277

print("=" * 60)

278

279

for shape in input_shapes:

280

ndim = len(shape)

281

max_level = pywt.dwtn_max_level(shape, wavelet) if ndim > 1 else pywt.dwt_max_level(shape[0], pywt.Wavelet(wavelet).dec_len)

282

283

print(f"\nInput shape: {shape}")

284

print(f"Maximum decomposition level: {max_level}")

285

286

# Analyze different decomposition levels

287

for level in range(1, min(max_level + 1, 6)): # Limit to 5 levels for display

288

if ndim == 1:

289

# Use regular DWT functions for 1D

290

test_coeffs = pywt.wavedec(np.zeros(shape), wavelet, level=level)

291

coeff_shapes = [c.shape for c in test_coeffs]

292

total_coeffs = sum(c.size for c in test_coeffs)

293

else:

294

# Use shape analysis for nD

295

coeff_shapes = pywt.wavedecn_shapes(shape, wavelet, level=level)

296

total_coeffs = pywt.wavedecn_size(coeff_shapes)

297

298

compression_ratio = np.prod(shape) / total_coeffs

299

print(f" Level {level}: {len(coeff_shapes)} groups, {total_coeffs} total coeffs, compression ratio: {compression_ratio:.3f}")

300

301

# Memory usage analysis

302

def analyze_memory_usage(shape, wavelet, level):

303

"""Analyze memory usage for different coefficient representations."""

304

305

# Original data size

306

original_size = np.prod(shape) * 8 # 8 bytes per float64

307

308

if len(shape) == 1:

309

coeffs = pywt.wavedec(np.zeros(shape), wavelet, level=level)

310

coeff_sizes = [c.size for c in coeffs]

311

else:

312

coeff_shapes = pywt.wavedecn_shapes(shape, wavelet, level=level)

313

coeff_sizes = [np.prod(s) if isinstance(s, tuple) else sum(np.prod(s) for s in s.values()) for s in coeff_shapes]

314

315

# Coefficient list memory

316

coeffs_size = sum(coeff_sizes) * 8

317

318

# Array format memory (coeffs_to_array)

319

array_size = sum(coeff_sizes) * 8 # Same as coeffs but contiguous

320

321

# Slice overhead (approximate)

322

slice_overhead = len(coeff_sizes) * 64 # Rough estimate

323

324

return {

325

'original': original_size,

326

'coeffs': coeffs_size,

327

'array': array_size + slice_overhead,

328

'compression': original_size / coeffs_size

329

}

330

331

# Memory analysis example

332

test_shape = (1024, 1024)

333

test_level = 5

334

335

memory_info = analyze_memory_usage(test_shape, 'db4', test_level)

336

337

print(f"\nMemory Usage Analysis for {test_shape} at level {test_level}:")

338

print(f"Original data: {memory_info['original'] / 1024**2:.2f} MB")

339

print(f"Coefficient lists: {memory_info['coeffs'] / 1024**2:.2f} MB")

340

print(f"Array format: {memory_info['array'] / 1024**2:.2f} MB")

341

print(f"Compression ratio: {memory_info['compression']:.3f}")

342

343

# Coefficient distribution analysis

344

def analyze_coefficient_distribution(coeffs):

345

"""Analyze the distribution of coefficient values."""

346

if isinstance(coeffs[0], np.ndarray):

347

# 1D coefficients

348

all_coeffs = np.concatenate(coeffs[1:]) # Skip approximation

349

else:

350

# 2D/nD coefficients - extract all detail coefficients

351

all_coeffs = []

352

for level_coeffs in coeffs[1:]:

353

if isinstance(level_coeffs, tuple):

354

# 2D case: (cH, cV, cD)

355

all_coeffs.extend([level_coeffs[0].ravel(), level_coeffs[1].ravel(), level_coeffs[2].ravel()])

356

else:

357

# nD case: dictionary

358

for key, coeff in level_coeffs.items():

359

all_coeffs.append(coeff.ravel())

360

all_coeffs = np.concatenate(all_coeffs)

361

362

return {

363

'mean': np.mean(all_coeffs),

364

'std': np.std(all_coeffs),

365

'min': np.min(all_coeffs),

366

'max': np.max(all_coeffs),

367

'zeros': np.sum(all_coeffs == 0) / len(all_coeffs) * 100,

368

'small': np.sum(np.abs(all_coeffs) < 0.01) / len(all_coeffs) * 100

369

}

370

371

# Test coefficient distribution

372

test_signal = np.sin(2 * np.pi * 5 * np.linspace(0, 1, 1024)) + 0.1 * np.random.randn(1024)

373

test_coeffs = pywt.wavedec(test_signal, 'db8', level=6)

374

dist_info = analyze_coefficient_distribution(test_coeffs)

375

376

print(f"\nCoefficient Distribution Analysis:")

377

print(f"Mean: {dist_info['mean']:.6f}")

378

print(f"Std: {dist_info['std']:.6f}")

379

print(f"Range: [{dist_info['min']:.6f}, {dist_info['max']:.6f}]")

380

print(f"Exact zeros: {dist_info['zeros']:.2f}%")

381

print(f"Small coefficients (|x| < 0.01): {dist_info['small']:.2f}%")

382

```

383

384

### Advanced Coefficient Manipulation

385

386

Advanced utilities for coefficient processing and analysis.

387

388

#### Usage Examples

389

390

```python

391

import pywt

392

import numpy as np

393

import matplotlib.pyplot as plt

394

395

def coefficient_energy_analysis(coeffs):

396

"""Analyze energy distribution across coefficient levels."""

397

if isinstance(coeffs[0], np.ndarray):

398

# 1D case

399

energies = [np.sum(c**2) for c in coeffs]

400

labels = ['Approx'] + [f'Detail {len(coeffs)-i}' for i in range(1, len(coeffs))]

401

else:

402

# 2D case

403

energies = [np.sum(coeffs[0]**2)] # Approximation

404

labels = ['Approximation']

405

406

for i, (cH, cV, cD) in enumerate(coeffs[1:]):

407

level = len(coeffs) - 1 - i

408

energies.extend([np.sum(cH**2), np.sum(cV**2), np.sum(cD**2)])

409

labels.extend([f'H{level}', f'V{level}', f'D{level}'])

410

411

total_energy = sum(energies)

412

energy_percentages = [e/total_energy * 100 for e in energies]

413

414

return labels, energies, energy_percentages

415

416

# Test energy analysis

417

test_image = np.random.randn(256, 256)

418

coeffs_2d = pywt.wavedec2(test_image, 'db4', level=4)

419

420

labels, energies, percentages = coefficient_energy_analysis(coeffs_2d)

421

422

print("Energy Distribution Analysis:")

423

for label, energy, pct in zip(labels, energies, percentages):

424

print(f"{label:>12}: {energy:>10.2f} ({pct:>5.2f}%)")

425

426

# Visualize energy distribution

427

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

428

plt.subplot(1, 2, 1)

429

plt.bar(range(len(labels)), percentages)

430

plt.xticks(range(len(labels)), labels, rotation=45)

431

plt.ylabel('Energy Percentage')

432

plt.title('Coefficient Energy Distribution')

433

plt.grid(True, alpha=0.3)

434

435

# Cumulative energy

436

cumulative = np.cumsum(percentages)

437

plt.subplot(1, 2, 2)

438

plt.plot(range(len(labels)), cumulative, 'o-')

439

plt.xticks(range(len(labels)), labels, rotation=45)

440

plt.ylabel('Cumulative Energy Percentage')

441

plt.title('Cumulative Energy Distribution')

442

plt.grid(True, alpha=0.3)

443

plt.axhline(y=90, color='r', linestyle='--', alpha=0.7, label='90% Energy')

444

plt.axhline(y=95, color='r', linestyle='--', alpha=0.7, label='95% Energy')

445

plt.legend()

446

447

plt.tight_layout()

448

plt.show()

449

450

# Find coefficient threshold for energy retention

451

def find_energy_threshold(coeffs, energy_target=0.9):

452

"""Find threshold that retains specified fraction of energy."""

453

# Collect all detail coefficients

454

all_details = []

455

if isinstance(coeffs[0], np.ndarray):

456

# 1D case

457

all_details = np.concatenate(coeffs[1:])

458

else:

459

# 2D case

460

for cH, cV, cD in coeffs[1:]:

461

all_details.extend([cH.ravel(), cV.ravel(), cD.ravel()])

462

all_details = np.concatenate(all_details)

463

464

# Sort by absolute value (descending)

465

sorted_coeffs = np.sort(np.abs(all_details))[::-1]

466

467

# Find threshold for energy retention

468

total_energy = np.sum(sorted_coeffs**2)

469

target_energy = energy_target * total_energy

470

471

cumulative_energy = np.cumsum(sorted_coeffs**2)

472

threshold_idx = np.argmax(cumulative_energy >= target_energy)

473

threshold = sorted_coeffs[threshold_idx]

474

475

return threshold, threshold_idx / len(sorted_coeffs)

476

477

threshold_90, coeff_fraction = find_energy_threshold(coeffs_2d, 0.9)

478

print(f"\nFor 90% energy retention:")

479

print(f"Threshold: {threshold_90:.6f}")

480

print(f"Coefficients kept: {coeff_fraction:.1%}")

481

```

482

483

## Types

484

485

```python { .api }

486

# Coefficient array formats

487

CoeffArray = np.ndarray # 1D array containing packed coefficients

488

CoeffSlices = List[slice] # Slice objects for extracting individual coefficients

489

CoeffShapes = List[Union[tuple, Dict[str, tuple]]] # Shape information for reconstruction

490

491

# Output format specifications

492

OutputFormat = Literal['wavedec', 'wavedec2', 'wavedecn']

493

494

# Coefficient analysis results

495

EnergyAnalysis = Tuple[List[str], List[float], List[float]] # (labels, energies, percentages)

496

```