[lab2] Structs hierarchy refactoring

This commit is contained in:
Andrew Golovashevich 2026-02-16 01:15:10 +03:00
parent 837dfe9ba0
commit f4f8f43d3e
6 changed files with 88 additions and 53 deletions

View File

@ -2,10 +2,15 @@ use super::BitVector;
use super::operations::attentivenessCheck; use super::operations::attentivenessCheck;
use super::operations::similarityCheck; use super::operations::similarityCheck;
pub struct AdaptiveResonanceTheoryConfig {
pub beta: usize,
pub attentiveness: f64,
}
pub fn adaptiveResonanceTheoryImpl( pub fn adaptiveResonanceTheoryImpl(
data: &[BitVector], data: &[BitVector],
beta: usize, cfg: &AdaptiveResonanceTheoryConfig
attentiveness: f64,
) -> Box<[usize]> { ) -> Box<[usize]> {
let mut prototypes = Vec::<BitVector>::new(); let mut prototypes = Vec::<BitVector>::new();
let mut groups = vec![0usize; data.len()].into_boxed_slice(); let mut groups = vec![0usize; data.len()].into_boxed_slice();
@ -17,10 +22,10 @@ pub fn adaptiveResonanceTheoryImpl(
'elements: for i in 1..data.len() { 'elements: for i in 1..data.len() {
for j in 0..prototypes.len() { for j in 0..prototypes.len() {
if !similarityCheck(&prototypes[j], &data[i], beta) { if !similarityCheck(&prototypes[j], &data[i], cfg.beta) {
continue; continue;
} }
if !attentivenessCheck(&prototypes[j], &data[i], attentiveness) { if !attentivenessCheck(&prototypes[j], &data[i], cfg.attentiveness) {
continue; continue;
} }
groups[i] = j; groups[i] = j;

View File

@ -1,6 +1,6 @@
mod bit_vector; mod bit_vector;
mod operations;
mod r#impl; mod r#impl;
mod operations;
pub use bit_vector::BitVector; pub use bit_vector::BitVector;
pub use r#impl::adaptiveResonanceTheoryImpl; pub use r#impl::{AdaptiveResonanceTheoryConfig, adaptiveResonanceTheoryImpl};

View File

@ -1,12 +1,10 @@
use crate::algo::BitVector; use crate::algo::{AdaptiveResonanceTheoryConfig, BitVector};
use bgtu_ai_utility::{UpdatePending, UpdateTarget}; use bgtu_ai_utility::{UpdatePending, UpdateTarget};
use std::ops::{Index, IndexMut};
pub(crate) struct MyApp { pub(crate) struct MyApp {
pub _isFirstFrame: bool, pub config: AdaptiveResonanceTheoryConfig,
pub bitCount: usize, pub data: VectorsList,
pub beta: usize,
pub attentiveness: f64,
pub data: Vec<BitVector>,
pub result: Option<Box<[usize]>>, pub result: Option<Box<[usize]>>,
pub columnUpdate: UpdatePending, pub columnUpdate: UpdatePending,
pub rowUpdate: UpdatePending, pub rowUpdate: UpdatePending,
@ -15,24 +13,75 @@ pub(crate) struct MyApp {
impl MyApp { impl MyApp {
pub(crate) fn new() -> Self { pub(crate) fn new() -> Self {
return Self { return Self {
_isFirstFrame: true, config: AdaptiveResonanceTheoryConfig {
bitCount: 0, beta: 1,
beta: 1, attentiveness: 0.5,
attentiveness: 0.5, },
data: Vec::new(), data: VectorsList::new(),
result: None, result: None,
columnUpdate: UpdatePending::NoChange, columnUpdate: UpdatePending::NoChange,
rowUpdate: UpdatePending::NoChange, rowUpdate: UpdatePending::NoChange,
}; };
} }
}
pub struct VectorsList {
bitCount: usize,
data: Vec<BitVector>,
}
impl VectorsList {
pub fn new() -> Self {
return Self {
bitCount: 0,
data: Vec::new(),
};
}
pub fn update_columns<'s>(&'s mut self) -> ColumnsUpdateTarget<'s> { pub fn update_columns<'s>(&'s mut self) -> ColumnsUpdateTarget<'s> {
return ColumnsUpdateTarget { data: self }; return ColumnsUpdateTarget { data: self };
} }
pub fn bit_count(&self) -> usize {
return self.bitCount;
}
pub fn as_slice<'s>(&'s self) -> &'s [BitVector] {
return self.data.as_slice();
}
pub fn len<'s>(&self) -> usize {
return self.data.len();
}
} }
struct ColumnsUpdateTarget<'d> { impl Index<usize> for VectorsList {
data: &'d mut MyApp, type Output = BitVector;
fn index(&self, i: usize) -> &Self::Output {
return self.data.index(i);
}
}
impl IndexMut<usize> for VectorsList {
fn index_mut(&mut self, i: usize) -> &mut Self::Output {
return self.data.index_mut(i);
}
}
impl UpdateTarget for VectorsList {
type Elem = ();
fn add(&mut self, value: Self::Elem) {
UpdateTarget::add(&mut self.data, BitVector::alloc(self.bitCount));
}
fn remove(&mut self, index: usize) {
UpdateTarget::remove(&mut self.data, index);
}
}
pub struct ColumnsUpdateTarget<'d> {
data: &'d mut VectorsList,
} }
impl UpdateTarget for ColumnsUpdateTarget<'_> { impl UpdateTarget for ColumnsUpdateTarget<'_> {

View File

@ -7,12 +7,12 @@ use egui_extras::{Column, TableBuilder};
pub(crate) fn input(ui: &mut Ui, data: &mut MyApp) { pub(crate) fn input(ui: &mut Ui, data: &mut MyApp) {
ui.add_enabled_ui(matches!(data.result, None), |ui| { ui.add_enabled_ui(matches!(data.result, None), |ui| {
labeled_slider(ui, "beta", &mut data.beta, 1..=10, 1f64); labeled_slider(ui, "beta", &mut data.config.beta, 1..=10, 1f64);
ui.label(""); ui.label("");
labeled_slider( labeled_slider(
ui, ui,
"attentiveness", "attentiveness",
&mut data.attentiveness, &mut data.config.attentiveness,
0f64..=1f64, 0f64..=1f64,
0.001, 0.001,
); );
@ -34,8 +34,7 @@ pub(crate) fn input(ui: &mut Ui, data: &mut MyApp) {
if ui.button("Classify").clicked() { if ui.button("Classify").clicked() {
data.result = Some(algo::adaptiveResonanceTheoryImpl( data.result = Some(algo::adaptiveResonanceTheoryImpl(
data.data.as_slice(), data.data.as_slice(),
data.beta, &data.config,
data.attentiveness,
)) ))
} }
}); });
@ -58,7 +57,7 @@ fn table(ui: &mut Ui, data: &mut MyApp) {
.resizable(true) .resizable(true)
.column(Column::remainder()) .column(Column::remainder())
.column(Column::remainder()) .column(Column::remainder())
.columns(Column::remainder(), data.bitCount) .columns(Column::remainder(), data.data.bit_count())
.header(20.0, |mut header| { .header(20.0, |mut header| {
header.col(|ui| { header.col(|ui| {
ui.horizontal(|ui| { ui.horizontal(|ui| {
@ -68,7 +67,7 @@ fn table(ui: &mut Ui, data: &mut MyApp) {
header.col(|ui| { header.col(|ui| {
ui.label("Group"); ui.label("Group");
}); });
for i in 0..data.bitCount { for i in 0..data.data.bit_count() {
header.col(|ui| { header.col(|ui| {
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.label(i.to_string()); ui.label(i.to_string());
@ -86,9 +85,11 @@ fn table(ui: &mut Ui, data: &mut MyApp) {
let i = row.index(); let i = row.index();
row.col(|ui| { row.col(|ui| {
ui.horizontal(|ui| { ui.horizontal(|ui| {
if ui.button("-").clicked() { ui.add_enabled_ui(matches!(data.result, None), |ui| {
data.rowUpdate = UpdatePending::Remove(i); if ui.button("-").clicked() {
} data.rowUpdate = UpdatePending::Remove(i);
}
});
ui.label(i.to_string()); ui.label(i.to_string());
}); });
}); });
@ -99,7 +100,7 @@ fn table(ui: &mut Ui, data: &mut MyApp) {
ui.label("?"); ui.label("?");
} }
}); });
for j in 0..data.bitCount { for j in 0..data.data.bit_count() {
row.col(|ui| { row.col(|ui| {
ui.add_enabled_ui(matches!(data.result, None), |ui| { ui.add_enabled_ui(matches!(data.result, None), |ui| {
ui.checkbox(&mut data.data[i][j], ""); ui.checkbox(&mut data.data[i][j], "");

View File

@ -11,18 +11,16 @@ fn main() -> eframe::Result {
return boot_eframe(|| gui::MyApp::new()); return boot_eframe(|| gui::MyApp::new());
} }
impl eframe::App for gui::MyApp { impl eframe::App for gui::MyApp {
fn update(&mut self, ui: &eframe::egui::Context, _frame: &mut eframe::Frame) { fn update(&mut self, ui: &eframe::egui::Context, _frame: &mut eframe::Frame) {
self.columnUpdate.apply( self.columnUpdate.apply_and_clear(
&mut self.update_columns(), &mut self.data.update_columns(),
|| false || false
); );
self.rowUpdate.apply_and_clear( self.rowUpdate.apply_and_clear(
&mut self.data, &mut self.data,
|| BitVector::alloc(self.bitCount) || ()
); );
egui::CentralPanel::default().show(ui, |ui| { egui::CentralPanel::default().show(ui, |ui| {

View File

@ -25,24 +25,6 @@ impl UpdatePending {
} }
*self = UpdatePending::NoChange; *self = UpdatePending::NoChange;
} }
pub fn apply_many<'c, C: UpdateTarget + 'c>(
&self,
it: impl Iterator<Item = &'c mut C>,
constructor: impl Fn() -> C::Elem,
) {
for e in it {
self.apply(e, || constructor())
}
}
pub fn apply_many_and_clear<'c, C: UpdateTarget + 'c>(
&mut self,
it: impl Iterator<Item = &'c mut C>,
constructor: impl Fn() -> C::Elem,
) {
self.apply_many(it, constructor);
*self = UpdatePending::NoChange;
}
} }
pub trait UpdateTarget { pub trait UpdateTarget {