use crate as pr4xis;
use crate::ontology::{Axiom, Ontology, Quality};
pr4xis::ontology! {
name: "SituationCalculus",
source: "McCarthy (1963) Situations, Actions, and Causal Laws; McCarthy & Hayes (1969); Fikes & Nilsson (1971) STRIPS; Reiter (2001) Knowledge in Action; Bratman (1987) Intention, Plans, and Practical Reason; Russell & Norvig (2009) AI: A Modern Approach",
concepts: [
Situation,
Action,
Fluent,
Effect,
Precondition,
Postcondition,
ActionSchema,
AddList,
DeleteList,
InitialState,
Goal,
Plan,
Trace,
TraceEntry,
Transition,
FrameAxiom,
SuccessorStateAxiom,
Agent,
Belief,
Desire,
Intention,
],
labels: {
Situation: ("en", "Situation",
"McCarthy (1963): a snapshot of the world at a point in time — a state from which actions may be taken."),
Action: ("en", "Action",
"McCarthy (1963): a primitive event that transforms one situation into another. Has preconditions and effects."),
Fluent: ("en", "Fluent",
"McCarthy (1963): a state-valued property whose truth depends on the situation — 'at(x, loc)', 'holding(obj)', etc."),
Effect: ("en", "Effect",
"The change an action causes in a situation — what becomes true / false after the action."),
Precondition: ("en", "Precondition",
"A proposition that must hold in the current situation for the action to be applicable. Fikes & Nilsson (1971)."),
Postcondition: ("en", "Postcondition",
"A proposition that holds in the successor situation after the action is applied."),
ActionSchema: ("en", "Action schema",
"A parameterised action template — an action with variables filled in by substitution. Fikes & Nilsson (1971) STRIPS operators."),
AddList: ("en", "Add list",
"STRIPS: the set of fluents that become true when the action is applied. Fikes & Nilsson (1971)."),
DeleteList: ("en", "Delete list",
"STRIPS: the set of fluents that become false when the action is applied. Fikes & Nilsson (1971)."),
InitialState: ("en", "Initial state",
"The situation from which planning begins — the set of fluents true at time zero."),
Goal: ("en", "Goal",
"A description (partial or total) of the situation the plan aims to achieve. Fikes & Nilsson (1971)."),
Plan: ("en", "Plan",
"A sequence of actions that, applied from the initial state, achieves the goal. Russell & Norvig (2009) Ch. 10."),
Trace: ("en", "Trace",
"A recording of an execution — the sequence of situations and actions experienced. pr4xis-specific (engine/trace.rs)."),
TraceEntry: ("en", "Trace entry",
"A single step in a trace: the situation before, the action taken, the situation after, and whatever precondition verdicts were reached."),
Transition: ("en", "Transition",
"The move from one situation to another via an action. Reiter (2001) — the ternary relation Do(action, situation, successor)."),
FrameAxiom: ("en", "Frame axiom",
"McCarthy & Hayes (1969): an axiom specifying which fluents are UNCHANGED by an action — the frame problem is the problem of their number."),
SuccessorStateAxiom: ("en", "Successor-state axiom",
"Reiter (1991/2001): a compact solution to the frame problem — a single axiom per fluent specifying when it holds in the successor situation."),
Agent: ("en", "Agent",
"A reasoning entity that acts. Bratman (1987); Russell & Norvig Ch. 2."),
Belief: ("en", "Belief",
"The agent's information about the world — what it takes to be true. Bratman (1987)."),
Desire: ("en", "Desire",
"A state of the world the agent prefers. Bratman (1987)."),
Intention: ("en", "Intention",
"A commitment to a plan for achieving a desire. Bratman (1987) — intentions resist reconsideration."),
},
is_a: [
(Precondition, Effect),
(Postcondition, Effect),
(AddList, Effect),
(DeleteList, Effect),
(ActionSchema, Action),
(InitialState, Situation),
(Goal, Situation),
(SuccessorStateAxiom, FrameAxiom),
],
has_a: [
(Situation, Fluent),
(Action, Precondition),
(Action, Postcondition),
(Action, Effect),
(Action, AddList),
(Action, DeleteList),
(Plan, Action),
(Plan, InitialState),
(Plan, Goal),
(Trace, TraceEntry),
(TraceEntry, Transition),
(Transition, Situation),
(Transition, Action),
(Agent, Belief),
(Agent, Desire),
(Agent, Intention),
(Intention, Plan),
],
opposes: [
(AddList, DeleteList),
(DeleteList, AddList),
(Precondition, Postcondition),
(Postcondition, Precondition),
],
}
#[derive(Debug, Clone)]
pub struct SituationCalculusTradition;
impl Quality for SituationCalculusTradition {
type Individual = SituationCalculusConcept;
type Value = &'static str;
fn get(&self, c: &SituationCalculusConcept) -> Option<&'static str> {
use SituationCalculusConcept as S;
Some(match c {
S::Situation | S::Action | S::Fluent | S::Effect | S::Transition => "mccarthy-1963",
S::FrameAxiom => "mccarthy-hayes-1969",
S::SuccessorStateAxiom => "reiter-2001",
S::Precondition
| S::Postcondition
| S::ActionSchema
| S::AddList
| S::DeleteList
| S::InitialState
| S::Goal
| S::Plan => "fikes-nilsson-1971",
S::Trace | S::TraceEntry => "pr4xis-specific",
S::Agent | S::Belief | S::Desire | S::Intention => "bratman-1987",
})
}
}
impl Ontology for SituationCalculusOntology {
type Cat = SituationCalculusCategory;
type Qual = SituationCalculusTradition;
fn axioms() -> Vec<Box<dyn Axiom>> {
crate::ontology::reasoning::structural_axioms_for::<Self::Cat>()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::category::laws::assert_category_laws;
use crate::category::{Arrow, Category, FinitelyGenerated};
use proptest::prelude::*;
#[test]
fn category_laws() {
assert_category_laws::<SituationCalculusCategory>();
}
#[test]
fn ontology_validates() {
SituationCalculusOntology::validate()
.unwrap_or_else(|c| panic!("validation failed: {}", c.meta().description.as_str()));
}
#[test]
fn strips_operators_have_add_and_delete_lists() {
let parthood: Vec<_> = SituationCalculusCategory::morphisms()
.iter()
.filter(|m| m.kind() == SituationCalculusRelationKind::Parthood)
.map(|m| (m.source(), m.target()))
.collect();
assert!(parthood.contains(&(
SituationCalculusConcept::Action,
SituationCalculusConcept::AddList
)));
assert!(parthood.contains(&(
SituationCalculusConcept::Action,
SituationCalculusConcept::DeleteList
)));
}
#[test]
fn bdi_agent_has_belief_desire_intention() {
let parthood: Vec<_> = SituationCalculusCategory::morphisms()
.iter()
.filter(|m| m.kind() == SituationCalculusRelationKind::Parthood)
.map(|m| (m.source(), m.target()))
.collect();
for part in [
SituationCalculusConcept::Belief,
SituationCalculusConcept::Desire,
SituationCalculusConcept::Intention,
] {
assert!(
parthood.contains(&(SituationCalculusConcept::Agent, part)),
"Agent should have-a {:?}",
part
);
}
}
#[test]
fn successor_state_refines_frame_axiom() {
let sub: Vec<_> = SituationCalculusCategory::morphisms()
.iter()
.filter(|m| m.kind() == SituationCalculusRelationKind::Subsumption)
.map(|m| (m.source(), m.target()))
.collect();
assert!(sub.contains(&(
SituationCalculusConcept::SuccessorStateAxiom,
SituationCalculusConcept::FrameAxiom
)));
}
#[test]
fn every_concept_has_tradition() {
let q = SituationCalculusTradition;
for c in SituationCalculusConcept::variants() {
assert!(q.get(&c).is_some(), "{:?} missing tradition", c);
}
}
fn arb_concept() -> impl Strategy<Value = SituationCalculusConcept> {
proptest::sample::select(SituationCalculusConcept::variants())
}
proptest! {
#[test]
fn prop_tradition_total(c in arb_concept()) {
prop_assert!(SituationCalculusTradition.get(&c).is_some());
}
#[test]
fn prop_every_arrow_is_named(_seed in any::<u32>()) {
for m in SituationCalculusCategory::morphisms() {
prop_assert!(!m.meta().name.as_str().is_empty());
}
}
#[test]
fn prop_structural_axioms_hold(_seed in any::<u32>()) {
for axiom in SituationCalculusOntology::axioms() {
match axiom.verify() {
Ok(_) => {}
Err(c) => prop_assert!(
false,
"structural axiom failed: {}",
c.meta().name.as_str()
),
}
}
}
#[test]
fn prop_subsumption_targets_valid(_seed in any::<u32>()) {
let variants: Vec<_> = SituationCalculusConcept::variants();
for m in SituationCalculusCategory::morphisms() {
if m.kind() == SituationCalculusRelationKind::Subsumption {
prop_assert!(variants.contains(&m.source()));
prop_assert!(variants.contains(&m.target()));
}
}
}
}
}