1use crate::error::Error;
13use crate::matrix::Mat;
14use crate::numeric::CustomNumeric;
15use simba::scalar::ComplexField;
16use std::fmt::Debug;
17
18fn check_weights<T>(x: &[T], w: &[T]) -> Result<(), Error> {
20 if x.len() == w.len() {
21 Ok(())
22 } else {
23 Err(Error::InvalidParameter {
24 name: "w",
25 value: format!("{} weights", w.len()),
26 reason: format!("must have one weight per point ({})", x.len()),
27 })
28 }
29}
30
31#[derive(Debug, Clone)]
37pub struct Rule<T> {
38 pub(crate) x: Vec<T>,
40 pub(crate) w: Vec<T>,
42 pub(crate) x_forward: Vec<T>,
44 pub(crate) x_backward: Vec<T>,
46 pub(crate) a: T,
48 pub(crate) b: T,
50}
51
52impl<T: Copy> Rule<T> {
53 pub fn x(&self) -> &[T] {
55 &self.x
56 }
57
58 pub fn w(&self) -> &[T] {
60 &self.w
61 }
62
63 pub fn x_forward(&self) -> &[T] {
65 &self.x_forward
66 }
67
68 pub fn x_backward(&self) -> &[T] {
70 &self.x_backward
71 }
72
73 pub fn a(&self) -> T {
75 self.a
76 }
77
78 pub fn b(&self) -> T {
80 self.b
81 }
82}
83
84impl<T> Rule<T>
85where
86 T: CustomNumeric,
87{
88 pub fn new(x: Vec<T>, w: Vec<T>, a: T, b: T) -> Result<Self, Error> {
102 check_weights(&x, &w)?;
103
104 let x_forward: Vec<T> = x.iter().map(|&xi| xi - a).collect();
105 let x_backward: Vec<T> = x.iter().map(|&xi| b - xi).collect();
106
107 Ok(Self {
108 x,
109 w,
110 x_forward,
111 x_backward,
112 a,
113 b,
114 })
115 }
116
117 pub fn from_vectors(x: Vec<T>, w: Vec<T>, a: T, b: T) -> Result<Self, Error> {
122 Self::new(x, w, a, b)
123 }
124
125 pub fn empty() -> Self {
127 Self {
128 x: vec![],
129 w: vec![],
130 x_forward: vec![],
131 x_backward: vec![],
132 a: <T as CustomNumeric>::from_f64_unchecked(-1.0),
133 b: <T as CustomNumeric>::from_f64_unchecked(1.0),
134 }
135 }
136
137 pub fn reseat(&self, a: T, b: T) -> Self {
141 let scaling = (b - a) / (self.b - self.a);
142 let midpoint_old = (self.b + self.a) * <T as CustomNumeric>::from_f64_unchecked(0.5);
143 let midpoint_new = (b + a) * <T as CustomNumeric>::from_f64_unchecked(0.5);
144
145 let new_x: Vec<T> = self
147 .x
148 .iter()
149 .map(|&xi| scaling * (xi - midpoint_old) + midpoint_new)
150 .collect();
151 let new_w: Vec<T> = self.w.iter().map(|&wi| wi * scaling).collect();
152 let new_x_forward: Vec<T> = self.x_forward.iter().map(|&xi| xi * scaling).collect();
153 let new_x_backward: Vec<T> = self.x_backward.iter().map(|&xi| xi * scaling).collect();
154
155 Self {
156 x: new_x,
157 w: new_w,
158 x_forward: new_x_forward,
159 x_backward: new_x_backward,
160 a,
161 b,
162 }
163 }
164
165 pub fn scale(&self, factor: T) -> Self {
167 Self {
168 x: self.x.clone(),
169 w: self.w.iter().map(|&wi| wi * factor).collect(),
170 x_forward: self.x_forward.clone(),
171 x_backward: self.x_backward.clone(),
172 a: self.a,
173 b: self.b,
174 }
175 }
176
177 pub fn piecewise(&self, edges: &[T]) -> Result<Self, Error> {
187 if edges.len() < 2 {
188 return Err(Error::InvalidParameter {
189 name: "edges",
190 value: format!("{} edges", edges.len()),
191 reason: "must have at least 2 entries".to_string(),
192 });
193 }
194 if let Some((i, e)) = edges
195 .iter()
196 .enumerate()
197 .find(|(_, e)| !e.to_f64().is_finite())
198 {
199 return Err(Error::InvalidParameter {
200 name: "edges",
201 value: format!("{:?} at index {i}", e.to_f64()),
202 reason: "must be finite".to_string(),
203 });
204 }
205 for i in 1..edges.len() {
206 let length = (edges[i] - edges[i - 1]).to_f64();
207 if !(length > 0.0 && length.is_finite()) {
208 return Err(Error::InvalidParameter {
209 name: "edges",
210 value: format!(
211 "{:?} after {:?} at index {i}",
212 edges[i].to_f64(),
213 edges[i - 1].to_f64()
214 ),
215 reason: "must be strictly increasing, with finite segment lengths".to_string(),
216 });
217 }
218 if !(edges[i] + edges[i - 1]).to_f64().is_finite() {
220 return Err(Error::InvalidParameter {
221 name: "edges",
222 value: format!(
223 "{:?} after {:?} at index {i}",
224 edges[i].to_f64(),
225 edges[i - 1].to_f64()
226 ),
227 reason: "must have a finite sum of the ends of each segment".to_string(),
228 });
229 }
230 }
231
232 let mut rules = Vec::new();
233 for i in 0..edges.len() - 1 {
234 let rule = self.reseat(edges[i], edges[i + 1]);
235 rules.push(rule);
236 }
237
238 Ok(Self::join(&rules))
239 }
240
241 pub fn join(rules: &[Self]) -> Self {
249 if rules.is_empty() {
250 return Self::empty();
251 }
252
253 let a = rules[0].a;
254 let b = rules[rules.len() - 1].b;
255
256 for i in 1..rules.len() {
258 if (rules[i].a - rules[i - 1].b).abs_as_same_type() > T::epsilon() {
259 panic!("rules must be contiguous");
260 }
261 }
262
263 let mut x_vec = Vec::new();
265 let mut w_vec = Vec::new();
266 let mut x_forward_vec = Vec::new();
267 let mut x_backward_vec = Vec::new();
268
269 for rule in rules {
270 let x_forward_adj: Vec<T> =
272 rule.x_forward.iter().map(|&xi| xi + (rule.a - a)).collect();
273 let x_backward_adj: Vec<T> = rule
274 .x_backward
275 .iter()
276 .map(|&xi| xi + (b - rule.b))
277 .collect();
278
279 x_vec.extend(rule.x.iter().cloned());
280 w_vec.extend(rule.w.iter().cloned());
281 x_forward_vec.extend(x_forward_adj.iter().cloned());
282 x_backward_vec.extend(x_backward_adj.iter().cloned());
283 }
284
285 let mut indices: Vec<usize> = (0..x_vec.len()).collect();
287 indices.sort_by(|&a, &b| x_vec[a].partial_cmp(&x_vec[b]).unwrap());
288
289 let sorted_x: Vec<T> = indices.iter().map(|&i| x_vec[i]).collect();
290 let sorted_w: Vec<T> = indices.iter().map(|&i| w_vec[i]).collect();
291
292 let sorted_x_forward: Vec<T> = sorted_x.iter().map(|&xi| xi - a).collect();
294 let sorted_x_backward: Vec<T> = sorted_x.iter().map(|&xi| b - xi).collect();
295
296 Self {
297 x: sorted_x,
298 w: sorted_w,
299 x_forward: sorted_x_forward,
300 x_backward: sorted_x_backward,
301 a,
302 b,
303 }
304 }
305
306 pub fn convert<U>(&self) -> Rule<U>
308 where
309 U: CustomNumeric + Copy + Debug + std::fmt::Display,
310 {
311 let x: Vec<U> = self
312 .x
313 .iter()
314 .map(|&xi| <U as CustomNumeric>::from_f64_unchecked(xi.to_f64()))
315 .collect();
316 let w: Vec<U> = self
317 .w
318 .iter()
319 .map(|&wi| <U as CustomNumeric>::from_f64_unchecked(wi.to_f64()))
320 .collect();
321 let x_forward: Vec<U> = self
322 .x_forward
323 .iter()
324 .map(|&xi| <U as CustomNumeric>::from_f64_unchecked(xi.to_f64()))
325 .collect();
326 let x_backward: Vec<U> = self
327 .x_backward
328 .iter()
329 .map(|&xi| <U as CustomNumeric>::from_f64_unchecked(xi.to_f64()))
330 .collect();
331 let a = <U as CustomNumeric>::from_f64_unchecked(self.a.to_f64());
332 let b = <U as CustomNumeric>::from_f64_unchecked(self.b.to_f64());
333
334 Rule {
335 x,
336 w,
337 x_forward,
338 x_backward,
339 a,
340 b,
341 }
342 }
343
344 pub fn validate(&self) -> bool {
349 if self.a >= self.b {
351 return false;
352 }
353
354 if self.x.len() != self.w.len() {
356 return false;
357 }
358
359 if self.x.len() != self.x_forward.len() || self.x.len() != self.x_backward.len() {
360 return false;
361 }
362
363 for &xi in self.x.iter() {
365 if xi < self.a || xi > self.b {
366 return false;
367 }
368 }
369
370 for i in 1..self.x.len() {
372 if self.x[i] <= self.x[i - 1] {
373 return false;
374 }
375 }
376
377 for i in 0..self.x.len() {
379 let expected_forward = self.x[i] - self.a;
380 let expected_backward = self.b - self.x[i];
381
382 if (self.x_forward[i] - expected_forward).abs_as_same_type() > T::epsilon() {
383 return false;
384 }
385 if (self.x_backward[i] - expected_backward).abs_as_same_type() > T::epsilon() {
386 return false;
387 }
388 }
389
390 true
391 }
392}
393
394impl<T> Rule<T>
396where
397 T: CustomNumeric,
398{
399 pub fn new_custom(x: Vec<T>, w: Vec<T>, a: T, b: T) -> Result<Self, Error> {
404 check_weights(&x, &w)?;
405
406 let x_forward: Vec<T> = x.iter().map(|&xi| xi - a).collect();
407 let x_backward: Vec<T> = x.iter().map(|&xi| b - xi).collect();
408
409 Ok(Self {
410 x,
411 w,
412 x_forward,
413 x_backward,
414 a,
415 b,
416 })
417 }
418
419 pub fn from_vectors_custom(x: Vec<T>, w: Vec<T>, a: T, b: T) -> Result<Self, Error> {
424 Self::new_custom(x, w, a, b)
425 }
426
427 pub fn reseat_custom(&self, a: T, b: T) -> Self {
429 let scaling = (b - a) / (self.b - self.a);
430 let midpoint_old = (self.b + self.a) * <T as CustomNumeric>::from_f64_unchecked(0.5);
431 let midpoint_new = (b + a) * <T as CustomNumeric>::from_f64_unchecked(0.5);
432
433 let new_x: Vec<T> = self
435 .x
436 .iter()
437 .map(|&xi| scaling * (xi - midpoint_old) + midpoint_new)
438 .collect();
439 let new_w: Vec<T> = self.w.iter().map(|&wi| wi * scaling).collect();
440 let new_x_forward: Vec<T> = self.x_forward.iter().map(|&xi| xi * scaling).collect();
441 let new_x_backward: Vec<T> = self.x_backward.iter().map(|&xi| xi * scaling).collect();
442
443 Self {
444 x: new_x,
445 w: new_w,
446 x_forward: new_x_forward,
447 x_backward: new_x_backward,
448 a,
449 b,
450 }
451 }
452
453 pub fn scale_custom(&self, factor: T) -> Self {
455 Self {
456 x: self.x.clone(),
457 w: self.w.iter().map(|&wi| wi * factor).collect(),
458 x_forward: self.x_forward.clone(),
459 x_backward: self.x_backward.clone(),
460 a: self.a,
461 b: self.b,
462 }
463 }
464
465 pub fn validate_custom(&self) -> bool {
467 if self.a >= self.b {
469 return false;
470 }
471
472 if self.x.len() != self.w.len() {
474 return false;
475 }
476
477 if self.x.len() != self.x_forward.len() || self.x.len() != self.x_backward.len() {
478 return false;
479 }
480
481 for &xi in self.x.iter() {
483 if xi < self.a || xi > self.b {
484 return false;
485 }
486 }
487
488 for i in 1..self.x.len() {
490 if self.x[i] <= self.x[i - 1] {
491 return false;
492 }
493 }
494
495 for i in 0..self.x.len() {
497 let expected_forward = self.x[i] - self.a;
498 let expected_backward = self.b - self.x[i];
499
500 if (self.x_forward[i] - expected_forward).abs_as_same_type() > T::epsilon() {
501 return false;
502 }
503 if (self.x_backward[i] - expected_backward).abs_as_same_type() > T::epsilon() {
504 return false;
505 }
506 }
507
508 true
509 }
510}
511
512impl Rule<crate::Df64> {
514 pub fn new_twofloat(
519 x: Vec<crate::Df64>,
520 w: Vec<crate::Df64>,
521 a: crate::Df64,
522 b: crate::Df64,
523 ) -> Result<Self, Error> {
524 check_weights(&x, &w)?;
525
526 let x_forward: Vec<crate::Df64> = x.iter().map(|&xi| xi - a).collect();
527 let x_backward: Vec<crate::Df64> = x.iter().map(|&xi| b - xi).collect();
528
529 Ok(Self {
530 x,
531 w,
532 x_forward,
533 x_backward,
534 a,
535 b,
536 })
537 }
538
539 pub fn from_vectors_twofloat(
544 x: Vec<crate::Df64>,
545 w: Vec<crate::Df64>,
546 a: crate::Df64,
547 b: crate::Df64,
548 ) -> Result<Self, Error> {
549 Self::new_twofloat(x, w, a, b)
550 }
551
552 pub fn reseat_twofloat(&self, a: crate::Df64, b: crate::Df64) -> Self {
554 let scaling = (b - a) / (self.b - self.a);
555 let midpoint_old =
556 (self.b + self.a) * <crate::Df64 as CustomNumeric>::from_f64_unchecked(0.5);
557 let midpoint_new = (b + a) * <crate::Df64 as CustomNumeric>::from_f64_unchecked(0.5);
558
559 let new_x: Vec<crate::Df64> = self
561 .x
562 .iter()
563 .map(|&xi| scaling * (xi - midpoint_old) + midpoint_new)
564 .collect();
565 let new_w: Vec<crate::Df64> = self.w.iter().map(|&wi| wi * scaling).collect();
566 let new_x_forward: Vec<crate::Df64> =
567 self.x_forward.iter().map(|&xi| xi * scaling).collect();
568 let new_x_backward: Vec<crate::Df64> =
569 self.x_backward.iter().map(|&xi| xi * scaling).collect();
570
571 Self {
572 x: new_x,
573 w: new_w,
574 x_forward: new_x_forward,
575 x_backward: new_x_backward,
576 a,
577 b,
578 }
579 }
580
581 pub fn scale_twofloat(&self, factor: crate::Df64) -> Self {
583 Self {
584 x: self.x.clone(),
585 w: self.w.iter().map(|&wi| wi * factor).collect(),
586 x_forward: self.x_forward.clone(),
587 x_backward: self.x_backward.clone(),
588 a: self.a,
589 b: self.b,
590 }
591 }
592
593 pub fn validate_twofloat(&self) -> bool {
595 if self.a >= self.b {
597 return false;
598 }
599
600 if self.x.len() != self.w.len() {
602 return false;
603 }
604
605 if self.x.len() != self.x_forward.len() || self.x.len() != self.x_backward.len() {
606 return false;
607 }
608
609 for &xi in self.x.iter() {
611 if xi < self.a || xi > self.b {
612 return false;
613 }
614 }
615
616 for i in 1..self.x.len() {
618 if self.x[i] <= self.x[i - 1] {
619 return false;
620 }
621 }
622
623 for i in 0..self.x.len() {
625 let expected_forward = self.x[i] - self.a;
626 let expected_backward = self.b - self.x[i];
627
628 if (self.x_forward[i] - expected_forward).abs() > crate::Df64::epsilon() {
629 return false;
630 }
631 if (self.x_backward[i] - expected_backward).abs() > crate::Df64::epsilon() {
632 return false;
633 }
634 }
635
636 true
637 }
638}
639
640fn gauss_legendre_nodes_weights<T>(n: usize) -> (Vec<T>, Vec<T>)
645where
646 T: CustomNumeric + Copy + Debug + std::fmt::Display + 'static,
647{
648 if n == 0 {
649 return (Vec::new(), Vec::new());
650 }
651
652 if n == 1 {
653 return (
654 vec![<T as CustomNumeric>::from_f64_unchecked(0.0)],
655 vec![<T as CustomNumeric>::from_f64_unchecked(2.0)],
656 );
657 }
658
659 let mut x = Vec::with_capacity(n);
660 let mut w = Vec::with_capacity(n);
661
662 let m = n.div_ceil(2);
664
665 let pi = T::pi();
667
668 for i in 0..m {
669 let i_val = <T as CustomNumeric>::from_f64_unchecked(i as f64);
671 let n_val = <T as CustomNumeric>::from_f64_unchecked(n as f64);
672 let three_quarters = <T as CustomNumeric>::from_f64_unchecked(0.75);
673 let half = <T as CustomNumeric>::from_f64_unchecked(0.5);
674
675 let mut z = (pi * (i_val + three_quarters) / (n_val + half)).cos();
677
678 for _ in 0..10 {
680 let (p0, p1) = legendre_polynomial_and_derivative(n, z);
681 if p0.abs_as_same_type() < T::epsilon() {
682 break;
683 }
684 z = z - p0 / p1;
685 }
686
687 let two = <T as CustomNumeric>::from_f64_unchecked(2.0);
689 let one = <T as CustomNumeric>::from_f64_unchecked(1.0);
690 let (_, p1) = legendre_polynomial_and_derivative(n, z);
691 let weight = two / ((one - z * z) * p1 * p1);
692
693 x.push(-z);
694 w.push(weight);
695
696 if i != n - 1 - i {
697 x.push(z);
698 w.push(weight);
699 }
700 }
701
702 let mut indices: Vec<usize> = (0..n).collect();
704 indices.sort_by(|&a, &b| x[a].partial_cmp(&x[b]).unwrap());
705
706 let sorted_x: Vec<T> = indices.iter().map(|&i| x[i]).collect();
707 let sorted_w: Vec<T> = indices.iter().map(|&i| w[i]).collect();
708
709 (sorted_x, sorted_w)
710}
711
712fn legendre_polynomial_and_derivative<T>(n: usize, x: T) -> (T, T)
714where
715 T: CustomNumeric + Copy + Debug + std::fmt::Display + 'static,
716{
717 if n == 0 {
718 return (
719 <T as CustomNumeric>::from_f64_unchecked(1.0),
720 <T as CustomNumeric>::from_f64_unchecked(0.0),
721 );
722 }
723
724 if n == 1 {
725 return (x, <T as CustomNumeric>::from_f64_unchecked(1.0));
726 }
727
728 let mut p0 = <T as CustomNumeric>::from_f64_unchecked(1.0);
729 let mut p1 = x;
730 let mut dp0 = <T as CustomNumeric>::from_f64_unchecked(0.0);
731 let mut dp1 = <T as CustomNumeric>::from_f64_unchecked(1.0);
732
733 for k in 2..=n {
734 let k_f = <T as CustomNumeric>::from_f64_unchecked(k as f64);
735 let k1_f = <T as CustomNumeric>::from_f64_unchecked((k - 1) as f64);
736 let _k2_f = <T as CustomNumeric>::from_f64_unchecked((k - 2) as f64);
737
738 let p2 = ((<T as CustomNumeric>::from_f64_unchecked(2.0) * k1_f
739 + <T as CustomNumeric>::from_f64_unchecked(1.0))
740 * x
741 * p1
742 - k1_f * p0)
743 / k_f;
744 let dp2 = ((<T as CustomNumeric>::from_f64_unchecked(2.0) * k1_f
745 + <T as CustomNumeric>::from_f64_unchecked(1.0))
746 * (p1 + x * dp1)
747 - k1_f * dp0)
748 / k_f;
749
750 p0 = p1;
751 p1 = p2;
752 dp0 = dp1;
753 dp1 = dp2;
754 }
755
756 (p1, dp1)
757}
758
759pub fn legendre<T>(n: usize) -> Rule<T>
767where
768 T: CustomNumeric + Copy + Debug + std::fmt::Display + 'static,
769{
770 if n == 0 {
771 return Rule::empty();
772 }
773
774 let (x, w) = gauss_legendre_nodes_weights(n);
775
776 Rule::from_vectors(
777 x,
778 w,
779 <T as CustomNumeric>::from_f64_unchecked(-1.0),
780 <T as CustomNumeric>::from_f64_unchecked(1.0),
781 )
782 .expect("the Gauss-Legendre nodes and weights have the same length")
783}
784
785fn gauss_legendre_nodes_weights_custom<T>(n: usize) -> (Vec<T>, Vec<T>)
787where
788 T: CustomNumeric,
789{
790 if n == 0 {
791 return (Vec::new(), Vec::new());
792 }
793
794 if n == 1 {
795 return (
796 vec![<T as CustomNumeric>::from_f64_unchecked(0.0)],
797 vec![<T as CustomNumeric>::from_f64_unchecked(2.0)],
798 );
799 }
800
801 let mut x = Vec::with_capacity(n);
802 let mut w = Vec::with_capacity(n);
803
804 let m = n.div_ceil(2);
806 let pi = <T as CustomNumeric>::from_f64_unchecked(std::f64::consts::PI);
807
808 for i in 0..m {
809 let mut z = (pi * <T as CustomNumeric>::from_f64_unchecked(i as f64 + 0.75)
814 / <T as CustomNumeric>::from_f64_unchecked(n as f64 + 0.5))
815 .cos();
816
817 for _ in 0..10 {
819 let (p0, p1) = legendre_polynomial_and_derivative_custom(n, z);
820 if p0.abs_as_same_type() < T::epsilon() {
821 break;
822 }
823 z = z - p0 / p1;
824 }
825
826 let (_, p1) = legendre_polynomial_and_derivative_custom(n, z);
828 let weight = <T as CustomNumeric>::from_f64_unchecked(2.0)
829 / ((<T as CustomNumeric>::from_f64_unchecked(1.0) - z * z) * p1 * p1);
830
831 x.push(-z);
832 w.push(weight);
833
834 if i != n - 1 - i {
835 x.push(z);
836 w.push(weight);
837 }
838 }
839
840 let mut indices: Vec<usize> = (0..n).collect();
842 indices.sort_by(|&a, &b| x[a].partial_cmp(&x[b]).unwrap());
843
844 let sorted_x: Vec<T> = indices.iter().map(|&i| x[i]).collect();
845 let sorted_w: Vec<T> = indices.iter().map(|&i| w[i]).collect();
846
847 (sorted_x, sorted_w)
848}
849
850fn legendre_polynomial_and_derivative_custom<T>(n: usize, x: T) -> (T, T)
852where
853 T: CustomNumeric,
854{
855 if n == 0 {
856 return (
857 <T as CustomNumeric>::from_f64_unchecked(1.0),
858 <T as CustomNumeric>::from_f64_unchecked(0.0),
859 );
860 }
861
862 if n == 1 {
863 return (x, <T as CustomNumeric>::from_f64_unchecked(1.0));
864 }
865
866 let mut p0 = <T as CustomNumeric>::from_f64_unchecked(1.0);
867 let mut p1 = x;
868 let mut dp0 = <T as CustomNumeric>::from_f64_unchecked(0.0);
869 let mut dp1 = <T as CustomNumeric>::from_f64_unchecked(1.0);
870
871 for k in 2..=n {
872 let k_f = <T as CustomNumeric>::from_f64_unchecked(k as f64);
873 let k1_f = <T as CustomNumeric>::from_f64_unchecked((k - 1) as f64);
874 let _k2_f = <T as CustomNumeric>::from_f64_unchecked((k - 2) as f64);
875
876 let two = <T as CustomNumeric>::from_f64_unchecked(2.0);
877 let one = <T as CustomNumeric>::from_f64_unchecked(1.0);
878
879 let p2 = ((two * k1_f + one) * x * p1 - k1_f * p0) / k_f;
880 let dp2 = ((two * k1_f + one) * (p1 + x * dp1) - k1_f * dp0) / k_f;
881
882 p0 = p1;
883 p1 = p2;
884 dp0 = dp1;
885 dp1 = dp2;
886 }
887
888 (p1, dp1)
889}
890
891pub fn legendre_custom<T>(n: usize) -> Rule<T>
893where
894 T: CustomNumeric,
895{
896 if n == 0 {
897 return Rule::new_custom(
898 vec![],
899 vec![],
900 <T as CustomNumeric>::from_f64_unchecked(-1.0),
901 <T as CustomNumeric>::from_f64_unchecked(1.0),
902 )
903 .expect("the Gauss-Legendre nodes and weights have the same length");
904 }
905
906 let (x, w) = gauss_legendre_nodes_weights_custom(n);
907
908 Rule::from_vectors_custom(
909 x,
910 w,
911 <T as CustomNumeric>::from_f64_unchecked(-1.0),
912 <T as CustomNumeric>::from_f64_unchecked(1.0),
913 )
914 .expect("the Gauss-Legendre nodes and weights have the same length")
915}
916
917pub fn legendre_twofloat(n: usize) -> Rule<crate::Df64> {
919 if n == 0 {
920 return Rule::new_twofloat(
921 vec![],
922 vec![],
923 <crate::Df64 as CustomNumeric>::from_f64_unchecked(-1.0),
924 <crate::Df64 as CustomNumeric>::from_f64_unchecked(1.0),
925 )
926 .expect("the Gauss-Legendre nodes and weights have the same length");
927 }
928
929 let mut x: Vec<crate::Df64> = vec![crate::Df64::ZERO; n];
930 let mut w: Vec<crate::Df64> = vec![crate::Df64::ZERO; n];
931 xprec::gauss::gauss_legendre(&mut x, &mut w);
932
933 Rule::from_vectors_twofloat(
934 x,
935 w,
936 <crate::Df64 as CustomNumeric>::from_f64_unchecked(-1.0),
937 <crate::Df64 as CustomNumeric>::from_f64_unchecked(1.0),
938 )
939 .expect("the Gauss-Legendre nodes and weights have the same length")
940}
941
942pub fn legendre_vandermonde<T: CustomNumeric>(x: &[T], degree: usize) -> Mat<T> {
951 let n = x.len();
952 let mut v = Mat::<T>::from_elem([n, degree + 1], T::zero());
953
954 for i in 0..n {
956 v[[i, 0]] = T::from_f64_unchecked(1.0);
957 }
958
959 if degree > 0 {
961 for i in 0..n {
962 v[[i, 1]] = x[i];
963 }
964 }
965
966 for j in 2..=degree {
968 for i in 0..n {
969 let n_f64 = j as f64;
970 let term1 = T::from_f64_unchecked(2.0 * n_f64 - 1.0) * x[i] * v[[i, j - 1]];
971 let term2 = T::from_f64_unchecked(n_f64 - 1.0) * v[[i, j - 2]];
972 v[[i, j]] = (term1 - term2) / T::from_f64_unchecked(n_f64);
973 }
974 }
975
976 v
977}
978
979pub fn legendre_generic<T: CustomNumeric + 'static>(n: usize) -> Rule<T> {
981 if std::any::TypeId::of::<T>() == std::any::TypeId::of::<f64>() {
982 let rule_f64 = legendre::<f64>(n);
984 Rule::new(
985 rule_f64
986 .x
987 .iter()
988 .map(|&x| T::from_f64_unchecked(x))
989 .collect(),
990 rule_f64
991 .w
992 .iter()
993 .map(|&w| T::from_f64_unchecked(w))
994 .collect(),
995 T::from_f64_unchecked(rule_f64.a),
996 T::from_f64_unchecked(rule_f64.b),
997 )
998 .expect("the Gauss-Legendre nodes and weights have the same length")
999 } else {
1000 let rule_tf = legendre_twofloat(n);
1002 Rule::new(
1003 rule_tf.x.iter().map(|&x| T::convert_from(x)).collect(),
1004 rule_tf.w.iter().map(|&w| T::convert_from(w)).collect(),
1005 T::from_f64_unchecked(rule_tf.a.into()),
1006 T::from_f64_unchecked(rule_tf.b.into()),
1007 )
1008 .expect("the Gauss-Legendre nodes and weights have the same length")
1009 }
1010}
1011
1012#[cfg(test)]
1013#[path = "gauss_tests.rs"]
1014mod tests;