GithubHelp home page GithubHelp logo

khojasteh / uf_rush Goto Github PK

View Code? Open in Web Editor NEW
2.0 1.0 1.0 15 KB

A lock-free, thread-safe implementation of the Union-Find (Disjoint-Set) data structure in Rust.

License: MIT License

Rust 100.00%
disjoint-set lock-free thread-safe union-find

uf_rush's Introduction

UFRush

UFRush is a lock-free, thread-safe implementation of the Union-Find (Disjoint-Set) data structure in Rust. This data structure allows efficient computation of equivalence relations (represented as disjoint sets) and supports the following operations: find, unite, and same.

Background

The Union-Find data structure provides an efficient way to manage a partition of a set into disjoint subsets. It supports two main operations: union (merging two subsets into one) and find (determining which subset a particular element is in).

Lock-free programming, or non-blocking programming, is a methodology applied in concurrent computing where multiple threads operate and manipulate shared data without the need for locks. Lock-free programming achieves its goals through the use of atomic operations which can be performed independently without interruption. In the context of UFRush, being lock-free means that multiple threads can perform operations on the Union-Find structure concurrently, and the system guarantees that at least one thread will make progress, improving the throughput and performance in a multithreaded environment.

The algorithm used in UFRush is based on the research paper "Wait-Free Parallel Algorithms for the Union-Find Problem" by Richard J. Anderson and Heather Woll.

Methods

UFRush offers the following methods:

  • new(size: usize) -> Self
    Creates a new union-find data structure with a specified number of elements.

  • size() -> usize
    Returns the total number of elements in the union-find structure.

  • same(x: usize, y: usize) -> bool
    Determines whether the elements x and y belong to the same subset.

  • find(x: usize) -> usize
    Finds the representative of the subset that x belongs to.

  • unite(x: usize, y: usize) -> bool
    Unites the subsets that contain x and y.

  • clear()
    Clears the union-find structure, making every element a separate subset.

Usage

Here's an example of how to use UFRush:

let n = 10;
let uf = UFRush::new(n);
uf.unite(0, 1);
uf.unite(1, 2);
uf.unite(3, 4);
uf.unite(5, 6);
uf.unite(6, 7);
uf.unite(7, 8);

// Test if these elements are in the same set
assert!(uf.same(0, 2)); // true, as 0 and 2 are connected through 1
assert!(uf.same(3, 4)); // true
assert!(uf.same(5, 8)); // true, as 5, 6, 7, and 8 are all connected

// Test some elements that are not in the same set
assert!(!uf.same(0, 3)); // false, as there is no connection between 0 and 3
assert!(!uf.same(2, 5)); // false

// Now, we connect some additional elements
uf.unite(2, 5);

// And re-test
assert!(uf.same(0, 5)); // true, as now 0 and 5 are connected through 1->2->5

Testing

UFRush includes comprehensive unit tests, including tests for multithreaded usage.

Run tests with:

cargo test

Disclaimer

Please note that while every effort has been made to ensure the accuracy, completeness, and reliability of the UFRush library, the developer makes no warranty, guarantee or promise (express or implied) concerning the content or functionality of this library.

The implementation of the library is based on complex lock-free programming techniques and is believed to be correct to the best of the developer's knowledge. However, due to the inherent complexity of lock-free programming, there may be unknown issues or edge cases that haven't been discovered yet. As such, the library is provided "as is", without warranty of any kind.

The developer disclaims all liability for any damages, direct or indirect, special or incidental, resulting from the use of the UFRush library. Users of the library are encouraged to thoroughly test and validate its performance and correctness in their specific use cases.

If any issues are discovered, please submit an issue with detailed steps for reproducing the bug. Contributions, in the form of code improvements or suggestions, are always welcome.

Finally, while the UFRush library aims to provide high performance in multithreaded environments, it is important to understand that the actual performance may vary based on specific workload characteristics and hardware configurations. Users are encouraged to conduct performance testing under their own workloads to ensure that the library meets their performance requirements.

License

This project is licensed under the MIT License - see the LICENSE file for details.

uf_rush's People

Contributors

khojasteh avatar truedoctor avatar

Stargazers

 avatar  avatar

Watchers

 avatar

Forkers

truedoctor

uf_rush's Issues

Bug: untite returns true when it should not

When working on a parallel MST implementation I encountered an error in your library.
The unite function seems to return true more often that should be possible due to some sort of race condition.
I wrote a test to verify the behaviour:

#[test]
    fn stress_test() {
        use rand::prelude::*;
        use std::sync::{Arc, Barrier};
        use std::thread;

        let num_elements = 10_00_000; // Adjust based on the system's capability
        let num_threads = 16; // High concurrency

        let elements = 1 << 8;

        // Preparing a pool of element pairs for unification
        // This simplistic approach ensures that we have a mix of pairs
        let mut pairs = Vec::new();
        for i in 0..=elements {
            let i = i % elements;
            pairs.push((i, i + 1));
        }
        for i in 0..num_elements - 1 {
            let source = rand::random::<usize>() % elements;
            let target = rand::random::<usize>() % elements;
            pairs.push((source, target));
        }

        for i in 0..1000 {
            let uf = Arc::new(UFRush::new(elements + 1));
            use rand::{thread_rng, Rng};
            use rayon::prelude::*;
            let mut rng = thread_rng();
            let total_unites = AtomicUsize::new(0);
            let total_unites = &total_unites;
            pairs.shuffle(&mut rng);

            pairs.par_iter().for_each(|(x, y)| {
                if uf.unite(*x, *y) {
                    total_unites.fetch_add(1, Ordering::Relaxed);
                }
            });

            assert_eq!(total_unites.load(Ordering::SeqCst), elements);
        }
    }
    ```
    I'll try to investigate this further and hopefully find a fix

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.