domain tiago_hri_mdp {
    types { 
        obj : object;
        person : object;
        robot : object;
        waypoint : object;
    };

    pvariables {
        COST: {non-fluent, real, default = -1.0};
        TASK_REWARD : {non-fluent, real, default = 20};
        PROB_LOSING_LOCALISATION : {non-fluent, real, default = 0.0};                      
        PROB_NEED_ASSISTANCE(person) : {non-fluent, real, default = 0.1};                  
        PERSON_GOAL_OBJECT_AT(person, obj, waypoint) : {non-fluent, bool, default = false};
        PERSON_GOAL_OBJECT_WITH(person, obj, person) : {non-fluent, bool, default = false};
        PERSON_IS_AT(person, waypoint) : {non-fluent, bool, default = false};              
        
        robot_at(robot, waypoint) : {state-fluent, bool, default = false};
        localised(robot) : {state-fluent, bool, default = false};
        emptyhand(robot) : {state-fluent, bool, default = false};
        holding(robot, obj) : {state-fluent, bool, default = false};
        object_at(obj, waypoint) : {state-fluent, bool, default = false};
        object_with(obj, person) : {state-fluent, bool, default = false};
        goal_object_at(obj, waypoint) : {state-fluent, bool, default = false};
        goal_object_with(obj, person) : {state-fluent, bool, default = false};
        person_at(person, waypoint) : {state-fluent, bool, default = false};
        need_assistance(person) : {state-fluent, bool, default = false};
        needed_assistance(person) : {state-fluent, bool, default = false};
        reward_received(obj) : {state-fluent, bool, default = false};

        move(robot, waypoint, waypoint) : {action-fluent, bool, default = false};
        localise(robot) : {action-fluent, bool, default = false};
        find_person(robot, person) : {action-fluent, bool, default = false};
        talk_to_person(robot, person) : {action-fluent, bool, default = false};
        pick_up(robot, obj, waypoint) : {action-fluent, bool, default = false};
        put_down(robot, obj, waypoint) : {action-fluent, bool, default = false};
        take(robot, obj, person) : {action-fluent, bool, default = false};
        give(robot, obj, person) : {action-fluent, bool, default = false};
    };

    cpfs {
        robot_at'(?r, ?loc) = 
                if (exists_{?loc1: waypoint} [(move(?r, ?loc1, ?loc))]) then true
                else if (exists_{?loc1: waypoint} [(robot_at(?r, ?loc) ^ move(?r, ?loc, ?loc1))]) then false 
                else if (exists_{?p: person} [(find_person(?r, ?p) ^ PERSON_IS_AT(?p, ?loc))]) then true
                else if (exists_{?p: person, ?loc1: waypoint} [(find_person(?r, ?p) ^ PERSON_IS_AT(?p, ?loc1))]) then false
                else robot_at(?r, ?loc);

        localised'(?r) =
                if (localise(?r)) then true
                else if (~localised(?r)) then false
                else if (exists_{?loc1 : waypoint, ?loc2 : waypoint} [move(?r, ?loc1, ?loc2)]) then (Bernoulli (1 - PROB_LOSING_LOCALISATION))
                else if (exists_{?p: person} [find_person(?r, ?p)]) then (Bernoulli (1 - PROB_LOSING_LOCALISATION))
                else localised(?r);
        
        emptyhand'(?r) = 
                if (exists_{?o: obj, ?loc: waypoint} [pick_up(?r, ?o, ?loc)]) then false
                else if (exists_{?o: obj, ?loc: waypoint} [put_down(?r, ?o, ?loc)]) then true
                else if (exists_{?o: obj, ?p: person} [take(?r, ?o, ?p)]) then false
                else if (exists_{?o: obj, ?p: person} [give(?r, ?o, ?p)]) then true
                else emptyhand(?r);
        
        holding'(?r, ?o) =
                if (exists_{?loc: waypoint} [pick_up(?r, ?o, ?loc)]) then true
                else if (exists_{?loc: waypoint} [put_down(?r, ?o, ?loc)]) then false
                else if (exists_{?p: person} [take(?r, ?o, ?p)]) then true
                else if (exists_{?p: person} [give(?r, ?o, ?p)]) then false
                else holding(?r, ?o);
        
        object_at'(?o, ?loc) =
                if (exists_{?r: robot} [pick_up(?r, ?o, ?loc)]) then false
                else if (exists_{?r: robot} [put_down(?r, ?o, ?loc)]) then true
                else object_at(?o, ?loc);
        
        object_with'(?o, ?p) =
                if (exists_{?r: robot} [(take(?r, ?o, ?p))]) then false
                else if (exists_{?r: robot} [(give(?r, ?o, ?p))]) then true
                else object_with(?o, ?p);
        
        goal_object_at'(?o, ?loc) =
                if (exists_{?r: robot, ?p: person} [(need_assistance(?p) ^ talk_to_person(?r, ?p) ^ PERSON_GOAL_OBJECT_AT(?p, ?o, ?loc))]) then true
                else goal_object_at(?o, ?loc);
        
        goal_object_with'(?o, ?p) =
                if (exists_{?r: robot, ?p2: person} [(need_assistance(?p2) ^ talk_to_person(?r, ?p2) ^ PERSON_GOAL_OBJECT_WITH(?p2, ?o, ?p))]) then true
                else goal_object_with(?o, ?p);

        person_at'(?p, ?loc) = 
                if (exists_{?r: robot} [(find_person(?r, ?p) ^ PERSON_IS_AT(?p, ?loc))]) then true
                else person_at(?p, ?loc);

        need_assistance'(?p) = 
                if (~needed_assistance(?p) ^ ~need_assistance(?p)) then (Bernoulli (PROB_NEED_ASSISTANCE(?p)))
                else if (exists_{?r: robot} [(need_assistance(?p) ^ talk_to_person(?r, ?p))]) then false
                else need_assistance(?p);
        
        needed_assistance'(?p) = 
                if (exists_{?r: robot} [(need_assistance(?p) ^ talk_to_person(?r, ?p))]) then true
                else needed_assistance(?p);
        
        reward_received'(?o) =
                if (exists_{?loc: waypoint} [(object_at(?o, ?loc) ^ goal_object_at(?o, ?loc))]) then true
                else if (exists_{?p: person} [(object_with(?o, ?p) ^ goal_object_with(?o, ?p))]) then true
                else reward_received(?o);
    };

    reward = [sum_{?r: robot, ?loc1: waypoint, ?loc2: waypoint} [COST * move(?r, ?loc1, ?loc2)]] +
             [sum_{?r: robot} [COST * localise(?r)]] +
             [sum_{?r: robot, ?p: person} [COST * find_person(?r, ?p)]] +
             [sum_{?r: robot, ?p: person} [COST * talk_to_person(?r, ?p)]] +
             [sum_{?r: robot, ?o: obj, ?loc: waypoint} [COST * pick_up(?r, ?o, ?loc)]] +
             [sum_{?r: robot, ?o: obj, ?loc: waypoint} [COST * put_down(?r, ?o, ?loc)]] +
             [sum_{?r: robot, ?o: obj, ?p: person} [COST * take(?r, ?o, ?p)]] +
             [sum_{?r: robot, ?o: obj, ?p: person} [COST * give(?r, ?o, ?p)]] +
             [sum_{?o: obj} 
                 [ TASK_REWARD * (exists_{?loc: waypoint} [(~reward_received(?o) ^ object_at(?o, ?loc) ^ goal_object_at(?o, ?loc))]) +
                   TASK_REWARD * (exists_{?p: person, ?loc: waypoint} [(~reward_received(?o) ^ object_with(?o, ?p) ^ goal_object_with(?o, ?p))])
                 ]
             ];
    
    action-preconditions {
        forall_{?r: robot, ?loc1: waypoint, ?loc2: waypoint} [move(?r, ?loc1, ?loc2) => (robot_at(?r, ?loc1) ^ localised(?r))];
        forall_{?r: robot} [localise(?r) => (~localised(?r))];
        forall_{?r: robot, ?p: person} [find_person(?r, ?p) => (~(exists_{?loc: waypoint} [person_at(?p, ?loc)]) ^ localised(?r)) ];
        forall_{?r: robot, ?p: person} [talk_to_person(?r, ?p) => (exists_{?loc: waypoint} [(robot_at(?r, ?loc) ^ person_at(?p, ?loc))] ) ];
        forall_{?r: robot, ?o: obj, ?loc: waypoint} [pick_up(?r, ?o, ?loc) => (robot_at(?r, ?loc) ^ object_at(?o, ?loc) ^ emptyhand(?r) ^ ~goal_object_at(?o, ?loc)) ];
        forall_{?r: robot, ?o: obj, ?loc: waypoint} [put_down(?r, ?o, ?loc) => (robot_at(?r, ?loc) ^ holding(?r, ?o))];
        forall_{?r: robot, ?o: obj, ?p: person} [take(?r, ?o, ?p) => (exists_{?loc: waypoint} [(robot_at(?r, ?loc) ^ person_at(?p, ?loc) ^ emptyhand(?r) ^ object_with(?o, ?p) ^ ~goal_object_with(?o, ?p))] ) ];
        forall_{?r: robot, ?o: obj, ?p: person} [give(?r, ?o, ?p) => (exists_{?loc: waypoint} [(robot_at(?r, ?loc) ^ person_at(?p, ?loc) ^ holding(?r, ?o))] ) ];
    };
}