use super::*;
pub(super) fn simplify_outcome(config: &RunConfig) -> StageOutcome {
if config.stages.simplify {
StageOutcome::Ran
} else {
StageOutcome::Skipped(SkipReason::NotRequested)
}
}
pub(super) fn arjun_skipped(formula: &CnfFormula, config: &RunConfig) -> Option<SkipReason> {
if !config.stages.arjun {
diag!("c note: skipping arjun (stage disabled)");
return Some(SkipReason::NotRequested);
}
if formula.num_vars == 0 {
diag!("c note: skipping arjun (nothing left to reduce)");
return Some(SkipReason::NothingToDo);
}
None
}
pub(super) trait ArjunReduction {
fn reduced_formula(&self) -> &CnfFormula;
fn var_map(&self) -> &VarMap<Reduced, Reduced>;
}
macro_rules! impl_arjun_reduction {
($($result:ty),+ $(,)?) => {$(
impl ArjunReduction for $result {
fn reduced_formula(&self) -> &CnfFormula {
&self.formula
}
fn var_map(&self) -> &VarMap<Reduced, Reduced> {
&self.input_to_reduced_lit
}
}
)+};
}
impl_arjun_reduction!(
ArjunResult,
ArjunProjResult,
ArjunWeightedProjResult,
ArjunWeightedResult,
);
pub(super) enum ArjunOutcome<P, W> {
Plain(P),
Weighted(W),
Skipped,
}
impl<P: ArjunReduction, W: ArjunReduction> ArjunOutcome<P, W> {
fn kept(&self) -> Option<&dyn ArjunReduction> {
match self {
ArjunOutcome::Plain(a) => Some(a),
ArjunOutcome::Weighted(a) => Some(a),
ArjunOutcome::Skipped => None,
}
}
pub(super) fn reduced_formula(&self) -> Option<&CnfFormula> {
self.kept().map(ArjunReduction::reduced_formula)
}
pub(super) fn var_map(&self) -> Option<&VarMap<Reduced, Reduced>> {
self.kept().map(ArjunReduction::var_map)
}
}
pub(super) fn arjun_stage<R: ArjunReduction>(
formula: &CnfFormula,
config: &RunConfig,
report: &mut StageReport,
telemetry: &mut PreprocessTelemetry,
run: impl FnOnce(std::time::Duration, bool) -> Result<Option<R>, VitriError>,
discard_reason: impl FnOnce(&R) -> Option<DiscardReason>,
) -> Result<Option<R>, VitriError> {
if let Some(why) = arjun_skipped(formula, config) {
report.arjun = Some(StageOutcome::Skipped(why));
return Ok(None);
}
let no_sbva = no_sbva(formula, config);
report.sbva = Some(if no_sbva {
StageOutcome::Skipped(SkipReason::NotRequested)
} else {
StageOutcome::Ran
});
let started = std::time::Instant::now();
let result = run(arjun_budget(config), no_sbva);
telemetry.arjun_ms = Some(started.elapsed().as_millis() as u64);
let Some(ar) = result? else {
diag!("c note: skipping arjun (no result inside its budget)");
report.arjun = Some(StageOutcome::GaveUp);
return Ok(None);
};
if let Some(why) = discard_reason(&ar)
&& !(why == DiscardReason::NotSmaller
&& config.arjun_clause_growth == crate::config::ArjunClauseGrowth::KeepSound)
{
diag!("c note: discarding the arjun reduction ({})", why.phrase());
report.arjun = Some(StageOutcome::Discarded(why));
return Ok(None);
}
if !ar.var_map().is_injective(ar.reduced_formula().num_vars) {
let why = DiscardReason::NonInjectiveMap;
diag!("c note: discarding the arjun reduction ({})", why.phrase());
report.arjun = Some(StageOutcome::Discarded(why));
return Ok(None);
}
report.arjun = Some(StageOutcome::Ran);
Ok(Some(ar))
}
pub(super) fn no_sbva(formula: &CnfFormula, config: &RunConfig) -> bool {
crate::preprocess::arjun::arjun_sbva_skip(formula, config.arjun.sbva)
}
pub(super) fn arjun_budget(config: &RunConfig) -> std::time::Duration {
let budget = match config.arjun_budget {
crate::config::ArjunBudget::Derived => {
std::time::Duration::from_millis(crate::budget::arjun_budget_ms(config.budget_ms))
}
crate::config::ArjunBudget::Exact(duration) => duration,
};
crate::budget::clamp(budget, config.deadline)
}