Add iterations per cycle & optional sqrt optimization
This commit is contained in:
parent
e0178e27d2
commit
37234a44c9
3 changed files with 185 additions and 64 deletions
100
qml/Main.qml
100
qml/Main.qml
|
@ -15,39 +15,28 @@ ApplicationWindow {
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 10
|
spacing: 15
|
||||||
|
|
||||||
Text {
|
GroupBox {
|
||||||
text: "Enter a number to factorize:"
|
title: "Input"
|
||||||
font.pixelSize: 16
|
Layout.fillWidth: true
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
}
|
ColumnLayout {
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: numberInput
|
id: numberInput
|
||||||
placeholderText: "Enter number"
|
placeholderText: "Enter a number"
|
||||||
// NOTE: We can't use the IntValidator here, since it doesn't support 64-bit values (long long)
|
// NOTE: We can't use the IntValidator here, since it doesn't support 64-bit values (long long)
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
onTextChanged: {
|
font.pixelSize: 16
|
||||||
// If the number changes, reset
|
onTextChanged: factorizationController.reset()
|
||||||
factorizationController.reset();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
spacing: 10
|
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
text: {
|
text: factorizationController.isPaused ? "Resume" : factorizationController.isRunning ? "..." : "Start"
|
||||||
if (factorizationController.isPaused) {
|
|
||||||
return "Resume";
|
|
||||||
} else if (factorizationController.isRunning) {
|
|
||||||
return "...";
|
|
||||||
} else {
|
|
||||||
return "Start";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
enabled: !factorizationController.isRunning
|
enabled: !factorizationController.isRunning
|
||||||
onClicked: {
|
onClicked: {
|
||||||
|
@ -66,6 +55,47 @@ ApplicationWindow {
|
||||||
onClicked: factorizationController.stop()
|
onClicked: factorizationController.stop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GroupBox {
|
||||||
|
title: "Settings"
|
||||||
|
Layout.fillWidth: true
|
||||||
|
ColumnLayout {
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: "Iterations per cycle:"
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
}
|
||||||
|
|
||||||
|
Slider {
|
||||||
|
id: iterationSlider
|
||||||
|
Layout.fillWidth: true
|
||||||
|
from: 1
|
||||||
|
to: 100000
|
||||||
|
stepSize: 1
|
||||||
|
value: 1
|
||||||
|
onValueChanged: factorizationController.iterationsPerCycle = value
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: iterationSlider.value.toFixed(0)
|
||||||
|
font.bold: true
|
||||||
|
Layout.alignment: Qt.AlignRight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
text: "Stop at sqrt(n)"
|
||||||
|
checked: true
|
||||||
|
onCheckedChanged: factorizationController.useSqrtOptimization = checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ProgressBar {
|
ProgressBar {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
@ -74,32 +104,34 @@ ApplicationWindow {
|
||||||
value: factorizationController.progress
|
value: factorizationController.progress
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GroupBox {
|
||||||
|
title: "Current Status"
|
||||||
|
Layout.fillWidth: true
|
||||||
|
ColumnLayout {
|
||||||
|
spacing: 5
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
text: "Current Factor: " + factorizationController.currentFactor
|
text: "Current Factor: " + factorizationController.currentFactor
|
||||||
font.pixelSize: 14
|
font.pixelSize: 14
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Text {
|
|
||||||
text: "Factors Found:"
|
|
||||||
font.pixelSize: 14
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ListView {
|
GroupBox {
|
||||||
|
title: "Factors Found"
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
model: factorizationController.factors
|
|
||||||
delegate: Text {
|
Text {
|
||||||
text: modelData
|
text: factorizationController.factors.join(", ")
|
||||||
font.pixelSize: 14
|
font.pixelSize: 14
|
||||||
horizontalAlignment: Text.AlignHCenter
|
color: "black"
|
||||||
width: parent.width
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
text: "Warning: This only shows factors below sqrt(num)"
|
text: factorizationController.useSqrtOptimization ? "Note: Only factors up to sqrt(n) are shown." : "Note: Finding all factors (slower)."
|
||||||
font.pixelSize: 12
|
font.pixelSize: 12
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
FactorizationController::FactorizationController(QObject* parent) : QObject{parent}, m_isRunning(false), m_currentFactNumber(0), m_currentFactor(2) {
|
FactorizationController::FactorizationController(QObject* parent) :
|
||||||
|
QObject{parent}, m_isRunning(false), m_useSqrtOptimization(true), m_iterationsPerCycle(1), m_currentFactNumber(0), m_currentFactor(2) {
|
||||||
assert(connect(&m_timer, &QTimer::timeout, this, &FactorizationController::onTimerTick));
|
assert(connect(&m_timer, &QTimer::timeout, this, &FactorizationController::onTimerTick));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +37,31 @@ bool FactorizationController::isPaused() const {
|
||||||
return m_isPaused;
|
return m_isPaused;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FactorizationController::useSqrtOptimization() const {
|
||||||
|
return m_useSqrtOptimization;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FactorizationController::setUseSqrtOptimization(bool value) {
|
||||||
|
if (value == m_useSqrtOptimization)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_useSqrtOptimization = value;
|
||||||
|
emit useSqrtOptimizationChanged();
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
int FactorizationController::iterationsPerCycle() const {
|
||||||
|
return m_iterationsPerCycle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FactorizationController::setIterationsPerCycle(int number) {
|
||||||
|
if (number == m_iterationsPerCycle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_iterationsPerCycle = number;
|
||||||
|
emit iterationsPerCycleChanged();
|
||||||
|
}
|
||||||
|
|
||||||
long long FactorizationController::currentFactor() const {
|
long long FactorizationController::currentFactor() const {
|
||||||
return m_currentFactor;
|
return m_currentFactor;
|
||||||
}
|
}
|
||||||
|
@ -48,8 +74,6 @@ void FactorizationController::start(long long number) {
|
||||||
m_originalNumber = number;
|
m_originalNumber = number;
|
||||||
m_currentFactNumber = number;
|
m_currentFactNumber = number;
|
||||||
m_currentFactor = 2;
|
m_currentFactor = 2;
|
||||||
// we could also just compute this every time, but sqrt is pretty expensive
|
|
||||||
m_stopFactor = static_cast<long long>(std::sqrt(m_currentFactNumber));
|
|
||||||
m_isRunning = true;
|
m_isRunning = true;
|
||||||
m_isFinished = false;
|
m_isFinished = false;
|
||||||
m_factors.clear();
|
m_factors.clear();
|
||||||
|
@ -60,6 +84,13 @@ void FactorizationController::start(long long number) {
|
||||||
emit progressChanged();
|
emit progressChanged();
|
||||||
emit factorsChanged();
|
emit factorsChanged();
|
||||||
|
|
||||||
|
if (m_useSqrtOptimization) {
|
||||||
|
// we could also just compute this every time, but sqrt is pretty expensive
|
||||||
|
m_stopFactor = static_cast<long long>(std::sqrt(m_currentFactNumber));
|
||||||
|
} else {
|
||||||
|
m_stopFactor = m_currentFactNumber;
|
||||||
|
}
|
||||||
|
|
||||||
m_timer.start(0);
|
m_timer.start(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +139,12 @@ void FactorizationController::reset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FactorizationController::onTimerTick() {
|
void FactorizationController::onTimerTick() {
|
||||||
|
for (int i = 0; i < m_iterationsPerCycle; i++) {
|
||||||
|
if (!m_isRunning)
|
||||||
|
break;
|
||||||
|
|
||||||
factorize();
|
factorize();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FactorizationController::factorize() {
|
void FactorizationController::factorize() {
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <QVariant>
|
||||||
#include <qqmlintegration.h>
|
#include <qqmlintegration.h>
|
||||||
#include <qtmetamacros.h>
|
#include <qtmetamacros.h>
|
||||||
|
|
||||||
|
@ -11,8 +12,11 @@
|
||||||
* @brief A class that performs integer factorization in a step-by-step manner.
|
* @brief A class that performs integer factorization in a step-by-step manner.
|
||||||
*
|
*
|
||||||
* This class uses a timer to progressively factorize a given number, allowing
|
* This class uses a timer to progressively factorize a given number, allowing
|
||||||
* for real-time updates on progress and discovered factors. It is designed
|
* for real-time updates on progress and discovered factors. The computation will
|
||||||
* to be used in a Qt-based QML application.
|
* run in a single thread, utilizing 0 tick timers to perform a small number of
|
||||||
|
* iterations on each cycle of the event loop.
|
||||||
|
*
|
||||||
|
* It is designed to be used in a Qt-based QML application.
|
||||||
*/
|
*/
|
||||||
class FactorizationController : public QObject {
|
class FactorizationController : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -20,6 +24,8 @@ class FactorizationController : public QObject {
|
||||||
Q_PROPERTY(bool isRunning READ isRunning NOTIFY isRunningChanged)
|
Q_PROPERTY(bool isRunning READ isRunning NOTIFY isRunningChanged)
|
||||||
Q_PROPERTY(bool isFinished READ isFinished NOTIFY isFinishedChanged)
|
Q_PROPERTY(bool isFinished READ isFinished NOTIFY isFinishedChanged)
|
||||||
Q_PROPERTY(bool isPaused READ isPaused NOTIFY isPausedChanged)
|
Q_PROPERTY(bool isPaused READ isPaused NOTIFY isPausedChanged)
|
||||||
|
Q_PROPERTY(int iterationsPerCycle READ iterationsPerCycle WRITE setIterationsPerCycle NOTIFY iterationsPerCycleChanged)
|
||||||
|
Q_PROPERTY(bool useSqrtOptimization READ useSqrtOptimization WRITE setUseSqrtOptimization NOTIFY useSqrtOptimizationChanged)
|
||||||
Q_PROPERTY(long long number READ number NOTIFY numberChanged)
|
Q_PROPERTY(long long number READ number NOTIFY numberChanged)
|
||||||
Q_PROPERTY(long long currentFactor READ currentFactor NOTIFY currentFactorChanged)
|
Q_PROPERTY(long long currentFactor READ currentFactor NOTIFY currentFactorChanged)
|
||||||
Q_PROPERTY(int progress READ progress NOTIFY progressChanged)
|
Q_PROPERTY(int progress READ progress NOTIFY progressChanged)
|
||||||
|
@ -68,6 +74,18 @@ class FactorizationController : public QObject {
|
||||||
*/
|
*/
|
||||||
bool isPaused() const;
|
bool isPaused() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the number of iterations to be performed per cycle.
|
||||||
|
* @return The number of iterations performed per cycle.
|
||||||
|
*/
|
||||||
|
int iterationsPerCycle() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks whether sqrt optimization is enabled.
|
||||||
|
* @return True if the sqrt optimization is enabled, otherwise False.
|
||||||
|
*/
|
||||||
|
bool useSqrtOptimization() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the original number being factorized.
|
* @brief Gets the original number being factorized.
|
||||||
* @return The number being factorized.
|
* @return The number being factorized.
|
||||||
|
@ -94,6 +112,37 @@ class FactorizationController : public QObject {
|
||||||
*/
|
*/
|
||||||
QList<long long> factors() const;
|
QList<long long> factors() const;
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
// region: Setters
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the number of iterations per cycle.
|
||||||
|
*
|
||||||
|
* This is a way to speed up the computation, by increasing the amount of iterations
|
||||||
|
* performed per each computation (on every event loop cycle). Setting this to a number
|
||||||
|
* too high might lead to OS thinking the application is not responding, and the UI
|
||||||
|
* feeling slow. The optimal number depends on the speed of the CPU and the allocated
|
||||||
|
* CPU time to this process.
|
||||||
|
*
|
||||||
|
* This value can be changed even as a computation is ongoing.
|
||||||
|
*/
|
||||||
|
void setIterationsPerCycle(int number);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable or disable using sqrt optimizations.
|
||||||
|
*
|
||||||
|
* When sqrt optimization is enabled, only factors up to sqrt of the original number
|
||||||
|
* will be checked. This allows the algorithm to finish quicker.
|
||||||
|
*
|
||||||
|
* If the intention is purely to check whether number is or isn't prime, this optimization
|
||||||
|
* is very useful. However, enabling it will lead to some factors not being found, so if
|
||||||
|
* you wish to perform a full factorization, leave this turned off.
|
||||||
|
*
|
||||||
|
* Note that changing this value while the computation is in progress will reset the
|
||||||
|
* computation.
|
||||||
|
*/
|
||||||
|
void setUseSqrtOptimization(bool value);
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
// region: Functions
|
// region: Functions
|
||||||
|
|
||||||
|
@ -135,11 +184,13 @@ class FactorizationController : public QObject {
|
||||||
signals:
|
signals:
|
||||||
void isRunningChanged();
|
void isRunningChanged();
|
||||||
void isFinishedChanged();
|
void isFinishedChanged();
|
||||||
|
void isPausedChanged();
|
||||||
|
void useSqrtOptimizationChanged();
|
||||||
|
void iterationsPerCycleChanged();
|
||||||
void numberChanged();
|
void numberChanged();
|
||||||
void currentFactorChanged();
|
void currentFactorChanged();
|
||||||
void factorsChanged();
|
void factorsChanged();
|
||||||
void progressChanged();
|
void progressChanged();
|
||||||
void isPausedChanged();
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onTimerTick();
|
void onTimerTick();
|
||||||
|
@ -148,6 +199,8 @@ class FactorizationController : public QObject {
|
||||||
bool m_isRunning; ///< Indicates whether factorization is active.
|
bool m_isRunning; ///< Indicates whether factorization is active.
|
||||||
bool m_isFinished; ///< Indicates whether the factorization process is done.
|
bool m_isFinished; ///< Indicates whether the factorization process is done.
|
||||||
bool m_isPaused; ///< Indicates whether the factorization process is paused (can be resumed).
|
bool m_isPaused; ///< Indicates whether the factorization process is paused (can be resumed).
|
||||||
|
bool m_useSqrtOptimization; ///< Indicates whether to use the sqrt optimization
|
||||||
|
int m_iterationsPerCycle; ///< The number of iterations to perform per cycle.
|
||||||
long long m_currentFactNumber; ///< The number currently being factorized.
|
long long m_currentFactNumber; ///< The number currently being factorized.
|
||||||
long long m_originalNumber; ///< The original input number.
|
long long m_originalNumber; ///< The original input number.
|
||||||
long long m_currentFactor; ///< The current divisor being checked.
|
long long m_currentFactor; ///< The current divisor being checked.
|
||||||
|
|
Loading…
Add table
Reference in a new issue