use std::sync::Arc;
use crate::vtree::Vtree;
mod best;
mod multilevel_bisect;
mod multilevel_hg_bisect;
pub(crate) use multilevel_hg_bisect::IMBALANCE_BALANCED;
mod force;
mod goatd;
mod hybrid;
pub(crate) use ::goatd::meter;
mod portfolio;
pub(crate) use force::{
ClauseWeight, ForceConfig, ForceMode, InitMode, MAX_DIM as FORCE_MAX_DIM, OrientRule, RootRule,
WeightRule, vtree_from_force,
};
pub(crate) use goatd::MAX_GOATD_CANDIDATES;
pub(crate) use goatd::vtree_from_goatd;
pub(crate) use goatd::vtrees_from_goatd_refined;
pub(crate) use goatd::{
INTERNAL_ELIMINATION_SEED, MINFILL_SPEC, VIEW_SUFFIXES, elimination_order_samples,
elimination_spec, elimination_spec_names, vtree_from_elimination, vtree_from_minfill,
};
pub(crate) use hybrid::guided_bisect_from_incidence_td;
pub(crate) use multilevel_bisect::vtree_from_primal_bisect;
pub(crate) use multilevel_hg_bisect::vtree_from_hg_bisect;
pub(crate) use portfolio::vtree_from_portfolio;
pub use ::goatd::decomposition::FlowCutterConfig as GoatdSeparatorConfig;
pub use goatd::{GoatdKnobs, GoatdLift, GoatdPolishing};
pub use portfolio::{
CandidatePreference, DEFAULT_SKIP, PairwiseWeighting, PortfolioBuildHistory, PortfolioKnobs,
TraceLevel,
};
pub use force::{Embedding, EmbeddingOptions, MAX_EMBEDDING_DIM, embed};
#[derive(Clone, Debug, PartialEq)]
pub struct SelectionCtx {
pub objective: SelectionObjective,
pub source_profile: Option<crate::score::StructureProfile>,
pub portfolio: PortfolioKnobs,
pub goatd: GoatdKnobs,
pub conversion: ConversionKnobs,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct ConversionKnobs {
pub trace: bool,
}
impl ConversionKnobs {
fn with_env_defaults(self) -> Result<Self, crate::error::VitriError> {
Ok(ConversionKnobs {
trace: crate::env::env_raw(
"VITRI_CONVERSION_TRACE",
"any value to trace every reading the conversion scores",
)?
.is_some()
|| self.trace,
})
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum SelectionObjective {
ClauseBalance,
PeakWidthAll,
PeakWidthShow(std::rc::Rc<crate::cnf::ShowMask>),
}
impl SelectionObjective {
pub fn is_peak(&self) -> bool {
!matches!(self, SelectionObjective::ClauseBalance)
}
pub fn show_mask(&self) -> Option<&crate::cnf::ShowMask> {
match self {
SelectionObjective::PeakWidthShow(mask) => Some(mask),
_ => None,
}
}
pub fn with_mask(&self, mask: Option<std::rc::Rc<crate::cnf::ShowMask>>) -> Self {
match (self, mask) {
(SelectionObjective::ClauseBalance, _) => SelectionObjective::ClauseBalance,
(_, Some(mask)) => SelectionObjective::PeakWidthShow(mask),
(_, None) => SelectionObjective::PeakWidthAll,
}
}
}
#[derive(Clone, Debug, Default)]
pub(crate) struct BuildLimits {
pub deadline: Option<std::time::Instant>,
pub budget_ms: Option<u64>,
pub candidates: usize,
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[non_exhaustive]
pub struct BuildLimitsReport {
pub truncated_builds: u32,
pub complete_builds: u32,
pub spent_ms: u64,
pub skipped: Vec<String>,
}
impl BuildLimitsReport {
pub(crate) fn absorb(&mut self, other: BuildLimitsReport) {
self.truncated_builds += other.truncated_builds;
self.complete_builds += other.complete_builds;
self.spent_ms += other.spent_ms;
self.skipped.extend(other.skipped);
}
}
pub(crate) const EMPTY_FORMULA: &str = "the formula has no variables";
impl SelectionCtx {
pub fn plain() -> Self {
SelectionCtx {
objective: SelectionObjective::ClauseBalance,
source_profile: None,
portfolio: PortfolioKnobs::default(),
goatd: GoatdKnobs::default(),
conversion: ConversionKnobs::default(),
}
}
pub fn peak() -> Self {
SelectionCtx {
objective: SelectionObjective::PeakWidthAll,
..Self::plain()
}
}
pub fn projected(mask: std::rc::Rc<crate::cnf::ShowMask>) -> Self {
SelectionCtx {
objective: SelectionObjective::PeakWidthShow(mask),
..Self::plain()
}
}
pub fn with_env_defaults(self) -> Result<Self, crate::error::VitriError> {
Ok(SelectionCtx {
portfolio: self.portfolio.with_env_defaults()?,
goatd: self.goatd.with_env_defaults()?,
conversion: self.conversion.with_env_defaults()?,
..self
})
}
pub fn with_show<S: crate::cnf::Space>(
self,
show: Option<&crate::cnf::ShowSet<S>>,
num_vars: u32,
) -> Self {
let objective = match show {
Some(s) => SelectionObjective::PeakWidthShow(std::rc::Rc::new(s.mask(num_vars))),
None => SelectionObjective::ClauseBalance,
};
SelectionCtx { objective, ..self }
}
pub fn for_show<S: crate::cnf::Space>(
show: Option<&crate::cnf::ShowSet<S>>,
num_vars: u32,
) -> Self {
Self::plain().with_show(show, num_vars)
}
}
mod flowcutter;
pub(crate) use flowcutter::{
FC_BARE_TIMEOUT_MS, FC_DEFAULT_ITERS, FC_DEFAULT_STEPS_ITERS, FC_PATIENCE_MS_BARE,
FC_PATIENCE_MS_PARAMETRIZED, FcBudget, WallCapMode, flowcutter_td, flowcutter_vtree,
};
mod td_to_vtree;
pub use td_to_vtree::{Binarization, Place, Reading, Root, td_to_vtree, td_to_vtree_reading};
pub(crate) use td_to_vtree::{BINARIZATIONS, ConversionRequest, PLACES, ROOTS, convert_td};
pub(crate) use td_to_vtree::TdConversionMeta;
pub(crate) struct TdConversion {
pub vtree: Arc<Vtree>,
pub td: TdConversionMeta,
}
impl TdConversion {
pub(crate) fn bare(vtree: Arc<Vtree>) -> Self {
TdConversion {
vtree,
td: TdConversionMeta::default(),
}
}
}
pub use td_to_vtree::BagMetadata;
mod td_parse;
pub use td_parse::{GraphKind, PaceGraph, TdBag, TreeDecomposition, parse_pace_td};
pub(crate) use td_parse::local_index;
mod bisect;
pub(crate) use bisect::{BisectDials, Bisection, BisectionSolver, run_bisection};
pub fn conditioned_primal_width_ub(
formula: &crate::cnf::CnfFormula,
conditioned: &[crate::cnf::VarId],
) -> Result<u32, crate::error::VitriError> {
let mut removed = vec![false; formula.num_vars as usize];
for v in conditioned {
let slot = removed.get_mut(v.idx()).ok_or_else(|| {
crate::error::VitriError::input(format!(
"conditioned variable {} is outside the formula's {} declared variables",
v.to_dimacs(),
formula.num_vars,
))
})?;
*slot = true;
}
let remaining: Vec<u32> = (0..formula.num_vars)
.filter(|&v| !removed[v as usize])
.collect();
if remaining.is_empty() {
return Ok(0);
}
let edges = td_parse::primal_edges_on_subset(formula, &remaining);
Ok(
goatd::minfill_td_from_edges(remaining.len() as u32, &edges, INTERNAL_ELIMINATION_SEED)
.treewidth(),
)
}