Skip to main content

geop_lib_constraints/
unknown.rs

1//! Which values of the state a solve may move, as the steps declare them:
2//! [`Unknown`]s, each step's in a target of its own, and all of a part's
3//! together ([`Unknowns`]), so that a solve of any program is set up from
4//! the part alone.
5//!
6//! Each step's own, not one target every step adds to: a joint's
7//! coordinate is seeded where its parts are, so a step's unknowns are made
8//! again whenever its parts move, and a target revised by every step would
9//! make every later step's again with it — copying all the unknowns before
10//! it, at a cost growing with the square of the steps. A drag of a robot
11//! arm of a thousand parts spent a third of its time there.
12
13use std::collections::BTreeMap;
14
15use geop_core_math::{
16    geop_error::{GeopError, GeopResult},
17    solvers::system::Mobility,
18};
19use geop_core_program::{
20    element::{ElementReference, HasElements, Kind},
21    part::{Make, StepContext},
22    placed::key_behind,
23    reader::Reader,
24    target::{Target, TargetReference},
25    values::StateValue,
26};
27
28use crate::Generated;
29
30/// A value of the state as a step declares it for solving: the state it is,
31/// and how a solve may move it — or that it holds it fixed. A solve starts
32/// it from `seed` where the state has none of it, and — given a constraint
33/// `unless` — where that constraint does not hold either: a joint's
34/// coordinate, measured from where its parts are unless the joint holds.
35#[derive(Clone, Debug, PartialEq)]
36pub struct Unknown {
37    pub state: String,
38    pub mobility: Mobility,
39    pub seed: Option<StateValue>,
40    pub unless: Option<String>,
41}
42
43/// What the name of a step's unknowns target starts with.
44const UNKNOWNS: &str = "unknowns";
45
46/// Every unknown the steps so far declared, by the state it is: gathered
47/// from their targets ([`Unknowns::of`]).
48#[derive(Clone, Debug, Default, PartialEq)]
49pub struct Unknowns(BTreeMap<String, Unknown>);
50
51impl Unknowns {
52    /// The unknowns of the part `reader` reads: none where no step declared
53    /// any, an error where a declaration failed.
54    ///
55    /// Those of every instance placed in it come up behind the instance's
56    /// name, as its constraints do (see [`crate::Constraints::of`]), each
57    /// starting where the instance's part has it, if it has it at all. A
58    /// state the part holds fixed stays fixed.
59    pub fn of(reader: &Reader) -> GeopResult<Self> {
60        if let Some(failed) = reader.failed_targets_of::<StepUnknowns>().pop() {
61            return Err(failed);
62        }
63        let mut all = Self::default();
64        for own in reader.targets_of::<StepUnknowns>() {
65            let own = reader.retrieve_element(&ElementReference::whole(own))?;
66            for declared in &own.0 {
67                all.declare(declared.clone());
68            }
69        }
70        for name in reader.instances() {
71            let inside = reader.placed_part(name)?;
72            let declared = Self::of(&inside)
73                .map_err(|e| e.with_context(format!("the unknowns of the placed part `{name}`")))?;
74            for unknown in declared.0.into_values() {
75                let seed = inside.given_state(&unknown.state).or(unknown.seed);
76                all.declare(Unknown {
77                    state: key_behind(name, &unknown.state),
78                    seed,
79                    unless: (unknown.unless).map(|unless| key_behind(name, &unless)),
80                    ..unknown
81                });
82            }
83        }
84        Ok(all)
85    }
86
87    /// The unknown the state `state` is, if a step declared it.
88    pub fn get(&self, state: &str) -> Option<&Unknown> {
89        self.0.get(state)
90    }
91
92    /// Every unknown, in order of their states' names.
93    pub fn iter(&self) -> impl Iterator<Item = &Unknown> {
94        self.0.values()
95    }
96
97    /// Adds `declared`. Of several declarations of one state, one that
98    /// holds it fixed wins, and otherwise the first made.
99    fn declare(&mut self, declared: Unknown) {
100        match self.0.get_mut(&declared.state) {
101            None => {
102                self.0.insert(declared.state.clone(), declared);
103            }
104            Some(kept) if declared.mobility == Mobility::Fixed => kept.mobility = Mobility::Fixed,
105            Some(_) => {}
106        }
107    }
108}
109
110/// The unknowns one step declared, in the order it made them: its target.
111#[derive(Clone, Debug, PartialEq)]
112struct StepUnknowns(Vec<Unknown>);
113
114/// Each step's own.
115impl Target for StepUnknowns {}
116
117/// One step's unknowns, read whole.
118impl Kind for StepUnknowns {
119    const NAME: &'static str = "step unknowns";
120}
121
122impl HasElements<StepUnknowns> for StepUnknowns {
123    type Element<'a> = &'a StepUnknowns;
124
125    fn element(&self, name: &str) -> GeopResult<&Self> {
126        match name.is_empty() {
127            true => Ok(self),
128            false => Err(GeopError::new(format!(
129                "a step's unknowns have no element `{name}`: they are read whole"
130            ))),
131        }
132    }
133}
134
135/// Declares the unknowns `generator` makes of `args` in the step being
136/// run, of the part's [`Unknowns`]: of several declarations of one state,
137/// one that holds it fixed wins, and otherwise the first made. A plain
138/// function, like a make ([`Make`]).
139pub fn declare_unknowns<Args: PartialEq + Clone + std::fmt::Debug + 'static>(
140    ctx: &mut StepContext,
141    args: &Args,
142    generator: Make<Args, Vec<Unknown>>,
143) -> GeopResult<()> {
144    let own = TargetReference::<StepUnknowns>::new(format!("{UNKNOWNS}:{}", ctx.step()));
145    let generated = Generated {
146        args: args.clone(),
147        generator,
148    };
149    ctx.produce(&own, &generated, declare)
150}
151
152/// The unknowns `generated` makes.
153fn declare<Args>(
154    reader: &Reader,
155    generated: &Generated<Args, Vec<Unknown>>,
156) -> GeopResult<StepUnknowns> {
157    Ok(StepUnknowns((generated.generator)(
158        reader,
159        &generated.args,
160    )?))
161}