<commit_before>use std;
use std::collections::HashSet;
use std::marker::PhantomData;
use uuid::Uuid;

use constraints::Constraint;
use core::{Apply, Bindings, BindingsValue, ToSexp, Unify};

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum SubgoalUnificationIndex {
    Init,
    Actor(usize),
    Datum(usize),
    Exhausted,
}

impl std::fmt::Display for SubgoalUnificationIndex {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match *self {
            SubgoalUnificationIndex::Init => write!(f, "Init"),
            SubgoalUnificationIndex::Actor(idx) => write!(f, "Actor({})", idx),
            SubgoalUnificationIndex::Datum(idx) => write!(f, "Datum({})", idx),
            SubgoalUnificationIndex::Exhausted => write!(f, "Exhausted"),
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PlanParameters<T: BindingsValue> {
    pub bindings: Bindings<T>,
    pub constraints: Vec<Constraint<T>>,
    pub used_data: HashSet<usize>,
}

impl<T: BindingsValue> PlanParameters<T> {
    pub fn new(bindings: Bindings<T>, constraints: Vec<Constraint<T>>) -> Self {
        PlanParameters {
            bindings: bindings,
            constraints: constraints,
            used_data: HashSet::new(),
        }
    }

    pub fn solve_constraints(&self) -> Option<Bindings<T>> {
        Constraint::solve_many(self.constraints.iter().collect(), &self.bindings).ok()
    }
}

impl<T: BindingsValue> std::fmt::Display for PlanParameters<T> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        let constraints_vec: Vec<String> = self.constraints.iter().map(|constraint| constraint.to_sexp_string()).collect();
        write!(f,
               "(plan-parameters bindings: {}, constraints: {})",
               self.bindings,
               constraints_vec.join(","),
            )
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PlanningConfig {
    pub debug: bool,
    pub max_depth: usize,
    pub reuse_data: bool,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Subgoal<T: BindingsValue, U: Unify<T>, A: Apply<T, U>> {
    pub config: PlanningConfig,
    pub current_plan_parameters: PlanParameters<T>,
    pub pattern: U,
    pub subgoals: Vec<Subgoal<T, U, A>>,
    pub unification_index: SubgoalUnificationIndex,
    _marker: PhantomData<A>,
}

impl<T: BindingsValue, U: Unify<T>, A: Apply<T, U>> Subgoal<T, U, A> {
    pub fn new(pattern: U, initial_parameters: &PlanParameters<T>, config: PlanningConfig) -> Self {
        Subgoal {
            config: config,
            current_plan_parameters: initial_parameters.clone(),
            pattern: pattern,
            subgoals: Vec::new(),
            unification_index: SubgoalUnificationIndex::Init,
            _marker: PhantomData,
        }
    }

    fn increment_unification_index(&mut self, datum_count: usize, rule_count: usize) -> SubgoalUnificationIndex {
        let initial_rule_index = if rule_count > 0 {
            SubgoalUnificationIndex::Actor(0)
        } else {
            SubgoalUnificationIndex::Exhausted
        };

        let initial_datum_index = if datum_count > 0 {
            SubgoalUnificationIndex::Datum(0)
        } else {
            initial_rule_index.clone()
        };

        self.unification_index = match self.unification_index {
            SubgoalUnificationIndex::Exhausted => SubgoalUnificationIndex::Exhausted,
            SubgoalUnificationIndex::Init => initial_datum_index.clone(),
            SubgoalUnificationIndex::Datum(current_idx) => {
                if current_idx + 1 < datum_count {
                    SubgoalUnificationIndex::Datum(current_idx + 1)
                } else {
                    initial_rule_index
                }
            }
            SubgoalUnificationIndex::Actor(current_idx) => {
                if current_idx + 1 < rule_count {
                    SubgoalUnificationIndex::Actor(current_idx + 1)
                } else {
                    SubgoalUnificationIndex::Exhausted
                }
            }
        };
        self.unification_index.clone()
    }

    pub fn plan(&mut self, data: &Vec<&U>, rules: &Vec<&A>) -> Option<PlanParameters<T>> {
        let max_depth = self.config.max_depth.clone();
        self.sub_plan(data, rules, max_depth)
    }

    pub fn sub_plan(&mut self, data: &Vec<&U>, rules: &Vec<&A>, max_depth: usize) -> Option<PlanParameters<T>> {
        let initial_plan_parameters = self.current_plan_parameters.clone();
        loop {
            if self.increment_unification_index(data.len(), rules.len()) == SubgoalUnificationIndex::Exhausted {
                return None;
            }
            if let Some(plan_parameters) = self.satisfied(data, rules, max_depth) {
                if let Some(bindings) = plan_parameters.solve_constraints() {
                    return Some(PlanParameters {
                        bindings: bindings,
                        constraints: plan_parameters.constraints.clone(),
                        used_data: plan_parameters.used_data.clone(),
                    });
                }
            }
            // Reset parameters and try again
            self.current_plan_parameters = initial_plan_parameters.clone();
        }
    }

    pub fn can_use_datum(&self, idx: usize) -> bool {
        self.config.reuse_data || !self.current_plan_parameters.used_data.contains(&idx)
    }

    pub fn satisfied(&mut self, data: &Vec<&U>, rules: &Vec<&A>, max_depth: usize) -> Option<PlanParameters<T>> {
        if max_depth == 0 {
            return None;
        }

        match self.unification_index {
            SubgoalUnificationIndex::Datum(idx) => {
                if self.can_use_datum(idx) {
                    if let Some(bindings) = data[idx].unify(&self.pattern, &self.current_plan_parameters.bindings) {
                        self.current_plan_parameters = PlanParameters {
                            bindings: bindings,
                            constraints: self.current_plan_parameters.constraints.clone(),
                            used_data: self.current_plan_parameters.used_data.clone(),
                        };
                        self.current_plan_parameters.used_data.insert(idx);
                        Some(self.current_plan_parameters.clone())
                    } else {
                        None
                    }
                } else {
                    None
                }
            }
            SubgoalUnificationIndex::Actor(idx) => {
                let rule = rules[idx].snowflake(self.construct_snowflake_prefix());
                rule.r_apply(&self.pattern, &self.current_plan_parameters.bindings).and_then(|(subgoal_patterns, bindings)| {
                    let mut updated_constraints = self.current_plan_parameters.constraints.clone();<commit_msg>Logging in simplan<commit_after>use std;
use std::collections::HashSet;
use std::marker::PhantomData;
use uuid::Uuid;

use constraints::Constraint;
use core::{Apply, Bindings, BindingsValue, ToSexp, Unify};

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum SubgoalUnificationIndex {
    Init,
    Actor(usize),
    Datum(usize),
    Exhausted,
}

impl std::fmt::Display for SubgoalUnificationIndex {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match *self {
            SubgoalUnificationIndex::Init => write!(f, "Init"),
            SubgoalUnificationIndex::Actor(idx) => write!(f, "Actor({})", idx),
            SubgoalUnificationIndex::Datum(idx) => write!(f, "Datum({})", idx),
            SubgoalUnificationIndex::Exhausted => write!(f, "Exhausted"),
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PlanParameters<T: BindingsValue> {
    pub bindings: Bindings<T>,
    pub constraints: Vec<Constraint<T>>,
    pub used_data: HashSet<usize>,
}

impl<T: BindingsValue> PlanParameters<T> {
    pub fn new(bindings: Bindings<T>, constraints: Vec<Constraint<T>>) -> Self {
        PlanParameters {
            bindings: bindings,
            constraints: constraints,
            used_data: HashSet::new(),
        }
    }

    pub fn solve_constraints(&self) -> Option<Bindings<T>> {
        Constraint::solve_many(self.constraints.iter().collect(), &self.bindings).ok()
    }
}

impl<T: BindingsValue> std::fmt::Display for PlanParameters<T> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        let constraints_vec: Vec<String> = self.constraints.iter().map(|constraint| constraint.to_sexp_string()).collect();
        write!(f,
               "(plan-parameters bindings: {}, constraints: {})",
               self.bindings,
               constraints_vec.join(","),
            )
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PlanningConfig {
    pub debug: bool,
    pub max_depth: usize,
    pub reuse_data: bool,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Subgoal<T: BindingsValue, U: Unify<T>, A: Apply<T, U>> {
    pub config: PlanningConfig,
    pub current_plan_parameters: PlanParameters<T>,
    pub pattern: U,
    pub subgoals: Vec<Subgoal<T, U, A>>,
    pub unification_index: SubgoalUnificationIndex,
    _marker: PhantomData<A>,
}

impl<T: BindingsValue, U: Unify<T>, A: Apply<T, U>> Subgoal<T, U, A> {
    pub fn new(pattern: U, initial_parameters: &PlanParameters<T>, config: PlanningConfig) -> Self {
        Subgoal {
            config: config,
            current_plan_parameters: initial_parameters.clone(),
            pattern: pattern,
            subgoals: Vec::new(),
            unification_index: SubgoalUnificationIndex::Init,
            _marker: PhantomData,
        }
    }

    fn increment_unification_index(&mut self, datum_count: usize, rule_count: usize) -> SubgoalUnificationIndex {
        let initial_rule_index = if rule_count > 0 {
            SubgoalUnificationIndex::Actor(0)
        } else {
            SubgoalUnificationIndex::Exhausted
        };

        let initial_datum_index = if datum_count > 0 {
            SubgoalUnificationIndex::Datum(0)
        } else {
            initial_rule_index.clone()
        };

        self.unification_index = match self.unification_index {
            SubgoalUnificationIndex::Exhausted => SubgoalUnificationIndex::Exhausted,
            SubgoalUnificationIndex::Init => initial_datum_index.clone(),
            SubgoalUnificationIndex::Datum(current_idx) => {
                if current_idx + 1 < datum_count {
                    SubgoalUnificationIndex::Datum(current_idx + 1)
                } else {
                    initial_rule_index
                }
            }
            SubgoalUnificationIndex::Actor(current_idx) => {
                if current_idx + 1 < rule_count {
                    SubgoalUnificationIndex::Actor(current_idx + 1)
                } else {
                    SubgoalUnificationIndex::Exhausted
                }
            }
        };
        self.unification_index.clone()
    }

    pub fn plan(&mut self, data: &Vec<&U>, rules: &Vec<&A>) -> Option<PlanParameters<T>> {
        let max_depth = self.config.max_depth.clone();
        self.sub_plan(data, rules, max_depth)
    }

    pub fn sub_plan(&mut self, data: &Vec<&U>, rules: &Vec<&A>, max_depth: usize) -> Option<PlanParameters<T>> {
        let initial_plan_parameters = self.current_plan_parameters.clone();
        loop {
            if self.increment_unification_index(data.len(), rules.len()) == SubgoalUnificationIndex::Exhausted {
                return None;
            }
            if let Some(plan_parameters) = self.satisfied(data, rules, max_depth) {
                if let Some(bindings) = plan_parameters.solve_constraints() {
                    return Some(PlanParameters {
                        bindings: bindings,
                        constraints: plan_parameters.constraints.clone(),
                        used_data: plan_parameters.used_data.clone(),
                    });
                }
            }
            // Reset parameters and try again
            self.current_plan_parameters = initial_plan_parameters.clone();
        }
    }

    pub fn can_use_datum(&self, idx: usize) -> bool {
        self.config.reuse_data || !self.current_plan_parameters.used_data.contains(&idx)
    }

    pub fn satisfied(&mut self, data: &Vec<&U>, rules: &Vec<&A>, max_depth: usize) -> Option<PlanParameters<T>> {
        if max_depth == 0 {
            return None;
        }

        match self.unification_index {
            SubgoalUnificationIndex::Datum(idx) => {
                if self.can_use_datum(idx) {
                    self.log(max_depth,
                             format!("Trying to unify: {} with {}", self.pattern, data[idx]));
                    if let Some(bindings) = data[idx].unify(&self.pattern, &self.current_plan_parameters.bindings) {
                        self.log(max_depth, format!("\tunified!: {}", bindings));
                        self.current_plan_parameters = PlanParameters {
                            bindings: bindings,
                            constraints: self.current_plan_parameters.constraints.clone(),
                            used_data: self.current_plan_parameters.used_data.clone(),
                        };
                        self.current_plan_parameters.used_data.insert(idx);
                        Some(self.current_plan_parameters.clone())
                    } else {
                        None
                    }
                } else {
                    None
                }
            }
            SubgoalUnificationIndex::Actor(idx) => {
                let rule = rules[idx].snowflake(self.construct_snowflake_prefix());
                self.log(max_depth,
                         format!("Trying to apply: {}, {}", self.pattern, rule));
                rule.r_apply(&self.pattern, &self.current_plan_parameters.bindings).and_then(|(subgoal_patterns, bindings)| {
                    self.log(max_depth, format!("\tapplied!: {}", bindings));
                    let mut updated_constraints = self.current_plan_parameters.constraints.clone();
{'fraction_non_alphanumeric': 0.11870299418192139, 'fraction_numerical': 0.001277139208173691, 'mean_word_length': 2.1817155756207676, 'pattern_counts': {'":': 0, '<': 85, '<?xml version=': 0, '>': 125, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2588252', 'n_tokens_mistral': 4137, 'n_tokens_neox': 4007, 'n_words': 750}