Breadth first search and lifetimes - algorithm

I want to write a function that uses breadth-first search on a binary tree to print node values in order:
use std::collections::VecDeque;
use std::ops::Deref;
struct BinarySearchNode<'a> {
value: &'a str,
key: i32,
left: Option<Box<BinarySearchNode<'a>>>,
right: Option<Box<BinarySearchNode<'a>>>,
}
impl<'a> BinarySearchNode<'a> {
pub fn print(&self) -> String {
let mut queue = VecDeque::new();
let mut output = String::new();
queue.push_back(&self);
while let Some(ref current) = queue.pop_front() {
if let Some(left_node) = current.left {
queue.push_back(&left_node.deref());
}
if let Some(right_node) = current.right {
queue.push_back(&right_node.deref());
}
output = output + current.value + "\n";
}
output
}
}
fn main() {}
I get the error
error: borrowed value does not live long enough
--> src/main.rs:19:34
|
19 | queue.push_back(&left_node.deref());
| ^^^^^^^^^^^^^^^^^ does not live long enough
|
note: reference must be valid for the block suffix following statement 0 at 13:40...
--> src/main.rs:13:41
|
13 | let mut queue = VecDeque::new();
| ^
note: ...but borrowed value is only valid for the statement at 19:16
--> src/main.rs:19:17
|
19 | queue.push_back(&left_node.deref());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: consider using a `let` binding to increase its lifetime
--> src/main.rs:19:17
|
19 | queue.push_back(&left_node.deref());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `left_node` does not live long enough
--> src/main.rs:19:34
|
19 | queue.push_back(&left_node.deref());
| ^^^^^^^^^
|
note: reference must be valid for the block suffix following statement 0 at 13:40...
--> src/main.rs:13:41
|
13 | let mut queue = VecDeque::new();
| ^
note: ...but borrowed value is only valid for the if let at 18:12
--> src/main.rs:18:13
|
18 | if let Some(left_node) = current.left {
| ^
error: borrowed value does not live long enough
--> src/main.rs:22:34
|
22 | queue.push_back(&right_node.deref());
| ^^^^^^^^^^^^^^^^^^ does not live long enough
|
note: reference must be valid for the block suffix following statement 0 at 13:40...
--> src/main.rs:13:41
|
13 | let mut queue = VecDeque::new();
| ^
note: ...but borrowed value is only valid for the statement at 22:16
--> src/main.rs:22:17
|
22 | queue.push_back(&right_node.deref());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: consider using a `let` binding to increase its lifetime
--> src/main.rs:22:17
|
22 | queue.push_back(&right_node.deref());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `right_node` does not live long enough
--> src/main.rs:22:34
|
22 | queue.push_back(&right_node.deref());
| ^^^^^^^^^^
|
note: reference must be valid for the block suffix following statement 0 at 13:40...
--> src/main.rs:13:41
|
13 | let mut queue = VecDeque::new();
| ^
note: ...but borrowed value is only valid for the if let at 21:12
--> src/main.rs:21:13
|
21 | if let Some(right_node) = current.right {
| ^
error[E0507]: cannot move out of borrowed content
--> src/main.rs:18:38
|
18 | if let Some(left_node) = current.left {
| --------- ^^^^^^^ cannot move out of borrowed content
| |
| hint: to prevent move, use `ref left_node` or `ref mut left_node`
error[E0507]: cannot move out of borrowed content
--> src/main.rs:21:39
|
21 | if let Some(right_node) = current.right {
| ---------- ^^^^^^^ cannot move out of borrowed content
| |
| hint: to prevent move, use `ref right_node` or `ref mut right_node`
I needed to deref() because simply using the operator * was causing a type mismatch as it expected a reference and not a box. It seems those dereference slightly differently and at least in stable I can't destructure it either.
I get that this value is scoped within the while loop and doesn't live long enough to be in the VecDeque (if this is the right data structure for the job) but I'm not sure what the best way to go about extending that lifetime is or if there's simply a better way to write this entire thing as it feels a bit complex.
My main problem is that I'm not sure where to start refactoring this code and I surprisingly had a hard time finding examples of a breadth-first search performed on a binary tree in Rust to take patterns from.

Your main problem lies in this line (and the right version):
if let Some(left_node) = current.left
This tries to move the value contained in current.left into the pattern on the right side. the problem is that current.left is an Option<Box<BinarySearchNode<'a>>>. When you move the Box out of current, that would leave current without a valid value for left! Accessing that value in the future would lead to bad behavior.
Instead, you need to leave the value where it is and instead take a reference. The two main ways are to use the ref pattern modifier:
if let Some(ref left_node) = current.left
Or to call as_ref:
if let Some(left_node) = current.left.as_ref()
Here is complete code:
use std::collections::VecDeque;
struct BinarySearchNode<'a> {
value: &'a str,
key: i32,
left: Option<Box<BinarySearchNode<'a>>>,
right: Option<Box<BinarySearchNode<'a>>>,
}
impl<'a> BinarySearchNode<'a> {
pub fn print(&self) -> String {
let mut queue = VecDeque::new();
let mut output = String::new();
queue.push_back(self);
while let Some(current) = queue.pop_front() {
if let Some(left_node) = current.left.as_ref() {
queue.push_back(left_node);
}
if let Some(right_node) = current.right.as_ref() {
queue.push_back(right_node);
}
output = output + current.value + "\n";
}
output
}
}
fn main() {
let root = BinarySearchNode {
value: "a",
key: 0,
left: Some(Box::new(BinarySearchNode {
value: "b",
key: 1,
left: None,
right: None,
})),
right: Some(Box::new(BinarySearchNode {
value: "c",
key: 2,
left: None,
right: None,
})),
};
println!("{}", root.print());
}

Try this one:
pub fn print(&self) -> String {
let mut queue = VecDeque::new();
let mut output = String::new();
if let Some(ref left_node) = self.left {
queue.push_back(left_node);
}
if let Some(ref right_node) = self.right {
queue.push_back(right_node);
}
while let Some(ref current) = queue.pop_front() {
if let Some(ref left_node) = current.left {
queue.push_back(left_node);
}
if let Some(ref right_node) = current.right {
queue.push_back(right_node);
}
output = output + current.value + "\n";
}
output
}

Related

Calculate sum of chars in parallel [duplicate]

This question already has answers here:
How can I pass a reference to a stack variable to a thread?
(1 answer)
How can I sum up using concurrency from 1 to 1000000 with Rust?
(1 answer)
Closed 3 years ago.
I have an array of strings. I would like to count the total chars but using threads for parallelisation (the original problem is not this but is similar).
use std::thread;
pub fn frequency<'a>(input: &'a [&'a str], worker_count: usize) -> usize {
let handlers: Vec<thread::JoinHandle<usize>> = input
.chunks(worker_count)
.map(|chunk| thread::spawn(calculate(chunk)))
.collect();
let hashes = handlers.into_iter().map(|handler| handler.join().unwrap());
let mut sum = 0;
for h in hashes {
sum += h
}
sum
}
fn calculate<'a>(input: &'a [&'a str]) -> impl Fn() -> usize + 'a {
move || input.iter().map(|s| s.len()).sum()
}
The compiler tells me this:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/lib.rs:5:10
|
5 | .chunks(worker_count)
| ^^^^^^
|
note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 3:18...
--> src/lib.rs:3:18
|
3 | pub fn frequency<'a>(input: &'a [&'a str], worker_count: usize) -> usize {
| ^^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:4:52
|
4 | let handlers: Vec<thread::JoinHandle<usize>> = input
| ^^^^^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `impl std::ops::Fn<()>` will meet its required lifetime bounds
--> src/lib.rs:6:22
|
6 | .map(|chunk| thread::spawn(calculate(chunk)))
| ^^^^^^^^^^^^^
I've tried to remove all lifetimes, use different lifetimes for str and the slice, and explicitly invoke calculate::<'a> but none of those solutions compile.
The input lifetime is the same everywhere: frequency declares 'a that is used in calculate, so the closure is bound to 'a because the captured variables live for 'a.
Where am I wrong?
NB: I would like not to use 'static.

Using the Bellman-Ford algorithm from petgraph

I would like to use the Bellman-Ford algorithm from the petgraph crate. Here is a very simple sample program which does not compile:
extern crate petgraph;
use petgraph::prelude::*;
use petgraph::dot::{Dot, Config};
use petgraph::algo::bellman_ford;
fn main() {
println!("Hello, world!");
let mut deps = Graph::<&str, u64>::new();
let a = deps.add_node("later");
let b = deps.add_node("hello");
deps.update_edge(a, b, 5);
deps.update_edge(b, a, 10);
let result = bellman_ford(deps, NodeIndex::new(0));
}
When I compile this program I get this error message:
error[E0277]: the trait bound `petgraph::Graph<&str, f64>: petgraph::visit::IntoNodeIdentifiers` is not satisfied
--> src/main.rs:16:18
|
16 | let result = bellman_ford(deps, NodeIndex::new(0));
| ^^^^^^^^^^^^ the trait `petgraph::visit::IntoNodeIdentifiers` is not implemented for `petgraph::Graph<&str, f64>`
|
= help: the following implementations were found:
<&'a petgraph::Graph<N, E, Ty, Ix> as petgraph::visit::IntoNodeIdentifiers>
= note: required by `petgraph::algo::bellman_ford`
error[E0277]: the trait bound `petgraph::Graph<&str, f64>: petgraph::visit::IntoEdges` is not satisfied
--> src/main.rs:16:18
|
16 | let result = bellman_ford(deps, NodeIndex::new(0));
| ^^^^^^^^^^^^ the trait `petgraph::visit::IntoEdges` is not implemented for `petgraph::Graph<&str, f64>`
|
= help: the following implementations were found:
<&'a petgraph::Graph<N, E, Ty, Ix> as petgraph::visit::IntoEdges>
= note: required by `petgraph::algo::bellman_ford`
From what I have gathered, the implemented Bellman-Ford algorithm works with floats, not integers.
Using floats instead of the u64 and referencing deps later does the trick:
use petgraph::algo::bellman_ford;
fn main() {
let mut deps = Graph::<&str, f64>::new();
let a = deps.add_node("later");
let b = deps.add_node("hello");
deps.update_edge(a, b, 5.0);
deps.update_edge(b, a, 10.0);
let result = bellman_ford(&deps, NodeIndex::new(0));
println!("{:?}", result);
}

"overflow while adding drop-check rules" while implementing a fingertree

I'm trying to define a finger tree structure and implement its basic operations as an exercise in Rust. I've come up with the following, which is basically what's described in this paper.
use self::FingerTree::{Empty, Single, Deep};
use self::Digit::{One, Two, Three, Four};
enum Digit<A> {
One(A),
Two(A, A),
Three(A, A, A),
Four(A, A, A, A),
}
enum Node<V, A> {
Node2(V, A, A),
Node3(V, A, A, A),
}
enum FingerTree<V, A> {
Empty,
Single(A),
Deep {
size: V,
prefix: Digit<A>,
tree: Box<FingerTree<V, Node<V, A>>>,
suffix: Digit<A>,
},
}
fn main() {
let e: FingerTree<i32, String> = Empty;
}
Compilation gives me an error that I don't understand:
error[E0320]: overflow while adding drop-check rules for FingerTree<i32, std::string::String>
--> fingertree.rs:28:9
|
28 | let e: FingerTree<i32, String> = Empty;
| ^
|
note: overflowed on enum Node variant Node2 field 0 type: i32
--> fingertree.rs:28:9
|
28 | let e: FingerTree<i32, String> = Empty;
| ^
error[E0320]: overflow while adding drop-check rules for FingerTree<i32, std::string::String>
--> fingertree.rs:28:38
|
28 | let e: FingerTree<i32, String> = Empty;
| ^^^^^
|
note: overflowed on enum Node variant Node2 field 0 type: i32
--> fingertree.rs:28:38
|
28 | let e: FingerTree<i32, String> = Empty;
| ^^^^^
Why is this not working? How do I make it work?
You have created an infinite type.
Instantiating FingerTree<V, A> instantiates FingerTree<V, Node<V, A>> which instantiates FingerTree<V, Node<V, Node<V, A>>> which instantiates, ... and there's no end in sight.
The compiler cannot tell that the type will not actually be used at run-time, so prepares itself for the worst. And the worst is infinite.
Simply replacing the type of tree by Box<FingerTree<V, A>> solves the issue, though it may not be correct for the situation at hand.

Cannot change one value of an enum because it's a re-assignment of an immutable variable

I have enums that contain variables:
enum Asymmetric {
One(i32),
Two(i32, i32),
}
I want to change just one field of an already existing enum, without reassigning the entire enum. My code (playground):
// Does not compile
fn main() {
let two = Asymmetric::Two(4, 5);
let mut vec = vec![two];
foo(&mut vec[0]);
}
fn foo(baa: &mut Asymmetric) {
match baa {
&mut Asymmetric::Two(x0, x1) => {
x0 = 6;
}
_ => {}
}
}
This results in this error:
error[E0384]: re-assignment of immutable variable `x0`
--> src/main.rs:16:13
|
15 | &mut Asymmetric::Two(x0, x1) => {
| -- first assignment to `x0`
16 | x0 = 6;
| ^^^^^^ re-assignment of immutable variable
Thanks to "match ergonomics" (introduced in Rust 1.26, proposed here), you can write your code like this:
fn foo(baa: &mut Asymmetric) {
match baa {
Asymmetric::Two(x0, _) => {
*x0 = 6;
}
_ => {}
}
}
Since baa is a mutable reference, but your pattern you're matching against (Asymmetric::Two(x0, _)) is not, the name x0 is automatically bound as mutable reference.
You can also do it manually by using ref mut. See this working code (playground):
fn foo(baa: &mut Asymmetric) {
match *baa {
Asymmetric::Two(ref mut x0, _) => {
*x0 = 6;
}
_ => {}
}
}
Some minor changes that are not related to your error, but which increase your code quality:
usually you deref (with *) the matched-on value instead of adding & or &mut to every pattern in the match
you should use _ as a name placeholder if you don't need to bind to that name
In your case, you can simplify the code even further by using if let. Whenever you are only interested in one match-case, you should use if let instead:
fn foo(baa: &mut Asymmetric) {
if let Asymmetric::Two(x0, _) = baa {
*x0 = 6;
}
}

How does the TED Talk home page organise the grid of videos?

I've been trying to work out exactly how the TED Talk homepage works. Leaving aside all the animation rubbish, I find the way that the boxes are organised is really fascinating.
At first glance it looks like the jQuery masonry plugin, bu it quickly becomes clear that it tends to create several right angle triangle shapes, but has no fixed number of columns or rows, and the final shape produced is always completely solid (no hollow parts).
My initial assumption was that the boxes (their size is predetermined by some factor on the site) were sorted randomly and then sequentially added to the grid using a few simple rules, however I can't identify what those rules might be, or how they could prevent any hollows in the final shape.
Does anyone have any idea how this works?
Could be wrong but a few observations:
Each section has 19 videos
There are 4 sizes 1 (#1), 1/4 (#2), 1/16 (#3) and 1/32 (#4)
For a given section, there are always 4(#1). The number of (#2), (#3) and (#4) can be either:
4(#1), 10(#2), 4(#3), 1(#1) = 19
4(#1), 11(#2), 4(#3), 0(#1) = 19
4(#1), 11(#2), 3(#3), 1(#1) = 19
4(#1), 12(#2), 2(#3), 1(#1) = 19
4(#1), 13(#2), 1(#3), 1(#1) = 19
As for the order:
The first row always contains 2(#1) and 4(#2)
(#4) are always at the bottom of a column
Here is the javascript code which does it (you need a html page with a div#container):
function ted_layout(settings, coordinates_array, num_elements, start_x, start_y, arrangement, remaining_elements, is_child){
var num_columns = arrangement.length;
var col = 0;
var current_x = start_x;
while( col < num_columns){
var column_x_scale = 100 / arrangement[col];
var current_column_arrangement;
if(is_child){
if(num_elements > 14){
if(column_x_scale == 50){
current_column_arrangement = random_shuffle([1, 2, 2]);
} else {
current_column_arrangement = random_shuffle([1, 2]);
}
} else if(num_elements > 10){
if(column_x_scale == 50){
current_column_arrangement = [1];
} else {
current_column_arrangement = random_shuffle([1, 2]);
}
} else{
current_column_arrangement = random_shuffle([1, 2]);
}
} else {
if(num_elements > 14){
if(column_x_scale == 25){
current_column_arrangement = [1, 1];
} else {
current_column_arrangement = [1];
}
} else if(column_x_scale == 25){
current_column_arrangement = [1, 1];
} else {
current_column_arrangement = [1];
}
}
var num_rows = current_column_arrangement.length;
var current_y = start_y;
var row = 0;
while(row < num_rows){
var numRects = current_column_arrangement[row];
var current_rectangle = 0;
var current_rectangle_x = current_x;
while( current_rectangle < numRects){
if(remaining_elements == 0){
return coordinates_array;
}
var currScale = column_x_scale/numRects;
var height = settings.height * currScale*0.01;
var width = settings.width * currScale*0.01;
if(current_rectangle == numRects-1 && row == num_rows-1 && is_child && Math.random() > 0.5){
coordinates_array.push({x: current_rectangle_x, y:current_y, w:width/2, h:height/2, scale:currScale/2*0.01*2})
}
else{
coordinates_array.push({x: current_rectangle_x, y:current_y, w:width, h:height, scale:currScale*0.01*2})
}
current_rectangle_x += width;
remaining_elements--;
current_rectangle++;
}
row++;
current_y += height;
}
current_x = current_rectangle_x;
col++;
}
if( remaining_elements > 0){
coordinates_array = ted_layout(settings, coordinates_array, num_elements, start_x, current_y, random_shuffle([2, 4, 4, 2]), remaining_elements, true);
}
return coordinates_array;
}
function generate_ted_layout(num_elements){
var settings = {
width: 640,
height: 480,
};
var coordinates_array=[];
returned = ted_layout(settings, coordinates_array, num_elements, 0, 0, random_shuffle([2, 4, 4, 2]), num_elements, false);
console.log("Returned", returned)
return returned;
}
function random_shuffle(array){
var temp;
for(var i = array.length - 1; i >= 1; i--){
var elem = Math.floor(Math.random() * (i + 1));
temp = array[elem];
array[elem] = array[i];
array[i] = temp;
}
return array;
}
function initAndLayout() {
var items = generate_ted_layout(20);
var container = $('#container'); // cache jquery object
console.log(items);
for (var i = 0; i < items.length; i++)
{
var item = items[i];
console.log(item);
$('#container').append($('<div class="item"></div>').css({'left': item.x, 'top': item.y, 'width': item.w, 'height': item.h}));
}
}
I think I've worked it out.
First of all the number of items varies substantially, I'm currently viewing a page with only 13 boxes.
To start I'll name each of the 4 sizes of blocks from largest to smallest as:
A,B,C,D
As we know the first 'row' contains two As and two vertical stacks of Bs, for example:
_______________________
| A | B | A | B |
| |___| |___|
| | B | | B |
|_______|___|_______|___|
The arrangement of these appears to be random, but the Bs are always in the same vertical pattern. Looking at this just now I realised that there are only two rows, and the second row works in the same way.
The second row is twice the height of the first, taking up the rest of the page. It is built of horizontally stacked patterns of shapes, which are (at least in part) selected randomly.
I've found 9 of these patterns of shapes, two of which are a single A or B and the rest are:
_______ _______ _______ ___ ___ _______ ___
| B | B | | A | | B | B | |C|C| | B | | A | |C|C|
|___|___| | | |___|___| | B | |___| | |
| A | | | | B | B | |___| |C|D | |
| | |_______| |___|___| |_______|
| | | B | B | | A | | B |
|_______| |___|___| | | |___|
|B |C| |B |C| | |
|___| |___| |_______|
The next question is how are these selected? There may be some clever searching to find the best configuration: for example if there are X items to be displayed we need to find a configuration with a total of X which does not exceed the width of the row.
This could be done with a metric of pattern density, which would be number of blocks divided by the width of the pattern.

Resources