General-purpose phonetic similarity detection — homophones, near-homophones, and sound-alike analysis
Project description
phonemenal
Phonetic similarity and homophone detection library for Python — near-homophones, sound-alike collisions, and variant generation.
Features
- Four scoring algorithms (all normalized 0.0–1.0):
- PPC-A — Positional Phoneme Correlation (Absolute)
- PLD — Phoneme Levenshtein Distance at syllable level
- PED — Phoneme edit distance at phoneme level
- LCS — Longest Common Subsequence ratio on phoneme sequences
- Composite scoring with configurable weights
- Exact homophone discovery via CMU Pronouncing Dictionary inversion
- Near-homophone search with threshold-based fuzzy matching
- Variant generation — phonetic substitutions, morphological variants, and separator permutations
- Compound word splitting with homophone permutation recombination
- Fast fallback encoder for words not in the dictionary (brand names, neologisms)
- Batch collision scanning — forward and reverse scanning pipelines
- LLM-powered deep analysis (optional, via Anthropic/OpenAI API or local agents)
- Rich CLI with formatted tables and JSON output
Install
pip install phonemenal
# With LLM support
pip install phonemenal[llm]
Quick Start
from phonemenal import similarity, homophones, variants, splitting, fallback, scanning
# Compare two words (all scores 0.0–1.0)
similarity.ppc("crowd", "crown") # PPC-A
similarity.pld("elastic", "fantastic") # PLD
similarity.ped("cat", "bat") # PED
similarity.lcs("packaging", "packages") # LCS
similarity.composite("crowd", "crown") # Weighted average
# Find exact homophones
homophones.find("blue") # → ["blew"]
# Find near-homophones
homophones.find_similar("crowd", min_score=0.7)
# Generate sound-alike variants
variants.generate("flask") # → {"phlask", "flazk", ...}
variants.generate_morphological("packaging") # → {"packaged", "packager", ...}
# Split compound words & generate permutations
splitting.split("bluevoyage") # → ["blue", "voyage"]
splitting.homophone_permutations("bluevoyage") # → all recombinations
# Fallback for non-dictionary words
fallback.phonetic_key("numpy") # → "nAmpY"
fallback.phonetic_key("numpie") # → "nAmpY" (same key)
# Batch collision scanning
matches = scanning.scan(
candidates=["numpie", "phlask"],
known_names=["numpy", "flask"],
)
# Composite tuning for CMU-backed comparisons
matches = scanning.scan(
candidates=["cat"],
known_names=["bat"],
use_composite=True,
edit_mode="length",
)
CLI
phonemenal similarity crowd crown # compare with all algorithms
phonemenal similarity crowd crown -a ppc # specific algorithm
phonemenal homophones blue # exact homophones
phonemenal variants flask -m # phonetic + morphological variants
phonemenal split bluevoyage -p # split & show permutations
phonemenal compare crowd crown # full comparison report
phonemenal compare crowd crown -j # JSON output
phonemenal analyze numpy --provider anthropic # LLM deep analysis
phonemenal prompt numpy | pbcopy # get raw prompt
Algorithms
PPC-A (Positional Phoneme Correlation — Absolute)
Builds positional phoneme combinations by traversing forward and reverse directions with padding, then measures set intersection. Captures how much of the positional phoneme structure two words share.
PLD (Phoneme Levenshtein Distance)
Syllable-level edit distance using the CMU dict's stress markers to split phonemes into syllable groups. Each syllable is an atomic unit, so the distance reflects how many whole syllables differ — matching how sound flows in speech.
PED (Phoneme Edit Distance)
Phoneme-level edit distance on stress-stripped CMU pronunciations. This complements PLD for short and monosyllabic words where syllable-level scoring is too coarse.
LCS (Longest Common Subsequence)
Ratio of the longest common subsequence length to the total sequence length. Applied to phoneme sequences from CMU dict, or to raw character strings as a fallback.
Composite
Weighted average of PPC-A, an adaptive edit channel, and LCS. By default the edit channel uses max(PLD, PED), and callers can switch to a length-based selector for monosyllables vs. longer words. Default weights are (1.0, 2.0, 1.0) to emphasize edit similarity. All bounded 0.0–1.0.
Note: the default composite score changed in 0.2.0, so scores are not directly comparable with 0.1.x.
Fallback Encoder
Simplified Metaphone-inspired encoding for words not in the CMU dict. Applies digraph replacement, vowel normalization, and character collapsing to produce phonetic keys. Sound-alike names produce the same or similar keys — e.g. numpy and numpie both map to nAmpY.
Documentation
Full documentation is available at brokensound77.github.io/phonemenal.
License
Apache-2.0
Background and Research
This project stems from previous research on homophonic collisions conducted by Reagan Short and Justin Ibarra. You can check out our TROOPERS 2023 talk: Homophonic Collisions: Hold me closer Tony Danza for more background on the problem space and their approach to phonetic similarity detection.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file phonemenal-0.2.0.tar.gz.
File metadata
- Download URL: phonemenal-0.2.0.tar.gz
- Upload date:
- Size: 1.1 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a1b8f4c54a83951205a4bbf5ac8d087ae4cd3cb5697a28b8252c506ef29d30c1
|
|
| MD5 |
2e0f95cffc90899661c4c322885c1b74
|
|
| BLAKE2b-256 |
f1f7c474fe9ffe278d9215b83187f137f335f5d95b0ea6281ff8ec4dc8383e97
|
Provenance
The following attestation bundles were made for phonemenal-0.2.0.tar.gz:
Publisher:
publish.yml on brokensound77/phonemenal
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
phonemenal-0.2.0.tar.gz -
Subject digest:
a1b8f4c54a83951205a4bbf5ac8d087ae4cd3cb5697a28b8252c506ef29d30c1 - Sigstore transparency entry: 1281042214
- Sigstore integration time:
-
Permalink:
brokensound77/phonemenal@ba231246f6a3460cf853a2fc8e9ecf610d52c571 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/brokensound77
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ba231246f6a3460cf853a2fc8e9ecf610d52c571 -
Trigger Event:
push
-
Statement type:
File details
Details for the file phonemenal-0.2.0-py3-none-any.whl.
File metadata
- Download URL: phonemenal-0.2.0-py3-none-any.whl
- Upload date:
- Size: 30.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fd344531160294176d007601ca14b7087544a4e682c3dc9d599bb0f8c534be03
|
|
| MD5 |
4953ac7471fa35c3f0d8d99011e4e7a3
|
|
| BLAKE2b-256 |
11c574179ebc42b1e2f94833307f217b06a9f070e69d92d1667458353146d425
|
Provenance
The following attestation bundles were made for phonemenal-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on brokensound77/phonemenal
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
phonemenal-0.2.0-py3-none-any.whl -
Subject digest:
fd344531160294176d007601ca14b7087544a4e682c3dc9d599bb0f8c534be03 - Sigstore transparency entry: 1281042221
- Sigstore integration time:
-
Permalink:
brokensound77/phonemenal@ba231246f6a3460cf853a2fc8e9ecf610d52c571 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/brokensound77
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ba231246f6a3460cf853a2fc8e9ecf610d52c571 -
Trigger Event:
push
-
Statement type: