Skip to content

Commit f12fc15

Browse files
feat(types): native type-system decoration layer (#26)
Add Term::Sigma + TypeInfo sidecar (8 dimensions: Universe, Multiplicity, EffectRow, refinement, Modality, TemporalOp, Semiring, relational_arity). Wire Idris2 QTT, F* effects/refinement, Dedukti Sigma, GNN type-info edges. Sigma rendering in all backends.
1 parent e44815a commit f12fc15

31 files changed

Lines changed: 413 additions & 17 deletions

src/rust/agent/explanations.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,18 @@ impl ExplanationGenerator {
301301
self.format_term(body)
302302
)
303303
},
304+
Term::Sigma {
305+
param,
306+
param_type,
307+
body,
308+
} => {
309+
format!(
310+
"∃{}:{}. {}",
311+
param,
312+
self.format_term(param_type),
313+
self.format_term(body)
314+
)
315+
},
304316
Term::App { func, args } => {
305317
let args_str: Vec<_> = args.iter().map(|a| self.format_term(a)).collect();
306318
format!("({} {})", self.format_term(func), args_str.join(" "))

src/rust/aspect.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,9 @@ pub struct TheoremFeatures {
417417
/// Pi type (dependent function) count
418418
pub pi_count: usize,
419419

420+
/// Sigma type (dependent pair) count
421+
pub sigma_count: usize,
422+
420423
/// Universe levels used
421424
pub universe_levels: HashSet<usize>,
422425

@@ -650,6 +653,9 @@ impl RuleBasedTagger {
650653
},
651654
Term::Pi {
652655
param_type, body, ..
656+
}
657+
| Term::Sigma {
658+
param_type, body, ..
653659
} => {
654660
self.extract_symbols_recursive(param_type, symbols);
655661
self.extract_symbols_recursive(body, symbols);
@@ -746,6 +752,11 @@ impl AspectTagger for RuleBasedTagger {
746752
total_matches += features.pi_count;
747753
}
748754

755+
if features.sigma_count > 0 {
756+
*aspect_counts.entry(Aspect::DependentTypes).or_insert(0) += features.sigma_count;
757+
total_matches += features.sigma_count;
758+
}
759+
749760
if !features.universe_levels.is_empty() {
750761
*aspect_counts.entry(Aspect::Universes).or_insert(0) += 1;
751762
total_matches += 1;
@@ -807,6 +818,13 @@ impl RuleBasedTagger {
807818
self.analyze_term(param_type, features, depth + 1);
808819
self.analyze_term(body, features, depth + 1);
809820
},
821+
Term::Sigma {
822+
param_type, body, ..
823+
} => {
824+
features.sigma_count += 1;
825+
self.analyze_term(param_type, features, depth + 1);
826+
self.analyze_term(body, features, depth + 1);
827+
},
810828
Term::Universe(level) | Term::Type(level) | Term::Sort(level) => {
811829
features.universe_levels.insert(*level);
812830
},

src/rust/core.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ pub enum Term {
3333
body: Box<Term>,
3434
},
3535

36+
/// Dependent pair / sum (Sigma type) Σ(x: A). B
37+
Sigma {
38+
param: String,
39+
param_type: Box<Term>,
40+
body: Box<Term>,
41+
},
42+
3643
/// Type universe at level
3744
Type(usize),
3845

@@ -121,6 +128,13 @@ impl fmt::Display for Term {
121128
} => {
122129
write!(f, "(Π {}: {}. {})", param, param_type, body)
123130
},
131+
Term::Sigma {
132+
param,
133+
param_type,
134+
body,
135+
} => {
136+
write!(f, "(Σ {}: {}. {})", param, param_type, body)
137+
},
124138
Term::Type(level) => write!(f, "Type{}", level),
125139
Term::Sort(level) => write!(f, "Sort{}", level),
126140
Term::Universe(level) => write!(f, "Type{}", level),
@@ -189,6 +203,10 @@ pub struct Hypothesis {
189203

190204
/// Optional body (for definitions)
191205
pub body: Option<Term>,
206+
207+
/// Optional native type-system decoration.
208+
#[serde(default, skip_serializing_if = "Option::is_none")]
209+
pub type_info: Option<crate::types::TypeInfo>,
192210
}
193211

194212
/// Proof context with available premises
@@ -222,13 +240,17 @@ pub struct Definition {
222240
pub name: String,
223241
pub ty: Term,
224242
pub body: Term,
243+
#[serde(default, skip_serializing_if = "Option::is_none")]
244+
pub type_info: Option<crate::types::TypeInfo>,
225245
}
226246

227247
/// A variable declaration
228248
#[derive(Debug, Clone, Serialize, Deserialize)]
229249
pub struct Variable {
230250
pub name: String,
231251
pub ty: Term,
252+
#[serde(default, skip_serializing_if = "Option::is_none")]
253+
pub type_info: Option<crate::types::TypeInfo>,
232254
}
233255

234256
/// A proof tactic/command

src/rust/exchange/dedukti.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,18 @@ impl DeduktiExporter {
211211
Self::term_to_dedukti(body)
212212
)
213213
},
214+
Term::Sigma {
215+
param,
216+
param_type,
217+
body,
218+
} => {
219+
format!(
220+
"(dk_sigma {} ({} => {}))",
221+
Self::term_to_dedukti(param_type),
222+
param,
223+
Self::term_to_dedukti(body)
224+
)
225+
},
214226
Term::Type(level) => format!("Type {}", level),
215227
Term::Sort(level) => format!("Sort {}", level),
216228
Term::Universe(level) => format!("Type {}", level),
@@ -224,6 +236,32 @@ impl DeduktiExporter {
224236
if trimmed.starts_with('(') && trimmed.ends_with(')') {
225237
// Unwrap parentheses and recurse
226238
Self::dedukti_to_term(&trimmed[1..trimmed.len() - 1])
239+
} else if trimmed.starts_with("dk_sigma ") {
240+
// Sigma type: dk_sigma A (x => B)
241+
let rest = trimmed.trim_start_matches("dk_sigma ").trim();
242+
// Split into the type part and the binder part (x => B)
243+
if let Some(paren_start) = rest.find('(') {
244+
let type_part = rest[..paren_start].trim();
245+
let binder_part = rest[paren_start..].trim();
246+
let inner = if binder_part.starts_with('(') && binder_part.ends_with(')') {
247+
&binder_part[1..binder_part.len() - 1]
248+
} else {
249+
binder_part
250+
};
251+
if let Some(arrow_pos) = inner.find("=>") {
252+
let param = inner[..arrow_pos].trim().to_string();
253+
let body_str = inner[arrow_pos + 2..].trim();
254+
Term::Sigma {
255+
param,
256+
param_type: Box::new(Self::dedukti_to_term(type_part)),
257+
body: Box::new(Self::dedukti_to_term(body_str)),
258+
}
259+
} else {
260+
Term::Const(trimmed.to_string())
261+
}
262+
} else {
263+
Term::Const(trimmed.to_string())
264+
}
227265
} else if trimmed.contains("->") {
228266
// Pi type: A -> B
229267
let parts: Vec<&str> = trimmed.splitn(2, "->").collect();
@@ -416,6 +454,28 @@ mod tests {
416454
assert_eq!(dk, "x");
417455
}
418456

457+
#[test]
458+
fn test_term_to_dedukti_sigma() {
459+
let term = Term::Sigma {
460+
param: "x".to_string(),
461+
param_type: Box::new(Term::Const("Nat".to_string())),
462+
body: Box::new(Term::Const("Prop".to_string())),
463+
};
464+
let dk = DeduktiExporter::term_to_dedukti(&term);
465+
assert!(dk.contains("dk_sigma"), "Sigma should render as dk_sigma, got: {}", dk);
466+
assert!(dk.contains("Nat"), "Sigma param type should appear, got: {}", dk);
467+
}
468+
469+
#[test]
470+
fn test_dedukti_to_term_sigma() {
471+
let dk = "dk_sigma Nat (x => Prop)";
472+
let term = DeduktiExporter::dedukti_to_term(dk);
473+
match term {
474+
Term::Sigma { ref param, .. } => assert_eq!(param, "x"),
475+
_ => panic!("Expected Sigma term, got: {:?}", term),
476+
}
477+
}
478+
419479
#[test]
420480
fn test_import_with_definition() {
421481
let module = DeduktiModule {

src/rust/gnn/embeddings.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,11 @@ impl TermFeatureExtractor {
184184
// Feature [29]: Contains quantifier (forall, exists, pi)
185185
if offset < FEATURE_DIM {
186186
features[offset] = if node.label.contains("pi_")
187+
|| node.label.contains("sigma_")
187188
|| node.label.contains("forall")
188189
|| node.label.contains("exists")
189190
|| node.label.contains("Pi")
191+
|| node.label.contains("Sigma")
190192
{
191193
1.0
192194
} else {
@@ -304,6 +306,8 @@ fn infer_term_kind_from_label(label: &str) -> usize {
304306
3 // Lambda
305307
} else if label.starts_with("pi_") {
306308
4 // Pi
309+
} else if label.starts_with("sigma_") {
310+
13 // Sigma
307311
} else if label.starts_with("let_") {
308312
7 // Let
309313
} else if label.starts_with("fix_") {
@@ -344,6 +348,7 @@ fn term_kind_index(term: &Term) -> usize {
344348
Term::Hole(_) => 10,
345349
Term::Meta(_) => 11,
346350
Term::ProverSpecific { .. } => 12,
351+
Term::Sigma { .. } => 13,
347352
}
348353
}
349354

@@ -370,6 +375,9 @@ fn term_depth(term: &Term) -> usize {
370375
},
371376
Term::Pi {
372377
param_type, body, ..
378+
}
379+
| Term::Sigma {
380+
param_type, body, ..
373381
} => 1 + term_depth(param_type).max(term_depth(body)),
374382
Term::Let {
375383
ty, value, body, ..
@@ -417,7 +425,7 @@ fn term_arity(term: &Term) -> usize {
417425
1
418426
}
419427
},
420-
Term::Pi { .. } => 2, // param_type + body
428+
Term::Pi { .. } | Term::Sigma { .. } => 2, // param_type + body
421429
Term::Let { ty, .. } => {
422430
if ty.is_some() {
423431
3

0 commit comments

Comments
 (0)