ftml_solver/rules/fixity/
conj.rs1use crate::{
2 CheckRef,
3 rules::{MarkerRule, PreparationRule, SizedSolverRule},
4 split::SplitStrategy,
5};
6use ftml_ontology::terms::{ApplicationTerm, Argument, MaybeSequence, Term};
7use ftml_uris::SymbolUri;
8use std::ops::ControlFlow;
9
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct IsConjunctionRule(pub SymbolUri);
12impl SizedSolverRule for IsConjunctionRule {
13 fn display(&self) -> Vec<crate::trace::Displayable> {
14 ftml_solver_trace::trace!(&self.0, "is a conjunction")
15 }
16}
17impl<Split: SplitStrategy> MarkerRule<Split> for IsConjunctionRule {}
18
19#[derive(Debug, Clone, PartialEq, Eq)]
20pub struct ConjunctiveRule(pub SymbolUri);
21impl SizedSolverRule for ConjunctiveRule {
22 fn priority(&self) -> isize {
23 10_000
24 }
25 fn display(&self) -> Vec<crate::trace::Displayable> {
26 ftml_solver_trace::trace!(&self.0, " is conjunctive")
27 }
28}
29impl std::fmt::Display for ConjunctiveRule {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 write!(f, "{} is conjunctive", self.0)
32 }
33}
34impl<Split: SplitStrategy> PreparationRule<Split> for ConjunctiveRule {
35 fn applicable(&self, checker: &CheckRef<'_, '_, Split>, t: &Term) -> bool {
36 let Some(head) = checker.get_head(t) else {
37 return false;
38 };
39 let head = head.as_ref().map_either(|e| &**e, |e| &**e);
40 super::is_sequence_binary(&self.0, t, head).is_some()
41 }
42 fn apply(
43 &self,
44 checker: &mut CheckRef<'_, '_, Split>,
45 t: Term,
46 path: Option<(&mut smallvec::SmallVec<u8, 16>, usize)>,
47 ) -> ControlFlow<Term, Term> {
48 let Some(head) = checker.get_head(&t) else {
49 return ControlFlow::Continue(t);
50 };
51 let head = head.as_ref().map_either(|e| &**e, |e| &**e);
52 let Some((app, args, index)) = super::is_sequence_binary(&self.0, &t, head) else {
53 return ControlFlow::Continue(t);
54 };
55 let Some(conj): Option<&IsConjunctionRule> = checker
56 .rules()
57 .marker()
58 .iter()
59 .rev()
60 .find_map(|rl| rl.as_any().downcast_ref())
61 else {
62 return ControlFlow::Continue(t);
63 };
64 let pre = &app.arguments[..index];
65 let post = &app.arguments[index + 1..];
66 let args: &[Term] = match args {
67 MaybeSequence::Seq(s) => s,
68 MaybeSequence::One(o) => std::slice::from_ref(o),
69 };
70 if args.is_empty() {
71 return ControlFlow::Continue(t);
72 }
73 let conjuncts = args.iter().map(|a| {
74 Term::Application(ApplicationTerm::new(
75 app.head.clone(),
76 {
77 let mut args = pre.to_vec();
78 args.push(Argument::Simple(a.clone()));
79 args.extend_from_slice(post);
80 args.into_boxed_slice()
81 },
82 app.presentation.clone(),
83 ))
84 });
85 let t = unsafe {
87 conjuncts
88 .reduce(|a, b| {
89 Term::Application(ApplicationTerm::new(
90 Term::Symbol {
91 uri: conj.0.clone(),
92 presentation: None,
93 },
94 Box::new([Argument::Simple(a), Argument::Simple(b)]),
95 None,
96 ))
97 })
98 .unwrap_unchecked()
99 };
100 ControlFlow::Continue(t)
101 }
102
103 fn applicable_revert(&self, _: &CheckRef<'_, '_, Split>, _: &Term) -> bool {
104 false
105 }
106 fn revert(&self, _: &CheckRef<'_, '_, Split>, t: Term) -> ControlFlow<Term, Term> {
107 ControlFlow::Continue(t)
108 }
109}
110
111#[derive(Debug, Clone, PartialEq, Eq)]
112pub struct PairwiseConjunctiveRule(pub SymbolUri);
113impl SizedSolverRule for PairwiseConjunctiveRule {
114 fn priority(&self) -> isize {
115 10_000
116 }
117 fn display(&self) -> Vec<crate::trace::Displayable> {
118 ftml_solver_trace::trace!(&self.0, " is pairwise conjunctive")
119 }
120}
121impl std::fmt::Display for PairwiseConjunctiveRule {
122 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
123 write!(f, "{} is pairwise conjunctive", self.0)
124 }
125}
126impl<Split: SplitStrategy> PreparationRule<Split> for PairwiseConjunctiveRule {
127 fn applicable(&self, checker: &CheckRef<'_, '_, Split>, t: &Term) -> bool {
128 let Some(head) = checker.get_head(t) else {
129 return false;
130 };
131 let head = head.as_ref().map_either(|e| &**e, |e| &**e);
132 super::is_sequence_binary(&self.0, t, head).is_some()
133 }
134 fn apply(
135 &self,
136 checker: &mut CheckRef<'_, '_, Split>,
137 t: Term,
138 path: Option<(&mut smallvec::SmallVec<u8, 16>, usize)>,
139 ) -> ControlFlow<Term, Term> {
140 let Some(head) = checker.get_head(&t) else {
141 return ControlFlow::Continue(t);
142 };
143 let head = head.as_ref().map_either(|e| &**e, |e| &**e);
144 let Some((app, args, index)) = super::is_sequence_binary(&self.0, &t, head) else {
145 return ControlFlow::Continue(t);
146 };
147 let Some(conj): Option<&IsConjunctionRule> = checker
148 .rules()
149 .marker()
150 .iter()
151 .rev()
152 .find_map(|rl| rl.as_any().downcast_ref())
153 else {
154 return ControlFlow::Continue(t);
155 };
156 let pre = &app.arguments[..index];
157 let post = &app.arguments[index + 1..];
158 let args: &[Term] = match args {
159 MaybeSequence::Seq(s) => s,
160 MaybeSequence::One(o) => std::slice::from_ref(o),
161 };
162 if args.len() < 2 {
163 return ControlFlow::Continue(t);
164 }
165 let mut conjuncts = (0..args.len() - 1).map(|i| {
167 let (a, b) = (&args[i], &args[i + 1]);
168 Term::Application(ApplicationTerm::new(
169 app.head.clone(),
170 {
171 let mut args = pre.to_vec();
172 args.push(Argument::Simple(a.clone()));
173 args.push(Argument::Simple(b.clone()));
174 args.extend_from_slice(post);
175 args.into_boxed_slice()
176 },
177 app.presentation.clone(),
178 ))
179 });
180 let t = if args.len() == 2 {
181 unsafe { conjuncts.next().unwrap_unchecked() }
183 } else {
184 unsafe {
186 conjuncts
187 .reduce(|a, b| {
188 Term::Application(ApplicationTerm::new(
189 Term::Symbol {
190 uri: conj.0.clone(),
191 presentation: None,
192 },
193 Box::new([Argument::Simple(a), Argument::Simple(b)]),
194 None,
195 ))
196 })
197 .unwrap_unchecked()
198 }
199 };
200 ControlFlow::Continue(t)
202 }
203 fn applicable_revert(&self, checker: &CheckRef<'_, '_, Split>, t: &Term) -> bool {
204 super::bin::BinLRule::app_rev(&self.0, checker, t)
205 }
206 fn revert(&self, checker: &CheckRef<'_, '_, Split>, t: Term) -> ControlFlow<Term, Term> {
207 super::bin::BinLRule::rev(&self.0, checker, t)
208 }
209}