pub struct Model {
pub categories: HashMap<CategoryId, Category>,
pub items: HashMap<ItemId, Item>,
pub measures: HashMap<MeasureId, Measure>,
pub inputs: HashMap<(MeasureId, Coordinate), Value>,
pub sql_sources: HashMap<MeasureId, SqlSource>,
pub views: HashMap<ViewId, View>,
pub external_fns: HashMap<String, ExternalFn>,
pub external_calls: HashMap<MeasureId, ExternalCall>,
pub scenarios: HashMap<ScenarioId, Scenario>,
pub lambdas: BTreeMap<u32, NamedLambda>,
}Expand description
The whole model: the multidimensional cube plus its raw input data.
Fields§
§categories: HashMap<CategoryId, Category>§items: HashMap<ItemId, Item>§measures: HashMap<MeasureId, Measure>§inputs: HashMap<(MeasureId, Coordinate), Value>Raw input data: (measure, coordinate) -> value. Only Input measures
have entries here; derived measures are computed by the engine.
Serialized as a sequence because JSON object keys must be strings and
this map is keyed by a (MeasureId, Coordinate) tuple.
sql_sources: HashMap<MeasureId, SqlSource>Metadata marking which input measures are backed by an external SQL
query (Phase 7). The measure’s kind stays Input — to the engine an
SQL measure is an ordinary input whose cells are (re)populated by
refreshing the query, so the deterministic core gains no SQL path. This
map records how to refresh; the actual query run lives in
improv_storage_sql.
views: HashMap<ViewId, View>Saved views: named pivot layouts over the model (parity with Improv/Quantrix “multiple views per model”). A view is presentation, not modeling — it does not change measures or data.
external_fns: HashMap<String, ExternalFn>External-language function definitions (Phase 6) available to formulas
via CALL(name, ...), keyed by name. Plain data; the improv_extfn
crate evaluates them. Marked non-deterministic-source-adjacent: the
engine treats a call as pure per the author’s purity assertion.
external_calls: HashMap<MeasureId, ExternalCall>Measures computed by calling an external function per coordinate over
argument measures (Phase 6). The measure’s kind stays Input; a
host-side refresh (in improv_engine::external) runs the function and
populates its cells — the engine’s dataflow gains no external-call path,
so its determinism is preserved.
scenarios: HashMap<ScenarioId, Scenario>What-if scenarios: named sets of input-cell overrides layered on the base model. First-class in the Improv sense — a scenario changes only which input values are fed to the engine, so evaluating “under” a scenario stays fully deterministic (the engine sees ordinary inputs).
lambdas: BTreeMap<u32, NamedLambda>Named LAMBDAs (Excel’s Name Manager functions): Margin = LAMBDA(p, c, (p - c) / p), called as Margin(Price, Cost) in any formula. A
call is stored by the lambda’s id (functions::named_lambda) and
expanded when compiled, so editing the lambda changes every use.
Implementations§
Source§impl Model
impl Model
pub fn new() -> Self
Sourcepub fn with_provisional(&self, id: MeasureId, name: &str) -> Cow<'_, Model>
pub fn with_provisional(&self, id: MeasureId, name: &str) -> Cow<'_, Model>
This model plus a provisional input measure id named name (when
no measure has the name), so a definition of a new measure can refer
to itself (Bal = PREV(Bal, Time, 1, 0) + Flow) while it is parsed.
Sourcepub fn lambda_by_name(&self, name: &str) -> Option<(u32, &NamedLambda)>
pub fn lambda_by_name(&self, name: &str) -> Option<(u32, &NamedLambda)>
The named LAMBDA called name (case-insensitive), with its id.
Sourcepub fn lambda_users(&self, id: u32) -> (Vec<u32>, Vec<MeasureId>)
pub fn lambda_users(&self, id: u32) -> (Vec<u32>, Vec<MeasureId>)
What calls named LAMBDA id, directly or through other lambdas: the
other lambdas’ ids and the derived measures, each sorted.
Sourcepub fn expand_lambdas(&self, e: &Expr) -> Result<Expr, String>
pub fn expand_lambdas(&self, e: &Expr) -> Result<Expr, String>
e with every named-LAMBDA call replaced by the lambda’s body, its
parameters bound to the call’s arguments (nested calls too). Errors
name an unknown lambda or a wrong argument count.
Sourcepub fn load_lambdas(&mut self, rows: &[(u32, String)]) -> Result<(), String>
pub fn load_lambdas(&mut self, rows: &[(u32, String)]) -> Result<(), String>
Add the named LAMBDAs stored as (id, definition) rows, each a JSON
NamedLambda or Name = LAMBDA(…) text. Text calls other lambdas
by name, and a redefined lambda may call one with a higher id, so the
text rows are parsed in passes until all are in. An error names the
row that never parsed.
pub fn add_category(&mut self, id: CategoryId, name: impl Into<String>)
pub fn add_item( &mut self, id: ItemId, category: CategoryId, name: impl Into<String>, )
pub fn add_measure(&mut self, m: Measure)
pub fn set_input(&mut self, measure: MeasureId, coord: Coordinate, value: Value)
pub fn input(&self, measure: MeasureId, coord: &Coordinate) -> Option<&Value>
Sourcepub fn measure_dependency_closure(
&self,
roots: &[MeasureId],
) -> HashSet<MeasureId>
pub fn measure_dependency_closure( &self, roots: &[MeasureId], ) -> HashSet<MeasureId>
The transitive closure of every measure roots depends on: for each
derived measure, its formula’s referenced_measures(); for an
external-call measure (Model.external_calls), its arg_measures.
Includes roots themselves. Storage-free, engine-free — a Model
loader (e.g. storage_mentat::ModelStore::load_partial) uses this to
load only the input cells an operation over roots actually needs,
instead of the whole model (see
.agent/steering/AGENT_OUT_OF_CORE_DESIGN.md §4).
Sourcepub fn measure_by_name(&self, name: &str) -> Option<&Measure>
pub fn measure_by_name(&self, name: &str) -> Option<&Measure>
Look up a measure by its human name.
Sourcepub fn category_by_name(&self, name: &str) -> Option<&Category>
pub fn category_by_name(&self, name: &str) -> Option<&Category>
Look up a category by its human name.
Sourcepub fn view_by_name(&self, name: &str) -> Option<&View>
pub fn view_by_name(&self, name: &str) -> Option<&View>
Look up a view by its human name.
Sourcepub fn add_scenario(&mut self, s: Scenario)
pub fn add_scenario(&mut self, s: Scenario)
Register a what-if scenario.
Sourcepub fn scenario_by_name(&self, name: &str) -> Option<&Scenario>
pub fn scenario_by_name(&self, name: &str) -> Option<&Scenario>
Look up a scenario by its human name.
Sourcepub fn with_scenario(&self, id: ScenarioId) -> Model
pub fn with_scenario(&self, id: ScenarioId) -> Model
Produce a model with a scenario’s input overrides applied on top of the
base inputs (overrides win). Structure, formulas, and every other input
are unchanged — only the overridden (measure, coordinate) cells differ,
so the returned model evaluates deterministically like any other. The
scenario set itself is cleared on the overlay (an overlay is a concrete
what-if world, not a base to re-branch). Returns the base model unchanged
if no scenario by that id exists.