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
use log::debug;

use crate::algorithms::offline::{OfflineOptions, PureOfflineResult};
use crate::config::IntegralConfig;
use crate::model::{ModelOutputFailure, ModelOutputSuccess};
use crate::problem::{IntegralSmoothedConvexOptimization, Problem};
use crate::result::{Failure, Result};
use crate::schedule::IntegralSchedule;
use crate::utils::assert;

/// Algorithm computing the static integral optimum.
///
/// Warning: do not use in practice, this algorithm is naive and has an exponential runtime.
pub fn static_integral<C, D>(
    p: IntegralSmoothedConvexOptimization<'_, C, D>,
    _: (),
    OfflineOptions { inverted, alpha, l }: OfflineOptions,
) -> Result<PureOfflineResult<i32>>
where
    C: ModelOutputSuccess,
    D: ModelOutputFailure,
{
    assert(!inverted, Failure::UnsupportedInvertedCost)?;
    assert(
        l.is_none() || l == Some(0.),
        Failure::UnsupportedLConstrainedMovement,
    )?;

    let (config, _) =
        check_configs(&p, alpha, 0, IntegralConfig::repeat(0, p.d))?;
    let xs = IntegralSchedule::new(vec![config; p.t_end as usize]);
    Ok(PureOfflineResult { xs })
}

fn check_configs<C, D>(
    p: &IntegralSmoothedConvexOptimization<'_, C, D>,
    alpha: f64,
    k: usize,
    mut base_config: IntegralConfig,
) -> Result<(IntegralConfig, f64)>
where
    C: ModelOutputSuccess,
    D: ModelOutputFailure,
{
    if k < p.d as usize {
        debug!("Checking dimension {}.", k + 1);
        let mut picked_config = base_config.clone();
        let mut picked_cost = f64::INFINITY;
        for j in p.bounds[k].0..=p.bounds[k].1 {
            base_config[k] = j;
            let (config, cost) =
                check_configs(p, alpha, k + 1, base_config.clone())?;
            if cost < picked_cost {
                picked_config = config;
                picked_cost = cost;
            } else if cost > picked_cost {
                break;
            }
        }
        Ok((picked_config, picked_cost))
    } else {
        let cost = p
            .objective_function(&IntegralSchedule::new(vec![
                base_config
                    .clone();
                p.t_end as usize
            ]))?
            .cost
            .raw();
        debug!("Config {:?} has associated cost {:?}.", base_config, cost);
        Ok((base_config, cost))
    }
}