reasoninglayer 1.0.3

Rust client SDK for the Reasoning Layer API
Documentation
//! Linear programming / optimization DTOs.
//!
//! These types live in the SDK layer — the backend itself performs optimization via inference
//! rules, so the server never sees the [`LinearProgramDefinition`] structure directly. The
//! [`OptimizeClient`](crate::OptimizeClient) compiles these into backward-chain calls.

use std::collections::BTreeMap;

use serde::{Deserialize, Serialize};

use super::terms::TermDto;

/// Direction for the optimization objective.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum OptimizationDirection {
    Maximize,
    Minimize,
}

/// Comparison operator for linear constraints.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ConstraintOperator {
    /// `<=`.
    Le,
    /// `>=`.
    Ge,
    /// `=`.
    Eq,
}

impl ConstraintOperator {
    pub fn as_str(&self) -> &'static str {
        match self {
            Self::Le => "<=",
            Self::Ge => ">=",
            Self::Eq => "=",
        }
    }
}

impl Serialize for ConstraintOperator {
    fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
        s.serialize_str(self.as_str())
    }
}

impl<'de> Deserialize<'de> for ConstraintOperator {
    fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
        let s = String::deserialize(d)?;
        match s.as_str() {
            "<=" => Ok(Self::Le),
            ">=" => Ok(Self::Ge),
            "=" => Ok(Self::Eq),
            other => Err(serde::de::Error::custom(format!(
                "unexpected constraint operator: {other}"
            ))),
        }
    }
}

/// Variable coefficients map: variable name → coefficient.
pub type LinearExpression = BTreeMap<String, f64>;

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct VariableBounds {
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub min: Option<f64>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub max: Option<f64>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LinearConstraint {
    pub coefficients: LinearExpression,
    pub op: ConstraintOperator,
    pub rhs: f64,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub label: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ObjectiveFunction {
    pub direction: OptimizationDirection,
    pub coefficients: LinearExpression,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LinearProgramDefinition {
    pub objective: ObjectiveFunction,
    #[serde(default)]
    pub constraints: Vec<LinearConstraint>,
    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
    pub bounds: BTreeMap<String, VariableBounds>,
}

#[derive(Debug, Clone, Default)]
pub struct SolveOptions {
    pub timeout_ms: Option<u64>,
    pub max_depth: Option<u32>,
    pub cleanup: Option<bool>,
}

/// LP optimization result.
#[derive(Debug, Clone)]
pub enum OptimizationResult {
    Optimal {
        variables: BTreeMap<String, f64>,
        objective_value: f64,
        solve_time_ms: u64,
    },
    Infeasible {
        solve_time_ms: u64,
    },
}

#[derive(Debug, Clone)]
pub struct KBVariableSpec {
    pub sort: String,
    pub name_feature: String,
}

#[derive(Debug, Clone)]
pub struct KBObjectiveSpec {
    pub direction: OptimizationDirection,
    pub coefficient_feature: String,
}

#[derive(Debug, Clone)]
pub struct KBResourceConstraint {
    pub cost_feature: String,
    pub op: Option<ConstraintOperator>,
    pub capacity: f64,
    pub label: Option<String>,
}

#[derive(Debug, Clone)]
pub struct KBOptimizationConfig {
    pub variables: KBVariableSpec,
    pub objective: KBObjectiveSpec,
    pub resource_constraints: Vec<KBResourceConstraint>,
    pub non_negative: bool,
    pub additional_constraints: Vec<LinearConstraint>,
}

#[derive(Debug, Clone)]
pub struct KBOptimizationResult {
    pub result: OptimizationResult,
    pub generated_problem: LinearProgramDefinition,
    pub discovered_terms: Vec<TermDto>,
}