Wavelet Registry Best Practices Guide
Overview
The VectorWave WaveletRegistry provides a centralized, thread-safe way to discover, access, and manage wavelets in your applications. This guide demonstrates best practices for using the registry effectively and safely.
Table of Contents
- Quick Start
- Discovery Patterns
- Safe Selection
- Error Handling
- Performance Optimization
- Advanced Selection Strategies
- Integration Patterns
- Common Pitfalls
Quick Start
Basic Usage
// Type-safe wavelet selection with enum
Wavelet db4 = WaveletRegistry.getWavelet(WaveletName.DB4);
Wavelet haar = WaveletRegistry.getWavelet(WaveletName.HAAR);
// Get all available wavelets
Set<WaveletName> allWavelets = WaveletRegistry.getAvailableWavelets();
// Get wavelets by type (returns enum list)
List<WaveletName> orthogonalWavelets = WaveletRegistry.getOrthogonalWavelets();
Set<WaveletName> continuousWavelets = WaveletRegistry.getWaveletsByType(WaveletType.CONTINUOUS);
With MODWT Integration
// Type-safe wavelet selection with MODWT
WaveletName selected = WaveletName.DB4; // IDE autocomplete!
if (WaveletRegistry.hasWavelet(selected)) {
Wavelet wavelet = WaveletRegistry.getWavelet(selected);
if (wavelet instanceof DiscreteWavelet discreteWavelet) {
MODWTTransform transform = new MODWTTransform(discreteWavelet);
// Perform transform...
}
}
Discovery Patterns
✅ Efficient Type-Based Discovery
// GOOD: Use type-specific queries with enum results
List<WaveletName> orthogonal = WaveletRegistry.getOrthogonalWavelets();
List<WaveletName> continuous = WaveletRegistry.getContinuousWavelets();
// Family-specific queries
List<WaveletName> daubechies = WaveletRegistry.getDaubechiesWavelets();
List<WaveletName> symlets = WaveletRegistry.getSymletWavelets();
List<WaveletName> coiflets = WaveletRegistry.getCoifletWavelets();
✅ Type-Safe Iteration
// Iterate through all orthogonal wavelets
for (WaveletName name : WaveletRegistry.getOrthogonalWavelets()) {
Wavelet wavelet = WaveletRegistry.getWavelet(name);
System.out.println(name + ": " + wavelet.description());
}
Registry Overview
// Print comprehensive overview
WaveletRegistry.printAvailableWavelets();
// Programmatic exploration with enum
for (WaveletType type : WaveletType.values()) {
Set<WaveletName> wavelets = WaveletRegistry.getWaveletsByType(type);
System.out.println(type + ": " + wavelets.size() + " wavelets");
}
// Use enum features for powerful queries
EnumSet<WaveletName> dbWavelets = EnumSet.of(
WaveletName.DB2, WaveletName.DB4, WaveletName.DB6,
WaveletName.DB8, WaveletName.DB10
);
Safe Selection
Type-Safe Selection with Enum
public Wavelet selectWaveletSafely(WaveletName... candidates) {
for (WaveletName candidate : candidates) {
if (WaveletRegistry.hasWavelet(candidate)) {
return WaveletRegistry.getWavelet(candidate);
}
}
// Fallback to HAAR which is always available
return WaveletRegistry.getWavelet(WaveletName.HAAR);
}
// Usage with fallback strategy - compile-time safe!
Wavelet wavelet = selectWaveletSafely(
WaveletName.SYM8,
WaveletName.DB4,
WaveletName.HAAR
);
// Switch on wavelet type - enum enables this!
switch (selectedWavelet) {
case DB2, DB4, DB6, DB8, DB10 -> processDataubechies();
case SYM2, SYM3, SYM4 -> processSymlet();
case HAAR -> processHaar();
default -> processGeneric();
}
Signal Compatibility Validation
public boolean isWaveletSuitableForSignal(DiscreteWavelet wavelet, int signalLength) {
int filterLength = wavelet.lowPassDecomposition().length;
// Rule of thumb: signal should be at least 3x the filter length
return signalLength >= filterLength * 3;
}
// Usage
if (wavelet instanceof DiscreteWavelet dw) {
if (isWaveletSuitableForSignal(dw, mySignal.length)) {
// Safe to proceed
} else {
// Consider alternative wavelet or preprocessing
}
}
Error Handling
Graceful Exception Handling
public Optional<Wavelet> getWaveletOptional(String name) {
try {
if (name == null || name.trim().isEmpty()) {
return Optional.empty();
}
return Optional.of(WaveletRegistry.getWavelet(name));
} catch (InvalidArgumentException e) {
logger.warn("Wavelet not found: {}", name);
return Optional.empty();
}
}
Validation with Detailed Feedback
public ValidationResult validateWaveletForUseCase(String waveletName, String useCase) {
if (!WaveletRegistry.isWaveletAvailable(waveletName)) {
return ValidationResult.failure("Wavelet '" + waveletName + "' not available");
}
try {
WaveletInfo info = WaveletRegistry.getWaveletInfo(waveletName);
return switch (useCase) {
case "financial_analysis" ->
info.vanishingMoments() >= 2
? ValidationResult.success()
: ValidationResult.warning("Consider higher vanishing moments for smooth financial data");
case "edge_detection" ->
"Haar".equals(info.family())
? ValidationResult.success()
: ValidationResult.info("Haar wavelets are typically preferred for edge detection");
default -> ValidationResult.success();
};
} catch (Exception e) {
return ValidationResult.failure("Error retrieving wavelet metadata: " + e.getMessage());
}
}
Performance Optimization
Wavelet Caching
public class WaveletCache {
private final Map<String, Wavelet> cache = new ConcurrentHashMap<>();
public Wavelet getWavelet(String name) {
return cache.computeIfAbsent(name.toLowerCase(),
n -> WaveletRegistry.getWavelet(n));
}
// Use for frequently accessed wavelets
private static final WaveletCache CACHE = new WaveletCache();
public static Wavelet getCachedWavelet(String name) {
return CACHE.getWavelet(name);
}
}
Batch Operations
// Efficient batch wavelet creation
public Map<String, Wavelet> createWaveletSet(List<String> names) {
return names.stream()
.filter(WaveletRegistry::isWaveletAvailable)
.collect(Collectors.toMap(
name -> name,
WaveletRegistry::getWavelet
));
}
Performance Measurements
Based on our testing (1000 lookups):
- Cached lookups: ~50% faster than direct registry access
- Type-specific queries: ~10x faster than filtering all wavelets
- Batch validation: ~3x faster than individual checks
Advanced Selection Strategies
Metadata-Based Selection
// Select wavelets with specific properties
public List<String> findSmoothWavelets(int minVanishingMoments) {
return WaveletRegistry.getWaveletsByType(WaveletType.ORTHOGONAL)
.stream()
.filter(name -> {
try {
WaveletInfo info = WaveletRegistry.getWaveletInfo(name);
return info.vanishingMoments() >= minVanishingMoments;
} catch (Exception e) {
return false;
}
})
.collect(Collectors.toList());
}
// Select by computational efficiency
public List<String> findCompactWavelets(int maxFilterLength) {
return WaveletRegistry.getAvailableWavelets()
.stream()
.filter(name -> {
try {
WaveletInfo info = WaveletRegistry.getWaveletInfo(name);
return info.filterLength() > 0 && info.filterLength() <= maxFilterLength;
} catch (Exception e) {
return false;
}
})
.sorted(Comparator.comparing(name -> {
try {
return WaveletRegistry.getWaveletInfo(name).filterLength();
} catch (Exception e) {
return Integer.MAX_VALUE;
}
}))
.collect(Collectors.toList());
}
Application-Specific Selection
public class WaveletSelector {
public static String selectForFinancialAnalysis() {
// Priority: orthogonal, high vanishing moments, reasonable filter length
return WaveletRegistry.getWaveletsByType(WaveletType.ORTHOGONAL)
.stream()
.filter(name -> {
try {
WaveletInfo info = WaveletRegistry.getWaveletInfo(name);
return info.vanishingMoments() >= 4 && info.filterLength() <= 20;
} catch (Exception e) {
return false;
}
})
.findFirst()
.orElse("db4"); // Fallback
}
public static String selectForImageCompression() {
// Priority: biorthogonal for perfect reconstruction, symmetric
return WaveletRegistry.getWaveletsByType(WaveletType.BIORTHOGONAL)
.stream()
.findFirst()
.orElse("haar"); // Fallback
}
public static String selectForEdgeDetection() {
// Simple, compact wavelets preferred
return WaveletRegistry.isWaveletAvailable("haar") ? "haar" : "db2";
}
}
Integration Patterns
With Spring Framework
@Component
public class WaveletService {
@Value("${app.default-wavelet:db4}")
private String defaultWaveletName;
@PostConstruct
public void validateConfiguration() {
if (!WaveletRegistry.isWaveletAvailable(defaultWaveletName)) {
throw new IllegalStateException(
"Configured wavelet '" + defaultWaveletName + "' is not available");
}
}
public Wavelet getDefaultWavelet() {
return WaveletRegistry.getWavelet(defaultWaveletName);
}
}
With Configuration Management
public class WaveletConfig {
private final String waveletName;
private final WaveletType requiredType;
private final int minVanishingMoments;
public WaveletConfig(String waveletName, WaveletType requiredType, int minVanishingMoments) {
this.waveletName = waveletName;
this.requiredType = requiredType;
this.minVanishingMoments = minVanishingMoments;
validate();
}
private void validate() {
if (!WaveletRegistry.isWaveletAvailable(waveletName)) {
throw new IllegalArgumentException("Wavelet not available: " + waveletName);
}
Wavelet wavelet = WaveletRegistry.getWavelet(waveletName);
if (wavelet.getType() != requiredType) {
throw new IllegalArgumentException(
"Wavelet type mismatch. Expected: " + requiredType + ", Actual: " + wavelet.getType());
}
try {
WaveletInfo info = WaveletRegistry.getWaveletInfo(waveletName);
if (info.vanishingMoments() < minVanishingMoments) {
throw new IllegalArgumentException(
"Insufficient vanishing moments. Required: " + minVanishingMoments +
", Actual: " + info.vanishingMoments());
}
} catch (Exception e) {
// Metadata not available - log warning but don't fail
logger.warn("Could not validate vanishing moments for {}: {}", waveletName, e.getMessage());
}
}
public Wavelet getWavelet() {
return WaveletRegistry.getWavelet(waveletName);
}
}
Common Pitfalls
❌ Case Sensitivity Issues
// WRONG: Assuming case sensitivity
WaveletRegistry.getWavelet("DB4"); // Works, but inconsistent
// RIGHT: Use consistent lowercase
WaveletRegistry.getWavelet("db4");
❌ Not Checking Availability
// WRONG: Direct access without validation
Wavelet wavelet = WaveletRegistry.getWavelet(userInput); // May throw exception
// RIGHT: Always validate first
if (WaveletRegistry.isWaveletAvailable(userInput)) {
Wavelet wavelet = WaveletRegistry.getWavelet(userInput);
// Safe to use
}
❌ Ignoring Wavelet Type
// WRONG: Assuming all wavelets work with MODWT
Wavelet wavelet = WaveletRegistry.getWavelet("morl");
MODWTTransform transform = new MODWTTransform((DiscreteWavelet) wavelet); // ClassCastException!
// RIGHT: Check type compatibility
Wavelet wavelet = WaveletRegistry.getWavelet("morl");
if (wavelet instanceof DiscreteWavelet discreteWavelet) {
MODWTTransform transform = new MODWTTransform(discreteWavelet);
} else {
// Handle continuous wavelets appropriately
}
❌ Performance Anti-patterns
// WRONG: Repeated registry lookups in loops
for (int i = 0; i < 1000; i++) {
Wavelet w = WaveletRegistry.getWavelet("db4"); // Inefficient
// process...
}
// RIGHT: Cache frequently used wavelets
Wavelet cachedWavelet = WaveletRegistry.getWavelet("db4");
for (int i = 0; i < 1000; i++) {
// Use cachedWavelet
}
Running the Demo
To see all these patterns in action, run the comprehensive demo:
# From the VectorWave project root
mvn test-compile exec:java -Dexec.mainClass="com.morphiqlabs.examples.WaveletRegistryBestPracticesDemo" -Dexec.classpathScope=test
The demo will show:
- ✅ Wavelet discovery patterns
- ✅ Safe selection with validation
- ✅ Error handling strategies
- ✅ Performance optimization techniques
- ✅ Advanced selection algorithms
- ✅ MODWT integration examples
- ✅ Metadata-driven decision making
Key Takeaways
- Always validate: Check wavelet availability before use
- Use type-specific queries: More efficient than filtering all wavelets
- Handle errors gracefully: Provide meaningful fallbacks
- Cache frequently used wavelets: Significant performance improvement
- Leverage metadata: Make informed decisions based on wavelet properties
- Consider signal compatibility: Match wavelet properties to your data characteristics
- Plan for extensibility: Design your code to handle new wavelets automatically
This approach ensures robust, performant, and maintainable wavelet-based applications.