Removed Candidates::None variant

This commit is contained in:
Andrey Tkachenko 2021-12-09 23:41:30 +04:00
parent d8323a144f
commit dc20c9aa76
2 changed files with 15 additions and 43 deletions

View File

@ -279,8 +279,8 @@ mod tests {
#[allow(clippy::identity_op, clippy::eq_op)] #[allow(clippy::identity_op, clippy::eq_op)]
fn test_ops() { fn test_ops() {
let mut puzzle = Puzzle::new(); let mut puzzle = Puzzle::new();
let x = puzzle.new_var(); let x = puzzle.new_var_with_range(10..=10);
let y = puzzle.new_var(); let y = puzzle.new_var_with_range(10..=10);
// expr = var + const; // expr = var + const;
let _ = x + 1; let _ = x + 1;
@ -337,8 +337,8 @@ mod tests {
#[allow(clippy::erasing_op, clippy::eq_op)] #[allow(clippy::erasing_op, clippy::eq_op)]
fn test_coef_zero() { fn test_coef_zero() {
let mut puzzle = Puzzle::new(); let mut puzzle = Puzzle::new();
let x = puzzle.new_var(); let x = puzzle.new_var_with_range(10..10);
let y = puzzle.new_var(); let y = puzzle.new_var_with_range(10..10);
let expr = x * 0; let expr = x * 0;
assert_eq!(expr.coef.len(), 0); assert_eq!(expr.coef.len(), 0);

View File

@ -11,15 +11,14 @@ use std::ops::RangeBounds;
use std::rc::Rc; use std::rc::Rc;
use crate::constraint; use crate::constraint;
use crate::Error;
use crate::{Constraint, PsResult, Solution, Val, VarToken};
use crate::linexpr::LinExpr; use crate::linexpr::LinExpr;
use crate::ranges::Ranges; use crate::ranges::Ranges;
use crate::Error;
use crate::{Constraint, PsResult, Solution, Val, VarToken};
/// A collection of candidates. /// A collection of candidates.
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
enum Candidates { enum Candidates {
None, // A variable with no candidates.
Value(Val), // A variable set to its initial value. Value(Val), // A variable set to its initial value.
Set(Rc<BTreeSet<Val>>), // A variable with a list of candidates. Set(Rc<BTreeSet<Val>>), // A variable with a list of candidates.
Range(Ranges), // A variable with candidate ranges. Range(Ranges), // A variable with candidate ranges.
@ -76,7 +75,6 @@ impl Candidates {
/// Count the number of candidates for a variable. /// Count the number of candidates for a variable.
fn len(&self) -> usize { fn len(&self) -> usize {
match self { match self {
Candidates::None => 0,
Candidates::Value(_) => 1, Candidates::Value(_) => 1,
Candidates::Set(ref rc) => rc.len(), Candidates::Set(ref rc) => rc.len(),
Candidates::Range(rc) => rc.len(), Candidates::Range(rc) => rc.len(),
@ -86,7 +84,6 @@ impl Candidates {
/// Get an iterator over all of the candidates of a variable. /// Get an iterator over all of the candidates of a variable.
fn iter(&self) -> Box<dyn Iterator<Item = Val> + '_> { fn iter(&self) -> Box<dyn Iterator<Item = Val> + '_> {
match self { match self {
Candidates::None => Box::new(iter::empty()),
Candidates::Value(val) => Box::new(iter::once(*val)), Candidates::Value(val) => Box::new(iter::once(*val)),
Candidates::Set(ref rc) => Box::new(rc.iter().cloned()), Candidates::Set(ref rc) => Box::new(rc.iter().cloned()),
Candidates::Range(range) => Box::new(range.iter()), Candidates::Range(range) => Box::new(range.iter()),
@ -113,19 +110,10 @@ impl Puzzle {
} }
} }
/// Allocate a new puzzle variable, without inserting any fn new_var(&mut self, candidates: Candidates) -> VarToken {
/// candidates.
///
/// # Examples
///
/// ```
/// let mut puzzle = puzzle_solver::Puzzle::new();
/// puzzle.new_var();
/// ```
pub fn new_var(&mut self) -> VarToken {
let var = VarToken(self.num_vars); let var = VarToken(self.num_vars);
self.num_vars += 1; self.num_vars += 1;
self.candidates.push(Candidates::None); self.candidates.push(candidates);
var var
} }
@ -139,9 +127,9 @@ impl Puzzle {
/// send_more_money.new_var_with_candidates(&[0,1,2,3,4,5,6,7,8,9]); /// send_more_money.new_var_with_candidates(&[0,1,2,3,4,5,6,7,8,9]);
/// ``` /// ```
pub fn new_var_with_candidates(&mut self, candidates: &[Val]) -> VarToken { pub fn new_var_with_candidates(&mut self, candidates: &[Val]) -> VarToken {
let var = self.new_var(); self.new_var(Candidates::Set(Rc::new(BTreeSet::from_iter(
self.insert_candidates(var, candidates); candidates.iter().copied(),
var ))))
} }
/// Allocate a new puzzle variable, initialising it with potential /// Allocate a new puzzle variable, initialising it with potential
@ -154,9 +142,10 @@ impl Puzzle {
/// send_more_money.new_var_with_candidates(&[0,1,2,3,4,5,6,7,8,9]); /// send_more_money.new_var_with_candidates(&[0,1,2,3,4,5,6,7,8,9]);
/// ``` /// ```
pub fn new_var_with_range<R: RangeBounds<Val>>(&mut self, range: R) -> VarToken { pub fn new_var_with_range<R: RangeBounds<Val>>(&mut self, range: R) -> VarToken {
let var = self.new_var(); self.new_var(Candidates::Range(Ranges::new(
self.insert_range(var, range); range.start_bound().cloned(),
var range.end_bound().cloned(),
)))
} }
/// Allocate a 1d vector of puzzle variables, each initialised to /// Allocate a 1d vector of puzzle variables, each initialised to
@ -285,11 +274,6 @@ impl Puzzle {
match self.candidates[idx] { match self.candidates[idx] {
Candidates::Value(_) => panic!("attempt to set fixed variable"), Candidates::Value(_) => panic!("attempt to set fixed variable"),
Candidates::Range(_) => panic!("attempt to insert candidates into range"), Candidates::Range(_) => panic!("attempt to insert candidates into range"),
Candidates::None => {
self.candidates[idx] = Candidates::Set(Rc::new(BTreeSet::new()));
}
Candidates::Set(_) => (), Candidates::Set(_) => (),
} }
@ -317,7 +301,6 @@ impl Puzzle {
let VarToken(idx) = var; let VarToken(idx) = var;
match self.candidates[idx] { match self.candidates[idx] {
Candidates::None => (),
Candidates::Value(_) => panic!("attempt to set fixed variable"), Candidates::Value(_) => panic!("attempt to set fixed variable"),
Candidates::Range(_) => panic!("attempt to remove candidates from range"), Candidates::Range(_) => panic!("attempt to remove candidates from range"),
Candidates::Set(ref mut rc) => { Candidates::Set(ref mut rc) => {
@ -346,7 +329,6 @@ impl Puzzle {
let VarToken(idx) = var; let VarToken(idx) = var;
match self.candidates[idx] { match self.candidates[idx] {
Candidates::None => (),
Candidates::Value(_) => panic!("attempt to set fixed variable"), Candidates::Value(_) => panic!("attempt to set fixed variable"),
Candidates::Range(_) => panic!("attempt to intersect candidates on the range"), Candidates::Range(_) => panic!("attempt to intersect candidates on the range"),
Candidates::Set(ref mut rc) => { Candidates::Set(ref mut rc) => {
@ -366,12 +348,6 @@ impl Puzzle {
let VarToken(idx) = var; let VarToken(idx) = var;
match self.candidates[idx] { match self.candidates[idx] {
ref mut x @ Candidates::None => {
*x = Candidates::Range(Ranges::new(
range.start_bound().cloned(),
range.end_bound().cloned(),
));
}
Candidates::Value(_) => panic!("attempt to set fixed variable"), Candidates::Value(_) => panic!("attempt to set fixed variable"),
Candidates::Range(ref mut r) => { Candidates::Range(ref mut r) => {
r.insert(range.start_bound().cloned(), range.end_bound().cloned()); r.insert(range.start_bound().cloned(), range.end_bound().cloned());
@ -653,7 +629,6 @@ impl<'a> PuzzleSearch<'a> {
match &self.vars[idx] { match &self.vars[idx] {
VarState::Assigned(val) => Ok((*val, *val)), VarState::Assigned(val) => Ok((*val, *val)),
VarState::Unassigned(ref cs) => match cs { VarState::Unassigned(ref cs) => match cs {
Candidates::None => Err(Error::Default),
Candidates::Value(val) => Ok((*val, *val)), Candidates::Value(val) => Ok((*val, *val)),
Candidates::Range(r) => r.get_bounds().ok_or(Error::Default), Candidates::Range(r) => r.get_bounds().ok_or(Error::Default),
Candidates::Set(ref rc) => rc Candidates::Set(ref rc) => rc
@ -676,7 +651,6 @@ impl<'a> PuzzleSearch<'a> {
match self.vars[idx] { match self.vars[idx] {
VarState::Assigned(v) => bool_to_result(v == val), VarState::Assigned(v) => bool_to_result(v == val),
VarState::Unassigned(ref mut cs) => match cs { VarState::Unassigned(ref mut cs) => match cs {
Candidates::None => Err(Error::Default),
Candidates::Value(v) => bool_to_result(*v == val), Candidates::Value(v) => bool_to_result(*v == val),
Candidates::Range(ref mut r) => { Candidates::Range(ref mut r) => {
if r.contains(val) { if r.contains(val) {
@ -711,7 +685,6 @@ impl<'a> PuzzleSearch<'a> {
match self.vars[idx] { match self.vars[idx] {
VarState::Assigned(v) => bool_to_result(v != val), VarState::Assigned(v) => bool_to_result(v != val),
VarState::Unassigned(ref mut cs) => match cs { VarState::Unassigned(ref mut cs) => match cs {
Candidates::None => Err(Error::Default),
Candidates::Value(v) => bool_to_result(*v != val), Candidates::Value(v) => bool_to_result(*v != val),
Candidates::Range(r) => { Candidates::Range(r) => {
if r.contains(val) { if r.contains(val) {
@ -753,7 +726,6 @@ impl<'a> PuzzleSearch<'a> {
} }
VarState::Unassigned(ref mut cs) => match cs { VarState::Unassigned(ref mut cs) => match cs {
Candidates::None => Err(Error::Default),
Candidates::Value(v) => { Candidates::Value(v) => {
if min <= *v && *v <= max { if min <= *v && *v <= max {
Ok((*v, *v)) Ok((*v, *v))