1use std::cmp::Ordering;
20use std::hash::{Hash, Hasher};
21use std::sync::Arc;
22
23use crate::algebraic::{negative_root, Algebraic};
24use crate::closure::{AlgValue, Recipe};
25use crate::exact_codec::{read_byte, read_len, write_len, ExactCodec, MAX_WIRE_DEPTH, MAX_WIRE_LEN};
26use crate::hyperreal::{Hyperreal, PowerError, MAX_POWER_DEGREE};
27use crate::numeric::{BigInt, Rational};
28use crate::ordered_field::{OrderedField, PolyOver};
29use crate::puiseux::{power_text, top_level, Closed, Puiseux};
30use crate::tower::Scale;
31
32#[derive(Clone, Debug)]
34pub enum Multi {
35 Standard(Algebraic),
37 One(Closed, Arc<Scale>),
39 Over {
42 scale: Arc<Scale>,
43 q: u32,
44 num: PolyOver<Multi>,
45 den: PolyOver<Multi>,
46 },
47 Alg(Arc<AlgValue>),
50}
51
52#[derive(Clone, Debug, PartialEq, Eq)]
55pub struct MultiPowerError {
56 pub error: PowerError,
57 pub name: String,
58 pub q: u32,
59}
60
61impl MultiPowerError {
62 pub fn describe(&self) -> String {
64 self.error.describe(&power_text(&self.name, &ratio(1, self.q)))
65 }
66}
67
68fn ratio(k: usize, q: u32) -> Rational {
69 Rational::from_ratio_i64(k as i64, i64::from(q)).expect("q is positive")
70}
71
72fn gcd_u64(a: u64, b: u64) -> u64 {
73 if b == 0 {
74 a
75 } else {
76 gcd_u64(b, a % b)
77 }
78}
79
80fn lcm_u32(a: u32, b: u32) -> u32 {
81 let g = gcd_u64(u64::from(a), u64::from(b));
82 u32::try_from(u64::from(a) / g * u64::from(b)).expect("a root of an infinitesimal of moderate index")
83}
84
85fn smaller<'a>(a: &'a Arc<Scale>, b: &'a Arc<Scale>) -> &'a Arc<Scale> {
87 match a.order(b).expect("every infinitesimal a value combines is ordered with the others") {
88 Ordering::Greater => b,
89 Ordering::Less | Ordering::Equal => a,
90 }
91}
92
93fn smallest(a: Option<&Arc<Scale>>, b: Option<&Arc<Scale>>) -> Option<Arc<Scale>> {
97 match (a, b) {
98 (Some(x), Some(y)) if x.same_infinitesimal(y) => Some(met(x, y)),
99 (Some(x), Some(y)) => Some(smaller(x, y).clone()),
100 (x, None) => x.cloned(),
101 (None, y) => y.cloned(),
102 }
103}
104
105fn met(a: &Arc<Scale>, b: &Arc<Scale>) -> Arc<Scale> {
108 match a.residues.and(&b.residues) {
109 Ok(both) if both == a.residues => a.clone(),
110 Ok(both) if both == b.residues => b.clone(),
111 Ok(both) => Arc::new(a.with_residues(both)),
112 Err(_) => a.clone(),
113 }
114}
115
116fn push_scale(out: &mut Vec<Arc<Scale>>, s: &Arc<Scale>) {
119 match out.iter_mut().find(|t| t.same_infinitesimal(s)) {
120 Some(t) => *t = met(t, s),
121 None => out.push(s.clone()),
122 }
123}
124
125impl Multi {
126 pub fn generator(scale: &Arc<Scale>) -> Multi {
128 Multi::One(Closed::from_hyperreal(Hyperreal::dt()), scale.clone())
129 }
130
131 pub fn of_closed(c: Closed, scale: &Arc<Scale>) -> Multi {
133 match c.as_standard() {
134 Some(a) => Multi::Standard(a),
135 None => Multi::One(c, scale.clone()),
136 }
137 }
138
139 pub fn top(&self) -> Option<&Arc<Scale>> {
141 match self {
142 Multi::Standard(_) => None,
143 Multi::One(_, s) | Multi::Over { scale: s, .. } => Some(s),
144 Multi::Alg(a) => Some(&a.scale),
145 }
146 }
147
148 pub fn scales(&self) -> Vec<Arc<Scale>> {
150 let mut out = Vec::new();
151 self.collect_scales(&mut out);
152 out
153 }
154
155 fn collect_scales(&self, out: &mut Vec<Arc<Scale>>) {
156 match self {
157 Multi::Standard(_) => {}
158 Multi::One(_, s) => push_scale(out, s),
159 Multi::Over { scale, num, den, .. } => {
160 push_scale(out, scale);
161 for c in num.c.iter().chain(den.c.iter()) {
162 c.collect_scales(out);
163 }
164 }
165 Multi::Alg(a) => {
166 push_scale(out, &a.scale);
167 recipe_scales(&a.recipe, out);
168 }
169 }
170 }
171
172 pub(crate) fn parts_at(&self, scale: &Arc<Scale>) -> (u32, PolyOver<Multi>, PolyOver<Multi>) {
175 match self {
176 Multi::Alg(a) if a.scale.same_infinitesimal(scale) => {
177 unreachable!("a root that is no rational function of a root of its infinitesimal has no fraction there")
178 }
179 Multi::Over { scale: s, q, num, den } if s.same_infinitesimal(scale) => (*q, num.clone(), den.clone()),
180 Multi::One(c, s) if s.same_infinitesimal(scale) => {
181 let (h, q) = c
182 .field()
183 .expect("a root that is no rational function of a root of its infinitesimal meets no larger one");
184 let (num, den) = h.parts();
185 let lift = |p: &PolyOver<Algebraic>| PolyOver::from(p.c.iter().cloned().map(Multi::Standard).collect());
186 (q, lift(num), lift(den))
187 }
188 _ => (1, PolyOver::constant(self.clone()), PolyOver::one()),
189 }
190 }
191
192 #[allow(clippy::type_complexity)]
195 fn over_one(
196 &self,
197 o: &Multi,
198 ) -> (Arc<Scale>, u32, (PolyOver<Multi>, PolyOver<Multi>), (PolyOver<Multi>, PolyOver<Multi>)) {
199 let scale = smallest(self.top(), o.top()).expect("a value of an infinitesimal is on one side");
200 let (qa, na, da) = self.parts_at(&scale);
201 let (qb, nb, db) = o.parts_at(&scale);
202 let q = lcm_u32(qa, qb);
203 let (ma, mb) = ((q / qa) as usize, (q / qb) as usize);
204 (scale, q, (na.spread(ma), da.spread(ma)), (nb.spread(mb), db.spread(mb)))
205 }
206
207 fn closed_pair(&self, o: &Multi) -> Option<(Closed, Closed, Arc<Scale>)> {
209 let closed = |m: &Multi| match m {
210 Multi::Standard(a) => Some(Closed::from_hyperreal(Hyperreal::from_algebraic(a.clone()))),
211 Multi::One(c, _) => Some(c.clone()),
212 Multi::Over { .. } | Multi::Alg(_) => None,
213 };
214 let scale = match (self.top(), o.top()) {
215 (Some(a), Some(b)) if a.same_infinitesimal(b) => met(a, b),
216 (Some(a), None) | (None, Some(a)) => a.clone(),
217 _ => return None,
218 };
219 Some((closed(self)?, closed(o)?, scale))
220 }
221
222 fn closure_pair(&self, o: &Multi) -> Option<(Arc<AlgValue>, Arc<AlgValue>)> {
225 let scale = &smallest(self.top(), o.top())?;
226 let root_there = |m: &Multi| match m {
227 Multi::Alg(a) => a.scale.same_infinitesimal(scale),
228 Multi::One(c, s) => s.same_infinitesimal(scale) && c.field().is_none(),
229 _ => false,
230 };
231 if !(root_there(self) || root_there(o)) {
232 return None;
233 }
234 Some((Arc::new(AlgValue::at(self, scale)), Arc::new(AlgValue::at(o, scale))))
235 }
236
237 pub(crate) fn make(scale: &Arc<Scale>, q: u32, num: PolyOver<Multi>, den: PolyOver<Multi>) -> Multi {
242 if num.is_zero() {
243 return Multi::zero();
244 }
245 let monomial = den.order().filter(|&d| den.c.iter().enumerate().all(|(i, c)| i == d || c.is_zero()));
246 let (num, den) = if den.degree() == Some(0) {
247 let inv = den.coeff(0).recip().expect("the denominator is nonzero");
248 (num.scale(&inv), PolyOver::one())
249 } else if let Some(d) = monomial {
250 let shift = d.min(num.order().expect("the numerator is nonzero"));
251 let inv = den.coeff(d).recip().expect("the denominator is nonzero");
252 let mut power = vec![Multi::zero(); d - shift + 1];
253 power[d - shift] = Multi::Standard(Algebraic::from_i64(1));
254 (PolyOver::from(num.c[shift..].to_vec()).scale(&inv), PolyOver::from(power))
255 } else {
256 let g = num.gcd(&den);
257 let (num, den) = (num.div_rem(&g).0, den.div_rem(&g).0);
258 let inv = den.coeff(den.order().expect("the denominator is nonzero")).recip().expect("nonzero");
259 (num.scale(&inv), den.scale(&inv))
260 };
261 let (num, den, q) = least_root(num, den, q);
262 if num.degree() == Some(0) && den.degree() == Some(0) {
263 return num.coeff(0);
264 }
265 let standard = |p: &PolyOver<Multi>| -> Option<PolyOver<Algebraic>> {
266 p.c.iter()
267 .map(|c| match c {
268 Multi::Standard(a) => Some(a.clone()),
269 _ => None,
270 })
271 .collect::<Option<Vec<_>>>()
272 .map(PolyOver::from)
273 };
274 if let (Some(n), Some(d)) = (standard(&num), standard(&den)) {
275 return Multi::of_closed(Closed::of_field(Hyperreal::from_parts(n, d), q), scale);
276 }
277 Multi::Over {
278 scale: scale.clone(),
279 q,
280 num,
281 den,
282 }
283 }
284
285 pub(crate) fn leading(&self) -> Option<(Rational, Multi)> {
288 match self {
289 Multi::Standard(_) => None,
290 Multi::Alg(a) => Some((a.order(), a.leading().1)),
291 Multi::One(c, _) => c.leading().map(|(v, a)| (v, Multi::Standard(a))),
292 Multi::Over { q, num, den, .. } => {
293 let n = num.order().expect("a value is nonzero");
294 let d = den.order().expect("the denominator is nonzero");
295 let v = Rational::from_ratio_i64(n as i64 - d as i64, i64::from(*q)).expect("q is positive");
296 Some((v, num.coeff(n)))
297 }
298 }
299 }
300
301 pub fn standard_part_at(&self, at: Option<&Arc<Scale>>) -> Option<Multi> {
306 let Some(top) = self.top() else {
307 return Some(self.clone());
308 };
309 if let Some(at) = at {
310 if top.order(at).expect("the standpoint is ordered with the value's infinitesimals") != Ordering::Less {
311 return Some(self.clone());
312 }
313 }
314 let (v, c) = self.leading().expect("a value of an infinitesimal is nonzero");
315 match v.cmp(&Rational::zero()) {
316 Ordering::Greater => Some(Multi::zero()),
317 Ordering::Less => None,
318 Ordering::Equal => c.standard_part_at(at),
319 }
320 }
321
322 pub fn standard_part(&self) -> Option<Algebraic> {
324 match self.standard_part_at(None)? {
325 Multi::Standard(a) => Some(a),
326 _ => unreachable!("the standard part of a value is standard"),
327 }
328 }
329
330 pub fn is_infinitesimal_at(&self, at: Option<&Arc<Scale>>) -> bool {
333 self.standard_part_at(at).is_some_and(|s| s.is_zero())
334 }
335
336 pub fn is_limited_at(&self, at: Option<&Arc<Scale>>) -> bool {
339 self.standard_part_at(at).is_some()
340 }
341
342 pub fn is_infinitesimal(&self) -> bool {
343 self.is_infinitesimal_at(None)
344 }
345
346 pub fn is_limited(&self) -> bool {
347 self.is_limited_at(None)
348 }
349
350 fn widest(&self) -> Option<(usize, Arc<Scale>, u32)> {
353 match self {
354 Multi::Standard(_) | Multi::Alg(_) => None,
355 Multi::One(c, s) => c.field().map(|(h, q)| (h.degree(), s.clone(), q)),
356 Multi::Over { scale, q, num, den } => {
357 let here = (num.degree().unwrap_or(0).max(den.degree().unwrap_or(0)), scale.clone(), *q);
358 num.c
359 .iter()
360 .chain(den.c.iter())
361 .filter_map(Multi::widest)
362 .chain(std::iter::once(here))
363 .max_by_key(|(d, _, _)| *d)
364 }
365 }
366 }
367
368 pub fn pow(&self, k: i32) -> Result<Multi, MultiPowerError> {
371 let zero_to_negative = |name: &str| MultiPowerError {
372 error: PowerError::ZeroToNegative,
373 name: name.to_string(),
374 q: 1,
375 };
376 match self {
377 Multi::Standard(a) => a.pow(k).map(Multi::Standard).ok_or_else(|| zero_to_negative("")),
378 Multi::One(c, s) => c.pow(k).map(|r| Multi::of_closed(r, s)).map_err(|e| MultiPowerError {
379 error: e.error,
380 name: s.name.clone(),
381 q: e.q,
382 }),
383 Multi::Alg(a) => {
384 let reach = u128::from(k.unsigned_abs());
385 if reach > u128::from(MAX_POWER_DEGREE) {
386 return Err(MultiPowerError {
387 error: PowerError::DegreeTooHigh { degree: reach },
388 name: a.scale.name.clone(),
389 q: a.expansion.ramification(),
390 });
391 }
392 Ok(match k.cmp(&0) {
393 Ordering::Equal => Multi::one(),
394 Ordering::Greater => AlgValue::pow(a, k.unsigned_abs()),
395 Ordering::Less => match AlgValue::recip(a) {
396 Multi::Alg(r) => AlgValue::pow(&r, k.unsigned_abs()),
397 r => r.pow(k.saturating_neg())?,
398 },
399 })
400 }
401 Multi::Over { .. } => {
402 if let Some((degree, scale, q)) = self.widest() {
403 let reach = degree as u128 * u128::from(k.unsigned_abs());
404 if reach > u128::from(MAX_POWER_DEGREE) {
405 return Err(MultiPowerError {
406 error: PowerError::DegreeTooHigh { degree: reach },
407 name: scale.name.clone(),
408 q,
409 });
410 }
411 }
412 let mut base = if k < 0 {
413 self.recip().expect("a value of several infinitesimals is nonzero")
414 } else {
415 self.clone()
416 };
417 let mut acc = Multi::one();
418 let mut e = k.unsigned_abs();
419 while e > 0 {
420 if e & 1 == 1 {
421 acc = acc.mul(&base);
422 }
423 e >>= 1;
424 if e > 0 {
425 base = base.mul(&base);
426 }
427 }
428 Ok(acc)
429 }
430 }
431 }
432
433 pub fn root(&self, n: u32) -> Result<Multi, String> {
437 if n == 1 || self.is_zero() {
438 return Ok(self.clone());
439 }
440 match self {
441 Multi::Standard(a) => a.nth_root(n).map(Multi::Standard).ok_or_else(|| negative_root(n)),
442 Multi::One(c, s) => Ok(Multi::of_closed(c.root(n)?, s)),
443 Multi::Alg(a) => AlgValue::root(a, n),
444 Multi::Over { scale, q, num, den } => {
445 let single = |p: &PolyOver<Multi>| -> Option<usize> {
446 let mut terms = p.c.iter().enumerate().filter(|(_, c)| !c.is_zero());
447 let (i, _) = terms.next()?;
448 terms.next().is_none().then_some(i)
449 };
450 let (Some(a), Some(b)) = (single(num), single(den)) else {
451 return AlgValue::root(&Arc::new(AlgValue::field(self, scale)), n);
452 };
453 let root = num.coeff(a).root(n)?;
454 let e = a as i64 - b as i64;
455 let mut power = vec![Multi::zero(); e.unsigned_abs() as usize + 1];
456 power[e.unsigned_abs() as usize] = Multi::one();
457 let power = PolyOver::from(power);
458 let (top, bottom) = if e >= 0 {
459 (power.scale(&root), PolyOver::one())
460 } else {
461 (PolyOver::constant(root), power)
462 };
463 Ok(Multi::make(scale, q * n, top, bottom))
464 }
465 }
466 }
467}
468
469fn least_root(num: PolyOver<Multi>, den: PolyOver<Multi>, q: u32) -> (PolyOver<Multi>, PolyOver<Multi>, u32) {
472 let powers = num
473 .c
474 .iter()
475 .enumerate()
476 .chain(den.c.iter().enumerate())
477 .filter(|(_, c)| !c.is_zero())
478 .map(|(i, _)| i as u64);
479 let m = powers.fold(u64::from(q), gcd_u64) as usize;
480 if m <= 1 {
481 return (num, den, q);
482 }
483 let gather = |p: &PolyOver<Multi>| PolyOver::from(p.c.iter().step_by(m).cloned().collect());
484 (gather(&num), gather(&den), q / m as u32)
485}
486
487impl OrderedField for Multi {
488 fn zero() -> Self {
489 Multi::Standard(Algebraic::from_i64(0))
490 }
491 fn one() -> Self {
492 Multi::Standard(Algebraic::from_i64(1))
493 }
494 fn from_i64(n: i64) -> Self {
495 Multi::Standard(Algebraic::from_i64(n))
496 }
497 fn is_zero(&self) -> bool {
498 matches!(self, Multi::Standard(a) if a.is_zero())
499 }
500 fn add(&self, o: &Self) -> Self {
501 if let (Multi::Standard(a), Multi::Standard(b)) = (self, o) {
502 return Multi::Standard(a.add(b));
503 }
504 if let Some((a, b, s)) = self.closed_pair(o) {
505 return Multi::of_closed(a.add(&b), &s);
506 }
507 if let Some((a, b)) = self.closure_pair(o) {
508 return AlgValue::add(&a, &b);
509 }
510 let (scale, q, (na, da), (nb, db)) = self.over_one(o);
511 if da == db {
512 return Multi::make(&scale, q, na.add(&nb), da);
513 }
514 Multi::make(&scale, q, na.mul(&db).add(&nb.mul(&da)), da.mul(&db))
515 }
516 fn neg(&self) -> Self {
517 match self {
518 Multi::Standard(a) => Multi::Standard(a.neg()),
519 Multi::One(c, s) => Multi::One(c.neg(), s.clone()),
520 Multi::Over { scale, q, num, den } => Multi::Over {
521 scale: scale.clone(),
522 q: *q,
523 num: num.neg(),
524 den: den.clone(),
525 },
526 Multi::Alg(a) => AlgValue::neg(a),
527 }
528 }
529 fn mul(&self, o: &Self) -> Self {
530 if let (Multi::Standard(a), Multi::Standard(b)) = (self, o) {
531 return Multi::Standard(a.mul(b));
532 }
533 if self.is_zero() || o.is_zero() {
534 return Multi::zero();
535 }
536 if let Some((a, b, s)) = self.closed_pair(o) {
537 return Multi::of_closed(a.mul(&b), &s);
538 }
539 if let Some((a, b)) = self.closure_pair(o) {
540 return AlgValue::mul(&a, &b);
541 }
542 let (scale, q, (na, da), (nb, db)) = self.over_one(o);
543 Multi::make(&scale, q, na.mul(&nb), da.mul(&db))
544 }
545 fn recip(&self) -> Option<Self> {
546 match self {
547 Multi::Standard(a) => a.recip().map(Multi::Standard),
548 Multi::One(c, s) => c.recip().map(|r| Multi::of_closed(r, s)),
549 Multi::Over { scale, q, num, den } => Some(Multi::make(scale, *q, den.clone(), num.clone())),
550 Multi::Alg(a) => Some(AlgValue::recip(a)),
551 }
552 }
553 fn signum(&self) -> i32 {
554 match self {
555 Multi::Standard(a) => a.signum(),
556 Multi::One(c, _) => c.signum(),
557 Multi::Over { num, .. } => num.coeff(num.order().expect("a value is nonzero")).signum(),
558 Multi::Alg(a) => a.sign(),
559 }
560 }
561}
562
563impl PartialEq for Multi {
564 fn eq(&self, o: &Self) -> bool {
565 match (self, o) {
566 (Multi::Standard(a), Multi::Standard(b)) => a == b,
567 (Multi::One(a, s), Multi::One(b, t)) => s.same_infinitesimal(t) && a == b,
568 (
569 Multi::Over { scale: s, q: qa, num: na, den: da },
570 Multi::Over { scale: t, q: qb, num: nb, den: db },
571 ) => s.same_infinitesimal(t) && qa == qb && na == nb && da == db,
572 (Multi::Alg(a), Multi::Alg(b)) => AlgValue::equals(a, b),
573 _ => false,
574 }
575 }
576}
577
578impl Eq for Multi {}
579
580impl Hash for Multi {
581 fn hash<H: Hasher>(&self, state: &mut H) {
583 match self {
584 Multi::Standard(a) => {
585 0u8.hash(state);
586 a.hash(state);
587 }
588 Multi::One(c, s) => {
589 1u8.hash(state);
590 s.name.hash(state);
591 c.hash(state);
592 }
593 Multi::Over { scale, q, num, den } => {
594 2u8.hash(state);
595 scale.name.hash(state);
596 q.hash(state);
597 num.hash(state);
598 den.hash(state);
599 }
600 Multi::Alg(a) => {
601 3u8.hash(state);
602 a.scale.name.hash(state);
603 let (order, lead) = a.leading();
604 order.hash(state);
605 a.expansion.ramification().hash(state);
606 lead.hash(state);
607 }
608 }
609 }
610}
611
612impl Multi {
615 pub fn render(&self) -> String {
622 if let Multi::Alg(a) = self {
623 return AlgValue::render(a);
624 }
625 if self.is_integral() {
626 if let Some(text) = self.render_reciprocals() {
627 return text;
628 }
629 }
630 let (n, d) = self.fraction();
631 if d.top().is_none() {
632 return render_polynomial(self);
633 }
634 let numerator = render_polynomial(&n);
635 let denominator = render_polynomial(&d);
636 let numerator = if top_level(&numerator, &[' ']) { format!("({numerator})") } else { numerator };
637 let denominator = if top_level(&denominator, &[' ', '·']) { format!("({denominator})") } else { denominator };
638 format!("{numerator}/{denominator}")
639 }
640
641 pub(crate) fn is_integral(&self) -> bool {
649 let mut terms = Vec::new();
650 if reciprocal_terms(self, &mut Vec::new(), &mut terms).is_none() {
651 return false;
652 }
653 let denominator = terms.iter().fold(BigInt::from_i64(1), |d, (_, c)| {
654 let g = d.gcd(c.denominator());
655 d.div_rem(&g).expect("a nonzero divisor").0.mul(c.denominator())
656 });
657 let Some(d) = denominator.to_i64().and_then(|d| u64::try_from(d).ok()) else {
658 return false;
659 };
660 if d == 1 {
661 return true;
662 }
663 let mut scales: Vec<Arc<Scale>> = Vec::new();
664 for (monomial, _) in &terms {
665 for (s, _) in monomial {
666 match scales.iter_mut().find(|t| t.same_infinitesimal(s)) {
667 Some(t) => *t = met(t, s),
668 None => scales.push(s.clone()),
669 }
670 }
671 }
672 let mut moduli: Vec<u64> = Vec::with_capacity(scales.len());
673 let mut joint: u64 = 1;
674 for s in &scales {
675 let ty = &s.residues;
676 let g = gcd_u64(d, ty.modulus());
677 let Some(m) = (d / g).checked_mul(ty.modulus()) else {
678 return false;
679 };
680 let per_period = (0..ty.modulus()).filter(|h| ty.admits(*h)).count() as u64;
681 joint = match joint.checked_mul((m / ty.modulus()).saturating_mul(per_period)) {
682 Some(j) if j <= INTEGRAL_CLASSES => j,
683 _ => return false,
684 };
685 moduli.push(m);
686 }
687 let members: Vec<Vec<u64>> = scales
688 .iter()
689 .zip(&moduli)
690 .map(|(s, m)| (0..*m).filter(|h| s.residues.admits(*h)).collect())
691 .collect();
692 let mut at = vec![0usize; scales.len()];
693 loop {
694 let value = terms.iter().fold(Rational::zero(), |acc, (monomial, c)| {
695 let product = monomial.iter().fold(c.clone(), |p, (s, k)| {
696 let i = scales.iter().position(|t| t.same_infinitesimal(s)).expect("every scale is listed");
697 let h = Rational::from_i64(members[i][at[i]] as i64);
698 p.mul(&h.pow(*k as i32).expect("a natural power"))
699 });
700 acc.add(&product)
701 });
702 if !value.is_integer() {
703 return false;
704 }
705 let mut i = 0;
706 loop {
707 if i == at.len() {
708 return true;
709 }
710 at[i] += 1;
711 if at[i] < members[i].len() {
712 break;
713 }
714 at[i] = 0;
715 i += 1;
716 }
717 }
718 }
719
720 pub(crate) fn render_reciprocals(&self) -> Option<String> {
726 let mut terms = Vec::new();
727 reciprocal_terms(self, &mut Vec::new(), &mut terms)?;
728 let mut scales: Vec<Arc<Scale>> = Vec::new();
729 for (monomial, _) in &terms {
730 for (s, _) in monomial {
731 if !scales.iter().any(|t| t.same_infinitesimal(s)) {
732 scales.push(s.clone());
733 }
734 }
735 }
736 scales.sort_by(|a, b| a.order(b).unwrap_or(Ordering::Equal));
737 let powers = |monomial: &[(Arc<Scale>, u32)]| -> Vec<u32> {
738 scales
739 .iter()
740 .map(|s| monomial.iter().find(|(t, _)| t.same_infinitesimal(s)).map_or(0, |(_, k)| *k))
741 .collect()
742 };
743 terms.sort_by(|(a, _), (b, _)| powers(b).cmp(&powers(a)));
744 let mut out = String::new();
745 for (i, (monomial, c)) in terms.iter().enumerate() {
746 let negative = c.is_negative();
747 let m = c.abs();
748 let body = if monomial.is_empty() {
749 m.to_string()
750 } else {
751 let factors: Vec<String> = scales
752 .iter()
753 .rev()
754 .filter_map(|s| {
755 let k = monomial.iter().find(|(t, _)| t.same_infinitesimal(s))?.1;
756 Some(if k == 1 { s.name.clone() } else { format!("{}^{k}", s.name) })
757 })
758 .collect();
759 let product = factors.join("·");
760 let (num, den) = (m.numerator().clone(), m.denominator().clone());
761 if den == BigInt::from_i64(1) && factors.len() == 1 {
762 format!("{num}/{product}")
763 } else if den == BigInt::from_i64(1) {
764 format!("{num}/({product})")
765 } else {
766 format!("{num}/({den}·{product})")
767 }
768 };
769 out.push_str(&match (i, negative) {
770 (0, true) => format!("-{body}"),
771 (0, false) => body,
772 (_, true) => format!(" - {body}"),
773 (_, false) => format!(" + {body}"),
774 });
775 }
776 Some(if out.is_empty() { "0".to_string() } else { out })
777 }
778
779 pub(crate) fn fraction_parts(&self) -> (Multi, Multi) {
781 self.fraction()
782 }
783
784 fn fraction(&self) -> (Multi, Multi) {
787 let (n, d) = self.raw_fraction();
788 if d.signum() < 0 {
789 (n.neg(), d.neg())
790 } else {
791 (n, d)
792 }
793 }
794
795 fn raw_fraction(&self) -> (Multi, Multi) {
796 match self {
797 Multi::Standard(a) => match a.to_rational() {
798 Some(r) => (
799 Multi::Standard(Algebraic::from_rational(Rational::from_bigint(r.numerator().clone()))),
800 Multi::Standard(Algebraic::from_rational(Rational::from_bigint(r.denominator().clone()))),
801 ),
802 None => (self.clone(), Multi::one()),
803 },
804 Multi::One(c, s) => match c.field() {
805 Some((h, q)) => {
806 let (n, d) = h.display_fraction();
807 let poly = |p: PolyOver<Algebraic>| {
808 Multi::of_closed(Closed::of_field(Hyperreal::from_parts(p, PolyOver::one()), q), s)
809 };
810 (poly(n), poly(d))
811 }
812 None => (self.clone(), Multi::one()),
813 },
814 Multi::Alg(_) => (self.clone(), Multi::one()),
815 Multi::Over { scale, q, num, den } => {
816 let l = num
817 .c
818 .iter()
819 .chain(den.c.iter())
820 .filter(|c| !c.is_zero())
821 .fold(Multi::one(), |acc, c| polynomial_lcm(&acc, &c.raw_fraction().1));
822 let lift = |p: &PolyOver<Multi>| PolyOver::from(p.c.iter().map(|c| c.mul(&l)).collect());
823 let (n, d) = (lift(num), lift(den));
824 let g = polynomial_gcd(&content(&n), &content(&d));
825 let g_inv = g.recip().expect("a gcd of nonzero polynomials is nonzero");
826 let reduce = |p: PolyOver<Multi>| Multi::make(scale, *q, p.scale(&g_inv), PolyOver::one());
827 (reduce(n), reduce(d))
828 }
829 }
830 }
831}
832
833fn content(p: &PolyOver<Multi>) -> Multi {
835 p.c.iter().filter(|c| !c.is_zero()).fold(Multi::zero(), |acc, c| polynomial_gcd(&acc, c))
836}
837
838fn polynomial_lcm(a: &Multi, b: &Multi) -> Multi {
839 let g = polynomial_gcd(a, b);
840 a.mul(b).mul(&g.recip().expect("a gcd of nonzero polynomials is nonzero"))
841}
842
843fn is_root_atom(m: &Multi) -> bool {
846 matches!(m, Multi::One(c, _) if c.field().is_none()) || matches!(m, Multi::Alg(_))
847}
848
849fn polynomial_top(m: &Multi) -> Option<&Arc<Scale>> {
851 if is_root_atom(m) {
852 None
853 } else {
854 m.top()
855 }
856}
857
858fn polynomial_at(m: &Multi, scale: &Arc<Scale>) -> (u32, PolyOver<Multi>) {
860 if is_root_atom(m) {
861 return (1, PolyOver::constant(m.clone()));
862 }
863 let (q, p, _) = m.parts_at(scale);
864 (q, p)
865}
866
867fn polynomial_gcd(a: &Multi, b: &Multi) -> Multi {
873 let positive = |m: &Multi| if m.signum() < 0 { m.neg() } else { m.clone() };
874 if a.is_zero() {
875 return positive(b);
876 }
877 if b.is_zero() {
878 return positive(a);
879 }
880 let Some(scale) = smallest(polynomial_top(a), polynomial_top(b)) else {
881 let integer = |m: &Multi| match m {
882 Multi::Standard(x) => x.to_rational().filter(Rational::is_integer).and_then(|r| r.to_bigint()),
883 _ => None,
884 };
885 return match (integer(a), integer(b)) {
886 (Some(x), Some(y)) => Multi::Standard(Algebraic::from_rational(Rational::from_bigint(x.gcd(&y)))),
887 _ => Multi::one(),
888 };
889 };
890 let (qa, pa) = polynomial_at(a, &scale);
891 let (qb, pb) = polynomial_at(b, &scale);
892 let q = lcm_u32(qa, qb);
893 let (pa, pb) = (pa.spread((q / qa) as usize), pb.spread((q / qb) as usize));
894 let (ca, cb) = (content(&pa), content(&pb));
895 let c = polynomial_gcd(&ca, &cb);
896 let primitive = |p: &PolyOver<Multi>, k: &Multi| p.scale(&k.recip().expect("a content is nonzero"));
897 let (pa, pb) = (primitive(&pa, &ca), primitive(&pb, &cb));
898 if pa.degree() == Some(0) || pb.degree() == Some(0) {
899 return c;
900 }
901 let g = Multi::make(&scale, q, pa.gcd(&pb), PolyOver::one());
902 let (g, _) = g.raw_fraction();
903 let g_content = match polynomial_top(&g) {
904 Some(t) if t.same_infinitesimal(&scale) => content(&polynomial_at(&g, &scale).1),
905 _ => g.clone(),
906 };
907 let g = g.mul(&g_content.recip().expect("a content is nonzero"));
908 c.mul(&positive(&g))
909}
910
911fn render_polynomial(p: &Multi) -> String {
914 match p {
915 Multi::Standard(a) => a.to_string(),
916 Multi::One(c, s) => c.render(&s.name),
917 Multi::Alg(a) => AlgValue::render(a),
918 Multi::Over { scale, q, num, .. } => {
919 let mut out = String::new();
920 for (k, c) in num.c.iter().enumerate() {
921 if c.is_zero() {
922 continue;
923 }
924 if k == 0 {
925 out.push_str(&render_polynomial(c));
926 continue;
927 }
928 let power = power_text(&scale.name, &ratio(k, *q));
929 let negative = c.signum() < 0;
930 let magnitude = render_polynomial(&if negative { c.neg() } else { c.clone() });
931 let body = if magnitude == "1" {
932 power
933 } else if top_level(&magnitude, &[' ', '/']) {
934 format!("({magnitude})·{power}")
935 } else {
936 format!("{magnitude}·{power}")
937 };
938 match (out.is_empty(), negative) {
939 (true, true) => out.push_str(&format!("-{body}")),
940 (true, false) => out.push_str(&body),
941 (false, true) => out.push_str(&format!(" - {body}")),
942 (false, false) => out.push_str(&format!(" + {body}")),
943 }
944 }
945 out
946 }
947 }
948}
949
950impl Multi {
953 pub fn to_bytes(&self) -> Vec<u8> {
958 let table = self.scales();
959 let mut out = Vec::new();
960 write_len(table.len(), &mut out);
961 for s in &table {
962 write_text(&s.name, &mut out);
963 let bytes = s.to_bytes();
964 write_len(bytes.len(), &mut out);
965 out.extend_from_slice(&bytes);
966 s.residues.write(&mut out);
967 }
968 self.write_value(&table, &mut out);
969 out
970 }
971
972 fn write_value(&self, table: &[Arc<Scale>], out: &mut Vec<u8>) {
973 let place = |s: &Arc<Scale>| {
974 table.iter().position(|t| t.same_infinitesimal(s)).expect("the table holds every infinitesimal") as u64
975 };
976 match self {
977 Multi::Standard(a) => {
978 out.push(0);
979 a.write(out);
980 }
981 Multi::One(c, s) => {
982 out.push(1);
983 place(s).write(out);
984 c.encode(out);
985 }
986 Multi::Over { scale, q, num, den } => {
987 out.push(2);
988 place(scale).write(out);
989 u64::from(*q).write(out);
990 for p in [num, den] {
991 write_len(p.c.len(), out);
992 for c in &p.c {
993 c.write_value(table, out);
994 }
995 }
996 }
997 Multi::Alg(a) => {
998 out.push(3);
999 place(&a.scale).write(out);
1000 write_recipe(&a.recipe, table, out);
1001 }
1002 }
1003 }
1004
1005 pub fn from_bytes(buf: &[u8]) -> Option<Multi> {
1007 let mut pos = 0;
1008 let count = read_len(buf, &mut pos, MAX_WIRE_LEN)?;
1009 let mut table = Vec::with_capacity(count.min(64));
1010 for _ in 0..count {
1011 let name = read_text(buf, &mut pos)?;
1012 let n = read_len(buf, &mut pos, MAX_WIRE_LEN)?;
1013 let bytes = buf.get(pos..pos.checked_add(n)?)?;
1014 pos += n;
1015 let declared = Scale::from_bytes(&name, bytes)?;
1016 let residues = crate::limit_value::ResidueType::read(buf, &mut pos)?;
1017 table.push(if residues == declared.residues {
1018 declared
1019 } else if declared.residues.and(&residues).ok()? == residues {
1020 Arc::new(declared.with_residues(residues))
1021 } else {
1022 return None;
1023 });
1024 }
1025 for (i, a) in table.iter().enumerate() {
1026 if table[i + 1..].iter().any(|b| a.order(b).is_none_or(|o| o == Ordering::Equal)) {
1027 return None;
1028 }
1029 }
1030 let value = Multi::read_value(buf, &mut pos, &table, 0)?;
1031 (pos == buf.len() && value.to_bytes() == buf).then_some(value)
1032 }
1033
1034 fn read_value(buf: &[u8], pos: &mut usize, table: &[Arc<Scale>], depth: usize) -> Option<Multi> {
1035 if depth > MAX_WIRE_DEPTH {
1036 return None;
1037 }
1038 Some(match read_byte(buf, pos)? {
1039 0 => Multi::Standard(Algebraic::read(buf, pos)?),
1040 1 => {
1041 let s = table.get(usize::try_from(u64::read(buf, pos)?).ok()?)?;
1042 Multi::of_closed(Closed::decode(buf, pos)?, s)
1043 }
1044 2 => {
1045 let s = table.get(usize::try_from(u64::read(buf, pos)?).ok()?)?.clone();
1046 let q = u32::try_from(u64::read(buf, pos)?).ok().filter(|q| *q > 0)?;
1047 let mut polys = Vec::with_capacity(2);
1048 for _ in 0..2 {
1049 let n = read_len(buf, pos, MAX_WIRE_LEN)?;
1050 let mut c = Vec::with_capacity(n.min(64));
1051 for _ in 0..n {
1052 c.push(Multi::read_value(buf, pos, table, depth + 1)?);
1053 }
1054 polys.push(PolyOver::from(c));
1055 }
1056 let den = polys.pop().expect("two polynomials");
1057 let num = polys.pop().expect("two polynomials");
1058 if den.is_zero() {
1059 return None;
1060 }
1061 let larger = num
1062 .c
1063 .iter()
1064 .chain(den.c.iter())
1065 .all(|c| c.scales().iter().all(|t| t.order(&s) == Some(Ordering::Greater)));
1066 if !larger {
1067 return None;
1068 }
1069 Multi::make(&s, q, num, den)
1070 }
1071 3 => {
1072 let s = table.get(usize::try_from(u64::read(buf, pos)?).ok()?)?.clone();
1073 read_recipe(buf, pos, table, &s, depth + 1)?
1074 }
1075 _ => return None,
1076 })
1077 }
1078}
1079
1080fn recipe_scales(recipe: &Recipe, out: &mut Vec<Arc<Scale>>) {
1082 match recipe {
1083 Recipe::Field(x) => x.collect_scales(out),
1084 Recipe::Closed(_) => {}
1085 Recipe::Add(a, b) | Recipe::Mul(a, b) => {
1086 recipe_scales(&a.recipe, out);
1087 recipe_scales(&b.recipe, out);
1088 }
1089 Recipe::Neg(a) | Recipe::Recip(a) | Recipe::Root(a, _) | Recipe::Pow(a, _) => recipe_scales(&a.recipe, out),
1090 }
1091}
1092
1093fn write_recipe(recipe: &Recipe, table: &[Arc<Scale>], out: &mut Vec<u8>) {
1097 match recipe {
1098 Recipe::Field(x) => {
1099 out.push(0);
1100 x.write_value(table, out);
1101 }
1102 Recipe::Closed(p) => {
1103 out.push(1);
1104 p.write(out);
1105 }
1106 Recipe::Add(a, b) => {
1107 out.push(2);
1108 write_recipe(&a.recipe, table, out);
1109 write_recipe(&b.recipe, table, out);
1110 }
1111 Recipe::Neg(a) => {
1112 out.push(3);
1113 write_recipe(&a.recipe, table, out);
1114 }
1115 Recipe::Mul(a, b) => {
1116 out.push(4);
1117 write_recipe(&a.recipe, table, out);
1118 write_recipe(&b.recipe, table, out);
1119 }
1120 Recipe::Recip(a) => {
1121 out.push(5);
1122 write_recipe(&a.recipe, table, out);
1123 }
1124 Recipe::Root(a, n) => {
1125 out.push(6);
1126 write_recipe(&a.recipe, table, out);
1127 u64::from(*n).write(out);
1128 }
1129 Recipe::Pow(a, k) => {
1130 out.push(7);
1131 write_recipe(&a.recipe, table, out);
1132 u64::from(*k).write(out);
1133 }
1134 }
1135}
1136
1137fn read_recipe(buf: &[u8], pos: &mut usize, table: &[Arc<Scale>], scale: &Arc<Scale>, depth: usize) -> Option<Multi> {
1139 use crate::exact_codec::MAX_WIRE_DEGREE;
1140 if depth > MAX_WIRE_DEPTH {
1141 return None;
1142 }
1143 let operand = |m: Multi| Arc::new(AlgValue::at(&m, scale));
1144 Some(match read_byte(buf, pos)? {
1145 0 => Multi::read_value(buf, pos, table, depth + 1)?,
1146 1 => Multi::of_closed(Puiseux::read(buf, pos)?.canonical(), scale),
1147 2 => {
1148 let a = operand(read_recipe(buf, pos, table, scale, depth + 1)?);
1149 let b = operand(read_recipe(buf, pos, table, scale, depth + 1)?);
1150 AlgValue::add(&a, &b)
1151 }
1152 3 => AlgValue::neg(&operand(read_recipe(buf, pos, table, scale, depth + 1)?)),
1153 4 => {
1154 let a = read_recipe(buf, pos, table, scale, depth + 1)?;
1155 let b = read_recipe(buf, pos, table, scale, depth + 1)?;
1156 if a.is_zero() || b.is_zero() {
1157 return None;
1158 }
1159 AlgValue::mul(&operand(a), &operand(b))
1160 }
1161 5 => {
1162 let a = read_recipe(buf, pos, table, scale, depth + 1)?;
1163 if a.is_zero() {
1164 return None;
1165 }
1166 AlgValue::recip(&operand(a))
1167 }
1168 6 => {
1169 let a = read_recipe(buf, pos, table, scale, depth + 1)?;
1170 let n = u32::try_from(u64::read(buf, pos)?).ok().filter(|n| (2..=MAX_WIRE_DEGREE as u32).contains(n))?;
1171 if a.is_zero() {
1172 return None;
1173 }
1174 AlgValue::root(&operand(a), n).ok()?
1175 }
1176 7 => {
1177 let a = read_recipe(buf, pos, table, scale, depth + 1)?;
1178 let k = u32::try_from(u64::read(buf, pos)?).ok().filter(|k| (2..=MAX_POWER_DEGREE as u32).contains(k))?;
1179 if a.is_zero() {
1180 return None;
1181 }
1182 AlgValue::pow(&operand(a), k)
1183 }
1184 _ => return None,
1185 })
1186}
1187
1188fn write_text(text: &str, out: &mut Vec<u8>) {
1189 write_len(text.len(), out);
1190 out.extend_from_slice(text.as_bytes());
1191}
1192
1193fn read_text(buf: &[u8], pos: &mut usize) -> Option<String> {
1194 let n = read_len(buf, pos, MAX_WIRE_LEN)?;
1195 let bytes = buf.get(*pos..pos.checked_add(n)?)?;
1196 *pos += n;
1197 String::from_utf8(bytes.to_vec()).ok()
1198}
1199
1200#[cfg(test)]
1201#[path = "../../logicaffeine_tests/unit/logicaffeine_base/multi/tests.rs"]
1202mod tests;
1203
1204fn reciprocal_terms(m: &Multi, monomial: &mut Vec<(Arc<Scale>, u32)>, out: &mut Vec<(Vec<(Arc<Scale>, u32)>, Rational)>) -> Option<()> {
1208 match m {
1209 Multi::Standard(a) => {
1210 let r = a.to_rational()?;
1211 if !r.is_zero() {
1212 out.push((monomial.clone(), r));
1213 }
1214 }
1215 Multi::One(c, s) => {
1216 let (h, q) = c.field()?;
1217 if q != 1 {
1218 return None;
1219 }
1220 for (j, r) in h.as_reciprocal_powers()?.into_iter().enumerate() {
1221 if r.is_zero() {
1222 continue;
1223 }
1224 let mut term = monomial.clone();
1225 if j > 0 {
1226 term.push((s.clone(), j as u32));
1227 }
1228 out.push((term, r));
1229 }
1230 }
1231 Multi::Over { scale, q, num, den } => {
1232 let d = den.order()?;
1233 if den.c.iter().enumerate().any(|(i, c)| i != d && !c.is_zero()) {
1234 return None;
1235 }
1236 for (i, c) in num.c.iter().enumerate() {
1237 if c.is_zero() {
1238 continue;
1239 }
1240 if i > d || (d - i) % *q as usize != 0 {
1241 return None;
1242 }
1243 let j = ((d - i) / *q as usize) as u32;
1244 if j > 0 {
1245 monomial.push((scale.clone(), j));
1246 }
1247 reciprocal_terms(&c.mul(&den.coeff(d).recip()?), monomial, out)?;
1248 if j > 0 {
1249 monomial.pop();
1250 }
1251 }
1252 }
1253 Multi::Alg(_) => return None,
1254 }
1255 Some(())
1256}
1257
1258const INTEGRAL_CLASSES: u64 = 1 << 16;