1use std::sync::Arc;
20
21use crate::closure::AlgValue;
22use crate::expansion::{Coefficient, Expansion, ExpansionError, Source};
23use crate::germ::{Germ, SIGN_ORDERS};
24use crate::multi::Multi;
25use crate::nested_flow::{FlowSpec, MatrixExpSpec, PowerSpec};
26use crate::number::Number;
27use crate::numeric::Rational;
28use crate::puiseux::{expansion_term, remainder, remainder_after};
29use crate::tower::{self, ExactRef, HyperForm, Scale, TowerValue};
30
31#[derive(Clone, Debug)]
33pub(crate) enum GermRecipe {
34 Exact(Multi),
36 Germ(Germ),
38 Constant(Number),
40 Add(Arc<NestedGerm>, Arc<NestedGerm>),
41 Sub(Arc<NestedGerm>, Arc<NestedGerm>),
42 Neg(Arc<NestedGerm>),
43 Mul(Arc<NestedGerm>, Arc<NestedGerm>),
44 Recip(Arc<NestedGerm>),
45 Root(Arc<NestedGerm>, u32),
46 Exp(Arc<NestedGerm>),
47 Ln(Arc<NestedGerm>),
48 MatrixExp(Arc<MatrixExpSpec>, usize, usize),
50 Flow(Arc<FlowSpec>, usize),
52 Power(Arc<PowerSpec>, usize),
54}
55
56#[derive(Clone, Debug)]
58pub struct NestedGerm {
59 pub(crate) scale: Arc<Scale>,
60 pub(crate) recipe: GermRecipe,
61 pub(crate) expansion: Expansion<Number>,
62}
63
64#[derive(Debug)]
66struct ExactSource(Expansion<Multi>);
67
68impl Source<Number> for ExactSource {
69 fn coefficient(&self, k: i64) -> Result<Number, ExpansionError> {
70 Ok(tower::from_multi(self.0.coefficient(k)?))
71 }
72}
73
74#[derive(Debug)]
76struct GermSource(Germ);
77
78impl Source<Number> for GermSource {
79 fn coefficient(&self, k: i64) -> Result<Number, ExpansionError> {
80 self.0
81 .coefficient(k)
82 .map(tower::from_exact_real)
83 .map_err(|e| ExpansionError::Coefficient(e.to_string()))
84 }
85}
86
87pub(crate) fn leading_order(n: &Number) -> Result<Option<(Arc<Scale>, Rational)>, String> {
90 let Some(ExactRef::Hyper(h)) = n.exact() else {
91 return Ok(None);
92 };
93 let order = match &h.value {
94 HyperForm::Rational(r) => Rational::from_i64(r.valuation().expect("a hyperreal held as one is nonzero")),
95 HyperForm::Puiseux(p) => {
96 Rational::from_ratio_i64(p.order(), i64::from(p.ramification())).expect("q is positive")
97 }
98 HyperForm::Germ(g) => {
99 let (k, _) = g.leading().map_err(|e| e.to_string())?;
100 Rational::from_ratio_i64(k, i64::from(g.ramification())).expect("q is positive")
101 }
102 HyperForm::Multi(m) | HyperForm::Integer(m) => m.leading().expect("a value of several infinitesimals is nonzero").0,
103 HyperForm::Nested(g) => g.order()?,
104 };
105 Ok(Some((h.scale.clone(), order)))
106}
107
108fn leading_coefficient(n: &Number) -> Result<Number, String> {
111 let Some(ExactRef::Hyper(h)) = n.exact() else {
112 return Ok(n.clone());
113 };
114 Ok(match &h.value {
115 HyperForm::Rational(r) => tower::from_algebraic(r.leading_coefficient().expect("nonzero")),
116 HyperForm::Puiseux(p) => {
117 tower::from_algebraic(p.coefficient(p.order()))
118 }
119 HyperForm::Germ(g) => tower::from_exact_real(g.leading().map_err(|e| e.to_string())?.1),
120 HyperForm::Multi(m) | HyperForm::Integer(m) => tower::from_multi(m.leading().expect("nonzero").1),
121 HyperForm::Nested(g) => g.leading()?.1,
122 })
123}
124
125fn number_scales(n: &Number) -> Vec<Arc<Scale>> {
127 match n.exact() {
128 Some(ExactRef::Hyper(h)) => match &h.value {
129 HyperForm::Multi(m) | HyperForm::Integer(m) => m.scales(),
130 HyperForm::Nested(g) => g.scales(),
131 _ => vec![h.scale.clone()],
132 },
133 Some(ExactRef::Natural(m)) => vec![m.scale.clone()],
134 _ => Vec::new(),
135 }
136}
137
138fn generator(scale: &Arc<Scale>) -> Number {
140 Number::hyper(tower::HyperValue {
141 value: HyperForm::Rational(crate::hyperreal::Hyperreal::dt()),
142 scale: scale.clone(),
143 })
144}
145
146impl NestedGerm {
147 pub(crate) fn scales(&self) -> Vec<Arc<Scale>> {
149 let mut out = vec![self.scale.clone()];
150 self.recipe_scales(&mut out);
151 out
152 }
153
154 fn recipe_scales(&self, out: &mut Vec<Arc<Scale>>) {
155 let push = |s: Arc<Scale>, out: &mut Vec<Arc<Scale>>| {
156 if !out.iter().any(|t| t.same_infinitesimal(&s)) {
157 out.push(s);
158 }
159 };
160 match &self.recipe {
161 GermRecipe::Exact(m) => m.scales().into_iter().for_each(|s| push(s, out)),
162 GermRecipe::Germ(_) => {}
163 GermRecipe::Constant(n) => number_scales(n).into_iter().for_each(|s| push(s, out)),
164 GermRecipe::Add(a, b) | GermRecipe::Sub(a, b) | GermRecipe::Mul(a, b) => {
165 a.recipe_scales(out);
166 b.recipe_scales(out);
167 }
168 GermRecipe::Neg(a)
169 | GermRecipe::Recip(a)
170 | GermRecipe::Root(a, _)
171 | GermRecipe::Exp(a)
172 | GermRecipe::Ln(a) => a.recipe_scales(out),
173 GermRecipe::MatrixExp(spec, _, _) => {
174 spec.a.iter().flatten().flat_map(number_scales).for_each(|s| push(s, out))
175 }
176 GermRecipe::Flow(spec, _) => spec
177 .a
178 .iter()
179 .flatten()
180 .chain(spec.start.iter())
181 .flat_map(number_scales)
182 .for_each(|s| push(s, out)),
183 GermRecipe::Power(spec, _) => spec
184 .a
185 .iter()
186 .flatten()
187 .chain(spec.start.iter())
188 .chain(std::iter::once(&spec.count))
189 .flat_map(number_scales)
190 .for_each(|s| push(s, out)),
191 }
192 }
193
194 pub(crate) fn same_recipe(a: &NestedGerm, b: &NestedGerm) -> bool {
196 if !a.scale.same_infinitesimal(&b.scale) {
197 return false;
198 }
199 match (&a.recipe, &b.recipe) {
200 (GermRecipe::Exact(x), GermRecipe::Exact(y)) => x == y,
201 (GermRecipe::Germ(x), GermRecipe::Germ(y)) => {
202 use crate::exact_codec::ExactCodec;
203 x.is_transmissible() && y.is_transmissible() && x.to_bytes() == y.to_bytes()
204 }
205 (GermRecipe::Constant(x), GermRecipe::Constant(y)) => x.values_equal(y),
206 (GermRecipe::Add(p, q), GermRecipe::Add(r, s))
207 | (GermRecipe::Sub(p, q), GermRecipe::Sub(r, s))
208 | (GermRecipe::Mul(p, q), GermRecipe::Mul(r, s)) => {
209 NestedGerm::same_recipe(p, r) && NestedGerm::same_recipe(q, s)
210 }
211 (GermRecipe::Neg(p), GermRecipe::Neg(r))
212 | (GermRecipe::Recip(p), GermRecipe::Recip(r))
213 | (GermRecipe::Exp(p), GermRecipe::Exp(r))
214 | (GermRecipe::Ln(p), GermRecipe::Ln(r)) => NestedGerm::same_recipe(p, r),
215 (GermRecipe::Root(p, n), GermRecipe::Root(r, m)) => n == m && NestedGerm::same_recipe(p, r),
216 (GermRecipe::MatrixExp(p, i, j), GermRecipe::MatrixExp(r, k, l)) => Arc::ptr_eq(p, r) && (i, j) == (k, l),
217 (GermRecipe::Flow(p, i), GermRecipe::Flow(r, k)) => Arc::ptr_eq(p, r) && i == k,
218 (GermRecipe::Power(p, i), GermRecipe::Power(r, k)) => Arc::ptr_eq(p, r) && i == k,
219 _ => false,
220 }
221 }
222
223 pub(crate) fn from_source(scale: &Arc<Scale>, recipe: GermRecipe, expansion: Expansion<Number>) -> NestedGerm {
225 NestedGerm::of(scale, recipe, expansion)
226 }
227
228 fn of(scale: &Arc<Scale>, recipe: GermRecipe, expansion: Expansion<Number>) -> NestedGerm {
229 NestedGerm {
230 scale: scale.clone(),
231 recipe,
232 expansion,
233 }
234 }
235
236 pub(crate) fn exact(m: &Multi, scale: &Arc<Scale>) -> NestedGerm {
238 match m.top() {
239 Some(t) if t.same_infinitesimal(scale) => {
240 let expansion = AlgValue::at(m, scale).expansion;
241 let (floor, q) = (expansion.floor(), expansion.ramification());
242 NestedGerm::of(scale, GermRecipe::Exact(m.clone()), Expansion::source(Arc::new(ExactSource(expansion)), floor, q))
243 }
244 _ => NestedGerm::constant(tower::from_multi(m.clone()), scale),
245 }
246 }
247
248 pub(crate) fn germ(g: &Germ, scale: &Arc<Scale>) -> NestedGerm {
250 let expansion = Expansion::source(Arc::new(GermSource(g.clone())), g.floor(), g.ramification());
251 NestedGerm::of(scale, GermRecipe::Germ(g.clone()), expansion)
252 }
253
254 pub(crate) fn constant(n: Number, scale: &Arc<Scale>) -> NestedGerm {
256 NestedGerm::of(scale, GermRecipe::Constant(n.clone()), Expansion::constant(n))
257 }
258
259 fn arc(self) -> Arc<NestedGerm> {
260 Arc::new(self)
261 }
262
263 pub(crate) fn add(a: &Arc<NestedGerm>, b: &Arc<NestedGerm>) -> NestedGerm {
264 NestedGerm::of(&a.scale, GermRecipe::Add(a.clone(), b.clone()), a.expansion.add(&b.expansion))
265 }
266
267 pub(crate) fn sub(a: &Arc<NestedGerm>, b: &Arc<NestedGerm>) -> NestedGerm {
268 NestedGerm::of(&a.scale, GermRecipe::Sub(a.clone(), b.clone()), a.expansion.sub(&b.expansion))
269 }
270
271 pub(crate) fn neg(a: &Arc<NestedGerm>) -> NestedGerm {
272 NestedGerm::of(&a.scale, GermRecipe::Neg(a.clone()), a.expansion.neg())
273 }
274
275 pub(crate) fn mul(a: &Arc<NestedGerm>, b: &Arc<NestedGerm>) -> NestedGerm {
276 NestedGerm::of(&a.scale, GermRecipe::Mul(a.clone(), b.clone()), a.expansion.mul(&b.expansion))
277 }
278
279 fn reach(&self) -> i64 {
281 self.expansion.floor() + SIGN_ORDERS * i64::from(self.expansion.ramification())
282 }
283
284 pub(crate) fn leading(&self) -> Result<(i64, Number), String> {
287 match self.expansion.leading_through(self.reach()) {
288 Ok(Some(term)) => Ok(term),
289 Ok(None) => Err(crate::germ::GermError::Flat.to_string()),
290 Err(e) => Err(e.to_string()),
291 }
292 }
293
294 pub(crate) fn order(&self) -> Result<Rational, String> {
296 let (k, _) = self.leading()?;
297 Ok(Rational::from_ratio_i64(k, i64::from(self.expansion.ramification())).expect("q is positive"))
298 }
299
300 pub(crate) fn sign(&self) -> Result<i32, String> {
301 let (_, c) = self.leading()?;
302 c.sign().map_err(|e| e.to_string())
303 }
304
305 pub(crate) fn recip(a: &Arc<NestedGerm>) -> Result<NestedGerm, String> {
306 let (k, c) = a.leading()?;
307 Ok(NestedGerm::of(&a.scale, GermRecipe::Recip(a.clone()), a.expansion.recip(k, c)))
308 }
309
310 pub(crate) fn root(a: &Arc<NestedGerm>, n: u32) -> Result<NestedGerm, String> {
312 if n == 1 {
313 return Ok((**a).clone());
314 }
315 let (k, c) = a.leading()?;
316 let expansion = a.expansion.root(n, k, c).map_err(|e| e.to_string())?;
317 Ok(NestedGerm::of(&a.scale, GermRecipe::Root(a.clone(), n), expansion))
318 }
319
320 pub(crate) fn pow(a: &Arc<NestedGerm>, k: i32) -> Result<NestedGerm, String> {
322 let mut base = if k < 0 { NestedGerm::recip(a)?.arc() } else { a.clone() };
323 let mut acc: Option<Arc<NestedGerm>> = None;
324 let mut e = k.unsigned_abs();
325 if e == 0 {
326 return Ok(NestedGerm::constant(Number::one(), &a.scale));
327 }
328 while e > 0 {
329 if e & 1 == 1 {
330 acc = Some(match acc {
331 None => base.clone(),
332 Some(x) => NestedGerm::mul(&x, &base).arc(),
333 });
334 }
335 e >>= 1;
336 if e > 0 {
337 base = NestedGerm::mul(&base, &base).arc();
338 }
339 }
340 Ok((*acc.expect("k ≠ 0")).clone())
341 }
342
343 pub(crate) fn exp(a: &Arc<NestedGerm>, shown: &str) -> Result<NestedGerm, String> {
346 let (k, _) = a.leading()?;
347 if k < 0 {
348 return Err(format!(
349 "the exponential of {shown} is beyond every power of {}",
350 a.scale.name
351 ));
352 }
353 Ok(NestedGerm::of(&a.scale, GermRecipe::Exp(a.clone()), a.expansion.exp()))
354 }
355
356 pub(crate) fn ln(a: &Arc<NestedGerm>, shown: &str) -> Result<NestedGerm, String> {
360 let (k, c) = a.leading()?;
361 if c.sign().map_err(|e| e.to_string())? < 0 {
362 return Err("logarithm of a nonpositive number".to_string());
363 }
364 let carries = |infinite: bool, name: &str| {
365 format!(
366 "the logarithm of {shown} carries ln({}{name})",
367 if infinite { "1/" } else { "" }
368 )
369 };
370 if k != 0 {
371 return Err(carries(k < 0, &a.scale.name));
372 }
373 let mut lead = c.clone();
374 while let Some((scale, order)) = leading_order(&lead)? {
375 if !order.is_zero() {
376 return Err(carries(order.is_negative(), &scale.name));
377 }
378 lead = leading_coefficient(&lead)?;
379 }
380 Ok(NestedGerm::of(&a.scale, GermRecipe::Ln(a.clone()), a.expansion.ln(c)))
381 }
382
383 pub(crate) fn standard_part_at(&self, at: Option<&Arc<Scale>>) -> Result<Option<Number>, String> {
386 if let Some(at) = at {
387 if self.scale.order(at).expect("the standpoint is ordered with the value's infinitesimals")
388 != std::cmp::Ordering::Less
389 {
390 return Ok(Some(Number::hyper(tower::HyperValue {
391 value: HyperForm::Nested(Arc::new(self.clone())),
392 scale: self.scale.clone(),
393 })));
394 }
395 }
396 let first = self.expansion.floor();
397 for k in first..0 {
398 let c = self.expansion.coefficient(k).map_err(|e| e.to_string())?;
399 if !c.is_zero().map_err(|e| e.to_string())? {
400 return Ok(None);
401 }
402 }
403 let c0 = self.expansion.coefficient(0).map_err(|e| e.to_string())?;
404 match at {
405 None => tower::standard_part(&c0).map(Some),
406 Some(scale) => tower::standard_part_relative(&c0, &generator(scale)).map(Some),
407 }
408 }
409
410 pub(crate) fn render(&self) -> String {
413 let name = &self.scale.name;
414 let q = i64::from(self.expansion.ramification());
415 let reach = self.reach();
416 let mut terms: Vec<(i64, Number)> = Vec::new();
417 let mut k = self.expansion.floor();
418 let mut next: Option<i64> = None;
419 while k <= reach {
420 match self.expansion.coefficient(k) {
421 Ok(c) => match c.is_zero() {
422 Ok(true) => {}
423 Ok(false) if terms.len() < 2 => terms.push((k, c)),
424 Ok(false) => {
425 next = Some(k);
426 break;
427 }
428 Err(_) => break,
429 },
430 Err(_) => break,
431 }
432 k += 1;
433 }
434 let exponent = |k: i64| Rational::from_ratio_i64(k, q).expect("q is positive");
435 let mut out = String::new();
436 for (i, (k, c)) in terms.iter().enumerate() {
437 let text = c.display_string();
438 let text = if *k == 0 && text.contains("O(") { format!("({text})") } else { text };
439 let t = expansion_term(name, &text, &exponent(*k));
440 match (i, t.strip_prefix('-')) {
441 (0, _) => out.push_str(&t),
442 (_, Some(rest)) => {
443 out.push_str(" - ");
444 out.push_str(rest);
445 }
446 (_, None) => {
447 out.push_str(" + ");
448 out.push_str(&t);
449 }
450 }
451 }
452 let shown: Vec<Rational> = terms.iter().map(|(k, _)| exponent(*k)).collect();
453 let rest = match (shown.is_empty(), next) {
454 (true, _) => remainder(name, &exponent(k)),
455 (false, Some(n)) => remainder(name, &remainder_after(&shown, &exponent(n))),
456 (false, None) => remainder(name, &remainder_after(&shown, &exponent(k))),
457 };
458 if out.is_empty() {
459 rest
460 } else {
461 format!("{out} + {rest}")
462 }
463 }
464}
465
466impl NestedGerm {
469 pub(crate) fn is_transmissible(&self) -> bool {
471 match &self.recipe {
472 GermRecipe::Exact(_) => true,
473 GermRecipe::Germ(g) => g.is_transmissible(),
474 GermRecipe::Constant(n) => tower::transmissible(n),
475 GermRecipe::Add(a, b) | GermRecipe::Sub(a, b) | GermRecipe::Mul(a, b) => {
476 a.is_transmissible() && b.is_transmissible()
477 }
478 GermRecipe::Neg(a)
479 | GermRecipe::Recip(a)
480 | GermRecipe::Root(a, _)
481 | GermRecipe::Exp(a)
482 | GermRecipe::Ln(a) => a.is_transmissible(),
483 GermRecipe::MatrixExp(spec, _, _) => spec.a.iter().flatten().all(tower::transmissible),
484 GermRecipe::Flow(spec, _) => spec.a.iter().flatten().chain(spec.start.iter()).all(tower::transmissible),
485 GermRecipe::Power(spec, _) => spec
486 .a
487 .iter()
488 .flatten()
489 .chain(spec.start.iter())
490 .chain(std::iter::once(&spec.count))
491 .all(tower::transmissible),
492 }
493 }
494
495 pub(crate) fn to_bytes(&self) -> Vec<u8> {
501 use crate::exact_codec::write_len;
502 let mut out = Vec::new();
503 write_len(self.scale.name.len(), &mut out);
504 out.extend_from_slice(self.scale.name.as_bytes());
505 let scale = self.scale.to_bytes();
506 write_len(scale.len(), &mut out);
507 out.extend_from_slice(&scale);
508 self.write_recipe(&mut out);
509 out
510 }
511
512 fn write_recipe(&self, out: &mut Vec<u8>) {
513 use crate::exact_codec::{write_len, ExactCodec};
514 let blob = |bytes: Vec<u8>, out: &mut Vec<u8>| {
515 write_len(bytes.len(), out);
516 out.extend_from_slice(&bytes);
517 };
518 match &self.recipe {
519 GermRecipe::Exact(m) => {
520 out.push(0);
521 blob(m.to_bytes(), out);
522 }
523 GermRecipe::Germ(g) => {
524 out.push(1);
525 blob(g.to_bytes(), out);
526 }
527 GermRecipe::Constant(n) => {
528 out.push(2);
529 blob(number_bytes(n), out);
530 }
531 GermRecipe::Add(a, b) | GermRecipe::Sub(a, b) | GermRecipe::Mul(a, b) => {
532 out.push(match &self.recipe {
533 GermRecipe::Add(..) => 3,
534 GermRecipe::Sub(..) => 4,
535 _ => 6,
536 });
537 a.write_recipe(out);
538 b.write_recipe(out);
539 }
540 GermRecipe::Neg(a) => {
541 out.push(5);
542 a.write_recipe(out);
543 }
544 GermRecipe::Recip(a) => {
545 out.push(7);
546 a.write_recipe(out);
547 }
548 GermRecipe::Root(a, n) => {
549 out.push(8);
550 a.write_recipe(out);
551 u64::from(*n).write(out);
552 }
553 GermRecipe::Exp(a) => {
554 out.push(9);
555 a.write_recipe(out);
556 }
557 GermRecipe::Ln(a) => {
558 out.push(10);
559 a.write_recipe(out);
560 }
561 GermRecipe::MatrixExp(spec, i, j) => {
562 out.push(11);
563 write_matrix(&spec.a, out);
564 spec.t.write(out);
565 (*i as u64).write(out);
566 (*j as u64).write(out);
567 }
568 GermRecipe::Flow(spec, i) => {
569 out.push(12);
570 write_matrix(&spec.a, out);
571 spec.t.write(out);
572 spec.delta.write(out);
573 write_numbers(&spec.start, out);
574 (*i as u64).write(out);
575 }
576 GermRecipe::Power(spec, i) => {
577 out.push(13);
578 write_matrix(&spec.a, out);
579 blob(number_bytes(&spec.count), out);
580 write_numbers(&spec.start, out);
581 (*i as u64).write(out);
582 }
583 }
584 }
585
586 pub(crate) fn from_bytes(buf: &[u8]) -> Option<NestedGerm> {
588 use crate::exact_codec::{read_len, MAX_WIRE_LEN};
589 let mut pos = 0;
590 let n = read_len(buf, &mut pos, MAX_WIRE_LEN)?;
591 let name = std::str::from_utf8(buf.get(pos..pos.checked_add(n)?)?).ok()?.to_string();
592 pos += n;
593 let n = read_len(buf, &mut pos, MAX_WIRE_LEN)?;
594 let scale = Scale::from_bytes(&name, buf.get(pos..pos.checked_add(n)?)?)?;
595 pos += n;
596 let germ = NestedGerm::read_recipe(buf, &mut pos, &scale, 0)?;
597 (pos == buf.len() && germ.to_bytes() == buf).then_some(germ)
598 }
599
600 fn read_recipe(buf: &[u8], pos: &mut usize, scale: &Arc<Scale>, depth: usize) -> Option<NestedGerm> {
601 use crate::exact_codec::{read_byte, read_len, ExactCodec, MAX_WIRE_DEGREE, MAX_WIRE_DEPTH, MAX_WIRE_LEN};
602 if depth > MAX_WIRE_DEPTH {
603 return None;
604 }
605 let blob = |pos: &mut usize| -> Option<Vec<u8>> {
606 let n = read_len(buf, pos, MAX_WIRE_LEN)?;
607 let bytes = buf.get(*pos..pos.checked_add(n)?)?.to_vec();
608 *pos += n;
609 Some(bytes)
610 };
611 let sub = |pos: &mut usize| NestedGerm::read_recipe(buf, pos, scale, depth + 1).map(Arc::new);
612 Some(match read_byte(buf, pos)? {
613 0 => NestedGerm::exact(&Multi::from_bytes(&blob(pos)?)?, scale),
614 1 => NestedGerm::germ(&Germ::from_bytes(&blob(pos)?)?, scale),
615 2 => NestedGerm::constant(number_from_bytes(&blob(pos)?)?, scale),
616 3 => {
617 let a = sub(pos)?;
618 NestedGerm::add(&a, &sub(pos)?)
619 }
620 4 => {
621 let a = sub(pos)?;
622 NestedGerm::sub(&a, &sub(pos)?)
623 }
624 5 => NestedGerm::neg(&sub(pos)?),
625 6 => {
626 let a = sub(pos)?;
627 NestedGerm::mul(&a, &sub(pos)?)
628 }
629 7 => NestedGerm::recip(&sub(pos)?).ok()?,
630 8 => {
631 let a = sub(pos)?;
632 let n = u32::try_from(u64::read(buf, pos)?).ok().filter(|n| (2..=MAX_WIRE_DEGREE as u32).contains(n))?;
633 NestedGerm::root(&a, n).ok()?
634 }
635 9 => NestedGerm::exp(&sub(pos)?, "").ok()?,
636 10 => NestedGerm::ln(&sub(pos)?, "").ok()?,
637 11 => {
638 let a = read_matrix(buf, pos)?;
639 let t = Rational::read(buf, pos)?;
640 let (i, j) = (read_index(buf, pos, a.len())?, read_index(buf, pos, a.len())?);
641 let e = crate::nested_flow::matrix_exp(&a, &t).ok()?;
642 nested_of(&e[i][j], scale)?
643 }
644 12 => {
645 let a = read_matrix(buf, pos)?;
646 let t = Rational::read(buf, pos)?;
647 let delta = Rational::read(buf, pos)?;
648 let start = read_numbers(buf, pos)?;
649 let i = read_index(buf, pos, a.len())?;
650 let state = crate::nested_flow::flow(scale, &a, t, delta, &start).ok()?;
651 nested_of(state.get(i)?, scale)?
652 }
653 13 => {
654 let a = read_matrix(buf, pos)?;
655 let count = number_from_bytes(&blob(pos)?)?;
656 let start = read_numbers(buf, pos)?;
657 let i = read_index(buf, pos, a.len())?;
658 let state = crate::nested_flow::power(scale, &a, count, &start).ok()?;
659 nested_of(state.get(i)?, scale)?
660 }
661 _ => return None,
662 })
663 }
664}
665
666fn nested_of(n: &Number, scale: &Arc<Scale>) -> Option<NestedGerm> {
668 match n.exact()? {
669 ExactRef::Hyper(h) => match &h.value {
670 HyperForm::Nested(g) if g.scale.same_infinitesimal(scale) => Some((**g).clone()),
671 _ => None,
672 },
673 _ => None,
674 }
675}
676
677fn write_numbers(numbers: &[Number], out: &mut Vec<u8>) {
678 use crate::exact_codec::write_len;
679 write_len(numbers.len(), out);
680 for n in numbers {
681 let bytes = number_bytes(n);
682 write_len(bytes.len(), out);
683 out.extend_from_slice(&bytes);
684 }
685}
686
687fn write_matrix(a: &[Vec<Number>], out: &mut Vec<u8>) {
688 use crate::exact_codec::write_len;
689 write_len(a.len(), out);
690 for row in a {
691 write_numbers(row, out);
692 }
693}
694
695fn read_numbers(buf: &[u8], pos: &mut usize) -> Option<Vec<Number>> {
696 use crate::exact_codec::{read_len, MAX_WIRE_DEGREE, MAX_WIRE_LEN};
697 let n = read_len(buf, pos, MAX_WIRE_DEGREE)?;
698 let mut out = Vec::with_capacity(n);
699 for _ in 0..n {
700 let len = read_len(buf, pos, MAX_WIRE_LEN)?;
701 let bytes = buf.get(*pos..pos.checked_add(len)?)?;
702 *pos += len;
703 out.push(number_from_bytes(bytes)?);
704 }
705 Some(out)
706}
707
708fn read_matrix(buf: &[u8], pos: &mut usize) -> Option<Vec<Vec<Number>>> {
709 use crate::exact_codec::{read_len, MAX_WIRE_DEGREE};
710 let n = read_len(buf, pos, MAX_WIRE_DEGREE).filter(|n| *n > 0)?;
711 let mut rows = Vec::with_capacity(n);
712 for _ in 0..n {
713 let row = read_numbers(buf, pos)?;
714 if row.len() != n {
715 return None;
716 }
717 rows.push(row);
718 }
719 Some(rows)
720}
721
722fn read_index(buf: &[u8], pos: &mut usize, below: usize) -> Option<usize> {
723 use crate::exact_codec::ExactCodec;
724 usize::try_from(u64::read(buf, pos)?).ok().filter(|i| *i < below)
725}
726
727fn number_bytes(n: &Number) -> Vec<u8> {
731 use crate::exact_codec::{write_len, ExactCodec};
732 let mut out = Vec::new();
733 let blob = |bytes: &[u8], out: &mut Vec<u8>| {
734 write_len(bytes.len(), out);
735 out.extend_from_slice(bytes);
736 };
737 if let Some(r) = n.standard_rational() {
738 out.push(0);
739 r.write(&mut out);
740 } else if let Some((kind, bytes)) = tower::exact_bytes(n) {
741 out.push(1);
742 out.push(kind);
743 blob(&bytes, &mut out);
744 } else if let Some((kind, name, residues, bytes)) = tower::scaled_bytes(n) {
745 out.push(2);
746 out.push(kind);
747 blob(name.as_bytes(), &mut out);
748 blob(&residues, &mut out);
749 blob(&bytes, &mut out);
750 } else {
751 out.push(3);
752 }
753 out
754}
755
756fn number_from_bytes(buf: &[u8]) -> Option<Number> {
757 use crate::exact_codec::{read_byte, read_len, ExactCodec, MAX_WIRE_LEN};
758 let mut pos = 0;
759 let blob = |pos: &mut usize| -> Option<Vec<u8>> {
760 let n = read_len(buf, pos, MAX_WIRE_LEN)?;
761 let bytes = buf.get(*pos..pos.checked_add(n)?)?.to_vec();
762 *pos += n;
763 Some(bytes)
764 };
765 let n = match read_byte(buf, &mut pos)? {
766 0 => Number::from_rational(Rational::read(buf, &mut pos)?),
767 1 => {
768 let kind = read_byte(buf, &mut pos)?;
769 tower::from_exact_bytes(kind, &blob(&mut pos)?)?
770 }
771 2 => {
772 let kind = read_byte(buf, &mut pos)?;
773 let name = String::from_utf8(blob(&mut pos)?).ok()?;
774 let residues = blob(&mut pos)?;
775 tower::from_scaled_bytes(kind, &name, &residues, &blob(&mut pos)?)?
776 }
777 _ => return None,
778 };
779 (pos == buf.len()).then_some(n)
780}