From 66a7bfa03eded38e7c37955150479e670aef5e08 Mon Sep 17 00:00:00 2001 From: Yirmandias Date: Fri, 13 Oct 2023 15:47:19 +0200 Subject: [PATCH] increase and decrease support integer variables --- planning/grpc/server/src/chronicles.rs | 6 +-- planning/planners/src/encode.rs | 44 ++++++++++++++------ planning/planning/src/chronicles/concrete.rs | 20 ++++++--- planning/planning/src/chronicles/printer.rs | 9 +++- planning/planning/src/parsing/mod.rs | 2 +- 5 files changed, 57 insertions(+), 24 deletions(-) diff --git a/planning/grpc/server/src/chronicles.rs b/planning/grpc/server/src/chronicles.rs index 1aee3ecb..354eae15 100644 --- a/planning/grpc/server/src/chronicles.rs +++ b/planning/grpc/server/src/chronicles.rs @@ -536,12 +536,12 @@ impl<'a> ChronicleFactory<'a> { let operation = match kind { EffectKind::Assign => EffectOp::Assign(value), EffectKind::Increase => { - let value = IntCst::try_from(value).context("Increase effect require a constant value.")?; + let value = IAtom::try_from(value).context("Increase effect require an integer value.")?; EffectOp::Increase(value) } EffectKind::Decrease => { - let value = IntCst::try_from(value).context("Decrease effect require a constant value.")?; - EffectOp::Increase(-value) + let value = IAtom::try_from(value).context("Decrease effect require an integer value.")?; + EffectOp::Decrease(value) } }; self.chronicle.effects.push(Effect { diff --git a/planning/planners/src/encode.rs b/planning/planners/src/encode.rs index b08f7e8e..302f5d54 100644 --- a/planning/planners/src/encode.rs +++ b/planning/planners/src/encode.rs @@ -785,7 +785,9 @@ pub fn encode(pb: &FiniteProblem, metric: Option) -> std::result::Result } // skip if it's two increases - if matches!(e1.operation, EffectOp::Increase(_)) && matches!(e2.operation, EffectOp::Increase(_)) { + if matches!(e1.operation, EffectOp::Increase(_) | EffectOp::Decrease(_)) + && matches!(e2.operation, EffectOp::Increase(_) | EffectOp::Decrease(_)) + { continue; } @@ -847,7 +849,9 @@ pub fn encode(pb: &FiniteProblem, metric: Option) -> std::result::Result if !unifiable_sv(&solver.model, &cond.state_var, &eff.state_var) { continue; } - let EffectOp::Assign(effect_value) = eff.operation else { unreachable!() }; + let EffectOp::Assign(effect_value) = eff.operation else { + unreachable!() + }; if !solver.model.unifiable(cond.value, effect_value) { continue; } @@ -976,7 +980,7 @@ pub fn encode(pb: &FiniteProblem, metric: Option) -> std::result::Result .iter() .filter(|(_, prez, eff)| { !solver.model.entails(!*prez) - && matches!(eff.operation, EffectOp::Increase(_)) + && matches!(eff.operation, EffectOp::Increase(_) | EffectOp::Decrease(_)) && is_integer(&eff.state_var) }) .collect(); @@ -988,8 +992,12 @@ pub fn encode(pb: &FiniteProblem, metric: Option) -> std::result::Result // Force the new assigned values to be in the state variable domain. for &&(_, prez, eff) in &assignments { - let Type::Int { lb, ub } = eff.state_var.fluent.return_type() else { unreachable!() }; - let EffectOp::Assign(val) = eff.operation else { unreachable!() }; + let Type::Int { lb, ub } = eff.state_var.fluent.return_type() else { + unreachable!() + }; + let EffectOp::Assign(val) = eff.operation else { + unreachable!() + }; let val: IAtom = val.try_into().expect("Not integer assignment to an int state variable"); solver.enforce(geq(val, lb), [prez]); solver.enforce(leq(val, ub), [prez]); @@ -1122,9 +1130,13 @@ pub fn encode(pb: &FiniteProblem, metric: Option) -> std::result::Result .implies(prez_cond, solver.model.presence_literal(li_lit.variable()))); // Get the `ci_j*` value. - let EffectOp::Increase(eff_val) = eff.operation else { unreachable!() }; - let ci: IAtom = eff_val.into(); - (li_lit, ci) + let (ci, sign) = match eff.operation { + EffectOp::Increase(eff_val) => (eff_val, 1), + EffectOp::Decrease(eff_val) => (eff_val, -1), + _ => unreachable!(), + }; + // let ci: IAtom = eff_val.into(); + (li_lit, ci, sign) }) .collect::>() }) @@ -1135,8 +1147,12 @@ pub fn encode(pb: &FiniteProblem, metric: Option) -> std::result::Result // Create the sum. let mut sum = LinearSum::zero(); sum += LinearSum::with_lit(ca, la); - for &(li, ci) in li_ci.iter() { - sum += LinearSum::with_lit(ci, li); + for &(li, ci, sign) in li_ci.iter() { + match sign { + -1 => sum -= LinearSum::with_lit(ci, li), + 1 => sum += LinearSum::with_lit(ci, li), + _ => unreachable!(), + } } let cond_val = IAtom::try_from(cond.value).expect("Condition value is not numeric for a numeric fluent"); @@ -1229,7 +1245,9 @@ fn create_la_vector_without_timepoints( .implies(prez_cond, solver.model.presence_literal(la_lit.variable()))); // Get the `ca_j` variable. - let EffectOp::Assign(eff_val) = eff.operation else { unreachable!() }; + let EffectOp::Assign(eff_val) = eff.operation else { + unreachable!() + }; let ca = IAtom::try_from(eff_val).expect("Try to assign a non-numeric value to a numeric fluent"); // Get the persistence timepoint of the effect `e_j`. @@ -1279,7 +1297,9 @@ fn create_la_vector_with_timepoints( .implies(prez_cond, solver.model.presence_literal(la_lit.variable()))); // Get the `ca_j` variable. - let EffectOp::Assign(eff_val) = eff.operation else { unreachable!() }; + let EffectOp::Assign(eff_val) = eff.operation else { + unreachable!() + }; let ca = IAtom::try_from(eff_val).expect("Try to assign a non-numeric value to a numeric fluent"); // Get the persistence timepoint of the effect `e_j`. diff --git a/planning/planning/src/chronicles/concrete.rs b/planning/planning/src/chronicles/concrete.rs index d41bbd17..c49c55b0 100644 --- a/planning/planning/src/chronicles/concrete.rs +++ b/planning/planning/src/chronicles/concrete.rs @@ -293,7 +293,8 @@ pub struct Effect { #[derive(Clone, Copy, Eq, PartialEq)] pub enum EffectOp { Assign(Atom), - Increase(IntCst), + Increase(IAtom), + Decrease(IAtom), } impl EffectOp { pub const TRUE_ASSIGNMENT: EffectOp = EffectOp::Assign(Atom::TRUE); @@ -305,11 +306,11 @@ impl Debug for EffectOp { EffectOp::Assign(val) => { write!(f, ":= {val:?}") } - EffectOp::Increase(val) if *val >= 0 => { - write!(f, "+= {val:?}") - } EffectOp::Increase(val) => { - write!(f, "-= {}", -val) + write!(f, "+= {:?}", val) + } + EffectOp::Decrease(val) => { + write!(f, "-= {:?}", val) } } } @@ -352,9 +353,15 @@ impl Substitute for EffectOp { match self { EffectOp::Assign(val) => EffectOp::Assign(substitution.sub(*val)), EffectOp::Increase(val) => { - let x: IntCst = *val; // guard: this will need substitution when val becomes a variable + let x = substitution.sub(Atom::from(*val)).try_into().unwrap(); + //let x: IntCst = *val; // guard: this will need substitution when val becomes a variable EffectOp::Increase(x) } + EffectOp::Decrease(val) => { + let x = substitution.sub(Atom::from(*val)).try_into().unwrap(); + //let x: IntCst = *val; // guard: this will need substitution when val becomes a variable + EffectOp::Decrease(x) + } } } } @@ -552,6 +559,7 @@ impl Chronicle { match eff.operation { EffectOp::Assign(x) => vars.add_atom(x), EffectOp::Increase(x) => vars.add_atom(x), + EffectOp::Decrease(x) => vars.add_atom(x), } vars.add_sv(&eff.state_var) } diff --git a/planning/planning/src/chronicles/printer.rs b/planning/planning/src/chronicles/printer.rs index 42755ec1..cfdecf51 100644 --- a/planning/planning/src/chronicles/printer.rs +++ b/planning/planning/src/chronicles/printer.rs @@ -142,10 +142,15 @@ impl<'a> Printer<'a> { match op { EffectOp::Assign(value) => { print!(" := "); - self.atom(*value) + self.atom(*value); } EffectOp::Increase(i) => { - print!(" += {i}") + print!(" += "); + self.atom((*i).into()); + } + EffectOp::Decrease(i) => { + print!(" -= "); + self.atom((*i).into()); } } } diff --git a/planning/planning/src/parsing/mod.rs b/planning/planning/src/parsing/mod.rs index 997b7e60..402b51b8 100644 --- a/planning/planning/src/parsing/mod.rs +++ b/planning/planning/src/parsing/mod.rs @@ -250,7 +250,7 @@ fn read_init( if closed_world { // closed world, every predicate that is not given a true value should be given a false value // to do this, we rely on the classical classical planning state - let state_desc = World::new(context.model.get_symbol_table().deref().clone(), &context.fluents)?; + let state_desc = World::new(context.model.get_symbol_table().clone(), &context.fluents)?; let mut s = state_desc.make_new_state(); for init in initial_facts { let pred = read_sv(init, &state_desc)?;