pub type Sym = String;
#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
#[error("line {line}: {message}")]
pub struct ParseError {
pub line: u32,
pub message: String,
}
impl ParseError {
pub fn new(line: u32, message: impl Into<String>) -> Self {
ParseError {
line,
message: message.into(),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Term {
Var(Sym),
Const(Sym),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum CompOp {
Lt,
Le,
Eq,
Ge,
Gt,
}
#[derive(Clone, Debug)]
pub enum Expr {
Num(f64),
Fluent(Sym, Vec<Term>),
Add(Box<Expr>, Box<Expr>),
Sub(Box<Expr>, Box<Expr>),
Mul(Box<Expr>, Box<Expr>),
Div(Box<Expr>, Box<Expr>),
Neg(Box<Expr>),
}
#[derive(Clone, Debug)]
pub enum Formula {
And(Vec<Formula>),
Or(Vec<Formula>),
Not(Box<Formula>),
Atom(Sym, Vec<Term>),
Comp(CompOp, Expr, Expr),
Forall(Vec<(Sym, Sym)>, Box<Formula>),
Exists(Vec<(Sym, Sym)>, Box<Formula>),
Eq(Term, Term),
Pref(Option<Sym>, Box<Formula>),
True,
False,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MetricDir {
Minimize,
Maximize,
}
#[derive(Clone, Debug)]
pub enum Constraint {
And(Vec<Constraint>),
Forall(Vec<(Sym, Sym)>, Box<Constraint>),
Pref(Option<Sym>, Box<Constraint>),
Always(Formula),
Sometime(Formula),
AtMostOnce(Formula),
SometimeAfter(Formula, Formula),
SometimeBefore(Formula, Formula),
AtEnd(Formula),
Within(f64, Formula),
AlwaysWithin(f64, Formula, Formula),
HoldDuring(f64, f64, Formula),
HoldAfter(f64, Formula),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum AssignOp {
Assign,
Increase,
Decrease,
ScaleUp,
ScaleDown,
}
#[derive(Clone, Debug)]
pub enum Effect {
Add(Sym, Vec<Term>),
Del(Sym, Vec<Term>),
Num(AssignOp, Sym, Vec<Term>, Expr),
And(Vec<Effect>),
When(Formula, Box<Effect>),
Forall(Vec<(Sym, Sym)>, Box<Effect>),
}
#[derive(Clone, Debug)]
pub struct Action {
pub name: Sym,
pub params: Vec<(Sym, Sym)>,
pub precond: Formula,
pub effect: Effect,
pub monitored: bool,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TimeSpec {
Start,
End,
All,
}
#[derive(Clone, Debug)]
pub struct Duration {
pub min: Option<Expr>,
pub max: Option<Expr>,
}
impl Duration {
pub fn fixed(e: Expr) -> Self {
Duration {
min: Some(e.clone()),
max: Some(e),
}
}
pub fn chosen(&self) -> Option<&Expr> {
self.min.as_ref().or(self.max.as_ref())
}
}
#[derive(Clone, Debug)]
pub struct DurativeAction {
pub name: Sym,
pub params: Vec<(Sym, Sym)>,
pub duration: Duration,
pub conditions: Vec<(TimeSpec, Formula)>,
pub effects: Vec<(TimeSpec, Effect)>,
}
#[derive(Clone, Debug)]
pub struct Domain {
pub name: Sym,
pub requirements: Vec<Sym>,
pub types: Vec<Sym>,
pub type_parent: Vec<(Sym, Sym)>,
pub constants: Vec<(Sym, Sym)>,
pub predicates: Vec<(Sym, Vec<Sym>)>,
pub functions: Vec<(Sym, Vec<Sym>)>,
pub actions: Vec<Action>,
pub durative_actions: Vec<DurativeAction>,
pub constraints: Vec<Constraint>,
pub derived: Vec<DerivedRule>,
pub monitors: Vec<Effect>,
}
#[derive(Clone, Debug)]
pub struct DerivedRule {
pub head: Sym,
pub params: Vec<(Sym, Sym)>,
pub body: Formula,
}
#[derive(Clone, Debug)]
pub struct TimedLiteral {
pub time: f64,
pub add: bool,
pub pred: Sym,
pub args: Vec<Sym>,
}
#[derive(Clone, Debug)]
pub struct Problem {
pub name: Sym,
pub domain_name: Sym,
pub objects: Vec<(Sym, Sym)>,
pub init_atoms: Vec<(Sym, Vec<Sym>)>,
pub init_fluents: Vec<((Sym, Vec<Sym>), f64)>,
pub til: Vec<TimedLiteral>,
pub goal: Formula,
pub constraints: Vec<Constraint>,
pub metric: Option<(MetricDir, Expr)>,
}
#[derive(Clone, Debug)]
pub enum NExpr {
Num(f64),
Fluent(u32),
Add(Box<NExpr>, Box<NExpr>),
Sub(Box<NExpr>, Box<NExpr>),
Mul(Box<NExpr>, Box<NExpr>),
Div(Box<NExpr>, Box<NExpr>),
Neg(Box<NExpr>),
}
impl NExpr {
pub fn collect_fluents(&self, out: &mut Vec<u32>) {
match self {
NExpr::Num(_) => {}
NExpr::Fluent(i) => out.push(*i),
NExpr::Neg(a) => a.collect_fluents(out),
NExpr::Add(a, b) | NExpr::Sub(a, b) | NExpr::Mul(a, b) | NExpr::Div(a, b) => {
a.collect_fluents(out);
b.collect_fluents(out);
}
}
}
pub fn eval(&self, fv: &[f64], def: &[bool]) -> Option<f64> {
Some(match self {
NExpr::Num(n) => *n,
NExpr::Fluent(i) => {
let i = *i as usize;
if !def[i] {
return None;
}
fv[i]
}
NExpr::Neg(a) => -a.eval(fv, def)?,
NExpr::Add(a, b) => a.eval(fv, def)? + b.eval(fv, def)?,
NExpr::Sub(a, b) => a.eval(fv, def)? - b.eval(fv, def)?,
NExpr::Mul(a, b) => a.eval(fv, def)? * b.eval(fv, def)?,
NExpr::Div(a, b) => a.eval(fv, def)? / b.eval(fv, def)?,
})
}
}
#[derive(Clone, Debug)]
pub struct NumPre {
pub op: CompOp,
pub lhs: NExpr,
pub rhs: NExpr,
}
#[derive(Clone, Debug)]
pub struct NumEff {
pub op: AssignOp,
pub target: u32,
pub value: NExpr,
}
pub fn eval_numpre(np: &NumPre, fv: &[f64], def: &[bool]) -> Option<bool> {
let l = np.lhs.eval(fv, def)?;
let r = np.rhs.eval(fv, def)?;
Some(match np.op {
CompOp::Lt => l < r,
CompOp::Le => l <= r,
CompOp::Eq => (l - r).abs() < 1e-6,
CompOp::Ge => l >= r,
CompOp::Gt => l > r,
})
}