use super::stage::{ArjunOutcome, arjun_stage};
use super::*;
use crate::cnf::{Original, ShowSet, WeightTable, Weights};
use crate::config::{ProjectionNoGain, ProjectionPolicy};
pub(super) fn projection_preserving_bundle(
formula: &CnfFormula,
meta: &CnfMeta,
config: &RunConfig,
mode: Mode,
) -> Result<PreprocessBundle, VitriError> {
let weighted = mode.is_weighted();
let orig_nv = formula.num_vars as usize;
let orig_show = meta
.declared_show_vars()
.expect("a projected mode requires a show set");
let orig_w = original_weights(meta, orig_nv, mode);
let weight_pairs: Vec<(i32, BigRational)> =
weight_table(meta, mode).map_or_else(Vec::new, WeightTable::to_literal_pairs);
let mut stages = StageReport::default();
let mut telemetry = PreprocessTelemetry::default();
let arjun_input = config.retain_arjun_input.then(|| formula.clone());
let arjun = projected_arjun_stage(
formula,
orig_show,
&weight_pairs,
config,
mode,
&mut stages,
&mut telemetry,
)?;
let arjun_map: Option<VarMap<Reduced, Reduced>> = arjun.var_map().cloned();
let (work, mut show_set, mut w, lift) = match arjun {
ProjArjun::Plain(a) => (
a.formula,
a.show,
Weights::empty(),
RecordLift::Pow2(a.multiplier_exp),
),
ProjArjun::Weighted(a) => (
a.formula,
a.show,
a.weights,
RecordLift::Weight(a.multiplier),
),
ProjArjun::Skipped => (
formula.clone(),
orig_show.clone().assume_reduced_identity(),
if weighted {
orig_w.clone().assume_reduced_identity()
} else {
Weights::empty()
},
RecordLift::neutral(),
),
};
let refutation_show = orig_show.clone().assume_reduced_identity();
if let Some(bundle) = refuted(
&work.clauses,
formula.num_vars,
mode,
Some(refutation_show.clone()),
stages.clone(),
telemetry,
) {
return Ok(bundle);
}
let ProjectedReduction {
formula: reduced,
show_set: reduced_show,
folds,
} = projection_tail(work, show_set, config.projection_policy, config.deadline);
if let Some(bundle) = refuted(
&reduced.clauses,
formula.num_vars,
mode,
Some(refutation_show),
stages.clone(),
telemetry,
) {
return Ok(bundle);
}
show_set = reduced_show;
if weighted {
w.fold_eliminated(&folds);
}
let reduced_num_vars = reduced.num_vars;
if weighted {
w.resize_neutral(reduced_num_vars as usize);
}
let reduced_to_original_dimacs = match &arjun_map {
Some(input_to_reduced) => input_to_reduced
.invert(reduced_num_vars)
.assume_original_target(),
None => VarMap::identity(reduced_num_vars),
};
let record = PreprocessRecord {
show_vars_reduced_dimacs: Some(show_set),
reduced_weights: weighted.then(|| w.to_record_rows()),
..PreprocessRecord::new(mode, lift, formula.num_vars, reduced_to_original_dimacs)
};
Ok(PreprocessBundle {
reduced,
record,
learnt_clauses_reduced_dimacs: Vec::new(),
stages,
count_lift: CountLift::default(),
telemetry,
decision_trace: None,
arjun_input,
independent_support_reduced: None,
})
}
pub(super) type ProjArjun = ArjunOutcome<ArjunProjResult, ArjunWeightedProjResult>;
pub(super) fn projection_tail(
formula: CnfFormula,
show_set: ShowSet<Reduced>,
policy: ProjectionPolicy,
deadline: Option<std::time::Instant>,
) -> ProjectedReduction {
match policy {
ProjectionPolicy::Full => strengthen_and_bve(&formula, show_set, deadline),
ProjectionPolicy::ArjunOnly(_) => ProjectedReduction {
formula,
show_set,
folds: Vec::new(),
},
}
}
pub(super) fn projection_gain_discard(
has_projection_gain: bool,
policy: ProjectionPolicy,
) -> Option<DiscardReason> {
let keep_without_gain = policy == ProjectionPolicy::ArjunOnly(ProjectionNoGain::KeepSound);
(!has_projection_gain && !keep_without_gain).then_some(DiscardReason::NoProjectionGain)
}
pub(super) fn projected_arjun_stage(
formula: &CnfFormula,
orig_show: &ShowSet<Original>,
weight_pairs: &[(i32, BigRational)],
config: &RunConfig,
mode: Mode,
report: &mut StageReport,
telemetry: &mut PreprocessTelemetry,
) -> Result<ProjArjun, VitriError> {
if mode.is_weighted() {
let ar = arjun_stage(
formula,
config,
report,
telemetry,
|budget, no_sbva| {
run_arjun_weighted_projected_anytime(
formula,
orig_show,
weight_pairs,
budget,
config.arjun,
no_sbva,
)
},
|ar| {
projection_gain_discard(
arjun_keep_reduction(ArjunKeep::weighted_projection_for(
orig_show.len(),
formula.num_vars,
ar,
)),
config.projection_policy,
)
},
)?;
Ok(ar.map_or(ProjArjun::Skipped, ProjArjun::Weighted))
} else {
let ar = arjun_stage(
formula,
config,
report,
telemetry,
|budget, no_sbva| {
run_arjun_projected_anytime(formula, orig_show, budget, config.arjun, no_sbva)
},
|ar| {
projection_gain_discard(
arjun_keep_reduction(ArjunKeep::projection_for(orig_show.len(), ar)),
config.projection_policy,
)
},
)?;
Ok(ar.map_or(ProjArjun::Skipped, ProjArjun::Plain))
}
}