COMPRESSION
DAWG Unicode Compression
This document explains the automatic Unicode compression feature in the DAWG module, which can reduce storage size by 50-75% for dictionaries with limited character diversity.
Overview
The DAWG module includes an innovative compression technique that stores Unicode characters using only 7-bit ASCII characters. This enables massive space savings for dictionaries that use a limited set of unique characters, regardless of which Unicode scripts they come from.
How It Works
The Compression Algorithm
Character Analysis: The DAWG analyzes all unique characters in your dictionary
Mapping Creation: If there are ≤89 unique characters total, each non-ASCII character is mapped to an unused ASCII character
Storage: Words are stored using these ASCII mappings internally
Transparent Access: The DAWG automatically decompresses strings when you retrieve them
Available Mapping Characters
The compression uses these 89 ASCII characters as mapping targets:
Letters:
a-z,A-Z(52 characters)Digits:
0-9(10 characters)Symbols:
!#$%&()*+,-./:;<=>?@[]^_{|}~(27 characters)
Only ASCII characters that don't appear in your actual text are used for mappings.
Example
Consider a French dictionary containing: "café", "naïve", "résumé", "crème"
# Unique characters: a,c,e,f,i,m,n,r,s,u,v,è,é,ï,ê
# Total: 15 characters (well under 89 limit)
# Automatic mapping created:
'é' → '!'
'è' → '#'
'ï' → '$'
'ê' → '%'
# Internal storage:
"café" → "caf!"
"naïve" → "na$ve"
"résumé" → "r!sum!"
"crème" → "cr#me"Storage Savings
Comparison by Encoding
| Text | UTF-8 | UTF-32 | Compressed |
|---|---|---|---|
| café | 5 bytes | 16 bytes | 4 bytes |
| naïve | 6 bytes | 20 bytes | 5 bytes |
| 北京市 | 9 bytes | 12 bytes | 3 bytes |
| Москва | 12 bytes | 24 bytes | 6 bytes |
Real-World Examples
French dictionary (é, è, à, ù, etc.): ~60% size reduction
Spanish dictionary (ñ, á, é, í, ó, ú): ~55% size reduction
Pinyin dictionary (ā, á, ǎ, à, etc.): ~70% size reduction
IPA phonetic dictionary: ~65% size reduction
Mathematical notation: ~50% size reduction
When Compression Activates
Automatic Compression
The DAWG automatically applies compression when:
Adding Unicode text to an ASCII-only DAWG
The total unique character count stays ≤89
Loading a dictionary file with limited character diversity
my $dawg = DAWG.new;
$dawg.add("hello"); # Starts as ASCII-only
$dawg.add("café"); # Automatically upgrades to compressed Unicode
$dawg.add("naïve"); # Still under 89 unique chars, stays compressedManual Control
You can also control compression explicitly:
# Force compressed mode (fails if >89 unique chars)
$dawg.rebuild(:encoding('compressed'));
# Force UTF-32 mode (no compression)
$dawg.rebuild(:encoding('utf32'));
# Let DAWG choose optimal encoding
$dawg.rebuild(:encoding('auto'));Use Cases
Ideal For
European languages: French, Spanish, German, Polish, Czech, etc.
Romanized texts: Pinyin, transliterated Arabic/Russian/Hindi
Phonetic dictionaries: IPA transcriptions
Technical vocabularies: Chemical formulas, mathematical notation
Domain-specific: Legal terms, medical terminology
Historical texts: Old English, Middle English, Latin
Constructed languages: Esperanto, Interlingua
Not Suitable For
Mixed multilingual content: UN documents, Wikipedia
Full Unicode range: Emoji dictionaries, symbol libraries
High character diversity: Japanese (hiragana + katakana + kanji)
API Access
For search modules and advanced usage:
# Check if using compression
if $dawg.is-compressed-unicode {
# Compress a string for internal operations
my $compressed = $dawg.compress-string("café");
# Decompress for display
my $original = $dawg.decompress-string($compressed);
}Performance Impact
Compression overhead: Negligible (simple hash lookup)
Decompression overhead: Negligible (simple hash lookup)
Memory usage: 50-75% reduction for suitable dictionaries
Traversal speed: Slightly faster due to better cache locality
Technical Details
Internal Structures
# Character mappings stored in the DAWG
%.unicode-map = {
'é' => '!',
'è' => '#',
'ñ' => '$',
# ... up to 89 mappings
}
%.reverse-unicode-map = {
'!' => 'é',
'#' => 'è',
'$' => 'ñ',
# ... reverse mappings
}Serialization
Compressed DAWGs save the mapping tables in their metadata:
JSON format: Mappings stored in the JSON structure
Binary format: Mapping table in the header
Memory-mapped: Mappings loaded into RAM on access
Compatibility
Compressed DAWGs are fully compatible with all DAWG operations
Search modules handle compression transparently
No API changes required for basic usage
Best Practices
Let automatic mode decide: The DAWG chooses optimal encoding automatically
Profile your data: Count unique characters before choosing compression
Consider future growth: Will your dictionary stay under 89 unique characters?
Benchmark for your use case: Compression helps most with large dictionaries
Limitations
Character limit: Maximum 89 unique characters
Mapping conflicts: Can't use ASCII chars that appear in the source text
Unicode normalization: Should normalize Unicode before adding to DAWG
Case sensitivity: Uppercase/lowercase count as different characters
Examples
Creating a Compressed DAWG
use DAWG;
# Automatic compression
my $dawg = DAWG.new;
$dawg.add($_) for <café résumé naïve crème>;
$dawg.minimize;
say $dawg.stats; # Will show is-compressed-unicode => True
# Check compression saved space
say "Compressed: ", $dawg.is-compressed-unicode;
say "Character map size: ", $dawg.unicode-map.elems;Handling Mixed Content
# Starts compressed
my $dawg = DAWG.new;
$dawg.add($_) for <café naïve>; # Using compressed mode
# Adding high-diversity content forces UTF-32
$dawg.add("Hello 世界 🌍"); # Too many unique chars
# DAWG automatically rebuilds in UTF-32 modeConclusion
The 7-bit Unicode compression in this DAWG implementation provides substantial space savings for appropriate use cases without sacrificing functionality or speed. It's particularly valuable for mobile applications, embedded systems, and large-scale dictionary deployments where memory efficiency matters.