1extern crate libc;
71use libc::{c_char, c_double, c_int, c_longlong, c_void};
72use std::ffi::CString;
73use std::ptr;
74use std::slice;
75
76pub enum CubaVerbosity {
82 Silent = 0,
83 Progress = 1,
84 Input = 2,
85 Subregions = 3,
86}
87
88macro_rules! gen_setter {
89 ($setr:ident, $r:ident, $t: ty) => {
90 pub fn $setr(&mut self, $r: $t) -> &mut Self {
91 self.$r = $r;
92 self
93 }
94 };
95}
96
97#[link(name = "cuba")]
98extern "C" {
99 fn cubacores(n: *const c_int, p: *const c_int);
100
101 fn llVegas(
102 ndim: c_int,
103 ncomp: c_int,
104 integrand: Option<VegasIntegrandC>,
105 userdata: *mut c_void,
106 nvec: c_longlong,
107 epsrel: c_double,
108 epsabs: c_double,
109 flags: c_int,
110 seed: c_int,
111 mineval: c_longlong,
112 maxeval: c_longlong,
113 nstart: c_longlong,
114 nincrease: c_longlong,
115 nbatch: c_longlong,
116 gridno: c_int,
117 statefile: *const c_char,
118 spin: *mut c_void,
119 neval: *mut c_longlong,
120 fail: *mut c_int,
121 integral: *mut c_double,
122 error: *mut c_double,
123 prob: *mut c_double,
124 );
125
126 fn llSuave(
127 ndim: c_int,
128 ncomp: c_int,
129 integrand: Option<SuaveIntegrandC>,
130 userdata: *mut c_void,
131 nvec: c_longlong,
132 epsrel: c_double,
133 epsabs: c_double,
134 flags: c_int,
135 seed: c_int,
136 mineval: c_longlong,
137 maxeval: c_longlong,
138 nnew: c_longlong,
139 nmin: c_longlong,
140 flatness: c_double,
141 statefile: *const c_char,
142 spin: *mut c_void,
143 nregions: *mut c_int,
144 neval: *mut c_longlong,
145 fail: *mut c_int,
146 integral: *mut c_double,
147 error: *mut c_double,
148 prob: *mut c_double,
149 );
150
151 fn llDivonne(
152 ndim: c_int,
153 ncomp: c_int,
154 integrand: Option<DivonneIntegrandC>,
155 userdata: *mut c_void,
156 nvec: c_longlong,
157 epsrel: c_double,
158 epsabs: c_double,
159 flags: c_int,
160 seed: c_int,
161 mineval: c_longlong,
162 maxeval: c_longlong,
163 key1: c_int,
164 key2: c_int,
165 key3: c_int,
166 maxpass: c_int,
167 border: c_double,
168 maxchisq: c_double,
169 mindeviation: c_double,
170 ngiven: c_longlong,
171 lxdgiven: c_int,
172 xgiven: *const c_double,
173 nextra: c_longlong,
174 peakfinder: Option<PeakfinderC>,
175 statefile: *const c_char,
176 spin: *mut c_void,
177 nregions: *mut c_int,
178 neval: *mut c_longlong,
179 fail: *mut c_int,
180 integral: *mut c_double,
181 error: *mut c_double,
182 prob: *mut c_double,
183 );
184
185 fn llCuhre(
186 ndim: c_int,
187 ncomp: c_int,
188 integrand: Option<CuhreIntegrandC>,
189 userdata: *mut c_void,
190 nvec: c_longlong,
191 epsrel: c_double,
192 epsabs: c_double,
193 flags: c_int,
194 mineval: c_longlong,
195 maxeval: c_longlong,
196 key: c_int,
197 statefile: *const c_char,
198 spin: *mut c_void,
199 nregions: *mut c_int,
200 neval: *mut c_longlong,
201 fail: *mut c_int,
202 integral: *mut c_double,
203 error: *mut c_double,
204 prob: *mut c_double,
205 );
206}
207
208type VegasIntegrandC = extern "C" fn(
209 ndim: *const c_int,
210 x: *const c_double,
211 ncomp: *const c_int,
212 f: *mut c_double,
213 userdata: *mut c_void,
214 nvec: *const c_int,
215 core: *const c_int,
216 weight: *const c_double,
217 iter: *const c_int,
218) -> c_int;
219
220type SuaveIntegrandC = extern "C" fn(
221 ndim: *const c_int,
222 x: *const c_double,
223 ncomp: *const c_int,
224 f: *mut c_double,
225 userdata: *mut c_void,
226 nvec: *const c_int,
227 core: *const c_int,
228 weight: *const c_double,
229 iter: *const c_int,
230) -> c_int;
231
232type CuhreIntegrandC = extern "C" fn(
233 ndim: *const c_int,
234 x: *const c_double,
235 ncomp: *const c_int,
236 f: *mut c_double,
237 userdata: *mut c_void,
238 nvec: *const c_int,
239 core: *const c_int,
240) -> c_int;
241
242type DivonneIntegrandC = extern "C" fn(
243 ndim: *const c_int,
244 x: *const c_double,
245 ncomp: *const c_int,
246 f: *mut c_double,
247 userdata: *mut c_void,
248 nvec: *const c_int,
249 core: *const c_int,
250 phase: *const c_int,
251) -> c_int;
252
253type PeakfinderC = extern "C" fn(
254 ndim: *const c_int,
255 b: *const c_double,
256 n: *mut c_int,
257 x: *mut c_double,
258 userdata: *mut c_void,
259);
260
261pub type VegasIntegrand<T> = fn(
273 x: &[f64],
274 f: &mut [f64],
275 user_data: &mut T,
276 nvec: usize,
277 core: i32,
278 weight: &[f64],
279 iter: usize,
280) -> Result<(), &'static str>;
281
282pub type SuaveIntegrand<T> = fn(
294 x: &[f64],
295 f: &mut [f64],
296 user_data: &mut T,
297 nvec: usize,
298 core: i32,
299 weight: &[f64],
300 iter: usize,
301) -> Result<(), &'static str>;
302
303pub type CuhreIntegrand<T> = fn(
315 x: &[f64],
316 f: &mut [f64],
317 user_data: &mut T,
318 nvec: usize,
319 core: i32,
320) -> Result<(), &'static str>;
321
322pub type DivonneIntegrand<T> = fn(
334 x: &[f64],
335 f: &mut [f64],
336 user_data: &mut T,
337 nvec: usize,
338 core: i32,
339 phase: usize,
340) -> Result<(), &'static str>;
341
342#[repr(C)]
343struct VegasUserData<T> {
344 integrand: VegasIntegrand<T>,
345 user_data: T,
346}
347
348#[repr(C)]
349struct CuhreUserData<T> {
350 integrand: CuhreIntegrand<T>,
351 user_data: T,
352}
353
354#[repr(C)]
355struct SuaveUserData<T> {
356 integrand: SuaveIntegrand<T>,
357 user_data: T,
358}
359
360#[repr(C)]
361struct DivonneUserData<T> {
362 integrand: DivonneIntegrand<T>,
363 user_data: T,
364}
365
366#[derive(Debug)]
368pub struct CubaResult {
369 pub neval: i64,
370 pub fail: i32,
371 pub result: Vec<f64>,
372 pub error: Vec<f64>,
373 pub prob: Vec<f64>,
374}
375
376pub struct CubaIntegrator {
378 mineval: i64,
379 maxeval: i64,
380 nstart: i64,
381 nincrease: i64,
382 epsrel: f64,
383 epsabs: f64,
384 batch: i64,
385 cores: usize,
386 max_points_per_core: usize,
387 seed: i32,
388 use_only_last_sample: bool,
389 save_state_file: String,
390 keep_state_file: bool,
391 reset_vegas_integrator: bool,
392 key: i32,
394 key1: i32,
396 key2: i32,
397 key3: i32,
398 maxpass: i32,
399 border: f64,
400 maxchisq: f64,
401 mindeviation: f64,
402}
403
404impl CubaIntegrator {
405 pub fn new() -> CubaIntegrator {
408 CubaIntegrator {
409 mineval: 0,
410 maxeval: 50000,
411 nstart: 1000,
412 nincrease: 500,
413 epsrel: 0.001,
414 epsabs: 1e-12,
415 batch: 1000,
416 cores: 1,
417 max_points_per_core: 1000,
418 seed: 0,
419 use_only_last_sample: false,
420 save_state_file: String::new(),
421 keep_state_file: false,
422 reset_vegas_integrator: false,
423 key: 0,
424 key1: 47,
425 key2: 1,
426 key3: 1,
427 maxpass: 5,
428 border: 0.,
429 maxchisq: 10.,
430 mindeviation: 0.25,
431 }
432 }
433
434 pub fn set_cores(&mut self, cores: usize, max_points_per_core: usize) -> &mut Self {
438 self.cores = cores;
439 self.max_points_per_core = max_points_per_core;
440 unsafe {
441 cubacores(&(cores as c_int), &(max_points_per_core as c_int));
442 }
443 self
444 }
445
446 gen_setter!(set_mineval, mineval, i64);
447 gen_setter!(set_maxeval, maxeval, i64);
448 gen_setter!(set_nstart, nstart, i64);
449 gen_setter!(set_nincrease, nincrease, i64);
450 gen_setter!(set_epsrel, epsrel, f64);
451 gen_setter!(set_epsabs, epsabs, f64);
452 gen_setter!(set_batch, batch, i64);
453 gen_setter!(set_seed, seed, i32);
454 gen_setter!(set_use_only_last_sample, use_only_last_sample, bool);
455 gen_setter!(set_save_state_file, save_state_file, String);
456 gen_setter!(set_keep_state_file, keep_state_file, bool);
457 gen_setter!(set_reset_vegas_integrator, reset_vegas_integrator, bool);
458 gen_setter!(set_key, key, i32);
459 gen_setter!(set_key1, key1, i32);
460 gen_setter!(set_key2, key2, i32);
461 gen_setter!(set_key3, key3, i32);
462 gen_setter!(set_maxpass, maxpass, i32);
463 gen_setter!(set_border, border, f64);
464 gen_setter!(set_maxchisq, maxchisq, f64);
465 gen_setter!(set_mindeviation, mindeviation, f64);
466
467 extern "C" fn c_vegas_integrand<T>(
468 ndim: *const c_int,
469 x: *const c_double,
470 ncomp: *const c_int,
471 f: *mut c_double,
472 userdata: *mut c_void,
473 nvec: *const c_int,
474 core: *const c_int,
475 weight: *const c_double,
476 iter: *const c_int,
477 ) -> c_int {
478 unsafe {
479 let k: &mut VegasUserData<T> = &mut *(userdata as *mut _);
480
481 match (k.integrand)(
483 &slice::from_raw_parts(x, *ndim as usize * *nvec as usize),
484 &mut slice::from_raw_parts_mut(f, *ncomp as usize * *nvec as usize),
485 &mut k.user_data,
486 *nvec as usize,
487 *core as i32,
488 &slice::from_raw_parts(weight, *nvec as usize),
489 *iter as usize,
490 ) {
491 Ok(_) => 0,
492 Err(e) => {
493 println!("Error during integration: {}. Aborting.", e);
494 -999
495 }
496 }
497 }
498 }
499
500 extern "C" fn c_suave_integrand<T>(
501 ndim: *const c_int,
502 x: *const c_double,
503 ncomp: *const c_int,
504 f: *mut c_double,
505 userdata: *mut c_void,
506 nvec: *const c_int,
507 core: *const c_int,
508 weight: *const c_double,
509 iter: *const c_int,
510 ) -> c_int {
511 unsafe {
512 let k: &mut SuaveUserData<T> = &mut *(userdata as *mut _);
513
514 match (k.integrand)(
516 &slice::from_raw_parts(x, *ndim as usize * *nvec as usize),
517 &mut slice::from_raw_parts_mut(f, *ncomp as usize * *nvec as usize),
518 &mut k.user_data,
519 *nvec as usize,
520 *core as i32,
521 &slice::from_raw_parts(weight, *ndim as usize * *nvec as usize),
522 *iter as usize,
523 ) {
524 Ok(_) => 0,
525 Err(e) => {
526 println!("Error during integration: {}. Aborting.", e);
527 -999
528 }
529 }
530 }
531 }
532
533 extern "C" fn c_cuhre_integrand<T>(
534 ndim: *const c_int,
535 x: *const c_double,
536 ncomp: *const c_int,
537 f: *mut c_double,
538 userdata: *mut c_void,
539 nvec: *const c_int,
540 core: *const c_int,
541 ) -> c_int {
542 unsafe {
543 let k: &mut CuhreUserData<T> = &mut *(userdata as *mut _);
544
545 match (k.integrand)(
547 &slice::from_raw_parts(x, *ndim as usize * *nvec as usize),
548 &mut slice::from_raw_parts_mut(f, *ncomp as usize * *nvec as usize),
549 &mut k.user_data,
550 *nvec as usize,
551 *core as i32,
552 ) {
553 Ok(_) => 0,
554 Err(e) => {
555 println!("Error during integration: {}. Aborting.", e);
556 -999
557 }
558 }
559 }
560 }
561
562 extern "C" fn c_divonne_integrand<T>(
563 ndim: *const c_int,
564 x: *const c_double,
565 ncomp: *const c_int,
566 f: *mut c_double,
567 userdata: *mut c_void,
568 nvec: *const c_int,
569 core: *const c_int,
570 phase: *const c_int,
571 ) -> c_int {
572 unsafe {
573 let k: &mut DivonneUserData<T> = &mut *(userdata as *mut _);
574
575 match (k.integrand)(
577 &slice::from_raw_parts(x, *ndim as usize * *nvec as usize),
578 &mut slice::from_raw_parts_mut(f, *ncomp as usize * *nvec as usize),
579 &mut k.user_data,
580 *nvec as usize,
581 *core as i32,
582 *phase as usize,
583 ) {
584 Ok(_) => 0,
585 Err(e) => {
586 println!("Error during integration: {}. Aborting.", e);
587 -999
588 }
589 }
590 }
591 }
592
593 extern "C" fn c_peakfinder(
594 ndim: *const c_int,
595 b: *const c_double,
596 n: *mut c_int,
597 x: *mut c_double,
598 userdata: *mut c_void,
599 ) {
600 }
602
603 pub fn vegas<T>(
614 &mut self,
615 ndim: usize,
616 ncomp: usize,
617 nvec: usize,
618 verbosity: CubaVerbosity,
619 gridno: i32,
620 integrand: VegasIntegrand<T>,
621 user_data: T,
622 ) -> CubaResult {
623 let mut out = CubaResult {
624 neval: 0,
625 fail: 0,
626 result: vec![0.; ncomp],
627 error: vec![0.; ncomp],
628 prob: vec![0.; ncomp],
629 };
630
631 assert!(
632 gridno >= -10 && gridno <= 10,
633 "Grid number needs to be between -10 and 10."
634 );
635
636 assert!(
637 nvec <= self.batch as usize && nvec <= self.max_points_per_core,
638 "nvec needs to be at most the vegas batch size or the max points per core"
639 );
640
641 let mut x = VegasUserData {
643 integrand: integrand,
644 user_data: user_data,
645 };
646
647 let user_data_ptr = &mut x as *mut _ as *mut c_void;
648
649 let mut cubaflags = verbosity as i32;
651 if self.use_only_last_sample {
653 cubaflags |= 0b100;
654 }
655 if self.keep_state_file {
657 cubaflags |= 0b10000;
658 }
659 if self.reset_vegas_integrator {
662 cubaflags |= 0b100000;
663 }
664 let c_str = CString::new(self.save_state_file.as_str()).expect("CString::new failed");
665 unsafe {
666 llVegas(
667 ndim as c_int, ncomp as c_int, Some(CubaIntegrator::c_vegas_integrand::<T>), user_data_ptr, nvec as c_longlong, self.epsrel, self.epsabs, cubaflags as c_int, self.seed, self.mineval, self.maxeval, self.nstart, self.nincrease, self.batch, gridno, c_str.as_ptr(), ptr::null_mut(), &mut out.neval,
685 &mut out.fail,
686 &mut out.result[0],
687 &mut out.error[0],
688 &mut out.prob[0],
689 );
690 }
691
692 out
693 }
694 pub fn suave<T>(
707 &mut self,
708 ndim: usize,
709 ncomp: usize,
710 nvec: usize,
711 nnew: usize,
712 nmin: usize,
713 flatness: f64,
714 verbosity: CubaVerbosity,
715 integrand: SuaveIntegrand<T>,
716 user_data: T,
717 ) -> CubaResult {
718 let mut out = CubaResult {
719 neval: 0,
720 fail: 0,
721 result: vec![0.; ncomp],
722 error: vec![0.; ncomp],
723 prob: vec![0.; ncomp],
724 };
725
726 assert!(
727 nvec <= self.max_points_per_core && nvec <= nnew,
728 "nvec needs to be at most the max points per core and nnew"
729 );
730
731 let mut x = SuaveUserData {
733 integrand: integrand,
734 user_data: user_data,
735 };
736
737 let user_data_ptr = &mut x as *mut _ as *mut c_void;
738
739 let mut cubaflags = verbosity as i32;
741 if self.use_only_last_sample {
743 cubaflags |= 0b100;
744 }
745 if self.keep_state_file {
747 cubaflags |= 0b10000;
748 }
749 if self.reset_vegas_integrator {
752 cubaflags |= 0b100000;
753 }
754
755 let mut nregions = 0;
756 let c_str = CString::new(self.save_state_file.as_str()).expect("CString::new failed");
757 unsafe {
758 llSuave(
759 ndim as c_int, ncomp as c_int, Some(CubaIntegrator::c_suave_integrand::<T>), user_data_ptr, nvec as c_longlong, self.epsrel, self.epsabs, cubaflags as c_int, self.seed, self.mineval, self.maxeval, nnew as c_longlong,
771 nmin as c_longlong,
772 flatness,
773 c_str.as_ptr(),
774 ptr::null_mut(),
775 &mut nregions,
776 &mut out.neval,
777 &mut out.fail,
778 &mut out.result[0],
779 &mut out.error[0],
780 &mut out.prob[0],
781 );
782 }
783
784 out
785 }
786
787 pub fn divonne<T>(
796 &mut self,
797 ndim: usize,
798 ncomp: usize,
799 nvec: usize,
800 xgiven: &[f64],
801 verbosity: CubaVerbosity,
802 integrand: DivonneIntegrand<T>,
803 user_data: T,
804 ) -> CubaResult {
805 let mut out = CubaResult {
806 neval: 0,
807 fail: 0,
808 result: vec![0.; ncomp],
809 error: vec![0.; ncomp],
810 prob: vec![0.; ncomp],
811 };
812
813 assert!(
814 nvec <= self.max_points_per_core,
815 "nvec needs to be at most the max points per core"
816 );
817
818 let mut x = DivonneUserData {
820 integrand: integrand,
821 user_data: user_data,
822 };
823
824 let user_data_ptr = &mut x as *mut _ as *mut c_void;
825
826 let mut cubaflags = verbosity as i32;
828 if self.use_only_last_sample {
830 cubaflags |= 0b100;
831 }
832 if self.keep_state_file {
834 cubaflags |= 0b10000;
835 }
836 if self.reset_vegas_integrator {
839 cubaflags |= 0b100000;
840 }
841
842 let mut nregions = 0;
843 let c_str = CString::new(self.save_state_file.as_str()).expect("CString::new failed");
844 unsafe {
845 llDivonne(
846 ndim as c_int, ncomp as c_int, Some(CubaIntegrator::c_divonne_integrand::<T>), user_data_ptr, nvec as c_longlong, self.epsrel, self.epsabs, cubaflags as c_int, self.seed, self.mineval, self.maxeval, self.key1,
858 self.key2,
859 self.key3,
860 self.maxpass,
861 self.border,
862 self.maxchisq,
863 self.mindeviation,
864 (xgiven.len() / ndim) as c_longlong,
865 ndim as c_int,
866 if xgiven.len() == 0 {
867 ptr::null_mut()
868 } else {
869 &xgiven[0]
870 },
871 0,
872 None,
873 c_str.as_ptr(),
874 ptr::null_mut(),
875 &mut nregions,
876 &mut out.neval,
877 &mut out.fail,
878 &mut out.result[0],
879 &mut out.error[0],
880 &mut out.prob[0],
881 );
882 }
883
884 out
885 }
886
887 pub fn cuhre<T>(
895 &mut self,
896 ndim: usize,
897 ncomp: usize,
898 nvec: usize,
899 verbosity: CubaVerbosity,
900 integrand: CuhreIntegrand<T>,
901 user_data: T,
902 ) -> CubaResult {
903 let mut out = CubaResult {
904 neval: 0,
905 fail: 0,
906 result: vec![0.; ncomp],
907 error: vec![0.; ncomp],
908 prob: vec![0.; ncomp],
909 };
910
911 assert!(nvec <= 32, "nvec needs to be at most 32");
912
913 let mut x = CuhreUserData {
915 integrand: integrand,
916 user_data: user_data,
917 };
918
919 let user_data_ptr = &mut x as *mut _ as *mut c_void;
920
921 let mut cubaflags = verbosity as i32;
923 if self.use_only_last_sample {
925 cubaflags |= 0b100;
926 }
927 if self.keep_state_file {
929 cubaflags |= 0b10000;
930 }
931
932 let mut nregions = 0;
933 let c_str = CString::new(self.save_state_file.as_str()).expect("CString::new failed");
934 unsafe {
935 llCuhre(
936 ndim as c_int, ncomp as c_int, Some(CubaIntegrator::c_cuhre_integrand::<T>), user_data_ptr, nvec as c_longlong, self.epsrel, self.epsabs, cubaflags as c_int, self.mineval, self.maxeval, self.key, c_str.as_ptr(), ptr::null_mut(), &mut nregions,
950 &mut out.neval,
951 &mut out.fail,
952 &mut out.result[0],
953 &mut out.error[0],
954 &mut out.prob[0],
955 );
956 }
957
958 out
959 }
960}