Skip to main content

omena_abstract_value/
cascade_family.rs

1use crate::AbstractPropertyValueV0;
2use serde::Serialize;
3use std::collections::{BTreeMap, BTreeSet};
4
5/// Research-staged cascade-family substrate for M6 positioning.
6///
7/// This is intentionally framing-neutral: it records context-indexed value
8/// families and restriction morphisms without claiming a sheaf/cosheaf theorem
9/// or committing paper-stage terminology.
10#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
11#[serde(rename_all = "camelCase")]
12pub struct CascadeValueFamilyV0 {
13    pub schema_version: &'static str,
14    pub product: &'static str,
15    pub framing: &'static str,
16    pub claim_level: &'static str,
17    pub property_name: String,
18    pub supported_readings: Vec<&'static str>,
19    pub context_value_count: usize,
20    pub restriction_map_count: usize,
21    pub property_consistent: bool,
22    pub dangling_restriction_count: usize,
23    pub theorem_claimed: bool,
24    pub members: Vec<CascadeValueFamilyMemberV0>,
25    pub restriction_maps: Vec<CascadeRestrictionMapV0>,
26}
27
28#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize)]
29#[serde(rename_all = "camelCase")]
30pub struct CascadeContextV0 {
31    pub id: String,
32    #[serde(skip_serializing_if = "Option::is_none")]
33    pub parent_id: Option<String>,
34    pub selectors: Vec<String>,
35    pub conditions: Vec<String>,
36    pub layers: Vec<String>,
37}
38
39#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
40#[serde(rename_all = "camelCase")]
41pub struct CascadeValueFamilyMemberV0 {
42    pub context: CascadeContextV0,
43    pub value: AbstractPropertyValueV0,
44}
45
46#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize)]
47#[serde(rename_all = "camelCase")]
48pub struct CascadeRestrictionMapV0 {
49    pub parent_context_id: String,
50    pub child_context_id: String,
51    pub morphism: CascadeMorphismV0,
52}
53
54#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize)]
55#[serde(rename_all = "camelCase")]
56pub struct CascadeMorphismV0 {
57    pub kind: &'static str,
58    pub direction: &'static str,
59    pub preserves_property_name: bool,
60    pub evidence: Vec<&'static str>,
61}
62
63pub fn summarize_cascade_value_family_v0(
64    property_name: impl Into<String>,
65    members: Vec<CascadeValueFamilyMemberV0>,
66    restriction_maps: Vec<CascadeRestrictionMapV0>,
67) -> CascadeValueFamilyV0 {
68    let property_name = property_name.into();
69    let mut members = members;
70    members.sort_by(|left, right| left.context.id.cmp(&right.context.id));
71    members.dedup_by(|left, right| left.context.id == right.context.id);
72
73    let mut restriction_maps = restriction_maps;
74    restriction_maps.sort();
75    restriction_maps.dedup();
76
77    let context_ids = members
78        .iter()
79        .map(|member| member.context.id.as_str())
80        .collect::<BTreeSet<_>>();
81    let property_consistent = members
82        .iter()
83        .all(|member| property_value_name(&member.value) == property_name);
84    let dangling_restriction_count = restriction_maps
85        .iter()
86        .filter(|restriction| {
87            !context_ids.contains(restriction.parent_context_id.as_str())
88                || !context_ids.contains(restriction.child_context_id.as_str())
89        })
90        .count();
91    let restriction_map_count = restriction_maps.len();
92
93    CascadeValueFamilyV0 {
94        schema_version: "0",
95        product: "omena-abstract-value.cascade-value-family",
96        framing: "framingNeutralCascadeFamily",
97        claim_level: "researchStagedSubstrate",
98        property_name,
99        supported_readings: vec!["presheafCompatible", "cosheafCompatible"],
100        context_value_count: members.len(),
101        restriction_map_count,
102        property_consistent,
103        dangling_restriction_count,
104        theorem_claimed: false,
105        members,
106        restriction_maps,
107    }
108}
109
110pub fn derive_cascade_restriction_maps_v0(
111    members: &[CascadeValueFamilyMemberV0],
112) -> Vec<CascadeRestrictionMapV0> {
113    let context_ids = members
114        .iter()
115        .map(|member| member.context.id.as_str())
116        .collect::<BTreeSet<_>>();
117    let mut maps = members
118        .iter()
119        .filter_map(|member| {
120            let parent_id = member.context.parent_id.as_deref()?;
121            context_ids
122                .contains(parent_id)
123                .then(|| CascadeRestrictionMapV0 {
124                    parent_context_id: parent_id.to_string(),
125                    child_context_id: member.context.id.clone(),
126                    morphism: cascade_context_refinement_morphism_v0(),
127                })
128        })
129        .collect::<Vec<_>>();
130    maps.sort();
131    maps.dedup();
132    maps
133}
134
135pub fn cascade_context_refinement_morphism_v0() -> CascadeMorphismV0 {
136    CascadeMorphismV0 {
137        kind: "contextRefinement",
138        direction: "parentToChildRestriction",
139        preserves_property_name: true,
140        evidence: vec![
141            "contextIndexedValueFamily",
142            "parentChildCascadeContext",
143            "noSheafTheoremClaim",
144        ],
145    }
146}
147
148pub fn cascade_value_for_context<'a>(
149    family: &'a CascadeValueFamilyV0,
150    context_id: &str,
151) -> Option<&'a AbstractPropertyValueV0> {
152    family
153        .members
154        .iter()
155        .find(|member| member.context.id == context_id)
156        .map(|member| &member.value)
157}
158
159pub fn cascade_family_context_values(
160    family: &CascadeValueFamilyV0,
161) -> BTreeMap<String, AbstractPropertyValueV0> {
162    family
163        .members
164        .iter()
165        .map(|member| (member.context.id.clone(), member.value.clone()))
166        .collect()
167}
168
169fn property_value_name(value: &AbstractPropertyValueV0) -> &str {
170    match value {
171        AbstractPropertyValueV0::Bottom { property_name }
172        | AbstractPropertyValueV0::Exact { property_name, .. }
173        | AbstractPropertyValueV0::FiniteSet { property_name, .. }
174        | AbstractPropertyValueV0::CustomPropertyReference { property_name, .. }
175        | AbstractPropertyValueV0::Top { property_name } => property_name,
176    }
177}