miniplan 0.1.1

A PDDL planner library built around the pddl crate, with grounding and search utilities
Documentation
use pddl::{ActionDefinition, FluentExpression, FunctionHead, Optimization, Problem};
use pddl::{AssignOp, ConditionalEffect, PrimitiveEffect};

use crate::error::MiniplanError;

pub fn extract_action_cost(action: &ActionDefinition) -> Result<u32, MiniplanError> {
    let effects = match action.effect() {
        Some(e) => e,
        None => return Ok(1),
    };

    for ceffect in effects.iter() {
        if let ConditionalEffect::Effect(PrimitiveEffect::AssignNumericFluent(op, head, exp)) =
            ceffect
            && is_total_cost_increase(op, head)
            && let Some(val) = extract_numeric_value(exp)
        {
            return Ok(val);
        }
    }

    Ok(1)
}

fn is_total_cost_increase(op: &AssignOp, head: &FunctionHead) -> bool {
    if !matches!(op, AssignOp::Increase) {
        return false;
    }
    match head {
        FunctionHead::Simple(fs) => fs.to_string() == "total-cost",
        FunctionHead::WithTerms(fs, _) => fs.to_string() == "total-cost",
    }
}

fn extract_numeric_value(exp: &FluentExpression) -> Option<u32> {
    match exp {
        FluentExpression::Number(n) => {
            let val: f32 = **n;
            Some(val as u32)
        }
        _ => None,
    }
}

#[allow(dead_code)]
pub fn has_action_costs_metric(problem: &Problem) -> bool {
    if let Some(metric) = problem.metric_spec() {
        matches!(metric.optimization(), Optimization::Minimize)
    } else {
        false
    }
}