use std::collections::HashMap;
use pyo3::prelude::*;
use super::config::{SolveConfig, SolveStats};
use crate::domain::bitset::BitsetDomain;
use crate::error::CspError;
use crate::{Csp as RustCsp, SolveConfig as RustSolveConfig};
#[pyclass(unsendable)]
pub struct Csp {
inner: RustCsp<BitsetDomain>,
}
#[pymethods]
impl Csp {
#[new]
fn new() -> Self {
Self {
inner: RustCsp::new(),
}
}
fn add_variable(&mut self, domain: Vec<u32>) -> u32 {
self.inner.add_variable(BitsetDomain::new(domain))
}
fn add_not_equal(&mut self, x: u32, y: u32) {
self.inner.add_not_equal(x, y);
}
fn add_all_different(&mut self, vars: Vec<u32>) {
self.inner.add_all_different(vars);
}
fn finalize(&mut self) {
self.inner.finalize();
}
fn propagate(&mut self, py: Python<'_>) -> PyResult<bool> {
let inner = &mut self.inner;
py.detach(|| inner.propagate())
.map(|()| true)
.map_err(|e| CspError::from(e).into())
}
fn solve(&mut self, py: Python<'_>, config: &SolveConfig) -> Vec<HashMap<u32, u32>> {
let rust_config: RustSolveConfig = config.into();
let inner = &mut self.inner;
py.detach(|| inner.solve(&rust_config))
.into_iter()
.map(|sol| {
sol.into_iter()
.enumerate()
.map(|(i, v)| (i as u32, v))
.collect()
})
.collect()
}
#[getter]
fn stats(&self) -> SolveStats {
let s = self.inner.stats();
SolveStats {
backtracks: s.backtracks,
nodes_explored: s.nodes_explored,
propagations: s.propagations,
budget_exceeded: s.budget_exceeded,
cancelled: s.cancelled,
}
}
}