diff --git a/lab2/src/algo/impl.rs b/lab2/src/algo/impl.rs index 95223f9..c19f5db 100644 --- a/lab2/src/algo/impl.rs +++ b/lab2/src/algo/impl.rs @@ -2,10 +2,15 @@ use super::BitVector; use super::operations::attentivenessCheck; use super::operations::similarityCheck; +pub struct AdaptiveResonanceTheoryConfig { + pub beta: usize, + pub attentiveness: f64, +} + + pub fn adaptiveResonanceTheoryImpl( data: &[BitVector], - beta: usize, - attentiveness: f64, + cfg: &AdaptiveResonanceTheoryConfig ) -> Box<[usize]> { let mut prototypes = Vec::::new(); let mut groups = vec![0usize; data.len()].into_boxed_slice(); @@ -17,10 +22,10 @@ pub fn adaptiveResonanceTheoryImpl( 'elements: for i in 1..data.len() { for j in 0..prototypes.len() { - if !similarityCheck(&prototypes[j], &data[i], beta) { + if !similarityCheck(&prototypes[j], &data[i], cfg.beta) { continue; } - if !attentivenessCheck(&prototypes[j], &data[i], attentiveness) { + if !attentivenessCheck(&prototypes[j], &data[i], cfg.attentiveness) { continue; } groups[i] = j; diff --git a/lab2/src/algo/mod.rs b/lab2/src/algo/mod.rs index f1c5fd0..4a43a94 100644 --- a/lab2/src/algo/mod.rs +++ b/lab2/src/algo/mod.rs @@ -1,6 +1,6 @@ mod bit_vector; -mod operations; mod r#impl; +mod operations; pub use bit_vector::BitVector; -pub use r#impl::adaptiveResonanceTheoryImpl; \ No newline at end of file +pub use r#impl::{AdaptiveResonanceTheoryConfig, adaptiveResonanceTheoryImpl}; diff --git a/lab2/src/gui/data.rs b/lab2/src/gui/data.rs index 840b746..c5a7555 100644 --- a/lab2/src/gui/data.rs +++ b/lab2/src/gui/data.rs @@ -1,12 +1,10 @@ -use crate::algo::BitVector; +use crate::algo::{AdaptiveResonanceTheoryConfig, BitVector}; use bgtu_ai_utility::{UpdatePending, UpdateTarget}; +use std::ops::{Index, IndexMut}; pub(crate) struct MyApp { - pub _isFirstFrame: bool, - pub bitCount: usize, - pub beta: usize, - pub attentiveness: f64, - pub data: Vec, + pub config: AdaptiveResonanceTheoryConfig, + pub data: VectorsList, pub result: Option>, pub columnUpdate: UpdatePending, pub rowUpdate: UpdatePending, @@ -15,24 +13,75 @@ pub(crate) struct MyApp { impl MyApp { pub(crate) fn new() -> Self { return Self { - _isFirstFrame: true, - bitCount: 0, - beta: 1, - attentiveness: 0.5, - data: Vec::new(), + config: AdaptiveResonanceTheoryConfig { + beta: 1, + attentiveness: 0.5, + }, + data: VectorsList::new(), result: None, columnUpdate: UpdatePending::NoChange, rowUpdate: UpdatePending::NoChange, }; } +} + +pub struct VectorsList { + bitCount: usize, + data: Vec, +} + +impl VectorsList { + pub fn new() -> Self { + return Self { + bitCount: 0, + data: Vec::new(), + }; + } pub fn update_columns<'s>(&'s mut self) -> ColumnsUpdateTarget<'s> { 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> { - data: &'d mut MyApp, +impl Index for VectorsList { + type Output = BitVector; + + fn index(&self, i: usize) -> &Self::Output { + return self.data.index(i); + } +} + +impl IndexMut 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<'_> { diff --git a/lab2/src/gui/input.rs b/lab2/src/gui/input.rs index 4f34cfc..715b98c 100644 --- a/lab2/src/gui/input.rs +++ b/lab2/src/gui/input.rs @@ -7,12 +7,12 @@ use egui_extras::{Column, TableBuilder}; pub(crate) fn input(ui: &mut Ui, data: &mut MyApp) { 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(""); labeled_slider( ui, "attentiveness", - &mut data.attentiveness, + &mut data.config.attentiveness, 0f64..=1f64, 0.001, ); @@ -34,8 +34,7 @@ pub(crate) fn input(ui: &mut Ui, data: &mut MyApp) { if ui.button("Classify").clicked() { data.result = Some(algo::adaptiveResonanceTheoryImpl( data.data.as_slice(), - data.beta, - data.attentiveness, + &data.config, )) } }); @@ -48,7 +47,7 @@ pub(crate) fn input(ui: &mut Ui, data: &mut MyApp) { }); ui.label(""); - + table(ui, data); } @@ -58,7 +57,7 @@ fn table(ui: &mut Ui, data: &mut MyApp) { .resizable(true) .column(Column::remainder()) .column(Column::remainder()) - .columns(Column::remainder(), data.bitCount) + .columns(Column::remainder(), data.data.bit_count()) .header(20.0, |mut header| { header.col(|ui| { ui.horizontal(|ui| { @@ -68,7 +67,7 @@ fn table(ui: &mut Ui, data: &mut MyApp) { header.col(|ui| { ui.label("Group"); }); - for i in 0..data.bitCount { + for i in 0..data.data.bit_count() { header.col(|ui| { ui.horizontal(|ui| { ui.label(i.to_string()); @@ -86,9 +85,11 @@ fn table(ui: &mut Ui, data: &mut MyApp) { let i = row.index(); row.col(|ui| { ui.horizontal(|ui| { - if ui.button("-").clicked() { - data.rowUpdate = UpdatePending::Remove(i); - } + ui.add_enabled_ui(matches!(data.result, None), |ui| { + if ui.button("-").clicked() { + data.rowUpdate = UpdatePending::Remove(i); + } + }); ui.label(i.to_string()); }); }); @@ -99,7 +100,7 @@ fn table(ui: &mut Ui, data: &mut MyApp) { ui.label("?"); } }); - for j in 0..data.bitCount { + for j in 0..data.data.bit_count() { row.col(|ui| { ui.add_enabled_ui(matches!(data.result, None), |ui| { ui.checkbox(&mut data.data[i][j], ""); diff --git a/lab2/src/main.rs b/lab2/src/main.rs index 8c85d6b..af29832 100644 --- a/lab2/src/main.rs +++ b/lab2/src/main.rs @@ -11,18 +11,16 @@ fn main() -> eframe::Result { return boot_eframe(|| gui::MyApp::new()); } - - impl eframe::App for gui::MyApp { fn update(&mut self, ui: &eframe::egui::Context, _frame: &mut eframe::Frame) { - self.columnUpdate.apply( - &mut self.update_columns(), + self.columnUpdate.apply_and_clear( + &mut self.data.update_columns(), || false ); self.rowUpdate.apply_and_clear( &mut self.data, - || BitVector::alloc(self.bitCount) + || () ); egui::CentralPanel::default().show(ui, |ui| { diff --git a/utility/src/update_pending.rs b/utility/src/update_pending.rs index 830a497..71412b6 100644 --- a/utility/src/update_pending.rs +++ b/utility/src/update_pending.rs @@ -25,24 +25,6 @@ impl UpdatePending { } *self = UpdatePending::NoChange; } - - pub fn apply_many<'c, C: UpdateTarget + 'c>( - &self, - it: impl Iterator, - 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, - constructor: impl Fn() -> C::Elem, - ) { - self.apply_many(it, constructor); - *self = UpdatePending::NoChange; - } } pub trait UpdateTarget {