use crate::cnf::CnfFormula;
use crate::decompose::{
BuildLimits, ConversionRequest, GoatdKnobs, GraphKind, SelectionCtx, TdConversion,
};
use crate::error::{VitriError, from_construction};
use super::{ParsedSpec, VtreeArtifacts, VtreeBase};
pub(super) fn conversion_request<'a>(
parsed: &'a ParsedSpec<'a>,
ctx: &SelectionCtx,
limits: &BuildLimits,
effort_scale: f64,
) -> ConversionRequest<'a> {
ConversionRequest {
spec: Some(parsed.base),
reading: parsed.reading,
effort_scale,
deadline: limits.deadline,
real_deadline: None,
trace: ctx.conversion.trace,
}
}
pub(super) fn build_vtree_elimination(
formula: &CnfFormula,
parsed: &ParsedSpec<'_>,
name: &'static str,
incidence: bool,
request: ConversionRequest<'_>,
) -> Result<TdConversion, VitriError> {
from_construction(
crate::decompose::vtree_from_elimination(
formula,
name,
incidence,
parsed.param.jw_sample(),
parsed.param.seed(),
request,
),
parsed,
)
}
pub(super) fn build_vtree_goatd(
formula: &CnfFormula,
parsed: &ParsedSpec<'_>,
incidence: bool,
knobs: GoatdKnobs,
request: ConversionRequest<'_>,
) -> Result<TdConversion, VitriError> {
let seed = parsed.param.seed();
let view = graph_kind(incidence);
let built = if parsed.param.refine() {
let index = parsed.param.candidate() as usize;
let knobs = GoatdKnobs {
candidates: parsed.param.candidate() + 1,
..knobs
};
crate::decompose::vtrees_from_goatd_refined(
formula, view, seed, None, knobs, false, request,
)
.and_then(|mut built| {
let found = built.len();
(built.len() > index)
.then(|| built.swap_remove(index))
.ok_or_else(|| {
format!(
"the schedule produced {found} decomposition(s), so there is no \
candidate {index}"
)
})
})
} else {
crate::decompose::vtree_from_goatd(formula, view, seed, request)
};
from_construction(built, parsed)
}
pub(super) fn build_vtree_flowcutter(
formula: &CnfFormula,
parsed: &ParsedSpec<'_>,
request: ConversionRequest<'_>,
) -> Result<TdConversion, VitriError> {
let kind = graph_kind(matches!(
parsed.family,
VtreeBase::Flowcutter { incidence: true }
));
let budget = parsed.param.fc_budget(parsed.base)?;
from_construction(
crate::decompose::flowcutter_vtree(formula, kind, budget, request),
parsed,
)
}
pub(super) fn build_vtree_guided_bisect(
formula: &CnfFormula,
parsed: &ParsedSpec<'_>,
request: ConversionRequest<'_>,
) -> Result<TdConversion, VitriError> {
let budget = parsed.param.fc_budget(parsed.base)?;
let built = crate::decompose::flowcutter_td(formula, GraphKind::Incidence, budget)
.and_then(|td| crate::decompose::guided_bisect_from_incidence_td(formula, &td, request));
from_construction(built, parsed)
}
pub(super) fn build_vtree_portfolio(
formula: &CnfFormula,
parsed: &ParsedSpec<'_>,
ctx: &SelectionCtx,
limits: &BuildLimits,
) -> Result<VtreeArtifacts, VitriError> {
crate::decompose::vtree_from_portfolio(
formula,
PORTFOLIO_STEPS,
PORTFOLIO_ITERS,
parsed.reading,
ctx,
limits,
)
}
fn graph_kind(incidence: bool) -> GraphKind {
if incidence {
GraphKind::Incidence
} else {
GraphKind::Primal
}
}
const PORTFOLIO_STEPS: i64 = 150_000;
const PORTFOLIO_ITERS: i32 = 15;