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

Add a priority queue implementation built on top of Heap #51

Closed
wants to merge 9 commits into from
98 changes: 81 additions & 17 deletions Benchmarks/Benchmarks/HeapBenchmarks.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

import CollectionsBenchmark
import PriorityQueueModule
import CppBenchmarks

extension Benchmark {
public mutating func addHeapBenchmarks() {
Expand All @@ -33,23 +32,23 @@ extension Benchmark {
title: "Heap<Int> insert",
input: [Int].self
) { input in
var queue = Heap<Int>()
var heap = Heap<Int>()
for i in input {
queue.insert(i)
heap.insert(i)
}
precondition(queue.count == input.count)
blackHole(queue)
precondition(heap.count == input.count)
blackHole(heap)
}

self.add(
title: "Heap<Int> insert(contentsOf:)",
input: ([Int], [Int]).self
) { (existing, new) in
return { timer in
var queue = Heap(existing)
queue.insert(contentsOf: new)
precondition(queue.count == existing.count + new.count)
blackHole(queue)
var heap = Heap(existing)
heap.insert(contentsOf: new)
precondition(heap.count == existing.count + new.count)
blackHole(heap)
}
}

Expand All @@ -58,14 +57,14 @@ extension Benchmark {
input: [Int].self
) { input in
return { timer in
var queue = Heap(input)
var heap = Heap(input)
timer.measure {
while let max = queue.popMax() {
while let max = heap.popMax() {
blackHole(max)
}
}
precondition(queue.isEmpty)
blackHole(queue)
precondition(heap.isEmpty)
blackHole(heap)
}
}

Expand All @@ -74,15 +73,80 @@ extension Benchmark {
input: [Int].self
) { input in
return { timer in
var queue = Heap(input)
var heap = Heap(input)
timer.measure {
while let min = queue.popMin() {
while let min = heap.popMin() {
blackHole(min)
}
}
precondition(queue.isEmpty)
blackHole(queue)
precondition(heap.isEmpty)
blackHole(heap)
}
}

// MARK: Small Struct Benchmarks

self.addSimple(
title: "Heap<Task> insert",
input: [Int].self
) { input in
var heap = Heap<HeapTask>()
for i in input {
heap.insert(HeapTask(priority: i))
}
precondition(heap.count == input.count)
blackHole(heap)
}
self.add(
title: "Heap<Task> popMax",
input: [Int].self
) { input in
return { timer in
var heap = Heap(input.map { HeapTask(priority: $0) })
timer.measure {
while let max = heap.popMax() {
blackHole(max)
}
}
precondition(heap.isEmpty)
blackHole(heap)
}
}

self.add(
title: "Heap<Task> popMin",
input: [Int].self
) { input in
return { timer in
var heap = Heap(input.map { HeapTask(priority: $0) })
timer.measure {
while let min = heap.popMin() {
blackHole(min)
}
}
precondition(heap.isEmpty)
blackHole(heap)
}
}
}

struct HeapTask: Comparable {
let name: String
let priority: Int
let work: () -> Void

init(name: String = "", priority: Int, work: @escaping () -> Void = {}) {
self.name = name
self.priority = priority
self.work = work
}

static func < (lhs: Self, rhs: Self) -> Bool {
lhs.priority < rhs.priority
}

static func == (lhs: Self, rhs: Self) -> Bool {
lhs.priority == rhs.priority
}
}
}
2 changes: 1 addition & 1 deletion Benchmarks/Benchmarks/Library.json
Original file line number Diff line number Diff line change
Expand Up @@ -802,7 +802,7 @@
]
}
]
},
}
]
},
{
Expand Down
121 changes: 121 additions & 0 deletions Benchmarks/Benchmarks/PriorityQueueBenchmarks.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift Collections open source project
//
// Copyright (c) 2021 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//

import CollectionsBenchmark
import PriorityQueueModule

extension Benchmark {
public mutating func addPriorityQueueBenchmarks() {
self.addSimple(
title: "PriorityQueue<Int, Int> insert",
input: [Int].self
) { input in
var queue = PriorityQueue<Int, Int>()
for i in input {
queue.insert(i, priority: i)
}
precondition(queue.count == input.count)
blackHole(queue)
}

self.add(
title: "PriorityQueue<Int, Int> popMax",
input: [Int].self
) { input in
return { timer in
var queue = PriorityQueue(input.map({ ($0, $0) }))
timer.measure {
while let max = queue.popMax() {
blackHole(max)
}
}
precondition(queue.isEmpty)
blackHole(queue)
}
}

self.add(
title: "PriorityQueue<Int, Int> popMin",
input: [Int].self
) { input in
return { timer in
var queue = PriorityQueue(input.map({ ($0, $0) }))
timer.measure {
while let min = queue.popMin() {
blackHole(min)
}
}
precondition(queue.isEmpty)
blackHole(queue)
}
}

// MARK: Small Struct Benchmarks

struct Task {
let name: String
let work: () -> Void

init(name: String = "", work: @escaping () -> Void = {}) {
self.name = name
self.work = work
}
}

self.addSimple(
title: "PriorityQueue<Task, Int> insert",
input: [Int].self
) { input in
var queue = PriorityQueue<Task, Int>()
for i in input {
queue.insert(Task(name: "Test", work: {}), priority: i)
}
precondition(queue.count == input.count)
blackHole(queue)
}

self.add(
title: "PriorityQueue<Task, Int> popMax",
input: [Int].self
) { input in
return { timer in
var queue = PriorityQueue<Task, Int>(
input.map({ (Task(name: $0.description), $0) })
)
timer.measure {
while let max = queue.popMax() {
blackHole(max)
}
}
precondition(queue.isEmpty)
blackHole(queue)
}
}

self.add(
title: "PriorityQueue<Task, Int> popMin",
input: [Int].self
) { input in
return { timer in
var queue = PriorityQueue(
input.map({ (Task(name: $0.description), $0) })
)
timer.measure {
while let min = queue.popMin() {
blackHole(min)
}
}
precondition(queue.isEmpty)
blackHole(queue)
}
}
}
}
64 changes: 64 additions & 0 deletions Benchmarks/Libraries/PriorityQueue.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"kind": "group",
"title": "Priority Queue Benchmarks",
"directory": "Results",
"contents": [
{
"kind": "group",
"title": "PriorityQueue Operations",
"contents": [
{
"kind": "chart",
"title": "operations",
"tasks": [
"PriorityQueue<Task, Int> insert",
"PriorityQueue<Task, Int> popMax",
"PriorityQueue<Task, Int> popMin"
]
},
{
"kind": "chart",
"title": "insert",
"tasks": [
"PriorityQueue<Task, Int> insert",
]
},
{
"kind": "chart",
"title": "remove",
"tasks": [
"PriorityQueue<Task, Int> popMax",
"PriorityQueue<Task, Int> popMin"
]
}
]
},
{
"kind": "group",
"title": "PriorityQueue vs Heap",
"directory": "PriorityQueue + Heap",
"contents": [
{
"kind": "chart",
"title": "insert",
"tasks": [
"PriorityQueue<Int, Int> insert",
"PriorityQueue<Task, Int> insert",
"Heap<Int> insert",
"Heap<Task> insert"
]
},
{
"kind": "chart",
"title": "pop",
"tasks": [
"PriorityQueue<Task, Int> popMin",
"PriorityQueue<Task, Int> popMax",
"Heap<Task> popMin",
"Heap<Task> popMax"
]
},
]
}
]
}
1 change: 1 addition & 0 deletions Benchmarks/benchmark-tool/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ benchmark.addDequeBenchmarks()
benchmark.addOrderedSetBenchmarks()
benchmark.addOrderedDictionaryBenchmarks()
benchmark.addHeapBenchmarks()
benchmark.addPriorityQueueBenchmarks()
benchmark.addCppBenchmarks()
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
benchmark.addFoundationBenchmarks()
Expand Down
Loading