From f7634bdd95d7fec7e90ea0b48078b55cb620cb57 Mon Sep 17 00:00:00 2001 From: Michael Mandl Date: Wed, 20 Mar 2024 09:34:54 +0100 Subject: [PATCH 1/6] feat: add ui layout --- QVectorSearch/mainwindow.ui | 83 +++++++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 4 deletions(-) diff --git a/QVectorSearch/mainwindow.ui b/QVectorSearch/mainwindow.ui index b232854..64e65ed 100644 --- a/QVectorSearch/mainwindow.ui +++ b/QVectorSearch/mainwindow.ui @@ -11,11 +11,86 @@ - MainWindow + QVectorSearch - - - + + false + + + + + 0 + 0 + + + + + 1920 + 1200 + + + + + + + QLayout::SetDefaultConstraint + + + + + Select search algorithm + + + + + + + + 0 + 0 + + + + <html><head/><body><p>Enter a search text</p></body></html> + + + + + + + + + + + 0 + 0 + + + + + + + + + + + 0 + 0 + + + + true + + + + + + + + + Option + + From 64ae4c62a947b7438d93e32bfa7d26392992b6c3 Mon Sep 17 00:00:00 2001 From: Michael Mandl Date: Wed, 20 Mar 2024 09:58:40 +0100 Subject: [PATCH 2/6] refactor: return numerical value from timer --- lib_vector_search/include/timer.h | 7 ++++--- lib_vector_search/src/timer.cpp | 13 +++++-------- vector_search_cli/main.cpp | 13 ++++++++----- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/lib_vector_search/include/timer.h b/lib_vector_search/include/timer.h index 45226e4..c04724f 100644 --- a/lib_vector_search/include/timer.h +++ b/lib_vector_search/include/timer.h @@ -1,16 +1,17 @@ #pragma once #include -#include class Timer { private: - std::string name_; std::chrono::time_point start_; + std::chrono::time_point end_; public: - Timer(std::string_view name); + Timer(); void start(); void stop(); + + long us() const; }; diff --git a/lib_vector_search/src/timer.cpp b/lib_vector_search/src/timer.cpp index 43987b5..960868c 100644 --- a/lib_vector_search/src/timer.cpp +++ b/lib_vector_search/src/timer.cpp @@ -1,17 +1,14 @@ #include "timer.h" #include -#include -Timer::Timer(std::string_view name) : name_(name) { start(); }; +Timer::Timer() { start(); }; void Timer::start() { start_ = std::chrono::high_resolution_clock::now(); } -void Timer::stop() { - auto end = std::chrono::high_resolution_clock::now(); +void Timer::stop() { end_ = std::chrono::high_resolution_clock::now(); } - auto duration = - std::chrono::duration_cast(end - start_); - - std::cout << name_ << " took " << duration << std::endl; +long Timer::us() const { + return std::chrono::duration_cast(end_ - start_) + .count(); } diff --git a/vector_search_cli/main.cpp b/vector_search_cli/main.cpp index f9c356e..f0377f9 100644 --- a/vector_search_cli/main.cpp +++ b/vector_search_cli/main.cpp @@ -13,10 +13,11 @@ using std::string, std::string_view, std::vector, std::thread, std::cout, vector generate_word_list() { cout << "\ngenerating word list" << endl; - Timer generator_timer("word list generator"); + Timer generator_timer; auto word_list = WordListGenerator().generate(); generator_timer.stop(); + cout << "word list generator took " << generator_timer.us() << " µs" << endl; cout << "word list is " << word_list.size() << " element(s) long" << endl; return word_list; @@ -25,14 +26,15 @@ vector generate_word_list() { void test_linear_finder(const vector &word_list) { cout << "\nrunning linear finder" << endl; - Timer constructor_timer("linear finder constructor"); + Timer constructor_timer; LinearFinder linear_finder(word_list); constructor_timer.stop(); - Timer find_timer("linear finder find"); + Timer find_timer; auto result = linear_finder.find_prefix("ABCD"); find_timer.stop(); + cout << "linear finder took " << find_timer.us() << " µs" << endl; cout << "result list is " << result.size() << " element(s) long" << endl; } @@ -43,14 +45,15 @@ void test_parallel_finder(const vector &word_list) { cout << "using " << thread_count << " threads" << endl; - Timer constructor_timer("parallel finder constructor"); + Timer constructor_timer; ParallelFinder parallel_finder(word_list, thread_count); constructor_timer.stop(); - Timer find_timer("parallel finder find"); + Timer find_timer; auto result = parallel_finder.find_prefix("ABCD"); find_timer.stop(); + cout << "parallel finder took " << find_timer.us() << " µs" << endl; cout << "result list is " << result.size() << " element(s) long" << endl; } From 42b8c8d7e75af9f5a442cbd8f8a8486c8dbf5384 Mon Sep 17 00:00:00 2001 From: Michael Mandl Date: Wed, 20 Mar 2024 10:13:08 +0100 Subject: [PATCH 3/6] feat: implement ostream operator for timer --- lib_vector_search/include/timer.h | 2 ++ lib_vector_search/src/timer.cpp | 18 ++++++++++++++++++ vector_search_cli/main.cpp | 6 +++--- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/lib_vector_search/include/timer.h b/lib_vector_search/include/timer.h index c04724f..e7fc1d6 100644 --- a/lib_vector_search/include/timer.h +++ b/lib_vector_search/include/timer.h @@ -15,3 +15,5 @@ public: long us() const; }; + +std::ostream &operator<<(std::ostream &os, const Timer &timer); diff --git a/lib_vector_search/src/timer.cpp b/lib_vector_search/src/timer.cpp index 960868c..a663e3e 100644 --- a/lib_vector_search/src/timer.cpp +++ b/lib_vector_search/src/timer.cpp @@ -12,3 +12,21 @@ long Timer::us() const { return std::chrono::duration_cast(end_ - start_) .count(); } + +std::ostream &operator<<(std::ostream &os, const Timer &timer) { + long time = timer.us(); + + if (time >= 1e6) { + os << time / static_cast(1e6) << " s "; + time %= static_cast(1e6); + } + + if (time >= 1e3) { + os << time / static_cast(1e3) << " ms "; + time %= static_cast(1e3); + } + + os << time << " µs"; + + return os; +} diff --git a/vector_search_cli/main.cpp b/vector_search_cli/main.cpp index f0377f9..ace12f7 100644 --- a/vector_search_cli/main.cpp +++ b/vector_search_cli/main.cpp @@ -17,7 +17,7 @@ vector generate_word_list() { auto word_list = WordListGenerator().generate(); generator_timer.stop(); - cout << "word list generator took " << generator_timer.us() << " µs" << endl; + cout << "word list generator took " << generator_timer << endl; cout << "word list is " << word_list.size() << " element(s) long" << endl; return word_list; @@ -34,7 +34,7 @@ void test_linear_finder(const vector &word_list) { auto result = linear_finder.find_prefix("ABCD"); find_timer.stop(); - cout << "linear finder took " << find_timer.us() << " µs" << endl; + cout << "linear finder took " << find_timer << endl; cout << "result list is " << result.size() << " element(s) long" << endl; } @@ -53,7 +53,7 @@ void test_parallel_finder(const vector &word_list) { auto result = parallel_finder.find_prefix("ABCD"); find_timer.stop(); - cout << "parallel finder took " << find_timer.us() << " µs" << endl; + cout << "parallel finder took " << find_timer << endl; cout << "result list is " << result.size() << " element(s) long" << endl; } From e2f9b630c52e1edac8823e7aeff1235b3dc6e7fd Mon Sep 17 00:00:00 2001 From: Michael Mandl Date: Wed, 20 Mar 2024 10:16:46 +0100 Subject: [PATCH 4/6] feat: generate word list --- QVectorSearch/CMakeLists.txt | 3 ++- QVectorSearch/mainwindow.cpp | 23 +++++++++++++++++++++++ QVectorSearch/mainwindow.h | 8 ++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/QVectorSearch/CMakeLists.txt b/QVectorSearch/CMakeLists.txt index 3193977..6b4aaac 100644 --- a/QVectorSearch/CMakeLists.txt +++ b/QVectorSearch/CMakeLists.txt @@ -33,7 +33,8 @@ else() endif() endif() -target_link_libraries(QVectorSearch PRIVATE Qt${QT_VERSION_MAJOR}::Widgets) +target_link_libraries(QVectorSearch PRIVATE Qt${QT_VERSION_MAJOR}::Widgets + vector_search) # Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. If # you are developing for iOS or macOS you should consider setting an explicit, diff --git a/QVectorSearch/mainwindow.cpp b/QVectorSearch/mainwindow.cpp index df8aa76..ac878e0 100644 --- a/QVectorSearch/mainwindow.cpp +++ b/QVectorSearch/mainwindow.cpp @@ -1,9 +1,32 @@ #include "mainwindow.h" #include "./ui_mainwindow.h" +#include "timer.h" +#include "word_list_generator.h" + MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); + ui->resultView->setModel(&result_model_); + + generate_word_list(); } MainWindow::~MainWindow() { delete ui; } + +void MainWindow::generate_word_list() { + Timer timer; + word_list_ = WordListGenerator().generate(); + timer.stop(); + + std::stringstream status_message; + status_message << "generated " << word_list_.size() << " words in " << timer; + ui->mainStatusBar->showMessage(QString::fromStdString(status_message.str())); + + QStringList words; + for (auto word : word_list_) { + words.append(QString::fromStdString(word)); + } + + result_model_.setStringList(words); +} diff --git a/QVectorSearch/mainwindow.h b/QVectorSearch/mainwindow.h index 94cd27c..a54de85 100644 --- a/QVectorSearch/mainwindow.h +++ b/QVectorSearch/mainwindow.h @@ -2,6 +2,7 @@ #define MAINWINDOW_H #include +#include QT_BEGIN_NAMESPACE namespace Ui { @@ -12,10 +13,17 @@ QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT +private: + std::vector word_list_; + QStringListModel result_model_; + public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); +private: + void generate_word_list(); + private: Ui::MainWindow *ui; }; From 2a8b342b914b71987b37d4f5602e6e8c8d6f9ab3 Mon Sep 17 00:00:00 2001 From: Michael Mandl Date: Wed, 20 Mar 2024 10:47:05 +0100 Subject: [PATCH 5/6] feat: implement search --- QVectorSearch/mainwindow.cpp | 69 ++++++++++++++++++++++++++++++++++-- QVectorSearch/mainwindow.h | 13 ++++++- 2 files changed, 78 insertions(+), 4 deletions(-) diff --git a/QVectorSearch/mainwindow.cpp b/QVectorSearch/mainwindow.cpp index ac878e0..81bd7fd 100644 --- a/QVectorSearch/mainwindow.cpp +++ b/QVectorSearch/mainwindow.cpp @@ -1,20 +1,33 @@ #include "mainwindow.h" #include "./ui_mainwindow.h" +#include "finder.h" +#include "linear_finder.h" +#include "parallel_finder.h" #include "timer.h" #include "word_list_generator.h" +#include + MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); - ui->resultView->setModel(&result_model_); - generate_word_list(); + ui->resultView->setModel(&result_model_); + ui->searchAlgorithmSelector->setModel(&search_algorithms_); + + setupAlgorithmSelector(); + generateWordList(); } MainWindow::~MainWindow() { delete ui; } -void MainWindow::generate_word_list() { +void MainWindow::setupAlgorithmSelector() { + search_algorithms_.appendRow(new QStandardItem("Linear search")); + search_algorithms_.appendRow(new QStandardItem("Parallel search")); +} + +void MainWindow::generateWordList() { Timer timer; word_list_ = WordListGenerator().generate(); timer.stop(); @@ -30,3 +43,53 @@ void MainWindow::generate_word_list() { result_model_.setStringList(words); } + +void MainWindow::search(const QString &search_term) { + if (search_term.isEmpty()) { + result_model_.setStringList(QStringList()); + ui->mainStatusBar->clearMessage(); + return; + } + + Timer timer; + const auto finder = createSelectedFinder(); + const auto results = finder->find_prefix(search_term.toStdString()); + timer.stop(); + + std::stringstream status_message; + status_message << "search took " << timer << ", found " << results.size() + << " results"; + ui->mainStatusBar->showMessage(QString::fromStdString(status_message.str())); + + showResults(results); +} + +std::unique_ptr MainWindow::createSelectedFinder() const { + auto selectedFinder = ui->searchAlgorithmSelector->currentIndex(); + + switch (selectedFinder) { + case 0: + default: + return std::make_unique(word_list_); + case 1: + return std::make_unique( + word_list_, std::thread::hardware_concurrency()); + } +} + +void MainWindow::showResults(const std::vector &results) { + QStringList ui_results; + for (auto word : results) { + ui_results.append(QString::fromStdString(*word)); + } + + result_model_.setStringList(ui_results); +} + +void MainWindow::on_searchInput_textChanged(const QString &search_term) { + search(search_term); +} + +void MainWindow::on_searchAlgorithmSelector_currentIndexChanged(int) { + search(ui->searchInput->displayText()); +} diff --git a/QVectorSearch/mainwindow.h b/QVectorSearch/mainwindow.h index a54de85..15ea3f8 100644 --- a/QVectorSearch/mainwindow.h +++ b/QVectorSearch/mainwindow.h @@ -1,7 +1,9 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H +#include "finder.h" #include +#include #include QT_BEGIN_NAMESPACE @@ -16,13 +18,22 @@ class MainWindow : public QMainWindow { private: std::vector word_list_; QStringListModel result_model_; + QStandardItemModel search_algorithms_; public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private: - void generate_word_list(); + void setupAlgorithmSelector(); + void generateWordList(); + void search(const QString &search_term); + std::unique_ptr createSelectedFinder() const; + void showResults(const std::vector &results); + +private slots: + void on_searchInput_textChanged(const QString &search_term); + void on_searchAlgorithmSelector_currentIndexChanged(int); private: Ui::MainWindow *ui; From 9a855daabfb21bf2601bdcfc22f68c106f93146e Mon Sep 17 00:00:00 2001 From: Michael Mandl Date: Wed, 20 Mar 2024 10:47:38 +0100 Subject: [PATCH 6/6] feat: reduce word list size --- lib_vector_search/src/word_list_generator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_vector_search/src/word_list_generator.cpp b/lib_vector_search/src/word_list_generator.cpp index 5863567..e4bdf52 100644 --- a/lib_vector_search/src/word_list_generator.cpp +++ b/lib_vector_search/src/word_list_generator.cpp @@ -7,7 +7,7 @@ const std::string WordListGenerator::charset_ = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; std::vector WordListGenerator::generate() { - const size_t multiplier = 10; + const size_t multiplier = 1; std::vector result; result.reserve(multiplier * std::pow(charset_.length(), 4));