use std::{num::Saturating, rc::Rc};
use ahash::AHashMap;
use colored::Colorize;
use malachite_bigint::BigInt;
use num_traits::Zero;
use veripb_formula::prelude::*;
use veripb_propagator::propagation_engine::PropagationEngine;
use crate::{
args::Args,
order_context::{OrderContext, ReflexivityContext, SpecificationContext, TransitivityContext},
prelude::*,
rules::ObjectiveUpdateType,
};
pub const CORE: usize = 0;
pub const DERIVED: usize = 1;
pub const AUTOPROVING: usize = 2;
pub const REQUIRED_RUP_STREAK: Saturating<u8> = Saturating(5);
#[derive(Debug)]
pub enum Subcontext {
Subproof(SubproofContext),
Order(OrderContext),
Transitivity(TransitivityContext),
Reflexivity(ReflexivityContext),
Specification(SpecificationContext),
}
impl Subcontext {
#[inline]
pub fn is_subproof(&self) -> bool {
matches!(self, Subcontext::Subproof(_))
}
}
#[derive(Debug, Default)]
pub struct Context {
pub args: Args,
pub var_names: VarNameManager,
pub original_constraints: Vec<Rc<DBConstraint>>,
pub objective: Option<PBObjective>,
pub best_valid_objective_value: Option<BigInt>,
pub best_objective_value: Option<BigInt>,
pub subcontexts: Vec<Subcontext>,
pub inside_strengthening_subproof: bool,
pub propagation_engine: PropagationEngine,
pub orders: AHashMap<String, Order>,
pub active_order: Option<ActiveOrder>,
pub rup_streak: Saturating<u8>,
pub annotated_rup_assignment: Assignment<BooleanVar>,
pub major_version: Option<u8>,
pub minor_version: Option<u8>,
pub has_output: bool,
pub has_conclusion: bool,
pub has_end_proof: bool,
pub assumption_used: bool,
pub elaborator: Option<Elaborator>,
pub current_level: Option<usize>,
pub level_ids: Vec<Vec<usize>>,
pub only_core: bool,
pub is_strengthening_to_core: bool,
}
impl Context {
pub fn new(args: Args, var_names: VarNameManager) -> Context {
Context {
args,
var_names,
propagation_engine: new_veripb_propagation_engine(),
rup_streak: REQUIRED_RUP_STREAK,
..Default::default()
}
}
pub fn update_objective(
&mut self,
mut objective_update: PBObjective,
update_type: ObjectiveUpdateType,
) {
match update_type {
ObjectiveUpdateType::New => self.objective = Some(objective_update),
ObjectiveUpdateType::Diff => {
let objective = self.objective.as_mut().unwrap();
objective.constant += objective_update.constant;
while let Some((var, term)) = objective_update.terms.pop_first() {
if let Some(existing_term) = objective.terms.get_mut(&var) {
objective.constant += existing_term.add_with(term);
if existing_term.coeff.is_zero() {
objective.terms.remove(&var);
}
} else {
objective.terms.insert(var, term);
}
}
}
}
if self.args.trace {
println!(
" {} updated to: {}",
"Objective".bright_green(),
self.objective
.as_ref()
.unwrap()
.to_pretty_string(&self.var_names)
.green()
);
}
}
}