use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
use smallvec::SmallVec;
use std::fmt;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConstraintIR {
pub version: u32,
pub variables: IndexMap<VarId, Variable>,
pub constraints: Vec<Constraint>,
pub objective: Option<Objective>,
pub theory_tags: SmallVec<[TheoryTag; 4]>,
}
impl ConstraintIR {
pub fn new() -> Self {
Self {
version: 1,
variables: IndexMap::new(),
constraints: Vec::new(),
objective: None,
theory_tags: SmallVec::new(),
}
}
pub fn add_variable(&mut self, var: Variable) -> VarId {
let id = VarId(self.variables.len());
self.variables.insert(id, var);
id
}
pub fn add_constraint(&mut self, constraint: Constraint) {
self.constraints.push(constraint);
}
pub fn set_objective(&mut self, objective: Objective) {
self.objective = Some(objective);
}
pub fn add_theory_tag(&mut self, tag: TheoryTag) {
if !self.theory_tags.contains(&tag) {
self.theory_tags.push(tag);
}
}
pub fn new_simple_test() -> Self {
let mut ir = Self::new();
let x = ir.add_variable(Variable {
name: "x".to_string(),
domain: Domain::Integer {
min: Some(0),
max: Some(100),
},
metadata: VariableMetadata::default(),
});
let y = ir.add_variable(Variable {
name: "y".to_string(),
domain: Domain::Integer {
min: Some(0),
max: Some(100),
},
metadata: VariableMetadata::default(),
});
ir.add_constraint(Constraint::Equal {
lhs: Expr::Binary {
op: BinaryOp::Add,
lhs: Box::new(Expr::Var(x)),
rhs: Box::new(Expr::Var(y)),
},
rhs: Expr::Const(ConstValue::Integer(10)),
});
ir.add_constraint(Constraint::Not {
constraint: Box::new(Constraint::Less {
lhs: Expr::Var(x),
rhs: Expr::Binary {
op: BinaryOp::Mul,
lhs: Box::new(Expr::Const(ConstValue::Integer(2))),
rhs: Box::new(Expr::Var(y)),
},
}),
});
ir.add_theory_tag(TheoryTag::LIA);
ir
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct VarId(pub usize);
impl fmt::Display for VarId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "v{}", self.0)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Variable {
pub name: String,
pub domain: Domain,
pub metadata: VariableMetadata,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Domain {
Boolean,
Integer { min: Option<i64>, max: Option<i64> },
Real { min: Option<f64>, max: Option<f64> },
BitVector { width: u32 },
String { max_length: Option<usize> },
Array {
element_type: Box<Domain>,
size: Option<usize>,
},
Enum { values: Vec<String> },
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct VariableMetadata {
pub description: Option<String>,
pub importance: f32, pub computation_cost: f32, }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Constraint {
Equal { lhs: Expr, rhs: Expr },
Less { lhs: Expr, rhs: Expr },
LessEqual { lhs: Expr, rhs: Expr },
And { constraints: Vec<Constraint> },
Or { constraints: Vec<Constraint> },
Not { constraint: Box<Constraint> },
Implies {
antecedent: Box<Constraint>,
consequent: Box<Constraint>,
},
Custom {
name: String,
params: IndexMap<String, Expr>,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Expr {
Var(VarId),
Const(ConstValue),
Binary {
op: BinaryOp,
lhs: Box<Expr>,
rhs: Box<Expr>,
},
Unary { op: UnaryOp, operand: Box<Expr> },
Call { function: String, args: Vec<Expr> },
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ConstValue {
Bool(bool),
Integer(i64),
Real(f64),
String(String),
BitVector { value: u64, width: u32 },
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum BinaryOp {
Add,
Sub,
Mul,
Div,
Mod,
Power, And,
Or,
Xor,
Equal,
NotEqual,
Less,
LessEqual,
Greater,
GreaterEqual,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum UnaryOp {
Not,
Negate, Sqrt, Abs, }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Objective {
pub goal: OptimizationGoal,
pub expr: Expr,
pub weight: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OptimizationGoal {
Minimize,
Maximize,
Satisfy, }
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum TheoryTag {
LIA,
LRA,
NLA,
BV,
Array,
String,
FP,
UF,
Quantified,
}
impl Default for ConstraintIR {
fn default() -> Self {
Self::new()
}
}