use crate::bitset;
use crate::types::{eval_numpre, AssignOp, NumEff, NumPre};
#[derive(Clone, Debug, Default)]
pub struct CondEff {
pub cond_pos: Vec<u32>,
pub cond_neg: Vec<u32>,
pub cond_num: Vec<NumPre>,
pub add: Vec<u32>,
pub del: Vec<u32>,
pub num: Vec<NumEff>,
}
#[derive(Clone, Debug, Default)]
pub struct Csr<T> {
pub flat: Vec<T>,
pub off: Vec<u32>,
}
impl<T> Csr<T> {
pub fn slice(&self, i: usize) -> &[T] {
&self.flat[self.off[i] as usize..self.off[i + 1] as usize]
}
}
pub struct CsrBuilder<T> {
pub flat: Vec<T>,
pub off: Vec<u32>,
}
impl<T> Default for CsrBuilder<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> CsrBuilder<T> {
pub fn new() -> Self {
CsrBuilder {
flat: Vec::new(),
off: vec![0],
}
}
pub fn push_row(&mut self, items: impl IntoIterator<Item = T>) {
self.flat.extend(items);
self.off.push(self.flat.len() as u32);
}
pub fn finish(self) -> Csr<T> {
Csr {
flat: self.flat,
off: self.off,
}
}
}
pub struct PackedTask {
pub n_facts: usize,
pub words: usize,
pub n_ops: usize,
pub op_display: Vec<String>,
pub pre_pos: Csr<u32>,
pub add: Csr<u32>,
pub del: Csr<u32>,
pub pre_num: Csr<NumPre>,
pub num_eff: Csr<NumEff>,
pub cond: Csr<CondEff>,
pub add_by_fact: Csr<u32>,
pub neff_by_fluent: Csr<u32>,
pub relevant_fluent: Vec<bool>,
pub rel_fluents: Vec<u32>,
pub init_bits: Vec<u64>,
pub fv0: Vec<f64>,
pub fdef0: Vec<bool>,
pub goal_pos: Vec<u32>,
pub goal_num: Vec<NumPre>,
pub fact_names: Vec<String>,
pub fluent_names: Vec<String>,
pub n_easy: usize,
pub n_hard: usize,
pub n_reach_facts: usize,
pub n_reach_actions: usize,
pub n_relevant_fluents: usize,
}
impl PackedTask {
#[inline]
pub fn op_applicable(&self, oi: usize, s: &State) -> bool {
self.pre_pos
.slice(oi)
.iter()
.all(|&f| bitset::test(&s.bits, f as usize))
&& self
.pre_num
.slice(oi)
.iter()
.all(|np| eval_numpre(np, &s.fv, &s.fdef).unwrap_or(false))
}
#[inline]
fn cond_holds(&self, ce: &CondEff, s: &State) -> bool {
ce.cond_pos
.iter()
.all(|&f| bitset::test(&s.bits, f as usize))
&& ce
.cond_neg
.iter()
.all(|&f| !bitset::test(&s.bits, f as usize))
&& ce
.cond_num
.iter()
.all(|np| eval_numpre(np, &s.fv, &s.fdef).unwrap_or(false))
}
pub fn apply(&self, oi: usize, s: &State) -> State {
let mut ns = s.clone();
let conds = self.cond.slice(oi);
let firing: Vec<bool> = conds.iter().map(|ce| self.cond_holds(ce, s)).collect();
let mut deltas: Vec<(usize, AssignOp, f64)> = self
.num_eff
.slice(oi)
.iter()
.map(|ne| {
(
ne.target as usize,
ne.op,
ne.value.eval(&s.fv, &s.fdef).unwrap_or(0.0),
)
})
.collect();
for (ce, &fire) in conds.iter().zip(&firing) {
if fire {
for ne in &ce.num {
deltas.push((
ne.target as usize,
ne.op,
ne.value.eval(&s.fv, &s.fdef).unwrap_or(0.0),
));
}
}
}
for &f in self.del.slice(oi) {
bitset::clear(&mut ns.bits, f as usize);
}
for (ce, &fire) in conds.iter().zip(&firing) {
if fire {
for &f in &ce.del {
bitset::clear(&mut ns.bits, f as usize);
}
}
}
for &f in self.add.slice(oi) {
bitset::set(&mut ns.bits, f as usize);
}
for (ce, &fire) in conds.iter().zip(&firing) {
if fire {
for &f in &ce.add {
bitset::set(&mut ns.bits, f as usize);
}
}
}
for (t, aop, v) in deltas {
match aop {
AssignOp::Assign => {
ns.fv[t] = v;
ns.fdef[t] = true;
}
AssignOp::Increase => ns.fv[t] += v,
AssignOp::Decrease => ns.fv[t] -= v,
AssignOp::ScaleUp => ns.fv[t] *= v,
AssignOp::ScaleDown => ns.fv[t] /= v,
}
}
ns
}
pub fn fluent_id(&self, disp: &str) -> Option<usize> {
self.fluent_names.iter().position(|s| s == disp)
}
pub fn fact_id(&self, disp: &str) -> Option<usize> {
self.fact_names.iter().position(|s| s == disp)
}
pub fn initial(&self) -> State {
State {
bits: self.init_bits.clone(),
fv: self.fv0.clone(),
fdef: self.fdef0.clone(),
}
}
pub fn goal_met(&self, s: &State) -> bool {
self.goal_met_with(s, &self.goal_pos, &self.goal_num)
}
pub fn state_key(&self, s: &State) -> StateKey {
let vals: Vec<i64> = self
.rel_fluents
.iter()
.map(|&i| {
let i = i as usize;
if s.fdef[i] {
(s.fv[i] * 1e6).round() as i64
} else {
0
}
})
.collect();
StateKey {
bits: s.bits.clone(),
vals,
}
}
pub fn state_key_with_cost(&self, s: &State, cost_fluent: Option<usize>) -> StateKey {
let mut k = self.state_key(s);
if let Some(cf) = cost_fluent {
k.vals.push(if s.fdef[cf] {
(s.fv[cf] * 1e6).round() as i64
} else {
0
});
}
k
}
pub fn goal_met_with(&self, s: &State, goal_pos: &[u32], goal_num: &[NumPre]) -> bool {
goal_pos.iter().all(|&f| bitset::test(&s.bits, f as usize))
&& goal_num
.iter()
.all(|np| eval_numpre(np, &s.fv, &s.fdef).unwrap_or(false))
}
}
#[derive(Clone)]
pub struct State {
pub bits: Vec<u64>,
pub fv: Vec<f64>,
pub fdef: Vec<bool>,
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct StateKey {
pub bits: Vec<u64>,
pub vals: Vec<i64>,
}