-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
std.PriorityQueue.update assumes T supports the equality operator #9918
Comments
Changing the implementation of pub fn indexOfScalarPos(comptime T: type, slice: []const T, start_index: usize, value: T) ?usize {
var i: usize = start_index;
while (i < slice.len) : (i += 1) {
if (slice[i] == value) return i;
}
return null;
} to: pub fn indexOfScalarPos(comptime T: type, slice: []const T, start_index: usize, value: T) ?usize {
var i: usize = start_index;
while (i < slice.len) : (i += 1) {
if (meta.eql(slice[i], value)) return i;
}
return null;
} resolves this issue and the program in my original comment will then proceed to compile. However, I can't comment on the performance implications of such a change, or whether this would even be the right way of solving this. |
I can't comment on the performance of that fix either; but whether the solution is that, or passing in a custom equality function (perhaps via a context like HashMap uses), I believe there are clear use cases for which Even basic algorithms like Dijkstra will require the association of a value to its priority; and as far as I'm aware, this requires the use of a struct as the priority queue type, something to the effect of: pub const DijkstraNode {
node_val: T,
priority: u32
}; Namely because, there isn't a good way (that I'm aware of) to implement the required comparison function for a priority queue unless the value and the priority are contained within the same struct. There are obviously some current limitations to closures/lambda capturing in Zig, as discussed particularly near the bottom of #1048, so if you had a priority queue of |
In Dijkstra's specifically, it is of note that it wouldn't require this association; you could just insert duplicate elements; but I would think that there are still cases where this behavior could be problematic. |
I think is a missuse of |
Ran into this today while doing Djikstra too. I propose that the update function shouldn't do any searching in the queue for you. Instead, it should take in an index of the item to update, and then just update it with the new value. Users can write their own version of Here's a code sample of what I'm thinking of. This is code from AoC day 15 I was working on, when I wanted to implement addOrUpdate to the priority queue. Bear in mind that this is fantasy code so it might not actually be correct 😅 fn addOrUpdate(queue: *DjikstraPQ, item: QueueDatum) !void {
var foundIdx: usize = 0;
// std::find
var it = queue.iterator();
while (it.next()) |elt|: (foundIdx += 1) {
// Users should change this to implement their own find function
if (elt.pos == item.pos) break;
}
if (found != queue.count()) {
queue.update(foundIdx, item) catch unreachable; // in this case, update takes an index instead
} else {
try queue.add(item);
}
} As @Chris3606 mentions, adding duplicate elements into the queue is definitely a workaround, but is not a good long term solution. I took a look at what a Rust crate does, looks like they take the element in but they also have a requirement that the elements inserted must be hashable, and there is an internal hash table that keeps track of which element is in which index. |
Closed in #10342? |
Additionally, I wanted to add a bit to the discussion on the API from above: I agree with @thomastay insofar as an Particularly since in theory (if the API allowed a user to cache nodes themselves and the data types were cached in a way accessible in constant time) it should be possible to have a constant-time lookup of the node then simply the |
update() calls mem.indexOfScalar() which uses `==` for comparing items, which fails when the operator is not supported. As PirorityQueue needs a comparing function anyway we can use `.eq` results to identify matching objects. closes ziglang#9918
update() calls mem.indexOfScalar() which uses `==` for comparing items, which fails when the operator is not supported. As PirorityQueue needs a comparing function anyway we can use `.eq` results to identify matching objects. closes ziglang#9918
I have tried my Aoc 2021 solutions with #12154: In ReleaseFast first part 1100 us -> 2200 us, the second part 33.000us -> 105.000 us. PriorityQueue use a binary heap under the hood, so we can not use |
update() calls mem.indexOfScalar() which uses `==` for comparing items, which fails when the operator is not supported. As PirorityQueue needs a comparing function anyway we can use `.eq` results to identify matching objects. closes #9918
update() calls mem.indexOfScalar() which uses `==` for comparing items, which fails when the operator is not supported. As PirorityQueue needs a comparing function anyway we can use `.eq` results to identify matching objects. closes ziglang#9918
Zig Version
0.9.0-dev.1275+ac52e0056
Steps to Reproduce
Given the
main.zig
described below:run
zig build
in order to reproduce the bug.Expected Behavior
I expected the zig program to compile.
Actual Behavior
I received the following from
stderr
:Which suggests to me that either this is an oversight or it should be made clear that there is an equality operator constraint on std.PriorityQueue.update or std.PriorityQueue as a whole.
The text was updated successfully, but these errors were encountered: