From 2d6830bf5e6bcdaf060c228484ea8ae16f573c08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNailLegProcessorDivide=E2=80=9D?= Date: Wed, 19 Jul 2023 20:22:06 +0100 Subject: [PATCH 01/13] temp push --- rust/src/hashless.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 rust/src/hashless.rs diff --git a/rust/src/hashless.rs b/rust/src/hashless.rs new file mode 100644 index 0000000..7940c23 --- /dev/null +++ b/rust/src/hashless.rs @@ -0,0 +1,33 @@ +use std::time::Instant; + +use opencubes::naive_polycube::NaivePolyCube; + +use crate::{Compression, polycube_reps::naive_to_map_pos, make_bar}; + + + + + +/// run pointlist based generation algorithm +pub fn gen_polycubes( + n: usize, + use_cache: bool, + compression: Compression, + parallel: bool, + mut current: Vec, + calculate_from: usize, +) -> usize { + let t1_start = Instant::now(); + + //convert input vector of NaivePolyCubes and convert them to + let mut seeds = Vec::new(); + for seed in current.iter() { + let (seed, dim) = naive_to_map_pos(seed); + seeds.push((seed, dim)); + } + current.drop(); + + + next + //count_polycubes(&seeds); +} \ No newline at end of file From d5e12e4fa1dfa3a75ae0c26f8e6ca534d581867d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNailLegProcessorDivide=E2=80=9D?= Date: Wed, 19 Jul 2023 20:22:33 +0100 Subject: [PATCH 02/13] temp push --- rust/src/cli.rs | 12 ++++++++++++ rust/src/hashless.rs | 5 +++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/rust/src/cli.rs b/rust/src/cli.rs index 31b5a45..4fc7917 100644 --- a/rust/src/cli.rs +++ b/rust/src/cli.rs @@ -17,6 +17,7 @@ mod pointlist; mod polycube_reps; mod rotation_reduced; mod rotations; +mod hashless; fn unknown_bar() -> ProgressBar { let style = ProgressStyle::with_template("[{elapsed_precise}] [{spinner:10.cyan/blue}] {msg}") @@ -98,6 +99,7 @@ pub enum EnumerationMode { Standard, RotationReduced, PointList, + Hashless } #[derive(Clone, Subcommand)] @@ -486,6 +488,16 @@ pub fn enumerate(opts: &EnumerateOpts) { ); cubes.len() } + (EnumerationMode::Hashless, para) => { + hashless::gen_polycubes( + n, + cache, + opts.cache_compression, + !para, + seed_list, + startn, + ) + } }; let duration = start.elapsed(); diff --git a/rust/src/hashless.rs b/rust/src/hashless.rs index 7940c23..cb2919c 100644 --- a/rust/src/hashless.rs +++ b/rust/src/hashless.rs @@ -25,9 +25,10 @@ pub fn gen_polycubes( let (seed, dim) = naive_to_map_pos(seed); seeds.push((seed, dim)); } - current.drop(); + drop(current); + let count = 0; - next + count //count_polycubes(&seeds); } \ No newline at end of file From 38d89076fe99ec9a078fee23d90cc4e0c50ecc1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNailLegProcessorDivide=E2=80=9D?= Date: Wed, 19 Jul 2023 23:44:20 +0100 Subject: [PATCH 03/13] temp for rebase --- rust/src/hashless.rs | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/rust/src/hashless.rs b/rust/src/hashless.rs index cb2919c..1586130 100644 --- a/rust/src/hashless.rs +++ b/rust/src/hashless.rs @@ -2,9 +2,30 @@ use std::time::Instant; use opencubes::naive_polycube::NaivePolyCube; -use crate::{Compression, polycube_reps::naive_to_map_pos, make_bar}; - - +use crate::{Compression, polycube_reps::{naive_to_map_pos, CubeMapPos}, make_bar, rotations::to_min_rot_points}; + +fn is_continuous(polycube: &CubeMapPos) -> bool { + todo!() +} + +fn canonical_root(exp: &CubeMapPos, count: usize) -> CubeMapPos { + let root = CubeMapPos {cubes: [0;16]}; + for sub_cube_id in 0..count { + let mut root_candidate = CubeMapPos {cubes: [0;16]}; + let mut candidate_ptr = 0; + for i in 0..count { + if i != sub_cube_id { + root_candidate.cubes[candidate_ptr] = exp.cubes[i]; + candidate_ptr += 1; + } + } + if is_continuous(&root_candidate) { + continue; + } + let mrp = to_min_rot_points(&root_candidate, root_candidate.shape(), count - 1); + } + root +} From 5600bbed15e3bce5e478109ebb16c2b7b6c53a8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNailLegProcessorDivide=E2=80=9D?= Date: Sat, 22 Jul 2023 00:46:08 +0100 Subject: [PATCH 04/13] almost arbritrary N (n=16 because small datatype) --- rust/src/cli.rs | 13 +- rust/src/hashless.rs | 440 +++++++++++++++++++++++++++++++++++++++--- rust/src/pointlist.rs | 6 +- 3 files changed, 419 insertions(+), 40 deletions(-) diff --git a/rust/src/cli.rs b/rust/src/cli.rs index 4fc7917..0bfac1e 100644 --- a/rust/src/cli.rs +++ b/rust/src/cli.rs @@ -13,11 +13,11 @@ use opencubes::{ }; use rayon::prelude::{IntoParallelIterator, ParallelIterator}; +mod hashless; mod pointlist; mod polycube_reps; mod rotation_reduced; mod rotations; -mod hashless; fn unknown_bar() -> ProgressBar { let style = ProgressStyle::with_template("[{elapsed_precise}] [{spinner:10.cyan/blue}] {msg}") @@ -99,7 +99,7 @@ pub enum EnumerationMode { Standard, RotationReduced, PointList, - Hashless + Hashless, } #[derive(Clone, Subcommand)] @@ -489,14 +489,7 @@ pub fn enumerate(opts: &EnumerateOpts) { cubes.len() } (EnumerationMode::Hashless, para) => { - hashless::gen_polycubes( - n, - cache, - opts.cache_compression, - !para, - seed_list, - startn, - ) + hashless::gen_polycubes(n, cache, opts.cache_compression, !para, seed_list, startn) } }; diff --git a/rust/src/hashless.rs b/rust/src/hashless.rs index 1586130..bb497f8 100644 --- a/rust/src/hashless.rs +++ b/rust/src/hashless.rs @@ -1,33 +1,370 @@ -use std::time::Instant; +use std::{ + cell::RefCell, + cmp::{max, min}, + sync::atomic::{AtomicUsize, Ordering}, + time::Instant, +}; -use opencubes::naive_polycube::NaivePolyCube; +use hashbrown::HashSet; +use opencubes::pcube::RawPCube; +use parking_lot::RwLock; +use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; -use crate::{Compression, polycube_reps::{naive_to_map_pos, CubeMapPos}, make_bar, rotations::to_min_rot_points}; +use crate::{ + make_bar, + pointlist::{array_insert, array_shift}, + polycube_reps::{CubeMapPos, Dim}, + rotations::{map_coord, rot_matrix_points, to_min_rot_points, MatrixCol}, + Compression, +}; -fn is_continuous(polycube: &CubeMapPos) -> bool { - todo!() +fn is_continuous(polycube: &[u16]) -> bool { + let start = polycube[0]; + let mut visited = HashSet::new(); + let mut to_explore = HashSet::new(); + to_explore.insert(start); + while let Some(p) = to_explore.iter().next() { + let p = *p; + to_explore.remove(&p); + visited.insert(p); + if p & 0x1f != 0 && polycube.contains(&(p - 1)) && !visited.contains(&(p - 1)) { + to_explore.insert(p - 1); + } + if p & 0x1f != 0x1f && polycube.contains(&(p + 1)) && !visited.contains(&(p + 1)) { + to_explore.insert(p + 1); + } + if (p >> 5) & 0x1f != 0 + && polycube.contains(&(p - (1 << 5))) + && !visited.contains(&(p - (1 << 5))) + { + to_explore.insert(p - (1 << 5)); + } + if (p >> 5) & 0x1f != 0x1f + && polycube.contains(&(p + (1 << 5))) + && !visited.contains(&(p + (1 << 5))) + { + to_explore.insert(p + (1 << 5)); + } + if (p >> 10) & 0x1f != 0 + && polycube.contains(&(p - (1 << 10))) + && !visited.contains(&(p - (1 << 10))) + { + to_explore.insert(p - (1 << 10)); + } + if (p >> 10) & 0x1f != 0x1f + && polycube.contains(&(p + (1 << 10))) + && !visited.contains(&(p + (1 << 10))) + { + to_explore.insert(p + (1 << 10)); + } + } + visited.len() == polycube.len() } -fn canonical_root(exp: &CubeMapPos, count: usize) -> CubeMapPos { - let root = CubeMapPos {cubes: [0;16]}; - for sub_cube_id in 0..count { - let mut root_candidate = CubeMapPos {cubes: [0;16]}; - let mut candidate_ptr = 0; - for i in 0..count { - if i != sub_cube_id { - root_candidate.cubes[candidate_ptr] = exp.cubes[i]; - candidate_ptr += 1; - } +fn renormalize(exp: &CubeMapPos, dim: &Dim, count: usize) -> CubeMapPos { + let mut dst = CubeMapPos { cubes: [0; 16] }; + let x = dim.x; + let y = dim.y; + let z = dim.z; + let (x_col, y_col, z_col) = if x >= y && y >= z { + (MatrixCol::XP, MatrixCol::YP, MatrixCol::ZP) + } else if x >= z && z >= y { + (MatrixCol::XP, MatrixCol::ZP, MatrixCol::YN) + } else if y >= x && x >= z { + (MatrixCol::YP, MatrixCol::XP, MatrixCol::ZN) + } else if y >= z && z >= x { + (MatrixCol::YP, MatrixCol::ZP, MatrixCol::XP) + } else if z >= x && x >= y { + (MatrixCol::ZN, MatrixCol::XP, MatrixCol::YN) + } else if z >= y && y >= x { + (MatrixCol::ZN, MatrixCol::YN, MatrixCol::XP) + } else { + panic!("imposible dimension of shape {:?}", dim) + }; + for (i, d) in exp.cubes[0..count].iter().enumerate() { + let dx = d & 0x1f; + let dy = (d >> 5) & 0x1f; + let dz = (d >> 10) & 0x1f; + let cx = map_coord(dx, dy, dz, &dim, x_col); + let cy = map_coord(dx, dy, dz, &dim, y_col); + let cz = map_coord(dx, dy, dz, &dim, z_col); + let pack = ((cz << 10) | (cy << 5) | cx) as u16; + dst.cubes[i] = pack; + } + //dst.cubes.sort(); + dst +} + +fn remove_cube(exp: &CubeMapPos, point: usize, count: usize) -> (CubeMapPos, Dim) { + let mut min_corner = Dim { + x: 0x1f, + y: 0x1f, + z: 0x1f, + }; + let mut max_corner = Dim { x: 0, y: 0, z: 0 }; + let mut root_candidate = CubeMapPos { cubes: [0; 16] }; + let mut candidate_ptr = 0; + for i in 0..=count { + if i != point { + let pos = exp.cubes[i]; + let x = pos as usize & 0x1f; + let y = (pos as usize >> 5) & 0x1f; + let z = (pos as usize >> 10) & 0x1f; + min_corner.x = min(min_corner.x, x); + min_corner.y = min(min_corner.y, y); + min_corner.z = min(min_corner.z, z); + max_corner.x = max(max_corner.x, x); + max_corner.y = max(max_corner.y, y); + max_corner.z = max(max_corner.z, z); + root_candidate.cubes[candidate_ptr] = exp.cubes[i]; + candidate_ptr += 1; } - if is_continuous(&root_candidate) { + } + // println!("u{:?}", root_candidate.cubes); + let offset = (min_corner.z << 10) | (min_corner.y << 5) | min_corner.x; + for i in 0..count { + root_candidate.cubes[i] -= offset as u16; + } + // println!("w{:?}", root_candidate.cubes); + max_corner.x = max_corner.x - min_corner.x; + max_corner.y = max_corner.y - min_corner.y; + max_corner.z = max_corner.z - min_corner.z; + (root_candidate, max_corner) +} + +fn is_canonical_root(exp: &CubeMapPos, count: usize, seed: &CubeMapPos) -> bool { + let mut seed_found = false; + for sub_cube_id in 0..=count { + let (mut root_candidate, dim) = remove_cube(exp, sub_cube_id, count); + // if dim.x == 1 && dim.y == 1 && dim.z == 1 { + // println!("111 {:?} {}", root_candidate, count); + // } + if dim.x < dim.y || dim.y < dim.z || dim.x < dim.z { + root_candidate = renormalize(&root_candidate, &dim, count); + // println!("a"); + // continue; + } + if !is_continuous(&root_candidate.cubes[0..count]) { + // println!("b"); continue; } - let mrp = to_min_rot_points(&root_candidate, root_candidate.shape(), count - 1); + root_candidate.cubes[0..count].sort_unstable(); + // println!("c"); + let mrp = to_min_rot_points(&root_candidate, &root_candidate.extrapolate_dim(), count); + if &mrp < seed { + return false; + } + // println!("mrp {:?}", mrp); + if &mrp == seed { + seed_found = true; + // println!("seedy"); + } + } + if !seed_found { + panic!("seedless {}\n{:?}\n{:?}", count, exp, seed); } - root + // println!("{:?} root of {:?}", exp, seed); + true } +/// helper function to not duplicate code for canonicalising polycubes +/// and storing them in the hashset +fn insert_map(store: &mut HashSet, dim: &Dim, map: &CubeMapPos, count: usize) { + // if map.extrapolate_count() != count { + // panic!("count missmatch {} {}", map.extrapolate_count(), count) + // } + // if !is_continuous(&map.cubes[0..count]) { + // panic!("not continuous {:?}", map) + // } + // for i in 1..count { + // if map.cubes[i - 1] >= map.cubes[i] { + // panic!("{} >= {} not sorted", map.cubes[i - 1], map.cubes[i]) + // } + // } + let map = to_min_rot_points(map, dim, count); + store.insert(map); +} + +/// try expaning each cube into both x+1 and x-1, calculating new dimension +/// and ensuring x is never negative +#[inline] +fn expand_xs(dst: &mut HashSet, seed: &CubeMapPos, shape: &Dim, count: usize) { + for (i, coord) in seed.cubes[0..count].iter().enumerate() { + if !seed.cubes[(i + 1)..count].contains(&(coord + 1)) { + let mut new_shape = *shape; + let mut exp_map = *seed; + array_insert(coord + 1, &mut exp_map.cubes[i..=count]); + new_shape.x = max(new_shape.x, ((coord + 1) & 0x1f) as usize); + insert_map(dst, &new_shape, &exp_map, count + 1) + } + if coord & 0x1f != 0 { + if !seed.cubes[0..i].contains(&(coord - 1)) { + let mut exp_map = *seed; + //faster move of top half hopefully + array_shift(&mut exp_map.cubes[i..=count]); + array_insert(coord - 1, &mut exp_map.cubes[0..=i]); + insert_map(dst, shape, &exp_map, count + 1) + } + } else { + let mut new_shape = *shape; + new_shape.x += 1; + let mut exp_map = *seed; + for i in 0..count { + exp_map.cubes[i] += 1; + } + array_shift(&mut exp_map.cubes[i..=count]); + array_insert(*coord, &mut exp_map.cubes[0..=i]); + insert_map(dst, &new_shape, &exp_map, count + 1) + } + } +} + +/// try expaning each cube into both y+1 and y-1, calculating new dimension +/// and ensuring y is never negative +#[inline] +fn expand_ys(dst: &mut HashSet, seed: &CubeMapPos, shape: &Dim, count: usize) { + for (i, coord) in seed.cubes[0..count].iter().enumerate() { + if !seed.cubes[(i + 1)..count].contains(&(coord + (1 << 5))) { + let mut new_shape = *shape; + let mut exp_map = *seed; + array_insert(coord + (1 << 5), &mut exp_map.cubes[i..=count]); + new_shape.y = max(new_shape.y, (((coord >> 5) + 1) & 0x1f) as usize); + insert_map(dst, &new_shape, &exp_map, count + 1) + } + if (coord >> 5) & 0x1f != 0 { + if !seed.cubes[0..i].contains(&(coord - (1 << 5))) { + let mut exp_map = *seed; + //faster move of top half hopefully + array_shift(&mut exp_map.cubes[i..=count]); + array_insert(coord - (1 << 5), &mut exp_map.cubes[0..=i]); + insert_map(dst, shape, &exp_map, count + 1) + } + } else { + let mut new_shape = *shape; + new_shape.y += 1; + let mut exp_map = *seed; + for i in 0..count { + exp_map.cubes[i] += 1 << 5; + } + array_shift(&mut exp_map.cubes[i..=count]); + array_insert(*coord, &mut exp_map.cubes[0..=i]); + insert_map(dst, &new_shape, &exp_map, count + 1) + } + } +} + +/// try expaning each cube into both z+1 and z-1, calculating new dimension +/// and ensuring z is never negative +#[inline] +fn expand_zs(dst: &mut HashSet, seed: &CubeMapPos, shape: &Dim, count: usize) { + for (i, coord) in seed.cubes[0..count].iter().enumerate() { + if !seed.cubes[(i + 1)..count].contains(&(coord + (1 << 10))) { + let mut new_shape = *shape; + let mut exp_map = *seed; + array_insert(coord + (1 << 10), &mut exp_map.cubes[i..=count]); + new_shape.z = max(new_shape.z, (((coord >> 10) + 1) & 0x1f) as usize); + insert_map(dst, &new_shape, &exp_map, count + 1) + } + if (coord >> 10) & 0x1f != 0 { + if !seed.cubes[0..i].contains(&(coord - (1 << 10))) { + let mut exp_map = *seed; + //faster move of top half hopefully + array_shift(&mut exp_map.cubes[i..=count]); + array_insert(coord - (1 << 10), &mut exp_map.cubes[0..=i]); + insert_map(dst, shape, &exp_map, count + 1) + } + } else { + let mut new_shape = *shape; + new_shape.z += 1; + let mut exp_map = *seed; + for i in 0..count { + exp_map.cubes[i] += 1 << 10; + } + array_shift(&mut exp_map.cubes[i..=count]); + array_insert(*coord, &mut exp_map.cubes[0..=i]); + insert_map(dst, &new_shape, &exp_map, count + 1) + } + } +} + +/// reduce number of expansions needing to be performed based on +/// X >= Y >= Z constraint on Dim +#[inline] +fn do_cube_expansion(dst: &mut HashSet, seed: &CubeMapPos, shape: &Dim, count: usize) { + if shape.y < shape.x { + expand_ys(dst, seed, shape, count); + } + if shape.z < shape.y { + expand_zs(dst, seed, shape, count); + } + expand_xs(dst, seed, shape, count); +} + +/// perform the cube expansion for a given polycube +/// if perform extra expansions for cases where the dimensions are equal as +/// square sides may miss poly cubes otherwise +#[inline] +fn expand_cube_map(dst: &mut HashSet, seed: &CubeMapPos, shape: &Dim, count: usize) { + if shape.x == shape.y && shape.x > 0 { + let rotz = rot_matrix_points( + seed, + shape, + count, + MatrixCol::YN, + MatrixCol::XN, + MatrixCol::ZN, + 1025, + ); + do_cube_expansion(dst, &rotz, shape, count); + } + if shape.y == shape.z && shape.y > 0 { + let rotx = rot_matrix_points( + seed, + shape, + count, + MatrixCol::XN, + MatrixCol::ZP, + MatrixCol::YP, + 1025, + ); + do_cube_expansion(dst, &rotx, shape, count); + } + if shape.x == shape.z && shape.x > 0 { + let roty = rot_matrix_points( + seed, + shape, + count, + MatrixCol::ZP, + MatrixCol::YP, + MatrixCol::XN, + 1025, + ); + do_cube_expansion(dst, &roty, shape, count); + } + do_cube_expansion(dst, seed, shape, count); +} + +fn enumerate_canonical_children( + seed: &CubeMapPos, + count: usize, + target: usize, + set_stack: &[RwLock>], +) -> usize { + let mut children = set_stack[count].write(); + children.clear(); + let shape = seed.extrapolate_dim(); + expand_cube_map(&mut children, seed, &shape, count); + children.retain(|child| is_canonical_root(child, count, seed)); + if count + 1 == target { + children.len() + } else { + children + .iter() + .map(|child| enumerate_canonical_children(child, count + 1, target, set_stack)) + .sum() + } +} /// run pointlist based generation algorithm pub fn gen_polycubes( @@ -35,21 +372,70 @@ pub fn gen_polycubes( use_cache: bool, compression: Compression, parallel: bool, - mut current: Vec, + mut current: Vec, calculate_from: usize, ) -> usize { let t1_start = Instant::now(); + let total: AtomicUsize = AtomicUsize::new(0); + let work_count: AtomicUsize = AtomicUsize::new(0); + + let seed_count = current.len(); + let bar = make_bar(seed_count as u64); + bar.set_message(format!( + "seed subsets expanded for N = {}...", + calculate_from - 1 + )); + //convert input vector of NaivePolyCubes and convert them to - let mut seeds = Vec::new(); - for seed in current.iter() { - let (seed, dim) = naive_to_map_pos(seed); - seeds.push((seed, dim)); + if parallel { + current.par_iter().for_each(|seed| { + let seed = seed.into(); + let sets = (0..n) + .map(|_| RwLock::new(HashSet::new())) + .collect::>(); + let children = enumerate_canonical_children(&seed, calculate_from - 1, n, &sets); + total.fetch_add(children, Ordering::Relaxed); + let steps = work_count.fetch_add(1, Ordering::Relaxed) + 1; + let t1_now = Instant::now(); + let time = t1_now.duration_since(t1_start).as_secs() as usize; + bar.set_message(format!( + "seed subsets expanded for N = {}. est {}m remaining..", + calculate_from - 1, + ((time * seed_count) / steps - time) / 60 + )); + bar.inc(1); + }); + } else { + current.iter().for_each(|seed| { + let seed = seed.into(); + let sets = (0..n) + .map(|_| RwLock::new(HashSet::new())) + .collect::>(); + let children = enumerate_canonical_children(&seed, calculate_from - 1, n, &sets); + total.fetch_add(children, Ordering::Relaxed); + let steps = work_count.fetch_add(1, Ordering::Relaxed) + 1; + let t1_now = Instant::now(); + let time = t1_now.duration_since(t1_start).as_secs() as usize; + bar.set_message(format!( + "seed subsets expanded for N = {}. est {}m remaining..", + calculate_from - 1, + (time * seed_count) / steps / 60 + )); + bar.inc(1); + }); } - drop(current); - let count = 0; + let count = total.load(Ordering::Relaxed); + let t1_stop = Instant::now(); + let time = t1_stop.duration_since(t1_start).as_micros(); + bar.set_message(format!( + "Found {} unique expansions (N = {n}) in {}.{:06}s", + count, + time / 1000000, + time % 1000000 + )); - + bar.finish(); count //count_polycubes(&seeds); -} \ No newline at end of file +} diff --git a/rust/src/pointlist.rs b/rust/src/pointlist.rs index 0f7ae5a..4924718 100644 --- a/rust/src/pointlist.rs +++ b/rust/src/pointlist.rs @@ -26,7 +26,7 @@ type MapStore = HashMap<(Dim, u16), RwLock>>; fn insert_map(store: &MapStore, dim: &Dim, map: &CubeMapPos, count: usize) { let map = to_min_rot_points(map, dim, count); let mut body = CubeMapPosPart { cubes: [0; 15] }; - for i in 1..16 { + for i in 1..count { body.cubes[i - 1] = map.cubes[i]; } match store.get(&(*dim, map.cubes[0])) { @@ -44,7 +44,7 @@ fn insert_map(store: &MapStore, dim: &Dim, map: &CubeMapPos, count: usize) { ///linearly scan backwards to insertion point overwrites end of slice #[inline] -fn array_insert(val: u16, arr: &mut [u16]) { +pub fn array_insert(val: u16, arr: &mut [u16]) { for i in 1..(arr.len()) { if arr[arr.len() - 1 - i] > val { arr[arr.len() - i] = arr[arr.len() - 1 - i]; @@ -58,7 +58,7 @@ fn array_insert(val: u16, arr: &mut [u16]) { /// moves contents of slice to index x+1, x==0 remains #[inline] -fn array_shift(arr: &mut [u16]) { +pub fn array_shift(arr: &mut [u16]) { for i in 1..(arr.len()) { arr[arr.len() - i] = arr[arr.len() - 1 - i]; } From dad1e80baf8a65602aa9698e9067f43bd4af60d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNailLegProcessorDivide=E2=80=9D?= Date: Sat, 22 Jul 2023 04:20:10 +0100 Subject: [PATCH 05/13] perf improvements --- rust/Cargo.toml | 3 + rust/src/hashless.rs | 172 ++++++++++++++++++++++++------------------- 2 files changed, 98 insertions(+), 77 deletions(-) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 3d96406..1dc02ba 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -10,6 +10,9 @@ diagnostics = [] size16 = [] smallset = [] +[profile.release] +debug = true + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/rust/src/hashless.rs b/rust/src/hashless.rs index bb497f8..4f2d55d 100644 --- a/rust/src/hashless.rs +++ b/rust/src/hashless.rs @@ -1,5 +1,4 @@ use std::{ - cell::RefCell, cmp::{max, min}, sync::atomic::{AtomicUsize, Ordering}, time::Instant, @@ -20,64 +19,107 @@ use crate::{ fn is_continuous(polycube: &[u16]) -> bool { let start = polycube[0]; - let mut visited = HashSet::new(); - let mut to_explore = HashSet::new(); - to_explore.insert(start); - while let Some(p) = to_explore.iter().next() { - let p = *p; - to_explore.remove(&p); - visited.insert(p); - if p & 0x1f != 0 && polycube.contains(&(p - 1)) && !visited.contains(&(p - 1)) { - to_explore.insert(p - 1); + //sets were actually slower even when no allocating + let mut to_explore = [0; 32]; + let mut exp_head = 1; + let mut exp_tail = 0; + to_explore[0] = start; + while exp_head > exp_tail { + let p = to_explore[exp_tail]; + exp_tail += 1; + if p & 0x1f != 0 + && polycube[0..polycube.len() - 1].contains(&(p - 1)) + && !to_explore[0..exp_head].contains(&(p - 1)) + { + to_explore[exp_head] = p - 1; + exp_head += 1; } - if p & 0x1f != 0x1f && polycube.contains(&(p + 1)) && !visited.contains(&(p + 1)) { - to_explore.insert(p + 1); + if p & 0x1f != 0x1f + && polycube[1..].contains(&(p + 1)) + && !to_explore[0..exp_head].contains(&(p + 1)) + { + to_explore[exp_head] = p + 1; + exp_head += 1; } if (p >> 5) & 0x1f != 0 - && polycube.contains(&(p - (1 << 5))) - && !visited.contains(&(p - (1 << 5))) + && polycube[0..polycube.len() - 1].contains(&(p - (1 << 5))) + && !to_explore[0..exp_head].contains(&(p - (1 << 5))) { - to_explore.insert(p - (1 << 5)); + to_explore[exp_head] = p - (1 << 5); + exp_head += 1; } if (p >> 5) & 0x1f != 0x1f - && polycube.contains(&(p + (1 << 5))) - && !visited.contains(&(p + (1 << 5))) + && polycube[1..].contains(&(p + (1 << 5))) + && !to_explore[0..exp_head].contains(&(p + (1 << 5))) { - to_explore.insert(p + (1 << 5)); + to_explore[exp_head] = p + (1 << 5); + exp_head += 1; } if (p >> 10) & 0x1f != 0 - && polycube.contains(&(p - (1 << 10))) - && !visited.contains(&(p - (1 << 10))) + && polycube[0..polycube.len() - 1].contains(&(p - (1 << 10))) + && !to_explore[0..exp_head].contains(&(p - (1 << 10))) { - to_explore.insert(p - (1 << 10)); + to_explore[exp_head] = p - (1 << 10); + exp_head += 1; } if (p >> 10) & 0x1f != 0x1f - && polycube.contains(&(p + (1 << 10))) - && !visited.contains(&(p + (1 << 10))) + && polycube[1..].contains(&(p + (1 << 10))) + && !to_explore[0..exp_head].contains(&(p + (1 << 10))) { - to_explore.insert(p + (1 << 10)); + to_explore[exp_head] = p + (1 << 10); + exp_head += 1; } } - visited.len() == polycube.len() + exp_head == polycube.len() } -fn renormalize(exp: &CubeMapPos, dim: &Dim, count: usize) -> CubeMapPos { +fn renormalize(exp: &CubeMapPos, dim: &Dim, count: usize) -> (CubeMapPos, Dim) { let mut dst = CubeMapPos { cubes: [0; 16] }; let x = dim.x; let y = dim.y; let z = dim.z; - let (x_col, y_col, z_col) = if x >= y && y >= z { - (MatrixCol::XP, MatrixCol::YP, MatrixCol::ZP) + let (x_col, y_col, z_col, rdim) = if x >= y && y >= z { + ( + MatrixCol::XP, + MatrixCol::YP, + MatrixCol::ZP, + Dim { x: x, y: y, z: z }, + ) } else if x >= z && z >= y { - (MatrixCol::XP, MatrixCol::ZP, MatrixCol::YN) + ( + MatrixCol::XP, + MatrixCol::ZP, + MatrixCol::YN, + Dim { x: x, y: z, z: y }, + ) } else if y >= x && x >= z { - (MatrixCol::YP, MatrixCol::XP, MatrixCol::ZN) + ( + MatrixCol::YP, + MatrixCol::XP, + MatrixCol::ZN, + Dim { x: y, y: x, z: z }, + ) } else if y >= z && z >= x { - (MatrixCol::YP, MatrixCol::ZP, MatrixCol::XP) + ( + MatrixCol::YP, + MatrixCol::ZP, + MatrixCol::XP, + Dim { x: y, y: z, z: x }, + ) } else if z >= x && x >= y { - (MatrixCol::ZN, MatrixCol::XP, MatrixCol::YN) + ( + MatrixCol::ZN, + MatrixCol::XP, + MatrixCol::YN, + Dim { x: z, y: x, z: y }, + ) } else if z >= y && y >= x { - (MatrixCol::ZN, MatrixCol::YN, MatrixCol::XP) + ( + MatrixCol::ZN, + MatrixCol::YN, + MatrixCol::XP, + Dim { x: z, y: y, z: x }, + ) } else { panic!("imposible dimension of shape {:?}", dim) }; @@ -92,7 +134,7 @@ fn renormalize(exp: &CubeMapPos, dim: &Dim, count: usize) -> CubeMapPos { dst.cubes[i] = pack; } //dst.cubes.sort(); - dst + (dst, rdim) } fn remove_cube(exp: &CubeMapPos, point: usize, count: usize) -> (CubeMapPos, Dim) { @@ -120,12 +162,10 @@ fn remove_cube(exp: &CubeMapPos, point: usize, count: usize) -> (CubeMapPos, Dim candidate_ptr += 1; } } - // println!("u{:?}", root_candidate.cubes); let offset = (min_corner.z << 10) | (min_corner.y << 5) | min_corner.x; for i in 0..count { root_candidate.cubes[i] -= offset as u16; } - // println!("w{:?}", root_candidate.cubes); max_corner.x = max_corner.x - min_corner.x; max_corner.y = max_corner.y - min_corner.y; max_corner.z = max_corner.z - min_corner.z; @@ -133,54 +173,28 @@ fn remove_cube(exp: &CubeMapPos, point: usize, count: usize) -> (CubeMapPos, Dim } fn is_canonical_root(exp: &CubeMapPos, count: usize, seed: &CubeMapPos) -> bool { - let mut seed_found = false; for sub_cube_id in 0..=count { - let (mut root_candidate, dim) = remove_cube(exp, sub_cube_id, count); - // if dim.x == 1 && dim.y == 1 && dim.z == 1 { - // println!("111 {:?} {}", root_candidate, count); - // } - if dim.x < dim.y || dim.y < dim.z || dim.x < dim.z { - root_candidate = renormalize(&root_candidate, &dim, count); - // println!("a"); - // continue; - } + let (mut root_candidate, mut dim) = remove_cube(exp, sub_cube_id, count); if !is_continuous(&root_candidate.cubes[0..count]) { - // println!("b"); continue; } - root_candidate.cubes[0..count].sort_unstable(); - // println!("c"); - let mrp = to_min_rot_points(&root_candidate, &root_candidate.extrapolate_dim(), count); + if dim.x < dim.y || dim.y < dim.z || dim.x < dim.z { + let (rroot_candidate, rdim) = renormalize(&root_candidate, &dim, count); + root_candidate = rroot_candidate; + dim = rdim; + root_candidate.cubes[0..count].sort_unstable(); + } + let mrp = to_min_rot_points(&root_candidate, &dim, count); if &mrp < seed { return false; } - // println!("mrp {:?}", mrp); - if &mrp == seed { - seed_found = true; - // println!("seedy"); - } - } - if !seed_found { - panic!("seedless {}\n{:?}\n{:?}", count, exp, seed); } - // println!("{:?} root of {:?}", exp, seed); true } /// helper function to not duplicate code for canonicalising polycubes /// and storing them in the hashset fn insert_map(store: &mut HashSet, dim: &Dim, map: &CubeMapPos, count: usize) { - // if map.extrapolate_count() != count { - // panic!("count missmatch {} {}", map.extrapolate_count(), count) - // } - // if !is_continuous(&map.cubes[0..count]) { - // panic!("not continuous {:?}", map) - // } - // for i in 1..count { - // if map.cubes[i - 1] >= map.cubes[i] { - // panic!("{} >= {} not sorted", map.cubes[i - 1], map.cubes[i]) - // } - // } let map = to_min_rot_points(map, dim, count); store.insert(map); } @@ -369,10 +383,10 @@ fn enumerate_canonical_children( /// run pointlist based generation algorithm pub fn gen_polycubes( n: usize, - use_cache: bool, - compression: Compression, + _use_cache: bool, + _compression: Compression, parallel: bool, - mut current: Vec, + current: Vec, calculate_from: usize, ) -> usize { let t1_start = Instant::now(); @@ -399,10 +413,12 @@ pub fn gen_polycubes( let steps = work_count.fetch_add(1, Ordering::Relaxed) + 1; let t1_now = Instant::now(); let time = t1_now.duration_since(t1_start).as_secs() as usize; + let rem_time = (time * seed_count) / steps - time; bar.set_message(format!( - "seed subsets expanded for N = {}. est {}m remaining..", + "seed subsets expanded for N = {}. est {}:{:02}m remaining..", calculate_from - 1, - ((time * seed_count) / steps - time) / 60 + rem_time / 60, + rem_time % 60 )); bar.inc(1); }); @@ -417,10 +433,12 @@ pub fn gen_polycubes( let steps = work_count.fetch_add(1, Ordering::Relaxed) + 1; let t1_now = Instant::now(); let time = t1_now.duration_since(t1_start).as_secs() as usize; + let rem_time = (time * seed_count) / steps - time; bar.set_message(format!( - "seed subsets expanded for N = {}. est {}m remaining..", + "seed subsets expanded for N = {}. est {}:{:02}m remaining..", calculate_from - 1, - (time * seed_count) / steps / 60 + rem_time / 60, + rem_time % 60 )); bar.inc(1); }); From 52699f2afd021b0fefe51ade7a601022d56f1796 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNailLegProcessorDivide=E2=80=9D?= Date: Sat, 22 Jul 2023 14:11:12 +0100 Subject: [PATCH 06/13] perf maybe --- rust/src/hashless.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/rust/src/hashless.rs b/rust/src/hashless.rs index 4f2d55d..097d2d8 100644 --- a/rust/src/hashless.rs +++ b/rust/src/hashless.rs @@ -31,42 +31,48 @@ fn is_continuous(polycube: &[u16]) -> bool { && polycube[0..polycube.len() - 1].contains(&(p - 1)) && !to_explore[0..exp_head].contains(&(p - 1)) { - to_explore[exp_head] = p - 1; + //to_explore[exp_head] = p - 1; + unsafe {*to_explore.get_unchecked_mut(exp_head) = p - 1;} exp_head += 1; } if p & 0x1f != 0x1f && polycube[1..].contains(&(p + 1)) && !to_explore[0..exp_head].contains(&(p + 1)) { - to_explore[exp_head] = p + 1; + //to_explore[exp_head] = p + 1; + unsafe {*to_explore.get_unchecked_mut(exp_head) = p + 1;} exp_head += 1; } if (p >> 5) & 0x1f != 0 && polycube[0..polycube.len() - 1].contains(&(p - (1 << 5))) && !to_explore[0..exp_head].contains(&(p - (1 << 5))) { - to_explore[exp_head] = p - (1 << 5); + //to_explore[exp_head] = p - (1 << 5); + unsafe {*to_explore.get_unchecked_mut(exp_head) = p - (1 << 5);} exp_head += 1; } if (p >> 5) & 0x1f != 0x1f && polycube[1..].contains(&(p + (1 << 5))) && !to_explore[0..exp_head].contains(&(p + (1 << 5))) { - to_explore[exp_head] = p + (1 << 5); + //to_explore[exp_head] = p + (1 << 5); + unsafe {*to_explore.get_unchecked_mut(exp_head) = p + (1 << 5);} exp_head += 1; } if (p >> 10) & 0x1f != 0 && polycube[0..polycube.len() - 1].contains(&(p - (1 << 10))) && !to_explore[0..exp_head].contains(&(p - (1 << 10))) { - to_explore[exp_head] = p - (1 << 10); + //to_explore[exp_head] = p - (1 << 10); + unsafe {*to_explore.get_unchecked_mut(exp_head) = p - (1 << 10);} exp_head += 1; } if (p >> 10) & 0x1f != 0x1f && polycube[1..].contains(&(p + (1 << 10))) && !to_explore[0..exp_head].contains(&(p + (1 << 10))) { - to_explore[exp_head] = p + (1 << 10); + //to_explore[exp_head] = p + (1 << 10); + unsafe {*to_explore.get_unchecked_mut(exp_head) = p + (1 << 10);} exp_head += 1; } } @@ -131,7 +137,8 @@ fn renormalize(exp: &CubeMapPos, dim: &Dim, count: usize) -> (CubeMapPos, Dim) { let cy = map_coord(dx, dy, dz, &dim, y_col); let cz = map_coord(dx, dy, dz, &dim, z_col); let pack = ((cz << 10) | (cy << 5) | cx) as u16; - dst.cubes[i] = pack; + //dst.cubes[i] = pack; + unsafe {*dst.cubes.get_unchecked_mut(i) = pack;} } //dst.cubes.sort(); (dst, rdim) @@ -148,7 +155,8 @@ fn remove_cube(exp: &CubeMapPos, point: usize, count: usize) -> (CubeMapPos, Dim let mut candidate_ptr = 0; for i in 0..=count { if i != point { - let pos = exp.cubes[i]; + //let pos = exp.cubes[i]; + let pos = unsafe {*exp.cubes.get_unchecked(i)}; let x = pos as usize & 0x1f; let y = (pos as usize >> 5) & 0x1f; let z = (pos as usize >> 10) & 0x1f; @@ -158,7 +166,8 @@ fn remove_cube(exp: &CubeMapPos, point: usize, count: usize) -> (CubeMapPos, Dim max_corner.x = max(max_corner.x, x); max_corner.y = max(max_corner.y, y); max_corner.z = max(max_corner.z, z); - root_candidate.cubes[candidate_ptr] = exp.cubes[i]; + //root_candidate.cubes[candidate_ptr] = pos; + unsafe {*root_candidate.cubes.get_unchecked_mut(candidate_ptr) = pos;} candidate_ptr += 1; } } From 01d860e37763a5c06d95115ea2106dfc9db2b44c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNailLegProcessorDivide=E2=80=9D?= Date: Sat, 22 Jul 2023 18:12:21 +0100 Subject: [PATCH 07/13] more vectorisable continuous function, generic number of cubes (now limited to 32) --- rust/src/hashless.rs | 101 ++++++++++++++++++++------------------ rust/src/pointlist.rs | 24 ++++----- rust/src/polycube_reps.rs | 23 +++++---- rust/src/rotations.rs | 16 +++--- 4 files changed, 86 insertions(+), 78 deletions(-) diff --git a/rust/src/hashless.rs b/rust/src/hashless.rs index 097d2d8..e0eba22 100644 --- a/rust/src/hashless.rs +++ b/rust/src/hashless.rs @@ -17,70 +17,75 @@ use crate::{ Compression, }; -fn is_continuous(polycube: &[u16]) -> bool { - let start = polycube[0]; +fn is_continuous(in_polycube: &[u16]) -> bool { + let start = in_polycube[0]; + let mut polycube2 = [start; 32]; + for i in 1..in_polycube.len() { + polycube2[i] = in_polycube[i]; + } + let polycube = polycube2; //sets were actually slower even when no allocating - let mut to_explore = [0; 32]; + let mut to_explore = [start; 32]; let mut exp_head = 1; let mut exp_tail = 0; - to_explore[0] = start; + //to_explore[0] = start; while exp_head > exp_tail { let p = to_explore[exp_tail]; exp_tail += 1; if p & 0x1f != 0 - && polycube[0..polycube.len() - 1].contains(&(p - 1)) - && !to_explore[0..exp_head].contains(&(p - 1)) + && !to_explore.contains(&(p - 1)) + && polycube.contains(&(p - 1)) { - //to_explore[exp_head] = p - 1; - unsafe {*to_explore.get_unchecked_mut(exp_head) = p - 1;} + to_explore[exp_head] = p - 1; + // unsafe {*to_explore.get_unchecked_mut(exp_head) = p - 1;} exp_head += 1; } if p & 0x1f != 0x1f - && polycube[1..].contains(&(p + 1)) - && !to_explore[0..exp_head].contains(&(p + 1)) + && !to_explore.contains(&(p + 1)) + && polycube.contains(&(p + 1)) { - //to_explore[exp_head] = p + 1; - unsafe {*to_explore.get_unchecked_mut(exp_head) = p + 1;} + to_explore[exp_head] = p + 1; + // unsafe {*to_explore.get_unchecked_mut(exp_head) = p + 1;} exp_head += 1; } if (p >> 5) & 0x1f != 0 - && polycube[0..polycube.len() - 1].contains(&(p - (1 << 5))) - && !to_explore[0..exp_head].contains(&(p - (1 << 5))) + && !to_explore.contains(&(p - (1 << 5))) + && polycube.contains(&(p - (1 << 5))) { - //to_explore[exp_head] = p - (1 << 5); - unsafe {*to_explore.get_unchecked_mut(exp_head) = p - (1 << 5);} + to_explore[exp_head] = p - (1 << 5); + // unsafe {*to_explore.get_unchecked_mut(exp_head) = p - (1 << 5);} exp_head += 1; } if (p >> 5) & 0x1f != 0x1f - && polycube[1..].contains(&(p + (1 << 5))) - && !to_explore[0..exp_head].contains(&(p + (1 << 5))) + && !to_explore.contains(&(p + (1 << 5))) + && polycube.contains(&(p + (1 << 5))) { - //to_explore[exp_head] = p + (1 << 5); - unsafe {*to_explore.get_unchecked_mut(exp_head) = p + (1 << 5);} + to_explore[exp_head] = p + (1 << 5); + // unsafe {*to_explore.get_unchecked_mut(exp_head) = p + (1 << 5);} exp_head += 1; } if (p >> 10) & 0x1f != 0 - && polycube[0..polycube.len() - 1].contains(&(p - (1 << 10))) - && !to_explore[0..exp_head].contains(&(p - (1 << 10))) + && !to_explore.contains(&(p - (1 << 10))) + && polycube.contains(&(p - (1 << 10))) { - //to_explore[exp_head] = p - (1 << 10); - unsafe {*to_explore.get_unchecked_mut(exp_head) = p - (1 << 10);} + to_explore[exp_head] = p - (1 << 10); + // unsafe {*to_explore.get_unchecked_mut(exp_head) = p - (1 << 10);} exp_head += 1; } if (p >> 10) & 0x1f != 0x1f - && polycube[1..].contains(&(p + (1 << 10))) - && !to_explore[0..exp_head].contains(&(p + (1 << 10))) + && !to_explore.contains(&(p + (1 << 10))) + && polycube.contains(&(p + (1 << 10))) { - //to_explore[exp_head] = p + (1 << 10); - unsafe {*to_explore.get_unchecked_mut(exp_head) = p + (1 << 10);} + to_explore[exp_head] = p + (1 << 10); + // unsafe {*to_explore.get_unchecked_mut(exp_head) = p + (1 << 10);} exp_head += 1; } } - exp_head == polycube.len() + exp_head == in_polycube.len() } -fn renormalize(exp: &CubeMapPos, dim: &Dim, count: usize) -> (CubeMapPos, Dim) { - let mut dst = CubeMapPos { cubes: [0; 16] }; +fn renormalize(exp: &CubeMapPos<32>, dim: &Dim, count: usize) -> (CubeMapPos<32>, Dim) { + let mut dst = CubeMapPos::new(); let x = dim.x; let y = dim.y; let z = dim.z; @@ -137,26 +142,26 @@ fn renormalize(exp: &CubeMapPos, dim: &Dim, count: usize) -> (CubeMapPos, Dim) { let cy = map_coord(dx, dy, dz, &dim, y_col); let cz = map_coord(dx, dy, dz, &dim, z_col); let pack = ((cz << 10) | (cy << 5) | cx) as u16; - //dst.cubes[i] = pack; - unsafe {*dst.cubes.get_unchecked_mut(i) = pack;} + dst.cubes[i] = pack; + // unsafe {*dst.cubes.get_unchecked_mut(i) = pack;} } //dst.cubes.sort(); (dst, rdim) } -fn remove_cube(exp: &CubeMapPos, point: usize, count: usize) -> (CubeMapPos, Dim) { +fn remove_cube(exp: &CubeMapPos<32>, point: usize, count: usize) -> (CubeMapPos<32>, Dim) { let mut min_corner = Dim { x: 0x1f, y: 0x1f, z: 0x1f, }; let mut max_corner = Dim { x: 0, y: 0, z: 0 }; - let mut root_candidate = CubeMapPos { cubes: [0; 16] }; + let mut root_candidate = CubeMapPos::new(); let mut candidate_ptr = 0; for i in 0..=count { if i != point { - //let pos = exp.cubes[i]; - let pos = unsafe {*exp.cubes.get_unchecked(i)}; + let pos = exp.cubes[i]; + // let pos = unsafe {*exp.cubes.get_unchecked(i)}; let x = pos as usize & 0x1f; let y = (pos as usize >> 5) & 0x1f; let z = (pos as usize >> 10) & 0x1f; @@ -166,8 +171,8 @@ fn remove_cube(exp: &CubeMapPos, point: usize, count: usize) -> (CubeMapPos, Dim max_corner.x = max(max_corner.x, x); max_corner.y = max(max_corner.y, y); max_corner.z = max(max_corner.z, z); - //root_candidate.cubes[candidate_ptr] = pos; - unsafe {*root_candidate.cubes.get_unchecked_mut(candidate_ptr) = pos;} + root_candidate.cubes[candidate_ptr] = pos; + // unsafe {*root_candidate.cubes.get_unchecked_mut(candidate_ptr) = pos;} candidate_ptr += 1; } } @@ -181,7 +186,7 @@ fn remove_cube(exp: &CubeMapPos, point: usize, count: usize) -> (CubeMapPos, Dim (root_candidate, max_corner) } -fn is_canonical_root(exp: &CubeMapPos, count: usize, seed: &CubeMapPos) -> bool { +fn is_canonical_root(exp: &CubeMapPos<32>, count: usize, seed: &CubeMapPos<32>) -> bool { for sub_cube_id in 0..=count { let (mut root_candidate, mut dim) = remove_cube(exp, sub_cube_id, count); if !is_continuous(&root_candidate.cubes[0..count]) { @@ -203,7 +208,7 @@ fn is_canonical_root(exp: &CubeMapPos, count: usize, seed: &CubeMapPos) -> bool /// helper function to not duplicate code for canonicalising polycubes /// and storing them in the hashset -fn insert_map(store: &mut HashSet, dim: &Dim, map: &CubeMapPos, count: usize) { +fn insert_map(store: &mut HashSet>, dim: &Dim, map: &CubeMapPos<32>, count: usize) { let map = to_min_rot_points(map, dim, count); store.insert(map); } @@ -211,7 +216,7 @@ fn insert_map(store: &mut HashSet, dim: &Dim, map: &CubeMapPos, coun /// try expaning each cube into both x+1 and x-1, calculating new dimension /// and ensuring x is never negative #[inline] -fn expand_xs(dst: &mut HashSet, seed: &CubeMapPos, shape: &Dim, count: usize) { +fn expand_xs(dst: &mut HashSet>, seed: &CubeMapPos<32>, shape: &Dim, count: usize) { for (i, coord) in seed.cubes[0..count].iter().enumerate() { if !seed.cubes[(i + 1)..count].contains(&(coord + 1)) { let mut new_shape = *shape; @@ -246,7 +251,7 @@ fn expand_xs(dst: &mut HashSet, seed: &CubeMapPos, shape: &Dim, coun /// try expaning each cube into both y+1 and y-1, calculating new dimension /// and ensuring y is never negative #[inline] -fn expand_ys(dst: &mut HashSet, seed: &CubeMapPos, shape: &Dim, count: usize) { +fn expand_ys(dst: &mut HashSet>, seed: &CubeMapPos<32>, shape: &Dim, count: usize) { for (i, coord) in seed.cubes[0..count].iter().enumerate() { if !seed.cubes[(i + 1)..count].contains(&(coord + (1 << 5))) { let mut new_shape = *shape; @@ -280,7 +285,7 @@ fn expand_ys(dst: &mut HashSet, seed: &CubeMapPos, shape: &Dim, coun /// try expaning each cube into both z+1 and z-1, calculating new dimension /// and ensuring z is never negative #[inline] -fn expand_zs(dst: &mut HashSet, seed: &CubeMapPos, shape: &Dim, count: usize) { +fn expand_zs(dst: &mut HashSet>, seed: &CubeMapPos<32>, shape: &Dim, count: usize) { for (i, coord) in seed.cubes[0..count].iter().enumerate() { if !seed.cubes[(i + 1)..count].contains(&(coord + (1 << 10))) { let mut new_shape = *shape; @@ -314,7 +319,7 @@ fn expand_zs(dst: &mut HashSet, seed: &CubeMapPos, shape: &Dim, coun /// reduce number of expansions needing to be performed based on /// X >= Y >= Z constraint on Dim #[inline] -fn do_cube_expansion(dst: &mut HashSet, seed: &CubeMapPos, shape: &Dim, count: usize) { +fn do_cube_expansion(dst: &mut HashSet>, seed: &CubeMapPos<32>, shape: &Dim, count: usize) { if shape.y < shape.x { expand_ys(dst, seed, shape, count); } @@ -328,7 +333,7 @@ fn do_cube_expansion(dst: &mut HashSet, seed: &CubeMapPos, shape: &D /// if perform extra expansions for cases where the dimensions are equal as /// square sides may miss poly cubes otherwise #[inline] -fn expand_cube_map(dst: &mut HashSet, seed: &CubeMapPos, shape: &Dim, count: usize) { +fn expand_cube_map(dst: &mut HashSet>, seed: &CubeMapPos<32>, shape: &Dim, count: usize) { if shape.x == shape.y && shape.x > 0 { let rotz = rot_matrix_points( seed, @@ -369,10 +374,10 @@ fn expand_cube_map(dst: &mut HashSet, seed: &CubeMapPos, shape: &Dim } fn enumerate_canonical_children( - seed: &CubeMapPos, + seed: &CubeMapPos<32>, count: usize, target: usize, - set_stack: &[RwLock>], + set_stack: &[RwLock>>], ) -> usize { let mut children = set_stack[count].write(); children.clear(); diff --git a/rust/src/pointlist.rs b/rust/src/pointlist.rs index 4924718..8684022 100644 --- a/rust/src/pointlist.rs +++ b/rust/src/pointlist.rs @@ -23,7 +23,7 @@ type MapStore = HashMap<(Dim, u16), RwLock>>; /// helper function to not duplicate code for canonicalising polycubes /// and storing them in the hashset -fn insert_map(store: &MapStore, dim: &Dim, map: &CubeMapPos, count: usize) { +fn insert_map(store: &MapStore, dim: &Dim, map: &CubeMapPos<16>, count: usize) { let map = to_min_rot_points(map, dim, count); let mut body = CubeMapPosPart { cubes: [0; 15] }; for i in 1..count { @@ -67,7 +67,7 @@ pub fn array_shift(arr: &mut [u16]) { /// try expaning each cube into both x+1 and x-1, calculating new dimension /// and ensuring x is never negative #[inline] -fn expand_xs(dst: &MapStore, seed: &CubeMapPos, shape: &Dim, count: usize) { +fn expand_xs(dst: &MapStore, seed: &CubeMapPos<16>, shape: &Dim, count: usize) { for (i, coord) in seed.cubes[0..count].iter().enumerate() { if !seed.cubes[(i + 1)..count].contains(&(coord + 1)) { let mut new_shape = *shape; @@ -102,7 +102,7 @@ fn expand_xs(dst: &MapStore, seed: &CubeMapPos, shape: &Dim, count: usize) { /// try expaning each cube into both y+1 and y-1, calculating new dimension /// and ensuring y is never negative #[inline] -fn expand_ys(dst: &MapStore, seed: &CubeMapPos, shape: &Dim, count: usize) { +fn expand_ys(dst: &MapStore, seed: &CubeMapPos<16>, shape: &Dim, count: usize) { for (i, coord) in seed.cubes[0..count].iter().enumerate() { if !seed.cubes[(i + 1)..count].contains(&(coord + (1 << 5))) { let mut new_shape = *shape; @@ -136,7 +136,7 @@ fn expand_ys(dst: &MapStore, seed: &CubeMapPos, shape: &Dim, count: usize) { /// try expaning each cube into both z+1 and z-1, calculating new dimension /// and ensuring z is never negative #[inline] -fn expand_zs(dst: &MapStore, seed: &CubeMapPos, shape: &Dim, count: usize) { +fn expand_zs(dst: &MapStore, seed: &CubeMapPos<16>, shape: &Dim, count: usize) { for (i, coord) in seed.cubes[0..count].iter().enumerate() { if !seed.cubes[(i + 1)..count].contains(&(coord + (1 << 10))) { let mut new_shape = *shape; @@ -170,7 +170,7 @@ fn expand_zs(dst: &MapStore, seed: &CubeMapPos, shape: &Dim, count: usize) { /// reduce number of expansions needing to be performed based on /// X >= Y >= Z constraint on Dim #[inline] -fn do_cube_expansion(dst: &MapStore, seed: &CubeMapPos, shape: &Dim, count: usize) { +fn do_cube_expansion(dst: &MapStore, seed: &CubeMapPos<16>, shape: &Dim, count: usize) { if shape.y < shape.x { expand_ys(dst, seed, shape, count); } @@ -184,7 +184,7 @@ fn do_cube_expansion(dst: &MapStore, seed: &CubeMapPos, shape: &Dim, count: usiz /// if perform extra expansions for cases where the dimensions are equal as /// square sides may miss poly cubes otherwise #[inline] -fn expand_cube_map(dst: &MapStore, seed: &CubeMapPos, shape: &Dim, count: usize) { +fn expand_cube_map(dst: &MapStore, seed: &CubeMapPos<16>, shape: &Dim, count: usize) { if shape.x == shape.y && shape.x > 0 { let rotz = rot_matrix_points( seed, @@ -300,13 +300,13 @@ fn count_polycubes(maps: &MapStore) -> usize { } /// distructively move the data from hashset to vector -fn move_polycubes_to_vec(maps: &mut MapStore) -> Vec { +fn move_polycubes_to_vec(maps: &mut MapStore) -> Vec> { let mut v = Vec::new(); while let Some(((dim, head), body)) = maps.iter().next() { //extra scope to free lock and make borrow checker allow mutation of maps { let bod = body.read(); - let mut cmp = CubeMapPos { cubes: [0; 16] }; + let mut cmp = CubeMapPos::new(); cmp.cubes[0] = *head; for b in bod.iter() { for i in 0..15 { @@ -323,14 +323,14 @@ fn move_polycubes_to_vec(maps: &mut MapStore) -> Vec { } /// distructively move the data from hashset to vector -fn clone_polycubes_to_vec(maps: &mut MapStore) -> Vec { +fn clone_polycubes_to_vec(maps: &mut MapStore) -> Vec> { let mut v = Vec::new(); for ((_, head), body) in maps.iter() { //extra scope to free lock and make borrow checker allow mutation of maps { let bod = body.read(); - let mut cmp = CubeMapPos { cubes: [0; 16] }; + let mut cmp = CubeMapPos::new(); cmp.cubes[0] = *head; for b in bod.iter() { for i in 0..15 { @@ -351,13 +351,13 @@ pub fn gen_polycubes( parallel: bool, current: Vec, calculate_from: usize, -) -> Vec { +) -> Vec> { let t1_start = Instant::now(); //convert input vector of NaivePolyCubes and convert them to let mut seeds = MapStore::new(); for seed in current.iter() { - let seed: CubeMapPos = seed.into(); + let seed: CubeMapPos<16> = seed.into(); let dim = seed.extrapolate_dim(); if !seeds.contains_key(&(dim, seed.cubes[0])) { for i in 0..(dim.y * 32 + dim.x + 1) { diff --git a/rust/src/polycube_reps.rs b/rust/src/polycube_reps.rs index 57a67e4..d3e7a14 100644 --- a/rust/src/polycube_reps.rs +++ b/rust/src/polycube_reps.rs @@ -9,15 +9,15 @@ use crate::rotations::{map_coord, MatrixCol}; /// well formed polycubes are a sorted list of coordinates low to high /// cordinates are group of packed 5 bit unsigned integers '-ZZZZZYYYYYXXXXX' #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug, PartialOrd, Ord)] -pub struct CubeMapPos { - pub cubes: [u16; 16], +pub struct CubeMapPos { + pub cubes: [u16; N], } /// Conversion function to assist with loading Polycubes from cache file to point-list implementation /// Returned cubes may not be fully canonicalized (X >= Y >= Z guarenteed but not exact rotation) -impl From<&RawPCube> for CubeMapPos { +impl From<&RawPCube> for CubeMapPos { fn from(src: &RawPCube) -> Self { - let mut dst = CubeMapPos { cubes: [0; 16] }; + let mut dst = CubeMapPos { cubes: [0; N] }; let (x, y, z) = src.dims(); let x = x as usize; let y = y as usize; @@ -112,8 +112,8 @@ impl From<&RawPCube> for CubeMapPos { } } -impl From<&'_ CubeMapPos> for RawPCube { - fn from(src: &'_ CubeMapPos) -> Self { +impl From<&'_ CubeMapPos> for RawPCube { + fn from(src: &'_ CubeMapPos) -> Self { //cube is sorted numerically and then has trailing zeros let count = src.extrapolate_count(); let dim = src.extrapolate_dim(); @@ -129,19 +129,22 @@ impl From<&'_ CubeMapPos> for RawPCube { } } -impl From for CubeMapPos { +impl From for CubeMapPos { fn from(value: RawPCube) -> Self { value.into() } } -impl From for RawPCube { - fn from(value: CubeMapPos) -> Self { +impl From> for RawPCube { + fn from(value: CubeMapPos) -> Self { value.into() } } -impl CubeMapPos { +impl CubeMapPos { + pub fn new() -> Self { + CubeMapPos {cubes: [0; N]} + } pub fn extrapolate_count(&self) -> usize { let mut count = 1; while self.cubes[count] > self.cubes[count - 1] { diff --git a/rust/src/rotations.rs b/rust/src/rotations.rs index 88a45ec..a94e080 100644 --- a/rust/src/rotations.rs +++ b/rust/src/rotations.rs @@ -339,16 +339,16 @@ pub fn map_coord(x: u16, y: u16, z: u16, shape: &Dim, col: MatrixCol) -> u16 { } #[inline] -pub fn rot_matrix_points( - map: &CubeMapPos, +pub fn rot_matrix_points( + map: &CubeMapPos, shape: &Dim, count: usize, x_col: MatrixCol, y_col: MatrixCol, z_col: MatrixCol, pmin: u16, -) -> CubeMapPos { - let mut res = CubeMapPos { cubes: [0; 16] }; +) -> CubeMapPos { + let mut res = CubeMapPos::new(); let mut mmin = 1024; for (i, coord) in map.cubes[0..count].iter().enumerate() { let ix = coord & 0x1f; @@ -371,7 +371,7 @@ pub fn rot_matrix_points( } #[inline] -fn xy_rots_points(map: &CubeMapPos, shape: &Dim, count: usize, res: &mut CubeMapPos) { +fn xy_rots_points(map: &CubeMapPos, shape: &Dim, count: usize, res: &mut CubeMapPos) { *res = min( *res, rot_matrix_points( @@ -426,7 +426,7 @@ fn xy_rots_points(map: &CubeMapPos, shape: &Dim, count: usize, res: &mut CubeMap } #[inline] -fn yz_rots_points(map: &CubeMapPos, shape: &Dim, count: usize, res: &mut CubeMapPos) { +fn yz_rots_points(map: &CubeMapPos, shape: &Dim, count: usize, res: &mut CubeMapPos) { *res = min( *res, rot_matrix_points( @@ -481,7 +481,7 @@ fn yz_rots_points(map: &CubeMapPos, shape: &Dim, count: usize, res: &mut CubeMap } #[inline] -fn xyz_rots_points(map: &CubeMapPos, shape: &Dim, count: usize, res: &mut CubeMapPos) { +fn xyz_rots_points(map: &CubeMapPos, shape: &Dim, count: usize, res: &mut CubeMapPos) { //xz *res = min( *res, @@ -641,7 +641,7 @@ fn xyz_rots_points(map: &CubeMapPos, shape: &Dim, count: usize, res: &mut CubeMa ); } -pub fn to_min_rot_points(map: &CubeMapPos, shape: &Dim, count: usize) -> CubeMapPos { +pub fn to_min_rot_points(map: &CubeMapPos, shape: &Dim, count: usize) -> CubeMapPos { let mut res = *map; if shape.x == shape.y && shape.x != 0 { xy_rots_points(map, shape, count, &mut res); From 63f15bba7f8036126dd1c3dc3cbb3f100a2c09fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNailLegProcessorDivide=E2=80=9D?= Date: Sat, 22 Jul 2023 20:42:36 +0100 Subject: [PATCH 08/13] into fix --- rust/src/polycube_reps.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rust/src/polycube_reps.rs b/rust/src/polycube_reps.rs index d3e7a14..87cceb7 100644 --- a/rust/src/polycube_reps.rs +++ b/rust/src/polycube_reps.rs @@ -131,13 +131,13 @@ impl From<&'_ CubeMapPos> for RawPCube { impl From for CubeMapPos { fn from(value: RawPCube) -> Self { - value.into() + (&value).into() } } impl From> for RawPCube { fn from(value: CubeMapPos) -> Self { - value.into() + (&value).into() } } From 5f76ef77cfe1d1492ea212a770f27fcf0db3c29f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNailLegProcessorDivide=E2=80=9D?= Date: Sun, 23 Jul 2023 00:53:29 +0100 Subject: [PATCH 09/13] some code improvements --- rust/src/cli.rs | 2 +- rust/src/hashless.rs | 290 +++++--------------------------------- rust/src/polycube_reps.rs | 191 ++++++++++++++++++++++--- rust/src/rotations.rs | 27 +++- 4 files changed, 233 insertions(+), 277 deletions(-) diff --git a/rust/src/cli.rs b/rust/src/cli.rs index 0bfac1e..3c1702f 100644 --- a/rust/src/cli.rs +++ b/rust/src/cli.rs @@ -54,7 +54,7 @@ pub fn make_bar(len: u64) -> indicatif::ProgressBar { let pos_width = format!("{len}").len(); let template = - format!("[{{elapsed_precise}}] {{bar:40.cyan/blue}} {{pos:>{pos_width}}}/{{len}} {{msg}}"); + format!("[{{elapsed_precise}}] {{bar:40.cyan/blue}} {{pos:>{pos_width}}}/{{len}} remaining: [{{eta_precise}}] {{msg}}"); bar.set_style( ProgressStyle::with_template(&template) diff --git a/rust/src/hashless.rs b/rust/src/hashless.rs index e0eba22..4343de5 100644 --- a/rust/src/hashless.rs +++ b/rust/src/hashless.rs @@ -1,211 +1,17 @@ -use std::{ - cmp::{max, min}, - sync::atomic::{AtomicUsize, Ordering}, - time::Instant, -}; +use std::{cmp::max, time::Instant}; use hashbrown::HashSet; use opencubes::pcube::RawPCube; -use parking_lot::RwLock; use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; use crate::{ make_bar, pointlist::{array_insert, array_shift}, polycube_reps::{CubeMapPos, Dim}, - rotations::{map_coord, rot_matrix_points, to_min_rot_points, MatrixCol}, + rotations::{rot_matrix_points, to_min_rot_points, MatrixCol}, Compression, }; -fn is_continuous(in_polycube: &[u16]) -> bool { - let start = in_polycube[0]; - let mut polycube2 = [start; 32]; - for i in 1..in_polycube.len() { - polycube2[i] = in_polycube[i]; - } - let polycube = polycube2; - //sets were actually slower even when no allocating - let mut to_explore = [start; 32]; - let mut exp_head = 1; - let mut exp_tail = 0; - //to_explore[0] = start; - while exp_head > exp_tail { - let p = to_explore[exp_tail]; - exp_tail += 1; - if p & 0x1f != 0 - && !to_explore.contains(&(p - 1)) - && polycube.contains(&(p - 1)) - { - to_explore[exp_head] = p - 1; - // unsafe {*to_explore.get_unchecked_mut(exp_head) = p - 1;} - exp_head += 1; - } - if p & 0x1f != 0x1f - && !to_explore.contains(&(p + 1)) - && polycube.contains(&(p + 1)) - { - to_explore[exp_head] = p + 1; - // unsafe {*to_explore.get_unchecked_mut(exp_head) = p + 1;} - exp_head += 1; - } - if (p >> 5) & 0x1f != 0 - && !to_explore.contains(&(p - (1 << 5))) - && polycube.contains(&(p - (1 << 5))) - { - to_explore[exp_head] = p - (1 << 5); - // unsafe {*to_explore.get_unchecked_mut(exp_head) = p - (1 << 5);} - exp_head += 1; - } - if (p >> 5) & 0x1f != 0x1f - && !to_explore.contains(&(p + (1 << 5))) - && polycube.contains(&(p + (1 << 5))) - { - to_explore[exp_head] = p + (1 << 5); - // unsafe {*to_explore.get_unchecked_mut(exp_head) = p + (1 << 5);} - exp_head += 1; - } - if (p >> 10) & 0x1f != 0 - && !to_explore.contains(&(p - (1 << 10))) - && polycube.contains(&(p - (1 << 10))) - { - to_explore[exp_head] = p - (1 << 10); - // unsafe {*to_explore.get_unchecked_mut(exp_head) = p - (1 << 10);} - exp_head += 1; - } - if (p >> 10) & 0x1f != 0x1f - && !to_explore.contains(&(p + (1 << 10))) - && polycube.contains(&(p + (1 << 10))) - { - to_explore[exp_head] = p + (1 << 10); - // unsafe {*to_explore.get_unchecked_mut(exp_head) = p + (1 << 10);} - exp_head += 1; - } - } - exp_head == in_polycube.len() -} - -fn renormalize(exp: &CubeMapPos<32>, dim: &Dim, count: usize) -> (CubeMapPos<32>, Dim) { - let mut dst = CubeMapPos::new(); - let x = dim.x; - let y = dim.y; - let z = dim.z; - let (x_col, y_col, z_col, rdim) = if x >= y && y >= z { - ( - MatrixCol::XP, - MatrixCol::YP, - MatrixCol::ZP, - Dim { x: x, y: y, z: z }, - ) - } else if x >= z && z >= y { - ( - MatrixCol::XP, - MatrixCol::ZP, - MatrixCol::YN, - Dim { x: x, y: z, z: y }, - ) - } else if y >= x && x >= z { - ( - MatrixCol::YP, - MatrixCol::XP, - MatrixCol::ZN, - Dim { x: y, y: x, z: z }, - ) - } else if y >= z && z >= x { - ( - MatrixCol::YP, - MatrixCol::ZP, - MatrixCol::XP, - Dim { x: y, y: z, z: x }, - ) - } else if z >= x && x >= y { - ( - MatrixCol::ZN, - MatrixCol::XP, - MatrixCol::YN, - Dim { x: z, y: x, z: y }, - ) - } else if z >= y && y >= x { - ( - MatrixCol::ZN, - MatrixCol::YN, - MatrixCol::XP, - Dim { x: z, y: y, z: x }, - ) - } else { - panic!("imposible dimension of shape {:?}", dim) - }; - for (i, d) in exp.cubes[0..count].iter().enumerate() { - let dx = d & 0x1f; - let dy = (d >> 5) & 0x1f; - let dz = (d >> 10) & 0x1f; - let cx = map_coord(dx, dy, dz, &dim, x_col); - let cy = map_coord(dx, dy, dz, &dim, y_col); - let cz = map_coord(dx, dy, dz, &dim, z_col); - let pack = ((cz << 10) | (cy << 5) | cx) as u16; - dst.cubes[i] = pack; - // unsafe {*dst.cubes.get_unchecked_mut(i) = pack;} - } - //dst.cubes.sort(); - (dst, rdim) -} - -fn remove_cube(exp: &CubeMapPos<32>, point: usize, count: usize) -> (CubeMapPos<32>, Dim) { - let mut min_corner = Dim { - x: 0x1f, - y: 0x1f, - z: 0x1f, - }; - let mut max_corner = Dim { x: 0, y: 0, z: 0 }; - let mut root_candidate = CubeMapPos::new(); - let mut candidate_ptr = 0; - for i in 0..=count { - if i != point { - let pos = exp.cubes[i]; - // let pos = unsafe {*exp.cubes.get_unchecked(i)}; - let x = pos as usize & 0x1f; - let y = (pos as usize >> 5) & 0x1f; - let z = (pos as usize >> 10) & 0x1f; - min_corner.x = min(min_corner.x, x); - min_corner.y = min(min_corner.y, y); - min_corner.z = min(min_corner.z, z); - max_corner.x = max(max_corner.x, x); - max_corner.y = max(max_corner.y, y); - max_corner.z = max(max_corner.z, z); - root_candidate.cubes[candidate_ptr] = pos; - // unsafe {*root_candidate.cubes.get_unchecked_mut(candidate_ptr) = pos;} - candidate_ptr += 1; - } - } - let offset = (min_corner.z << 10) | (min_corner.y << 5) | min_corner.x; - for i in 0..count { - root_candidate.cubes[i] -= offset as u16; - } - max_corner.x = max_corner.x - min_corner.x; - max_corner.y = max_corner.y - min_corner.y; - max_corner.z = max_corner.z - min_corner.z; - (root_candidate, max_corner) -} - -fn is_canonical_root(exp: &CubeMapPos<32>, count: usize, seed: &CubeMapPos<32>) -> bool { - for sub_cube_id in 0..=count { - let (mut root_candidate, mut dim) = remove_cube(exp, sub_cube_id, count); - if !is_continuous(&root_candidate.cubes[0..count]) { - continue; - } - if dim.x < dim.y || dim.y < dim.z || dim.x < dim.z { - let (rroot_candidate, rdim) = renormalize(&root_candidate, &dim, count); - root_candidate = rroot_candidate; - dim = rdim; - root_candidate.cubes[0..count].sort_unstable(); - } - let mrp = to_min_rot_points(&root_candidate, &dim, count); - if &mrp < seed { - return false; - } - } - true -} - /// helper function to not duplicate code for canonicalising polycubes /// and storing them in the hashset fn insert_map(store: &mut HashSet>, dim: &Dim, map: &CubeMapPos<32>, count: usize) { @@ -319,7 +125,12 @@ fn expand_zs(dst: &mut HashSet>, seed: &CubeMapPos<32>, shape: &D /// reduce number of expansions needing to be performed based on /// X >= Y >= Z constraint on Dim #[inline] -fn do_cube_expansion(dst: &mut HashSet>, seed: &CubeMapPos<32>, shape: &Dim, count: usize) { +fn do_cube_expansion( + dst: &mut HashSet>, + seed: &CubeMapPos<32>, + shape: &Dim, + count: usize, +) { if shape.y < shape.x { expand_ys(dst, seed, shape, count); } @@ -333,7 +144,12 @@ fn do_cube_expansion(dst: &mut HashSet>, seed: &CubeMapPos<32>, s /// if perform extra expansions for cases where the dimensions are equal as /// square sides may miss poly cubes otherwise #[inline] -fn expand_cube_map(dst: &mut HashSet>, seed: &CubeMapPos<32>, shape: &Dim, count: usize) { +fn expand_cube_map( + dst: &mut HashSet>, + seed: &CubeMapPos<32>, + shape: &Dim, + count: usize, +) { if shape.x == shape.y && shape.x > 0 { let rotz = rot_matrix_points( seed, @@ -373,23 +189,18 @@ fn expand_cube_map(dst: &mut HashSet>, seed: &CubeMapPos<32>, sha do_cube_expansion(dst, seed, shape, count); } -fn enumerate_canonical_children( - seed: &CubeMapPos<32>, - count: usize, - target: usize, - set_stack: &[RwLock>>], -) -> usize { - let mut children = set_stack[count].write(); +fn enumerate_canonical_children(seed: &CubeMapPos<32>, count: usize, target: usize) -> usize { + let mut children = HashSet::new(); children.clear(); let shape = seed.extrapolate_dim(); expand_cube_map(&mut children, seed, &shape, count); - children.retain(|child| is_canonical_root(child, count, seed)); + children.retain(|child| child.is_canonical_root(count, seed)); if count + 1 == target { children.len() } else { children .iter() - .map(|child| enumerate_canonical_children(child, count + 1, target, set_stack)) + .map(|child| enumerate_canonical_children(child, count + 1, target)) .sum() } } @@ -405,9 +216,6 @@ pub fn gen_polycubes( ) -> usize { let t1_start = Instant::now(); - let total: AtomicUsize = AtomicUsize::new(0); - let work_count: AtomicUsize = AtomicUsize::new(0); - let seed_count = current.len(); let bar = make_bar(seed_count as u64); bar.set_message(format!( @@ -415,51 +223,27 @@ pub fn gen_polycubes( calculate_from - 1 )); + let process = |seed| { + let children = enumerate_canonical_children(&seed, calculate_from - 1, n); + bar.set_message(format!( + "seed subsets expanded for N = {}...", + calculate_from - 1, + )); + bar.inc(1); + children + }; + //convert input vector of NaivePolyCubes and convert them to - if parallel { - current.par_iter().for_each(|seed| { - let seed = seed.into(); - let sets = (0..n) - .map(|_| RwLock::new(HashSet::new())) - .collect::>(); - let children = enumerate_canonical_children(&seed, calculate_from - 1, n, &sets); - total.fetch_add(children, Ordering::Relaxed); - let steps = work_count.fetch_add(1, Ordering::Relaxed) + 1; - let t1_now = Instant::now(); - let time = t1_now.duration_since(t1_start).as_secs() as usize; - let rem_time = (time * seed_count) / steps - time; - bar.set_message(format!( - "seed subsets expanded for N = {}. est {}:{:02}m remaining..", - calculate_from - 1, - rem_time / 60, - rem_time % 60 - )); - bar.inc(1); - }); + let count: usize = if parallel { + current + .par_iter() + .map(|seed| seed.into()) + .map(process) + .sum() } else { - current.iter().for_each(|seed| { - let seed = seed.into(); - let sets = (0..n) - .map(|_| RwLock::new(HashSet::new())) - .collect::>(); - let children = enumerate_canonical_children(&seed, calculate_from - 1, n, &sets); - total.fetch_add(children, Ordering::Relaxed); - let steps = work_count.fetch_add(1, Ordering::Relaxed) + 1; - let t1_now = Instant::now(); - let time = t1_now.duration_since(t1_start).as_secs() as usize; - let rem_time = (time * seed_count) / steps - time; - bar.set_message(format!( - "seed subsets expanded for N = {}. est {}:{:02}m remaining..", - calculate_from - 1, - rem_time / 60, - rem_time % 60 - )); - bar.inc(1); - }); - } - let count = total.load(Ordering::Relaxed); - let t1_stop = Instant::now(); - let time = t1_stop.duration_since(t1_start).as_micros(); + current.iter().map(|seed| seed.into()).map(process).sum() + }; + let time = t1_start.elapsed().as_micros(); bar.set_message(format!( "Found {} unique expansions (N = {n}) in {}.{:06}s", count, diff --git a/rust/src/polycube_reps.rs b/rust/src/polycube_reps.rs index 87cceb7..bdee9d4 100644 --- a/rust/src/polycube_reps.rs +++ b/rust/src/polycube_reps.rs @@ -1,8 +1,8 @@ -use std::cmp::max; +use std::cmp::{max, min}; use opencubes::pcube::RawPCube; -use crate::rotations::{map_coord, MatrixCol}; +use crate::rotations::{map_coord, to_min_rot_points, MatrixCol::*}; /// Polycube representation /// stores up to 16 blocks (number of cubes normally implicit or seperate in program state) @@ -30,12 +30,12 @@ impl From<&RawPCube> for CubeMapPos { //correction matrix to convert to canonical dimension. I dont like it but it works let (x_col, y_col, z_col, rdim) = if x >= y && y >= z { - (MatrixCol::XP, MatrixCol::YP, MatrixCol::ZP, dim) + (XP, YP, ZP, dim) } else if x >= z && z >= y { ( - MatrixCol::XP, - MatrixCol::ZP, - MatrixCol::YN, + XP, + ZP, + YN, Dim { x: x - 1, y: z - 1, @@ -44,9 +44,9 @@ impl From<&RawPCube> for CubeMapPos { ) } else if y >= x && x >= z { ( - MatrixCol::YP, - MatrixCol::XP, - MatrixCol::ZN, + YP, + XP, + ZN, Dim { x: y - 1, y: x - 1, @@ -55,9 +55,9 @@ impl From<&RawPCube> for CubeMapPos { ) } else if y >= z && z >= x { ( - MatrixCol::YP, - MatrixCol::ZP, - MatrixCol::XP, + YP, + ZP, + XP, Dim { x: y - 1, y: z - 1, @@ -66,9 +66,9 @@ impl From<&RawPCube> for CubeMapPos { ) } else if z >= x && x >= y { ( - MatrixCol::ZN, - MatrixCol::XP, - MatrixCol::YN, + ZN, + XP, + YN, Dim { x: z - 1, y: x - 1, @@ -77,9 +77,9 @@ impl From<&RawPCube> for CubeMapPos { ) } else if z >= y && y >= x { ( - MatrixCol::ZN, - MatrixCol::YN, - MatrixCol::XP, + ZN, + YN, + XP, Dim { x: z - 1, y: y - 1, @@ -143,7 +143,7 @@ impl From> for RawPCube { impl CubeMapPos { pub fn new() -> Self { - CubeMapPos {cubes: [0; N]} + CubeMapPos { cubes: [0; N] } } pub fn extrapolate_count(&self) -> usize { let mut count = 1; @@ -165,6 +165,159 @@ impl CubeMapPos { } dim } + + fn is_continuous(&self, len: usize) -> bool { + let start = self.cubes[0]; + let mut polycube2 = [start; 32]; + for i in 1..len { + polycube2[i] = self.cubes[i]; + } + let polycube = polycube2; + //sets were actually slower even when no allocating + let mut to_explore = [start; 32]; + let mut exp_head = 1; + let mut exp_tail = 0; + //to_explore[0] = start; + while exp_head > exp_tail { + let p = to_explore[exp_tail]; + exp_tail += 1; + if p & 0x1f != 0 && !to_explore.contains(&(p - 1)) && polycube.contains(&(p - 1)) { + to_explore[exp_head] = p - 1; + // unsafe {*to_explore.get_unchecked_mut(exp_head) = p - 1;} + exp_head += 1; + } + if p & 0x1f != 0x1f && !to_explore.contains(&(p + 1)) && polycube.contains(&(p + 1)) { + to_explore[exp_head] = p + 1; + // unsafe {*to_explore.get_unchecked_mut(exp_head) = p + 1;} + exp_head += 1; + } + if (p >> 5) & 0x1f != 0 + && !to_explore.contains(&(p - (1 << 5))) + && polycube.contains(&(p - (1 << 5))) + { + to_explore[exp_head] = p - (1 << 5); + // unsafe {*to_explore.get_unchecked_mut(exp_head) = p - (1 << 5);} + exp_head += 1; + } + if (p >> 5) & 0x1f != 0x1f + && !to_explore.contains(&(p + (1 << 5))) + && polycube.contains(&(p + (1 << 5))) + { + to_explore[exp_head] = p + (1 << 5); + // unsafe {*to_explore.get_unchecked_mut(exp_head) = p + (1 << 5);} + exp_head += 1; + } + if (p >> 10) & 0x1f != 0 + && !to_explore.contains(&(p - (1 << 10))) + && polycube.contains(&(p - (1 << 10))) + { + to_explore[exp_head] = p - (1 << 10); + // unsafe {*to_explore.get_unchecked_mut(exp_head) = p - (1 << 10);} + exp_head += 1; + } + if (p >> 10) & 0x1f != 0x1f + && !to_explore.contains(&(p + (1 << 10))) + && polycube.contains(&(p + (1 << 10))) + { + to_explore[exp_head] = p + (1 << 10); + // unsafe {*to_explore.get_unchecked_mut(exp_head) = p + (1 << 10);} + exp_head += 1; + } + } + exp_head == len + } + + fn renormalize(&self, dim: &Dim, count: usize) -> (Self, Dim) { + let mut dst = CubeMapPos::new(); + let x = dim.x; + let y = dim.y; + let z = dim.z; + let (x_col, y_col, z_col, rdim) = if x >= y && y >= z { + (XP, YP, ZP, Dim { x: x, y: y, z: z }) + } else if x >= z && z >= y { + (XP, ZP, YN, Dim { x: x, y: z, z: y }) + } else if y >= x && x >= z { + (YP, XP, ZN, Dim { x: y, y: x, z: z }) + } else if y >= z && z >= x { + (YP, ZP, XP, Dim { x: y, y: z, z: x }) + } else if z >= x && x >= y { + (ZN, XP, YN, Dim { x: z, y: x, z: y }) + } else if z >= y && y >= x { + (ZN, YN, XP, Dim { x: z, y: y, z: x }) + } else { + panic!("imposible dimension of shape {:?}", dim) + }; + for (i, d) in self.cubes[0..count].iter().enumerate() { + let dx = d & 0x1f; + let dy = (d >> 5) & 0x1f; + let dz = (d >> 10) & 0x1f; + let cx = map_coord(dx, dy, dz, &dim, x_col); + let cy = map_coord(dx, dy, dz, &dim, y_col); + let cz = map_coord(dx, dy, dz, &dim, z_col); + let pack = ((cz << 10) | (cy << 5) | cx) as u16; + dst.cubes[i] = pack; + // unsafe {*dst.cubes.get_unchecked_mut(i) = pack;} + } + //dst.cubes.sort(); + (dst, rdim) + } + + fn remove_cube(&self, point: usize, count: usize) -> (Self, Dim) { + let mut min_corner = Dim { + x: 0x1f, + y: 0x1f, + z: 0x1f, + }; + let mut max_corner = Dim { x: 0, y: 0, z: 0 }; + let mut root_candidate = CubeMapPos::new(); + let mut candidate_ptr = 0; + for i in 0..=count { + if i != point { + let pos = self.cubes[i]; + // let pos = unsafe {*exp.cubes.get_unchecked(i)}; + let x = pos as usize & 0x1f; + let y = (pos as usize >> 5) & 0x1f; + let z = (pos as usize >> 10) & 0x1f; + min_corner.x = min(min_corner.x, x); + min_corner.y = min(min_corner.y, y); + min_corner.z = min(min_corner.z, z); + max_corner.x = max(max_corner.x, x); + max_corner.y = max(max_corner.y, y); + max_corner.z = max(max_corner.z, z); + root_candidate.cubes[candidate_ptr] = pos; + // unsafe {*root_candidate.cubes.get_unchecked_mut(candidate_ptr) = pos;} + candidate_ptr += 1; + } + } + let offset = (min_corner.z << 10) | (min_corner.y << 5) | min_corner.x; + for i in 0..count { + root_candidate.cubes[i] -= offset as u16; + } + max_corner.x = max_corner.x - min_corner.x; + max_corner.y = max_corner.y - min_corner.y; + max_corner.z = max_corner.z - min_corner.z; + (root_candidate, max_corner) + } + + pub fn is_canonical_root(&self, count: usize, seed: &Self) -> bool { + for sub_cube_id in 0..=count { + let (mut root_candidate, mut dim) = self.remove_cube(sub_cube_id, count); + if !root_candidate.is_continuous(count) { + continue; + } + if dim.x < dim.y || dim.y < dim.z || dim.x < dim.z { + let (rroot_candidate, rdim) = root_candidate.renormalize(&dim, count); + root_candidate = rroot_candidate; + dim = rdim; + root_candidate.cubes[0..count].sort_unstable(); + } + let mrp = to_min_rot_points(&root_candidate, &dim, count); + if &mrp < seed { + return false; + } + } + true + } } /// Partial Polycube representation for storage diff --git a/rust/src/rotations.rs b/rust/src/rotations.rs index a94e080..c9834a9 100644 --- a/rust/src/rotations.rs +++ b/rust/src/rotations.rs @@ -371,7 +371,12 @@ pub fn rot_matrix_points( } #[inline] -fn xy_rots_points(map: &CubeMapPos, shape: &Dim, count: usize, res: &mut CubeMapPos) { +fn xy_rots_points( + map: &CubeMapPos, + shape: &Dim, + count: usize, + res: &mut CubeMapPos, +) { *res = min( *res, rot_matrix_points( @@ -426,7 +431,12 @@ fn xy_rots_points(map: &CubeMapPos, shape: &Dim, count: usize } #[inline] -fn yz_rots_points(map: &CubeMapPos, shape: &Dim, count: usize, res: &mut CubeMapPos) { +fn yz_rots_points( + map: &CubeMapPos, + shape: &Dim, + count: usize, + res: &mut CubeMapPos, +) { *res = min( *res, rot_matrix_points( @@ -481,7 +491,12 @@ fn yz_rots_points(map: &CubeMapPos, shape: &Dim, count: usize } #[inline] -fn xyz_rots_points(map: &CubeMapPos, shape: &Dim, count: usize, res: &mut CubeMapPos) { +fn xyz_rots_points( + map: &CubeMapPos, + shape: &Dim, + count: usize, + res: &mut CubeMapPos, +) { //xz *res = min( *res, @@ -641,7 +656,11 @@ fn xyz_rots_points(map: &CubeMapPos, shape: &Dim, count: usiz ); } -pub fn to_min_rot_points(map: &CubeMapPos, shape: &Dim, count: usize) -> CubeMapPos { +pub fn to_min_rot_points( + map: &CubeMapPos, + shape: &Dim, + count: usize, +) -> CubeMapPos { let mut res = *map; if shape.x == shape.y && shape.x != 0 { xy_rots_points(map, shape, count, &mut res); From 88bca6bcd30e4323bd28bd747baf65f8ea4c3f36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNailLegProcessorDivide=E2=80=9D?= Date: Sun, 23 Jul 2023 17:16:37 +0100 Subject: [PATCH 10/13] refactoring --- rust/src/cli.rs | 21 +++++---- rust/src/hashless.rs | 16 +++---- rust/src/lib.rs | 6 +++ rust/src/pointlist.rs | 83 +++++++++++++++++------------------- rust/src/polycube_reps.rs | 2 +- rust/src/rotation_reduced.rs | 8 ++-- 6 files changed, 67 insertions(+), 69 deletions(-) diff --git a/rust/src/cli.rs b/rust/src/cli.rs index 3c1702f..feccaf3 100644 --- a/rust/src/cli.rs +++ b/rust/src/cli.rs @@ -9,16 +9,10 @@ use clap::{Args, Parser, Subcommand, ValueEnum}; use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; use opencubes::{ naive_polycube::NaivePolyCube, - pcube::{PCubeFile, RawPCube}, + pcube::{PCubeFile, RawPCube}, pointlist, rotation_reduced, hashless, }; use rayon::prelude::{IntoParallelIterator, ParallelIterator}; -mod hashless; -mod pointlist; -mod polycube_reps; -mod rotation_reduced; -mod rotations; - fn unknown_bar() -> ProgressBar { let style = ProgressStyle::with_template("[{elapsed_precise}] [{spinner:10.cyan/blue}] {msg}") .unwrap() @@ -366,6 +360,7 @@ fn unique_expansions( compression: Compression, current: Vec, calculate_from: usize, + bar: &ProgressBar ) -> Vec where F: FnMut(&ProgressBar, std::slice::Iter<'_, NaivePolyCube>) -> Vec, @@ -381,7 +376,7 @@ where .collect::>(); for i in calculate_from..=n { - let bar = make_bar(current.len() as u64); + bar.set_length(current.len() as u64); bar.set_message(format!("base polycubes expanded for N = {i}...")); let start = Instant::now(); @@ -434,6 +429,7 @@ pub fn enumerate(opts: &EnumerateOpts) { //calculate from 2 because 1 is in the vec (current, 2) }; + let bar = make_bar(seed_list.len() as u64); //Select enumeration function to run let cubes_len = match (opts.mode, opts.no_parallelism) { @@ -447,6 +443,7 @@ pub fn enumerate(opts: &EnumerateOpts) { opts.cache_compression, seed_list, startn, + &bar ); cubes.len() } @@ -460,6 +457,7 @@ pub fn enumerate(opts: &EnumerateOpts) { opts.cache_compression, seed_list, startn, + &bar ); cubes.len() } @@ -471,7 +469,7 @@ pub fn enumerate(opts: &EnumerateOpts) { if !para { println!("no parallel implementation for rotation-reduced, running single threaded") } - rotation_reduced::gen_polycubes(n) + rotation_reduced::gen_polycubes(n, &bar) } (EnumerationMode::PointList, para) => { if n > 16 { @@ -481,15 +479,16 @@ pub fn enumerate(opts: &EnumerateOpts) { let cubes = pointlist::gen_polycubes( n, cache, - opts.cache_compression, !para, seed_list, startn, + &bar ); cubes.len() } (EnumerationMode::Hashless, para) => { - hashless::gen_polycubes(n, cache, opts.cache_compression, !para, seed_list, startn) + hashless::gen_polycubes(n, !para, seed_list, startn, + &bar) } }; diff --git a/rust/src/hashless.rs b/rust/src/hashless.rs index 4343de5..b812021 100644 --- a/rust/src/hashless.rs +++ b/rust/src/hashless.rs @@ -1,22 +1,23 @@ use std::{cmp::max, time::Instant}; use hashbrown::HashSet; -use opencubes::pcube::RawPCube; +use indicatif::ProgressBar; +use crate::pcube::RawPCube; use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; use crate::{ - make_bar, pointlist::{array_insert, array_shift}, polycube_reps::{CubeMapPos, Dim}, rotations::{rot_matrix_points, to_min_rot_points, MatrixCol}, - Compression, }; /// helper function to not duplicate code for canonicalising polycubes /// and storing them in the hashset fn insert_map(store: &mut HashSet>, dim: &Dim, map: &CubeMapPos<32>, count: usize) { - let map = to_min_rot_points(map, dim, count); - store.insert(map); + if !store.contains(map) { + let map = to_min_rot_points(map, dim, count); + store.insert(map); + } } /// try expaning each cube into both x+1 and x-1, calculating new dimension @@ -208,16 +209,15 @@ fn enumerate_canonical_children(seed: &CubeMapPos<32>, count: usize, target: usi /// run pointlist based generation algorithm pub fn gen_polycubes( n: usize, - _use_cache: bool, - _compression: Compression, parallel: bool, current: Vec, calculate_from: usize, + bar: &ProgressBar ) -> usize { let t1_start = Instant::now(); let seed_count = current.len(); - let bar = make_bar(seed_count as u64); + bar.set_length(seed_count as u64); bar.set_message(format!( "seed subsets expanded for N = {}...", calculate_from - 1 diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 86c3040..49586fa 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -4,3 +4,9 @@ mod test; pub mod pcube; pub mod naive_polycube; + +pub mod hashless; +pub mod pointlist; +pub mod polycube_reps; +pub mod rotation_reduced; +pub mod rotations; \ No newline at end of file diff --git a/rust/src/pointlist.rs b/rust/src/pointlist.rs index 8684022..5730a90 100644 --- a/rust/src/pointlist.rs +++ b/rust/src/pointlist.rs @@ -1,15 +1,13 @@ use std::{cmp::max, time::Instant}; use crate::{ - make_bar, polycube_reps::{CubeMapPos, CubeMapPosPart, Dim}, rotations::{rot_matrix_points, to_min_rot_points, MatrixCol}, - Compression, }; use hashbrown::{HashMap, HashSet}; use indicatif::ProgressBar; -use opencubes::pcube::{PCubeFile, RawPCube}; +use crate::pcube::RawPCube; use parking_lot::RwLock; use rayon::prelude::*; @@ -246,7 +244,7 @@ fn expand_cube_set( seeds: &MapStore, count: usize, dst: &mut MapStore, - bar: &mut ProgressBar, + bar: &ProgressBar, parallel: bool, ) { // set up the dst sets before starting parallel processing so accessing doesnt block a global mutex @@ -260,13 +258,11 @@ fn expand_cube_set( } } - let bar = RwLock::new(bar); - bar.write() - .set_message(format!("seed subsets expanded for N = {}...", count + 1)); + bar.set_message(format!("seed subsets expanded for N = {}...", count + 1)); let inner_exp = |(ss, body)| { expand_cube_sub_set(ss, body, count, dst); - bar.write().inc(1); + bar.inc(1); }; //use parallel iterator or not to run expand_cube_set @@ -323,7 +319,7 @@ fn move_polycubes_to_vec(maps: &mut MapStore) -> Vec> { } /// distructively move the data from hashset to vector -fn clone_polycubes_to_vec(maps: &mut MapStore) -> Vec> { +fn _clone_polycubes_to_vec(maps: &mut MapStore) -> Vec> { let mut v = Vec::new(); for ((_, head), body) in maps.iter() { @@ -346,11 +342,11 @@ fn clone_polycubes_to_vec(maps: &mut MapStore) -> Vec> { /// run pointlist based generation algorithm pub fn gen_polycubes( n: usize, - use_cache: bool, - compression: Compression, + _use_cache: bool, parallel: bool, current: Vec, calculate_from: usize, + bar: &ProgressBar ) -> Vec> { let t1_start = Instant::now(); @@ -369,28 +365,27 @@ pub fn gen_polycubes( drop(current); for i in calculate_from..=n as usize { - let mut bar = make_bar(seeds.len() as u64); bar.set_message(format!("seed subsets expanded for N = {}...", i)); let mut dst = MapStore::new(); - expand_cube_set(&mut seeds, i - 1, &mut dst, &mut bar, parallel); + expand_cube_set(&mut seeds, i - 1, &mut dst, bar, parallel); seeds = dst; - if use_cache && i < n { - let next = clone_polycubes_to_vec(&mut seeds); - let name = &format!("cubes_{i}.pcube"); - if !std::fs::File::open(name).is_ok() { - println!("Saving {} cubes to cache file", next.len()); - PCubeFile::write_file( - false, - compression.into(), - next.iter().map(|v| v.into()), - name, - ) - .unwrap(); - } else { - println!("Cache file already exists for N = {i}. Not overwriting."); - } - } + // if use_cache && i < n { + // let next = clone_polycubes_to_vec(&mut seeds); + // let name = &format!("cubes_{i}.pcube"); + // // if !std::fs::File::open(name).is_ok() { + // // println!("Saving {} cubes to cache file", next.len()); + // // PCubeFile::write_file( + // // false, + // // compression.into(), + // // next.iter().map(|v| v.into()), + // // name, + // // ) + // // .unwrap(); + // // } else { + // // println!("Cache file already exists for N = {i}. Not overwriting."); + // // } + // } let t1_stop = Instant::now(); let time = t1_stop.duration_since(t1_start).as_micros(); @@ -405,21 +400,21 @@ pub fn gen_polycubes( } // exported eperately for memory concerns. already quite a lot more probably but not much I can do let next = move_polycubes_to_vec(&mut seeds); - if use_cache { - let name = &format!("cubes_{n}.pcube"); - if !std::fs::File::open(name).is_ok() { - println!("Saving {} cubes to cache file", next.len()); - PCubeFile::write_file( - false, - compression.into(), - next.iter().map(|v| v.into()), - name, - ) - .unwrap(); - } else { - println!("Cache file already exists for N = {n}. Not overwriting."); - } - } + // if use_cache { + // let name = &format!("cubes_{n}.pcube"); + // if !std::fs::File::open(name).is_ok() { + // println!("Saving {} cubes to cache file", next.len()); + // PCubeFile::write_file( + // false, + // compression.into(), + // next.iter().map(|v| v.into()), + // name, + // ) + // .unwrap(); + // } else { + // println!("Cache file already exists for N = {n}. Not overwriting."); + // } + // } next //count_polycubes(&seeds); } diff --git a/rust/src/polycube_reps.rs b/rust/src/polycube_reps.rs index bdee9d4..ac82979 100644 --- a/rust/src/polycube_reps.rs +++ b/rust/src/polycube_reps.rs @@ -1,6 +1,6 @@ use std::cmp::{max, min}; -use opencubes::pcube::RawPCube; +use crate::pcube::RawPCube; use crate::rotations::{map_coord, to_min_rot_points, MatrixCol::*}; diff --git a/rust/src/rotation_reduced.rs b/rust/src/rotation_reduced.rs index f44b767..22854cb 100644 --- a/rust/src/rotation_reduced.rs +++ b/rust/src/rotation_reduced.rs @@ -6,7 +6,6 @@ use std::{cmp::max, collections::HashSet, time::Instant}; use indicatif::ProgressBar; use crate::{ - make_bar, polycube_reps::CubeMap, rotations::{self, rot_matrix, MatrixCol}, }; @@ -445,7 +444,7 @@ fn expand_cube_set( in_set: &HashSet, #[cfg(feature = "diagnostics")] depth: usize, out_set: &mut HashSet, - bar: &mut ProgressBar, + bar: &ProgressBar, ) { let mut i = 0; for map in in_set.iter() { @@ -487,7 +486,7 @@ fn expand_cube_set( } } -pub fn gen_polycubes(n: usize) -> usize { +pub fn gen_polycubes(n: usize, bar: &ProgressBar) -> usize { let unit_cube = CubeMap { x: 1, y: 0, @@ -507,14 +506,13 @@ pub fn gen_polycubes(n: usize) -> usize { 2, ); for i in 3..=n as usize { - let mut bar = make_bar(seeds.len() as u64); bar.set_message(format!("seed subsets expanded for N = {}...", i)); expand_cube_set( &seeds, #[cfg(feature = "diagnostics")] i, &mut dst, - &mut bar, + bar, ); //if diagnostics enabled panic if the returned values are wrong #[cfg(feature = "diagnostics")] From 7d5672e70129fba330a2a2bb638f80b5cfa210f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNailLegProcessorDivide=E2=80=9D?= Date: Sun, 23 Jul 2023 18:02:07 +0100 Subject: [PATCH 11/13] bench hashless --- rust/README.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/rust/README.md b/rust/README.md index e2c4115..a0cf522 100644 --- a/rust/README.md +++ b/rust/README.md @@ -47,7 +47,7 @@ Commands: - Times are measured with a large sample set of 1 run in an environment with many background processes of varying resource intensiveness throughout and rounded to 3 sig figs -- No cache files used. +- No cache files used (hashless uses N=12). - Working with Low% speedrun rules - more cubes is always better no matter the time, a faster time is better than a slower time if cube count is equal. @@ -67,12 +67,9 @@ Ryzen 9 7900X | afa90ad | 0.184ms | 1.43ms | 11.4ms | 8.41ms | 0.686s | 6.58s | 62.45s | 574s | OoM | OoM | OoM | OoM | rotation-reduced | | 68090de | 13.2ms | 20.4ms | 37.4ms | 85.3ms | 0.304s | 1.74s | 14.2s | 124s | OoM | OoM | OoM | OoM | point-list + rayon | | b83f9c6 | 3ms | 4.3ms | 8.58ms | 25.4ms | 0.137s | 0.986s | 8.02s | 66.7s | OoM | OoM | OoM | OoM | point-list + rayon | +| 88bca6b | NA | NA | NA | NA | NA | NA | NA | 1m28 | 12m55 | 1h50 | 16h10 | NA | hashless + rayon | ## To Do -- implement hashtableless solution that just enumerates - - profile and optimise further -- deduplicate mirrors as well to reduce (optimistically) ~50% memory usage in the -hashset and then test for symatry when counting unique variants - +- folding@home home style cluster support From faae4ce059f1497d70775a04829666056413ad57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNailLegProcessorDivide=E2=80=9D?= Date: Sun, 23 Jul 2023 18:14:46 +0100 Subject: [PATCH 12/13] update readme --- rust/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/README.md b/rust/README.md index a0cf522..0f98f29 100644 --- a/rust/README.md +++ b/rust/README.md @@ -72,4 +72,4 @@ Ryzen 9 7900X ## To Do - profile and optimise further -- folding@home home style cluster support +- folding@home home style cluster :) From 3128029abdfdbd598f0e8555622526450e03c486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNailLegProcessorDivide=E2=80=9D?= Date: Sun, 23 Jul 2023 18:24:05 +0100 Subject: [PATCH 13/13] cargo fmt --- rust/src/cli.rs | 22 ++++++++-------------- rust/src/hashless.rs | 4 ++-- rust/src/lib.rs | 2 +- rust/src/pointlist.rs | 4 ++-- 4 files changed, 13 insertions(+), 19 deletions(-) diff --git a/rust/src/cli.rs b/rust/src/cli.rs index feccaf3..ceccfe3 100644 --- a/rust/src/cli.rs +++ b/rust/src/cli.rs @@ -8,8 +8,10 @@ use std::{ use clap::{Args, Parser, Subcommand, ValueEnum}; use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; use opencubes::{ + hashless, naive_polycube::NaivePolyCube, - pcube::{PCubeFile, RawPCube}, pointlist, rotation_reduced, hashless, + pcube::{PCubeFile, RawPCube}, + pointlist, rotation_reduced, }; use rayon::prelude::{IntoParallelIterator, ParallelIterator}; @@ -360,7 +362,7 @@ fn unique_expansions( compression: Compression, current: Vec, calculate_from: usize, - bar: &ProgressBar + bar: &ProgressBar, ) -> Vec where F: FnMut(&ProgressBar, std::slice::Iter<'_, NaivePolyCube>) -> Vec, @@ -443,7 +445,7 @@ pub fn enumerate(opts: &EnumerateOpts) { opts.cache_compression, seed_list, startn, - &bar + &bar, ); cubes.len() } @@ -457,7 +459,7 @@ pub fn enumerate(opts: &EnumerateOpts) { opts.cache_compression, seed_list, startn, - &bar + &bar, ); cubes.len() } @@ -476,19 +478,11 @@ pub fn enumerate(opts: &EnumerateOpts) { println!("n > 16 not supported for point-list"); return; } - let cubes = pointlist::gen_polycubes( - n, - cache, - !para, - seed_list, - startn, - &bar - ); + let cubes = pointlist::gen_polycubes(n, cache, !para, seed_list, startn, &bar); cubes.len() } (EnumerationMode::Hashless, para) => { - hashless::gen_polycubes(n, !para, seed_list, startn, - &bar) + hashless::gen_polycubes(n, !para, seed_list, startn, &bar) } }; diff --git a/rust/src/hashless.rs b/rust/src/hashless.rs index b812021..4ce4ed2 100644 --- a/rust/src/hashless.rs +++ b/rust/src/hashless.rs @@ -1,8 +1,8 @@ use std::{cmp::max, time::Instant}; +use crate::pcube::RawPCube; use hashbrown::HashSet; use indicatif::ProgressBar; -use crate::pcube::RawPCube; use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; use crate::{ @@ -212,7 +212,7 @@ pub fn gen_polycubes( parallel: bool, current: Vec, calculate_from: usize, - bar: &ProgressBar + bar: &ProgressBar, ) -> usize { let t1_start = Instant::now(); diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 49586fa..b45964d 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -9,4 +9,4 @@ pub mod hashless; pub mod pointlist; pub mod polycube_reps; pub mod rotation_reduced; -pub mod rotations; \ No newline at end of file +pub mod rotations; diff --git a/rust/src/pointlist.rs b/rust/src/pointlist.rs index 5730a90..5de9030 100644 --- a/rust/src/pointlist.rs +++ b/rust/src/pointlist.rs @@ -5,9 +5,9 @@ use crate::{ rotations::{rot_matrix_points, to_min_rot_points, MatrixCol}, }; +use crate::pcube::RawPCube; use hashbrown::{HashMap, HashSet}; use indicatif::ProgressBar; -use crate::pcube::RawPCube; use parking_lot::RwLock; use rayon::prelude::*; @@ -346,7 +346,7 @@ pub fn gen_polycubes( parallel: bool, current: Vec, calculate_from: usize, - bar: &ProgressBar + bar: &ProgressBar, ) -> Vec> { let t1_start = Instant::now();