#[macro_export]
macro_rules! kv {
($($k:expr => $v:expr;)*) => {
$crate::core::KV { kv: std::collections::HashMap::from([ $(($k.into(), $v.into())),* ]) }
};
}
#[macro_export]
macro_rules! check_param {
($param:expr, $msg:expr, $error:ident) => {
match $param {
None => {
return Err($crate::core::ArgminError::$error {
text: $msg.to_string(),
}
.into());
}
Some(ref x) => x.clone(),
}
};
($param:expr, $msg:expr) => {
check_param!($param, $msg, NotInitialized)
};
}
#[macro_export]
macro_rules! argmin_error {
($error_type:ident, $msg:expr) => {
$crate::core::ArgminError::$error_type {
text: $msg.to_string(),
}
.into()
};
}
#[macro_export]
macro_rules! argmin_error_closure {
($error_type:ident, $msg:expr) => {
|| -> $crate::core::Error { $crate::argmin_error!($error_type, $msg) }
};
}
#[macro_export]
macro_rules! float {
($t:ident, $val:expr) => {
$t::from_f64($val).unwrap()
};
($val:expr) => {
F::from_f64($val).unwrap()
};
}
#[macro_export]
macro_rules! bulk {
($method_name:tt, $input:ty, $output:ty) => {
paste::item! {
#[doc = concat!(
"Compute `",
stringify!($method_name),
"` in bulk. ",
"If the `rayon` feature is enabled, multiple calls to `",
stringify!($method_name),
"` will be run in parallel using `rayon`, otherwise they will execute ",
"sequentially. If the `rayon` feature is enabled, parallelization can still be ",
"turned off by overwriting `parallelize` to return `false`. This can be useful ",
"in cases where it is preferable to parallelize only certain parts. ",
"Note that even if `parallelize` is set to false, the parameter vectors and the ",
"problem are still required to be `Send` and `Sync`. Those bounds are linked to ",
"the `rayon` feature. This method can be overwritten.",
)]
fn [<bulk_ $method_name>]<P>(&self, params: &[P]) -> Result<Vec<$output>, Error>
where
P: std::borrow::Borrow<$input> + SyncAlias,
$output: SendAlias,
Self: SyncAlias,
{
#[cfg(feature = "rayon")]
{
if self.parallelize() {
params.par_iter().map(|p| self.$method_name(p.borrow())).collect()
} else {
params.iter().map(|p| self.$method_name(p.borrow())).collect()
}
}
#[cfg(not(feature = "rayon"))]
{
params.iter().map(|p| self.$method_name(p.borrow())).collect()
}
}
}
#[doc = concat!(
"Indicates whether to parallelize calls to `",
stringify!($method_name),
"` when using `bulk_",
stringify!($method_name),
"`. By default returns true, but can be set manually to `false` if needed. ",
"This allows users to turn off parallelization for certain traits ",
"implemented on their problem. ",
"Note that parallelization requires the `rayon` feature to be enabled, ",
"otherwise calls to `",
stringify!($method_name),
"` will be executed sequentially independent of how `parallelize` is set."
)]
fn parallelize(&self) -> bool {
true
}
};
}
#[cfg(test)]
macro_rules! send_sync_test {
($n:ident, $t:ty) => {
paste::item! {
#[test]
#[allow(non_snake_case)]
fn [<test_send_ $n>]() {
fn assert_send<T: Send>() {}
assert_send::<$t>();
}
}
paste::item! {
#[test]
#[allow(non_snake_case)]
fn [<test_sync_ $n>]() {
fn assert_sync<T: Sync>() {}
assert_sync::<$t>();
}
}
};
}
#[cfg(test)]
#[macro_export]
macro_rules! test_trait_impl {
($n:ident, $t:ty) => {
paste::item! {
#[test]
#[allow(non_snake_case)]
fn [<test_send_ $n>]() {
fn assert_send<T: Send>() {}
assert_send::<$t>();
}
}
paste::item! {
#[test]
#[allow(non_snake_case)]
fn [<test_sync_ $n>]() {
fn assert_sync<T: Sync>() {}
assert_sync::<$t>();
}
}
paste::item! {
#[test]
#[allow(non_snake_case)]
fn [<test_clone_ $n>]() {
fn assert_clone<T: Clone>() {}
assert_clone::<$t>();
}
}
};
}
#[cfg(test)]
#[macro_export]
macro_rules! assert_error {
($n:expr, $t:ty, $s:expr) => {
assert_eq!(
$n.err().unwrap().downcast_ref::<$t>().unwrap().to_string(),
$s
);
};
}