diff --git a/.idea/workspace (conflicted copy 2024-11-04 192927).xml b/.idea/workspace (conflicted copy 2024-11-04 192927).xml
deleted file mode 100644
index 99fca5a..0000000
--- a/.idea/workspace (conflicted copy 2024-11-04 192927).xml
+++ /dev/null
@@ -1,164 +0,0 @@
-
-
-
-
-
- {
- "useNewFormat": true
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {
- "associatedIndex": 7
-}
-
-
-
-
-
- {
- "keyToString": {
- "CMake Application.COSC-4P80-Assignment-3.executor": "Run",
- "NIXITCH_NIXPKGS_CONFIG": "/etc/nix/nixpkgs-config.nix",
- "NIXITCH_NIX_CONF_DIR": "",
- "NIXITCH_NIX_OTHER_STORES": "",
- "NIXITCH_NIX_PATH": "/home/brett/.nix-defexpr/channels:nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos:nixos-config=/etc/nixos/configuration.nix:/nix/var/nix/profiles/per-user/root/channels",
- "NIXITCH_NIX_PROFILES": "/run/current-system/sw /nix/var/nix/profiles/default /etc/profiles/per-user/brett /home/brett/.local/state/nix/profile /nix/profile /home/brett/.nix-profile",
- "NIXITCH_NIX_REMOTE": "",
- "NIXITCH_NIX_USER_PROFILE_DIR": "/nix/var/nix/profiles/per-user/brett",
- "RunOnceActivity.ShowReadmeOnStart": "true",
- "RunOnceActivity.cidr.known.project.marker": "true",
- "RunOnceActivity.readMode.enableVisualFormatting": "true",
- "cf.first.check.clang-format": "false",
- "cidr.known.project.marker": "true",
- "git-widget-placeholder": "main",
- "last_opened_file_path": "/home/brett/Documents/Brock/CS 4P80/COSC-4P80-Assignment-3",
- "node.js.detected.package.eslint": "true",
- "node.js.detected.package.tslint": "true",
- "node.js.selected.package.eslint": "(autodetect)",
- "node.js.selected.package.tslint": "(autodetect)",
- "nodejs_package_manager_path": "npm",
- "settings.editor.selected.configurable": "CMakeSettings",
- "vue.rearranger.settings.migration": "true"
- }
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1730483030448
-
-
- 1730483030448
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5c94a9d..1363d70 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.25)
-project(COSC-4P80-Assignment-3 VERSION 0.0.5)
+project(COSC-4P80-Assignment-3 VERSION 0.0.6)
option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF)
option(ENABLE_UBSAN "Enable the ub sanitizer" OFF)
diff --git a/commit.py b/commit.py
old mode 100644
new mode 100755
diff --git a/include/assign3/array.h b/include/assign3/array.h
new file mode 100644
index 0000000..a19d0d0
--- /dev/null
+++ b/include/assign3/array.h
@@ -0,0 +1,70 @@
+#pragma once
+/*
+ * Copyright (C) 2024 Brett Terpstra
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef COSC_4P80_ASSIGNMENT_3_ARRAY_H
+#define COSC_4P80_ASSIGNMENT_3_ARRAY_H
+
+#include
+#include
+
+namespace assign3
+{
+
+ class array_t
+ {
+ public:
+ explicit array_t(blt::size_t dimensions, blt::size_t width, blt::size_t height):
+ width(static_cast(width)), height(static_cast(height))
+ {
+ for (blt::size_t i = 0; i < width; i++)
+ for (blt::size_t j = 0; j < height; j++)
+ map.emplace_back(dimensions, i, j);
+ }
+
+ inline neuron_t& get(blt::size_t x, blt::size_t y)
+ { return map[y * width + x]; }
+
+ [[nodiscard]] inline const neuron_t& get(blt::size_t x, blt::size_t y) const
+ { return map[y * width + x]; }
+
+ [[nodiscard]] inline blt::size_t get_width() const
+ { return width; }
+
+ [[nodiscard]] inline blt::size_t get_height() const
+ { return height; }
+
+ [[nodiscard]] inline std::vector& get_map()
+ { return map; }
+
+ [[nodiscard]] inline const std::vector& get_map() const
+ { return map; }
+
+ private:
+ [[nodiscard]] inline blt::i64 wrap_width(blt::i64 x) const;
+
+ [[nodiscard]] inline blt::i64 wrap_height(blt::i64 y) const;
+
+ private:
+ blt::i64 width, height;
+ std::vector map;
+ };
+
+
+}
+
+#endif //COSC_4P80_ASSIGNMENT_3_ARRAY_H
diff --git a/include/assign3/functions.h b/include/assign3/functions.h
index 5848935..5fe6327 100644
--- a/include/assign3/functions.h
+++ b/include/assign3/functions.h
@@ -26,6 +26,11 @@ namespace assign3
struct topology_function_t
{
+ /**
+ * @param dist input - usually the distance
+ * @param r time ratio - t / max_t
+ * @return basis results
+ */
[[nodiscard]] virtual Scalar call(Scalar dist, Scalar r) const = 0;
};
diff --git a/include/assign3/fwdecl.h b/include/assign3/fwdecl.h
index 7025d45..978d602 100644
--- a/include/assign3/fwdecl.h
+++ b/include/assign3/fwdecl.h
@@ -22,6 +22,11 @@
namespace assign3
{
using Scalar = float;
+
+ enum class shape
+ {
+ GRID, HONEYCOMB
+ };
}
#endif //COSC_4P80_ASSIGNMENT_3_FWDECL_H
diff --git a/include/assign3/neuron.h b/include/assign3/neuron.h
index c14db39..54f4812 100644
--- a/include/assign3/neuron.h
+++ b/include/assign3/neuron.h
@@ -36,9 +36,11 @@ namespace assign3
neuron_t& randomize(blt::size_t seed);
- neuron_t& update(const std::vector& new_data, const topology_function_t* basis_func, Scalar eta, Scalar r);
+ neuron_t& update(const std::vector& new_data, Scalar dist, Scalar eta);
- static Scalar distance(const neuron_t& n1, const neuron_t& n2, Scalar time_ratio);
+ static Scalar distance(const neuron_t& n1, const neuron_t& n2);
+
+ [[nodiscard]] Scalar dist(const std::vector& X) const;
[[nodiscard]] inline const std::vector& get_data() const
{ return data; }
@@ -48,9 +50,8 @@ namespace assign3
[[nodiscard]] inline Scalar get_y() const
{ return y_pos; }
- private:
- [[nodiscard]] Scalar dist(const std::vector& X) const;
+ private:
Scalar x_pos, y_pos;
std::vector data;
};
diff --git a/include/assign3/som.h b/include/assign3/som.h
new file mode 100644
index 0000000..70e89a7
--- /dev/null
+++ b/include/assign3/som.h
@@ -0,0 +1,56 @@
+#pragma once
+/*
+ * Copyright (C) 2024 Brett Terpstra
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef COSC_4P80_ASSIGNMENT_3_SOM_H
+#define COSC_4P80_ASSIGNMENT_3_SOM_H
+
+#include
+#include
+#include
+
+namespace assign3
+{
+
+ class som_t
+ {
+ public:
+ som_t(const data_file_t& file, blt::size_t width, blt::size_t height, blt::size_t max_epochs);
+
+ blt::size_t get_closest_neuron(const std::vector& data);
+
+ void train_epoch(Scalar initial_learn_rate, topology_function_t* basis_func);
+
+ [[nodiscard]] const array_t& get_array() const
+ { return array; }
+
+ [[nodiscard]] blt::size_t get_current_epoch() const
+ { return current_epoch; }
+
+ [[nodiscard]] blt::size_t get_max_epochs() const
+ { return max_epochs; }
+
+ private:
+ array_t array;
+ data_file_t file;
+ blt::size_t current_epoch = 0;
+ blt::size_t max_epochs;
+ };
+
+}
+
+#endif //COSC_4P80_ASSIGNMENT_3_SOM_H
diff --git a/src/array.cpp b/src/array.cpp
new file mode 100644
index 0000000..75559dc
--- /dev/null
+++ b/src/array.cpp
@@ -0,0 +1,43 @@
+/*
+ *
+ * Copyright (C) 2024 Brett Terpstra
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include
+#include
+
+namespace assign3
+{
+
+ blt::i64 array_t::wrap_height(blt::i64 y) const
+ {
+ if (y >= height)
+ return y - height;
+ else if (y < 0)
+ return height + y;
+ else
+ return y;
+ }
+
+ blt::i64 array_t::wrap_width(blt::i64 x) const
+ {
+ if (x >= width)
+ return x - width;
+ else if (x < 0)
+ return width + x;
+ else
+ return x;
+ }
+}
\ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
index da971c0..84edc44 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -6,9 +6,13 @@
#include "blt/gfx/renderer/batch_2d_renderer.h"
#include "blt/gfx/renderer/camera.h"
#include
+#include
#include
-std::vector files;
+using namespace assign3;
+
+std::vector files;
+std::unique_ptr som;
blt::gfx::matrix_state_manager global_matrices;
blt::gfx::resource_manager resources;
@@ -23,16 +27,39 @@ void init(const blt::gfx::window_data&)
global_matrices.create_internals();
resources.load_resources();
renderer_2d.create();
+
+ blt::size_t size = 5;
+ som = std::make_unique(
+ *std::find_if(files.begin(), files.end(), [](const data_file_t& v) { return v.data_points.begin()->bins.size() == 32; }),
+ size, size, 100);
}
void update(const blt::gfx::window_data& data)
{
+ using namespace blt::gfx;
global_matrices.update_perspectives(data.width, data.height, 90, 0.1, 2000);
camera.update();
camera.update_view(global_matrices);
global_matrices.update();
+ if (ImGui::Begin("Controls"))
+ {
+ ImGui::Button("Run Epoch");
+ if (ImGui::IsItemClicked())
+ {
+ static gaussian_function_t func;
+ som->train_epoch(0.1, &func);
+ }
+ }
+ ImGui::End();
+
+ for (auto& v : som->get_array().get_map())
+ {
+ float scale = 35;
+ renderer_2d.drawPointInternal(blt::make_color(1, 0, 0), point2d_t{v.get_x() * scale + scale, v.get_y() * scale + scale, scale});
+ }
+
renderer_2d.render(data.width, data.height);
}
diff --git a/src/neuron.cpp b/src/neuron.cpp
index 9de8933..8d264cb 100644
--- a/src/neuron.cpp
+++ b/src/neuron.cpp
@@ -32,11 +32,17 @@ namespace assign3
return *this;
}
- neuron_t& neuron_t::update(const std::vector& new_data, const topology_function_t* basis_func, Scalar eta, Scalar r)
+ neuron_t& neuron_t::update(const std::vector& new_data, Scalar dist, Scalar eta)
{
- auto d = dist(new_data);
- for (auto& v : data)
- v = eta * basis_func->call(d, r);
+ static thread_local std::vector diff;
+ diff.clear();
+
+ for (auto [x, v] : blt::in_pairs(new_data, data))
+ diff.push_back(v - x);
+
+ for (auto [v, d] : blt::in_pairs(data, diff))
+ v += eta * dist * d;
+
return *this;
}
@@ -51,10 +57,10 @@ namespace assign3
return std::sqrt(dist);
}
- Scalar neuron_t::distance(const neuron_t& n1, const neuron_t& n2, Scalar time_ratio)
+ Scalar neuron_t::distance(const neuron_t& n1, const neuron_t& n2)
{
- auto dist = n1.dist(n2.data);
- auto dist_sq = dist * dist;
- return std::exp(-time_ratio * dist_sq);
+ auto dx = n1.get_x() - n2.get_x();
+ auto dy = n1.get_y() - n2.get_y();
+ return std::sqrt(dx * dx + dy * dy);
}
}
\ No newline at end of file
diff --git a/src/som.cpp b/src/som.cpp
new file mode 100644
index 0000000..f14044a
--- /dev/null
+++ b/src/som.cpp
@@ -0,0 +1,79 @@
+/*
+ *
+ * Copyright (C) 2024 Brett Terpstra
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include
+#include
+#include
+#include
+#include
+
+namespace assign3
+{
+
+ som_t::som_t(const data_file_t& file, blt::size_t width, blt::size_t height, blt::size_t max_epochs):
+ array(file.data_points.begin()->bins.size(), width, height), file(file), max_epochs(max_epochs)
+ {
+ for (auto& v : array.get_map())
+ v.randomize(std::random_device{}());
+ }
+
+ void som_t::train_epoch(Scalar initial_learn_rate, topology_function_t* basis_func)
+ {
+ blt::random::random_t rand{std::random_device{}()};
+ std::shuffle(file.data_points.begin(), file.data_points.end(), rand);
+
+ auto time_ratio = static_cast(current_epoch) / static_cast(max_epochs);
+ auto eta = initial_learn_rate * std::exp(-2 * time_ratio);
+
+ for (auto& current_data : file.data_points)
+ {
+ auto v0_idx = get_closest_neuron(current_data.bins);
+ auto v0 = array.get_map()[v0_idx];
+ v0.update(current_data.bins, 1, eta);
+
+ for (auto [i, n] : blt::enumerate(array.get_map()))
+ {
+ if (i == v0_idx)
+ continue;
+ auto dist = basis_func->call(neuron_t::distance(v0, n), time_ratio);
+ n.update(current_data.bins, dist, eta);
+ }
+ }
+
+ current_epoch++;
+ }
+
+ blt::size_t som_t::get_closest_neuron(const std::vector& data)
+ {
+ blt::size_t index = 0;
+ Scalar distance = std::numeric_limits::max();
+
+ for (auto [i, d] : blt::enumerate(array.get_map()))
+ {
+ auto dist = d.dist(data);
+ if (dist < distance)
+ {
+ index = i;
+ distance = dist;
+ }
+ }
+
+ return index;
+ }
+
+
+}
\ No newline at end of file