Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor polycube_reps and rotations #34

Draft
wants to merge 15 commits into
base: main
Choose a base branch
from
Draft
7 changes: 0 additions & 7 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,6 @@ name = "opencubes"
version = "0.1.0"
edition = "2021"

#feature flags to enable and disable features at compile time

[features]
diagnostics = []
size16 = []
smallset = []

[profile.release]
debug = true

Expand Down
8 changes: 4 additions & 4 deletions rust/src/cli/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::{

use clap::{Args, Parser, Subcommand, ValueEnum};
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
use opencubes::{naive_polycube::NaivePolyCube, pcube::PCubeFile};
use opencubes::polycubes::{naive_polycube::NaivePolyCube, pcube::PCubeFile};
use rayon::prelude::{IntoParallelIterator, ParallelIterator};

mod enumerate;
Expand Down Expand Up @@ -188,11 +188,11 @@ pub enum Compression {
Gzip,
}

impl From<Compression> for opencubes::pcube::Compression {
impl From<Compression> for opencubes::polycubes::pcube::Compression {
fn from(value: Compression) -> Self {
match value {
Compression::None => opencubes::pcube::Compression::None,
Compression::Gzip => opencubes::pcube::Compression::Gzip,
Compression::None => opencubes::polycubes::pcube::Compression::None,
Compression::Gzip => opencubes::polycubes::pcube::Compression::Gzip,
}
}
}
Expand Down
10 changes: 6 additions & 4 deletions rust/src/cli/enumerate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ use std::{io::ErrorKind, sync::Arc, time::Instant};
use opencubes::{
hashless::MapStore,
iterator::{indicatif::PolycubeProgressBarIter, *},
naive_polycube::NaivePolyCube,
pcube::{PCubeFile, RawPCube},
pointlist,
polycube_reps::CubeMapPos,
polycubes::{
naive_polycube::NaivePolyCube,
pcube::{PCubeFile, RawPCube},
point_list::CubeMapPos,
},
rotation_reduced,
};

Expand Down Expand Up @@ -83,7 +85,7 @@ fn load_cache_file(n: usize) -> Option<PCubeFile> {
}

enum CacheOrbase {
Cache(opencubes::pcube::AllUnique),
Cache(opencubes::polycubes::pcube::AllUnique),
Base(bool),
}

Expand Down
182 changes: 26 additions & 156 deletions rust/src/hashless.rs
Original file line number Diff line number Diff line change
@@ -1,110 +1,14 @@
use std::cmp::max;

use hashbrown::HashSet;

use crate::{
pointlist::{array_insert, array_shift},
polycube_reps::{CubeMapPos, Dim},
rotations::{rot_matrix_points, to_min_rot_points, MatrixCol},
use crate::polycubes::{
point_list::{CubeMapPos, PointListMeta},
Dim, PolyCube,
};

pub struct MapStore<const N: usize> {
inner: HashSet<CubeMapPos<N>>,
}

macro_rules! cube_map_pos_expand {
($name:ident, $dim:ident, $shift:literal) => {
#[inline(always)]
pub fn $name<'a>(
&'a self,
shape: &'a Dim,
count: usize,
) -> impl Iterator<Item = (Dim, usize, Self)> + 'a {
struct Iter<'a, const C: usize> {
inner: &'a CubeMapPos<C>,
shape: &'a Dim,
count: usize,
i: usize,
stored: Option<(Dim, usize, CubeMapPos<C>)>,
}

impl<'a, const C: usize> Iterator for Iter<'a, C> {
type Item = (Dim, usize, CubeMapPos<C>);

fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(stored) = self.stored.take() {
return Some(stored);
}

let i = self.i;

if i == self.count {
return None;
}

self.i += 1;
let coord = *self.inner.cubes.get(i)?;

let plus = coord + (1 << $shift);
let minus = coord - (1 << $shift);

if !self.inner.cubes[(i + 1)..self.count].contains(&plus) {
let mut new_shape = *self.shape;
let mut new_map = *self.inner;

array_insert(plus, &mut new_map.cubes[i..=self.count]);
new_shape.$dim =
max(new_shape.$dim, (((coord >> $shift) + 1) & 0x1f) as usize);

self.stored = Some((new_shape, self.count + 1, new_map));
}

let mut new_map = *self.inner;
let mut new_shape = *self.shape;

// If the coord is out of bounds for $dim, shift everything
// over and create the cube at the out-of-bounds position.
// If it is in bounds, check if the $dim - 1 value already
// exists.
let insert_coord = if (coord >> $shift) & 0x1f != 0 {
if !self.inner.cubes[0..i].contains(&minus) {
minus
} else {
continue;
}
} else {
new_shape.$dim += 1;
for i in 0..self.count {
new_map.cubes[i] += 1 << $shift;
}
coord
};

array_shift(&mut new_map.cubes[i..=self.count]);
array_insert(insert_coord, &mut new_map.cubes[0..=i]);
return Some((new_shape, self.count + 1, new_map));
}
}
}

Iter {
inner: self,
shape,
count,
i: 0,
stored: None,
}
}
};
}

impl<const N: usize> CubeMapPos<N> {
cube_map_pos_expand!(expand_x, x, 0);
cube_map_pos_expand!(expand_y, y, 5);
cube_map_pos_expand!(expand_z, z, 10);
}

impl<const N: usize> MapStore<N> {
pub fn new() -> Self {
Self {
Expand All @@ -114,59 +18,13 @@ impl<const N: usize> MapStore<N> {

/// helper function to not duplicate code for canonicalising polycubes
/// and storing them in the hashset
fn insert_map(&mut self, dim: &Dim, map: &CubeMapPos<N>, count: usize) {
if !self.inner.contains(map) {
let map = to_min_rot_points(map, dim, count);
fn insert_map(&mut self, dim: Dim, map: CubeMapPos<N>, count: usize) {
if !self.inner.contains(&map) {
let map = map.to_min_rot_points(dim, count);
self.inner.insert(map);
}
}

/// reduce number of expansions needing to be performed based on
/// X >= Y >= Z constraint on Dim
#[inline]
fn do_cube_expansion(&mut self, seed: &CubeMapPos<N>, shape: &Dim, count: usize) {
let expand_ys = if shape.y < shape.x {
Some(seed.expand_y(shape, count))
} else {
None
};

let expand_zs = if shape.z < shape.y {
Some(seed.expand_z(shape, count))
} else {
None
};

seed.expand_x(shape, count)
.chain(expand_ys.into_iter().flatten())
.chain(expand_zs.into_iter().flatten())
.for_each(|(dim, new_count, map)| self.insert_map(&dim, &map, new_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(&mut self, seed: &CubeMapPos<N>, shape: &Dim, count: usize) {
use MatrixCol::*;

if shape.x == shape.y && shape.x > 0 {
let rotz = rot_matrix_points(seed, shape, count, YN, XN, ZN, 1025);
self.do_cube_expansion(&rotz, shape, count);
}

if shape.y == shape.z && shape.y > 0 {
let rotx = rot_matrix_points(seed, shape, count, XN, ZP, YP, 1025);
self.do_cube_expansion(&rotx, shape, count);
}
if shape.x == shape.z && shape.x > 0 {
let roty = rot_matrix_points(seed, shape, count, ZP, YP, XN, 1025);
self.do_cube_expansion(&roty, shape, count);
}

self.do_cube_expansion(seed, shape, count);
}

/// Calculate the amount of canonical children of size `target`
/// that polycube `seed` of size `count` has.
///
Expand All @@ -179,21 +37,33 @@ impl<const N: usize> MapStore<N> {
count: usize,
target: usize,
) -> usize {
let mut map = Self::new();
let mut store = Self::new();
let shape = seed.extrapolate_dim();

let seed = to_min_rot_points(seed, &shape, count);
let seed = seed.to_min_rot_points(shape, count);
let shape = seed.extrapolate_dim();

map.expand_cube_map(&seed, &shape, count);

map.inner
let meta = PointListMeta {
point_list: seed,
dim: shape,
count: count,
};
meta.unique_expansions().for_each(
|PointListMeta {
point_list: map,
dim,
count,
}| store.insert_map(dim, map, count),
);

store
.inner
.retain(|child| child.is_canonical_root(count, &seed));

if count + 1 == target {
map.inner.len()
store.inner.len()
} else {
map.inner
store
.inner
.iter()
.map(|child| Self::enumerate_canonical_children_min_mem(child, count + 1, target))
.sum()
Expand Down
2 changes: 1 addition & 1 deletion rust/src/iterator.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::collections::{HashMap, HashSet};

use crate::pcube::RawPCube;
use crate::polycubes::pcube::RawPCube;

/// An iterator over polycubes
pub trait PolycubeIterator: Iterator<Item = RawPCube>
Expand Down
6 changes: 1 addition & 5 deletions rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@
mod test;

pub mod iterator;
pub mod pcube;

pub mod naive_polycube;
pub mod polycubes;

pub mod hashless;
pub mod pointlist;
pub mod polycube_reps;
pub mod rotation_reduced;
pub mod rotations;