Skip to main content

cuba/
lib.rs

1//! Rust binding for the Cuba integrator.
2//!
3//! Cuba (http://www.feynarts.de/cuba/) is written by Thomas Hahn.
4//!
5//! # Usage
6//! Create a `CubaIntegrator` and supply it with a function of the form
7//!
8//! ```
9//! type UserData = ();
10//!
11//! fn integrand(
12//!     x: &[f64],
13//!     f: &mut [f64],
14//!     user_data: &mut UserData,
15//!     nvec: usize,
16//!     core: i32,
17//!     weight: &[f64],
18//!     iter: usize,
19//! ) -> Result<(), &'static str> {
20//!     Ok(())
21//! }
22//! ```
23//! where `UserData` can be any type. If you don't want to provide user data,
24//! simply make `UserData` a `usize` and provide any number.
25//!
26//! # Example
27//!
28//! ```
29//! extern crate cuba;
30//! use cuba::{CubaIntegrator, CubaVerbosity};
31//!
32//! #[derive(Debug)]
33//! struct UserData {
34//!     f1: f64,
35//!     f2: f64,
36//! }
37//!
38//! #[inline(always)]
39//! fn integrand(
40//!     x: &[f64],
41//!     f: &mut [f64],
42//!     user_data: &mut UserData,
43//!     nvec: usize,
44//!     _core: i32,
45//!     _weight: &[f64],
46//!     _iter: usize,
47//! ) -> Result<(), &'static str> {
48//!     for i in 0..nvec {
49//!         f[i * 2] = (x[i * 2] * x[i * 2]).sin() * user_data.f1;
50//!         f[i * 2 + 1] = (x[i * 2 + 1] * x[i * 2 + 1]).cos() * user_data.f2;
51//!     }
52//!
53//!     Ok(())
54//! }
55//!
56//! fn main() {
57//!     let mut ci = CubaIntegrator::new();
58//!     ci.set_mineval(10)
59//!         .set_maxeval(10000000)
60//!         .set_epsrel(0.0001)
61//!         .set_seed(0) // use quasi-random numbers
62//!         .set_cores(2, 1000);
63//!
64//!     let data = UserData { f1: 5., f2: 7. };
65//!     let r = ci.vegas(2, 2, 4, CubaVerbosity::Progress, 0, integrand, data);
66//!
67//!     println!("{:#?}", r);
68//! }
69//! ```
70extern 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
76/// Logging level.
77///
78/// `Silent` does not print any output, `Progress` prints 'reasonable' information on the
79/// progress of the integration, `Input` also echoes the input parameters,
80/// and `Subregions` further prints the subregion results.
81pub 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
261/// Vegas integrand evaluation function.
262///
263/// The dimensions of random input variables `x` and output `f`
264/// are provided to the integration routine as dimension and components respectively.
265/// `T` can be any type. If you don't want to provide user data,
266/// simply make `T` a `usize` and provide any number.
267///
268/// `core` specifies the current core that is being used. This can be used to write to
269/// the user data in a thread-safe way.
270///
271/// On returning an error, the integration will be aborted.
272pub 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
282/// Suave integrand evaluation function.
283///
284/// The dimensions of random input variables `x` and output `f`
285/// are provided to the integration routine as dimension and components respectively.
286/// `T` can be any type. If you don't want to provide user data,
287/// simply make `T` a `usize` and provide any number.
288///
289/// `core` specifies the current core that is being used. This can be used to write to
290/// the user data in a thread-safe way.
291///
292/// On returning an error, the integration will be aborted.
293pub 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
303/// Cuhre integrand evaluation function.
304///
305/// The dimensions of random input variables `x` and output `f`
306/// are provided to the integration routine as dimension and components respectively.
307/// `T` can be any type. If you don't want to provide user data,
308/// simply make `T` a `usize` and provide any number.
309///
310/// `core` specifies the current core that is being used. This can be used to write to
311/// the user data in a thread-safe way.
312///
313/// On returning an error, the integration will be aborted.
314pub 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
322/// Divonne integrand evaluation function.
323///
324/// The dimensions of random input variables `x` and output `f`
325/// are provided to the integration routine as dimension and components respectively.
326/// `T` can be any type. If you don't want to provide user data,
327/// simply make `T` a `usize` and provide any number.
328///
329/// `core` specifies the current core that is being used. This can be used to write to
330/// the user data in a thread-safe way.
331///
332/// On returning an error, the integration will be aborted.
333pub 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/// The result of an integration with Cuba.
367#[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
376/// A Cuba integrator. It should be created with an integrand function.
377pub 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    // Cuhre
393    key: i32,
394    // Divonne
395    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    /// Create a new Cuba integrator. Use the `set_` functions
406    /// to set integration parameters.
407    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    /// Set the number of cores and the maximum number of points per core.
435    /// The default is the number of idle cores for `cores` and
436    /// 1000 for `max_points_per_core`.
437    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            // call the safe integrand
482            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            // call the safe integrand
515            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            // call the safe integrand
546            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            // call the safe integrand
576            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        // TODO: call a safe peakfinder routine
601    }
602
603    /// Integrate using the Vegas integrator.
604    ///
605    /// * `ndim` - Dimension of the input
606    /// * `ncomp` - Dimension (components) of the output
607    /// * `nvec` - Number of input points given to the integrand function
608    /// * `verbosity` - Verbosity level
609    /// * `gridno` - Grid number between -10 and 10. If 0, no grid is stored.
610    ///              If it is positive, the grid is storedin the `gridno`th slot.
611    ///              With a negative number the grid is cleared.
612    /// * `user_data` - User data used by the integrand function
613    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        // pass the safe integrand and the user data
642        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        // Bits 0 and 1 set the CubaVerbosity
650        let mut cubaflags = verbosity as i32;
651        // Bit 2 sets whether only last sample should be used
652        if self.use_only_last_sample {
653            cubaflags |= 0b100;
654        }
655        // Bit 4 specifies whether the state file should be retained after integration
656        if self.keep_state_file {
657            cubaflags |= 0b10000;
658        }
659        // Bit 5 specifies whether the integrator state (except the grid) should be reset
660        // after having loaded a state file (Vegas only)
661        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,                                // ndim
668                ncomp as c_int,                               // ncomp
669                Some(CubaIntegrator::c_vegas_integrand::<T>), // integrand
670                user_data_ptr,                                // user data
671                nvec as c_longlong,                           // nvec
672                self.epsrel,                                  // epsrel
673                self.epsabs,                                  // epsabs
674                cubaflags as c_int,                           // flags
675                self.seed,                                    // seed
676                self.mineval,                                 // mineval
677                self.maxeval,                                 // maxeval
678                self.nstart,                                  // nstart
679                self.nincrease,                               // nincrease
680                self.batch,                                   // batch
681                gridno,                                       // grid no
682                c_str.as_ptr(),                               // statefile
683                ptr::null_mut(),                              // spin
684                &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    /// Integrate using the Suave integrator.
695    ///
696    /// * `ndim` - Dimension of the input
697    /// * `ncomp` - Dimension (components) of the output
698    /// * `nvec` - Number of input points given to the integrand function
699    /// * `nnew` - Number of new integrand evaluations in each subdivision
700    /// * `nmin` - Minimum number of samples a former pass must contribute to a
701    ///            subregion to be considered in that region’s compound integral value
702    /// * `flatness` - This determines how prominently individual samples with a large fluctuation
703    ///                figure in the total fluctuation
704    /// * `verbosity` - Verbosity level
705    /// * `user_data` - User data used by the integrand function
706    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        // pass the safe integrand and the user data
732        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        // Bits 0 and 1 set the CubaVerbosity
740        let mut cubaflags = verbosity as i32;
741        // Bit 2 sets whether only last sample should be used
742        if self.use_only_last_sample {
743            cubaflags |= 0b100;
744        }
745        // Bit 4 specifies whether the state file should be retained after integration
746        if self.keep_state_file {
747            cubaflags |= 0b10000;
748        }
749        // Bit 5 specifies whether the integrator state (except the grid) should be reset
750        // after having loaded a state file (Vegas only)
751        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,                                // ndim
760                ncomp as c_int,                               // ncomp
761                Some(CubaIntegrator::c_suave_integrand::<T>), // integrand
762                user_data_ptr,                                // user data
763                nvec as c_longlong,                           // nvec
764                self.epsrel,                                  // epsrel
765                self.epsabs,                                  // epsabs
766                cubaflags as c_int,                           // flags
767                self.seed,                                    // seed
768                self.mineval,                                 // mineval
769                self.maxeval,                                 // maxeval
770                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    /// Integrate using the Divonne integrator.
788    ///
789    /// * `ndim` - Dimension of the input
790    /// * `ncomp` - Dimension (components) of the output
791    /// * `nvec` - Number of input points given to the integrand function
792    /// * `xgiven` - A list of input points which lie close to peaks
793    /// * `verbosity` - Verbosity level
794    /// * `user_data` - User data used by the integrand function
795    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        // pass the safe integrand and the user data
819        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        // Bits 0 and 1 set the CubaVerbosity
827        let mut cubaflags = verbosity as i32;
828        // Bit 2 sets whether only last sample should be used
829        if self.use_only_last_sample {
830            cubaflags |= 0b100;
831        }
832        // Bit 4 specifies whether the state file should be retained after integration
833        if self.keep_state_file {
834            cubaflags |= 0b10000;
835        }
836        // Bit 5 specifies whether the integrator state (except the grid) should be reset
837        // after having loaded a state file (Vegas only)
838        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,                                  // ndim
847                ncomp as c_int,                                 // ncomp
848                Some(CubaIntegrator::c_divonne_integrand::<T>), // integrand
849                user_data_ptr,                                  // user data
850                nvec as c_longlong,                             // nvec
851                self.epsrel,                                    // epsrel
852                self.epsabs,                                    // epsabs
853                cubaflags as c_int,                             // flags
854                self.seed,                                      // seed
855                self.mineval,                                   // mineval
856                self.maxeval,                                   // maxeval
857                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    /// Integrate using the Cuhre integrator.
888    ///
889    /// * `ndim` - Dimension of the input
890    /// * `ncomp` - Dimension (components) of the output
891    /// * `nvec` - Number of input points given to the integrand function
892    /// * `verbosity` - Verbosity level
893    /// * `user_data` - User data used by the integrand function
894    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        // pass the safe integrand and the user data
914        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        // Bits 0 and 1 set the CubaVerbosity
922        let mut cubaflags = verbosity as i32;
923        // Bit 2 sets whether only last sample should be used
924        if self.use_only_last_sample {
925            cubaflags |= 0b100;
926        }
927        // Bit 4 specifies whether the state file should be retained after integration
928        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,                                // ndim
937                ncomp as c_int,                               // ncomp
938                Some(CubaIntegrator::c_cuhre_integrand::<T>), // integrand
939                user_data_ptr,                                // user data
940                nvec as c_longlong,                           // nvec
941                self.epsrel,                                  // epsrel
942                self.epsabs,                                  // epsabs
943                cubaflags as c_int,                           // flags
944                self.mineval,                                 // mineval
945                self.maxeval,                                 // maxeval
946                self.key,                                     // key
947                c_str.as_ptr(),                               // statefile
948                ptr::null_mut(),                              // spin
949                &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}