use itertools::izip;
use veripb_formula::prelude::*;
use veripb_propagator::propagation_engine::PropagationEngine;
use crate::{order::Order, prelude::*};
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
pub enum OrderVariableKind {
External = 0u8,
Mapped = 1u8,
Auxiliary = 2u8,
}
impl OrderVariableKind {
pub fn is_external(self) -> bool {
self as u8 == 0u8
}
pub fn is_mapped_or_auxiliary(self) -> bool {
self as u8 >= 1u8
}
pub fn is_auxiliary(self) -> bool {
self as u8 == 2u8
}
}
#[derive(Debug, Default)]
pub struct OrderContext {
pub name: String,
pub inside_vars: bool,
pub left_vars_defined: bool,
pub right_vars_defined: bool,
pub aux_vars_defined: bool,
pub inside_def: bool,
pub reflexivity_proven: bool,
pub transitivity_proven: bool,
pub constructed_order: Order,
pub stored_database: Box<Database>,
pub stored_prop_engine: Box<PropagationEngine>,
pub stored_elaborator_id: usize,
pub stored_active_order: Box<Option<ActiveOrder>>,
}
impl OrderContext {
#[inline]
pub fn new(
name: String,
database: Database,
prop_engine: PropagationEngine,
active_order: Option<ActiveOrder>,
) -> Self {
OrderContext {
name,
stored_database: Box::new(database),
stored_prop_engine: Box::new(prop_engine),
stored_active_order: Box::new(active_order),
..Default::default()
}
}
#[inline]
pub fn get_reflexivity_substitution(&self) -> Substitution {
let mut substitution = Substitution::with_size(self.constructed_order.left_vars.len());
for (&left, &right) in izip!(
self.constructed_order.left_vars.iter(),
self.constructed_order.right_vars.iter(),
) {
substitution.set(right, SubstitutionValue::lit(Lit::from_var(left, false)));
}
substitution
}
#[inline]
pub fn get_transitivity_substitution(
&self,
transitivity: &TransitivityContext,
) -> (Substitution, Substitution) {
let mut substitution_y_z = Substitution::with_size(
2 * self.constructed_order.left_vars.len() + self.constructed_order.aux_vars.len(),
);
let mut substitution_x_z = Substitution::with_size(
self.constructed_order.left_vars.len() + self.constructed_order.aux_vars.len(),
);
for (&left, &right, &fresh) in izip!(
self.constructed_order.left_vars.iter(),
self.constructed_order.right_vars.iter(),
transitivity.fresh_right.iter(),
) {
substitution_y_z.set(right, SubstitutionValue::lit(Lit::from_var(fresh, false)));
substitution_y_z.set(left, SubstitutionValue::lit(Lit::from_var(right, false)));
substitution_x_z.set(right, SubstitutionValue::lit(Lit::from_var(fresh, false)));
}
for (&aux, &fresh_aux_1, &fresh_aux_2) in izip!(
self.constructed_order.aux_vars.iter(),
transitivity.fresh_aux_1.iter(),
transitivity.fresh_aux_2.iter()
) {
substitution_y_z.set(
aux,
SubstitutionValue::lit(Lit::from_var(fresh_aux_1, false)),
);
substitution_x_z.set(
aux,
SubstitutionValue::lit(Lit::from_var(fresh_aux_2, false)),
);
}
(substitution_y_z, substitution_x_z)
}
pub fn autoprove_reflexivity(&self, elaborator: &mut Option<Elaborator>) -> bool {
let reflexivity_substitution = self.get_reflexivity_substitution();
for constraint in self.constructed_order.definition.iter() {
if !constraint
.substitute(&reflexivity_substitution)
.is_trivial()
{
return false;
}
}
if let Some(elaborator) = elaborator {
elaborator.writeln("\treflexivity\n\t\tproof");
for id in 1..=self.constructed_order.definition.len() {
elaborator.write("\t\t\tproofgoal #");
elaborator.writeln(&id.to_string());
let proofgoal_constraint_id = elaborator.inc_id();
elaborator.write("\t\t\tqed : ");
elaborator.write(&proofgoal_constraint_id.to_string());
elaborator.writeln(";");
}
elaborator.writeln("\t\tqed;\n\tend;");
}
true
}
pub fn autoprove_transitivity(&self) -> bool {
todo!()
}
}
#[derive(Debug, Default)]
pub struct TransitivityContext {
pub inside_vars: bool,
pub is_proven: bool,
pub fresh_right: Vec<VarIdx>,
pub fresh_aux_1: Vec<VarIdx>,
pub fresh_aux_2: Vec<VarIdx>,
}
#[derive(Debug, Default)]
pub struct ReflexivityContext {
pub is_proven: bool,
}
#[derive(Debug, Default)]
pub struct SpecificationContext {
pub stored_database: Box<Database>,
pub stored_prop_engine: Box<PropagationEngine>,
pub stored_elaborator_id: usize,
}
impl SpecificationContext {
#[inline]
pub fn new(database: Database, prop_engine: PropagationEngine) -> SpecificationContext {
SpecificationContext {
stored_database: Box::new(database),
stored_prop_engine: Box::new(prop_engine),
..Default::default()
}
}
}