From 35f0e2076ef2e1401f26ddee7c4ade762fe17ba9 Mon Sep 17 00:00:00 2001
From: Caleb Biggs <calebjbiggs@gmail.com>
Date: Mon, 9 Dec 2024 14:51:03 -0800
Subject: [PATCH] Final touches for submission

---
 README.md                   |  9 ++++
 build/src/controller.cpp    | 88 +++++++++++++++++++++++++++++++------
 build/src/controller.hpp    |  6 +--
 build/src/edge_widget.cpp   |  1 +
 build/src/graph.cpp         | 74 +++++++++++++++++++------------
 build/src/graph.hpp         | 25 ++++-------
 build/src/main.cpp          | 33 ++------------
 build/src/selected_pane.cpp |  1 -
 8 files changed, 145 insertions(+), 92 deletions(-)
 create mode 100644 README.md

diff --git a/README.md b/README.md
new file mode 100644
index 0000000..c885cc5
--- /dev/null
+++ b/README.md
@@ -0,0 +1,9 @@
+Requires Qt 5
+This was only tested on Debian 12 using the g++ compiler and qmake
+
+To build:
+run `qmake` in this directory to generate a Makefile
+run `make` to compile
+
+To run:
+Either run `make run` or `./math453`
\ No newline at end of file
diff --git a/build/src/controller.cpp b/build/src/controller.cpp
index dc14615..0cfe05b 100644
--- a/build/src/controller.cpp
+++ b/build/src/controller.cpp
@@ -1,6 +1,16 @@
 #include "controller.hpp"
 
 
+/**
+ * For most of this project I took care to simplify my code once I got 
+ * it working, avoided repeating code, and tried to make all of my 
+ * functions be short and easy to understand. Then I added a bunch of
+ * features that I put no further work into once they were functional
+ * because the deadline was approaching. Most of those features are 
+ * contained in this constructor, which is very bloated and probably 
+ * difficult to read. The program as a whole is also mostly lacking
+ * in comments, hopefully the function names are descriptive enough.
+ */
 controller::controller(QWidget* window): QWidget(window){
 	auto new_node_button = new QPushButton("New Node", this);
     new_node_button->setGeometry(0, 0, 200, 60);
@@ -11,18 +21,65 @@ controller::controller(QWidget* window): QWidget(window){
 
 
     //TODO: Create some sort of "Mass actions" class to house these
-    auto debug_print_button = new QPushButton("Debug: Print Graph", this);
-    debug_print_button->setGeometry(0, 620, 200, 60);
-    QPushButton::connect(debug_print_button, &QPushButton::clicked, this, &controller::debug_print_graph);
-
-    auto clear_edges_button = new QPushButton("Remove All Edges", this);
-    clear_edges_button->setGeometry(0, 680, 200, 60);
+    QLabel* mass_actions = new QLabel("Mass Actions", this);
+    mass_actions->move(5, 445);
+    mass_actions->setAlignment(Qt::AlignLeft);
+    mass_actions->setAlignment(Qt::AlignVCenter);
+    mass_actions->setFixedSize(200, 25);
+
+    auto clear_edges_button = new QPushButton("Clear Edges", this);
+    clear_edges_button->setGeometry(5, 470, 92, 25);
     QPushButton::connect(clear_edges_button, &QPushButton::clicked, this, &controller::rem_all_edges);
 
-    auto rem_all_nodes_button = new QPushButton("Remove All Nodes", this);
-    rem_all_nodes_button->setGeometry(0, 740, 200, 60);
+    auto rem_all_nodes_button = new QPushButton("Clear Nodes", this);
+    rem_all_nodes_button->setGeometry(102, 470, 93, 25);
     QPushButton::connect(rem_all_nodes_button, &QPushButton::clicked, this, &controller::rem_all_nodes); 
 
+    auto show_degree = new QPushButton("Degrees", this);
+    show_degree->setGeometry(5, 500, 92, 25);
+    QPushButton::connect(show_degree, &QPushButton::clicked, this, [&](){
+    	for(auto &[k, v] : nodes){
+    		v->setText(QString::fromStdString(to_string(matrix.get_edges(k).size())));
+    	}
+    }); 
+
+    auto show_index = new QPushButton("Indices", this);
+    show_index->setGeometry(102, 500, 93, 25);
+    QPushButton::connect(show_index, &QPushButton::clicked, this, [&](){
+    	for(auto &[k, v] : nodes){
+    		v->setText(QString::fromStdString(to_string(k)));
+    	}
+    });
+
+    auto min_coloring = new QPushButton("Min Coloring", this);
+    min_coloring->setGeometry(5, 530, 92, 25);
+    QPushButton::connect(min_coloring, &QPushButton::clicked, this, [&](){
+    	vector<tuple<const char*,const string>> colors = {
+    		{"R", "#e50000"}, {"O", "#ff8d00"}, {"Y", "#ffee00"}, {"G", "#028121"}, {"B", "#004cff"}, {"P", "#770088"}};
+    	auto coloring = matrix.minimal_coloring(6);
+    	if(!coloring) return;
+    	for(auto &[k, v] : *coloring) nodes[k]->color(get<1>(colors[v]));
+    });
+
+    k_value = new QLineEdit(this);
+    k_value->move(102, 530);
+    k_value->setFixedSize(22, 25);
+    k_value->setPlaceholderText("K");
+
+    auto k_coloring = new QPushButton("Color", this);
+    k_coloring->setGeometry(129, 530, 66, 25); //102
+    QPushButton::connect(k_coloring, &QPushButton::clicked, this, [&](){
+    	vector<tuple<const char*,const string>> colors = {
+    		{"R", "#e50000"}, {"O", "#ff8d00"}, {"Y", "#ffee00"}, {"G", "#028121"}, {"B", "#004cff"}, {"P", "#770088"}};
+		uint32_t k = 3;
+		try{ k = stol(k_value->text().toStdString());
+    	} catch(...){ return; }
+		if(k > 6) return;
+		auto coloring = matrix.k_color(k);
+		if(!coloring) return;
+		for(auto &[k, v] : *coloring) nodes[k]->color(get<1>(colors[v]));
+    });
+
 
     //TODO: Make a "graph search" class for these
     QLabel* graph_search = new QLabel("Graph Search", this);
@@ -81,12 +138,15 @@ controller::controller(QWidget* window): QWidget(window){
     });
 
 
-    //Testing button
-    auto test_button = new QPushButton("Test Button", this);
-    test_button->setGeometry(0, 560, 200, 60);
-    QPushButton::connect(test_button, &QPushButton::clicked, this, [&](){
-    	
-    }); 
+    //Debug buttons
+    auto test_button = new QPushButton("Debug: Test New Feature", this);
+    test_button->setGeometry(0, 680, 200, 60);
+    QPushButton::connect(test_button, &QPushButton::clicked, this, [&](){});
+
+    auto debug_print_button = new QPushButton("Debug: Print Graph", this);
+    debug_print_button->setGeometry(0, 740, 200, 60);
+    QPushButton::connect(debug_print_button, &QPushButton::clicked, this, &controller::debug_print_graph);
+
 
     area = new graph_area(800, 800, this);
     area->move(200, 0);
diff --git a/build/src/controller.hpp b/build/src/controller.hpp
index f2bc59c..c150782 100644
--- a/build/src/controller.hpp
+++ b/build/src/controller.hpp
@@ -12,10 +12,9 @@
 #include <QString>
 #include <QLineEdit>
 
-#include <bits/stdc++.h> //TODO: Replace with correct imports
+#include "graph.hpp"
 using namespace std;
 
-#include "graph.hpp"
 
 enum Mode { REM_NODE, ADD_EDGE, REM_EDGE };
 
@@ -35,9 +34,10 @@ class controller: public QWidget {
 	graph_area* area;
 	adj_matrix matrix;
 	Mode mode = REM_NODE;
-	//TODO: Put these in their own QWidget class
+	//TODO: Put these in their own QWidget class(es)
 	QLineEdit* search_start;
 	QLineEdit* search_end;
+	QLineEdit* k_value;
 
 	public:
 	controller(QWidget* window);
diff --git a/build/src/edge_widget.cpp b/build/src/edge_widget.cpp
index 41e4bf5..9b4f6b1 100644
--- a/build/src/edge_widget.cpp
+++ b/build/src/edge_widget.cpp
@@ -1,3 +1,4 @@
+#include <cmath>
 #include "controller.hpp"
 
 
diff --git a/build/src/graph.cpp b/build/src/graph.cpp
index 4fb6ecc..03c70fd 100644
--- a/build/src/graph.cpp
+++ b/build/src/graph.cpp
@@ -1,3 +1,9 @@
+#include <queue>
+#include <stack>
+#include <iterator>
+#include <random>
+#include <cmath>
+#include <algorithm>
 #include "graph.hpp"
 
 
@@ -91,6 +97,44 @@ bool adj_matrix::is_adjacent(uint32_t head, uint32_t tail){
 }
 
 
+bool adj_matrix::check_coloring(unordered_map<uint32_t,uint32_t> coloring){
+	for(auto &[node, color] : coloring){
+		for(auto adj : get_adj(node)){
+			if(coloring[adj] == color) return false;
+		}
+	}
+	return true;
+}
+
+
+unordered_map<uint32_t,uint32_t>* adj_matrix::k_color(uint32_t k){
+	auto output = new unordered_map<uint32_t,uint32_t>;
+	vector<uint32_t> keys; 
+	for(auto &[k, v] : matrix) {
+		keys.push_back(k);
+		(*output)[k] = 0;
+	}
+	for(uint64_t i = 0; i < pow(k, matrix.size()); i++){
+		bool carry = true;
+		for(uint32_t j = 0; j < keys.size() && carry; j++){
+			(*output)[keys[j]] = ((*output)[keys[j]]+1)%k;
+			if(!((*output)[keys[j]])) carry = false;
+		}
+		if(check_coloring(*output)) return output;
+	}
+	return NULL;
+}
+
+
+unordered_map<uint32_t,uint32_t>* adj_matrix::minimal_coloring(uint32_t max){
+	for(uint32_t i = 2; i <= max; i++){
+		auto output = k_color(i);
+		if(output) return output;
+	}
+	return NULL;
+}
+
+
 void adj_matrix::print_node(uint32_t node){}
 
 
@@ -196,32 +240,4 @@ vector<uint32_t> Graph::IDS(uint32_t s, uint32_t e){
 	vector<uint32_t> path;
 	for(int i = 1; path.size() == 0; path = DFS(s, e, i++));
 	return path;
-}
-
-
-/****************\
-| Grid Functions |
-\****************/
-
-
-uint32_t Grid::get_x(uint32_t node){ return node/height; }
-uint32_t Grid::get_y(uint32_t node){ return node%height; }
-uint32_t Grid::get_node(uint32_t x, uint32_t y){ return (x*height)+y; }
-
-
-Grid::Grid(uint32_t x, uint32_t y){ width = x; height = y; }
-
-vector<uint32_t> Grid::get_adj(uint32_t node){
-	set<uint32_t> output;
-	uint32_t node_x = get_x(node);
-	uint32_t node_y = get_y(node);
-
-	output.insert(get_node(node_x, (node_y+1)%height));
-	output.insert(get_node(node_x, (node_y-1+height)%height));
-	output.insert(get_node((node_x+1)%width, node_y));
-	output.insert(get_node((node_x-1+width)%width, node_y));
-
-	return vector<uint32_t>(output.begin(), output.end());
-}
-
-void Grid::print_node(uint32_t node){ cout << "(" << get_x(node) << ", " << get_y(node) << ")"; }
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/build/src/graph.hpp b/build/src/graph.hpp
index 591ec4d..61a0737 100644
--- a/build/src/graph.hpp
+++ b/build/src/graph.hpp
@@ -1,5 +1,10 @@
 #pragma once
-#include <bits/stdc++.h>
+#include <iostream>
+#include <cstdint>
+#include <vector>
+#include <unordered_map>
+#include <unordered_set>
+
 using namespace std;
 
 
@@ -18,21 +23,6 @@ public:
 };
 
 
-class Grid : public Graph{
-private:
-	uint32_t width, height;
-	uint32_t get_x(uint32_t node);
-	uint32_t get_y(uint32_t node);
-	uint32_t get_node(uint32_t x, uint32_t y);
-
-
-public:
-	Grid(uint32_t x, uint32_t y);
-	virtual vector<uint32_t> get_adj(uint32_t node);
-	virtual void print_node(uint32_t node);
-};
-
-
 //Directed/Undirected
 //Weighted/Unweighted
 // enum graph_type {  };
@@ -57,5 +47,8 @@ class adj_matrix : public Graph {
 	uint32_t get_edge(uint32_t head, uint32_t tail);
 	unordered_set<uint32_t> get_edges(uint32_t node_index);
 	unordered_multiset<uint32_t> get_weights(uint32_t edge_index);
+	bool check_coloring(unordered_map<uint32_t,uint32_t> coloring);
+	unordered_map<uint32_t,uint32_t>* k_color(uint32_t k);
+	unordered_map<uint32_t,uint32_t>* minimal_coloring(uint32_t max);
 	void print();
 };
\ No newline at end of file
diff --git a/build/src/main.cpp b/build/src/main.cpp
index f996dcb..83e51ee 100644
--- a/build/src/main.cpp
+++ b/build/src/main.cpp
@@ -1,6 +1,9 @@
 #include "controller.hpp"
 
 
+//TODO: Move main into controller.cpp
+//See controller.cpp for the core functionality of the program and
+//graph.cpp and graph.hpp for the underlying graph structure
 int main(int argc, char* argv[]){
 	QApplication app(argc, argv);
 	QWidget window;
@@ -12,33 +15,5 @@ int main(int argc, char* argv[]){
     window.show();
     return app.exec();
 
-
-
-	// Grid g(5, 5);
-	// vector<uint32_t> temp = g.BFS(0, 12);
-	// // for(int i = 0; i < 4; i++) cout << temp[i] << endl;
-	// cout << "start: ";
-	// g.print_node(0);
-	// cout << endl << "end: ";
-	// g.print_node(12);
-	// cout << endl;
-	// for(auto i : temp){
-	// 	g.print_node(i);
-	// 	cout << endl;
-	// }
-
-	// auto temp = g.IDS(0, 12);
-	// cout << "start: ";
-	// g.print_node(0);
-	// cout << endl << "end: ";
-	// g.print_node(12);
-	// cout << endl;
-	// for(auto i : temp){
-	// 	g.print_node(i);
-	// 	cout << endl;
-	// }
-
 	return 0;
-}
-
-// #include "main.moc"
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/build/src/selected_pane.cpp b/build/src/selected_pane.cpp
index 64336bf..08ec2e8 100644
--- a/build/src/selected_pane.cpp
+++ b/build/src/selected_pane.cpp
@@ -12,7 +12,6 @@ controller::selected_pane::selected_pane(controller* parent) : QWidget(parent){
     sel_label->setFixedSize(200, 25);
 
 
-    //TODO: Soften colors
     auto colors = new vector<tuple<const char*,const string>>({
     	{"R", "#e50000"}, {"O", "#ff8d00"}, {"Y", "#ffee00"}, {"G", "#028121"}, {"B", "#004cff"}, {"P", "#770088"}});
     
-- 
GitLab