1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
use crate::parameter::{ParamDomain, ParamValue}; use crate::solver::SolverCapabilities; use crate::Result; use rustats::num::FiniteF64; use rustats::range::MinMax; use serde::{Deserialize, Serialize}; use std::collections::BTreeSet; use std::fmt; use std::num::NonZeroU64; use structopt::StructOpt; use yamakan::budget::Budget; use yamakan::observation::ObsId; pub trait Evaluate { fn evaluate(&mut self, params: &[ParamValue], budget: &mut Budget) -> Result<Values>; } impl<T: Evaluate + ?Sized> Evaluate for Box<T> { fn evaluate(&mut self, params: &[ParamValue], budget: &mut Budget) -> Result<Values> { (**self).evaluate(params, budget) } } pub trait Problem { type Evaluator: Evaluate; fn specification(&self) -> ProblemSpec; fn create_evaluator(&mut self, id: ObsId) -> Result<Self::Evaluator>; } pub trait ProblemRecipe: Clone + StructOpt + Serialize + for<'a> Deserialize<'a> { type Problem: Problem; fn create_problem(&self) -> Result<Self::Problem>; } pub type Values = Vec<FiniteF64>; #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] pub struct ProblemSpec { pub name: String, #[serde(default)] pub version: Option<String>, pub params_domain: Vec<ParamDomain>, pub values_domain: Vec<MinMax<FiniteF64>>, pub evaluation_expense: NonZeroU64, #[serde(default)] pub capabilities: EvaluatorCapabilities, } impl ProblemSpec { pub fn required_solver_capabilities(&self) -> SolverCapabilities { let mut c = SolverCapabilities::empty(); if self.values_domain.len() > 1 { c = c.multi_objective(); } for p in &self.params_domain { c = c.union(p.required_solver_capabilities()); } c } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] pub enum EvaluatorCapability { Concurrent, DynamicParamChange, } pub type EvaluatorCapabilities = BTreeSet<EvaluatorCapability>; pub struct BoxProblem { spec: ProblemSpec, create: Box<FnMut(ObsId) -> Result<BoxEvaluator>>, } impl BoxProblem { pub fn new<T>(mut problem: T) -> Self where T: Problem + 'static, T::Evaluator: 'static, { Self { spec: problem.specification(), create: Box::new(move |id| { let evaluator = track!(problem.create_evaluator(id))?; Ok(BoxEvaluator::new(evaluator)) }), } } } impl Problem for BoxProblem { type Evaluator = BoxEvaluator; fn specification(&self) -> ProblemSpec { self.spec.clone() } fn create_evaluator(&mut self, id: ObsId) -> Result<Self::Evaluator> { track!((self.create)(id)) } } impl fmt::Debug for BoxProblem { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "BoxProblem {{ .. }}") } } pub struct BoxEvaluator(Box<(dyn Evaluate + 'static)>); impl BoxEvaluator { pub fn new<T>(evaluator: T) -> Self where T: Evaluate + 'static, { Self(Box::new(evaluator)) } } impl Evaluate for BoxEvaluator { fn evaluate(&mut self, params: &[ParamValue], budget: &mut Budget) -> Result<Values> { self.0.evaluate(params, budget) } } impl fmt::Debug for BoxEvaluator { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "BoxEvaluator {{ .. }}") } }