soco/algorithms/offline/multi_dimensional/
convex_optimization.rs

1use crate::algorithms::offline::{OfflineOptions, PureOfflineResult};
2use crate::config::Config;
3use crate::model::{ModelOutputFailure, ModelOutputSuccess};
4use crate::numerics::convex_optimization::{minimize, WrappedObjective};
5use crate::problem::{FractionalSmoothedConvexOptimization, Problem};
6use crate::result::{Failure, Result};
7use crate::schedule::Schedule;
8use crate::utils::assert;
9use noisy_float::prelude::*;
10
11#[derive(Clone)]
12struct ObjectiveData<'a, C, D> {
13    p: FractionalSmoothedConvexOptimization<'a, C, D>,
14    alpha: f64,
15}
16
17#[derive(Clone)]
18struct ConstraintData<'a, C, D> {
19    p: FractionalSmoothedConvexOptimization<'a, C, D>,
20    l: f64,
21}
22
23/// Convex Optimization
24pub fn co<C, D>(
25    p: FractionalSmoothedConvexOptimization<'_, C, D>,
26    _: (),
27    OfflineOptions { inverted, alpha, l }: OfflineOptions,
28) -> Result<PureOfflineResult<f64>>
29where
30    C: ModelOutputSuccess,
31    D: ModelOutputFailure,
32{
33    assert(!inverted, Failure::UnsupportedInvertedCost)?;
34
35    let d = p.d;
36    let t_end = p.t_end;
37
38    let (lower, upper): (Vec<_>, Vec<_>) = p.bounds.iter().cloned().unzip();
39    let extended_lower = Schedule::build_raw(p.t_end, &Config::new(lower));
40    let extended_upper = Schedule::build_raw(p.t_end, &Config::new(upper));
41    let bounds = extended_lower
42        .into_iter()
43        .zip(extended_upper.into_iter())
44        .collect();
45
46    let objective = WrappedObjective::new(
47        ObjectiveData {
48            p: p.clone(),
49            alpha,
50        },
51        |raw_xs, data| {
52            let xs = Schedule::from_raw(data.p.d, data.p.t_end, raw_xs);
53            data.p
54                .alpha_unfair_objective_function(&xs, data.alpha)
55                .unwrap()
56                .cost
57        },
58    );
59
60    // l-constrained movement
61    let constraints = match l {
62        Some(l) => {
63            vec![WrappedObjective::new(
64                ConstraintData { p, l },
65                |raw_xs, data| {
66                    let xs = Schedule::from_raw(data.p.d, data.p.t_end, raw_xs);
67                    data.p.total_movement(&xs, false).unwrap() - n64(data.l)
68                },
69            )]
70        }
71        None => vec![],
72    };
73
74    let (raw_xs, _) = minimize(objective, bounds, None, constraints);
75    let xs = Schedule::from_raw(d, t_end, &raw_xs);
76    Ok(PureOfflineResult { xs })
77}