Skip to main content

xlog_logic/
compiler_config.rs

1//! Compile-time configuration for the W2.1 variable-ordering cost
2//! model.
3//!
4//! `CompilerConfig` is a per-call argument to
5//! [`crate::compile::Compiler::compile_with_config_and_stats_snapshot`].
6//! `CompilerConfig::default()` disables W2.1 — slice 1/2/4 + W2.2
7//! dispatch behavior is bit-identical when the default config is in
8//! effect.
9//!
10//! Activation requires explicitly constructing a `CompilerConfig`
11//! with [`WcojVarOrderingKind::LeaderCardinality`]. There is no
12//! environment override on this path; env-driven activation is out
13//! of W2.1 scope.
14//!
15//! # Threshold contract
16//!
17//! `wcoj_var_ordering_threshold` is `pub` to allow struct-literal
18//! construction, but the promoter MUST go through
19//! [`CompilerConfig::effective_wcoj_var_ordering_threshold`] so
20//! out-of-range struct-literal values fall back to
21//! [`CompilerConfig::DEFAULT_THRESHOLD`] rather than silently
22//! widening the gate.
23
24/// Selector for the W2.1 variable-ordering cost model.
25///
26/// `Disabled` is the load-bearing default: when set, the promoter
27/// never emits `RirNode::MultiWayJoin::var_order`, and slice
28/// 1/2/4/W2.2 dispatch + row-set semantics are bit-identical.
29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub enum WcojVarOrderingKind {
31    /// W2.1 disabled: promoter never sets `var_order`. Bit-identical
32    /// to slice 1/2/4 + W2.2.
33    Disabled,
34    /// Use the default `LeaderCardinalityModel` to pick a
35    /// stats-driven leader for triangle / 4-cycle WCOJ inputs.
36    LeaderCardinality,
37    /// W2.6: use `HeatAwareLeaderModel` — combines cardinality,
38    /// access heat, and observed join selectivity into a
39    /// composite score. Hot relations and rels in tight (low
40    /// selectivity) edges get demoted from the leader slot;
41    /// cold extensional rels are preferred as leader. Same
42    /// threshold gate as `LeaderCardinality` via
43    /// `effective_wcoj_var_ordering_threshold()`.
44    HeatAware,
45}
46
47/// Compile-time configuration for the W2.1 variable-ordering cost
48/// model.
49///
50/// See module docs for activation semantics + threshold contract.
51#[derive(Debug, Clone, PartialEq)]
52pub struct CompilerConfig {
53    /// Variable-ordering cost-model selector. Default `Disabled`.
54    pub wcoj_variable_ordering: WcojVarOrderingKind,
55
56    /// Raw threshold field. Public to keep struct-literal
57    /// construction available, but the promoter MUST NOT read this
58    /// field directly. Use
59    /// [`CompilerConfig::effective_wcoj_var_ordering_threshold`] so
60    /// out-of-range values are clamped at use, not silently honored.
61    pub wcoj_var_ordering_threshold: f64,
62}
63
64impl Default for CompilerConfig {
65    fn default() -> Self {
66        Self {
67            wcoj_variable_ordering: WcojVarOrderingKind::Disabled,
68            wcoj_var_ordering_threshold: Self::DEFAULT_THRESHOLD,
69        }
70    }
71}
72
73impl CompilerConfig {
74    /// Default ratio at or below which a leader candidate triggers
75    /// `var_order = Some(...)`. The gate fires on
76    /// `min_card / default_leader_card ≤ threshold`. A smaller
77    /// threshold demands a clearer win.
78    pub const DEFAULT_THRESHOLD: f64 = 0.5;
79
80    /// Resolve the threshold the promoter actually uses.
81    ///
82    /// Out-of-range values fall back to [`Self::DEFAULT_THRESHOLD`]:
83    /// * `NaN`
84    /// * non-finite (`±INFINITY`)
85    /// * `≤ 0.0` (would never fire — clamps to default to keep the
86    ///   gate honest)
87    /// * `> 1.0` (would always fire — clamps to default to prevent
88    ///   silent gate-disable via struct-literal)
89    pub fn effective_wcoj_var_ordering_threshold(&self) -> f64 {
90        let t = self.wcoj_var_ordering_threshold;
91        if !t.is_finite() || t <= 0.0 || t > 1.0 {
92            Self::DEFAULT_THRESHOLD
93        } else {
94            t
95        }
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    //! W2.1 step 4: 4 resolver unit tests pinning the
102    //! out-of-range fallback contract.
103    use super::*;
104
105    #[test]
106    fn default_threshold_is_half() {
107        let c = CompilerConfig::default();
108        assert_eq!(c.wcoj_var_ordering_threshold, 0.5);
109        assert_eq!(c.effective_wcoj_var_ordering_threshold(), 0.5);
110        assert_eq!(c.wcoj_variable_ordering, WcojVarOrderingKind::Disabled);
111    }
112
113    #[test]
114    fn resolver_passes_through_valid_in_range() {
115        let c = CompilerConfig {
116            wcoj_var_ordering_threshold: 0.3,
117            ..CompilerConfig::default()
118        };
119        assert_eq!(c.effective_wcoj_var_ordering_threshold(), 0.3);
120    }
121
122    #[test]
123    fn resolver_clamps_zero_and_negative_to_default() {
124        // `0.0` boundary: the gate would never fire — clamp.
125        let zero = CompilerConfig {
126            wcoj_var_ordering_threshold: 0.0,
127            ..CompilerConfig::default()
128        };
129        assert_eq!(
130            zero.effective_wcoj_var_ordering_threshold(),
131            CompilerConfig::DEFAULT_THRESHOLD
132        );
133        let neg = CompilerConfig {
134            wcoj_var_ordering_threshold: -0.5,
135            ..CompilerConfig::default()
136        };
137        assert_eq!(
138            neg.effective_wcoj_var_ordering_threshold(),
139            CompilerConfig::DEFAULT_THRESHOLD
140        );
141    }
142
143    #[test]
144    fn resolver_clamps_above_one_and_nonfinite_to_default() {
145        let above = CompilerConfig {
146            wcoj_var_ordering_threshold: 1.5,
147            ..CompilerConfig::default()
148        };
149        assert_eq!(
150            above.effective_wcoj_var_ordering_threshold(),
151            CompilerConfig::DEFAULT_THRESHOLD
152        );
153        let nan = CompilerConfig {
154            wcoj_var_ordering_threshold: f64::NAN,
155            ..CompilerConfig::default()
156        };
157        assert_eq!(
158            nan.effective_wcoj_var_ordering_threshold(),
159            CompilerConfig::DEFAULT_THRESHOLD
160        );
161        let inf = CompilerConfig {
162            wcoj_var_ordering_threshold: f64::INFINITY,
163            ..CompilerConfig::default()
164        };
165        assert_eq!(
166            inf.effective_wcoj_var_ordering_threshold(),
167            CompilerConfig::DEFAULT_THRESHOLD
168        );
169    }
170}