Skip to content

Commit

Permalink
Support antisymmetric tensor canonization
Browse files Browse the repository at this point in the history
- Add HiddenData that hides data from Eq, Hash and Ord
- Fix get_packed_size and use (i64, u64) instead of (i64, i64)
  • Loading branch information
benruijl committed Sep 2, 2024
1 parent d246a31 commit 80313c2
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 37 deletions.
34 changes: 17 additions & 17 deletions src/atom/coefficient.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,9 @@ impl PackedRationalNumberWriter for Coefficient {
fn write_packed(&self, dest: &mut Vec<u8>) {
match self {
Coefficient::Rational(r) => match (r.numerator_ref(), r.denominator_ref()) {
(Integer::Natural(num), Integer::Natural(den)) => (*num, *den).write_packed(dest),
(Integer::Natural(num), Integer::Natural(den)) => {
(*num, *den as u64).write_packed(dest)
}
_ => {
let r = r.clone().to_multi_prec();
dest.put_u8(ARB_NUM | ARB_DEN);
Expand All @@ -146,9 +148,9 @@ impl PackedRationalNumberWriter for Coefficient {
let den_digits = r.denom().significant_digits::<u8>();

if r.numer() < &0 {
(-(num_digits as i64), den_digits as i64).write_packed(dest);
(-(num_digits as i64), den_digits as u64).write_packed(dest);
} else {
(num_digits as i64, den_digits as i64).write_packed(dest);
(num_digits as i64, den_digits as u64).write_packed(dest);
}

let old_len = dest.len();
Expand Down Expand Up @@ -229,7 +231,7 @@ impl PackedRationalNumberWriter for Coefficient {
match self {
Coefficient::Rational(r) => match (r.numerator_ref(), r.denominator_ref()) {
(Integer::Natural(num), Integer::Natural(den)) => {
(*num, *den).write_packed_fixed(dest)
(*num, *den as u64).write_packed_fixed(dest)
}
_ => todo!("Writing large packed rational not implemented"),
},
Expand All @@ -247,11 +249,13 @@ impl PackedRationalNumberWriter for Coefficient {
fn get_packed_size(&self) -> u64 {
match self {
Coefficient::Rational(r) => match (r.numerator_ref(), r.denominator_ref()) {
(Integer::Natural(num), Integer::Natural(den)) => (*num, *den).get_packed_size(),
(Integer::Natural(num), Integer::Natural(den)) => {
(*num, *den as u64).get_packed_size()
}
_ => {
let l = r.clone().to_multi_prec();
let n = l.numer().significant_digits::<u8>() as i64;
let d = l.denom().significant_digits::<u8>() as i64;
let n = l.numer().significant_digits::<u8>() as u64;
let d = l.denom().significant_digits::<u8>() as u64;
1 + (n, d).get_packed_size() + n as u64 + d as u64
}
},
Expand Down Expand Up @@ -574,33 +578,29 @@ impl PackedRationalNumberReader for [u8] {
}
}

impl PackedRationalNumberWriter for (i64, i64) {
impl PackedRationalNumberWriter for (i64, u64) {
#[inline(always)]
fn write_packed(&self, dest: &mut Vec<u8>) {
let p = dest.len();

let num_u64 = self.0.unsigned_abs();
let den_u64 = self.1.unsigned_abs();
(num_u64, den_u64).write_packed(dest);
(self.0.unsigned_abs(), self.1).write_packed(dest);

if self.0 >= 0 && self.1 < 0 || self.0 < 0 && self.1 >= 0 {
if self.0 < 0 {
dest[p] |= SIGN;
}
}

#[inline(always)]
fn write_packed_fixed(&self, dest: &mut [u8]) {
let num_u64 = self.0.unsigned_abs();
let den_u64 = self.1.unsigned_abs();
(num_u64, den_u64).write_packed_fixed(dest);
(self.0.unsigned_abs(), self.1).write_packed_fixed(dest);

if self.0 >= 0 && self.1 < 0 || self.0 < 0 && self.1 >= 0 {
if self.0 < 0 {
dest[0] |= SIGN;
}
}

fn get_packed_size(&self) -> u64 {
(self.0 as u64, self.1 as u64).get_packed_size()
(self.0.unsigned_abs(), self.1).get_packed_size()
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/atom/representation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ pub struct InlineNum {

impl InlineNum {
/// Create a new inline number. The gcd of num and den should be 1.
pub fn new(num: i64, den: i64) -> InlineNum {
pub fn new(num: i64, den: u64) -> InlineNum {
let mut data = [0; 24];
data[0] = NUM_ID;

Expand Down
52 changes: 52 additions & 0 deletions src/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,55 @@ impl Display for Empty {
}
}

/// Data that has a public part and a private part. The private
/// part is not used for equality or hashing.
#[derive(Clone)]
pub struct HiddenData<T, U> {
pub data: T,
pub hidden: U,
}

impl<T, U> HiddenData<T, U> {
pub fn new(data: T, hidden: U) -> Self {
HiddenData { data, hidden }
}
}

impl<T: PartialEq, U> PartialEq for HiddenData<T, U> {
fn eq(&self, other: &Self) -> bool {
self.data == other.data
}
}

impl<T: Eq, U> Eq for HiddenData<T, U> {}

impl<T: Hash, U> Hash for HiddenData<T, U> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.data.hash(state);
}
}

impl<T: Display, U: Display> Display for HiddenData<T, U> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{} ({})", self.data, self.hidden)
}
}

impl<T: PartialOrd, U> PartialOrd for HiddenData<T, U> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.data.partial_cmp(&other.data)
}
}

impl<T: Ord, U> Ord for HiddenData<T, U> {
fn cmp(&self, other: &Self) -> Ordering {
self.data.cmp(&other.data)
}
}

/// A multigraph with support for arbitrary node and edge data.
///
/// Use [HiddenData] to hide parts of the data from all equality and hashing.
#[derive(Clone, PartialEq, Eq, PartialOrd, Hash)]
pub struct Graph<NodeData = Empty, EdgeData = Empty> {
nodes: Vec<Node<NodeData>>,
Expand Down Expand Up @@ -124,6 +172,10 @@ impl<N: Clone + PartialOrd + Ord + Eq + Hash, E: Clone + PartialOrd + Ord + Eq +
/// Canonize the graph using McKay's canonical graph labeling algorithm,
/// returning the vertex mapping and the canonical form.
pub fn canonize(&self) -> (Vec<usize>, Self) {
if self.nodes.is_empty() {
return (vec![], self.clone());
}

if self.nodes.len() <= u16::MAX as usize {
let r = self.canonize_impl::<u16>();
(r.0.into_iter().map(|x| x as usize).collect(), r.1)
Expand Down
Loading

0 comments on commit 80313c2

Please sign in to comment.