1#[allow(unused_imports)] use crate::{
7 SPIR_COMPUTATION_SUCCESS, SPIR_INTERNAL_ERROR, SPIR_ORDER_COLUMN_MAJOR, SPIR_ORDER_ROW_MAJOR,
8 SPIR_TWORK_FLOAT64, SPIR_TWORK_FLOAT64X2,
9};
10#[allow(unused_imports)]
11use mdarray::Shape;
12use sparse_ir::numeric::CustomNumeric; pub fn is_debug_enabled() -> bool {
18 std::env::var("SPARSEIR_DEBUG").is_ok()
19}
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub enum MemoryOrder {
24 RowMajor, ColumnMajor, }
27
28impl MemoryOrder {
29 pub fn from_c_int(order: libc::c_int) -> Result<Self, ()> {
31 match order {
32 SPIR_ORDER_ROW_MAJOR => Ok(Self::RowMajor),
33 SPIR_ORDER_COLUMN_MAJOR => Ok(Self::ColumnMajor),
34 _ => Err(()),
35 }
36 }
37}
38
39pub fn convert_dims_for_row_major(
62 dims: &[usize],
63 target_dim: usize,
64 order: MemoryOrder,
65) -> (Vec<usize>, usize) {
66 match order {
67 MemoryOrder::RowMajor => {
68 (dims.to_vec(), target_dim)
70 }
71 MemoryOrder::ColumnMajor => {
72 let mut rev_dims = dims.to_vec();
75 rev_dims.reverse();
76 let rev_target_dim = dims.len() - 1 - target_dim;
77 (rev_dims, rev_target_dim)
78 }
79 }
80}
81
82pub(crate) unsafe fn _read_tensor_nd_row_major<T: Copy>(
97 ptr: *const T,
98 dims: &[usize],
99) -> sparse_ir::Tensor<T, sparse_ir::DynRank> {
100 assert!(!dims.is_empty(), "dims must not be empty");
101 let total: usize = dims.iter().product();
102
103 let slice = unsafe { std::slice::from_raw_parts(ptr, total) };
105 let data: Vec<T> = slice.to_vec();
106
107 let flat = sparse_ir::Tensor::<T, (usize,)>::from(data);
109 flat.into_dyn().reshape(dims).to_tensor()
110}
111
112pub(crate) unsafe fn _read_tensor_nd_column_major<T: Copy>(
128 ptr: *const T,
129 dims: &[usize],
130) -> sparse_ir::Tensor<T, sparse_ir::DynRank> {
131 assert!(!dims.is_empty(), "dims must not be empty");
132
133 let mut rev_dims = dims.to_vec();
135 rev_dims.reverse();
136 let tmp = unsafe { _read_tensor_nd_row_major(ptr, &rev_dims) };
137
138 let rank = dims.len();
142 let perm: Vec<usize> = (0..rank).rev().collect();
143
144 use mdarray::Slice;
146 (&tmp as &Slice<T, sparse_ir::DynRank>)
147 .permute(&perm[..])
148 .to_tensor()
149}
150
151pub(crate) unsafe fn read_tensor_nd<T: Copy>(
168 ptr: *const T,
169 dims: &[usize],
170 order: MemoryOrder,
171) -> sparse_ir::Tensor<T, sparse_ir::DynRank> {
172 match order {
173 MemoryOrder::RowMajor => unsafe { _read_tensor_nd_row_major(ptr, dims) },
174 MemoryOrder::ColumnMajor => unsafe { _read_tensor_nd_column_major(ptr, dims) },
175 }
176}
177
178pub(crate) unsafe fn copy_tensor_to_c_array<T: Copy>(
192 tensor: sparse_ir::Tensor<T, sparse_ir::DynRank>,
193 out: *mut T,
194 order: MemoryOrder,
195) {
196 let total = tensor.len();
197
198 let flat = match order {
200 MemoryOrder::RowMajor => {
201 tensor.into_dyn().reshape(&[total]).to_tensor()
203 }
204 MemoryOrder::ColumnMajor => {
205 use mdarray::Slice;
208 let rank = tensor.rank();
209 let perm: Vec<usize> = (0..rank).rev().collect();
210 let permuted = (&tensor as &Slice<T, sparse_ir::DynRank>)
211 .permute(&perm[..])
212 .to_tensor();
213 permuted.into_dyn().reshape(&[total]).to_tensor()
214 }
215 };
216
217 for i in 0..total {
218 unsafe {
219 *out.add(i) = flat[i];
220 }
221 }
222}
223
224pub(crate) fn build_output_dims(
226 input_dims: &[usize],
227 target_dim: usize,
228 new_size: usize,
229) -> Vec<usize> {
230 let mut out_dims = input_dims.to_vec();
231 out_dims[target_dim] = new_size;
232 out_dims
233}
234
235pub(crate) unsafe fn create_dview_from_ptr<'a, T>(
244 ptr: *const T,
245 dims: &[usize],
246) -> mdarray::View<'a, T, sparse_ir::DynRank, mdarray::Dense> {
247 use mdarray::Shape;
248 let shape = sparse_ir::DynRank::from_dims(dims);
249 let mapping = mdarray::DenseMapping::new(shape);
250 unsafe { mdarray::View::new_unchecked(ptr, mapping) }
251}
252
253pub(crate) unsafe fn create_dviewmut_from_ptr<'a, T>(
263 ptr: *mut T,
264 dims: &[usize],
265) -> mdarray::ViewMut<'a, T, sparse_ir::DynRank> {
266 use mdarray::Shape;
267 let shape = sparse_ir::DynRank::from_dims(dims);
268 let mapping = mdarray::DenseMapping::new(shape);
269 unsafe { mdarray::ViewMut::new_unchecked(ptr, mapping) }
270}
271
272#[unsafe(no_mangle)]
287pub extern "C" fn spir_choose_working_type(epsilon: f64) -> libc::c_int {
288 if epsilon.is_nan() || epsilon < 1e-8 {
289 SPIR_TWORK_FLOAT64X2
290 } else {
291 SPIR_TWORK_FLOAT64
292 }
293}
294
295#[unsafe(no_mangle)]
315pub extern "C" fn spir_gauss_legendre_rule_piecewise_double(
316 n: libc::c_int,
317 segments: *const f64,
318 n_segments: libc::c_int,
319 x: *mut f64,
320 w: *mut f64,
321 status: *mut crate::StatusCode,
322) -> crate::StatusCode {
323 use crate::{SPIR_COMPUTATION_SUCCESS, SPIR_INTERNAL_ERROR, SPIR_INVALID_ARGUMENT};
324 use sparse_ir::legendre;
325 use std::panic::catch_unwind;
326
327 if status.is_null() {
328 return SPIR_INVALID_ARGUMENT;
329 }
330
331 if segments.is_null() || x.is_null() || w.is_null() {
332 unsafe {
333 *status = SPIR_INVALID_ARGUMENT;
334 }
335 return SPIR_INVALID_ARGUMENT;
336 }
337
338 if n < 1 || n_segments < 1 {
339 unsafe {
340 *status = SPIR_INVALID_ARGUMENT;
341 }
342 return SPIR_INVALID_ARGUMENT;
343 }
344
345 let result = catch_unwind(|| {
346 let segments_slice =
348 unsafe { std::slice::from_raw_parts(segments, (n_segments + 1) as usize) };
349 let segs_vec = segments_slice.to_vec();
350
351 for i in 1..segs_vec.len() {
353 if segs_vec[i] <= segs_vec[i - 1] {
354 unsafe {
355 *status = SPIR_INVALID_ARGUMENT;
356 }
357 return SPIR_INVALID_ARGUMENT;
358 }
359 }
360
361 let rule_dd = legendre::<sparse_ir::Df64>(n as usize);
363 let rule = sparse_ir::gauss::Rule::from_vectors(
364 rule_dd.x.iter().map(|&x| x.to_f64()).collect(),
365 rule_dd.w.iter().map(|&w| w.to_f64()).collect(),
366 rule_dd.a.to_f64(),
367 rule_dd.b.to_f64(),
368 );
369
370 let piecewise_rule = rule.piecewise(&segs_vec);
372
373 for i in 0..piecewise_rule.x.len() {
375 unsafe {
376 *x.add(i) = piecewise_rule.x[i];
377 *w.add(i) = piecewise_rule.w[i];
378 }
379 }
380
381 unsafe {
382 *status = SPIR_COMPUTATION_SUCCESS;
383 }
384 SPIR_COMPUTATION_SUCCESS
385 });
386
387 result.unwrap_or_else(|_| {
388 unsafe {
389 *status = SPIR_INTERNAL_ERROR;
390 }
391 SPIR_INTERNAL_ERROR
392 })
393}
394
395#[unsafe(no_mangle)]
421pub extern "C" fn spir_gauss_legendre_rule_piecewise_ddouble(
422 n: libc::c_int,
423 segments: *const f64,
424 n_segments: libc::c_int,
425 x_high: *mut f64,
426 x_low: *mut f64,
427 w_high: *mut f64,
428 w_low: *mut f64,
429 status: *mut crate::StatusCode,
430) -> crate::StatusCode {
431 use crate::{SPIR_COMPUTATION_SUCCESS, SPIR_INTERNAL_ERROR, SPIR_INVALID_ARGUMENT};
432 use sparse_ir::legendre;
433 use std::panic::catch_unwind;
434
435 if status.is_null() {
436 return SPIR_INVALID_ARGUMENT;
437 }
438
439 if segments.is_null()
440 || x_high.is_null()
441 || x_low.is_null()
442 || w_high.is_null()
443 || w_low.is_null()
444 {
445 unsafe {
446 *status = SPIR_INVALID_ARGUMENT;
447 }
448 return SPIR_INVALID_ARGUMENT;
449 }
450
451 if n < 1 || n_segments < 1 {
452 unsafe {
453 *status = SPIR_INVALID_ARGUMENT;
454 }
455 return SPIR_INVALID_ARGUMENT;
456 }
457
458 let result = catch_unwind(|| {
459 let segments_slice =
461 unsafe { std::slice::from_raw_parts(segments, (n_segments + 1) as usize) };
462 let segs_vec: Vec<sparse_ir::Df64> = segments_slice
463 .iter()
464 .map(|&x| sparse_ir::Df64::new(x))
465 .collect();
466
467 for i in 1..segs_vec.len() {
469 if segs_vec[i] <= segs_vec[i - 1] {
470 unsafe {
471 *status = SPIR_INVALID_ARGUMENT;
472 }
473 return SPIR_INVALID_ARGUMENT;
474 }
475 }
476
477 let rule_dd = legendre::<sparse_ir::Df64>(n as usize);
479
480 let piecewise_rule = rule_dd.piecewise(&segs_vec);
482
483 for i in 0..piecewise_rule.x.len() {
485 unsafe {
486 *x_high.add(i) = piecewise_rule.x[i].hi();
487 *x_low.add(i) = piecewise_rule.x[i].lo();
488 *w_high.add(i) = piecewise_rule.w[i].hi();
489 *w_low.add(i) = piecewise_rule.w[i].lo();
490 }
491 }
492
493 unsafe {
494 *status = SPIR_COMPUTATION_SUCCESS;
495 }
496 SPIR_COMPUTATION_SUCCESS
497 });
498
499 result.unwrap_or_else(|_| {
500 unsafe {
501 *status = SPIR_INTERNAL_ERROR;
502 }
503 SPIR_INTERNAL_ERROR
504 })
505}
506
507#[cfg(test)]
508mod tests {
509 use super::*;
510
511 #[test]
512 fn test_memory_order_conversion() {
513 assert_eq!(
514 MemoryOrder::from_c_int(SPIR_ORDER_ROW_MAJOR),
515 Ok(MemoryOrder::RowMajor)
516 );
517 assert_eq!(
518 MemoryOrder::from_c_int(SPIR_ORDER_COLUMN_MAJOR),
519 Ok(MemoryOrder::ColumnMajor)
520 );
521 assert_eq!(MemoryOrder::from_c_int(99), Err(()));
522 }
523
524 #[test]
525 fn test_choose_working_type() {
526 {
528 let twork = spir_choose_working_type(1e-6);
529 assert_eq!(twork, SPIR_TWORK_FLOAT64);
530 }
531
532 {
533 let twork = spir_choose_working_type(1e-8);
534 assert_eq!(twork, SPIR_TWORK_FLOAT64);
535 }
536
537 {
539 let twork = spir_choose_working_type(1e-10);
540 assert_eq!(twork, SPIR_TWORK_FLOAT64X2);
541 }
542
543 {
544 let twork = spir_choose_working_type(1e-15);
545 assert_eq!(twork, SPIR_TWORK_FLOAT64X2);
546 }
547
548 {
550 let twork = spir_choose_working_type(f64::NAN);
551 assert_eq!(twork, SPIR_TWORK_FLOAT64X2);
552 }
553
554 {
556 let twork = spir_choose_working_type(1e-8);
557 assert_eq!(twork, SPIR_TWORK_FLOAT64);
558 }
559
560 {
562 let twork = spir_choose_working_type(0.99e-8);
563 assert_eq!(twork, SPIR_TWORK_FLOAT64X2);
564 }
565 }
566
567 #[test]
568 fn test_gauss_legendre_rule_piecewise_double() {
569 {
571 let n = 5;
572 let segments = [-1.0, 1.0];
573 let n_segments = 1;
574 let mut x = vec![0.0; n as usize];
575 let mut w = vec![0.0; n as usize];
576 let mut status = SPIR_INTERNAL_ERROR;
577
578 let result = spir_gauss_legendre_rule_piecewise_double(
579 n,
580 segments.as_ptr(),
581 n_segments,
582 x.as_mut_ptr(),
583 w.as_mut_ptr(),
584 &mut status,
585 );
586 assert_eq!(result, SPIR_COMPUTATION_SUCCESS);
587 assert_eq!(status, SPIR_COMPUTATION_SUCCESS);
588
589 assert!(x[0] >= -1.0);
592 assert!(x[(n - 1) as usize] <= 1.0);
593 for i in 1..(n as usize) {
594 assert!(x[i] > x[i - 1]);
595 }
596
597 for i in 0..(n as usize) {
599 assert!(w[i] > 0.0);
600 }
601
602 let weight_sum: f64 = w.iter().sum();
604 assert!((weight_sum - 2.0).abs() < 1e-10);
605 }
606
607 {
609 let n = 3;
610 let segments = [-1.0, 0.0, 1.0];
611 let n_segments = 2;
612 let mut x = vec![0.0; (n * n_segments) as usize];
613 let mut w = vec![0.0; (n * n_segments) as usize];
614 let mut status = SPIR_INTERNAL_ERROR;
615
616 let result = spir_gauss_legendre_rule_piecewise_double(
617 n,
618 segments.as_ptr(),
619 n_segments,
620 x.as_mut_ptr(),
621 w.as_mut_ptr(),
622 &mut status,
623 );
624 assert_eq!(result, SPIR_COMPUTATION_SUCCESS);
625 assert_eq!(status, SPIR_COMPUTATION_SUCCESS);
626
627 assert!(x[0] >= -1.0);
630 assert!(x[5] <= 1.0);
631 for i in 1..6 {
632 assert!(x[i] > x[i - 1]);
633 }
634
635 for i in 0..6 {
637 assert!(w[i] > 0.0);
638 }
639
640 let weight_sum: f64 = w.iter().sum();
642 assert!((weight_sum - 2.0).abs() < 1e-10);
643 }
644
645 {
647 let mut status = SPIR_INTERNAL_ERROR;
648 let result = spir_gauss_legendre_rule_piecewise_double(
649 5,
650 std::ptr::null(),
651 1,
652 std::ptr::null_mut(),
653 std::ptr::null_mut(),
654 &mut status,
655 );
656 assert_ne!(result, SPIR_COMPUTATION_SUCCESS);
657 }
658
659 {
660 let segments = [-1.0, 1.0];
661 let mut x = vec![0.0; 5];
662 let mut w = vec![0.0; 5];
663 let mut status = SPIR_INTERNAL_ERROR;
664 let result = spir_gauss_legendre_rule_piecewise_double(
665 0,
666 segments.as_ptr(),
667 1,
668 x.as_mut_ptr(),
669 w.as_mut_ptr(),
670 &mut status,
671 );
672 assert_ne!(result, SPIR_COMPUTATION_SUCCESS);
673 }
674
675 {
676 let segments = [1.0, -1.0]; let mut x = vec![0.0; 5];
678 let mut w = vec![0.0; 5];
679 let mut status = SPIR_INTERNAL_ERROR;
680 let result = spir_gauss_legendre_rule_piecewise_double(
681 5,
682 segments.as_ptr(),
683 1,
684 x.as_mut_ptr(),
685 w.as_mut_ptr(),
686 &mut status,
687 );
688 assert_ne!(result, SPIR_COMPUTATION_SUCCESS);
689 }
690 }
691
692 #[test]
693 fn test_read_tensor_nd_row_major() {
694 use num_complex::Complex64;
695
696 {
698 let data = vec![
703 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0,
704 ];
705 let tensor = unsafe { _read_tensor_nd_row_major(data.as_ptr(), &[3, 4]) };
706
707 let shape_dims = tensor.shape().with_dims(|dims| dims.to_vec());
708 assert_eq!(shape_dims, &[3, 4]);
709 assert_eq!(tensor[[0, 0]], 1.0);
710 assert_eq!(tensor[[0, 3]], 4.0);
711 assert_eq!(tensor[[1, 0]], 5.0);
712 assert_eq!(tensor[[2, 3]], 12.0);
713 }
714
715 {
717 let data: Vec<f64> = (1..=24).map(|x| x as f64).collect();
718 let tensor = unsafe { _read_tensor_nd_row_major(data.as_ptr(), &[2, 3, 4]) };
719
720 let shape_dims = tensor.shape().with_dims(|dims| dims.to_vec());
721 assert_eq!(shape_dims, &[2, 3, 4]);
722 assert_eq!(tensor[[0, 0, 0]], 1.0);
723 assert_eq!(tensor[[0, 0, 3]], 4.0);
724 assert_eq!(tensor[[0, 1, 0]], 5.0);
725 assert_eq!(tensor[[1, 2, 3]], 24.0);
726 }
727
728 {
730 let data = vec![
731 Complex64::new(1.0, 2.0),
732 Complex64::new(3.0, 4.0),
733 Complex64::new(5.0, 6.0),
734 Complex64::new(7.0, 8.0),
735 ];
736 let tensor = unsafe { _read_tensor_nd_row_major(data.as_ptr(), &[2, 2]) };
737
738 let shape_dims = tensor.shape().with_dims(|dims| dims.to_vec());
739 assert_eq!(shape_dims, &[2, 2]);
740 assert_eq!(tensor[[0, 0]], Complex64::new(1.0, 2.0));
741 assert_eq!(tensor[[1, 1]], Complex64::new(7.0, 8.0));
742 }
743 }
744
745 #[test]
746 fn test_read_tensor_nd_column_major() {
747 use num_complex::Complex64;
748
749 {
756 let data = vec![
762 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0,
763 ];
764 let tensor = unsafe { _read_tensor_nd_column_major(data.as_ptr(), &[3, 4]) };
765
766 let shape_dims = tensor.shape().with_dims(|dims| dims.to_vec());
767 assert_eq!(shape_dims, &[3, 4]);
768 assert_eq!(tensor[[0, 0]], 1.0);
773 assert_eq!(tensor[[0, 1]], 4.0);
774 assert_eq!(tensor[[0, 3]], 10.0);
775 assert_eq!(tensor[[1, 0]], 2.0);
776 assert_eq!(tensor[[2, 3]], 12.0);
777 }
778
779 {
782 let data: Vec<f64> = (1..=24).map(|x| x as f64).collect();
786 let tensor = unsafe { _read_tensor_nd_column_major(data.as_ptr(), &[2, 3, 4]) };
787
788 let shape_dims = tensor.shape().with_dims(|dims| dims.to_vec());
789 assert_eq!(shape_dims, &[2, 3, 4]);
790 assert_eq!(tensor[[0, 0, 0]], 1.0);
792 assert_eq!(tensor[[1, 0, 0]], 2.0);
793 assert_eq!(tensor[[0, 1, 0]], 3.0);
794 }
795
796 {
798 let data = vec![
800 Complex64::new(1.0, 2.0),
801 Complex64::new(3.0, 4.0),
802 Complex64::new(5.0, 6.0),
803 Complex64::new(7.0, 8.0),
804 ];
805 let tensor = unsafe { _read_tensor_nd_column_major(data.as_ptr(), &[2, 2]) };
806
807 let shape_dims = tensor.shape().with_dims(|dims| dims.to_vec());
808 assert_eq!(shape_dims, &[2, 2]);
809 assert_eq!(tensor[[0, 0]], Complex64::new(1.0, 2.0));
811 assert_eq!(tensor[[1, 0]], Complex64::new(3.0, 4.0));
812 assert_eq!(tensor[[0, 1]], Complex64::new(5.0, 6.0));
813 assert_eq!(tensor[[1, 1]], Complex64::new(7.0, 8.0));
814 }
815 }
816
817 #[test]
818 fn test_read_tensor_nd_roundtrip() {
819 let row_major_data = vec![
824 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0,
825 ];
826 let row_tensor = unsafe { _read_tensor_nd_row_major(row_major_data.as_ptr(), &[3, 4]) };
827
828 let col_major_data = vec![
832 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0,
833 ];
834 let col_tensor = unsafe { _read_tensor_nd_column_major(col_major_data.as_ptr(), &[3, 4]) };
835
836 let row_shape = row_tensor.shape().with_dims(|dims| dims.to_vec());
838 let col_shape = col_tensor.shape().with_dims(|dims| dims.to_vec());
839 assert_eq!(row_shape, col_shape);
840
841 assert_eq!(row_tensor[[0, 0]], 1.0);
845 assert_eq!(col_tensor[[0, 0]], 1.0);
846 assert_eq!(row_tensor[[0, 1]], 2.0);
847 assert_eq!(col_tensor[[0, 1]], 4.0); }
849
850 #[test]
851 fn test_gauss_legendre_rule_piecewise_ddouble() {
852 {
854 let n = 5;
855 let segments = [-1.0, 1.0];
856 let n_segments = 1;
857 let mut x_high = vec![0.0; n as usize];
858 let mut x_low = vec![0.0; n as usize];
859 let mut w_high = vec![0.0; n as usize];
860 let mut w_low = vec![0.0; n as usize];
861 let mut status = SPIR_INTERNAL_ERROR;
862
863 let result = spir_gauss_legendre_rule_piecewise_ddouble(
864 n,
865 segments.as_ptr(),
866 n_segments,
867 x_high.as_mut_ptr(),
868 x_low.as_mut_ptr(),
869 w_high.as_mut_ptr(),
870 w_low.as_mut_ptr(),
871 &mut status,
872 );
873 assert_eq!(result, SPIR_COMPUTATION_SUCCESS);
874 assert_eq!(status, SPIR_COMPUTATION_SUCCESS);
875
876 let x0 = x_high[0] + x_low[0];
879 let x_last = x_high[(n - 1) as usize] + x_low[(n - 1) as usize];
880 assert!(x0 >= -1.0);
881 assert!(x_last <= 1.0);
882 for i in 1..(n as usize) {
883 let x_val = x_high[i] + x_low[i];
884 let x_prev = x_high[i - 1] + x_low[i - 1];
885 assert!(x_val > x_prev);
886 }
887
888 let mut weight_sum = 0.0;
890 for i in 0..(n as usize) {
891 let w_val = w_high[i] + w_low[i];
892 assert!(w_val > 0.0);
893 weight_sum += w_val;
894 }
895 assert!((weight_sum - 2.0).abs() < 1e-10);
897 }
898
899 {
901 let n = 3;
902 let segments = [-1.0, 0.0, 1.0];
903 let n_segments = 2;
904 let mut x_high = vec![0.0; (n * n_segments) as usize];
905 let mut x_low = vec![0.0; (n * n_segments) as usize];
906 let mut w_high = vec![0.0; (n * n_segments) as usize];
907 let mut w_low = vec![0.0; (n * n_segments) as usize];
908 let mut status = SPIR_INTERNAL_ERROR;
909
910 let result = spir_gauss_legendre_rule_piecewise_ddouble(
911 n,
912 segments.as_ptr(),
913 n_segments,
914 x_high.as_mut_ptr(),
915 x_low.as_mut_ptr(),
916 w_high.as_mut_ptr(),
917 w_low.as_mut_ptr(),
918 &mut status,
919 );
920 assert_eq!(result, SPIR_COMPUTATION_SUCCESS);
921 assert_eq!(status, SPIR_COMPUTATION_SUCCESS);
922
923 for i in 1..6 {
925 let x_val = x_high[i] + x_low[i];
926 let x_prev = x_high[i - 1] + x_low[i - 1];
927 assert!(x_val > x_prev);
928 }
929
930 let mut weight_sum = 0.0;
932 for i in 0..6 {
933 let w_val = w_high[i] + w_low[i];
934 weight_sum += w_val;
935 }
936 assert!((weight_sum - 2.0).abs() < 1e-10);
937 }
938
939 {
941 let mut status = SPIR_INTERNAL_ERROR;
942 let result = spir_gauss_legendre_rule_piecewise_ddouble(
943 5,
944 std::ptr::null(),
945 1,
946 std::ptr::null_mut(),
947 std::ptr::null_mut(),
948 std::ptr::null_mut(),
949 std::ptr::null_mut(),
950 &mut status,
951 );
952 assert_ne!(result, SPIR_COMPUTATION_SUCCESS);
953 }
954 }
955}