1use super::functions::*;
6use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
7
8pub struct L2Sequence {
9 pub terms: Vec<f64>,
10 pub max_terms: usize,
11}
12impl L2Sequence {
13 pub fn new(terms: Vec<f64>) -> Self {
14 let max_terms = terms.len();
15 L2Sequence { terms, max_terms }
16 }
17 pub fn l2_norm(&self) -> f64 {
18 self.terms.iter().map(|x| x * x).sum::<f64>().sqrt()
19 }
20 pub fn is_in_l2(&self) -> bool {
21 self.l2_norm().is_finite()
22 }
23 pub fn inner_product(&self, other: &Self) -> f64 {
24 self.terms
25 .iter()
26 .zip(other.terms.iter())
27 .map(|(a, b)| a * b)
28 .sum()
29 }
30 pub fn shift_left(&self) -> Self {
31 let terms = if self.terms.is_empty() {
32 vec![]
33 } else {
34 self.terms[1..].to_vec()
35 };
36 L2Sequence {
37 max_terms: terms.len(),
38 terms,
39 }
40 }
41 pub fn shift_right(&self) -> Self {
42 let mut terms = vec![0.0];
43 terms.extend_from_slice(&self.terms);
44 L2Sequence {
45 max_terms: terms.len(),
46 terms,
47 }
48 }
49 pub fn seq_add(&self, other: &Self) -> Self {
50 let len = self.terms.len().max(other.terms.len());
51 let terms: Vec<f64> = (0..len)
52 .map(|i| {
53 let a = if i < self.terms.len() {
54 self.terms[i]
55 } else {
56 0.0
57 };
58 let b = if i < other.terms.len() {
59 other.terms[i]
60 } else {
61 0.0
62 };
63 a + b
64 })
65 .collect();
66 L2Sequence {
67 max_terms: terms.len(),
68 terms,
69 }
70 }
71 pub fn seq_scale(&self, c: f64) -> Self {
72 let terms: Vec<f64> = self.terms.iter().map(|x| x * c).collect();
73 L2Sequence {
74 max_terms: terms.len(),
75 terms,
76 }
77 }
78 pub fn convolve(&self, other: &Self) -> Self {
79 let (n, m) = (self.terms.len(), other.terms.len());
80 if n == 0 || m == 0 {
81 return L2Sequence::new(vec![]);
82 }
83 let mut result = vec![0.0; n + m - 1];
84 for i in 0..n {
85 for j in 0..m {
86 result[i + j] += self.terms[i] * other.terms[j];
87 }
88 }
89 L2Sequence::new(result)
90 }
91 pub fn parseval_residual(&self) -> f64 {
92 let norm_sq = self.l2_norm().powi(2);
93 let sum_sq: f64 = self.terms.iter().map(|x| x * x).sum();
94 (norm_sq - sum_sq).abs()
95 }
96}
97#[allow(dead_code)]
99#[derive(Debug, Clone)]
100pub struct SobolevSpaceData {
101 pub order: usize,
103 pub p: f64,
105 pub domain_dim: usize,
107 pub domain: String,
109}
110#[allow(dead_code)]
111impl SobolevSpaceData {
112 pub fn new(order: usize, p: f64, domain_dim: usize, domain: &str) -> Self {
114 SobolevSpaceData {
115 order,
116 p,
117 domain_dim,
118 domain: domain.to_string(),
119 }
120 }
121 pub fn hilbert_sobolev(order: usize, domain_dim: usize, domain: &str) -> Self {
123 SobolevSpaceData::new(order, 2.0, domain_dim, domain)
124 }
125 pub fn embedding_exponent(&self) -> Option<f64> {
127 if self.p < 1.0 {
128 return None;
129 }
130 let critical = 1.0 / self.p - (self.order as f64) / (self.domain_dim as f64);
131 if critical <= 0.0 {
132 None
133 } else {
134 Some(1.0 / critical)
135 }
136 }
137 pub fn critical_sobolev_exponent(&self) -> Option<f64> {
139 let kp = self.order as f64 * self.p;
140 let n = self.domain_dim as f64;
141 if kp >= n {
142 None
143 } else {
144 Some(n * self.p / (n - kp))
145 }
146 }
147 pub fn rellich_kondrachov_compact(&self) -> bool {
149 self.order >= 1 && self.domain_dim >= 1
150 }
151 pub fn trace_theorem(&self) -> String {
153 if self.order >= 1 {
154 format!(
155 "Trace: W^{{{},{}}}'(Ω) → W^{{{}−1/p,p}}(∂Ω)",
156 self.order, self.p, self.order
157 )
158 } else {
159 "No trace for W^{0,p}".to_string()
160 }
161 }
162}
163#[allow(dead_code)]
165#[derive(Debug, Clone)]
166pub struct InterpolationData {
167 pub space0: String,
169 pub space1: String,
171 pub theta: f64,
173 pub method: InterpolationMethod,
175}
176#[allow(dead_code)]
177impl InterpolationData {
178 pub fn new(space0: &str, space1: &str, theta: f64, method: InterpolationMethod) -> Self {
180 InterpolationData {
181 space0: space0.to_string(),
182 space1: space1.to_string(),
183 theta,
184 method,
185 }
186 }
187 pub fn lp_exponent(&self, p0: f64, p1: f64) -> f64 {
189 (1.0 - self.theta) / p0 + self.theta / p1
190 }
191 pub fn riesz_thorin_bound(&self, m0: f64, m1: f64) -> f64 {
194 m0.powf(1.0 - self.theta) * m1.powf(self.theta)
195 }
196 pub fn interpolation_space(&self) -> String {
198 format!("[{}, {}]_{}", self.space0, self.space1, self.theta)
199 }
200}
201#[derive(Debug, Clone)]
202pub struct RnVector {
203 pub components: Vec<f64>,
204}
205impl RnVector {
206 pub fn new(components: Vec<f64>) -> Self {
207 RnVector { components }
208 }
209 pub fn dim(&self) -> usize {
210 self.components.len()
211 }
212 pub fn zero(dim: usize) -> Self {
213 RnVector {
214 components: vec![0.0; dim],
215 }
216 }
217 pub fn basis(dim: usize, i: usize) -> Self {
218 let mut v = vec![0.0; dim];
219 if i < dim {
220 v[i] = 1.0;
221 }
222 RnVector { components: v }
223 }
224 pub fn norm(&self) -> f64 {
225 self.components.iter().map(|x| x * x).sum::<f64>().sqrt()
226 }
227 pub fn norm_p(&self, p: f64) -> f64 {
228 if p.is_infinite() {
229 self.components
230 .iter()
231 .map(|x| x.abs())
232 .fold(0.0_f64, f64::max)
233 } else {
234 self.components
235 .iter()
236 .map(|x| x.abs().powf(p))
237 .sum::<f64>()
238 .powf(1.0 / p)
239 }
240 }
241 pub fn inner(&self, other: &Self) -> f64 {
242 self.components
243 .iter()
244 .zip(other.components.iter())
245 .map(|(a, b)| a * b)
246 .sum()
247 }
248 pub fn normalized(&self) -> Option<Self> {
249 let n = self.norm();
250 if n == 0.0 {
251 None
252 } else {
253 Some(self.scale(1.0 / n))
254 }
255 }
256 pub fn add(&self, other: &Self) -> Self {
257 RnVector {
258 components: self
259 .components
260 .iter()
261 .zip(other.components.iter())
262 .map(|(a, b)| a + b)
263 .collect(),
264 }
265 }
266 pub fn sub(&self, other: &Self) -> Self {
267 RnVector {
268 components: self
269 .components
270 .iter()
271 .zip(other.components.iter())
272 .map(|(a, b)| a - b)
273 .collect(),
274 }
275 }
276 pub fn scale(&self, s: f64) -> Self {
277 RnVector {
278 components: self.components.iter().map(|x| x * s).collect(),
279 }
280 }
281 pub fn angle_with(&self, other: &Self) -> f64 {
282 let n1 = self.norm();
283 let n2 = other.norm();
284 if n1 == 0.0 || n2 == 0.0 {
285 return f64::NAN;
286 }
287 (self.inner(other) / (n1 * n2)).clamp(-1.0, 1.0).acos()
288 }
289 pub fn cross(&self, other: &Self) -> Option<Self> {
290 if self.dim() != 3 || other.dim() != 3 {
291 return None;
292 }
293 let (a, b) = (&self.components, &other.components);
294 Some(RnVector::new(vec![
295 a[1] * b[2] - a[2] * b[1],
296 a[2] * b[0] - a[0] * b[2],
297 a[0] * b[1] - a[1] * b[0],
298 ]))
299 }
300 pub fn project_onto(&self, other: &Self) -> Self {
301 let d = other.inner(other);
302 if d.abs() < 1e-15 {
303 return RnVector::zero(self.dim());
304 }
305 other.scale(self.inner(other) / d)
306 }
307}
308#[derive(Debug, Clone)]
310pub struct QrDecomposition {
311 pub q: BoundedOp,
312 pub r: BoundedOp,
313}
314#[allow(dead_code)]
316#[derive(Debug, Clone, PartialEq)]
317pub enum InterpolationMethod {
318 Complex,
320 Real,
322 RieszThorin,
324}
325#[derive(Debug, Clone)]
326pub struct BoundedOp {
327 pub matrix: Vec<Vec<f64>>,
328 pub domain_dim: usize,
329 pub range_dim: usize,
330}
331impl BoundedOp {
332 pub fn new(matrix: Vec<Vec<f64>>) -> Self {
333 let range_dim = matrix.len();
334 let domain_dim = if range_dim > 0 { matrix[0].len() } else { 0 };
335 BoundedOp {
336 matrix,
337 domain_dim,
338 range_dim,
339 }
340 }
341 pub fn identity(n: usize) -> Self {
342 let matrix: Vec<Vec<f64>> = (0..n)
343 .map(|i| (0..n).map(|j| if i == j { 1.0 } else { 0.0 }).collect())
344 .collect();
345 BoundedOp {
346 matrix,
347 domain_dim: n,
348 range_dim: n,
349 }
350 }
351 pub fn diagonal(entries: &[f64]) -> Self {
352 let n = entries.len();
353 let matrix: Vec<Vec<f64>> = (0..n)
354 .map(|i| {
355 let mut row = vec![0.0; n];
356 row[i] = entries[i];
357 row
358 })
359 .collect();
360 BoundedOp {
361 matrix,
362 domain_dim: n,
363 range_dim: n,
364 }
365 }
366 pub fn zero_op(m: usize, n: usize) -> Self {
367 BoundedOp {
368 matrix: vec![vec![0.0; n]; m],
369 domain_dim: n,
370 range_dim: m,
371 }
372 }
373 pub fn apply(&self, v: &RnVector) -> RnVector {
374 if v.dim() != self.domain_dim {
375 return RnVector::zero(self.range_dim);
376 }
377 let comps: Vec<f64> = self
378 .matrix
379 .iter()
380 .map(|row| {
381 row.iter()
382 .zip(v.components.iter())
383 .map(|(a, b)| a * b)
384 .sum()
385 })
386 .collect();
387 RnVector { components: comps }
388 }
389 pub fn operator_norm(&self) -> f64 {
390 self.frobenius_norm()
391 }
392 pub fn operator_norm_power_iter(&self, iterations: usize) -> f64 {
393 let ata = match self.transpose().compose(self) {
394 Some(m) => m,
395 None => return 0.0,
396 };
397 if self.domain_dim == 0 {
398 return 0.0;
399 }
400 let mut v = RnVector::new(vec![1.0; self.domain_dim]);
401 let n = v.norm();
402 if n > 0.0 {
403 v = v.scale(1.0 / n);
404 }
405 let mut eigenvalue = 0.0;
406 for _ in 0..iterations {
407 let w = ata.apply(&v);
408 eigenvalue = w.norm();
409 if eigenvalue < 1e-15 {
410 return 0.0;
411 }
412 v = w.scale(1.0 / eigenvalue);
413 }
414 eigenvalue.sqrt()
415 }
416 pub fn transpose(&self) -> Self {
417 if self.range_dim == 0 || self.domain_dim == 0 {
418 return BoundedOp::new(vec![]);
419 }
420 let matrix: Vec<Vec<f64>> = (0..self.domain_dim)
421 .map(|j| (0..self.range_dim).map(|i| self.matrix[i][j]).collect())
422 .collect();
423 BoundedOp {
424 matrix,
425 domain_dim: self.range_dim,
426 range_dim: self.domain_dim,
427 }
428 }
429 pub fn compose(&self, other: &Self) -> Option<Self> {
430 if other.range_dim != self.domain_dim {
431 return None;
432 }
433 let (m, n, k) = (self.range_dim, other.domain_dim, self.domain_dim);
434 let matrix: Vec<Vec<f64>> = (0..m)
435 .map(|i| {
436 (0..n)
437 .map(|j| (0..k).map(|l| self.matrix[i][l] * other.matrix[l][j]).sum())
438 .collect()
439 })
440 .collect();
441 Some(BoundedOp {
442 matrix,
443 domain_dim: n,
444 range_dim: m,
445 })
446 }
447 pub fn op_add(&self, other: &Self) -> Option<Self> {
448 if self.domain_dim != other.domain_dim || self.range_dim != other.range_dim {
449 return None;
450 }
451 let matrix: Vec<Vec<f64>> = self
452 .matrix
453 .iter()
454 .zip(other.matrix.iter())
455 .map(|(r1, r2)| r1.iter().zip(r2.iter()).map(|(a, b)| a + b).collect())
456 .collect();
457 Some(BoundedOp {
458 matrix,
459 domain_dim: self.domain_dim,
460 range_dim: self.range_dim,
461 })
462 }
463 pub fn scalar_mul(&self, c: f64) -> Self {
464 let matrix: Vec<Vec<f64>> = self
465 .matrix
466 .iter()
467 .map(|row| row.iter().map(|x| x * c).collect())
468 .collect();
469 BoundedOp {
470 matrix,
471 domain_dim: self.domain_dim,
472 range_dim: self.range_dim,
473 }
474 }
475 pub fn is_symmetric(&self) -> bool {
476 if self.domain_dim != self.range_dim {
477 return false;
478 }
479 let n = self.domain_dim;
480 for i in 0..n {
481 for j in (i + 1)..n {
482 if (self.matrix[i][j] - self.matrix[j][i]).abs() > 1e-10 {
483 return false;
484 }
485 }
486 }
487 true
488 }
489 pub fn is_positive_definite(&self) -> bool {
490 if !self.is_symmetric() {
491 return false;
492 }
493 let n = self.domain_dim;
494 let mut l = vec![vec![0.0; n]; n];
495 for i in 0..n {
496 for j in 0..=i {
497 let mut sum = 0.0;
498 for k in 0..j {
499 sum += l[i][k] * l[j][k];
500 }
501 if i == j {
502 let val = self.matrix[i][i] - sum;
503 if val <= 0.0 {
504 return false;
505 }
506 l[i][j] = val.sqrt();
507 } else {
508 if l[j][j].abs() < 1e-15 {
509 return false;
510 }
511 l[i][j] = (self.matrix[i][j] - sum) / l[j][j];
512 }
513 }
514 }
515 true
516 }
517 pub fn eigenvalues_2x2(&self) -> Option<(f64, f64)> {
518 if self.domain_dim != 2 || self.range_dim != 2 || !self.is_symmetric() {
519 return None;
520 }
521 let (a, b, d) = (self.matrix[0][0], self.matrix[0][1], self.matrix[1][1]);
522 let tr = a + d;
523 let det = a * d - b * b;
524 let disc = tr * tr - 4.0 * det;
525 if disc < 0.0 {
526 return None;
527 }
528 let s = disc.sqrt();
529 Some(((tr + s) / 2.0, (tr - s) / 2.0))
530 }
531 pub fn power_iteration(&self, iterations: usize) -> Option<(f64, RnVector)> {
532 if self.domain_dim != self.range_dim || self.domain_dim == 0 {
533 return None;
534 }
535 let n = self.domain_dim;
536 let mut v = RnVector::new(vec![1.0; n]);
537 let nrm = v.norm();
538 if nrm > 0.0 {
539 v = v.scale(1.0 / nrm);
540 }
541 let mut eigenvalue = 0.0;
542 for _ in 0..iterations {
543 let w = self.apply(&v);
544 eigenvalue = w.inner(&v);
545 let nrm = w.norm();
546 if nrm < 1e-15 {
547 return Some((0.0, v));
548 }
549 v = w.scale(1.0 / nrm);
550 }
551 Some((eigenvalue, v))
552 }
553 pub fn trace(&self) -> f64 {
554 let n = self.domain_dim.min(self.range_dim);
555 (0..n).map(|i| self.matrix[i][i]).sum()
556 }
557 pub fn frobenius_norm(&self) -> f64 {
558 self.matrix
559 .iter()
560 .flat_map(|row| row.iter())
561 .map(|x| x * x)
562 .sum::<f64>()
563 .sqrt()
564 }
565 pub fn determinant(&self) -> Option<f64> {
566 if self.domain_dim != self.range_dim {
567 return None;
568 }
569 let n = self.domain_dim;
570 if n == 0 {
571 return Some(1.0);
572 }
573 let mut a = self.matrix.clone();
574 let mut sign = 1.0;
575 for col in 0..n {
576 let mut max_row = col;
577 let mut max_val = a[col][col].abs();
578 for row in (col + 1)..n {
579 if a[row][col].abs() > max_val {
580 max_val = a[row][col].abs();
581 max_row = row;
582 }
583 }
584 if max_val < 1e-15 {
585 return Some(0.0);
586 }
587 if max_row != col {
588 a.swap(col, max_row);
589 sign *= -1.0;
590 }
591 let pivot = a[col][col];
592 for row in (col + 1)..n {
593 let factor = a[row][col] / pivot;
594 for j in col..n {
595 let val = a[col][j];
596 a[row][j] -= factor * val;
597 }
598 }
599 }
600 Some((0..n).map(|i| a[i][i]).product::<f64>() * sign)
601 }
602 pub fn solve(&self, b: &RnVector) -> Option<RnVector> {
603 if self.domain_dim != self.range_dim || b.dim() != self.range_dim {
604 return None;
605 }
606 let n = self.domain_dim;
607 let mut aug: Vec<Vec<f64>> = self
608 .matrix
609 .iter()
610 .enumerate()
611 .map(|(i, row)| {
612 let mut r = row.clone();
613 r.push(b.components[i]);
614 r
615 })
616 .collect();
617 for col in 0..n {
618 let mut max_row = col;
619 let mut max_val = aug[col][col].abs();
620 for row in (col + 1)..n {
621 if aug[row][col].abs() > max_val {
622 max_val = aug[row][col].abs();
623 max_row = row;
624 }
625 }
626 if max_val < 1e-15 {
627 return None;
628 }
629 if max_row != col {
630 aug.swap(col, max_row);
631 }
632 let pivot = aug[col][col];
633 for row in (col + 1)..n {
634 let factor = aug[row][col] / pivot;
635 for j in col..=n {
636 let val = aug[col][j];
637 aug[row][j] -= factor * val;
638 }
639 }
640 }
641 let mut x = vec![0.0; n];
642 for i in (0..n).rev() {
643 let mut sum = aug[i][n];
644 for j in (i + 1)..n {
645 sum -= aug[i][j] * x[j];
646 }
647 if aug[i][i].abs() < 1e-15 {
648 return None;
649 }
650 x[i] = sum / aug[i][i];
651 }
652 Some(RnVector::new(x))
653 }
654 pub fn rank(&self) -> usize {
655 let (m, n) = (self.range_dim, self.domain_dim);
656 let mut a = self.matrix.clone();
657 let mut rank = 0;
658 for col in 0..n {
659 let mut pivot_row = None;
660 for row in rank..m {
661 if a[row][col].abs() > 1e-12 {
662 pivot_row = Some(row);
663 break;
664 }
665 }
666 let pr = match pivot_row {
667 Some(r) => r,
668 None => continue,
669 };
670 a.swap(rank, pr);
671 let pivot = a[rank][col];
672 for row in (rank + 1)..m {
673 let factor = a[row][col] / pivot;
674 for j in col..n {
675 let val = a[rank][j];
676 a[row][j] -= factor * val;
677 }
678 }
679 rank += 1;
680 }
681 rank
682 }
683 pub fn nullity(&self) -> usize {
684 self.domain_dim - self.rank()
685 }
686 pub fn is_injective(&self) -> bool {
687 self.nullity() == 0
688 }
689 pub fn is_surjective(&self) -> bool {
690 self.rank() == self.range_dim
691 }
692}
693#[derive(Debug, Clone)]
695pub struct LuDecomposition {
696 pub l: BoundedOp,
697 pub u: BoundedOp,
698 pub permutation: Vec<usize>,
699}
700#[allow(dead_code)]
702#[derive(Debug, Clone)]
703pub struct WeakConvergenceData {
704 pub sequence: Vec<Vec<f64>>,
706 pub weak_limit: Option<Vec<f64>>,
708 pub is_bounded: bool,
710}
711#[allow(dead_code)]
712impl WeakConvergenceData {
713 pub fn new(sequence: Vec<Vec<f64>>) -> Self {
715 let is_bounded = sequence.iter().all(|v| {
716 let norm: f64 = v.iter().map(|&x| x * x).sum::<f64>().sqrt();
717 norm <= 1e6
718 });
719 WeakConvergenceData {
720 sequence,
721 weak_limit: None,
722 is_bounded,
723 }
724 }
725 pub fn check_weak_convergence(&self, limit: &[f64], tol: f64) -> bool {
727 if self.sequence.is_empty() {
728 return true;
729 }
730 let last = &self.sequence[self.sequence.len().saturating_sub(5)..];
731 last.iter().all(|v| {
732 limit
733 .iter()
734 .zip(v.iter())
735 .map(|(&l, &x)| (l - x).abs())
736 .fold(0.0f64, f64::max)
737 < tol
738 })
739 }
740 pub fn banach_alaoglu_applies(&self) -> bool {
742 self.is_bounded
743 }
744 pub fn last_norm(&self) -> Option<f64> {
746 self.sequence
747 .last()
748 .map(|v| v.iter().map(|&x| x * x).sum::<f64>().sqrt())
749 }
750}
751#[allow(dead_code)]
753#[derive(Debug, Clone)]
754pub struct FredholmOperatorData {
755 pub name: String,
757 pub kernel_dim: usize,
759 pub cokernel_dim: usize,
761 pub is_fredholm: bool,
763}
764#[allow(dead_code)]
765impl FredholmOperatorData {
766 pub fn new(name: &str, kernel_dim: usize, cokernel_dim: usize) -> Self {
768 FredholmOperatorData {
769 name: name.to_string(),
770 kernel_dim,
771 cokernel_dim,
772 is_fredholm: true,
773 }
774 }
775 pub fn index(&self) -> i64 {
777 self.kernel_dim as i64 - self.cokernel_dim as i64
778 }
779 pub fn atkinson_description(&self) -> String {
781 format!("T = {} is Fredholm with index {}", self.name, self.index())
782 }
783 pub fn index_stable_under_compact(&self) -> bool {
785 true
786 }
787 pub fn is_isomorphism(&self) -> bool {
789 self.kernel_dim == 0 && self.cokernel_dim == 0
790 }
791 pub fn essential_spectrum_description(&self) -> String {
793 format!("σ_ess({}): values λ making T-λI non-Fredholm", self.name)
794 }
795}
796#[allow(dead_code)]
798#[derive(Debug, Clone)]
799pub struct Distribution {
800 pub name: String,
802 pub order: Option<usize>,
804 pub support: String,
806 pub is_regular: bool,
808}
809#[allow(dead_code)]
810impl Distribution {
811 pub fn new(name: &str) -> Self {
813 Distribution {
814 name: name.to_string(),
815 order: None,
816 support: "unknown".to_string(),
817 is_regular: false,
818 }
819 }
820 pub fn dirac_delta(point: f64) -> Self {
822 Distribution {
823 name: format!("δ_{{{point}}}"),
824 order: Some(0),
825 support: point.to_string(),
826 is_regular: false,
827 }
828 }
829 pub fn regular(name: &str, support: &str) -> Self {
831 Distribution {
832 name: name.to_string(),
833 order: Some(0),
834 support: support.to_string(),
835 is_regular: true,
836 }
837 }
838 pub fn differentiate(&self) -> Distribution {
840 Distribution {
841 name: format!("d/dx ({})", self.name),
842 order: self.order.map(|o| o + 1),
843 support: self.support.clone(),
844 is_regular: false,
845 }
846 }
847 pub fn fourier_transform_description(&self) -> String {
849 if self.name.starts_with('δ') {
850 "F[δ_a](ξ) = e^{-2πiαξ} (constant modulus 1)".to_string()
851 } else {
852 format!("F[{}](ξ) (distributional Fourier transform)", self.name)
853 }
854 }
855 pub fn is_tempered(&self) -> bool {
857 self.order.map(|o| o <= 100).unwrap_or(false)
858 }
859}