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

BitSet.bitand operation returns non-empty BitSetAnd even if no ids match. #51

Open
prixt opened this issue Jul 26, 2019 · 11 comments
Open

Comments

@prixt
Copy link

prixt commented Jul 26, 2019

Code:

use hibitset::*;

fn main() {
    let mut a = BitSet::new();
    let mut b = BitSet::new();
    assert!( a.is_empty() && b.is_empty(), "This shouldn't happen!");
    a.add(0);
    b.add(10);
    assert!( !a.is_empty() && !b.is_empty(), "This also shouldn't happen!");
    assert!( (a&b).is_empty(), "This definetely shouldn't happen!");
}

Output:

thread 'main' panicked at 'This definetely shouldn't happen!', src\main.rs:10:5
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
error: process didn't exit successfully: `target\debug\rust-test.exe` (exit code: 101)
@prixt
Copy link
Author

prixt commented Jul 26, 2019

Currently using hibitset version 0.6.1.

@prixt
Copy link
Author

prixt commented Jul 26, 2019

https://github.com/prixt/hibitset/blob/master/src/ops.rs
88c5d57

A band-aid fix. Basically created a separate 'is_empty' function for BitSetAnd.

#[inline]
fn is_empty(&self) -> bool {
    self.iter().count() == 0
}

There probably is a better solution, but this will fix the problem for now.

@torkleyy
Copy link
Member

Argh, this is a severe bug in our operators! We can not simply AND / XOR layers 1 - 3; they need to be recomputed.

@torkleyy
Copy link
Member

This essentially means we'll likely have to drop our "lazy" operators and rely exclusively on *Assign, so we can recalculate the layers.

@prixt
Copy link
Author

prixt commented Jul 26, 2019

https://github.com/prixt/hibitset/blob/and_xor_assign/src/ops.rs
b5d3b60

Tried to create new BitSetAnd and BitSetXor structs. While these do pass the tests, I think these won't work in all cases, since they internally use BitSet.

@WaDelma
Copy link
Member

WaDelma commented Jul 26, 2019

Should we also do eager calculation of BitSetNot? I first looked at it again because I was thinking you could do the -(-a | -b) trick

@WaDelma
Copy link
Member

WaDelma commented Jul 26, 2019

Yeah this pretty much forces dropping lazy operators.

@prixt
Copy link
Author

prixt commented Jul 27, 2019

Only bitand op and bitxor op need eager calculation.
nvm, bitnot seems to need some adjustsments too.

@prixt
Copy link
Author

prixt commented Jul 28, 2019

If all operators need to create a new BitSetLike structure, and now need to be recalculated, why not just return a BitSet?

@hjfreyer
Copy link

Am I correct in thinking this means the bitsets simply return incorrect answers?? This crate has been downloaded more than 400,000 times, so if its logic is incorrect it should really get pulled!

@torkleyy
Copy link
Member

@hjfreyer

Am I correct in thinking this means the bitsets simply return incorrect answers?? This crate has been downloaded more than 400,000 times, so if its logic is incorrect it should really get pulled!

This bug has three implications as far as I see it:

  • it means is_empty can return false even though in fact the bit set is empty
  • higher-up layers might have a set bit even though the corresponding bits on the lower layer are all 0
  • however, layer0 always has the correct bits set meaning that this bug (which really should be a documented limitation in this latter case) only has a performance cost while iterating, i.e. the results are still correct

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

4 participants