use std::sync::Arc;
use crate::cnf::CnfFormula;
use crate::decompose::{BuildLimits, SelectionCtx};
use crate::error::{VitriError, from_construction};
use crate::vtree::Vtree;
mod builders;
mod parse;
use builders::{
build_vtree_elimination, build_vtree_flowcutter, build_vtree_goatd, build_vtree_guided_bisect,
build_vtree_portfolio, conversion_request,
};
use parse::unknown_vtree_type;
pub(crate) use parse::{
BALANCED_SPEC, ParsedSpec, VtreeBase, parse_vtree_spec, spec_has_candidates, spec_string,
};
pub use parse::{SpecParamDoc, spec_param_docs, validate_vtree_spec, vtree_spec_bases};
#[cfg(test)]
pub(crate) use parse::{SpecParam, classify_base};
pub const DEFAULT_VTREE_SPEC: &str = "portfolio";
pub fn elimination_spec_names() -> impl Iterator<Item = &'static str> {
crate::decompose::elimination_spec_names()
}
pub fn decomposition_spec_names() -> impl Iterator<Item = &'static str> {
parse::decomposition_spec_names()
}
pub fn baseline_spec_names() -> impl Iterator<Item = &'static str> {
parse::baseline_spec_names()
}
pub fn standalone_spec_names() -> impl Iterator<Item = &'static str> {
parse::standalone_spec_names()
}
#[derive(Clone, Debug, Default)]
pub struct SelectionRecord {
pub winning_spec: Option<String>,
pub scores: Option<crate::score::VtreeScores>,
pub td_meta: Option<Arc<crate::decompose::BagMetadata>>,
}
#[derive(Clone)]
pub(crate) struct VtreeArtifacts {
pub vtree: Arc<Vtree>,
pub selection: SelectionRecord,
pub candidate_set: crate::candidates::CandidateSet,
pub limits: crate::decompose::BuildLimitsReport,
}
impl VtreeArtifacts {
fn bare(vtree: Arc<Vtree>, spec: &ParsedSpec<'_>) -> Self {
VtreeArtifacts {
vtree,
selection: SelectionRecord {
winning_spec: Some(spec.to_string()),
scores: None,
td_meta: None,
},
candidate_set: crate::candidates::CandidateSet::default(),
limits: crate::decompose::BuildLimitsReport::default(),
}
}
fn from_td(built: crate::decompose::TdConversion, spec: &ParsedSpec<'_>) -> Self {
VtreeArtifacts {
vtree: built.vtree,
selection: SelectionRecord {
winning_spec: Some(spec.to_string()),
scores: None,
td_meta: built.td.meta,
},
candidate_set: crate::candidates::CandidateSet::default(),
limits: crate::decompose::BuildLimitsReport::default(),
}
}
}
#[derive(Clone, Copy)]
pub(crate) struct BuildRequest<'a> {
pub formula: &'a CnfFormula,
pub spec: &'a ParsedSpec<'a>,
pub ctx: &'a SelectionCtx,
pub limits: &'a BuildLimits,
}
pub(crate) fn build_one_vtree_artifacts(
req: BuildRequest<'_>,
) -> Result<VtreeArtifacts, VitriError> {
let BuildRequest {
formula,
spec: parsed,
ctx,
limits,
} = req;
let num_vars = formula.num_vars;
let effort_scale = crate::budget::vtree_effort_scale(limits.budget_ms);
let request = conversion_request(parsed, ctx, limits, effort_scale);
match parsed.family {
VtreeBase::Balanced => Ok(VtreeArtifacts::bare(
Arc::new(Vtree::balanced(num_vars)),
parsed,
)),
VtreeBase::Linear => Ok(VtreeArtifacts::bare(
Arc::new(Vtree::linear(num_vars)),
parsed,
)),
VtreeBase::ReverseLinear => Ok(VtreeArtifacts::bare(
Arc::new(Vtree::reverse_linear(num_vars)),
parsed,
)),
VtreeBase::Random => Ok(VtreeArtifacts::bare(
Arc::new(Vtree::random(num_vars, 0)),
parsed,
)),
VtreeBase::Goatd { incidence } => {
build_vtree_goatd(formula, parsed, incidence, ctx.goatd, request)
.map(|b| VtreeArtifacts::from_td(b, parsed))
}
VtreeBase::Flowcutter { .. } => build_vtree_flowcutter(formula, parsed, request)
.map(|b| VtreeArtifacts::from_td(b, parsed)),
VtreeBase::GuidedBisect => build_vtree_guided_bisect(formula, parsed, request)
.map(|b| VtreeArtifacts::from_td(b, parsed)),
VtreeBase::Portfolio => build_vtree_portfolio(formula, parsed, ctx, limits),
VtreeBase::Elimination { name, incidence } => {
build_vtree_elimination(formula, parsed, name, incidence, request)
.map(|b| VtreeArtifacts::from_td(b, parsed))
}
VtreeBase::HypergraphBisect | VtreeBase::PrimalBisect => {
let dials = crate::decompose::BisectDials {
imbalance: parsed.param.imbalance(),
base_seed: 0,
effort_scale,
};
let built = if parsed.family == VtreeBase::PrimalBisect {
crate::decompose::vtree_from_primal_bisect(formula, dials)
} else {
crate::decompose::vtree_from_hg_bisect(formula, dials)
};
from_construction(built, parsed).map(|v| VtreeArtifacts::bare(v, parsed))
}
VtreeBase::Force => {
let cfg = parsed.param.force();
from_construction(crate::decompose::vtree_from_force(formula, cfg), parsed)
.map(|v| VtreeArtifacts::bare(v, parsed))
}
VtreeBase::Unknown => Err(unknown_vtree_type(parsed.raw)),
}
}