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

Hash for Matrix doesn't match Borrow<[[T; R]; C]> semantics #1352

Open
CAD97 opened this issue Jan 14, 2024 · 0 comments
Open

Hash for Matrix doesn't match Borrow<[[T; R]; C]> semantics #1352

CAD97 opened this issue Jan 14, 2024 · 0 comments

Comments

@CAD97
Copy link
Contributor

CAD97 commented Jan 14, 2024

Borrow<T> for Self implies that trait implementations on Self and T behave identically, in notable particular Eq, Ord, and Hash. The Hash implementation for Matrix is different from the one for arrays, resulting in e.g. the hash of Matrix3<i32> differing from that of the same matrix Borrow::borrowed as [[i32; 3]; 3]. [playground]

use nalgebra; // 0.32.3

use std::borrow::Borrow;
use std::hash::{BuildHasher, Hash};
use std::collections::hash_map::RandomState;

fn main() {
    let s = RandomState::new();
    let v = nalgebra::matrix![3, 1, 4; 1, 5, 9; 2, 6, 5];
    assert_eq!(s.hash_one(&v), s.hash_one(<_ as Borrow<[_; 3]>>::borrow(&v))); // fails, should pass
}

Either the Borrow implementation should be removed or the Hash implementation should be changed to try to match the array Hash implementation. I think the only way to do so properly1 would be to hash the data field directly; ArrayStorage has the properly equivalent Hash implementation, so it's a matter of requiring all impl RawStorage to provide a Hash impl. I think the way to do so in a non-API-breaking manner would be to add a copy of the Hash::hash method into the RawStorage trait and use that, as a default of the current behavior can be kept which ArrayStorage uses its derived Hash implementation. (This will result in hashing slightly more data, since R gets prefixed to each column individually, but that should be marginal for ArrayStorage-backed Matrix.)

Footnotes

  1. The presence of Hash::hash_slice as a customization point means any and all attempts to mirror the Hash behavior will fail in an edge case, short of constructing &[[T; R]] or &[&[T]] (which would require allocation in the general case).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant