idk if this is supposed to work so well?

v1
Brett 2024-09-22 16:53:09 -04:00
parent 8f0361df0f
commit fcb28332a5
4 changed files with 167 additions and 85 deletions

View File

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.25) cmake_minimum_required(VERSION 3.25)
project(COSC-4P80-Assignment-1 VERSION 0.0.7) project(COSC-4P80-Assignment-1 VERSION 0.0.8)
option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF) option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF)
option(ENABLE_UBSAN "Enable the ub sanitizer" OFF) option(ENABLE_UBSAN "Enable the ub sanitizer" OFF)

106
include/a1.h Normal file
View File

@ -0,0 +1,106 @@
#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 <https://www.gnu.org/licenses/>.
*/
#ifndef COSC_4P80_ASSIGNMENT_1_A1_H
#define COSC_4P80_ASSIGNMENT_1_A1_H
#include <blt/math/matrix.h>
#include <blt/math/log_util.h>
namespace a1
{
void test_math()
{
blt::generalized_matrix<float, 1, 4> input{1, -1, -1, 1};
blt::generalized_matrix<float, 1, 3> output{1, 1, 1};
blt::generalized_matrix<float, 4, 3> expected{
blt::vec4{1, -1, -1, 1},
blt::vec4{1, -1, -1, 1},
blt::vec4{1, -1, -1, 1}
};
auto w_matrix = input.transpose() * output;
BLT_ASSERT(w_matrix == expected && "MATH MATRIX FAILURE");
blt::vec4 one{5, 1, 3, 0};
blt::vec4 two{9, -5, -8, 3};
blt::generalized_matrix<float, 1, 4> g1{5, 1, 3, 0};
blt::generalized_matrix<float, 1, 4> g2{9, -5, -8, 3};
BLT_ASSERT(g1 * g2.transpose() == blt::vec4::dot(one, two) && "MATH DOT FAILURE");
}
template<typename input_t>
float crosstalk(const input_t& i, const input_t& j)
{
return i * j.transpose();
}
template<typename T, blt::u32 rows, blt::u32 columns>
blt::generalized_matrix<T, rows, columns> threshold(const blt::generalized_matrix<T, rows, columns>& y,
const blt::generalized_matrix<T, rows, columns>& base)
{
blt::generalized_matrix<T, rows, columns> result;
for (blt::u32 i = 0; i < columns; i++)
{
for (blt::u32 j = 0; j < rows; j++)
result[i][j] = y[i][j] > 1 ? 1 : (y[i][j] < -1 ? -1 : base[i][j]);
}
return result;
}
template<typename T, blt::size_t size>
bool equal(const std::array<T, size>& a, const std::array<T, size>& b)
{
for (const auto& [index, val] : blt::enumerate(a))
{
if (b[index] != val)
return false;
}
return true;
}
template<typename weight_t, typename input_t, typename output_t>
std::pair<input_t, output_t> run_step(const weight_t& associated_weights, const input_t& input, const output_t& output)
{
output_t output_recall = input * associated_weights;
input_t input_recall = output * associated_weights.transpose();
return std::pair{a1::threshold(input_recall, input), a1::threshold(output_recall, output)};
}
template<typename weight_t, typename T, typename G, blt::size_t size>
void check_recall(const weight_t& weights, const std::array<G, size>& inputs, const std::array<T, size>& outputs)
{
for (const auto& [index, val] : blt::enumerate(inputs))
{
auto result = run_step(weights, val, outputs[index]);
if (result.first != val)
BLT_ERROR("Recall of input #%ld failed", index + 1);
else
BLT_INFO("Recall of input #%ld passed", index + 1);
if (result.second != outputs[index])
BLT_ERROR("Recall of output #%ld failed", index + 1);
else
BLT_INFO("recall of output #%ld passed", index + 1);
}
}
}
#endif //COSC_4P80_ASSIGNMENT_1_A1_H

View File

@ -1,58 +0,0 @@
#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 <https://www.gnu.org/licenses/>.
*/
#ifndef COSC_4P80_ASSIGNMENT_1_FWD_DECL_H
#define COSC_4P80_ASSIGNMENT_1_FWD_DECL_H
#include <blt/math/matrix.h>
#include <blt/math/log_util.h>
namespace a1
{
void test_math()
{
blt::generalized_matrix<float, 1, 4> input{1, -1, -1, 1};
blt::generalized_matrix<float, 1, 3> output{1, 1, 1};
blt::generalized_matrix<float, 4, 3> expected{
blt::vec4{1, -1, -1, 1},
blt::vec4{1, -1, -1, 1},
blt::vec4{1, -1, -1, 1}
};
auto w_matrix = input.transpose() * output;
BLT_ASSERT(w_matrix == expected && "MATH MATRIX FAILURE");
blt::vec4 one{5, 1, 3, 0};
blt::vec4 two{9, -5, -8, 3};
blt::generalized_matrix<float, 1, 4> g1{5, 1, 3, 0};
blt::generalized_matrix<float, 1, 4> g2{9, -5, -8, 3};
BLT_ASSERT(g1 * g2.transpose() == blt::vec4::dot(one, two) && "MATH DOT FAILURE");
}
enum class recall_error_t
{
// failed to predict input
INPUT_FAILURE,
// failed to predict output
OUTPUT_FAILURE
};
}
#endif //COSC_4P80_ASSIGNMENT_1_FWD_DECL_H

View File

@ -3,7 +3,7 @@
#include <blt/math/log_util.h> #include <blt/math/log_util.h>
#include "blt/std/assert.h" #include "blt/std/assert.h"
#include <blt/format/boxing.h> #include <blt/format/boxing.h>
#include <fwd_decl.h> #include <a1.h>
constexpr blt::u32 num_values = 4; constexpr blt::u32 num_values = 4;
constexpr blt::u32 input_count = 5; constexpr blt::u32 input_count = 5;
@ -14,58 +14,83 @@ using output_t = blt::generalized_matrix<float, 1, output_count>;
using weight_t = decltype(std::declval<input_t>().transpose() * std::declval<output_t>()); using weight_t = decltype(std::declval<input_t>().transpose() * std::declval<output_t>());
using crosstalk_t = blt::generalized_matrix<float, output_count, num_values>; using crosstalk_t = blt::generalized_matrix<float, output_count, num_values>;
float crosstalk(const input_t& i, const input_t& j) // part a
{
return i * j.transpose();
}
input_t input_1{-1, 1, 1, 1, -1}; input_t input_1{-1, 1, 1, 1, -1};
input_t input_2{-1, -1, -1, -1, 1}; input_t input_2{-1, -1, -1, -1, 1};
input_t input_3{-1, -1, -1, 1, 1}; input_t input_3{-1, -1, -1, 1, 1};
// part c 1
input_t input_4{1, 1, 1, 1, 1}; input_t input_4{1, 1, 1, 1, 1};
// part c 2
input_t input_5{-1, 1, -1, 1, 1};
input_t input_6{1, -1, 1, -1, 1};
input_t input_7{-1, 1, -1, 1, -1};
// part a
output_t output_1{1, 1, -1, 1}; output_t output_1{1, 1, -1, 1};
output_t output_2{1, -1, -1, -1}; output_t output_2{1, -1, -1, -1};
output_t output_3{-1, -1, 1, 1}; output_t output_3{-1, -1, 1, 1};
// part c 1
output_t output_4{-1, 1, 1, -1}; output_t output_4{-1, 1, 1, -1};
// part c 2
output_t output_5{1, 1, 1, 1};
output_t output_6{1, -1, -1, 1};
output_t output_7{1, 1, 1, -1};
const weight_t weight_1 = input_1.transpose() * output_1; const weight_t weight_1 = input_1.transpose() * output_1;
const weight_t weight_2 = input_2.transpose() * output_2; const weight_t weight_2 = input_2.transpose() * output_2;
const weight_t weight_3 = input_3.transpose() * output_3; const weight_t weight_3 = input_3.transpose() * output_3;
const weight_t weight_4 = input_4.transpose() * output_4; const weight_t weight_4 = input_4.transpose() * output_4;
const weight_t weight_5 = input_5.transpose() * output_5;
const weight_t weight_6 = input_6.transpose() * output_6;
const weight_t weight_7 = input_7.transpose() * output_7;
auto starting_inputs = std::array{input_1, input_2, input_3, input_4}; auto part_a_inputs = std::array{input_1, input_2, input_3};
auto starting_outputs = std::array{output_1, output_2, output_3, output_4}; auto part_a_outputs = std::array{output_1, output_2, output_3};
auto part_c_1_inputs = std::array{input_1, input_2, input_3, input_4};
auto part_c_1_outputs = std::array{output_1, output_2, output_3, output_4};
auto part_c_2_inputs = std::array{input_1, input_2, input_3, input_4, input_5, input_6, input_7};
auto part_c_2_outputs = std::array{output_1, output_2, output_3, output_4, output_5, output_6, output_7};
const auto weight_total_a = weight_1 + weight_2 + weight_3; const auto weight_total_a = weight_1 + weight_2 + weight_3;
const auto weight_total_c = weight_total_a + weight_4; const auto weight_total_c = weight_total_a + weight_4;
const auto weight_total_c_2 = weight_total_c + weight_5 + weight_6 + weight_7;
crosstalk_t crosstalk_values{}; crosstalk_t crosstalk_values{};
template<typename T, blt::u32 rows, blt::u32 columns> template<typename Weights, typename Inputs, typename Outputs>
blt::generalized_matrix<T, rows, columns> threshold(const blt::generalized_matrix<T, rows, columns>& y, const blt::generalized_matrix<T, rows, columns>& base) void execute_BAM(const Weights& weights, const Inputs& input, const Outputs& output)
{ {
blt::generalized_matrix<T, rows, columns> result; auto current_inputs = input;
for (blt::u32 i = 0; i < columns; i++) auto current_outputs = output;
auto next_inputs = current_inputs;
auto next_outputs = current_outputs;
blt::size_t iterations = 0;
constexpr blt::size_t max_iterations = 5;
do
{ {
for (blt::u32 j = 0; j < rows; j++) current_inputs = next_inputs;
result[i][j] = y[i][j] > 1 ? 1 : (y[i][j] < -1 ? -1 : base[i][j]); current_outputs = next_outputs;
++iterations;
for (const auto& [index, val] : blt::enumerate(current_inputs))
{
auto next = a1::run_step(weights, val, current_outputs[index]);
next_inputs[index] = next.first;
next_outputs[index] = next.second;
} }
return result; } while ((!a1::equal(current_inputs, next_inputs) || !a1::equal(current_outputs, next_outputs)) && iterations < max_iterations);
}
std::pair<input_t, output_t> run_step(const weight_t& associated_weights, const input_t& input, const output_t & output) BLT_DEBUG("Tracked after %ld iterations", iterations);
{ a1::check_recall(weights, next_inputs, next_outputs);
output_t output_recall = input * associated_weights;
input_t input_recall = output * associated_weights.transpose();
return std::pair{threshold(input_recall, input), threshold(output_recall, output)};
} }
void part_a() void part_a()
{ {
blt::log_box_t box(BLT_TRACE_STREAM, "Part A", 8); blt::log_box_t box(BLT_TRACE_STREAM, "Part A", 8);
execute_BAM(weight_total_a, part_a_inputs, part_a_outputs);
} }
void part_b() void part_b()
@ -78,7 +103,7 @@ void part_b()
{ {
if (i == k) if (i == k)
continue; continue;
accum += (outputs[k] * crosstalk(inputs[k].normalize(), inputs[i].normalize())); accum += (part_a_outputs[k] * a1::crosstalk(part_a_inputs[k].normalize(), part_a_inputs[i].normalize()));
} }
crosstalk_values.assign_to_column_from_column_rows(accum, i); crosstalk_values.assign_to_column_from_column_rows(accum, i);
} }
@ -88,11 +113,20 @@ void part_b()
} }
} }
void part_c()
{
blt::log_box_t box(BLT_TRACE_STREAM, "Part C", 8);
execute_BAM(weight_total_c, part_c_1_inputs, part_c_1_outputs);
BLT_TRACE("--- { Part C with 3 extra pairs } ---");
execute_BAM(weight_total_c_2, part_c_2_inputs, part_c_2_outputs);
}
int main() int main()
{ {
blt::logging::setLogOutputFormat("\033[94m[${{TIME}}]${{RC}} \033[35m(${{FILE}}:${{LINE}})${{RC}} ${{LF}}${{CNR}}${{STR}}${{RC}}\n"); blt::logging::setLogOutputFormat("\033[94m[${{TIME}}]${{RC}} \033[35m(${{FILE}}:${{LINE}})${{RC}} ${{LF}}${{CNR}}${{STR}}${{RC}}\n");
test_math(); a1::test_math();
part_a(); part_a();
part_b(); part_b();
part_c();
} }