Skip to main content

xlog_logic/
compiler_config.rs

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