Skip to content

Commit

Permalink
feat(up): Add support for default values in up-problems.
Browse files Browse the repository at this point in the history
  • Loading branch information
arbimo committed Jan 16, 2024
1 parent a816e96 commit 22ff45c
Show file tree
Hide file tree
Showing 2 changed files with 163 additions and 17 deletions.
151 changes: 135 additions & 16 deletions planning/grpc/server/src/chronicles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ use aries::core::{IntCst, Lit, INT_CST_MAX, INT_CST_MIN};
use aries::model::extensions::Shaped;
use aries::model::lang::linear::LinearSum;
use aries::model::lang::*;
use aries::model::symbols::SymbolTable;
use aries::model::types::TypeHierarchy;
use aries::model::symbols::{SymId, SymbolTable};
use aries::model::types::{TypeHierarchy, TypeId};
use aries::utils::enumerate;
use aries::utils::input::Sym;
use aries_planning::chronicles::constraints::{Constraint, ConstraintType, Duration};
use aries_planning::chronicles::VarType::Reification;
use aries_planning::chronicles::*;
use aries_planning::parsing::pddl::TypedSymbol;
use env_param::EnvParam;
use itertools::Itertools;
use regex::Regex;
use std::collections::HashMap;
use std::convert::{TryFrom, TryInto};
Expand Down Expand Up @@ -218,7 +220,7 @@ pub fn problem_to_chronicles(problem: &Problem) -> Result<aries_planning::chroni

let mut factory = ChronicleFactory::new(&mut context, init_ch, Container::Base, vec![]);

factory.add_initial_state(&problem.initial_state)?;
factory.add_initial_state(&problem.initial_state, &problem.fluents)?;
factory.add_timed_effects(&problem.timed_effects)?;
factory.add_goals(&problem.goals)?;

Expand Down Expand Up @@ -325,7 +327,7 @@ fn scheduling_problem_to_chronicles(
// it must used as a context for all expression evaluations
let global_env = factory.env.clone();

factory.add_initial_state(&problem.initial_state)?;
factory.add_initial_state(&problem.initial_state, &problem.fluents)?;
factory.add_timed_effects(&problem.timed_effects)?;
factory.add_goals(&problem.goals)?;

Expand Down Expand Up @@ -358,6 +360,13 @@ struct ActionCosts {
default: Option<Expression>,
}

fn atom_to_symid(atom: &up::Atom, symbols: &SymbolTable) -> anyhow::Result<SymId> {
let Some(Content::Symbol(s)) = &atom.content else {
bail!("No symbolic content in atom: {atom:?}");
};
symbols.id(s).with_context(|| format!("Unknown symbol: {s:?}"))
}

fn str_to_symbol(name: &str, symbol_table: &SymbolTable) -> anyhow::Result<SAtom> {
let sym = symbol_table
.id(name)
Expand All @@ -384,6 +393,50 @@ fn read_atom(atom: &up::Atom, symbol_table: &SymbolTable) -> Result<aries::model
}
}

struct InitFact {
fluent: SymId,
params: Vec<SymId>,
value: Atom,
}

fn read_init_fact(fact: &up::Assignment, symbols: &SymbolTable) -> anyhow::Result<InitFact> {
let get_atom = |e: &up::Expression| {
let atom = e.atom.as_ref().with_context(|| format!("Not an atom: {e:?}"))?;
read_atom(atom, symbols)
};
let get_sym = |e: &up::Expression| {
let atom = e.atom.as_ref().with_context(|| format!("Not an atom: {e:?}"))?;
match atom.content.as_ref() {
Some(up::atom::Content::Symbol(s)) => symbols.id(s).with_context(|| format!("Unknown symbol: {:?}", s)),
_ => bail!("Not a symbol {:?}", e),
}
};
let Some(fluent) = fact.fluent.as_ref() else {
bail!("Malformed init fact: {fact:?}")
};

// first symbol as the fluent, the rest are the parameters
ensure!(fluent.list.len() > 0, "Malformed fluent expression: {fluent:?}");
let fluent_sym = atom_to_symid(
fluent.list[0]
.atom
.as_ref()
.with_context(|| format!("Missing fluent atom : {:?}", fluent))?,
symbols,
)?;
let params: Vec<SymId> = fluent.list[1..].iter().map(get_sym).try_collect()?;

let Some(value) = fact.value.as_ref() else {
bail!("Malformed init fact: {fact:?}")
};
let value = get_atom(value)?;
Ok(InitFact {
fluent: fluent_sym,
params,
value,
})
}

#[derive(Copy, Clone, Debug)]
struct Span {
start: Time,
Expand Down Expand Up @@ -565,20 +618,86 @@ impl<'a> ChronicleFactory<'a> {
}

/// Converts initial state to a set of effects at the start time
fn add_initial_state(&mut self, init_state: &[Assignment]) -> Result<(), Error> {
for assignment in init_state {
let state_var = assignment
.fluent
.as_ref()
.context("Initial state assignment has no valid fluent")?;
let value = assignment
.value
.as_ref()
.context("Initial state assignment has no valid value")?;
let init_time = Span::instant(self.chronicle.start);
fn add_initial_state(&mut self, init_state: &[Assignment], fluents: &[up::Fluent]) -> Result<(), Error> {
let mut explicit_init_facts = Vec::with_capacity(init_state.len());
for init_assignment in init_state {
explicit_init_facts.push(read_init_fact(init_assignment, &self.context.model.shape.symbols)?)
}

for up_fluent in fluents {
let symbols = self.context.model.get_symbol_table();
let fluent_sym = symbols
.id(&up_fluent.name)
.with_context(|| format!("Unknown symbol: {}", up_fluent.name))?;
let fluent = self
.context
.fluents
.iter()
.find(|f| f.sym == fluent_sym)
.with_context(|| format!("No such fluent: {}", up_fluent.name))?
.clone();

if let Some(default) = &up_fluent.default_value {
// fluent has a default value
let default = read_atom(
default
.atom
.as_ref()
.with_context(|| format!("Not an atom in default fluent value: {:?}", up_fluent))?,
symbols,
)?;

// gather all values that are explicitly set for this fluent
let mut explicit_values: HashMap<&[SymId], Atom> = Default::default();
for fact in &explicit_init_facts {
if fact.fluent == fluent_sym {
explicit_values.insert(&fact.params, fact.value);
}
}

self.add_effect(init_time, state_var, value, EffectKind::Assign)?;
// build an iterator over all combinations of values for the fluent's parameters
let arg_types: Vec<TypeId> = fluent
.argument_types()
.iter()
.map(|tpe| TypeId::try_from(*tpe))
.try_collect()
.context("unsupported non symbolic type in fluent parameters")?;
let arg_domains = arg_types.iter().map(|tpe| symbols.instances_of_type(*tpe)).collect();
use aries::utils::StreamingIterator;
let mut combinations = enumerate(arg_domains);

// for each possible instantiation of the fluent add an initial fact (with a default)
while let Some(comb) = combinations.next() {
let value = explicit_values.get(comb).unwrap_or(&default);
self.add_init_fact(fluent.clone(), comb, *value)?;
}
} else {
// no default value for fluent, only put the value explicitly stated
for explicit_fact in &explicit_init_facts {
if explicit_fact.fluent == fluent_sym {
self.add_init_fact(fluent.clone(), &explicit_fact.params, explicit_fact.value)?;
}
}
}
}

Ok(())
}

fn add_init_fact(&mut self, fluent: Arc<Fluent>, args: &[SymId], value: Atom) -> anyhow::Result<()> {
let args = args
.iter()
.map(|&sym| SAtom::new_constant(sym, self.context.model.get_symbol_table().type_of(sym)))
.collect();
let sv = StateVar { fluent, args };

self.chronicle.effects.push(Effect {
transition_start: self.context.origin(),
transition_end: self.context.origin(),
min_mutex_end: vec![],
state_var: sv,
operation: EffectOp::Assign(value),
});
Ok(())
}

Expand Down
29 changes: 28 additions & 1 deletion solver/src/model/types.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use crate::collections::id_map::IdMap;
use crate::collections::ref_store::RefPool;
use crate::model::lang::Type;
use crate::utils::input::Sym;
use std::borrow::Borrow;
use std::error::Error;
use std::fmt::{Debug, Formatter};
use std::fmt::{Debug, Display, Formatter};
use std::hash::Hash;

// Todo: use Ref
Expand All @@ -21,6 +22,32 @@ impl From<usize> for TypeId {
}
}

pub struct NotASymbolicType(Type);

impl Debug for NotASymbolicType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Not a symbolic type: {:?}", self.0)
}
}

impl Display for NotASymbolicType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{self:?}")
}
}
impl std::error::Error for NotASymbolicType {}

impl TryFrom<Type> for TypeId {
type Error = NotASymbolicType;

fn try_from(value: Type) -> Result<Self, Self::Error> {
match value {
Type::Sym(t) => Ok(t),
_ => Err(NotASymbolicType(value)),
}
}
}

#[derive(Clone)]
pub struct TypeHierarchy {
types: RefPool<TypeId, Sym>,
Expand Down

0 comments on commit 22ff45c

Please sign in to comment.