about to start convert

main
Brett 2024-11-18 19:50:46 -05:00
parent f84919ccb5
commit 73da5ff006
12 changed files with 581 additions and 94 deletions

View File

@ -0,0 +1,222 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AnalysisUIOptions">
<option name="ANALYZE_INJECTED_CODE" value="false" />
<option name="SCOPE_TYPE" value="3" />
</component>
<component name="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="BackendCodeEditorMiscSettings">
<option name="/Default/RiderDebugger/RiderRestoreDecompile/RestoreDecompileSetting/@EntryValue" value="false" type="bool" />
<option name="/Default/Housekeeping/GlobalSettingsUpgraded/IsUpgraded/@EntryValue" value="true" type="bool" />
<option name="/Default/Housekeeping/FeatureSuggestion/FeatureSuggestionManager/DisabledSuggesters/=SwitchToGoToActionSuggester/@EntryIndexedValue" value="true" type="bool" />
<option name="/Default/Housekeeping/FeatureSuggestion/FeatureSuggestionManager/DisabledSuggesters/=SwitchToGoToActionSuggester/@EntryIndexRemoved" />
<option name="/Default/Environment/Hierarchy/GeneratedFilesCacheKey/Timestamp/@EntryValue" value="14" type="long" />
<option name="/Default/Housekeeping/OptionsDialog/SelectedPageId/@EntryValue" value="CppFormatterOtherPage" type="string" />
</component>
<component name="CMakePresetLoader">{
&quot;useNewFormat&quot;: true
}</component>
<component name="CMakeProjectFlavorService">
<option name="flavorId" value="CMakePlainProjectFlavor" />
</component>
<component name="CMakeReloadState">
<option name="reloaded" value="true" />
</component>
<component name="CMakeRunConfigurationManager">
<generated>
<config projectName="COSC-4P80-Assignment-3" targetName="BLT_WITH_GRAPHICS" />
<config projectName="COSC-4P80-Assignment-3" targetName="freetype" />
<config projectName="COSC-4P80-Assignment-3" targetName="BLT" />
<config projectName="COSC-4P80-Assignment-3" targetName="COSC-4P80-Assignment-3" />
</generated>
</component>
<component name="CMakeSettings">
<configurations>
<configuration PROFILE_NAME="Debug" ENABLED="true" CONFIG_NAME="Debug" />
<configuration PROFILE_NAME="Release" ENABLED="true" CONFIG_NAME="Release" />
<configuration PROFILE_NAME="RelWithDebInfo" ENABLED="true" CONFIG_NAME="RelWithDebInfo" />
<configuration PROFILE_NAME="RelWithDebInfo Addrsan" ENABLED="true" CONFIG_NAME="RelWithDebInfo" GENERATION_OPTIONS="-DENABLE_ADDRSAN=ON -DENABLE_UBSAN=ON" />
<configuration PROFILE_NAME="RelWithDebInfo ubsan" ENABLED="true" CONFIG_NAME="RelWithDebInfo" GENERATION_OPTIONS="-DENABLE_UBSAN=ON" />
<configuration PROFILE_NAME="Debug Addrsan" ENABLED="true" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DENABLE_ADDRSAN=ON" />
</configurations>
</component>
<component name="ChangeListManager">
<list default="true" id="df4fb81f-8c9e-43af-9712-6ff8baeb587a" name="Changes" comment="">
<change beforePath="$PROJECT_DIR$/lib/blt-with-graphics" beforeDir="false" afterPath="$PROJECT_DIR$/lib/blt-with-graphics" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/blt-with-graphics/libraries/BLT" beforeDir="false" afterPath="$PROJECT_DIR$/lib/blt-with-graphics/libraries/BLT" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/blt-with-graphics/libraries/BLT/libraries/parallel-hashmap" beforeDir="false" afterPath="$PROJECT_DIR$/lib/blt-with-graphics/libraries/BLT/libraries/parallel-hashmap" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/blt-with-graphics/libraries/BLT/libraries/parallel-hashmap/examples/llil_utils/gen-llil.pl" beforeDir="false" afterPath="$PROJECT_DIR$/lib/blt-with-graphics/libraries/BLT/libraries/parallel-hashmap/examples/llil_utils/gen-llil.pl" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/blt-with-graphics/libraries/BLT/libraries/parallel-hashmap/examples/llil_utils/gen_files" beforeDir="false" afterPath="$PROJECT_DIR$/lib/blt-with-graphics/libraries/BLT/libraries/parallel-hashmap/examples/llil_utils/gen_files" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/blt-with-graphics/libraries/BLT/libraries/parallel-hashmap/examples/llil_utils/run_llil4map" beforeDir="false" afterPath="$PROJECT_DIR$/lib/blt-with-graphics/libraries/BLT/libraries/parallel-hashmap/examples/llil_utils/run_llil4map" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/blt-with-graphics/libraries/BLT/libraries/parallel-hashmap/phmap_lldb.py" beforeDir="false" afterPath="$PROJECT_DIR$/lib/blt-with-graphics/libraries/BLT/libraries/parallel-hashmap/phmap_lldb.py" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="ClangdSettings">
<option name="formatViaClangd" value="false" />
<option name="indexerUseModules" value="false" />
</component>
<component name="ExecutionTargetManager" SELECTED_TARGET="CMakeBuildProfile:RelWithDebInfo" />
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="HighlightingSettingsPerFile">
<setting file="file://$PROJECT_DIR$/include/assign3/array.h" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/include/assign3/file.h" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/include/assign3/functions.h" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/include/assign3/neuron.h" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/include/assign3/som.h" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/include/assign3/ui.h" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/lib/blt-with-graphics/include/blt/gfx/font/font_awesome_defines.h" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/lib/blt-with-graphics/include/blt/gfx/renderer/font_renderer.h" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/lib/blt-with-graphics/libraries/BLT/include/blt/std/ranges.h" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/src/array.cpp" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/src/file.cpp" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/src/functions.cpp" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/src/main.cpp" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/src/neuron.cpp" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/src/som.cpp" root0="FORCE_HIGHLIGHTING" />
</component>
<component name="ProblemsViewState">
<option name="selectedTabId" value="CurrentFile" />
</component>
<component name="ProjectApplicationVersion">
<option name="ide" value="CLion" />
<option name="majorVersion" value="2024" />
<option name="minorVersion" value="1.3" />
<option name="productBranch" value="Classic" />
</component>
<component name="ProjectColorInfo">{
&quot;associatedIndex&quot;: 7
}</component>
<component name="ProjectId" id="2oG5NNX4GedKhxLJDuzQ5OR5kr5" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">{
&quot;keyToString&quot;: {
&quot;CMake Application.COSC-4P80-Assignment-3.executor&quot;: &quot;Run&quot;,
&quot;NIXITCH_NIXPKGS_CONFIG&quot;: &quot;/etc/nix/nixpkgs-config.nix&quot;,
&quot;NIXITCH_NIX_CONF_DIR&quot;: &quot;&quot;,
&quot;NIXITCH_NIX_OTHER_STORES&quot;: &quot;&quot;,
&quot;NIXITCH_NIX_PATH&quot;: &quot;/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&quot;,
&quot;NIXITCH_NIX_PROFILES&quot;: &quot;/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&quot;,
&quot;NIXITCH_NIX_REMOTE&quot;: &quot;&quot;,
&quot;NIXITCH_NIX_USER_PROFILE_DIR&quot;: &quot;/nix/var/nix/profiles/per-user/brett&quot;,
&quot;RunOnceActivity.RadMigrateCodeStyle&quot;: &quot;true&quot;,
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
&quot;RunOnceActivity.cidr.known.project.marker&quot;: &quot;true&quot;,
&quot;RunOnceActivity.readMode.enableVisualFormatting&quot;: &quot;true&quot;,
&quot;SHARE_PROJECT_CONFIGURATION_FILES&quot;: &quot;true&quot;,
&quot;cf.advertisement.text.has.clang-format&quot;: &quot;true&quot;,
&quot;cf.first.check.clang-format&quot;: &quot;false&quot;,
&quot;cidr.known.project.marker&quot;: &quot;true&quot;,
&quot;git-widget-placeholder&quot;: &quot;main&quot;,
&quot;last_opened_file_path&quot;: &quot;/home/brett/Documents/Brock/CS 4P80/COSC-4P80-Assignment-3&quot;,
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
&quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
&quot;run.code.analysis.last.selected.profile&quot;: &quot;pProject Default&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;preferences.sourceCode.C/C++&quot;,
&quot;structure.view.defaults.are.configured&quot;: &quot;true&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
}
}</component>
<component name="RecentsManager">
<key name="MoveFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/lib/blt-with-graphics/include/blt/gfx/font" />
</key>
</component>
<component name="RunManager" selected="CMake Application.COSC-4P80-Assignment-3">
<configuration name="BLT" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="COSC-4P80-Assignment-3" TARGET_NAME="BLT" CONFIG_NAME="Debug">
<method v="2">
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
</method>
</configuration>
<configuration name="BLT_WITH_GRAPHICS" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="COSC-4P80-Assignment-3" TARGET_NAME="BLT_WITH_GRAPHICS" CONFIG_NAME="Debug">
<method v="2">
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
</method>
</configuration>
<configuration name="COSC-4P80-Assignment-3" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="COSC-4P80-Assignment-3" TARGET_NAME="COSC-4P80-Assignment-3" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="COSC-4P80-Assignment-3" RUN_TARGET_NAME="COSC-4P80-Assignment-3">
<method v="2">
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
</method>
</configuration>
<configuration name="freetype" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="COSC-4P80-Assignment-3" TARGET_NAME="freetype" CONFIG_NAME="Debug">
<method v="2">
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
</method>
</configuration>
<configuration name="msdfgen-core" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="COSC-4P80-Assignment-3" TARGET_NAME="msdfgen-core" CONFIG_NAME="Debug">
<method v="2">
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
</method>
</configuration>
<list>
<item itemvalue="CMake Application.BLT_WITH_GRAPHICS" />
<item itemvalue="CMake Application.BLT" />
<item itemvalue="CMake Application.COSC-4P80-Assignment-3" />
<item itemvalue="CMake Application.freetype" />
<item itemvalue="CMake Application.msdfgen-core" />
</list>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="df4fb81f-8c9e-43af-9712-6ff8baeb587a" name="Changes" comment="" />
<created>1730483030448</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1730483030448</updated>
<workItem from="1730483031471" duration="57000" />
<workItem from="1730483139508" duration="22719000" />
<workItem from="1730760265254" duration="6300000" />
<workItem from="1730932443628" duration="1866000" />
<workItem from="1731098529771" duration="11456000" />
<workItem from="1731298352794" duration="46000" />
<workItem from="1731298462144" duration="20154000" />
<workItem from="1731370094158" duration="776000" />
<workItem from="1731430940789" duration="18816000" />
<workItem from="1731607891598" duration="688000" />
<workItem from="1731608714255" duration="241000" />
<workItem from="1731609005148" duration="269000" />
<workItem from="1731609278663" duration="148000" />
<workItem from="1731609433368" duration="774000" />
<workItem from="1731610215063" duration="10825000" />
<workItem from="1731969052837" duration="4000" />
</task>
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
<component name="VCPKGProject">
<isAutomaticCheckingOnLaunch value="false" />
<isAutomaticFoundErrors value="true" />
<isAutomaticReloadCMake value="true" />
</component>
<component name="Vcs.Log.Tabs.Properties">
<option name="TAB_STATES">
<map>
<entry key="MAIN">
<value>
<State />
</value>
</entry>
</map>
</option>
</component>
<component name="XSLT-Support.FileAssociations.UIState">
<expand />
<select />
</component>
</project>

View File

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.25) cmake_minimum_required(VERSION 3.25)
project(COSC-4P80-Assignment-3 VERSION 0.0.20) project(COSC-4P80-Assignment-3 VERSION 0.0.21)
include(FetchContent) include(FetchContent)
option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF) option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF)

0
build_emscripten.sh Executable file → Normal file
View File

View File

@ -44,8 +44,8 @@ namespace assign3
case shape_t::GRID_OFFSET_WRAP: case shape_t::GRID_OFFSET_WRAP:
for (blt::size_t j = 0; j < height; j++) for (blt::size_t j = 0; j < height; j++)
for (blt::size_t i = 0; i < width; i++) for (blt::size_t i = 0; i < width; i++)
map.emplace_back(dimensions, (j % 2 == 0 ? static_cast<Scalar>(i) : static_cast<Scalar>(i) + 0.5f), map.emplace_back(dimensions, (j % 2 == 0 ? static_cast<Scalar>(i) : static_cast<Scalar>(i) + 0.5f), j);
static_cast<Scalar>(static_cast<double>(j) * (std::sqrt(3) / 2.0))); // static_cast<Scalar>(static_cast<double>(j) * (std::sqrt(3) / 2.0))
break; break;
} }
} }

View File

@ -77,6 +77,23 @@ namespace assign3
blt::i32 width, height; blt::i32 width, height;
}; };
struct axial_distance_function_t : public distance_function_t
{
[[nodiscard]] Scalar distance(blt::span<const Scalar> x, blt::span<const Scalar> y) const final;
};
struct toroidal_axial_distance_function_t : public distance_function_t
{
public:
toroidal_axial_distance_function_t(blt::i32 width, blt::i32 height): width(width), height(height)
{}
[[nodiscard]] Scalar distance(blt::span<const Scalar> x, blt::span<const Scalar> y) const final;
private:
blt::i32 width, height;
};
} }
#endif //COSC_4P80_ASSIGNMENT_3_FUNCTIONS_H #endif //COSC_4P80_ASSIGNMENT_3_FUNCTIONS_H

View File

@ -82,10 +82,6 @@ namespace assign3
void cleanup(); void cleanup();
std::vector<float> get_neuron_activations(const data_file_t& file);
static std::vector<float> normalize_data(const std::vector<float>& data);
void draw_som(neuron_render_info_t info, const std::function<blt::vec4(render_data_t)>& color_func); void draw_som(neuron_render_info_t info, const std::function<blt::vec4(render_data_t)>& color_func);
void draw_debug(const data_file_t& file); void draw_debug(const data_file_t& file);
@ -97,19 +93,22 @@ namespace assign3
switch (static_cast<shape_t>(selected_som_mode)) switch (static_cast<shape_t>(selected_som_mode))
{ {
case shape_t::GRID: case shape_t::GRID:
case shape_t::GRID_OFFSET:
distance_function = std::make_unique<euclidean_distance_function_t>(); distance_function = std::make_unique<euclidean_distance_function_t>();
break; break;
case shape_t::GRID_OFFSET_WRAP:
case shape_t::GRID_WRAP: case shape_t::GRID_WRAP:
distance_function = std::make_unique<toroidal_euclidean_distance_function_t>(som_width, som_height); distance_function = std::make_unique<toroidal_euclidean_distance_function_t>(som_width, som_height);
break; break;
case shape_t::GRID_OFFSET:
distance_function = std::make_unique<axial_distance_function_t>();
break;
case shape_t::GRID_OFFSET_WRAP:
distance_function = std::make_unique<toroidal_axial_distance_function_t>(som_width, som_height);
break;
} }
error_plotting.clear();
som = std::make_unique<som_t>(motor_data.files[currently_selected_network], som_width, som_height, max_epochs, som = std::make_unique<som_t>(motor_data.files[currently_selected_network], som_width, som_height, max_epochs,
distance_function.get(), static_cast<shape_t>(selected_som_mode), distance_function.get(), topology_function.get(), static_cast<shape_t>(selected_som_mode),
static_cast<init_t>(selected_init_type), normalize_init); static_cast<init_t>(selected_init_type), normalize_init);
error_plotting.push_back(som->topological_error(motor_data.files[currently_selected_network])); som->compute_neuron_activations();
} }
private: private:
@ -118,8 +117,6 @@ namespace assign3
std::unique_ptr<topology_function_t> topology_function; std::unique_ptr<topology_function_t> topology_function;
std::unique_ptr<distance_function_t> distance_function; std::unique_ptr<distance_function_t> distance_function;
std::vector<Scalar> error_plotting;
blt::gfx::font_renderer_t fr2d{}; blt::gfx::font_renderer_t fr2d{};
blt::gfx::batch_renderer_2d br2d; blt::gfx::batch_renderer_2d br2d;

View File

@ -30,17 +30,23 @@ namespace assign3
{ {
public: public:
som_t(const data_file_t& file, blt::size_t width, blt::size_t height, blt::size_t max_epochs, distance_function_t* dist_func, som_t(const data_file_t& file, blt::size_t width, blt::size_t height, blt::size_t max_epochs, distance_function_t* dist_func,
shape_t shape, init_t init, bool normalize); topology_function_t* topology_function, shape_t shape, init_t init, bool normalize);
blt::size_t get_closest_neuron(const std::vector<Scalar>& data); blt::size_t get_closest_neuron(const std::vector<Scalar>& data);
Scalar find_closest_neighbour_distance(blt::size_t v0); Scalar find_closest_neighbour_distance(blt::size_t v0);
void train_epoch(Scalar initial_learn_rate, topology_function_t* basis_func); void train_epoch(Scalar initial_learn_rate);
blt::vec2 get_topological_position(const std::vector<Scalar>& data); blt::vec2 get_topological_position(const std::vector<Scalar>& data);
Scalar topological_error(const data_file_t& data); Scalar topological_error();
void compute_neuron_activations(Scalar distance = 2, Scalar activation = 0.5);
void write_activations(std::ostream& out);
void write_topology_errors(std::ostream& out);
[[nodiscard]] const array_t& get_array() const [[nodiscard]] const array_t& get_array() const
{ return array; } { return array; }
@ -51,12 +57,18 @@ namespace assign3
[[nodiscard]] blt::size_t get_max_epochs() const [[nodiscard]] blt::size_t get_max_epochs() const
{ return max_epochs; } { return max_epochs; }
[[nodiscard]] const std::vector<Scalar>& get_topological_errors() const
{ return topological_errors; }
private: private:
array_t array; array_t array;
data_file_t file; data_file_t file;
blt::size_t current_epoch = 0; blt::size_t current_epoch = 0;
blt::size_t max_epochs; blt::size_t max_epochs;
distance_function_t* dist_func; distance_function_t* dist_func;
topology_function_t* topology_function;
std::vector<Scalar> topological_errors;
}; };
} }

View File

@ -54,4 +54,38 @@ namespace assign3
Scalar y_min = std::min(y_diff, static_cast<Scalar>(height) - y_diff); Scalar y_min = std::min(y_diff, static_cast<Scalar>(height) - y_diff);
return std::sqrt(x_min * x_min + y_min * y_min); return std::sqrt(x_min * x_min + y_min * y_min);
} }
Scalar axial_distance_function_t::distance(blt::span<const Scalar> x, blt::span<const Scalar> y) const
{
static thread_local std::vector<Scalar> distances;
distances.clear();
Scalar total = 0;
for (auto [q, r] : blt::in_pairs(x, y))
{
distances.push_back(std::abs(q - r));
total += distances.back();
}
Scalar min = distances.front();
for (auto v : distances)
min = std::min(min, v);
return total - min;
}
Scalar axial_distance(Scalar q1, Scalar r1, Scalar q2, Scalar r2) {
return (std::abs(q1 - q2) + std::abs(r1 - r2) + std::abs((q1 + r1) - (q2 + r2))) / 2;
}
Scalar toroidal_axial_distance_function_t::distance(blt::span<const Scalar> x, blt::span<const Scalar> y) const
{
BLT_ASSERT(x.size() == 2 && y.size() == 2);
Scalar x_diff = std::abs(x[0] - y[0]);
Scalar y_diff = std::abs(x[1] - y[1]);
Scalar x_min = std::min(x_diff, static_cast<Scalar>(width) - x_diff);
Scalar y_min = std::min(y_diff, static_cast<Scalar>(height) - y_diff);
Scalar total = x_min + y_min;
return total - std::min(x_min, y_min);
}
} }

View File

@ -0,0 +1,125 @@
#include <blt/std/logging.h>
#include <blt/parse/argparse.h>
#include <blt/gfx/window.h>
#include "blt/gfx/renderer/resource_manager.h"
#include "blt/gfx/renderer/camera.h"
#include "implot.h"
#include <assign3/file.h>
#include <assign3/manager.h>
using namespace assign3;
blt::gfx::matrix_state_manager global_matrices;
blt::gfx::resource_manager resources;
blt::gfx::first_person_camera_2d camera;
assign3::motor_data_t data{};
assign3::renderer_t renderer{data, resources, global_matrices};
void init(const blt::gfx::window_data&)
{
using namespace blt::gfx;
BLT_INFO("Hello World!");
global_matrices.create_internals();
resources.load_resources();
renderer.create();
ImPlot::CreateContext();
}
void update(const blt::gfx::window_data& window_data)
{
using namespace blt::gfx;
global_matrices.update_perspectives(window_data.width, window_data.height, 90, 0.1, 2000);
camera.update();
camera.update_view(global_matrices);
global_matrices.update();
renderer.render();
}
void destroy(const blt::gfx::window_data&)
{
global_matrices.cleanup();
resources.cleanup();
renderer.cleanup();
ImPlot::DestroyContext();
blt::gfx::cleanup();
BLT_INFO("Goodbye World!");
}
void load_data_files(const std::string& str)
{
data.files = assign3::data_file_t::load_data_files_from_path(str);
for (auto& v : data.files)
v = v.normalize();
data.update();
}
void action_start_graphics(const std::vector<std::string>& argv_vector)
{
blt::arg_parse parser{};
parser.addArgument(blt::arg_builder{"--file", "-f"}
.setDefault("../data")
.setHelp("Path to data files").build());
auto args = parser.parse_args(argv_vector);
load_data_files(args.get<std::string>("file"));
blt::gfx::init(blt::gfx::window_data{"My Sexy Window", init, update, destroy}.setSyncInterval(1).setMaximized(true));
}
void action_test(const std::vector<std::string>& argv_vector)
{
blt::arg_parse parser{};
parser.addArgument(blt::arg_builder{"--file", "-f"}
.setDefault("../data")
.setHelp("Path to data files").build());
auto args = parser.parse_args(argv_vector);
load_data_files(args.get<std::string>("file"));
}
void action_convert(const std::vector<std::string>& argv_vector)
{
}
int main(int argc, const char** argv)
{
std::vector<std::string> argv_vector;
for (int i = 0; i < argc; i++)
argv_vector.emplace_back(argv[i]);
blt::arg_parse parser{};
parser.addArgument(blt::arg_builder{"action"}
.setAction(blt::arg_action_t::SUBCOMMAND)
.setHelp("Action to run. Can be: [graphics, test, convert]").build());
auto args = parser.parse_args(argv_vector);
if (!args.contains("action"))
{
BLT_ERROR("Please provide an action");
return 0;
}
argv_vector.erase(argv_vector.begin() + 1);
auto action = blt::string::toLowerCase(args.get<std::string>("action"));
if (action == "graphics")
action_start_graphics(argv_vector);
else if (action == "test")
action_test(argv_vector);
else if (action == "convert")
action_convert(argv_vector);
}

View File

@ -49,18 +49,82 @@ void destroy(const blt::gfx::window_data&)
BLT_INFO("Goodbye World!"); BLT_INFO("Goodbye World!");
} }
int main(int argc, const char** argv) void load_data_files(const std::string& str)
{ {
blt::arg_parse parser{}; data.files = assign3::data_file_t::load_data_files_from_path(str);
parser.addArgument(blt::arg_builder{"--file", "-f"}.setDefault("../data").setHelp("Path to data files").build());
auto args = parser.parse_args(argc, argv);
data.files = assign3::data_file_t::load_data_files_from_path(args.get<std::string>("file"));
for (auto& v : data.files) for (auto& v : data.files)
v = v.normalize(); v = v.normalize();
data.update(); data.update();
}
void action_start_graphics(const std::vector<std::string>& argv_vector)
{
blt::arg_parse parser{};
parser.setHelpExtras("graphics");
parser.addArgument(blt::arg_builder{"--file", "-f"}
.setDefault("../data")
.setHelp("Path to data files").build());
auto args = parser.parse_args(argv_vector);
load_data_files(args.get<std::string>("file"));
blt::gfx::init(blt::gfx::window_data{"My Sexy Window", init, update, destroy}.setSyncInterval(1).setMaximized(true)); blt::gfx::init(blt::gfx::window_data{"My Sexy Window", init, update, destroy}.setSyncInterval(1).setMaximized(true));
} }
void action_test(const std::vector<std::string>& argv_vector)
{
blt::arg_parse parser{};
parser.setHelpExtras("test");
parser.addArgument(blt::arg_builder{"--file", "-f"}
.setDefault("../data")
.setHelp("Path to data files").build());
auto args = parser.parse_args(argv_vector);
load_data_files(args.get<std::string>("file"));
}
void action_convert(const std::vector<std::string>& argv_vector)
{
blt::arg_parse parser{};
parser.setHelpExtras("convert");
auto args = parser.parse_args(argv_vector);
}
int main(int argc, const char** argv)
{
std::vector<std::string> argv_vector;
for (int i = 0; i < argc; i++)
argv_vector.emplace_back(argv[i]);
blt::arg_parse parser{};
parser.addArgument(blt::arg_builder{"action"}
.setAction(blt::arg_action_t::SUBCOMMAND)
.setHelp("Action to run. Can be: [graphics, test, convert]").build());
auto args = parser.parse_args(argv_vector);
if (!args.contains("action"))
{
BLT_ERROR("Please provide an action");
return 0;
}
// argv_vector.erase(argv_vector.begin() + 1);
auto action = blt::string::toLowerCase(args.get<std::string>("action"));
if (action == "graphics")
action_start_graphics(argv_vector);
else if (action == "test")
action_test(argv_vector);
else if (action == "convert")
action_convert(argv_vector);
}

View File

@ -123,8 +123,8 @@ namespace assign3
{ {
using namespace blt::gfx; using namespace blt::gfx;
ImGui::ShowDemoWindow(); // ImGui::ShowDemoWindow();
ImPlot::ShowDemoWindow(); // ImPlot::ShowDemoWindow();
if (ImGui::Begin("Controls")) if (ImGui::Begin("Controls"))
{ {
@ -137,7 +137,10 @@ namespace assign3
regenerate_network(); regenerate_network();
if (ImGui::Button("Run Epoch")) if (ImGui::Button("Run Epoch"))
som->train_epoch(initial_learn_rate, topology_function.get()); {
som->train_epoch(initial_learn_rate);
som->compute_neuron_activations();
}
ImGui::Checkbox("Run to completion", &running); ImGui::Checkbox("Run to completion", &running);
ImGui::Text("Epoch %ld / %ld", som->get_current_epoch(), som->get_max_epochs()); ImGui::Text("Epoch %ld / %ld", som->get_current_epoch(), som->get_max_epochs());
} }
@ -152,8 +155,9 @@ namespace assign3
if (ImGui::ListBox("##InitType", &selected_init_type, get_selection_string, init_names.data(), static_cast<int>(init_names.size()))) if (ImGui::ListBox("##InitType", &selected_init_type, get_selection_string, init_names.data(), static_cast<int>(init_names.size())))
regenerate_network(); regenerate_network();
ImGui::TextWrapped("Help: %s", init_helps[selected_init_type].c_str()); ImGui::TextWrapped("Help: %s", init_helps[selected_init_type].c_str());
ImGui::Separator(); if (ImGui::Checkbox("Normalize Init Data", &normalize_init))
ImGui::Checkbox("Normalize Init Data", &normalize_init); regenerate_network();
ImGui::SeparatorText("Som Specifics");
if (ImGui::InputInt("SOM Width", &som_width) || ImGui::InputInt("SOM Height", &som_height) || if (ImGui::InputInt("SOM Width", &som_width) || ImGui::InputInt("SOM Height", &som_height) ||
ImGui::InputInt("Max Epochs", &max_epochs)) ImGui::InputInt("Max Epochs", &max_epochs))
regenerate_network(); regenerate_network();
@ -187,7 +191,11 @@ namespace assign3
static std::vector<std::string> names; static std::vector<std::string> names;
names.clear(); names.clear();
for (blt::size_t i = 0; i < som->get_array().get_map().size(); i++) for (blt::size_t i = 0; i < som->get_array().get_map().size(); i++)
names.push_back("Neuron " + std::to_string(i)); {
auto pos = som->get_array().from_index(i);
names.push_back("Neuron " + std::to_string(i) +
" (" + std::to_string(pos.x()) + ", " + std::to_string(pos.y()) + ")");
}
ImGui::Text("Select Neuron"); ImGui::Text("Select Neuron");
ImGui::ListBox("##SelectNeuron", &selected_neuron, get_selection_string, names.data(), static_cast<int>(names.size())); ImGui::ListBox("##SelectNeuron", &selected_neuron, get_selection_string, names.data(), static_cast<int>(names.size()));
} }
@ -199,14 +207,17 @@ namespace assign3
ImGui::End(); ImGui::End();
auto current_data_file = motor_data.files[currently_selected_network]; auto current_data_file = motor_data.files[currently_selected_network];
auto closest_type = get_neuron_activations(current_data_file);
if (ImGui::Begin("Plots & Data")) if (ImGui::Begin("Plots & Data"))
{ {
ImPlot::SetNextAxesLimits(0, som_width, 0, som_height, ImPlotCond_Always); ImPlot::SetNextAxesLimits(0, som_width, 0, som_height, ImPlotCond_Always);
if (ImPlot::BeginPlot("Activations", ImVec2(-1, 0), ImPlotFlags_NoInputs)) if (ImPlot::BeginPlot("Activations", ImVec2(-1, 0), ImPlotFlags_NoInputs))
{ {
auto rev = rotate90Clockwise(closest_type, som_width, som_height); static std::vector<float> activations;
activations.clear();
for (const auto& n : som->get_array().get_map())
activations.push_back(n.get_activation());
auto rev = rotate90Clockwise(activations, som_width, som_height);
// auto rev = closest_type; // auto rev = closest_type;
// std::reverse(rev.begin(), rev.end()); // std::reverse(rev.begin(), rev.end());
ImPlot::PlotHeatmap("##data_map", rev.data(), som_height, som_width, 0, 0, "%.1f", ImPlotPoint(0, 0), ImPlot::PlotHeatmap("##data_map", rev.data(), som_height, som_width, 0, 0, "%.1f", ImPlotPoint(0, 0),
@ -216,7 +227,7 @@ namespace assign3
ImPlot::SetNextAxesLimits(0, max_epochs, 0, 1, ImPlotCond_Once); ImPlot::SetNextAxesLimits(0, max_epochs, 0, 1, ImPlotCond_Once);
if (ImPlot::BeginPlot("Error")) if (ImPlot::BeginPlot("Error"))
{ {
ImPlot::PlotLine("##error", error_plotting.data(), static_cast<int>(error_plotting.size())); ImPlot::PlotLine("##error", som->get_topological_errors().data(), static_cast<int>(som->get_topological_errors().size()));
ImPlot::EndPlot(); ImPlot::EndPlot();
} }
} }
@ -226,18 +237,17 @@ namespace assign3
{ {
if (som->get_current_epoch() < som->get_max_epochs()) if (som->get_current_epoch() < som->get_max_epochs())
{ {
som->train_epoch(initial_learn_rate, topology_function.get()); som->train_epoch(initial_learn_rate);
error_plotting.push_back(som->topological_error(current_data_file)); som->compute_neuron_activations();
} }
} }
if (!debug_mode) if (!debug_mode)
{ {
closest_type = normalize_data(closest_type);
draw_som(neuron_render_info_t{}.set_base_pos({370, 145}).set_neuron_scale(120).set_neuron_padding({5, 5}), draw_som(neuron_render_info_t{}.set_base_pos({370, 145}).set_neuron_scale(120).set_neuron_padding({5, 5}),
[&closest_type](render_data_t context) { [](render_data_t context) {
auto type = closest_type[context.index]; auto type = context.neuron.get_activation();
return type >= 0 ? blt::make_color(0, type, 0) : blt::make_color(-type, 0, 0); return type >= 0 ? blt::make_color(0, type, 0) : blt::make_color(-type, 0, 0);
}); });
} else } else
@ -247,33 +257,6 @@ namespace assign3
fr2d.render(); fr2d.render();
} }
std::vector<float> renderer_t::get_neuron_activations(const data_file_t& file)
{
static std::vector<float> closest_type;
closest_type.clear();
closest_type.resize(som->get_array().get_map().size());
for (auto [i, v] : blt::enumerate(som->get_array().get_map()))
{
auto half = som->find_closest_neighbour_distance(i) / at_distance_measurement;
// auto sigma = std::sqrt(-(half * half) / (2 * std::log(requested_activation)));
// auto r = 1 / (2 * sigma * sigma);
//
auto scale = topology_function->scale(half, requested_activation);
for (const auto& data : file.data_points)
{
auto ds = topology_function->call(v.dist(data.bins), scale);
if (data.is_bad)
closest_type[i] -= ds;
else
closest_type[i] += ds;
}
}
return closest_type;
}
void renderer_t::draw_debug(const data_file_t& file) void renderer_t::draw_debug(const data_file_t& file)
{ {
switch (static_cast<debug_t>(debug_state)) switch (static_cast<debug_t>(debug_state))
@ -307,9 +290,8 @@ namespace assign3
} }
const auto& data_point = file.data_points[selected_data_point]; const auto& data_point = file.data_points[selected_data_point];
auto closest_type = normalize_data(get_neuron_activations(file));
draw_som(neuron_render_info_t{}.set_base_pos({370, 145}).set_neuron_scale(120).set_neuron_padding({0, 0}), draw_som(neuron_render_info_t{}.set_base_pos({370, 145}).set_neuron_scale(120).set_neuron_padding({0, 0}),
[this, &neuron_positions, &data_point, &closest_type](render_data_t context) { [this, &neuron_positions, &data_point](render_data_t context) {
auto half = som->find_closest_neighbour_distance(context.index) / at_distance_measurement; auto half = som->find_closest_neighbour_distance(context.index) / at_distance_measurement;
auto scale = topology_function->scale(half, requested_activation); auto scale = topology_function->scale(half, requested_activation);
auto ds = topology_function->call(context.neuron.dist(data_point.bins), scale); auto ds = topology_function->call(context.neuron.dist(data_point.bins), scale);
@ -321,7 +303,7 @@ namespace assign3
auto text_height = text.getAssociatedText().getTextHeight(); auto text_height = text.getAssociatedText().getTextHeight();
text.setPosition(context.neuron_padded - blt::vec2{text_width / 2.0f, text_height / 2.0f}).setZIndex(1); text.setPosition(context.neuron_padded - blt::vec2{text_width / 2.0f, text_height / 2.0f}).setZIndex(1);
auto type = closest_type[context.index]; auto type = context.neuron.get_activation();
return type >= 0 ? blt::make_color(0, type, 0) : blt::make_color(-type, 0, 0); return type >= 0 ? blt::make_color(0, type, 0) : blt::make_color(-type, 0, 0);
}); });
@ -334,7 +316,6 @@ namespace assign3
break; break;
case debug_t::DISTANCE: case debug_t::DISTANCE:
{ {
auto closest_type = normalize_data(get_neuron_activations(file));
auto& selected_neuron_ref = som->get_array().get_map()[selected_neuron]; auto& selected_neuron_ref = som->get_array().get_map()[selected_neuron];
static std::vector<Scalar> distances_2d; static std::vector<Scalar> distances_2d;
static std::vector<Scalar> distances_nd; static std::vector<Scalar> distances_nd;
@ -348,7 +329,7 @@ namespace assign3
} }
draw_som(neuron_render_info_t{}.set_base_pos({370, 145}).set_neuron_scale(120).set_neuron_padding({0, 0}), draw_som(neuron_render_info_t{}.set_base_pos({370, 145}).set_neuron_scale(120).set_neuron_padding({0, 0}),
[this, &closest_type](render_data_t context) { [this](render_data_t context) {
auto& text = fr2d.render_text( auto& text = fr2d.render_text(
"2D: " + std::to_string(distances_2d[context.index]) + "\nND: " + "2D: " + std::to_string(distances_2d[context.index]) + "\nND: " +
std::to_string(distances_nd[context.index]), 18).setColor(0.2, 0.2, 0.8); std::to_string(distances_nd[context.index]), 18).setColor(0.2, 0.2, 0.8);
@ -357,24 +338,11 @@ namespace assign3
if (static_cast<blt::size_t>(selected_neuron) == context.index) if (static_cast<blt::size_t>(selected_neuron) == context.index)
return blt::make_color(0, 0, 1); return blt::make_color(0, 0, 1);
auto type = closest_type[context.index]; auto type = context.neuron.get_activation();
return type >= 0 ? blt::make_color(0, type, 0) : blt::make_color(-type, 0, 0); return type >= 0 ? blt::make_color(0, type, 0) : blt::make_color(-type, 0, 0);
}); });
} }
break; break;
} }
} }
std::vector<float> renderer_t::normalize_data(const std::vector<float>& data)
{
std::vector<float> return_data;
auto min_act = *std::min_element(data.begin(), data.end());
auto max_act = *std::max_element(data.begin(), data.end());
for (auto& v : data)
{
auto n = 2 * (v - min_act) / (max_act - min_act) - 1;
return_data.push_back(n);
}
return return_data;
}
} }

View File

@ -27,14 +27,16 @@ namespace assign3
{ {
som_t::som_t(const data_file_t& file, blt::size_t width, blt::size_t height, blt::size_t max_epochs, distance_function_t* dist_func, som_t::som_t(const data_file_t& file, blt::size_t width, blt::size_t height, blt::size_t max_epochs, distance_function_t* dist_func,
shape_t shape, init_t init, bool normalize): topology_function_t* topology_function, shape_t shape, init_t init, bool normalize):
array(file.data_points.begin()->bins.size(), width, height, shape), file(file), max_epochs(max_epochs), dist_func(dist_func) array(file.data_points.begin()->bins.size(), width, height, shape), file(file), max_epochs(max_epochs), dist_func(dist_func),
topology_function(topology_function)
{ {
for (auto& v : array.get_map()) for (auto& v : array.get_map())
v.randomize(std::random_device{}(), init, normalize, file); v.randomize(std::random_device{}(), init, normalize, file);
topological_errors.push_back(topological_error());
} }
void som_t::train_epoch(Scalar initial_learn_rate, topology_function_t* basis_func) void som_t::train_epoch(Scalar initial_learn_rate)
{ {
blt::random::random_t rand{std::random_device{}()}; blt::random::random_t rand{std::random_device{}()};
std::shuffle(file.data_points.begin(), file.data_points.end(), rand); std::shuffle(file.data_points.begin(), file.data_points.end(), rand);
@ -52,18 +54,18 @@ namespace assign3
auto distance_min = find_closest_neighbour_distance(v0_idx); auto distance_min = find_closest_neighbour_distance(v0_idx);
// this will find the required scaling factor to make a point in the middle between v0 and its closest neighbour activate 50% // this will find the required scaling factor to make a point in the middle between v0 and its closest neighbour activate 50%
// from the perspective of the gaussian function // from the perspective of the gaussian function
auto scale = basis_func->scale(distance_min * 0.5f, 0.5); auto scale = topology_function->scale(distance_min * 0.5f, 0.5);
for (auto [i, n] : blt::enumerate(array.get_map())) for (auto [i, n] : blt::enumerate(array.get_map()))
{ {
if (i == v0_idx) if (i == v0_idx)
continue; continue;
auto dist = basis_func->call(neuron_t::distance(dist_func, v0, n), time_ratio * scale); auto dist = topology_function->call(neuron_t::distance(dist_func, v0, n), time_ratio * scale);
n.update(current_data.bins, dist, eta); n.update(current_data.bins, dist, eta);
} }
} }
current_epoch++; current_epoch++;
topological_errors.push_back(topological_error());
} }
blt::size_t som_t::get_closest_neuron(const std::vector<Scalar>& data) blt::size_t som_t::get_closest_neuron(const std::vector<Scalar>& data)
@ -139,12 +141,12 @@ namespace assign3
return (dp1 * p_1) + (dp2 * p_2) + (dp3 * p_3); return (dp1 * p_1) + (dp2 * p_2) + (dp3 * p_3);
} }
Scalar som_t::topological_error(const data_file_t& data) Scalar som_t::topological_error()
{ {
Scalar total = 0; Scalar total = 0;
std::vector<std::pair<blt::size_t, Scalar>> distances; std::vector<std::pair<blt::size_t, Scalar>> distances;
for (const auto& x : data.data_points) for (const auto& x : file.data_points)
{ {
distances.clear(); distances.clear();
for (const auto& [i, n] : blt::enumerate(array.get_map())) for (const auto& [i, n] : blt::enumerate(array.get_map()))
@ -171,7 +173,53 @@ namespace assign3
total += 1; total += 1;
} }
return total / static_cast<Scalar>(data.data_points.size()); return total / static_cast<Scalar>(file.data_points.size());
}
void som_t::compute_neuron_activations(Scalar distance, Scalar activation)
{
for (auto& n : array.get_map())
n.set_activation(0);
Scalar min = std::numeric_limits<Scalar>::max();
Scalar max = std::numeric_limits<Scalar>::min();
for (auto [i, v] : blt::enumerate(array.get_map()))
{
auto half = find_closest_neighbour_distance(i) / distance;
// auto sigma = std::sqrt(-(half * half) / (2 * std::log(requested_activation)));
// auto r = 1 / (2 * sigma * sigma);
//
auto scale = topology_function->scale(half, activation);
for (const auto& data : file.data_points)
{
auto ds = topology_function->call(v.dist(data.bins), scale);
if (data.is_bad)
v.activate(-ds);
else
v.activate(ds);
}
min = std::min(min, v.get_activation());
max = std::max(max, v.get_activation());
}
for (auto& n : array.get_map())
n.set_activation(2 * (n.get_activation() - min) / (max - min) - 1);
}
void som_t::write_activations(std::ostream& out)
{
out << "x,y,activation\n";
for (const auto& v : array.get_map())
out << v.get_x() << ',' << v.get_y() << ',' << v.get_activation() << '\n';
}
void som_t::write_topology_errors(std::ostream& out)
{
out << "epoch,error\n";
for (auto [i, v] : blt::enumerate(topological_errors))
out << i << ',' << v << '\n';
} }