1use crate::algebraic::Algebraic;
33use crate::exact_real::{ExactReal, RealError};
34use crate::hybrid;
35use crate::germ::{Flow, Germ};
36use crate::hypernatural::Hypernatural;
37use crate::hyperreal::Hyperreal;
38use crate::limit_value::{bounded_lcm, Depends, ResidueError, ResidueType, MAX_MODULUS};
39use crate::number::Number;
40use crate::numeric::{BigInt, Rational};
41use crate::ode::{escape_time_bound, Field as OdeField, Monomial};
42use crate::poly::Poly;
43use crate::tower::{self, Branch, ExactRef, HyperForm, HyperValue, NaturalValue, Rel, Scale, Shape, TowerValue, ValueAlgebra};
44use std::cmp::Ordering;
45use std::sync::Arc;
46
47pub type Matrix<V> = Vec<Vec<V>>;
49
50fn int<V: TowerValue>(n: i64) -> V {
51 V::from_bigint(BigInt::from_i64(n))
52}
53
54fn items<V: ValueAlgebra>(v: &V, what: &str) -> Result<Vec<V>, String> {
55 match v.shape() {
56 Shape::List(values) => Ok(values),
57 _ => Err(format!("{what} is a Seq, got {}", v.type_name())),
58 }
59}
60
61fn is_number<V: TowerValue>(v: &V) -> bool {
65 v.is_standard_number() || matches!(v.exact(), Some(e) if !matches!(e, ExactRef::Ordinal(_)))
66}
67
68fn is_standard<V: TowerValue>(v: &V) -> bool {
70 v.is_standard_number() || matches!(v.exact(), Some(ExactRef::Algebraic(_)) | Some(ExactRef::Real(_)))
71}
72
73pub fn trip_count<V: ValueAlgebra>(t0: &V, step: &V, bound: &V, relation: &str) -> Result<V, String> {
79 let (guard, rising) = match relation {
80 "<" => (Rel::Lt, true),
81 "<=" => (Rel::LtEq, true),
82 ">" => (Rel::Gt, false),
83 ">=" => (Rel::GtEq, false),
84 other => {
85 return Err(format!(
86 "a clock's guard is a relation <, <=, > or >=, got `{other}`"
87 ))
88 }
89 };
90 if !(is_number(t0) && is_number(step) && is_number(bound)) {
91 return Ok(int(-1));
92 }
93 if !V::holds(guard, t0, bound)? {
94 return Ok(int(0));
95 }
96 let toward = if rising { Rel::Gt } else { Rel::Lt };
97 if !V::holds(toward, step, &int(0))? {
98 if is_standard(step) {
99 return Ok(int(-1));
100 }
101 return Err(format!(
102 "the clock never reaches its bound: it starts at {}, steps by {} and runs while it is {relation} {}",
103 t0.display_string(),
104 step.display_string(),
105 bound.display_string()
106 ));
107 }
108 let distance = V::subtract(bound.clone(), t0.clone())?;
109 let steps = V::exact_divide(distance, step.clone())?;
110 match guard {
111 Rel::Lt | Rel::Gt => V::ceil(steps),
112 _ => V::add(V::floor(steps)?, int(1)),
113 }
114}
115
116fn matrix_of<V: ValueAlgebra>(v: &V) -> Result<Matrix<V>, String> {
119 let rows = items(v, "a supertask's update matrix")?;
120 let rows: Matrix<V> = rows
121 .iter()
122 .map(|r| items(r, "each row of a supertask's update matrix"))
123 .collect::<Result<_, _>>()?;
124 if rows.is_empty() || rows.iter().any(|r| r.len() != rows.len()) {
125 return Err("a supertask's update matrix is square and not empty".to_string());
126 }
127 Ok(rows)
128}
129
130fn identity<V: ValueAlgebra>(n: usize) -> Matrix<V> {
131 (0..n)
132 .map(|i| (0..n).map(|j| int(i64::from(i == j))).collect())
133 .collect()
134}
135
136fn mat_mul<V: ValueAlgebra>(a: &Matrix<V>, b: &Matrix<V>) -> Result<Matrix<V>, String> {
137 let n = a.len();
138 let mut out = Vec::with_capacity(n);
139 for row in a {
140 let mut out_row = Vec::with_capacity(n);
141 for j in 0..n {
142 let mut acc = int(0);
143 for (k, entry) in row.iter().enumerate() {
144 acc = V::add(acc, V::multiply(entry.clone(), b[k][j].clone())?)?;
145 }
146 out_row.push(acc);
147 }
148 out.push(out_row);
149 }
150 Ok(out)
151}
152
153fn mat_vec<V: ValueAlgebra>(a: &Matrix<V>, x: &[V]) -> Result<Vec<V>, String> {
154 a.iter()
155 .map(|row| {
156 row.iter().zip(x).try_fold(int(0), |acc, (e, v)| {
157 V::add(acc, V::multiply(e.clone(), v.clone())?)
158 })
159 })
160 .collect()
161}
162
163fn mat_sub<V: ValueAlgebra>(a: &Matrix<V>, b: &Matrix<V>) -> Result<Matrix<V>, String> {
164 a.iter()
165 .zip(b)
166 .map(|(ra, rb)| {
167 ra.iter()
168 .zip(rb)
169 .map(|(x, y)| V::subtract(x.clone(), y.clone()))
170 .collect()
171 })
172 .collect()
173}
174
175fn mat_pow<V: ValueAlgebra>(a: &Matrix<V>, mut e: BigInt) -> Result<Matrix<V>, String> {
176 let two = BigInt::from_u64(2);
177 let mut acc = identity(a.len());
178 let mut base = a.clone();
179 while e.is_positive() {
180 let (q, r) = e.div_rem(&two).expect("two is nonzero");
181 if !r.is_zero() {
182 acc = mat_mul(&acc, &base)?;
183 }
184 e = q;
185 if e.is_positive() {
186 base = mat_mul(&base, &base)?;
187 }
188 }
189 Ok(acc)
190}
191
192fn is_zero<V: ValueAlgebra>(v: &V) -> Result<bool, String> {
193 V::holds(Rel::Eq, v, &int(0))
194}
195
196fn as_rational<V: ValueAlgebra>(v: &V) -> Option<Rational> {
199 match v.shape() {
200 Shape::Int(n) => Some(Rational::from_i64(n)),
201 Shape::BigInt(b) => Some(Rational::from_bigint(b)),
202 Shape::Rational(r) => Some(r),
203 Shape::Float => v.standard_rational(),
204 _ => match v.exact()? {
205 ExactRef::Algebraic(a) => a.to_rational(),
206 _ => None,
207 },
208 }
209}
210
211fn characteristic_polynomial<V: ValueAlgebra>(a: &Matrix<V>) -> Result<Vec<V>, String> {
214 let n = a.len();
215 let mut c: Vec<V> = vec![int(0); n + 1];
216 c[n] = int(1);
217 let mut m: Matrix<V> = vec![vec![int(0); n]; n];
218 for k in 1..=n {
219 let am = mat_mul(a, &m)?;
220 m = am;
221 for (i, row) in m.iter_mut().enumerate() {
222 row[i] = V::add(row[i].clone(), c[n - k + 1].clone())?;
223 }
224 let am = mat_mul(a, &m)?;
225 let trace = (0..n).try_fold(int(0), |acc, i| V::add(acc, am[i][i].clone()))?;
226 let neg = V::subtract(int(0), trace)?;
227 c[n - k] = V::exact_divide(neg, int(k as i64))?;
228 }
229 Ok(c)
230}
231
232fn totient(mut n: u64) -> u64 {
233 let mut result = n;
234 let mut p = 2;
235 while p * p <= n {
236 if n.is_multiple_of(p) {
237 while n.is_multiple_of(p) {
238 n /= p;
239 }
240 result -= result / p;
241 }
242 p += 1;
243 }
244 if n > 1 {
245 result -= result / n;
246 }
247 result
248}
249
250fn mobius(mut n: u64) -> i32 {
251 let mut sign = 1;
252 let mut p = 2;
253 while p * p <= n {
254 if n.is_multiple_of(p) {
255 n /= p;
256 if n.is_multiple_of(p) {
257 return 0;
258 }
259 sign = -sign;
260 }
261 p += 1;
262 }
263 if n > 1 {
264 sign = -sign;
265 }
266 sign
267}
268
269fn cyclotomic(d: u64) -> Poly {
271 let mut num = Poly::one();
272 let mut den = Poly::one();
273 for e in (1..=d).filter(|e| d.is_multiple_of(*e)) {
274 let mut c = vec![Rational::zero(); e as usize + 1];
275 c[0] = Rational::from_i64(-1);
276 c[e as usize] = Rational::from_i64(1);
277 let factor = Poly::from_coeffs(c);
278 match mobius(d / e) {
279 1 => num = num.mul(&factor),
280 -1 => den = den.mul(&factor),
281 _ => {}
282 }
283 }
284 num.div_rem(&den).expect("a nonzero divisor").0
285}
286
287fn cyclotomic_order(f: &Poly) -> Option<u64> {
290 let degree = f.degree()? as u64;
291 (1..=2 * degree * degree + 2)
292 .filter(|d| totient(*d) == degree)
293 .find(|d| cyclotomic(*d) == *f)
294}
295
296fn unit_root_structure<V: ValueAlgebra>(a: &Matrix<V>) -> Result<(u64, u64, u64), String> {
300 let coefficients = characteristic_polynomial(a)?;
301 let rational: Vec<Rational> = coefficients
302 .iter()
303 .map(|c| {
304 as_rational(c).ok_or_else(|| {
305 format!(
306 "the update's characteristic polynomial has the coefficient {}; a supertask's closed \
307 form is exact here only for an eigenvalue that is a standard root of unity",
308 c.display_string()
309 )
310 })
311 })
312 .collect::<Result<_, _>>()?;
313 let chi = Poly::from_coeffs(rational);
314 let (mut z, mut p, mut m) = (0u64, 1u64, 0u64);
315 for (factor, multiplicity) in chi.factor_over_q() {
316 let factor = factor.monic();
317 if factor == Poly::x() {
318 z = u64::from(multiplicity);
319 continue;
320 }
321 let d = cyclotomic_order(&factor).ok_or_else(|| {
322 format!(
323 "an eigenvalue of the update is not a root of unity (a root of {factor}); the state \
324 grows, shrinks or turns by an irrational angle at every step, and a supertask over \
325 such an update has no exact closed form here"
326 )
327 })?;
328 p = p / gcd(p, d) * d;
329 m = m.max(u64::from(multiplicity));
330 }
331 Ok((z, p, m))
332}
333
334fn gcd(a: u64, b: u64) -> u64 {
335 if b == 0 {
336 a
337 } else {
338 gcd(b, a % b)
339 }
340}
341
342fn infinite_count<V: TowerValue>(n: &V) -> Result<NaturalValue, String> {
344 match n.exact() {
345 Some(ExactRef::Natural(nv)) => Ok(nv.clone()),
346 _ if several_count(n) => Err(format!(
347 "this supertask's step count, {}, is infinite in more than one infinitesimal, which only an affine \
348 closed form or a cycle is read over; a flow is integrated over a count of one",
349 n.display_string()
350 )),
351 _ => Err(format!(
352 "a supertask's step count is a natural number, got {}",
353 n.display_string()
354 )),
355 }
356}
357
358fn several_count<V: TowerValue>(n: &V) -> bool {
360 matches!(n.exact(), Some(ExactRef::Hyper(h)) if matches!(h.value, HyperForm::Integer(_)))
361}
362
363fn on_residue<V: ValueAlgebra>(r: &V, f: &dyn Fn(u64) -> Result<V, String>) -> Result<V, String> {
366 if let Some(k) = r.integer() {
367 return f(k.to_u64().ok_or_else(|| format!("a residue is a natural number, got {}", r.display_string()))?);
368 }
369 match r.exact() {
370 Some(ExactRef::Depends(d)) => tower::map_depends(d, |b| on_residue(&b, f)),
371 _ => Err(format!("a residue is a natural number, got {}", r.display_string())),
372 }
373}
374
375fn several_count_power<V: ValueAlgebra>(a: &Matrix<V>, x: &[V], n: &V) -> Result<Vec<V>, String> {
381 let width = a.len();
382 let mut values: Vec<Option<V>> = vec![None; width];
383 for i in 0..width {
384 if values[i].is_some() {
385 continue;
386 }
387 let closure = dependency_closure(a, i)?;
388 let sub_a: Matrix<V> = closure
389 .iter()
390 .map(|&r| closure.iter().map(|&c| a[r][c].clone()).collect())
391 .collect();
392 let sub_x: Vec<V> = closure.iter().map(|&k| x[k].clone()).collect();
393 let standard = characteristic_polynomial(&sub_a)?
394 .iter()
395 .all(|c| as_rational(c).is_some());
396 let results = if standard {
397 let (z, p, m) = unit_root_structure(&sub_a)?;
398 check_annihilator(&sub_a, z, p, m)?;
399 let differences = root_differences(&sub_a, &sub_x, z, p, m)?;
400 evaluate_over_count(n, z, p, &differences, sub_x.len())?
401 } else {
402 let mut found = Vec::new();
403 for v in sub_a.iter().flatten().chain(sub_x.iter()).chain(std::iter::once(n)) {
404 infinitesimals_in(v, &mut found);
405 }
406 for (k, s) in found.iter().enumerate() {
407 if let Some(t) = found[k + 1..].iter().find(|t| s.order(t).is_none()) {
408 return Err(s.unordered(t));
409 }
410 }
411 let finest = found
412 .iter()
413 .find(|s| found.iter().all(|t| s.order(t) != Some(Ordering::Greater)))
414 .expect("a count infinite in several infinitesimals holds one")
415 .clone();
416 let matrix: crate::nested_flow::NMatrix = sub_a.iter().map(|row| row.iter().map(tower::as_number).collect()).collect();
417 let start: Vec<Number> = sub_x.iter().map(tower::as_number).collect();
418 crate::nested_flow::power(&finest, &matrix, tower::as_number(n), &start)?
419 .into_iter()
420 .map(tower::from_number)
421 .collect()
422 };
423 for (pos, &k) in closure.iter().enumerate() {
424 values[k].get_or_insert_with(|| results[pos].clone());
425 }
426 }
427 Ok(values.into_iter().map(|v| v.expect("every component is resolved")).collect())
428}
429
430fn evaluate_over_count<V: ValueAlgebra>(
433 n: &V,
434 z: u64,
435 p: u64,
436 differences: &[Vec<Vec<V>>],
437 width: usize,
438) -> Result<Vec<V>, String> {
439 let shifted = V::subtract(n.clone(), int(z as i64))?;
440 let residue = V::modulo(shifted.clone(), int(p as i64))?;
441 (0..width)
442 .map(|i| {
443 on_residue(&residue, &|r| {
444 let q = V::exact_divide(V::subtract(shifted.clone(), int(r as i64))?, int(p as i64))?;
445 let mut binomial: V = int(1);
446 let mut total: V = int(0);
447 for (j, delta) in differences[r as usize].iter().enumerate() {
448 if j > 0 {
449 let factor = V::subtract(q.clone(), int(j as i64 - 1))?;
450 binomial = V::exact_divide(V::multiply(binomial, factor)?, int(j as i64))?;
451 }
452 total = V::add(total, V::multiply(binomial.clone(), delta[i].clone())?)?;
453 }
454 Ok(total)
455 })
456 })
457 .collect()
458}
459
460pub fn affine_power<V: ValueAlgebra>(matrix: &V, vector: &V, n: &V) -> Result<V, String> {
462 if let Some(on_classes) = on_each_class(&[matrix, vector, n], |args| affine_power(&args[0], &args[1], &args[2])) {
463 return on_classes;
464 }
465 let a = matrix_of(matrix)?;
466 let x = items(vector, "a supertask's state")?;
467 if x.len() != a.len() {
468 return Err(format!(
469 "a supertask's state has {} values for a {}-by-{} update",
470 x.len(),
471 a.len(),
472 a.len()
473 ));
474 }
475 let natural = match n.shape() {
476 Shape::Int(k) if k >= 0 => {
477 return Ok(V::list(mat_vec(&mat_pow(&a, BigInt::from_i64(k))?, &x)?));
478 }
479 Shape::BigInt(k) if k.is_positive() => {
480 return Ok(V::list(mat_vec(&mat_pow(&a, k)?, &x)?));
481 }
482 _ if several_count(n) => return Ok(V::list(several_count_power(&a, &x, n)?)),
483 _ => infinite_count(n)?,
484 };
485 let width = a.len();
486 let mut values: Vec<Option<V>> = vec![None; width];
487 for i in 0..width {
488 if values[i].is_some() {
489 continue;
490 }
491 let closure = dependency_closure(&a, i)?;
492 let sub_a: Matrix<V> = closure
493 .iter()
494 .map(|&r| closure.iter().map(|&c| a[r][c].clone()).collect())
495 .collect();
496 let sub_x: Vec<V> = closure.iter().map(|&k| x[k].clone()).collect();
497 let standard = characteristic_polynomial(&sub_a)?
498 .iter()
499 .all(|c| as_rational(c).is_some());
500 let results = if standard {
501 root_of_unity_power(&sub_a, &sub_x, &natural)?
502 } else {
503 flow_power(&sub_a, &sub_x, &natural)?
504 };
505 for (pos, &k) in closure.iter().enumerate() {
506 values[k].get_or_insert_with(|| results[pos].clone());
507 }
508 }
509 Ok(V::list(
510 values
511 .into_iter()
512 .map(|v| v.expect("every component is resolved"))
513 .collect(),
514 ))
515}
516
517fn dependency_closure<V: ValueAlgebra>(a: &Matrix<V>, i: usize) -> Result<Vec<usize>, String> {
519 let mut seen = vec![false; a.len()];
520 let mut stack = vec![i];
521 seen[i] = true;
522 while let Some(r) = stack.pop() {
523 for (c, entry) in a[r].iter().enumerate() {
524 if !seen[c] && !is_zero(entry)? {
525 seen[c] = true;
526 stack.push(c);
527 }
528 }
529 }
530 Ok((0..a.len()).filter(|&k| seen[k]).collect())
531}
532
533pub fn check_annihilator<V: ValueAlgebra>(a: &Matrix<V>, z: u64, p: u64, m: u64) -> Result<(), String> {
535 let checked = mat_mul(
536 &mat_pow(a, BigInt::from_u64(z))?,
537 &mat_pow(
538 &mat_sub(&mat_pow(a, BigInt::from_u64(p))?, &identity(a.len()))?,
539 BigInt::from_u64(m),
540 )?,
541 )?;
542 for entry in checked.iter().flatten() {
543 if !is_zero(entry)? {
544 return Err(format!(
545 "the supertask engine's certificate A^{z}·(A^{p} − I)^{m} = 0 failed to check; no closed form is used"
546 ));
547 }
548 }
549 Ok(())
550}
551
552fn root_of_unity_power<V: ValueAlgebra>(
555 a: &Matrix<V>,
556 x: &[V],
557 natural: &NaturalValue,
558) -> Result<Vec<V>, String> {
559 let (z, p, m) = unit_root_structure(a)?;
560 check_annihilator(a, z, p, m)?;
561 let differences = root_differences(a, x, z, p, m)?;
562 evaluate_by_class(natural, z, p, &differences, x.len())
563}
564
565fn root_differences<V: ValueAlgebra>(a: &Matrix<V>, x: &[V], z: u64, p: u64, m: u64) -> Result<Vec<Vec<Vec<V>>>, String> {
568 let samples = m.max(1);
569 let mut differences: Vec<Vec<Vec<V>>> = Vec::with_capacity(p as usize);
570 for r in 0..p {
571 let mut points = Vec::with_capacity(samples as usize);
572 for j in 0..samples {
573 let power = mat_pow(a, BigInt::from_u64(z + r + p * j))?;
574 points.push(mat_vec(&power, x)?);
575 }
576 let mut deltas = Vec::with_capacity(samples as usize);
577 for _ in 0..samples {
578 deltas.push(points[0].clone());
579 points = points
580 .windows(2)
581 .map(|w| {
582 w[1].iter()
583 .zip(&w[0])
584 .map(|(b, a)| V::subtract(b.clone(), a.clone()))
585 .collect::<Result<Vec<_>, _>>()
586 })
587 .collect::<Result<_, _>>()?;
588 }
589 differences.push(deltas);
590 }
591 Ok(differences)
592}
593
594fn dt_polynomial<V: ValueAlgebra>(v: &V, scale: &Scale) -> Option<(u32, Vec<Rational>)> {
597 let (h, q) = match v.exact() {
598 Some(ExactRef::Hyper(h)) if !h.scale.same_infinitesimal(scale) => return None,
599 Some(ExactRef::Hyper(h)) => match &h.value {
600 HyperForm::Rational(r) => (r.clone(), 1),
601 HyperForm::Puiseux(p) => p.rational_function()?,
602 HyperForm::Germ(_) | HyperForm::Multi(_) | HyperForm::Integer(_) | HyperForm::Nested(_) => return None,
603 },
604 _ => return Some((1, vec![as_rational(v)?])),
605 };
606 let coefficients = h.as_dt_polynomial()?.iter().map(|c| c.to_rational()).collect::<Option<_>>()?;
607 Some((q, coefficients))
608}
609
610fn below_dt(q: u32, coefficients: &[Rational]) -> bool {
612 coefficients.iter().take(q as usize).skip(1).any(|c| !c.is_zero())
613}
614
615fn at_class<V: TowerValue>(v: &V, c: u64) -> V {
617 match v.exact() {
618 Some(ExactRef::Depends(d)) => d.value.at(c).map(|b| b.0.clone()).unwrap_or_else(|| v.clone()),
619 Some(ExactRef::Natural(n)) => match n.value.depends().at(c) {
620 Some(p) => tower::from_hyper(Hyperreal::from_reciprocal_powers(p.coeffs()), &n.scale),
621 None => v.clone(),
622 },
623 _ => v.clone(),
624 }
625}
626
627fn state_moduli<V: TowerValue>(x: &[V]) -> Vec<u64> {
629 x.iter()
630 .filter_map(|v| match v.exact() {
631 Some(ExactRef::Depends(d)) => Some(d.value.modulus()),
632 Some(ExactRef::Natural(h)) => Some(h.value.depends().modulus()),
633 _ => None,
634 })
635 .collect()
636}
637
638fn classes(moduli: impl IntoIterator<Item = u64>) -> Option<u64> {
639 moduli.into_iter().try_fold(1u64, |acc, m| {
640 let l = u128::from(acc / gcd(acc, m)) * u128::from(m);
641 (l <= u128::from(MAX_MODULUS)).then_some(l as u64)
642 })
643}
644
645fn flow_power<V: ValueAlgebra>(a: &Matrix<V>, x: &[V], natural: &NaturalValue) -> Result<Vec<V>, String> {
648 let n = a.len();
649 let clock = &natural.scale;
650 let mut found = Vec::new();
651 for v in a.iter().flatten().chain(x.iter()) {
652 infinitesimals_in(v, &mut found);
653 }
654 for s in &found {
655 if s.order(clock).is_none() {
656 return Err(clock.unordered(s));
657 }
658 }
659 let finer = found
660 .iter()
661 .filter(|s| s.order(clock) == Some(Ordering::Less))
662 .fold(None::<Arc<Scale>>, |least, s| match least {
663 Some(t) if t.order(s) == Some(Ordering::Less) => Some(t),
664 _ => Some(s.clone()),
665 });
666 if let Some(finer) = finer {
667 return several_on_classes(a, x, natural, |matrix, start, count| {
668 crate::nested_flow::power(&finer, matrix, count.clone(), start)
669 });
670 }
671 if found.iter().any(|s| s.order(clock) == Some(Ordering::Greater)) {
672 return several_on_classes(a, x, natural, |matrix, start, count| {
673 let (t, delta) = linear_count(count)?;
674 crate::nested_flow::flow(clock, matrix, t, delta, start)
675 });
676 }
677 let mut entries = Vec::with_capacity(n * n);
678 for (i, row) in a.iter().enumerate() {
679 for (j, entry) in row.iter().enumerate() {
680 let (q, coefficients) = dt_polynomial(entry, &natural.scale).ok_or_else(|| {
681 format!(
682 "the update's entry {} is not a polynomial in the infinitesimal, or in a root of it, with rational coefficients, so this supertask is not a flow the engine integrates",
683 entry.display_string()
684 )
685 })?;
686 if below_dt(q, &coefficients) {
687 return Err(format!(
688 "the update's entry {} has a term of a fractional order of the infinitesimal below its first, so this supertask is not a flow",
689 entry.display_string()
690 ));
691 }
692 entries.push((i, j, q, coefficients));
693 }
694 }
695 let grid = entries.iter().fold(1u64, |l, (_, _, q, _)| l / gcd(l, u64::from(*q)) * u64::from(*q));
696 let grid = u32::try_from(grid).map_err(|_| "the update's entries lie on too fine a root of the infinitesimal".to_string())?;
697 let mut orders: Vec<Vec<Vec<Rational>>> = Vec::new();
698 for (i, j, q, coefficients) in entries {
699 let spread = (grid / q) as usize;
700 for (k, c) in coefficients.into_iter().enumerate() {
701 while orders.len() <= k * spread {
702 orders.push(vec![vec![Rational::zero(); n]; n]);
703 }
704 orders[k * spread][i][j] = c;
705 }
706 }
707 let identity: Vec<Vec<Rational>> = (0..n)
708 .map(|i| (0..n).map(|j| if i == j { Rational::one() } else { Rational::zero() }).collect())
709 .collect();
710 if orders.first() != Some(&identity) {
711 return Err(
712 "the update changes its state by a standard amount at every step as well as an infinitesimal one, so this supertask is neither a cycle nor a flow"
713 .to_string(),
714 );
715 }
716 let terms: Vec<Vec<Vec<Rational>>> = orders[1..].to_vec();
717 if terms.is_empty() {
718 return Ok(x.to_vec());
719 }
720 let scale = &natural.scale;
721 let ty = scale.residues.clone();
722 let counts = natural.value.depends();
723 let l = classes([counts.modulus(), ty.modulus()].into_iter().chain(state_moduli(x)))
724 .ok_or_else(|| "a flow's step count and state split over more residue classes than one value holds".to_string())?;
725 let mut columns: Vec<Vec<Option<Branch<V>>>> = vec![Vec::with_capacity(l as usize); n];
726 for c in 0..l {
727 let Some(count) = counts.at(c) else {
728 columns.iter_mut().for_each(|col| col.push(None));
729 continue;
730 };
731 if count.degree().unwrap_or(0) != 1 {
732 return Err(
733 "a flow's step count is a multiple of 1/dt; one that grows faster or slower has no standard end state here"
734 .to_string(),
735 );
736 }
737 let (t, delta) = (count.coeff(1), count.coeff(0));
738 if !t.is_positive() {
739 return Err("a flow runs forward a positive time".to_string());
740 }
741 let start: Vec<Germ> = x
742 .iter()
743 .map(|v| {
744 let at = at_class(v, c);
745 tower::germ_of(&at).ok_or_else(|| {
746 format!("a flow's state is numbers, not {}", at.display_string())
747 })
748 })
749 .collect::<Result<_, _>>()?;
750 let flow = Flow::on_grid(grid, terms.clone(), t, delta, start)
751 .ok_or_else(|| "a flow's update and state disagree in shape".to_string())?;
752 for (i, column) in columns.iter_mut().enumerate() {
753 column.push(Some(Branch(tower::from_germ(Germ::flow(&flow, i), scale))));
754 }
755 }
756 Ok(columns
757 .into_iter()
758 .map(|raw| {
759 let d = Depends::from_branches(ty.clone(), l, raw).expect("the classes are the type's own");
760 tower::from_depends(d, scale)
761 })
762 .collect())
763}
764
765fn several_on_classes<V: ValueAlgebra>(
769 a: &Matrix<V>,
770 x: &[V],
771 natural: &NaturalValue,
772 end: impl Fn(&crate::nested_flow::NMatrix, &[Number], &Number) -> Result<Vec<Number>, String>,
773) -> Result<Vec<V>, String> {
774 let n = a.len();
775 let scale = &natural.scale;
776 let ty = scale.residues.clone();
777 let counts = natural.value.depends();
778 let l = classes([counts.modulus(), ty.modulus()].into_iter().chain(state_moduli(x)))
779 .ok_or_else(|| "a flow's step count and state split over more residue classes than one value holds".to_string())?;
780 let matrix: crate::nested_flow::NMatrix = a.iter().map(|row| row.iter().map(tower::as_number).collect()).collect();
781 let mut columns: Vec<Vec<Option<Branch<V>>>> = vec![Vec::with_capacity(l as usize); n];
782 for c in 0..l {
783 let Some(count) = counts.at(c) else {
784 columns.iter_mut().for_each(|col| col.push(None));
785 continue;
786 };
787 let count = tower::as_number::<V>(&tower::from_hyper(Hyperreal::from_reciprocal_powers(count.coeffs()), scale));
788 let start: Vec<Number> = x.iter().map(|v| tower::as_number(&at_class(v, c))).collect();
789 let state = end(&matrix, &start, &count)?;
790 for (column, value) in columns.iter_mut().zip(state) {
791 column.push(Some(Branch(tower::from_number(value))));
792 }
793 }
794 Ok(columns
795 .into_iter()
796 .map(|raw| {
797 let d = Depends::from_branches(ty.clone(), l, raw).expect("the classes are the type's own");
798 tower::from_depends(d, scale)
799 })
800 .collect())
801}
802
803fn linear_count(count: &Number) -> Result<(Rational, Rational), String> {
806 let refuse = || {
807 "a flow's step count is a multiple of 1/dt; one that grows faster or slower has no standard end state here".to_string()
808 };
809 let hyper = match count.exact() {
810 Some(ExactRef::Hyper(h)) => h.value.rational().cloned().ok_or_else(refuse)?,
811 Some(ExactRef::Natural(n)) => n.value.to_hyperreal().single().cloned().ok_or_else(refuse)?,
812 _ => return Err(refuse()),
813 };
814 let powers = hyper.as_reciprocal_powers().ok_or_else(refuse)?;
815 if powers.len() != 2 || !powers[1].is_positive() {
816 return Err(if powers.len() == 2 { "a flow runs forward a positive time".to_string() } else { refuse() });
817 }
818 Ok((powers[1].clone(), powers[0].clone()))
819}
820
821struct Term<V> {
823 coefficient: V,
824 exponents: Vec<u32>,
825}
826
827fn poly_terms<V: ValueAlgebra>(poly: &V, width: usize) -> Result<Vec<Term<V>>, String> {
830 items(poly, "a polynomial update's component")?
831 .iter()
832 .map(|entry| {
833 let entry = items(entry, "a polynomial update's term")?;
834 if entry.len() != width + 1 {
835 return Err("a polynomial update's term names an exponent for every state variable".to_string());
836 }
837 let exponents = entry[1..]
838 .iter()
839 .map(|e| match e.shape() {
840 Shape::Int(k) => u32::try_from(k).map_err(|_| "an exponent is a small natural number".to_string()),
841 _ => Err("an exponent is a small natural number".to_string()),
842 })
843 .collect::<Result<Vec<u32>, String>>()?;
844 Ok(Term {
845 coefficient: entry[0].clone(),
846 exponents,
847 })
848 })
849 .collect()
850}
851
852fn update_terms<V: ValueAlgebra>(field: &V, width: usize) -> Result<Vec<Vec<Term<V>>>, String> {
854 let components = items(field, "a polynomial update")?;
855 if components.len() != width {
856 return Err(format!(
857 "a polynomial update has {} components for a state of {width}",
858 components.len()
859 ));
860 }
861 components.iter().map(|component| poly_terms(component, width)).collect()
862}
863
864fn eval_terms<V: ValueAlgebra>(terms: &[Term<V>], x: &[V]) -> Result<V, String> {
866 let mut total = int(0);
867 for term in terms {
868 let mut value = term.coefficient.clone();
869 for (v, e) in x.iter().zip(&term.exponents) {
870 for _ in 0..*e {
871 value = V::multiply(value, v.clone())?;
872 }
873 }
874 total = V::add(total, value)?;
875 }
876 Ok(total)
877}
878
879fn apply_update<V: ValueAlgebra>(terms: &[Vec<Term<V>>], x: &[V]) -> Result<Vec<V>, String> {
881 terms.iter().map(|component| eval_terms(component, x)).collect()
882}
883
884pub fn polynomial_flow<V: ValueAlgebra>(field: &V, vector: &V, n: &V) -> Result<V, String> {
890 let x = items(vector, "a supertask's state")?;
891 let terms = update_terms(field, x.len())?;
892 let natural = match n.shape() {
893 Shape::Int(k) if k >= 0 => {
894 let mut state = x;
895 for _ in 0..k {
896 state = apply_update(&terms, &state)?;
897 }
898 return Ok(V::list(state));
899 }
900 _ => infinite_count(n)?,
901 };
902 let width = x.len();
903 on_one_infinitesimal(terms.iter().flatten().map(|t| &t.coefficient), &natural.scale, "update", "a nonlinear flow is integrated over rates that are standard numbers")?;
904 on_one_infinitesimal(x.iter(), &natural.scale, "state", "a nonlinear flow is integrated from a start whose standard part is a number")?;
905 let mut components = Vec::with_capacity(width);
906 for (i, component) in terms.iter().enumerate() {
907 let mut monomials = Vec::new();
908 let mut identity = false;
909 for term in component {
910 let (q, series) = dt_polynomial(&term.coefficient, &natural.scale).ok_or_else(|| {
911 format!(
912 "the update's coefficient {} is not a polynomial in the infinitesimal, or in a root of it, with rational coefficients, so this supertask is not a flow the engine integrates",
913 term.coefficient.display_string()
914 )
915 })?;
916 if below_dt(q, &series) {
917 return Err(format!(
918 "the update's coefficient {} has a term of a fractional order of the infinitesimal below its first, so this supertask is not a flow",
919 term.coefficient.display_string()
920 ));
921 }
922 let at_zero = series.first().cloned().unwrap_or_else(Rational::zero);
923 let own = term.exponents.iter().enumerate().all(|(j, e)| *e == u32::from(j == i));
924 if own && at_zero == Rational::one() {
925 identity = true;
926 } else if !at_zero.is_zero() {
927 return Err(
928 "the update changes its state by a standard amount at every step as well as an infinitesimal one, so this supertask is neither a cycle nor a flow"
929 .to_string(),
930 );
931 }
932 let rate = series.get(q as usize).cloned().unwrap_or_else(Rational::zero);
933 if !rate.is_zero() {
934 monomials.push(Monomial {
935 coefficient: rate,
936 powers: term.exponents.clone(),
937 });
938 }
939 }
940 if !identity {
941 return Err(
942 "the update does not keep its state when the infinitesimal is zero, so this supertask is not a flow"
943 .to_string(),
944 );
945 }
946 components.push(monomials);
947 }
948 let ode = OdeField { components };
949 let scale = &natural.scale;
950 let ty = scale.residues.clone();
951 let counts = natural.value.depends();
952 let l = classes([counts.modulus(), ty.modulus()].into_iter().chain(state_moduli(&x)))
953 .ok_or_else(|| "a flow's step count and state split over more residue classes than one value holds".to_string())?;
954 let mut columns: Vec<Vec<Option<Branch<V>>>> = vec![Vec::with_capacity(l as usize); width];
955 for c in 0..l {
956 let Some(count) = counts.at(c) else {
957 columns.iter_mut().for_each(|col| col.push(None));
958 continue;
959 };
960 if count.degree().unwrap_or(0) != 1 {
961 return Err(
962 "a flow's step count is a multiple of 1/dt; one that grows faster or slower has no standard end state here"
963 .to_string(),
964 );
965 }
966 let t = count.coeff(1);
967 if !t.is_positive() {
968 return Err("a flow runs forward a positive time".to_string());
969 }
970 let start = x
971 .iter()
972 .map(|v| {
973 let at = at_class(v, c);
974 tower::germ_of(&at)
975 .and_then(|g| g.standard_part().ok().flatten())
976 .ok_or_else(|| {
977 format!("a flow starts from limited numbers, not {}", at.display_string())
978 })
979 })
980 .collect::<Result<Vec<ExactReal>, String>>()?;
981 let ends = flow_end(&ode, &start, &t)?;
982 for (column, end) in columns.iter_mut().zip(ends) {
983 column.push(Some(Branch(tower::from_germ(end, scale))));
984 }
985 }
986 Ok(V::list(
987 columns
988 .into_iter()
989 .map(|raw| {
990 let d = Depends::from_branches(ty.clone(), l, raw).expect("the classes are the type's own");
991 tower::from_depends(d, scale)
992 })
993 .collect(),
994 ))
995}
996
997fn flow_end(ode: &OdeField, start: &[ExactReal], t: &Rational) -> Result<Vec<Germ>, String> {
1000 let ends = ExactReal::flow(ode, start, t)
1001 .ok_or_else(|| "a flow's update and state disagree in shape".to_string())?;
1002 match ends[0].enclosure(8) {
1003 Ok(_) => Ok(ends.iter().map(Germ::standard).collect()),
1004 Err(RealError::Domain(_)) => {
1005 let escape = |p: &Poly, x0: &Rational| {
1006 escape_time_bound(p, x0, 24).is_some_and(|bound| bound < *t)
1007 };
1008 let scalar = (ode.components.len() == 1).then(|| {
1009 let mut coefficients = Vec::new();
1010 for m in &ode.components[0] {
1011 let k = m.powers[0] as usize;
1012 if coefficients.len() <= k {
1013 coefficients.resize(k + 1, Rational::zero());
1014 }
1015 coefficients[k] = coefficients[k].add(&m.coefficient);
1016 }
1017 Poly::from_coeffs(coefficients)
1018 });
1019 let x0 = start[0].exact_algebraic().and_then(|a| a.to_rational());
1020 match (scalar, x0) {
1021 (Some(p), Some(x0)) if escape(&p, &x0) => Ok(vec![Germ::unlimited(1)]),
1022 (Some(p), Some(x0)) if escape(&p.neg_var().neg(), &x0.negated()) => {
1023 Ok(vec![Germ::unlimited(-1)])
1024 }
1025 _ => Err(format!(
1026 "the solution of the flow leaves every bound before time {t}, and no certificate says it blows up there"
1027 )),
1028 }
1029 }
1030 Err(e) => Err(e.to_string()),
1031 }
1032}
1033
1034fn evaluate_by_class<V: ValueAlgebra>(
1037 natural: &NaturalValue,
1038 z: u64,
1039 p: u64,
1040 differences: &[Vec<Vec<V>>],
1041 width: usize,
1042) -> Result<Vec<V>, String> {
1043 let scale = &natural.scale;
1044 let refuse = |e: ResidueError| e.describe(&scale.generator_text());
1045 let ty = scale.residues.clone();
1046 let shifted = natural
1047 .value
1048 .sub(&Hypernatural::from_integer(BigInt::from_u64(z), &ty))
1049 .map_err(refuse)?;
1050 let residues = shifted.rem(&BigInt::from_u64(p)).map_err(refuse)?;
1051 let l = classes([residues.modulus(), shifted.depends().modulus(), ty.modulus()])
1052 .ok_or_else(|| "a supertask's step count splits over more residue classes than one value holds".to_string())?;
1053 let mut columns: Vec<Vec<Option<Branch<V>>>> = vec![Vec::with_capacity(l as usize); width];
1054 for c in 0..l {
1055 let (Some(r), Some(poly)) = (residues.at(c), shifted.depends().at(c)) else {
1056 for column in &mut columns {
1057 column.push(None);
1058 }
1059 continue;
1060 };
1061 let r_value = r.to_u64().expect("a residue below p");
1062 let q = poly
1063 .sub(&Poly::constant(Rational::from_bigint(r.clone())))
1064 .scale(&Rational::new(BigInt::from_u64(1), BigInt::from_u64(p)).expect("p > 0"));
1065 let q: V = tower::from_hyper(Hyperreal::from_reciprocal_powers(q.coeffs()), scale);
1066 let deltas = &differences[r_value as usize];
1067 let mut binomial: V = int(1);
1068 let mut totals: Vec<V> = vec![int(0); width];
1069 for (j, delta) in deltas.iter().enumerate() {
1070 if j > 0 {
1071 let factor = V::subtract(q.clone(), int(j as i64 - 1))?;
1072 binomial = V::exact_divide(V::multiply(binomial, factor)?, int(j as i64))?;
1073 }
1074 for (total, d) in totals.iter_mut().zip(delta) {
1075 *total = V::add(total.clone(), V::multiply(binomial.clone(), d.clone())?)?;
1076 }
1077 }
1078 for (column, total) in columns.iter_mut().zip(totals) {
1079 column.push(Some(Branch(total)));
1080 }
1081 }
1082 Ok(columns
1083 .into_iter()
1084 .map(|raw| {
1085 let d = Depends::from_branches(ty.clone(), l, raw).expect("the classes are the type's own");
1086 tower::from_depends(d, scale)
1087 })
1088 .collect())
1089}
1090
1091enum Encoded<V> {
1096 All(Vec<Encoded<V>>),
1097 Any(Vec<Encoded<V>>),
1098 Not(Box<Encoded<V>>),
1099 Compare(hybrid::Rel, Vec<Term<V>>),
1100 Infinitesimal(Vec<Term<V>>),
1101 Limited(Vec<Term<V>>),
1102 Truth(usize),
1103 Constant(bool),
1104}
1105
1106enum EncodedStmt<V> {
1107 Set(usize, Vec<Term<V>>),
1108 Put(usize, V),
1109 If(Encoded<V>, Vec<EncodedStmt<V>>, Vec<EncodedStmt<V>>),
1110}
1111
1112struct EncodedJump<V> {
1113 guard: Encoded<V>,
1114 block: Vec<EncodedStmt<V>>,
1115}
1116
1117enum EncodedItem<V> {
1120 Flow(Vec<Vec<Term<V>>>),
1121 Check(usize),
1122}
1123
1124fn tagged<V: ValueAlgebra>(v: &V, what: &str) -> Result<(String, Vec<V>), String> {
1126 let mut parts = items(v, what)?;
1127 if parts.is_empty() {
1128 return Err(format!("{what} is empty"));
1129 }
1130 let head = parts.remove(0);
1131 let tag = head
1132 .text()
1133 .ok_or_else(|| format!("{what} starts with its kind, named by Text"))?
1134 .to_string();
1135 Ok((tag, parts))
1136}
1137
1138fn slot_of<V: ValueAlgebra>(v: &V, width: usize) -> Result<usize, String> {
1139 match v.shape() {
1140 Shape::Int(k) if k >= 0 && (k as usize) < width => Ok(k as usize),
1141 _ => Err(format!(
1142 "a hybrid loop names a value by its place among its {width}, got {}",
1143 v.display_string()
1144 )),
1145 }
1146}
1147
1148fn encoded_cond<V: ValueAlgebra>(v: &V, width: usize) -> Result<Encoded<V>, String> {
1149 let (tag, parts) = tagged(v, "a hybrid loop's condition")?;
1150 let many = |parts: &[V]| -> Result<Vec<Encoded<V>>, String> { parts.iter().map(|p| encoded_cond(p, width)).collect() };
1151 fn one<'p, V>(parts: &'p [V], tag: &str) -> Result<&'p V, String> {
1152 match parts {
1153 [p] => Ok(p),
1154 _ => Err(format!("a hybrid loop's `{tag}` condition has one operand")),
1155 }
1156 }
1157 Ok(match tag.as_str() {
1158 "all" => Encoded::All(many(&parts)?),
1159 "any" => Encoded::Any(many(&parts)?),
1160 "not" => Encoded::Not(Box::new(encoded_cond(one(&parts, &tag)?, width)?)),
1161 "compare" => match parts.as_slice() {
1162 [rel, poly] => {
1163 let rel = rel
1164 .text()
1165 .and_then(hybrid::Rel::named)
1166 .ok_or_else(|| "a hybrid loop's comparison names its relation".to_string())?;
1167 Encoded::Compare(rel, poly_terms(poly, width)?)
1168 }
1169 _ => return Err("a hybrid loop's comparison is a relation and a polynomial".to_string()),
1170 },
1171 "infinitesimal" => Encoded::Infinitesimal(poly_terms(one(&parts, &tag)?, width)?),
1172 "limited" => Encoded::Limited(poly_terms(one(&parts, &tag)?, width)?),
1173 "truth" => Encoded::Truth(slot_of(one(&parts, &tag)?, width)?),
1174 "constant" => Encoded::Constant(truth_of(one(&parts, &tag)?)?),
1175 other => return Err(format!("a hybrid loop has no condition of kind `{other}`")),
1176 })
1177}
1178
1179fn encoded_block<V: ValueAlgebra>(v: &V, width: usize) -> Result<Vec<EncodedStmt<V>>, String> {
1180 items(v, "a hybrid loop's jump")?
1181 .iter()
1182 .map(|stmt| {
1183 let (tag, parts) = tagged(stmt, "a hybrid loop's statement")?;
1184 Ok(match (tag.as_str(), parts.as_slice()) {
1185 ("set", [slot, poly]) => EncodedStmt::Set(slot_of(slot, width)?, poly_terms(poly, width)?),
1186 ("put", [slot, value]) => EncodedStmt::Put(slot_of(slot, width)?, value.clone()),
1187 ("if", [cond, then, otherwise]) => EncodedStmt::If(
1188 encoded_cond(cond, width)?,
1189 encoded_block(then, width)?,
1190 encoded_block(otherwise, width)?,
1191 ),
1192 _ => return Err(format!("a hybrid loop has no statement of kind `{tag}` with {} parts", parts.len())),
1193 })
1194 })
1195 .collect()
1196}
1197
1198fn encoded_jumps<V: ValueAlgebra>(v: &V, width: usize) -> Result<Vec<EncodedJump<V>>, String> {
1199 items(v, "a hybrid loop's jumps")?
1200 .iter()
1201 .map(|jump| match items(jump, "a hybrid loop's jump")?.as_slice() {
1202 [guard, block] => Ok(EncodedJump {
1203 guard: encoded_cond(guard, width)?,
1204 block: encoded_block(block, width)?,
1205 }),
1206 _ => Err("a hybrid loop's jump is a guard and a block".to_string()),
1207 })
1208 .collect()
1209}
1210
1211fn encoded_schedule<V: ValueAlgebra>(v: &V, width: usize, jumps: usize) -> Result<Vec<EncodedItem<V>>, String> {
1212 let schedule = items(v, "a hybrid loop's body")?
1213 .iter()
1214 .map(|item| {
1215 let (tag, parts) = tagged(item, "a part of a hybrid loop's body")?;
1216 match (tag.as_str(), parts.as_slice()) {
1217 ("flow", [field]) => Ok(EncodedItem::Flow(update_terms(field, width)?)),
1218 ("check", [k]) => match k.shape() {
1219 Shape::Int(k) if k >= 0 && (k as usize) < jumps => Ok(EncodedItem::Check(k as usize)),
1220 _ => Err(format!("a hybrid loop checks one of its {jumps} jumps, got {}", k.display_string())),
1221 },
1222 _ => Err(format!("a part of a hybrid loop's body is a `flow` or a `check`, not `{tag}`")),
1223 }
1224 })
1225 .collect::<Result<Vec<_>, String>>()?;
1226 for k in 0..jumps {
1227 if schedule.iter().filter(|item| matches!(item, EncodedItem::Check(j) if *j == k)).count() != 1 {
1228 return Err("a hybrid loop's body checks each of its jumps once".to_string());
1229 }
1230 }
1231 Ok(schedule)
1232}
1233
1234fn truth_of<V: ValueAlgebra>(v: &V) -> Result<bool, String> {
1235 match v.shape() {
1236 Shape::Bool => Ok(v.values_equal(&V::boolean(true))),
1237 _ => Err(format!("a hybrid loop's condition reads a truth value, got {}", v.type_name())),
1238 }
1239}
1240
1241fn tower_rel(rel: hybrid::Rel) -> Rel {
1242 match rel {
1243 hybrid::Rel::Lt => Rel::Lt,
1244 hybrid::Rel::Le => Rel::LtEq,
1245 hybrid::Rel::Gt => Rel::Gt,
1246 hybrid::Rel::Ge => Rel::GtEq,
1247 hybrid::Rel::Eq => Rel::Eq,
1248 hybrid::Rel::Ne => Rel::NotEq,
1249 }
1250}
1251
1252fn literal_update<V: ValueAlgebra>(field: &[Vec<Term<V>>], x: &[V]) -> Result<Vec<V>, String> {
1255 field
1256 .iter()
1257 .enumerate()
1258 .map(|(i, component)| match component.as_slice() {
1259 [only]
1260 if only.exponents.iter().enumerate().all(|(j, e)| *e == u32::from(j == i))
1261 && only.coefficient.integer().is_some_and(|n| n == BigInt::from_i64(1)) =>
1262 {
1263 Ok(x[i].clone())
1264 }
1265 _ => eval_terms(component, x),
1266 })
1267 .collect()
1268}
1269
1270fn literal_cond<V: ValueAlgebra>(c: &Encoded<V>, x: &[V]) -> Result<bool, String> {
1271 Ok(match c {
1272 Encoded::All(cs) => {
1273 for c in cs {
1274 if !literal_cond(c, x)? {
1275 return Ok(false);
1276 }
1277 }
1278 true
1279 }
1280 Encoded::Any(cs) => {
1281 for c in cs {
1282 if literal_cond(c, x)? {
1283 return Ok(true);
1284 }
1285 }
1286 false
1287 }
1288 Encoded::Not(c) => !literal_cond(c, x)?,
1289 Encoded::Compare(rel, p) => V::holds(tower_rel(*rel), &eval_terms(p, x)?, &int(0))?,
1290 Encoded::Infinitesimal(p) => truth_of(&tower::is_infinitesimal(&eval_terms(p, x)?)?)?,
1291 Encoded::Limited(p) => truth_of(&tower::is_limited(&eval_terms(p, x)?)?)?,
1292 Encoded::Truth(slot) => truth_of(&x[*slot])?,
1293 Encoded::Constant(b) => *b,
1294 })
1295}
1296
1297fn literal_exec<V: ValueAlgebra>(stmts: &[EncodedStmt<V>], x: &mut [V]) -> Result<(), String> {
1298 for s in stmts {
1299 match s {
1300 EncodedStmt::Set(slot, p) => x[*slot] = eval_terms(p, x)?,
1301 EncodedStmt::Put(slot, v) => x[*slot] = v.clone(),
1302 EncodedStmt::If(c, then, otherwise) => {
1303 if literal_cond(c, x)? {
1304 literal_exec(then, x)?;
1305 } else {
1306 literal_exec(otherwise, x)?;
1307 }
1308 }
1309 }
1310 }
1311 Ok(())
1312}
1313
1314fn standard_value<V: ValueAlgebra>(v: &V) -> Result<(Algebraic, bool), String> {
1317 if let Some(r) = v.standard_rational() {
1318 return Ok((Algebraic::from_rational(r), true));
1319 }
1320 if let Some(ExactRef::Algebraic(a)) = v.exact() {
1321 return Ok((a.clone(), true));
1322 }
1323 let germ = tower::germ_of(v)
1324 .ok_or_else(|| format!("a hybrid loop computes with numbers, not {}", v.type_name()))?;
1325 let standard = germ
1326 .standard_part()
1327 .map_err(|e| e.to_string())?
1328 .ok_or_else(|| format!("a hybrid loop starts from limited numbers, not {}", v.display_string()))?;
1329 let a = standard.exact_algebraic().ok_or_else(|| {
1330 format!(
1331 "{} has no algebraic standard part, so the times a hybrid loop's jumps fire at are not found exactly",
1332 v.display_string()
1333 )
1334 })?;
1335 let exact = is_standard(v) || germ.as_hyperreal().is_some_and(|h| h.as_standard().is_some());
1336 Ok((a, exact))
1337}
1338
1339fn step_coefficients<V: ValueAlgebra>(v: &V) -> Result<(Algebraic, Algebraic), String> {
1342 if let Some(r) = v.standard_rational() {
1343 return Ok((Algebraic::from_rational(r), Algebraic::from_i64(0)));
1344 }
1345 let germ = tower::germ_of(v)
1346 .ok_or_else(|| format!("a hybrid loop's flow computes with numbers, not {}", v.type_name()))?;
1347 let order = |k: i64| -> Result<Algebraic, String> {
1348 germ.coefficient(k)
1349 .map_err(|e| e.to_string())?
1350 .exact_algebraic()
1351 .ok_or_else(|| format!("the flow's coefficient {} is not algebraic", v.display_string()))
1352 };
1353 if germ.floor() < 0 && (germ.floor()..0).any(|k| order(k).map_or(true, |c| !c.is_zero())) {
1354 return Err(format!("the flow's coefficient {} is not limited", v.display_string()));
1355 }
1356 let dt = i64::from(germ.ramification());
1357 if (1..dt).any(|k| order(k).map_or(true, |c| !c.is_zero())) {
1358 return Err(format!(
1359 "the flow's coefficient {} has a term of a fractional order of the infinitesimal below its first, so the loop is not an Euler step",
1360 v.display_string()
1361 ));
1362 }
1363 Ok((order(0)?, order(dt)?))
1364}
1365
1366fn ideal_poly<V: ValueAlgebra>(terms: &[Term<V>], width: usize, class: u64) -> Result<hybrid::Term, String> {
1367 let mut out = Vec::with_capacity(terms.len());
1368 let mut exact = true;
1369 for t in terms {
1370 let (a, is_exact) = standard_value(&at_class(&t.coefficient, class))?;
1371 exact &= is_exact;
1372 out.push((t.exponents.clone(), a));
1373 }
1374 Ok(hybrid::Term {
1375 poly: hybrid::MPoly::from_terms(width, out),
1376 exact,
1377 })
1378}
1379
1380fn ideal_cond<V: ValueAlgebra>(c: &Encoded<V>, width: usize, class: u64) -> Result<hybrid::Cond, String> {
1381 Ok(match c {
1382 Encoded::All(cs) => hybrid::Cond::All(cs.iter().map(|c| ideal_cond(c, width, class)).collect::<Result<_, _>>()?),
1383 Encoded::Any(cs) => hybrid::Cond::Any(cs.iter().map(|c| ideal_cond(c, width, class)).collect::<Result<_, _>>()?),
1384 Encoded::Not(c) => hybrid::Cond::Not(Box::new(ideal_cond(c, width, class)?)),
1385 Encoded::Compare(rel, p) => hybrid::Cond::Compare(*rel, ideal_poly(p, width, class)?),
1386 Encoded::Infinitesimal(p) => hybrid::Cond::Infinitesimal(ideal_poly(p, width, class)?),
1387 Encoded::Limited(p) => hybrid::Cond::Limited(ideal_poly(p, width, class)?),
1388 Encoded::Truth(slot) => hybrid::Cond::Truth(*slot),
1389 Encoded::Constant(b) => hybrid::Cond::Constant(*b),
1390 })
1391}
1392
1393fn ideal_cell<V: ValueAlgebra>(v: &V, others: &mut Vec<V>) -> Result<hybrid::Cell, String> {
1396 if matches!(v.shape(), Shape::Bool) {
1397 return Ok(hybrid::Cell::Bool(truth_of(v)?));
1398 }
1399 if is_number(v) {
1400 let (value, exact) = standard_value(v)?;
1401 return Ok(hybrid::Cell::Num { value, exact });
1402 }
1403 others.push(v.clone());
1404 Ok(hybrid::Cell::Other(others.len() - 1))
1405}
1406
1407fn ideal_block<V: ValueAlgebra>(
1408 stmts: &[EncodedStmt<V>],
1409 width: usize,
1410 class: u64,
1411 others: &mut Vec<V>,
1412) -> Result<Vec<hybrid::Stmt>, String> {
1413 stmts
1414 .iter()
1415 .map(|s| {
1416 Ok(match s {
1417 EncodedStmt::Set(slot, p) => hybrid::Stmt::Set {
1418 slot: *slot,
1419 value: hybrid::Value::Poly(ideal_poly(p, width, class)?),
1420 },
1421 EncodedStmt::Put(slot, v) => hybrid::Stmt::Set {
1422 slot: *slot,
1423 value: match ideal_cell(&at_class(v, class), others)? {
1424 hybrid::Cell::Num { value, exact } => hybrid::Value::Poly(hybrid::Term {
1425 poly: hybrid::MPoly::constant(width, value),
1426 exact,
1427 }),
1428 cell => hybrid::Value::Fixed(cell),
1429 },
1430 },
1431 EncodedStmt::If(c, then, otherwise) => hybrid::Stmt::If {
1432 cond: ideal_cond(c, width, class)?,
1433 then: ideal_block(then, width, class, others)?,
1434 otherwise: ideal_block(otherwise, width, class, others)?,
1435 },
1436 })
1437 })
1438 .collect()
1439}
1440
1441fn segment<V: ValueAlgebra>(field: &[Vec<Term<V>>], class: u64) -> Result<(Vec<hybrid::MPoly>, Vec<bool>), String> {
1444 let width = field.len();
1445 let mut rates = Vec::with_capacity(width);
1446 let mut preserved = Vec::with_capacity(width);
1447 for (i, component) in field.iter().enumerate() {
1448 let own = |t: &Term<V>| t.exponents.iter().enumerate().all(|(j, e)| *e == u32::from(j == i));
1449 let mut terms = Vec::new();
1450 let mut identity = false;
1451 for term in component {
1452 let (at_zero, rate) = step_coefficients(&at_class(&term.coefficient, class))?;
1453 if own(term) && at_zero == Algebraic::from_i64(1) {
1454 identity = true;
1455 } else if !at_zero.is_zero() {
1456 return Err(
1457 "a hybrid loop's flow changes a value by a standard amount at every step, so it is not an Euler step"
1458 .to_string(),
1459 );
1460 }
1461 if !rate.is_zero() {
1462 terms.push((term.exponents.clone(), rate));
1463 }
1464 }
1465 if !identity {
1466 return Err("a hybrid loop's flow does not keep its state when the infinitesimal is zero".to_string());
1467 }
1468 preserved.push(match component.as_slice() {
1469 [only] => {
1470 let c = at_class(&only.coefficient, class);
1471 own(only) && is_standard(&c) && as_rational(&c) == Some(Rational::one())
1472 }
1473 _ => false,
1474 });
1475 rates.push(hybrid::MPoly::from_terms(width, terms));
1476 }
1477 Ok((rates, preserved))
1478}
1479
1480fn float_reach<V: ValueAlgebra>(jumps: &[EncodedJump<V>], start: &[V]) -> Vec<bool> {
1483 fn walk<V: ValueAlgebra>(stmts: &[EncodedStmt<V>], reach: &mut [bool]) -> bool {
1484 let mut grown = false;
1485 for s in stmts {
1486 match s {
1487 EncodedStmt::Set(slot, p) => {
1488 let floats = p.iter().any(|t| {
1489 matches!(t.coefficient.shape(), Shape::Float)
1490 || t.exponents.iter().enumerate().any(|(i, e)| *e > 0 && reach[i])
1491 });
1492 if floats && !reach[*slot] {
1493 reach[*slot] = true;
1494 grown = true;
1495 }
1496 }
1497 EncodedStmt::Put(slot, v) => {
1498 if matches!(v.shape(), Shape::Float) && !reach[*slot] {
1499 reach[*slot] = true;
1500 grown = true;
1501 }
1502 }
1503 EncodedStmt::If(_, then, otherwise) => {
1504 grown |= walk(then, reach);
1505 grown |= walk(otherwise, reach);
1506 }
1507 }
1508 }
1509 grown
1510 }
1511 let mut reach: Vec<bool> = start.iter().map(|v| matches!(v.shape(), Shape::Float)).collect();
1512 while jumps.iter().any(|j| walk(&j.block, &mut reach)) {}
1513 reach
1514}
1515
1516pub fn hybrid_flow<V: ValueAlgebra>(model: &V, vector: &V, n: &V) -> Result<V, String> {
1524 let x = items(vector, "a hybrid loop's state")?;
1525 let width = x.len();
1526 let parts = items(model, "a hybrid loop's model")?;
1527 let [body, jumps] = parts.as_slice() else {
1528 return Err("a hybrid loop's model is its body and its jumps".to_string());
1529 };
1530 let jumps = encoded_jumps(jumps, width)?;
1531 let schedule = encoded_schedule(body, width, jumps.len())?;
1532 let natural = match n.shape() {
1533 Shape::Int(k) if k >= 0 => {
1534 let mut state = x;
1535 for _ in 0..k {
1536 for item in &schedule {
1537 match item {
1538 EncodedItem::Flow(field) => state = literal_update(field, &state)?,
1539 EncodedItem::Check(j) => {
1540 if literal_cond(&jumps[*j].guard, &state)? {
1541 literal_exec(&jumps[*j].block, &mut state)?;
1542 }
1543 }
1544 }
1545 }
1546 }
1547 return Ok(V::list(state));
1548 }
1549 _ => infinite_count(n)?,
1550 };
1551 on_one_infinitesimal([model, vector].into_iter(), &natural.scale, "loop", "a hybrid loop's rates and jumps are standard numbers")?;
1552 let floats = float_reach(&jumps, &x);
1553 let scale = &natural.scale;
1554 let ty = scale.residues.clone();
1555 let counts = natural.value.depends();
1556 let coefficient_moduli: Vec<V> = schedule
1557 .iter()
1558 .flat_map(|item| match item {
1559 EncodedItem::Flow(field) => field.iter().flatten().map(|t| t.coefficient.clone()).collect(),
1560 EncodedItem::Check(_) => Vec::new(),
1561 })
1562 .collect();
1563 let l = classes(
1564 [counts.modulus(), ty.modulus()]
1565 .into_iter()
1566 .chain(state_moduli(&x))
1567 .chain(state_moduli(&coefficient_moduli)),
1568 )
1569 .ok_or_else(|| "a hybrid loop's step count and state split over more residue classes than one value holds".to_string())?;
1570 let mut columns: Vec<Vec<Option<Branch<V>>>> = vec![Vec::with_capacity(l as usize); width];
1571 for c in 0..l {
1572 let Some(count) = counts.at(c) else {
1573 columns.iter_mut().for_each(|col| col.push(None));
1574 continue;
1575 };
1576 if count.degree().unwrap_or(0) != 1 {
1577 return Err(
1578 "a hybrid loop's step count is a multiple of 1/dt; one that grows faster or slower has no standard end state here"
1579 .to_string(),
1580 );
1581 }
1582 let span = count.coeff(1);
1583 if !span.is_positive() {
1584 return Err("a hybrid loop runs forward a positive time".to_string());
1585 }
1586 let items = schedule
1587 .iter()
1588 .map(|item| {
1589 Ok(match item {
1590 EncodedItem::Flow(field) => {
1591 let (rates, preserved) = segment(field, c)?;
1592 hybrid::Item::Flow { rates, preserved }
1593 }
1594 EncodedItem::Check(k) => hybrid::Item::Check(*k),
1595 })
1596 })
1597 .collect::<Result<Vec<_>, String>>()?;
1598 let mut others = Vec::new();
1599 let start = x
1600 .iter()
1601 .map(|v| ideal_cell(&at_class(v, c), &mut others))
1602 .collect::<Result<Vec<_>, String>>()?;
1603 let ideal_jumps = jumps
1604 .iter()
1605 .map(|j| {
1606 Ok(hybrid::Jump {
1607 guard: ideal_cond(&j.guard, width, c)?,
1608 block: ideal_block(&j.block, width, c, &mut others)?,
1609 })
1610 })
1611 .collect::<Result<Vec<_>, String>>()?;
1612 let model = hybrid::Model::new(width, items, ideal_jumps);
1613 let end = hybrid::run(&model, start.clone(), &Algebraic::from_rational(span))?;
1614 for (i, (column, cell)) in columns.iter_mut().zip(end).enumerate() {
1615 let value = match cell {
1616 hybrid::Cell::Num { value, exact: true } => {
1617 if floats[i] {
1618 match &start[i] {
1619 hybrid::Cell::Num { value: was, .. } if *was == value => at_class(&x[i], c),
1620 _ => {
1621 return Err(
1622 "a hybrid loop computes exactly, and a value its jumps set is a floating-point number, whose arithmetic rounds; declare it Rational or Real"
1623 .to_string(),
1624 )
1625 }
1626 }
1627 } else {
1628 tower::from_algebraic(value)
1629 }
1630 }
1631 hybrid::Cell::Num { value, exact: false } => {
1632 tower::from_germ(Germ::standard(&ExactReal::from_algebraic(value)), scale)
1633 }
1634 hybrid::Cell::Bool(b) => V::boolean(b),
1635 hybrid::Cell::Other(k) => others[k].clone(),
1636 };
1637 column.push(Some(Branch(value)));
1638 }
1639 }
1640 Ok(V::list(
1641 columns
1642 .into_iter()
1643 .map(|raw| {
1644 let d = Depends::from_branches(ty.clone(), l, raw).expect("the classes are the type's own");
1645 tower::from_depends(d, scale)
1646 })
1647 .collect(),
1648 ))
1649}
1650
1651pub fn cycle_at<V: ValueAlgebra>(states: &V, repeated: &V, n: &V) -> Result<V, String> {
1657 let states = items(states, "a supertask's recorded states")?;
1658 let mu = states
1659 .iter()
1660 .position(|s| s.values_equal(repeated))
1661 .ok_or_else(|| "the supertask engine's repeated state is not among the recorded ones".to_string())?;
1662 let lambda = (states.len() - mu) as u64;
1663 let state_at = |i: usize| items(&states[i], "a recorded state");
1664 if let Shape::Int(k) = n.shape() {
1665 if k >= 0 {
1666 let k = k as u64;
1667 let i = if k < states.len() as u64 {
1668 k
1669 } else {
1670 mu as u64 + (k - mu as u64) % lambda
1671 };
1672 return Ok(V::list(state_at(i as usize)?));
1673 }
1674 }
1675 if several_count(n) {
1676 let residue = V::modulo(V::subtract(n.clone(), int(mu as i64))?, int(lambda as i64))?;
1677 let width = state_at(mu)?.len();
1678 return Ok(V::list(
1679 (0..width)
1680 .map(|i| on_residue(&residue, &|r| Ok(state_at(mu + r as usize)?[i].clone())))
1681 .collect::<Result<_, _>>()?,
1682 ));
1683 }
1684 let nv = infinite_count(n)?;
1685 let scale = &nv.scale;
1686 let refuse = |e: ResidueError| e.describe(&scale.generator_text());
1687 let ty = scale.residues.clone();
1688 let shifted = nv
1689 .value
1690 .sub(&Hypernatural::from_integer(BigInt::from_u64(mu as u64), &ty))
1691 .map_err(refuse)?;
1692 let residues = shifted.rem(&BigInt::from_u64(lambda)).map_err(refuse)?;
1693 let width = state_at(mu)?.len();
1694 let mut columns: Vec<Vec<Option<Branch<V>>>> = vec![Vec::new(); width];
1695 for c in 0..residues.modulus() {
1696 match residues.at(c) {
1697 None => columns.iter_mut().for_each(|col| col.push(None)),
1698 Some(r) => {
1699 let state = state_at(mu + r.to_u64().expect("a residue below λ") as usize)?;
1700 for (column, value) in columns.iter_mut().zip(state) {
1701 column.push(Some(Branch(value)));
1702 }
1703 }
1704 }
1705 }
1706 Ok(V::list(
1707 columns
1708 .into_iter()
1709 .map(|raw| {
1710 let d = Depends::from_branches(ty.clone(), residues.modulus(), raw)
1711 .expect("the classes are the type's own");
1712 tower::from_depends(d, scale)
1713 })
1714 .collect(),
1715 ))
1716}
1717
1718pub fn state_size<V: ValueAlgebra>(v: &V) -> u64 {
1724 match v.shape() {
1725 Shape::Bool => 1,
1726 Shape::Int(_) | Shape::Float => 64,
1727 Shape::BigInt(b) => b.bit_len().max(64),
1728 Shape::Rational(r) => r.numerator().bit_len() + r.denominator().bit_len(),
1729 Shape::Text(len) => 8 * len as u64,
1730 Shape::List(values) | Shape::Tuple(values) => values.iter().map(state_size).sum(),
1731 Shape::Decimal | Shape::Other => match tower::exact_bytes(v) {
1732 Some((_, bytes)) => 8 * bytes.len() as u64,
1733 None => 8 * v.display_string().len() as u64,
1734 },
1735 }
1736}
1737
1738enum Guard<V> {
1743 Linear { rel: Rel, a: V, b: V },
1745 Remainder { rel: Rel, a: V, b: V, m: V, c: V },
1747 And(Box<Guard<V>>, Box<Guard<V>>),
1748 Or(Box<Guard<V>>, Box<Guard<V>>),
1749 Not(Box<Guard<V>>),
1750}
1751
1752enum Truth {
1755 Holds(bool),
1756 Finer(u64),
1757}
1758
1759fn relation_named(name: &str) -> Option<Rel> {
1760 Some(match name {
1761 "<" => Rel::Lt,
1762 "<=" => Rel::LtEq,
1763 ">" => Rel::Gt,
1764 ">=" => Rel::GtEq,
1765 "=" => Rel::Eq,
1766 "!=" => Rel::NotEq,
1767 _ => return None,
1768 })
1769}
1770
1771impl<V: ValueAlgebra> Guard<V> {
1772 fn read(v: &V) -> Result<Guard<V>, String> {
1775 let malformed = || format!("a loop's guard is a formula the supertask engine writes, got {}", v.display_string());
1776 let parts = items(v, "a loop's guard")?;
1777 let tag = parts.first().and_then(|t| t.text().map(str::to_string));
1778 let sub = |i: usize| match parts.get(i) {
1779 Some(p) => Guard::read(p).map(Box::new),
1780 None => Err(malformed()),
1781 };
1782 let at = |i: usize| parts.get(i).cloned().ok_or_else(malformed);
1783 let relation = |v: V| v.text().and_then(relation_named).ok_or_else(malformed);
1784 match (tag.as_deref(), parts.len()) {
1785 (Some("and"), 3) => Ok(Guard::And(sub(1)?, sub(2)?)),
1786 (Some("or"), 3) => Ok(Guard::Or(sub(1)?, sub(2)?)),
1787 (Some("not"), 2) => Ok(Guard::Not(sub(1)?)),
1788 (Some("%"), 6) => Ok(Guard::Remainder {
1789 rel: relation(at(1)?)?,
1790 a: at(2)?,
1791 b: at(3)?,
1792 m: at(4)?,
1793 c: at(5)?,
1794 }),
1795 (Some(_), 3) => Ok(Guard::Linear {
1796 rel: relation(at(0)?)?,
1797 a: at(1)?,
1798 b: at(2)?,
1799 }),
1800 _ => Err(malformed()),
1801 }
1802 }
1803
1804 fn numbers<'g>(&'g self, out: &mut Vec<&'g V>) {
1806 match self {
1807 Guard::Linear { a, b, .. } => out.extend([a, b]),
1808 Guard::Remainder { a, b, m, c, .. } => out.extend([a, b, m, c]),
1809 Guard::And(f, g) | Guard::Or(f, g) => {
1810 f.numbers(out);
1811 g.numbers(out);
1812 }
1813 Guard::Not(f) => f.numbers(out),
1814 }
1815 }
1816
1817 fn atoms<'g>(&'g self, out: &mut Vec<&'g Guard<V>>) {
1819 match self {
1820 Guard::Linear { .. } | Guard::Remainder { .. } => out.push(self),
1821 Guard::And(f, g) | Guard::Or(f, g) => {
1822 f.atoms(out);
1823 g.atoms(out);
1824 }
1825 Guard::Not(f) => f.atoms(out),
1826 }
1827 }
1828
1829 fn map(&self, f: &dyn Fn(&V) -> V) -> Guard<V> {
1831 match self {
1832 Guard::Linear { rel, a, b } => Guard::Linear {
1833 rel: *rel,
1834 a: f(a),
1835 b: f(b),
1836 },
1837 Guard::Remainder { rel, a, b, m, c } => Guard::Remainder {
1838 rel: *rel,
1839 a: f(a),
1840 b: f(b),
1841 m: f(m),
1842 c: f(c),
1843 },
1844 Guard::And(x, y) => Guard::And(Box::new(x.map(f)), Box::new(y.map(f))),
1845 Guard::Or(x, y) => Guard::Or(Box::new(x.map(f)), Box::new(y.map(f))),
1846 Guard::Not(x) => Guard::Not(Box::new(x.map(f))),
1847 }
1848 }
1849
1850 fn at(&self, t: &V) -> Result<Truth, String> {
1852 let term = |a: &V, b: &V| V::add(V::multiply(a.clone(), t.clone())?, b.clone());
1853 let decided = |value: V, rel: Rel, against: &V| -> Result<Truth, String> {
1854 match dependence(&value) {
1855 1 => Ok(Truth::Holds(V::holds(rel, &value, against)?)),
1856 finer => Ok(Truth::Finer(finer)),
1857 }
1858 };
1859 let both = |f: &Guard<V>, g: &Guard<V>, and: bool| -> Result<Truth, String> {
1860 match f.at(t)? {
1861 Truth::Holds(x) if x != and => Ok(Truth::Holds(x)),
1862 Truth::Holds(_) => g.at(t),
1863 finer => Ok(finer),
1864 }
1865 };
1866 match self {
1867 Guard::Linear { rel, a, b } => decided(term(a, b)?, *rel, &int(0)),
1868 Guard::Remainder { rel, a, b, m, c } => decided(V::modulo(term(a, b)?, m.clone())?, *rel, c),
1869 Guard::And(f, g) => both(f, g, true),
1870 Guard::Or(f, g) => both(f, g, false),
1871 Guard::Not(f) => Ok(match f.at(t)? {
1872 Truth::Holds(x) => Truth::Holds(!x),
1873 finer => finer,
1874 }),
1875 }
1876 }
1877}
1878
1879fn dependence<V: TowerValue>(v: &V) -> u64 {
1882 match v.exact() {
1883 Some(ExactRef::Natural(n)) if n.value.depends().single().is_none() => n.value.depends().modulus(),
1884 Some(ExactRef::Depends(d)) if d.value.single().is_none() => d.value.modulus(),
1885 _ => 1,
1886 }
1887}
1888
1889fn infinitesimals_in<V: ValueAlgebra>(v: &V, out: &mut Vec<Arc<Scale>>) {
1894 let push = |s: &Arc<Scale>, out: &mut Vec<Arc<Scale>>| {
1895 if !out.iter().any(|t| t.same_infinitesimal(s)) {
1896 out.push(s.clone());
1897 }
1898 };
1899 if let Shape::List(items) | Shape::Tuple(items) = v.shape() {
1900 for item in &items {
1901 infinitesimals_in(item, out);
1902 }
1903 return;
1904 }
1905 match v.exact() {
1906 Some(ExactRef::Hyper(h)) => match &h.value {
1907 HyperForm::Multi(m) | HyperForm::Integer(m) => m.scales().iter().for_each(|s| push(s, out)),
1908 HyperForm::Nested(g) => g.scales().iter().for_each(|s| push(s, out)),
1909 _ => push(&h.scale, out),
1910 },
1911 Some(ExactRef::Natural(n)) => push(&n.scale, out),
1912 Some(ExactRef::Depends(d)) => {
1913 push(&d.scale, out);
1914 for (_, b) in d.value.branches() {
1915 infinitesimals_in(&b.0, out);
1916 }
1917 }
1918 Some(ExactRef::Converging(c)) => infinitesimals_in(c.value(), out),
1919 _ => {}
1920 }
1921}
1922
1923fn on_one_infinitesimal<'v, V: ValueAlgebra + 'v>(
1926 values: impl Iterator<Item = &'v V>,
1927 clock: &Scale,
1928 what: &str,
1929 why: &str,
1930) -> Result<(), String> {
1931 let mut found = Vec::new();
1932 for v in values {
1933 infinitesimals_in(v, &mut found);
1934 }
1935 match found.iter().find(|s| !s.same_infinitesimal(clock)) {
1936 Some(other) => Err(format!(
1937 "this supertask steps by {} and its {what} holds {}: {why}",
1938 clock.name, other.name
1939 )),
1940 None => Ok(()),
1941 }
1942}
1943
1944fn sole_infinitesimal<V: ValueAlgebra>(values: &[&V]) -> Result<Option<Arc<Scale>>, String> {
1946 let mut found = Vec::new();
1947 for v in values {
1948 infinitesimals_in(*v, &mut found);
1949 }
1950 match found.as_slice() {
1951 [] => Ok(None),
1952 [one] => Ok(Some(one.clone())),
1953 [a, b, ..] => Err(format!(
1954 "this supertask's values hold both {} and {}; a supertask over one infinitesimal whose values hold another is not resolved",
1955 a.name, b.name
1956 )),
1957 }
1958}
1959
1960fn residue_generators<V: ValueAlgebra>(v: &V, out: &mut Vec<Arc<Scale>>) {
1964 let mut push = |s: &Arc<Scale>| {
1965 if !out.iter().any(|t| t.same_infinitesimal(s)) {
1966 out.push(s.clone());
1967 }
1968 };
1969 if let Shape::List(items) | Shape::Tuple(items) = v.shape() {
1970 for item in &items {
1971 residue_generators(item, out);
1972 }
1973 return;
1974 }
1975 match v.exact() {
1976 Some(ExactRef::Natural(n)) if n.value.depends().single().is_none() => push(&n.scale),
1977 Some(ExactRef::Depends(d)) => {
1978 push(&d.scale);
1979 for (_, b) in d.value.branches() {
1980 residue_generators(&b.0, out);
1981 }
1982 }
1983 Some(ExactRef::Converging(c)) => residue_generators(c.value(), out),
1984 _ => {}
1985 }
1986}
1987
1988fn moduli_on<V: ValueAlgebra>(v: &V, scale: &Scale, out: &mut Vec<u64>) {
1991 if let Shape::List(items) | Shape::Tuple(items) = v.shape() {
1992 for item in &items {
1993 moduli_on(item, scale, out);
1994 }
1995 return;
1996 }
1997 match v.exact() {
1998 Some(ExactRef::Natural(n)) if n.scale.same_infinitesimal(scale) => out.push(dependence(v)),
1999 Some(ExactRef::Depends(d)) => {
2000 if d.scale.same_infinitesimal(scale) {
2001 out.push(dependence(v));
2002 }
2003 for (_, b) in d.value.branches() {
2004 moduli_on(&b.0, scale, out);
2005 }
2006 }
2007 Some(ExactRef::Converging(c)) => moduli_on(c.value(), scale, out),
2008 _ => {}
2009 }
2010}
2011
2012fn dependences<V: ValueAlgebra>(v: &V, out: &mut Vec<V>) {
2014 match v.shape() {
2015 Shape::List(items) | Shape::Tuple(items) => {
2016 for item in &items {
2017 dependences(item, out);
2018 }
2019 }
2020 _ => {
2021 if matches!(v.exact(), Some(ExactRef::Depends(_))) {
2022 out.push(v.clone());
2023 }
2024 }
2025 }
2026}
2027
2028fn pinned<V: ValueAlgebra>(v: &V, h: u64, class: &Arc<Scale>) -> V {
2030 match v.shape() {
2031 Shape::List(items) => V::list(items.iter().map(|item| pinned(item, h, class)).collect()),
2032 _ => on_class(v, h, class),
2033 }
2034}
2035
2036fn rescaled<V: ValueAlgebra>(v: &V, scale: &Arc<Scale>) -> V {
2040 if let Shape::List(items) = v.shape() {
2041 return V::list(items.iter().map(|item| rescaled(item, scale)).collect());
2042 }
2043 match v.exact() {
2044 Some(ExactRef::Hyper(x)) if x.scale.same_infinitesimal(scale) && !matches!(x.value, HyperForm::Multi(_) | HyperForm::Integer(_) | HyperForm::Nested(_)) => V::hyper(HyperValue {
2045 value: x.value.clone(),
2046 scale: scale.clone(),
2047 }),
2048 _ => v.clone(),
2049 }
2050}
2051
2052fn joined<V: ValueAlgebra>(scale: &Arc<Scale>, modulus: u64, answers: Vec<Option<V>>) -> V {
2055 let lists: Option<Vec<Option<Vec<V>>>> = answers
2056 .iter()
2057 .map(|a| match a {
2058 None => Some(None),
2059 Some(v) => match v.shape() {
2060 Shape::List(items) => Some(Some(items)),
2061 _ => None,
2062 },
2063 })
2064 .collect();
2065 if let Some(lists) = lists {
2066 let mut widths = lists.iter().flatten().map(Vec::len);
2067 if let Some(width) = widths.next().filter(|w| widths.all(|x| x == *w)) {
2068 return V::list(
2069 (0..width)
2070 .map(|i| joined(scale, modulus, lists.iter().map(|l| l.as_ref().map(|l| l[i].clone())).collect()))
2071 .collect(),
2072 );
2073 }
2074 }
2075 let branches = answers.into_iter().map(|a| a.map(Branch)).collect();
2076 let value = Depends::from_branches(scale.residues.clone(), modulus, branches).expect("the classes are the type's own");
2077 tower::from_depends(value, scale)
2078}
2079
2080fn on_each_class<V: ValueAlgebra>(args: &[&V], f: impl Fn(&[V]) -> Result<V, String>) -> Option<Result<V, String>> {
2091 let mut found = Vec::new();
2092 for arg in args {
2093 dependences(*arg, &mut found);
2094 }
2095 let mut generators = Vec::new();
2096 for arg in args {
2097 residue_generators(*arg, &mut generators);
2098 }
2099 for (i, x) in generators.iter().enumerate() {
2100 if let Some(y) = generators[i + 1..].iter().find(|y| x.order(y).is_none()) {
2101 return Some(Err(x.unordered(y)));
2102 }
2103 }
2104 let scale = match generators.as_slice() {
2105 [first, _, ..] => first.clone(),
2106 _ => scale_among(&found.iter().collect::<Vec<_>>())?,
2107 };
2108 let refuse = |e: ResidueError| e.describe(&scale.generator_text());
2109 let mut modulus = scale.residues.modulus();
2110 let mut moduli = Vec::new();
2111 for arg in args {
2112 moduli_on(*arg, &scale, &mut moduli);
2113 }
2114 for m in moduli {
2115 modulus = match bounded_lcm(modulus, m) {
2116 Ok(m) => m,
2117 Err(e) => return Some(Err(refuse(e))),
2118 };
2119 }
2120 let mut answers: Vec<Option<V>> = Vec::with_capacity(modulus as usize);
2121 for h in 0..modulus {
2122 if !scale.residues.admits(h) {
2123 answers.push(None);
2124 continue;
2125 }
2126 let class = Arc::new(scale.with_residues(
2127 scale
2128 .residues
2129 .and(&ResidueType::congruent(h, modulus))
2130 .expect("an admitted class is consistent with its type"),
2131 ));
2132 let on_class: Vec<V> = args.iter().map(|arg| pinned(*arg, h, &class)).collect();
2133 match f(&on_class) {
2134 Ok(answer) => answers.push(Some(rescaled(&answer, &scale))),
2135 Err(e) => return Some(Err(e)),
2136 }
2137 }
2138 Some(Ok(joined(&scale, modulus, answers)))
2139}
2140
2141fn scale_among<V: TowerValue>(values: &[&V]) -> Option<Arc<Scale>> {
2143 values.iter().find_map(|v| match v.exact()? {
2144 ExactRef::Hyper(h) => Some(h.scale.clone()),
2145 ExactRef::Natural(n) => Some(n.scale.clone()),
2146 ExactRef::Depends(d) => Some(d.scale.clone()),
2147 _ => None,
2148 })
2149}
2150
2151fn on_class<V: TowerValue>(v: &V, h: u64, class: &Arc<Scale>) -> V {
2155 match v.exact() {
2156 Some(ExactRef::Hyper(x)) if x.scale.same_infinitesimal(class) && !matches!(x.value, HyperForm::Multi(_) | HyperForm::Integer(_) | HyperForm::Nested(_)) => V::hyper(HyperValue {
2157 value: x.value.clone(),
2158 scale: class.clone(),
2159 }),
2160 Some(ExactRef::Natural(n)) if n.scale.same_infinitesimal(class) => {
2161 let p = n.value.depends().at(h).expect("an admitted class has a branch").clone();
2162 let value = Hypernatural::from_polynomial(p, &class.residues).expect("a branch is an integer on its class");
2163 tower::from_natural(value, class)
2164 }
2165 Some(ExactRef::Depends(d)) if d.scale.same_infinitesimal(class) => {
2166 on_class(&d.value.at(h).expect("an admitted class has a branch").0, h, class)
2167 }
2168 _ => v.clone(),
2169 }
2170}
2171
2172fn class_polynomial<V: TowerValue>(v: &V) -> Option<Poly> {
2174 if let Some(n) = v.integer() {
2175 return Some(Poly::constant(Rational::from_bigint(n)));
2176 }
2177 match v.exact()? {
2178 ExactRef::Natural(n) => n.value.depends().single().cloned(),
2179 _ => None,
2180 }
2181}
2182
2183enum Exit<V> {
2185 At(V),
2186 Never,
2187 Finer(u64),
2189}
2190
2191pub fn first_exit<V: ValueAlgebra>(t0: &V, step: &V, guard: &V) -> Result<V, String> {
2203 let guard = Guard::read(guard)?;
2204 let mut numbers = vec![t0, step];
2205 guard.numbers(&mut numbers);
2206 let countable = |v: &&V| {
2207 v.is_standard_number()
2208 || matches!(
2209 v.exact(),
2210 Some(
2211 ExactRef::Algebraic(_)
2212 | ExactRef::Real(_)
2213 | ExactRef::Hyper(_)
2214 | ExactRef::Natural(_)
2215 | ExactRef::Depends(_)
2216 )
2217 )
2218 };
2219 if !numbers.iter().all(countable) || numbers.iter().all(|v| is_standard(*v)) {
2220 return Ok(int(-1));
2221 }
2222 sole_infinitesimal(&numbers)?;
2223 let scale = scale_among(&numbers).expect("a value that is not standard has a scale");
2224 let refuse = |e: ResidueError| e.describe(&scale.generator_text());
2225 let mut modulus = scale.residues.modulus();
2226 for v in &numbers {
2227 modulus = bounded_lcm(modulus, dependence(*v)).map_err(refuse)?;
2228 }
2229 'refine: loop {
2230 let mut exits: Vec<Option<Exit<V>>> = Vec::with_capacity(modulus as usize);
2231 for h in 0..modulus {
2232 if !scale.residues.admits(h) {
2233 exits.push(None);
2234 continue;
2235 }
2236 let class = Arc::new(scale.with_residues(
2237 scale
2238 .residues
2239 .and(&ResidueType::congruent(h, modulus))
2240 .expect("an admitted class is consistent with its type"),
2241 ));
2242 let pin = |v: &V| on_class(v, h, &class);
2243 let (t0, step) = (pin(t0), pin(step));
2244 match exit_on_class(&t0, &step, &guard.map(&pin))? {
2245 Exit::Finer(m) => {
2246 let finer = bounded_lcm(modulus, m).map_err(refuse)?;
2247 if finer == modulus {
2248 return Err(format!(
2249 "this loop's guard depends on the residue of {} past the classes that separate it",
2250 scale.generator_text()
2251 ));
2252 }
2253 modulus = finer;
2254 continue 'refine;
2255 }
2256 exit => exits.push(Some(exit)),
2257 }
2258 }
2259 if exits.iter().flatten().any(|e| matches!(e, Exit::Never)) {
2260 let finite = exits.iter().flatten().all(|e| match e {
2261 Exit::At(k) => is_standard(k),
2262 _ => true,
2263 });
2264 if is_standard(step) && finite {
2265 return Ok(int(-1));
2266 }
2267 return Err(format!(
2268 "this loop never ends: its counter starts at {}, steps by {}, and its guard holds at every step",
2269 t0.display_string(),
2270 step.display_string()
2271 ));
2272 }
2273 let branches: Vec<Option<Poly>> = exits
2274 .iter()
2275 .map(|e| match e {
2276 Some(Exit::At(k)) => Some(class_polynomial(k).expect("an exit is an integer on its class")),
2277 _ => None,
2278 })
2279 .collect();
2280 let value = Depends::from_branches(scale.residues.clone(), modulus, branches)
2281 .expect("the classes are the type's own");
2282 let count = Hypernatural::from_branches(value).expect("each branch is an integer on its class");
2283 return Ok(tower::from_natural(count, &scale));
2284 }
2285}
2286
2287fn exit_on_class<V: ValueAlgebra>(t0: &V, step: &V, guard: &Guard<V>) -> Result<Exit<V>, String> {
2289 let mut starts: Vec<V> = vec![int(0)];
2290 let mut period: u64 = 1;
2291 let mut atoms = Vec::new();
2292 guard.atoms(&mut atoms);
2293 for atom in atoms {
2294 let (Guard::Linear { a, b, .. } | Guard::Remainder { a, b, .. }) = atom else {
2295 unreachable!("an atom is a linear term or a remainder");
2296 };
2297 let rate = V::multiply(a.clone(), step.clone())?;
2298 if let Guard::Remainder { m, .. } = atom {
2299 let entry = V::list(vec![rate.clone(), m.clone()]);
2300 let p = remainder_period(&entry)?.ok_or_else(|| {
2301 format!(
2302 "a loop's guard takes a remainder by a whole number of a term that steps by a \
2303 rational amount; here the term steps by {} and the remainder is by {}",
2304 rate.display_string(),
2305 m.display_string()
2306 )
2307 })?;
2308 period = bounded_lcm(period, p).map_err(|_| "a loop's guard repeats with too long a period".to_string())?;
2309 continue;
2310 }
2311 if V::holds(Rel::Eq, &rate, &int(0))? {
2312 continue;
2313 }
2314 let start = V::add(V::multiply(a.clone(), t0.clone())?, b.clone())?;
2315 let crossing = V::floor(V::exact_divide(V::subtract(int(0), start)?, rate)?)?;
2316 match dependence(&crossing) {
2317 1 => starts.push(crossing),
2318 finer => return Ok(Exit::Finer(finer)),
2319 }
2320 }
2321 let mut ordered: Vec<V> = Vec::with_capacity(starts.len());
2322 for s in starts {
2323 if !V::holds(Rel::GtEq, &s, &int(0))? {
2324 continue;
2325 }
2326 let mut at = ordered.len();
2327 for (i, o) in ordered.iter().enumerate() {
2328 if V::holds(Rel::LtEq, &s, o)? {
2329 at = i;
2330 break;
2331 }
2332 }
2333 if at == ordered.len() || !V::holds(Rel::Eq, &s, &ordered[at])? {
2334 ordered.insert(at, s);
2335 }
2336 }
2337 let mut examined: u64 = 0;
2338 let mut next: Option<V> = None;
2339 for s in ordered {
2340 let mut k = match next {
2341 Some(n) if V::holds(Rel::Gt, &n, &s)? => n,
2342 _ => s.clone(),
2343 };
2344 let last = V::add(s, int(period as i64))?;
2345 while V::holds(Rel::LtEq, &k, &last)? {
2346 examined += 1;
2347 if examined > MAX_CANDIDATES {
2348 return Err("a loop's guard changes at too many points to read where it first fails".to_string());
2349 }
2350 let t = V::add(t0.clone(), V::multiply(k.clone(), step.clone())?)?;
2351 match guard.at(&t)? {
2352 Truth::Holds(true) => {}
2353 Truth::Holds(false) => return Ok(Exit::At(k)),
2354 Truth::Finer(m) => return Ok(Exit::Finer(m)),
2355 }
2356 k = V::add(k, int(1))?;
2357 }
2358 next = Some(k);
2359 }
2360 Ok(Exit::Never)
2361}
2362
2363const MAX_CANDIDATES: u64 = 1 << 20;
2367
2368fn exact_standard<V: ValueAlgebra>(v: &V) -> Option<V> {
2371 match v.shape() {
2372 Shape::Int(_) | Shape::BigInt(_) | Shape::Rational(_) => Some(v.clone()),
2373 _ => matches!(v.exact(), Some(ExactRef::Algebraic(_))).then(|| v.clone()),
2374 }
2375}
2376
2377fn remainder_period<V: ValueAlgebra>(entry: &V) -> Result<Option<u64>, String> {
2381 let (a, m) = match entry.shape() {
2382 Shape::List(_) => {
2383 let pair = items(entry, "a remainder term")?;
2384 match pair.as_slice() {
2385 [a, m] => (a.clone(), m.clone()),
2386 _ => return Ok(None),
2387 }
2388 }
2389 _ => (int(1), entry.clone()),
2390 };
2391 let m = match m.shape() {
2392 Shape::Int(k) if k > 0 => k as u64,
2393 _ => return Ok(None),
2394 };
2395 let denominator = match a.shape() {
2396 Shape::Int(_) | Shape::BigInt(_) => 1,
2397 Shape::Rational(r) => match r.denominator().to_u64() {
2398 Some(q) => q,
2399 None => return Ok(None),
2400 },
2401 _ => return Ok(None),
2402 };
2403 Ok(m.checked_mul(denominator))
2404}
2405
2406pub fn search_candidates<V: ValueAlgebra>(atoms: &V, moduli: &V) -> Result<V, String> {
2410 let undecided = || Ok(V::list(Vec::new()));
2411 let mut period: u64 = 1;
2412 for entry in items(moduli, "a search's periods")? {
2413 let Some(m) = remainder_period(&entry)? else {
2414 return undecided();
2415 };
2416 let l = u128::from(period / gcd(period, m)) * u128::from(m);
2417 if l > u128::from(MAX_CANDIDATES) {
2418 return undecided();
2419 }
2420 period = l as u64;
2421 }
2422 let mut starts: Vec<u64> = vec![0];
2423 for atom in items(atoms, "a search's linear terms")? {
2424 let pair = items(&atom, "a linear term")?;
2425 let (Some(a), Some(b)) = (
2426 pair.first().and_then(exact_standard),
2427 pair.get(1).and_then(exact_standard),
2428 ) else {
2429 return undecided();
2430 };
2431 if V::holds(Rel::Eq, &a, &int(0))? {
2432 continue;
2433 }
2434 let root = V::exact_divide(V::subtract(int(0), b)?, a)?;
2435 let sides: [fn(V) -> Result<V, String>; 2] = [V::floor, V::ceil];
2436 for side in sides {
2437 match side(root.clone())?.shape() {
2438 Shape::Int(t) if t >= 0 => starts.push(t as u64),
2439 Shape::Int(_) => {}
2440 Shape::BigInt(t) if t.is_negative() => {}
2441 _ => return undecided(),
2442 }
2443 }
2444 }
2445 starts.sort_unstable();
2446 starts.dedup();
2447 let mut out: Vec<u64> = Vec::new();
2448 for s in starts {
2449 let from = out.last().map_or(s, |last| s.max(last + 1));
2450 let to = s.saturating_add(period);
2451 if to >= from {
2452 if out.len() as u64 + (to - from + 1) > MAX_CANDIDATES {
2453 return undecided();
2454 }
2455 out.extend(from..=to);
2456 }
2457 }
2458 Ok(V::list(out.into_iter().map(|n| int(n as i64)).collect()))
2459}
2460
2461#[cfg(test)]
2462#[path = "../../logicaffeine_tests/unit/logicaffeine_base/supertask/tests.rs"]
2463mod tests;