1use crate::numeric::BigInt;
8use crate::supertask;
9use crate::tower::{self, ValueAlgebra};
10
11#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
13pub enum Builtin {
14 Infinitesimal,
17 StandardPart,
21 IsInfinitesimal,
22 IsLimited,
23 InfinitelyClose,
24 GeneratorOf,
26 LimitOf,
28 Provisional,
30 AtTheLimit,
32 TripCount,
33 AffinePower,
34 PolynomialFlow,
35 CycleAt,
36 SearchCandidates,
37 StateSize,
38 EveryNatural,
40 ExactSqrt,
43 ExactExp,
44 ExactLn,
45 ExactPi,
47 ExactE,
48 ExactOmega,
50 HybridFlow,
52 FirstExit,
54 ExactPower,
57 OrderedInfinitesimal,
61}
62
63impl Builtin {
64 pub const ALL: [Builtin; 26] = [
65 Builtin::Infinitesimal,
66 Builtin::StandardPart,
67 Builtin::IsInfinitesimal,
68 Builtin::IsLimited,
69 Builtin::InfinitelyClose,
70 Builtin::GeneratorOf,
71 Builtin::LimitOf,
72 Builtin::Provisional,
73 Builtin::AtTheLimit,
74 Builtin::TripCount,
75 Builtin::AffinePower,
76 Builtin::PolynomialFlow,
77 Builtin::CycleAt,
78 Builtin::SearchCandidates,
79 Builtin::StateSize,
80 Builtin::EveryNatural,
81 Builtin::ExactSqrt,
82 Builtin::ExactExp,
83 Builtin::ExactLn,
84 Builtin::ExactPi,
85 Builtin::ExactE,
86 Builtin::ExactOmega,
87 Builtin::HybridFlow,
88 Builtin::FirstExit,
89 Builtin::ExactPower,
90 Builtin::OrderedInfinitesimal,
91 ];
92
93 pub fn name(self) -> &'static str {
95 match self {
96 Builtin::Infinitesimal => "infinitesimal",
97 Builtin::StandardPart => "standardPart",
98 Builtin::IsInfinitesimal => "isInfinitesimal",
99 Builtin::IsLimited => "isLimited",
100 Builtin::InfinitelyClose => "infinitelyClose",
101 Builtin::GeneratorOf => "generatorOf",
102 Builtin::LimitOf => "limitOf",
103 Builtin::Provisional => "provisional",
104 Builtin::AtTheLimit => "atTheLimit",
105 Builtin::TripCount => "tripCount",
106 Builtin::AffinePower => "affinePower",
107 Builtin::PolynomialFlow => "polynomialFlow",
108 Builtin::HybridFlow => "hybridFlow",
109 Builtin::FirstExit => "firstExit",
110 Builtin::CycleAt => "cycleAt",
111 Builtin::SearchCandidates => "searchCandidates",
112 Builtin::StateSize => "stateSize",
113 Builtin::EveryNatural => "everyNatural",
114 Builtin::ExactSqrt => "exactSqrt",
115 Builtin::ExactExp => "exactExp",
116 Builtin::ExactLn => "exactLn",
117 Builtin::ExactPi => "exactPi",
118 Builtin::ExactE => "exactE",
119 Builtin::ExactOmega => "exactOmega",
120 Builtin::ExactPower => "exactPower",
121 Builtin::OrderedInfinitesimal => "orderedInfinitesimal",
122 }
123 }
124
125 pub fn named(name: &str) -> Option<Builtin> {
127 Builtin::ALL.into_iter().find(|b| b.name() == name)
128 }
129}
130
131pub fn call<V: ValueAlgebra>(builtin: Builtin, args: Vec<V>) -> Result<V, String> {
134 let mut args = args.into_iter();
135 let mut next = || args.next().expect("the checker counted this builtin's arguments");
136 let name_of = |v: V| match v.text() {
137 Some(t) => Ok(t.to_string()),
138 None => Err(format!("an infinitesimal's name is Text, got {}", v.type_name())),
139 };
140 let natural = |v: V| match v.integer().and_then(|b| b.to_i64()) {
141 Some(n) if n >= 0 => Ok(n as u64),
142 _ => Err(format!(
143 "an infinitesimal's residue facts are natural numbers, got {}",
144 v.display_string()
145 )),
146 };
147 match builtin {
148 Builtin::Infinitesimal => {
149 let name = name_of(next())?;
150 let modulus = natural(next())?;
151 let allowed = args.map(natural).collect::<Result<Vec<u64>, String>>()?;
152 tower::new_infinitesimal(&name, modulus, &allowed)
153 }
154 Builtin::OrderedInfinitesimal => {
155 let name = name_of(next())?;
156 let (larger, smaller) = (next(), next());
157 let modulus = natural(next())?;
158 let allowed = args.map(natural).collect::<Result<Vec<u64>, String>>()?;
159 tower::new_ordered_infinitesimal(&name, &larger, &smaller, modulus, &allowed)
160 }
161 Builtin::StandardPart => {
162 let x = next();
163 match args.next() {
164 Some(at) => tower::standard_part_relative(&x, &at),
165 None => tower::standard_part(&x),
166 }
167 }
168 Builtin::IsInfinitesimal => {
169 let x = next();
170 match args.next() {
171 Some(at) => tower::is_infinitesimal_relative(&x, &at),
172 None => tower::is_infinitesimal(&x),
173 }
174 }
175 Builtin::IsLimited => {
176 let x = next();
177 match args.next() {
178 Some(at) => tower::is_limited_relative(&x, &at),
179 None => tower::is_limited(&x),
180 }
181 }
182 Builtin::InfinitelyClose => {
183 let left = next();
184 let right = next();
185 let difference = V::subtract(left, right)?;
186 match args.next() {
187 Some(at) => tower::is_infinitesimal_relative(&difference, &at),
188 None => tower::is_infinitesimal(&difference),
189 }
190 }
191 Builtin::GeneratorOf => tower::generator_of(&next()),
192 Builtin::LimitOf => {
193 let value = next();
194 let rule = rule_named(&next())?;
195 tower::apply_limit(&value, rule)
196 }
197 Builtin::Provisional => {
198 let count = |v: V| match v.integer().and_then(|b| b.to_i64()) {
199 Some(n) if n >= 0 => Ok(n as u64),
200 _ => Err(format!(
201 "a provisional answer counts with natural numbers, got {}",
202 v.display_string()
203 )),
204 };
205 let value = next();
206 let steps = count(next())?;
207 let revisions = count(next())?;
208 Ok(tower::provisional(value, steps, revisions))
209 }
210 Builtin::AtTheLimit => {
211 rule_named(&next())?;
212 Ok(V::nothing())
213 }
214 Builtin::TripCount => {
215 let (t0, step, bound, relation) = (next(), next(), next(), next());
216 match relation.text() {
217 Some(rel) => supertask::trip_count(&t0, &step, &bound, rel),
218 None => Err(format!("a clock's relation is named by Text, got {}", relation.type_name())),
219 }
220 }
221 Builtin::AffinePower => {
222 let (matrix, vector, n) = (next(), next(), next());
223 supertask::affine_power(&matrix, &vector, &n)
224 }
225 Builtin::PolynomialFlow => {
226 let (field, vector, n) = (next(), next(), next());
227 supertask::polynomial_flow(&field, &vector, &n)
228 }
229 Builtin::HybridFlow => {
230 let (model, vector, n) = (next(), next(), next());
231 supertask::hybrid_flow(&model, &vector, &n)
232 }
233 Builtin::FirstExit => {
234 let (t0, step, guard) = (next(), next(), next());
235 supertask::first_exit(&t0, &step, &guard)
236 }
237 Builtin::CycleAt => {
238 let (states, repeated, n) = (next(), next(), next());
239 supertask::cycle_at(&states, &repeated, &n)
240 }
241 Builtin::SearchCandidates => {
242 let (atoms, moduli) = (next(), next());
243 supertask::search_candidates(&atoms, &moduli)
244 }
245 Builtin::StateSize => {
246 let bits = supertask::state_size(&next());
247 Ok(V::from_bigint(BigInt::from_i64(i64::try_from(bits).unwrap_or(i64::MAX))))
248 }
249 Builtin::EveryNatural => Err(
250 "a search over every natural number reached the runtime unresolved; the supertask engine resolves every such loop before the program runs"
251 .to_string(),
252 ),
253 Builtin::ExactSqrt => tower::real_fn(tower::RealFn::Sqrt, &next()),
254 Builtin::ExactExp => tower::real_fn(tower::RealFn::Exp, &next()),
255 Builtin::ExactLn => tower::real_fn(tower::RealFn::Ln, &next()),
256 Builtin::ExactPi => Ok(tower::pi()),
257 Builtin::ExactE => Ok(tower::euler()),
258 Builtin::ExactOmega => Ok(tower::omega()),
259 Builtin::ExactPower => {
260 let (base, exponent) = (next(), next());
261 tower::exact_power(&base, &exponent)
262 }
263 }
264}
265
266fn rule_named<V: ValueAlgebra>(rule: &V) -> Result<crate::limit_value::LimitRule, String> {
267 match rule.text() {
268 Some(name) => tower::limit_rule(name),
269 None => Err(format!("a limit rule is named by Text, got {}", rule.type_name())),
270 }
271}
272
273#[cfg(test)]
274#[path = "../../logicaffeine_tests/unit/logicaffeine_base/extension/tests.rs"]
275mod tests;