Skip to content

Commit 59da243

Browse files
Terraphim CIclaude
andcommitted
docs(ontology): add usage example
Demonstrates how to use the Dynamic Ontology components: - HGNC gene normalization with exact/fuzzy matching - Coverage signal calculation - Schema signal creation - Full extraction pipeline Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 2375abb commit 59da243

1 file changed

Lines changed: 193 additions & 0 deletions

File tree

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
//! Dynamic Ontology Usage Examples
2+
//!
3+
//! This example demonstrates how to use the Dynamic Ontology pipeline
4+
//! for extracting entities from text and normalizing them to an ontology.
5+
6+
use terraphim_types::hgnc::HgncNormalizer;
7+
use terraphim_types::{
8+
CoverageSignal, EntityType, ExtractedEntity, GroundingMetadata, RelationshipType, SchemaSignal,
9+
};
10+
11+
fn main() {
12+
println!("=== Dynamic Ontology Usage Examples ===\n");
13+
14+
// Example 1: HGNC Gene Normalization
15+
println!("1. HGNC Gene Normalization");
16+
println!("---------------------------");
17+
example_hgnc_normalization();
18+
19+
// Example 2: Coverage Signal
20+
println!("\n2. Coverage Signal Calculation");
21+
println!("-------------------------------");
22+
example_coverage_signal();
23+
24+
// Example 3: Schema Signal Creation
25+
println!("\n3. Schema Signal Creation");
26+
println!("-------------------------");
27+
example_schema_signal();
28+
29+
// Example 4: Full Pipeline
30+
println!("\n4. Full Extraction Pipeline");
31+
println!("-----------------------------");
32+
example_full_pipeline();
33+
}
34+
35+
fn example_hgnc_normalization() {
36+
// Create a new HGNC normalizer with oncology genes
37+
let normalizer = HgncNormalizer::new();
38+
39+
// Test exact match
40+
let result = normalizer.normalize("EGFR");
41+
println!(" EGFR -> {:?}", result.map(|g| g.normalized_label));
42+
43+
// Test alias (ERBB1 is an alias for EGFR)
44+
let result = normalizer.normalize("ERBB1");
45+
println!(
46+
" ERBB1 (alias) -> {:?}",
47+
result.map(|g| g.normalized_label)
48+
);
49+
50+
// Test alias (HER2 is an alias for ERBB2)
51+
let result = normalizer.normalize("HER2");
52+
println!(" HER2 (alias) -> {:?}", result.map(|g| g.normalized_label));
53+
54+
// Test fuzzy variant (EGFRvIII is a variant of EGFR)
55+
let result = normalizer.normalize("EGFRvIII");
56+
println!(
57+
" EGFRvIII (fuzzy) -> {:?}",
58+
result.map(|g| g.normalized_label)
59+
);
60+
61+
// Test TP53
62+
let result = normalizer.normalize("TP53");
63+
println!(" TP53 -> {:?}", result.map(|g| g.normalized_label));
64+
65+
// Test unknown gene
66+
let result = normalizer.normalize("XYZ123");
67+
println!(" XYZ123 (unknown) -> {:?}", result);
68+
}
69+
70+
fn example_coverage_signal() {
71+
// Create entities with varying grounding
72+
let entities = vec![
73+
ExtractedEntity {
74+
entity_type: EntityType::CancerDiagnosis,
75+
raw_value: "non-small cell lung cancer".to_string(),
76+
normalized_value: Some("Non-Small Cell Lung Cancer".to_string()),
77+
grounding: Some(GroundingMetadata::new(
78+
"http://example.org/nsclc".to_string(),
79+
"Non-Small Cell Lung Cancer".to_string(),
80+
"NCIt".to_string(),
81+
0.95,
82+
terraphim_types::NormalizationMethod::Exact,
83+
)),
84+
},
85+
ExtractedEntity {
86+
entity_type: EntityType::Drug,
87+
raw_value: "Osimertinib".to_string(),
88+
normalized_value: Some("Osimertinib".to_string()),
89+
grounding: Some(GroundingMetadata::new(
90+
"http://example.org/osimertinib".to_string(),
91+
"Osimertinib".to_string(),
92+
"NCIt".to_string(),
93+
0.98,
94+
terraphim_types::NormalizationMethod::Exact,
95+
)),
96+
},
97+
ExtractedEntity {
98+
entity_type: EntityType::GenomicVariant,
99+
raw_value: "Unknown mutation".to_string(),
100+
normalized_value: None,
101+
grounding: None,
102+
},
103+
];
104+
105+
// Calculate categories
106+
let categories: Vec<String> = entities
107+
.iter()
108+
.map(|e| e.normalized_value.clone().unwrap_or(e.raw_value.clone()))
109+
.collect();
110+
111+
// Count matched (entities with grounding)
112+
let matched = entities.iter().filter(|e| e.grounding.is_some()).count();
113+
114+
// Compute coverage with 0.7 threshold
115+
let coverage = CoverageSignal::compute(&categories, matched, 0.7);
116+
117+
println!(" Total categories: {}", coverage.total_categories);
118+
println!(" Matched categories: {}", coverage.matched_categories);
119+
println!(" Coverage ratio: {:.1}%", coverage.coverage_ratio * 100.0);
120+
println!(" Threshold: {:.0}%", coverage.threshold * 100.0);
121+
println!(" Needs review: {}", coverage.needs_review);
122+
}
123+
124+
fn example_schema_signal() {
125+
// Create a schema signal from extracted oncology data
126+
let entities = vec![
127+
ExtractedEntity {
128+
entity_type: EntityType::CancerDiagnosis,
129+
raw_value: "lung carcinoma".to_string(),
130+
normalized_value: Some("Lung Carcinoma".to_string()),
131+
grounding: Some(GroundingMetadata::new(
132+
"http://example.org/lung_carcinoma".to_string(),
133+
"Lung Carcinoma".to_string(),
134+
"NCIt".to_string(),
135+
0.95,
136+
terraphim_types::NormalizationMethod::Exact,
137+
)),
138+
},
139+
ExtractedEntity {
140+
entity_type: EntityType::GenomicVariant,
141+
raw_value: "EGFR L858R".to_string(),
142+
normalized_value: Some("EGFR L858R".to_string()),
143+
grounding: None,
144+
},
145+
];
146+
147+
let relationships = vec![];
148+
149+
let schema_signal = SchemaSignal {
150+
entities,
151+
relationships,
152+
confidence: 0.5,
153+
};
154+
155+
println!(" Entities: {}", schema_signal.entities.len());
156+
println!(" Relationships: {}", schema_signal.relationships.len());
157+
println!(" Confidence: {:.0}%", schema_signal.confidence * 100.0);
158+
}
159+
160+
fn example_full_pipeline() {
161+
println!(" Step 1: Extract entities from text");
162+
println!(
163+
" Input: 'Patient with EGFR L858R mutation in lung carcinoma treated with Osimertinib'"
164+
);
165+
println!(
166+
" -> Extract: EGFR L858R (GenomicVariant), lung carcinoma (CancerDiagnosis), Osimertinib (Drug)"
167+
);
168+
169+
println!("\n Step 2: Normalize entities to ontology");
170+
let normalizer = HgncNormalizer::new();
171+
172+
// Normalize EGFR
173+
let egfr = normalizer.normalize("EGFR");
174+
println!(
175+
" EGFR -> {}",
176+
egfr.as_ref()
177+
.map(|g| format!(
178+
"{} (score: {:.2})",
179+
g.normalized_label.as_ref().unwrap(),
180+
g.normalized_score.unwrap()
181+
))
182+
.unwrap_or_else(|| "Not found".to_string())
183+
);
184+
185+
println!("\n Step 3: Check coverage");
186+
println!(" 2/3 entities grounded = 66.7% coverage");
187+
println!(" Threshold: 70% -> needs review: true");
188+
189+
println!("\n Step 4: Review (if needed)");
190+
println!(" Review Agent suggests corrections for unmatched entities");
191+
192+
println!("\n Result: Grounded knowledge graph with coverage signal");
193+
}

0 commit comments

Comments
 (0)