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
//! A function for creating linear constraint systems.

use super::factory::{cname, vname, ComponentFactory};
use crate::{
    macros::{RawComponent, RawConstraint, RawMethod},
    model::Component,
};
use std::{fmt::Debug, sync::Arc};

/// A component factory for creating linear-oneway components.
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct LinearOneway;

impl ComponentFactory for LinearOneway {
    fn name() -> &'static str {
        "linear-oneway"
    }
    fn build<T>(n_constraints: usize) -> Component<T>
    where
        T: Clone + Debug + Default + 'static,
    {
        let n_variables = n_constraints + 1;

        // Shared dummy apply function
        let apply = Arc::new(Ok);

        // Shared variable names
        let variable_names: Vec<String> = (0..n_variables).map(vname).collect();

        // Create constraints between each consecutive variable
        let mut constraints = Vec::new();
        for constraint_id in 1..n_variables {
            let prev = &vname(constraint_id - 1);
            let current = &vname(constraint_id);
            let constraint: RawConstraint<T> = RawConstraint::new(
                &cname(constraint_id),
                vec![RawMethod::new(
                    "right",
                    vec![prev],
                    vec![current],
                    apply.clone(),
                )],
            );
            constraints.push(constraint);
        }

        // Construct component
        let comp = RawComponent::new(
            LinearOneway::name().to_string(),
            variable_names,
            vec![T::default(); n_variables],
            constraints,
        );

        comp.into_component()
    }
}

/// A component factory for creating linear-twoway components.
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct LinearTwoway;

impl ComponentFactory for LinearTwoway {
    fn name() -> &'static str {
        "linear-twoway"
    }
    fn build<T>(n_constraints: usize) -> Component<T>
    where
        T: Clone + Debug + Default + 'static,
    {
        let n_variables = n_constraints + 1;

        // Shared dummy apply function
        let apply = Arc::new(Ok);

        // Shared variable names
        let variable_names: Vec<String> = (0..n_variables).map(vname).collect();

        // Create constraints between each consecutive variable
        let mut constraints = Vec::new();
        for constraint_id in 1..n_variables {
            let prev = &vname(constraint_id - 1);
            let current = &vname(constraint_id);
            let constraint: RawConstraint<T> = RawConstraint::new(
                &cname(constraint_id),
                vec![
                    RawMethod::new("left", vec![prev], vec![current], apply.clone()),
                    RawMethod::new("right", vec![current], vec![prev], apply.clone()),
                ],
            );
            constraints.push(constraint);
        }

        // Construct component
        let comp = RawComponent::new(
            LinearTwoway::name().to_string(),
            variable_names,
            vec![T::default(); n_variables],
            constraints,
        );

        comp.into_component()
    }
}

#[cfg(test)]
mod tests {
    use super::{super::factory::ComponentFactory, LinearOneway};
    use crate::{model::Component, planner::ComponentSpec};

    #[test]
    fn linear_oneway_right_number_of_constraints() {
        for nc in 0..20 {
            let ladder: Component<()> = LinearOneway::build(nc);
            assert_eq!(ladder.n_constraints(), nc);
        }
    }

    #[test]
    fn linear_twoway_right_number_of_constraints() {
        for nc in 0..20 {
            let ladder: Component<()> = LinearOneway::build(nc);
            assert_eq!(ladder.n_constraints(), nc);
        }
    }
}