Skip to content

Commit

Permalink
Prepare the prune table and IDFS for genericization.
Browse files Browse the repository at this point in the history
  • Loading branch information
lgarron committed Oct 18, 2024
1 parent c7e5469 commit d671a15
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 50 deletions.
4 changes: 2 additions & 2 deletions src/rs/_internal/search/check_pattern.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use cubing::kpuzzle::KPattern;

pub trait CheckPattern {
pub trait PatternValidityChecker {
fn is_valid(pattern: &KPattern) -> bool;
}

pub struct AlwaysValid;

impl CheckPattern for AlwaysValid {
impl PatternValidityChecker for AlwaysValid {
fn is_valid(_pattern: &KPattern) -> bool {
true
}
Expand Down
17 changes: 9 additions & 8 deletions src/rs/_internal/search/idf_search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ use serde::{Deserialize, Serialize};

use crate::_internal::{
cli::options::{Generators, MetricEnum},
CanonicalFSM, CanonicalFSMState, MoveClassIndex, PruneTable, RecursiveWorkTracker, SearchError,
SearchGenerators, SearchLogger, CANONICAL_FSM_START_STATE,
CanonicalFSM, CanonicalFSMState, HashPruneTable, MoveClassIndex, RecursiveWorkTracker,
SearchError, SearchGenerators, SearchLogger, CANONICAL_FSM_START_STATE,
};

use super::{CheckPattern, KPatternStack};
use super::{AlwaysValid, KPatternStack, PatternValidityChecker};

const MAX_SUPPORTED_SEARCH_DEPTH: usize = 500; // TODO: increase

Expand Down Expand Up @@ -137,12 +137,12 @@ pub struct IDFSearchAPIData {
pub search_logger: Arc<SearchLogger>,
}

pub struct IDFSearch<T: CheckPattern> {
pub struct IDFSearch<ValidityChecker: PatternValidityChecker = AlwaysValid> {
api_data: Arc<IDFSearchAPIData>,
pub prune_table: PruneTable<T>,
pub prune_table: HashPruneTable<ValidityChecker>,
}

impl<T: CheckPattern> IDFSearch<T> {
impl<ValidityChecker: PatternValidityChecker> IDFSearch<ValidityChecker> {
pub fn try_new(
kpuzzle: KPuzzle,
target_pattern: KPattern,
Expand All @@ -163,7 +163,8 @@ impl<T: CheckPattern> IDFSearch<T> {
search_logger: search_logger.clone(),
});

let prune_table = PruneTable::new(api_data.clone(), search_logger, min_prune_table_size); // TODO: make the prune table reusable across searches.
let prune_table =
HashPruneTable::new(api_data.clone(), search_logger, min_prune_table_size); // TODO: make the prune table reusable across searches.
Ok(Self {
api_data,
prune_table,
Expand Down Expand Up @@ -264,7 +265,7 @@ impl<T: CheckPattern> IDFSearch<T> {
) -> SearchRecursionResult {
let current_pattern = kpattern_stack.current_pattern();
// TODO: apply invalid checks only to intermediate state (i.e. exclude remaining_depth == 0)?
if !T::is_valid(current_pattern) {
if !ValidityChecker::is_valid(current_pattern) {
return SearchRecursionResult::ContinueSearchingDefault();
}

Expand Down
24 changes: 12 additions & 12 deletions src/rs/_internal/search/prune_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::_internal::{
};

use super::idf_search::IDFSearchAPIData;
use super::CheckPattern;
use super::PatternValidityChecker;

type PruneTableEntryType = u8;
// 0 is uninitialized, all other values are stored as 1+depth.
Expand All @@ -22,10 +22,10 @@ const MAX_PRUNE_TABLE_DEPTH: PruneTableEntryType = PruneTableEntryType::MAX - 2;

const DEFAULT_MIN_PRUNE_TABLE_SIZE: usize = 1 << 20;

struct PruneTableImmutableData {
struct HashPruneTableImmutableData {
search_api_data: Arc<IDFSearchAPIData>,
}
struct PruneTableMutableData {
struct HashPruneTableMutableData {
min_size: usize, // power of 2
prune_table_size: usize, // power of 2
prune_table_index_mask: usize, // prune_table_size - 1
Expand All @@ -35,7 +35,7 @@ struct PruneTableMutableData {
search_logger: Arc<SearchLogger>,
}

impl PruneTableMutableData {
impl HashPruneTableMutableData {
fn hash_pattern(&self, pattern: &KPattern) -> usize {
let h = cityhasher::CityHasher::new();
(h.hash_one(unsafe { pattern.byte_slice() }) as usize) & self.prune_table_index_mask
Expand Down Expand Up @@ -67,13 +67,13 @@ impl PruneTableMutableData {
}
}

pub struct PruneTable<T: CheckPattern> {
immutable: PruneTableImmutableData,
mutable: PruneTableMutableData,
pub struct HashPruneTable<T: PatternValidityChecker> {
immutable: HashPruneTableImmutableData,
mutable: HashPruneTableMutableData,
phantom: PhantomData<T>,
}

impl<T: CheckPattern> PruneTable<T> {
impl<T: PatternValidityChecker> HashPruneTable<T> {
pub fn new(
search_api_data: Arc<IDFSearchAPIData>,
search_logger: Arc<SearchLogger>,
Expand All @@ -84,8 +84,8 @@ impl<T: CheckPattern> PruneTable<T> {
None => DEFAULT_MIN_PRUNE_TABLE_SIZE,
};
let mut prune_table = Self {
immutable: PruneTableImmutableData { search_api_data },
mutable: PruneTableMutableData {
immutable: HashPruneTableImmutableData { search_api_data },
mutable: HashPruneTableMutableData {
min_size,
prune_table_size: min_size,
prune_table_index_mask: min_size - 1,
Expand Down Expand Up @@ -162,8 +162,8 @@ impl<T: CheckPattern> PruneTable<T> {
// TODO: dedup with IDFSearch?
// TODO: Store a reference to `search_api_data` so that you can't accidentally pass in the wrong `search_api_data`?
fn recurse(
immutable_data: &PruneTableImmutableData,
mutable_data: &mut PruneTableMutableData,
immutable_data: &HashPruneTableImmutableData,
mutable_data: &mut HashPruneTableMutableData,
current_pattern: &KPattern,
current_state: CanonicalFSMState,
remaining_depth: PruneTableEntryType,
Expand Down
15 changes: 6 additions & 9 deletions src/rs/scramble/puzzles/cube2x2x2.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
use cubing::{alg::Alg, puzzles::cube2x2x2_kpuzzle};

use crate::{
_internal::AlwaysValid,
scramble::{
puzzles::static_move_list::{add_random_suffixes_from, static_parsed_opt_list},
randomize::PieceZeroConstraint,
scramble_search::FilteredSearch,
},
use crate::scramble::{
puzzles::static_move_list::{add_random_suffixes_from, static_parsed_opt_list},
randomize::PieceZeroConstraint,
scramble_search::FilteredSearch,
};

use super::{
Expand All @@ -20,15 +17,15 @@ pub fn scramble_2x2x2() -> Alg {
let kpuzzle = cube2x2x2_kpuzzle();

#[allow(non_snake_case)] // Move meanings are case sensitive.
let mut filtered_search_L_B_D = FilteredSearch::<AlwaysValid>::new(
let mut filtered_search_L_B_D = <FilteredSearch>::new(
kpuzzle,
generators_from_vec_str(vec!["L", "B", "D"]),
None,
kpuzzle.default_pattern(),
);

#[allow(non_snake_case)] // Move meanings are case sensitive.
let mut filtered_search_U_L_F_R = FilteredSearch::<AlwaysValid>::new(
let mut filtered_search_U_L_F_R = <FilteredSearch>::new(
kpuzzle,
generators_from_vec_str(vec!["U", "L", "F", "R"]),
None,
Expand Down
8 changes: 4 additions & 4 deletions src/rs/scramble/puzzles/cube3x3x3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use cubing::{
use lazy_static::lazy_static;

use crate::{
_internal::{AlwaysValid, IDFSearch, IndividualSearchOptions},
_internal::{IDFSearch, IndividualSearchOptions},
scramble::{
collapse::collapse_adjacent_moves,
randomize::{basic_parity, BasicParity, PieceZeroConstraint},
Expand All @@ -30,12 +30,12 @@ use super::{
pub struct Scramble3x3x3TwoPhase {
kpuzzle: KPuzzle,

filtering_idfs: IDFSearch<AlwaysValid>,
filtering_idfs: IDFSearch,

phase1_target_pattern: KPattern,
phase1_idfs: IDFSearch<AlwaysValid>,
phase1_idfs: IDFSearch,

phase2_idfs: IDFSearch<AlwaysValid>,
phase2_idfs: IDFSearch,
}

impl Default for Scramble3x3x3TwoPhase {
Expand Down
6 changes: 3 additions & 3 deletions src/rs/scramble/puzzles/square1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use rand::seq::SliceRandom;
use rand::thread_rng;

use crate::{
_internal::{CheckPattern, FlatMoveIndex},
_internal::{PatternValidityChecker, FlatMoveIndex},
scramble::{
randomize::{basic_parity, BasicParity, PieceZeroConstraint},
scramble_search::FilteredSearch,
Expand Down Expand Up @@ -70,7 +70,7 @@ struct Phase1Checker;

const SLOTS_THAT_ARE_AFTER_SLICES: [u8; 4] = [0, 6, 12, 18];

impl CheckPattern for Phase1Checker {
impl PatternValidityChecker for Phase1Checker {
fn is_valid(pattern: &cubing::kpuzzle::KPattern) -> bool {
let orbit_info = &pattern.kpuzzle().data.ordered_orbit_info[0];
assert_eq!(orbit_info.name.0, "WEDGES");
Expand All @@ -95,7 +95,7 @@ impl CheckPattern for Phase1Checker {

struct Phase2Checker;

impl CheckPattern for Phase2Checker {
impl PatternValidityChecker for Phase2Checker {
fn is_valid(pattern: &cubing::kpuzzle::KPattern) -> bool {
let orbit_info = &pattern.kpuzzle().data.ordered_orbit_info[0];
assert_eq!(orbit_info.name.0, "WEDGES");
Expand Down
9 changes: 6 additions & 3 deletions src/rs/scramble/puzzles/square1_phase_lookup_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use cubing::kpuzzle::{KPattern, KPuzzle};
use crate::{
_internal::{
options::{Generators, MetricEnum},
CheckPattern, FlatMoveIndex, SearchGenerators,
FlatMoveIndex, PatternValidityChecker, SearchGenerators,
},
scramble::randomize::BasicParity,
};
Expand All @@ -36,7 +36,10 @@ impl Debug for LookupPattern {
}

impl LookupPattern {
fn try_new<C: CheckPattern>(full_pattern: &KPattern, phase_mask: &KPattern) -> Option<Self> {
fn try_new<C: PatternValidityChecker>(
full_pattern: &KPattern,
phase_mask: &KPattern,
) -> Option<Self> {
let Ok(masked_pattern) = mask(full_pattern, phase_mask) else {
panic!("Mask application failed");
};
Expand Down Expand Up @@ -75,7 +78,7 @@ impl PhaseLookupTable {
}
}

pub fn build_phase_lookup_table<C: CheckPattern>(
pub fn build_phase_lookup_table<C: PatternValidityChecker>(
kpuzzle: KPuzzle,
generators: &Generators,
phase_mask: &KPattern,
Expand Down
19 changes: 10 additions & 9 deletions src/rs/scramble/scramble_search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ use cubing::{

use crate::_internal::{
options::{CustomGenerators, Generators, MetricEnum, VerbosityLevel},
CheckPattern, IDFSearch, IndividualSearchOptions, SearchLogger, SearchSolutions,
AlwaysValid, IDFSearch, IndividualSearchOptions, PatternValidityChecker, SearchLogger,
SearchSolutions,
};

pub fn move_list_from_vec(move_str_list: Vec<&str>) -> Vec<Move> {
Expand All @@ -24,7 +25,7 @@ pub fn generators_from_vec_str(move_str_list: Vec<&str>) -> Generators {
})
}

pub(crate) fn idfs_with_target_pattern<T: CheckPattern>(
pub(crate) fn idfs_with_target_pattern<T: PatternValidityChecker>(
kpuzzle: &KPuzzle,
generators: Generators,
target_pattern: KPattern,
Expand All @@ -45,26 +46,26 @@ pub(crate) fn idfs_with_target_pattern<T: CheckPattern>(
.unwrap()
}

pub(crate) fn basic_idfs<T: CheckPattern>(
pub(crate) fn basic_idfs<ValidityChecker: PatternValidityChecker>(
kpuzzle: &KPuzzle,
generators: Generators,
min_prune_table_size: Option<usize>,
target_pattern: KPattern,
) -> IDFSearch<T> {
) -> IDFSearch<ValidityChecker> {
idfs_with_target_pattern(kpuzzle, generators, target_pattern, min_prune_table_size)
}

pub struct FilteredSearch<T: CheckPattern> {
pub(crate) idfs: IDFSearch<T>,
pub struct FilteredSearch<ValidityChecker: PatternValidityChecker = AlwaysValid> {
pub(crate) idfs: IDFSearch<ValidityChecker>,
}

impl<T: CheckPattern> FilteredSearch<T> {
impl<ValidityChecker: PatternValidityChecker> FilteredSearch<ValidityChecker> {
pub fn new(
kpuzzle: &KPuzzle,
generators: Generators,
min_prune_table_size: Option<usize>,
target_pattern: KPattern,
) -> FilteredSearch<T> {
) -> FilteredSearch<ValidityChecker> {
let idfs = basic_idfs(kpuzzle, generators, min_prune_table_size, target_pattern);
Self { idfs }
}
Expand Down Expand Up @@ -125,7 +126,7 @@ impl<T: CheckPattern> FilteredSearch<T> {
}
}

pub(crate) fn simple_filtered_search<T: CheckPattern>(
pub(crate) fn simple_filtered_search<T: PatternValidityChecker>(
scramble_pattern: &KPattern,
generators: Generators,
min_optimal_moves: usize,
Expand Down

0 comments on commit d671a15

Please sign in to comment.