Agent skill
similarity
Use when working with component similarity calculations - comparing MPNs, finding equivalent parts, implementing new similarity calculators, or understanding how component matching works.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/similarity-cantara-lib-electronic-compo
SKILL.md
Component Similarity Calculator Skill
This skill provides guidance for working with component similarity calculators in the lib-electronic-components library.
For metadata-driven similarity architecture, see /similarity-metadata:
- SpecImportance levels (CRITICAL, HIGH, MEDIUM, LOW, OPTIONAL)
- ToleranceRule types (exactMatch, percentageTolerance, minimumRequired, etc.)
- SimilarityProfile contexts (DESIGN_PHASE, REPLACEMENT, COST_OPTIMIZATION, etc.)
- Calculator integration patterns and gotchas
Overview
Similarity calculators determine how similar two electronic components are based on their MPNs (Manufacturer Part Numbers). They return a value between 0.0 (completely different) and 1.0 (identical or equivalent).
Core Interfaces
SimilarityCalculator (Simple)
public interface SimilarityCalculator {
double calculateSimilarity(String normalizedMpn1, String normalizedMpn2);
}
Used for generic calculators that don't need component type context.
ComponentSimilarityCalculator (Type-Aware)
public interface ComponentSimilarityCalculator {
boolean isApplicable(ComponentType type);
double calculateSimilarity(String mpn1, String mpn2, PatternRegistry registry);
}
Used for component-specific calculators that need to check applicability.
Standard Similarity Thresholds
private static final double HIGH_SIMILARITY = 0.9; // Equivalent/interchangeable
private static final double MEDIUM_SIMILARITY = 0.7; // Similar, may work as substitute
private static final double LOW_SIMILARITY = 0.3; // Same category but different specs
Available Calculators
| Calculator | Interface | Component Types | Key Features |
|---|---|---|---|
ResistorSimilarityCalculator |
Component | RESISTOR, RESISTOR_* | Value, package, tolerance |
CapacitorSimilarityCalculator |
Component | CAPACITOR, CAPACITOR_* | Value, voltage, dielectric |
TransistorSimilarityCalculator |
Component | TRANSISTOR, TRANSISTOR_* | NPN/PNP polarity, equivalent groups |
DiodeSimilarityCalculator |
Component | DIODE, DIODE_* | Signal/rectifier/zener types |
MosfetSimilarityCalculator |
Component | MOSFET, MOSFET_* | N/P channel, equivalent groups |
OpAmpSimilarityCalculator |
Component | OPAMP, OPAMP_* | Single/dual/quad, equivalent families |
VoltageRegulatorSimilarityCalculator |
Component | VOLTAGE_REGULATOR* | Fixed (78xx) vs adjustable (LM317) |
LogicICSimilarityCalculator |
Component | LOGIC_IC, IC | 74xx/CD4000 series, function groups |
LEDSimilarityCalculator |
Component | LED, LED_* | Color, bins, families |
MemorySimilarityCalculator |
Component | MEMORY, MEMORY_* | I2C/SPI EEPROM, Flash equivalents |
SensorSimilarityCalculator |
Component | SENSOR, TEMPERATURE_SENSOR, ACCELEROMETER | Sensor families, package variants |
ConnectorSimilarityCalculator |
Component | CONNECTOR, CONNECTOR_* | Pin count, pitch, family |
MicrocontrollerSimilarityCalculator |
Component | MICROCONTROLLER* | Series, package, manufacturer |
MCUSimilarityCalculator |
Simple | (generic) | Family, series, features |
PassiveComponentCalculator |
Simple | (generic) | Value, size code, tolerance |
LevenshteinCalculator |
Simple | (generic) | String edit distance |
DefaultSimilarityCalculator |
Simple | (generic) | Prefix, numeric, suffix weights |
Creating a New Similarity Calculator
1. Implement the Interface
public class NewComponentSimilarityCalculator implements ComponentSimilarityCalculator {
private static final double HIGH_SIMILARITY = 0.9;
private static final double MEDIUM_SIMILARITY = 0.7;
private static final double LOW_SIMILARITY = 0.3;
@Override
public boolean isApplicable(ComponentType type) {
if (type == null) return false;
return type == ComponentType.NEW_COMPONENT ||
type.name().startsWith("NEW_COMPONENT_");
}
@Override
public double calculateSimilarity(String mpn1, String mpn2, PatternRegistry registry) {
if (mpn1 == null || mpn2 == null) return 0.0;
// Check if both are the component type we handle
if (!isComponentType(mpn1) || !isComponentType(mpn2)) {
return 0.0;
}
// Compare components
// ...
return similarity;
}
}
2. Key Design Principles
- Return 0.0 for null inputs - Always check for null MPNs and registry
- Return 0.0 for non-matching types - If the MPN isn't your component type
- Use equivalent groups - Define known equivalent parts (e.g., 2N2222 ≈ PN2222)
- Consider package variants - Same part in different package should be high similarity
- Ensure symmetry -
sim(A,B) == sim(B,A) - Keep in [0.0, 1.0] - Never return values outside this range
3. Common Patterns
Equivalent Groups
private static final Map<String, Set<String>> EQUIVALENT_GROUPS = new HashMap<>();
static {
EQUIVALENT_GROUPS.put("2N2222", Set.of("2N2222", "2N2222A", "PN2222", "PN2222A"));
}
private boolean areEquivalent(String mpn1, String mpn2) {
for (Set<String> group : EQUIVALENT_GROUPS.values()) {
if (group.contains(mpn1) && group.contains(mpn2)) {
return true;
}
}
return false;
}
Package Code Extraction
private String extractBasePart(String mpn) {
// Remove common package suffixes
return mpn.replaceAll("(?:CT|T|N|P|DG|PW|DR)$", "");
}
Polarity/Type Checking
private boolean areSamePolarity(String mpn1, String mpn2) {
boolean isNPN1 = NPN_PATTERNS.stream().anyMatch(mpn1::matches);
boolean isNPN2 = NPN_PATTERNS.stream().anyMatch(mpn2::matches);
return isNPN1 == isNPN2;
}
Testing
Test Structure
@Nested
@DisplayName("isApplicable tests")
class IsApplicableTests { /* ... */ }
@Nested
@DisplayName("Equivalent groups tests")
class EquivalentGroupTests { /* ... */ }
@Nested
@DisplayName("Edge cases and null handling")
class EdgeCaseTests { /* ... */ }
@Nested
@DisplayName("Symmetry and property tests")
class PropertyTests { /* ... */ }
Run Tests
# All similarity calculator tests
mvn test -Dtest="*SimilarityCalculatorTest,PassiveComponentCalculatorTest"
# Specific calculator
mvn test -Dtest=TransistorSimilarityCalculatorTest
Related Skills
/similarity-resistor- Resistor similarity details/similarity-transistor- Transistor equivalent groups and polarity/similarity-mosfet- MOSFET N/P channel comparison/similarity-opamp- Op-amp families and equivalents/similarity-memory- Memory IC equivalents (I2C/SPI EEPROM, Flash)/similarity-sensor- Sensor family comparison/similarity-led- LED bins and color temperature/similarity-regulator- Voltage regulator comparison (78xx, LM317)/similarity-logic- Logic IC function groups (74xx, CD4000)
Metadata-Driven Architecture (January 2026)
The similarity system now uses a metadata-driven architecture for configurable, type-specific similarity rules.
Conversion Status: 12 of 17 calculators converted (71% complete)
| Calculator | Status | PR | Conversion Date |
|---|---|---|---|
| ResistorSimilarityCalculator | ✅ Converted | - | Jan 2026 |
| CapacitorSimilarityCalculator | ✅ Converted | - | Jan 2026 |
| TransistorSimilarityCalculator | ✅ Converted | - | Jan 2026 |
| DiodeSimilarityCalculator | ✅ Converted | - | Jan 2026 |
| MosfetSimilarityCalculator | ✅ Converted | - | Jan 2026 |
| VoltageRegulatorSimilarityCalculator | ✅ Converted | - | Jan 2026 |
| OpAmpSimilarityCalculator | ✅ Converted | #116 | Jan 2026 |
| MemorySimilarityCalculator | ✅ Converted | #117 | Jan 2026 |
| LEDSimilarityCalculator | ✅ Converted | #118 | Jan 2026 |
| ConnectorSimilarityCalculator | ✅ Converted | (pre-existing) | Jan 2026 |
| LogicICSimilarityCalculator | ✅ Converted | #119 | Jan 2026 |
| SensorSimilarityCalculator | ✅ Converted | #120 | Jan 2026 |
| MicrocontrollerSimilarityCalculator | ⏳ Legacy | - | - |
| MCUSimilarityCalculator | ⏳ Legacy | - | - |
| PassiveComponentCalculator | ⏳ Legacy | - | - |
| LevenshteinCalculator | ⏳ Legacy | - | - |
| DefaultSimilarityCalculator | ⏳ Legacy | - | - |
Core Metadata Classes
| Class | Purpose |
|---|---|
ComponentTypeMetadata |
Defines specs, importance levels, tolerance rules per component type |
ComponentTypeMetadataRegistry |
Singleton registry mapping ComponentType → metadata |
SpecImportance |
Enum: CRITICAL (1.0), HIGH (0.7), MEDIUM (0.4), LOW (0.2), OPTIONAL (0.0) |
ToleranceRule |
Interface for comparing spec values (ExactMatch, Percentage, MinRequired, MaxAllowed, Range) |
SimilarityProfile |
Context-aware profiles (DESIGN_PHASE, REPLACEMENT, COST_OPTIMIZATION, PERFORMANCE_UPGRADE, EMERGENCY_SOURCING) |
Retrieving Metadata
ComponentTypeMetadataRegistry registry = ComponentTypeMetadataRegistry.getInstance();
// Get metadata for a component type
Optional<ComponentTypeMetadata> metadata = registry.getMetadata(ComponentType.RESISTOR);
// Query specs
if (metadata.isPresent()) {
ComponentTypeMetadata meta = metadata.get();
// Check if spec is critical
boolean critical = meta.isCritical("resistance"); // true
// Get tolerance rule for a spec
SpecConfig config = meta.getSpecConfig("resistance");
if (config != null) {
ToleranceRule rule = config.getToleranceRule();
SpecImportance importance = config.getImportance();
}
// Get all configured specs
Set<String> allSpecs = meta.getAllSpecs();
}
Pre-Registered Types (10)
RESISTOR, CAPACITOR, MOSFET, TRANSISTOR, DIODE, OPAMP, MICROCONTROLLER, MEMORY, LED, CONNECTOR
Each type has:
- Critical specs (must match for similarity)
- High/Medium/Low importance specs (contribute to score)
- Tolerance rules (how to compare values)
- Default similarity profile
Context-Aware Profiles
Adjust importance multipliers based on use case:
| Profile | Threshold | CRITICAL | HIGH | MEDIUM | LOW | Use Case |
|---|---|---|---|---|---|---|
| DESIGN_PHASE | 0.85 | 1.0 | 0.9 | 0.7 | 0.4 | Exact match for new designs |
| REPLACEMENT | 0.75 | 1.0 | 0.7 | 0.4 | 0.2 | Default: Direct replacement |
| COST_OPTIMIZATION | 0.60 | 1.0 | 0.4 | 0.2 | 0.0 | Maintain critical specs only |
| EMERGENCY_SOURCING | 0.50 | 0.8 | 0.4 | 0.2 | 0.0 | Urgent, relaxed requirements |
// Check if similarity meets threshold for a profile
SimilarityProfile profile = SimilarityProfile.REPLACEMENT;
double similarity = 0.78;
boolean passes = profile.meetsThreshold(similarity); // true
// Get effective weight for a spec
double effectiveWeight = profile.getEffectiveWeight(SpecImportance.HIGH); // 0.7 × 0.7 = 0.49
Converted Calculator Implementation Pattern
Calculators converted to metadata-driven approach follow this pattern:
@Override
public double calculateSimilarity(String mpn1, String mpn2, PatternRegistry registry) {
if (mpn1 == null || mpn2 == null) return 0.0;
// Try metadata-driven approach first
Optional<ComponentTypeMetadata> metadataOpt = metadataRegistry.getMetadata(ComponentType.OPAMP);
if (metadataOpt.isPresent()) {
logger.trace("Using metadata-driven similarity calculation");
return calculateMetadataDrivenSimilarity(mpn1, mpn2, metadataOpt.get());
}
// Fallback to legacy pattern-based approach
logger.trace("No metadata found, using legacy approach");
return calculateLegacySimilarity(mpn1, mpn2);
}
private double calculateMetadataDrivenSimilarity(String mpn1, String mpn2, ComponentTypeMetadata metadata) {
SimilarityProfile profile = metadata.getDefaultProfile();
// Extract specs from MPNs
String config1 = extractConfiguration(mpn1); // e.g., "dual", "quad"
String config2 = extractConfiguration(mpn2);
// ... extract other specs
// Short-circuit check for CRITICAL incompatibility
if (!config1.isEmpty() && !config2.isEmpty() && !config1.equals(config2)) {
return LOW_SIMILARITY;
}
double totalScore = 0.0;
double maxPossibleScore = 0.0;
// Compare each spec with weighted scoring
ComponentTypeMetadata.SpecConfig configSpec = metadata.getSpecConfig("configuration");
if (configSpec != null && !config1.isEmpty() && !config2.isEmpty()) {
ToleranceRule rule = configSpec.getToleranceRule();
SpecValue<String> orig = new SpecValue<>(config1, SpecUnit.NONE);
SpecValue<String> cand = new SpecValue<>(config2, SpecUnit.NONE);
double specScore = rule.compare(orig, cand);
double specWeight = profile.getEffectiveWeight(configSpec.getImportance());
totalScore += specScore * specWeight;
maxPossibleScore += specWeight;
}
// Repeat for other specs (family, package, etc.)
// ...
double similarity = maxPossibleScore > 0 ? totalScore / maxPossibleScore : 0.0;
// Apply boosts for equivalent groups
if (areEquivalentParts(mpn1, mpn2)) {
similarity = Math.max(similarity, HIGH_SIMILARITY);
}
return similarity;
}
Key Features of Converted Calculators:
- Dual-path approach - Try metadata first, fall back to legacy
- Short-circuit checks - Early return for CRITICAL spec mismatches
- Weighted scoring -
totalScore / maxPossibleScoreformula - Spec extraction - Component-specific methods to extract values from MPNs
- Equivalent boost - Apply known equivalence rules after scoring
- Profile support - Use
getEffectiveWeight()for context-aware weights
Converted Calculator Specs
| Calculator | Critical Specs | High Importance | Medium Importance | Low Importance |
|---|---|---|---|---|
| OpAmp | configuration | family | package | - |
| Memory | memoryType, capacity | interface | - | package |
| LED | color | family, brightness | - | package |
| Connector | pinCount, pitch | family | mountingType | - |
| LogicIC | function | series, technology | - | package |
| Sensor | sensorType | family | interface | package |
Migration Path
For converting existing calculators:
- Add imports:
SimilarityProfile,ToleranceRule,SpecUnit,SpecValue - Modify
calculateSimilarity()to check for metadata first - Implement
calculateMetadataDrivenSimilarity()method - Add spec extraction helper methods
- Update tests to use threshold assertions (
>= HIGH_SIMILARITY) - Run full test suite to verify backward compatibility
For new calculators:
- Start with metadata-driven approach from the beginning
- Define specs in
ComponentTypeMetadataRegistry - Implement spec extraction methods
- Use
SpecValuewrapper for type-safe comparison - Apply context-aware profiles with
SimilarityProfile
See CLAUDE.md § "Metadata-Driven Similarity Framework" for complete architecture details.
Learnings & Quirks
General Patterns
- Always normalize MPNs to uppercase before comparison
- Package suffixes vary by manufacturer - don't assume consistency
- Some calculators return HIGH_SIMILARITY (0.9) for identical parts, not 1.0
Edge Cases
- Parts starting with digits (e.g., "2N2222") need special regex handling -
^[A-Za-z]+won't match - Some MPNs have significant hyphens (Molex) vs decorative hyphens (TI)
- Reel/tape suffixes (-RL, -T, -TR) should generally be ignored
Metadata System Gotchas (January 2026)
SpecValue Instantiation:
// NO static factory - use constructor
SpecValue<Double> v = new SpecValue<>(100.0, SpecUnit.FARAD); // ✓
SpecValue<Double> v = SpecValue.of(100.0); // ✗ Does not exist
API Return Types:
// Registry returns Optional, metadata methods return direct values
Optional<ComponentTypeMetadata> meta = registry.getMetadata(type); // Optional
SpecConfig config = metadata.getSpecConfig("resistance"); // Can be null
boolean critical = metadata.isCritical("resistance"); // false if not found
Singleton Side Effects:
- Registry is shared across all tests
- Custom registrations persist
- Use unregistered types (CRYSTAL, FUSE) for tests, not RESISTOR/CAPACITOR
Profile Multiplier Values:
- COST_OPTIMIZATION maintains CRITICAL=1.0 (safety specs never compromised)
- EMERGENCY_SOURCING relaxes CRITICAL to 0.8 (only for urgent scenarios)
Builder Validation:
ComponentTypeMetadata.builder(null).build(); // IllegalArgumentException
ComponentTypeMetadata.builder(ComponentType.IC).build(); // IllegalStateException (no specs)
See Also
Advanced Skills
/similarity-calculator-architecture- Calculator registration, ordering, and the OpAmp IC interception bug/metadata-driven-similarity-conversion- Converting calculators to metadata-driven approach/component-spec-extraction- How to extract specs from MPNs for comparison/equivalent-group-identification- Hardcoded equivalent groups across calculators
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?