Compare commits
5 Commits
const_mut_
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| e4b75957a7 | |||
| dab2d16e38 | |||
| 0e735f4db5 | |||
| 2b601e8d9a | |||
| 2ea5448ae3 |
@ -23,8 +23,9 @@ impl AntsSimulationState<'_> {
|
||||
match weighted_random(rng, &outbound_weights, |e| e.2) {
|
||||
None => {}
|
||||
Some((ei, nvi, _)) => {
|
||||
self.ferments[*ei] += self._calculate_weight(*ei);
|
||||
self.ferments[*ei] += self._calculate_ferment(*ei);
|
||||
ant.current_vertex = *nvi;
|
||||
ant.allowed_vertices.remove(nvi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,15 @@
|
||||
use bgtu_ai_utility::graph::CompleteGraph;
|
||||
use bgtu_ai_utility::UpdatePending;
|
||||
use crate::algo::{AntsSimulationConfig, AntsSimulationState};
|
||||
use bgtu_ai_utility::UpdatePending;
|
||||
use bgtu_ai_utility::graph::CompleteGraph;
|
||||
use std::pin::Pin;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
pub(crate) enum AntsVisualisationData<'cfg> {
|
||||
pub(crate) struct AntsVisualisationData {
|
||||
pub config: AntsSimulationConfig,
|
||||
pub graph: CompleteGraph<()>,
|
||||
}
|
||||
|
||||
pub(crate) enum AntsVisualisationState<'cfg> {
|
||||
Edit {
|
||||
config: &'cfg mut AntsSimulationConfig,
|
||||
graph: &'cfg mut CompleteGraph<()>,
|
||||
@ -15,28 +22,31 @@ pub(crate) enum AntsVisualisationData<'cfg> {
|
||||
vertex_locations: Vec<(f32, f32)>,
|
||||
},
|
||||
}
|
||||
pub(crate) struct MyApp<'cfg> {
|
||||
pub state: AntsVisualisationData<'cfg>,
|
||||
pub ants_per_vertex: usize,
|
||||
|
||||
pub(crate) struct AntsVisualisationApp {
|
||||
pub data: Pin<Box<AntsVisualisationData>>,
|
||||
pub state: AntsVisualisationState<'static /* actually not but fuck rust */>,
|
||||
}
|
||||
|
||||
impl MyApp {
|
||||
pub(crate) fn new() -> Self {
|
||||
return Self {
|
||||
simulation: AntsSimulationState {
|
||||
graph: CompleteGraph::new(),
|
||||
ants: Vec::new(),
|
||||
},
|
||||
vertex_update: UpdatePending::NoChange,
|
||||
impl AntsVisualisationApp {
|
||||
pub fn new() -> Self {
|
||||
let mut data = Box::pin(AntsVisualisationData {
|
||||
config: AntsSimulationConfig {
|
||||
ferment_weight: 0.5,
|
||||
heuristic_coefficient: 0.5,
|
||||
q: 1.0,
|
||||
r: 0.5,
|
||||
},
|
||||
state: AntsVisualisationData::Edit {},
|
||||
vertex_locations: Vec::new(),
|
||||
graph: CompleteGraph::new(),
|
||||
});
|
||||
|
||||
let state = AntsVisualisationState::Edit {
|
||||
config: unsafe { NonNull::from_mut(&mut data.config).as_mut() },
|
||||
graph: unsafe { NonNull::from_mut(&mut data.graph).as_mut() },
|
||||
ants_per_vertex: 1,
|
||||
vertex_update: UpdatePending::NoChange,
|
||||
};
|
||||
|
||||
return Self { data, state };
|
||||
}
|
||||
}
|
||||
@ -1,47 +1,57 @@
|
||||
use super::{AntsVisualisationData, MyApp};
|
||||
use crate::algo::updateState;
|
||||
use crate::algo::AntsSimulationState;
|
||||
use bgtu_ai_utility::gui::render_graph;
|
||||
use eframe::egui::Ui;
|
||||
use rand::{Rng, rng};
|
||||
|
||||
pub(crate) fn graph_with_controls(ui: &mut Ui, data: &mut MyApp) {
|
||||
pub(crate) fn graph_with_controls(
|
||||
ui: &mut Ui,
|
||||
vertex_locations: &mut [(f32, f32)],
|
||||
data: &mut AntsSimulationState,
|
||||
exit: &mut bool,
|
||||
) {
|
||||
ui.vertical(|ui| {
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button("Exit").clicked() {
|
||||
data.state = AntsVisualisationData::Edit
|
||||
*exit = true;
|
||||
}
|
||||
|
||||
if ui.button("Step").clicked() {
|
||||
updateState(&mut data.simulation, &mut data.config, &mut rand::rng());
|
||||
data.update1(&mut rng());
|
||||
}
|
||||
ui.label("");
|
||||
});
|
||||
draw_ants(ui, data);
|
||||
draw_ants(ui, vertex_locations, data);
|
||||
if ui.input(|i| i.viewport().close_requested()) {
|
||||
data.state = AntsVisualisationData::Edit
|
||||
*exit = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn draw_ants(ui: &mut Ui, data: &mut MyApp) {
|
||||
let mut cap: f64 = 0.000000000001;
|
||||
fn draw_ants(ui: &mut Ui, vertex_locations: &mut [(f32, f32)], data: &mut AntsSimulationState) {
|
||||
let mut cap: f64 = data.cfg.q * (data.graph.vertex_count() as f64);
|
||||
|
||||
for w in data
|
||||
.simulation
|
||||
.graph
|
||||
.edges
|
||||
.iter()
|
||||
.map(|e| e.extra.ferment_intensity)
|
||||
{
|
||||
if w > cap {
|
||||
cap = w
|
||||
}
|
||||
}
|
||||
// for w in data.graph.edges.iter_indexes().map(|i| data.ferments[i]) {
|
||||
// if w > cap {
|
||||
// cap = w
|
||||
// }
|
||||
// }
|
||||
|
||||
render_graph(
|
||||
ui,
|
||||
&data.simulation.graph.vertices,
|
||||
data.vertex_locations.as_mut_slice(),
|
||||
&data.simulation.graph.edges,
|
||||
|e| e.extra.ferment_intensity / cap,
|
||||
&data.graph.vertices,
|
||||
vertex_locations,
|
||||
&data.graph.edges,
|
||||
|ei, _| data.ferments[ei] / cap,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn gen_vertex_locations(rng: &mut impl Rng, count: usize) -> Vec<(f32, f32)> {
|
||||
let mut v = Vec::new();
|
||||
for _ in 0..count {
|
||||
v.push((
|
||||
rng.random::<f32>() * 0.8 + 0.1,
|
||||
rng.random::<f32>() * 0.8 + 0.1,
|
||||
));
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
@ -1,23 +1,24 @@
|
||||
use crate::algo::AntsSimulationConfig;
|
||||
use bgtu_ai_utility::UpdatePending;
|
||||
use bgtu_ai_utility::graph::CompleteGraph;
|
||||
use bgtu_ai_utility::gui::const_mut_switch::{_ConstMutSwitchUiCallback, ConstMutSwitchUi, RefType, RefGetter};
|
||||
use bgtu_ai_utility::gui::const_mut_switch::{
|
||||
_ConstMutSwitchUiCallback, ConstMutSwitchUi, MutUI, RefType,
|
||||
};
|
||||
use bgtu_ai_utility::gui::graph_lengths_table::{Graph, draw_lengths_table};
|
||||
|
||||
pub(crate) fn input<Ctx: ConstMutSwitchUi + RefGetter>(
|
||||
pub(crate) fn input<Ctx: ConstMutSwitchUi>(
|
||||
ctx: &mut Ctx,
|
||||
mut config: Ctx::Ref<'_, AntsSimulationConfig>,
|
||||
mut graph: Ctx::RefType::Ref<'_, CompleteGraph<()>>,
|
||||
mut ants_per_vertex: Ctx::RefType::Ref<'_, usize>,
|
||||
mut vertex_update: Ctx::RefType::Ref<'_, UpdatePending>,
|
||||
mut launch: Ctx::RefType::Ref<'_, bool>,
|
||||
mut config: <Ctx::RefType as RefType>::Ref<'_, AntsSimulationConfig>,
|
||||
graph: &mut impl Graph<RefType = Ctx::RefType>,
|
||||
mut ants_per_vertex: <Ctx::RefType as RefType>::Ref<'_, usize>,
|
||||
mut vertex_update: <Ctx::RefType as RefType>::Ref<'_, UpdatePending>,
|
||||
mut launch: <Ctx::RefType as RefType>::Ref<'_, bool>,
|
||||
) {
|
||||
type Ref<'a, T> = <<Ctx as ConstMutSwitchUi>::RefType as RefType>::Ref<'a, T>;
|
||||
|
||||
ctx.labeled_slider(
|
||||
"Ferment weight",
|
||||
0.0..=1.0,
|
||||
0.001,
|
||||
&mut Ctx::_get(
|
||||
&mut Ctx::RefType::_get(
|
||||
&mut config,
|
||||
|config| &config.ferment_weight,
|
||||
|config| &mut config.ferment_weight,
|
||||
@ -30,7 +31,7 @@ pub(crate) fn input<Ctx: ConstMutSwitchUi + RefGetter>(
|
||||
"Heuristic coefficient",
|
||||
0.0..=1.0,
|
||||
0.001,
|
||||
&mut Ctx::_get(
|
||||
&mut Ctx::RefType::_get(
|
||||
&mut config,
|
||||
|config| &config.heuristic_coefficient,
|
||||
|config| &mut config.heuristic_coefficient,
|
||||
@ -43,7 +44,7 @@ pub(crate) fn input<Ctx: ConstMutSwitchUi + RefGetter>(
|
||||
"Q",
|
||||
0.0..=1.0,
|
||||
0.001,
|
||||
&mut Ctx::_get(&mut config, |config| &config.q, |config| &mut config.q),
|
||||
&mut Ctx::RefType::_get(&mut config, |config| &config.q, |config| &mut config.q),
|
||||
);
|
||||
|
||||
ctx.space();
|
||||
@ -52,7 +53,7 @@ pub(crate) fn input<Ctx: ConstMutSwitchUi + RefGetter>(
|
||||
"R",
|
||||
0.0..=1.0,
|
||||
0.001,
|
||||
&mut Ctx::_get(&mut config, |config| &config.r, |config| &mut config.r),
|
||||
&mut Ctx::RefType::_get(&mut config, |config| &config.r, |config| &mut config.r),
|
||||
);
|
||||
|
||||
ctx.space();
|
||||
@ -61,63 +62,28 @@ pub(crate) fn input<Ctx: ConstMutSwitchUi + RefGetter>(
|
||||
"Ants per vertex",
|
||||
1..=100,
|
||||
1.0,
|
||||
&mut Ctx::_get(&mut ants_per_vertex, |apv| apv, |apv| apv),
|
||||
&mut Ctx::RefType::_get(&mut ants_per_vertex, |apv| apv, |apv| apv),
|
||||
);
|
||||
|
||||
ctx.space();
|
||||
|
||||
struct ControlsRow {}
|
||||
impl _ConstMutSwitchUiCallback<Ctx::RefType> for ControlsRow {
|
||||
type Clojure = (Ref<'_, UpdatePending>, Ref<'_, bool>);
|
||||
ctx.horizontal(ControlsRow {
|
||||
update: &mut vertex_update,
|
||||
run: &mut launch,
|
||||
});
|
||||
|
||||
fn render<SubCtx: ConstMutSwitchUi<RefType = Ctx::RefType>>(
|
||||
ctx: &mut SubCtx,
|
||||
mut clojure: (Ref<'_, UpdatePending>, Ref<'_, bool>),
|
||||
) {
|
||||
ctx.button("Add vertex", &mut clojure.0, |d| *d = UpdatePending::Add);
|
||||
ctx.separator();
|
||||
ctx.button("Run", &mut clojure.1, |d| *d = true);
|
||||
}
|
||||
}
|
||||
|
||||
ctx.horizontal::<ControlsRow>(&mut (vertex_update, launch))
|
||||
|
||||
/*
|
||||
|
||||
draw_lengths_table(
|
||||
ui,
|
||||
&mut data.simulation.graph.vertices,
|
||||
&mut data.simulation.graph.edges,
|
||||
&mut data.vertex_update,
|
||||
);
|
||||
|
||||
if run {
|
||||
let mut coords = vec![(0.0, 0.0); data.simulation.graph.vertices.capacity()];
|
||||
|
||||
for (i, _) in data.simulation.graph.vertices.iter_indexed() {
|
||||
coords[i] = (
|
||||
rand::random::<f32>() * 0.8 + 0.1,
|
||||
rand::random::<f32>() * 0.8 + 0.1,
|
||||
)
|
||||
}
|
||||
|
||||
data.state = AntsVisualisationData::Running;
|
||||
data.vertex_locations = coords;
|
||||
|
||||
let allowed_locations = data
|
||||
.simulation
|
||||
.graph
|
||||
.vertices
|
||||
.iter_indexed()
|
||||
.map(|(i, _)| i)
|
||||
.collect::<HashSet<usize>>();
|
||||
|
||||
let mut ants = Vec::new();
|
||||
for (i, _) in data.simulation.graph.vertices.iter_indexed() {
|
||||
for _ in 0..data.ants_per_vertex {
|
||||
ants.push(Ant::new(i, allowed_locations.clone()))
|
||||
}
|
||||
}
|
||||
data.simulation.ants = ants;
|
||||
}*/
|
||||
draw_lengths_table(ctx, graph, vertex_update)
|
||||
}
|
||||
|
||||
struct ControlsRow<'uu, 'u, 'rr, 'r, RT: RefType> {
|
||||
update: &'uu mut RT::Ref<'u, UpdatePending>,
|
||||
run: &'rr mut RT::Ref<'r, bool>,
|
||||
}
|
||||
|
||||
impl<RT: RefType> _ConstMutSwitchUiCallback<RT> for ControlsRow<'_, '_, '_, '_, RT> {
|
||||
fn render(self, ctx: &mut impl ConstMutSwitchUi<RefType = RT>) {
|
||||
ctx.button("Add vertex", self.update, |d| *d = UpdatePending::Add);
|
||||
ctx.separator();
|
||||
ctx.button("Run", self.run, |d| *d = true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
mod data;
|
||||
mod input;
|
||||
mod graph;
|
||||
mod input;
|
||||
|
||||
pub(crate) use data::{MyApp, AntsVisualisationData};
|
||||
pub(crate) use data::{AntsVisualisationApp, AntsVisualisationData, AntsVisualisationState};
|
||||
pub(crate) use graph::{graph_with_controls, gen_vertex_locations};
|
||||
pub(crate) use input::input;
|
||||
pub(crate) use graph::graph_with_controls;
|
||||
@ -3,42 +3,105 @@
|
||||
mod algo;
|
||||
mod gui;
|
||||
|
||||
use crate::algo::EdgeExtraData;
|
||||
use crate::algo::AntsSimulationState;
|
||||
use bgtu_ai_utility::gui::boot_eframe;
|
||||
use bgtu_ai_utility::gui::const_mut_switch::{ConstUI, MutUI};
|
||||
use bgtu_ai_utility::gui::graph_lengths_table::{ConstGraph, MutableGraph};
|
||||
use bgtu_ai_utility::gui::subwindow;
|
||||
use bgtu_ai_utility::UpdatePending;
|
||||
use eframe::egui;
|
||||
use rand::rng;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
fn main() -> eframe::Result {
|
||||
return boot_eframe("Ants simulation", || gui::MyApp::new());
|
||||
return boot_eframe("Ants simulation", || gui::AntsVisualisationApp::new());
|
||||
}
|
||||
|
||||
impl eframe::App for gui::MyApp {
|
||||
impl eframe::App for gui::AntsVisualisationApp {
|
||||
fn update(&mut self, ui: &eframe::egui::Context, _frame: &mut eframe::Frame) {
|
||||
egui::CentralPanel::default().show(ui, |ui| match self.state {
|
||||
gui::AntsVisualisationData::Edit {} => {
|
||||
match self.vertex_update {
|
||||
let state_ptr = NonNull::from_mut(&mut self.state);
|
||||
egui::CentralPanel::default().show(ui, |ui| match &mut self.state {
|
||||
gui::AntsVisualisationState::Edit {
|
||||
config,
|
||||
graph,
|
||||
ants_per_vertex,
|
||||
vertex_update,
|
||||
} => {
|
||||
match vertex_update {
|
||||
UpdatePending::NoChange => {}
|
||||
UpdatePending::Add => {
|
||||
self.simulation.graph.add_vertex(|| EdgeExtraData {
|
||||
ferment_intensity: 0.0,
|
||||
});
|
||||
self.vertex_update = UpdatePending::NoChange;
|
||||
graph.add_vertex(|| ());
|
||||
*vertex_update = UpdatePending::NoChange;
|
||||
}
|
||||
UpdatePending::Remove(vi) => {
|
||||
self.simulation.graph.remove_vertex(vi);
|
||||
self.vertex_update = UpdatePending::NoChange;
|
||||
graph.remove_vertex(*vi);
|
||||
*vertex_update = UpdatePending::NoChange;
|
||||
}
|
||||
}
|
||||
gui::input(ui, self)
|
||||
|
||||
let mut run = false;
|
||||
gui::input(
|
||||
&mut MutUI { ui },
|
||||
*config,
|
||||
&mut MutableGraph { graph },
|
||||
ants_per_vertex,
|
||||
vertex_update,
|
||||
&mut run,
|
||||
);
|
||||
|
||||
if run {
|
||||
let ns = gui::AntsVisualisationState::Running {
|
||||
simulation: AntsSimulationState::new(*graph, *config, *ants_per_vertex),
|
||||
ants_per_vertex: *ants_per_vertex,
|
||||
vertex_locations: gui::gen_vertex_locations(
|
||||
&mut rng(),
|
||||
graph.vertices.capacity(),
|
||||
),
|
||||
};
|
||||
unsafe {
|
||||
state_ptr.write(ns);
|
||||
}
|
||||
gui::AntsVisualisationData::Running { .. } => {
|
||||
ui.add_enabled_ui(false, |ui| gui::input(ui, self));
|
||||
}
|
||||
}
|
||||
gui::AntsVisualisationState::Running {
|
||||
simulation,
|
||||
ants_per_vertex,
|
||||
vertex_locations,
|
||||
} => {
|
||||
gui::input(
|
||||
&mut ConstUI { ui },
|
||||
&simulation.cfg,
|
||||
&mut ConstGraph {
|
||||
graph: &simulation.graph,
|
||||
},
|
||||
ants_per_vertex,
|
||||
&UpdatePending::NoChange,
|
||||
&false,
|
||||
);
|
||||
|
||||
let mut exit = false;
|
||||
subwindow(
|
||||
ui, "visualisation", "Visualisation",
|
||||
ui,
|
||||
"visualisation",
|
||||
"Visualisation",
|
||||
|vb| vb.with_inner_size([640.0, 480.0]),
|
||||
|ui| gui::graph_with_controls(ui, self),
|
||||
).on_close(|| self.state = gui::AntsVisualisationData::Edit);
|
||||
|ui| gui::graph_with_controls(ui, vertex_locations, simulation, &mut exit),
|
||||
)
|
||||
.on_close(|| exit = true);
|
||||
|
||||
if exit {
|
||||
let ns = gui::AntsVisualisationState::Edit {
|
||||
config: unsafe {
|
||||
NonNull::from_mut(&mut self.data.config).as_mut()
|
||||
},
|
||||
graph: unsafe { NonNull::from_mut(&mut self.data.graph).as_mut() },
|
||||
ants_per_vertex: *ants_per_vertex,
|
||||
vertex_update: UpdatePending::NoChange,
|
||||
};
|
||||
unsafe {
|
||||
state_ptr.write(ns);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
3
lab5/src/algo/config.rs
Normal file
3
lab5/src/algo/config.rs
Normal file
@ -0,0 +1,3 @@
|
||||
pub struct GeneticSimulationConfig {
|
||||
pub mutation_chance: f64,
|
||||
}
|
||||
@ -1,3 +1,7 @@
|
||||
mod product;
|
||||
mod mutate;
|
||||
mod simulation;
|
||||
mod config;
|
||||
|
||||
pub use config::GeneticSimulationConfig;
|
||||
pub use simulation::GeneticSimulationState;
|
||||
@ -0,0 +1,85 @@
|
||||
use crate::algo::config::GeneticSimulationConfig;
|
||||
use crate::algo::mutate::mutate;
|
||||
use crate::algo::product::product;
|
||||
use bgtu_ai_utility::graph::CompleteGraph;
|
||||
use bgtu_ai_utility::weighted_random_index;
|
||||
use rand::prelude::SliceRandom;
|
||||
use rand::Rng;
|
||||
|
||||
pub struct GeneticSimulationState<'a> {
|
||||
pub config: &'a GeneticSimulationConfig,
|
||||
pub graph: &'a CompleteGraph<()>,
|
||||
pub chromosome_size: usize,
|
||||
pub population: Vec<Vec<usize>>,
|
||||
}
|
||||
|
||||
impl<'a> GeneticSimulationState<'a> {
|
||||
pub fn new(
|
||||
config: &'a GeneticSimulationConfig,
|
||||
graph: &'a CompleteGraph<()>,
|
||||
chromosome_size: usize,
|
||||
population_size: usize,
|
||||
rng: &mut impl Rng,
|
||||
) -> Self {
|
||||
let mut population = vec![vec![0; chromosome_size]; population_size];
|
||||
for chromosome in population.iter_mut() {
|
||||
for (i, gene) in chromosome.iter_mut().enumerate() {
|
||||
*gene = i;
|
||||
}
|
||||
chromosome.shuffle(rng)
|
||||
}
|
||||
|
||||
return Self {
|
||||
config,
|
||||
graph,
|
||||
chromosome_size,
|
||||
population,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn next_generation(&mut self, rng: &mut impl Rng) {
|
||||
let mut new_generation = Vec::new();
|
||||
let weights = self.calculate_population_weights(self.population.as_slice());
|
||||
|
||||
for _ in 0..self.population.len() {
|
||||
let mut new_chromosome = vec![0; self.chromosome_size];
|
||||
|
||||
product(
|
||||
&self.population[weighted_random_index(rng, weights.as_slice(), |w| *w).unwrap()],
|
||||
&self.population[weighted_random_index(rng, weights.as_slice(), |w| *w).unwrap()],
|
||||
&mut new_chromosome,
|
||||
rng,
|
||||
);
|
||||
|
||||
new_generation.push(new_chromosome);
|
||||
}
|
||||
|
||||
for h in new_generation.iter_mut() {
|
||||
if rng.random::<f64>() < self.config.mutation_chance {
|
||||
mutate(h.as_mut(), rng);
|
||||
}
|
||||
}
|
||||
|
||||
self.population = new_generation;
|
||||
}
|
||||
|
||||
fn calculate_population_weights(&self, population: &[Vec<usize>]) -> Vec<f64> {
|
||||
return population
|
||||
.iter()
|
||||
.map(|h| {
|
||||
let mut weight = 0.0;
|
||||
h.iter().reduce(|a, b| {
|
||||
match self.graph.vertices[*a]
|
||||
.iter()
|
||||
.find(|e| self.graph.edges[**e].another(*a) == *b)
|
||||
{
|
||||
None => unreachable!(),
|
||||
Some(e) => weight += self.graph.edges[*e].length,
|
||||
};
|
||||
return b;
|
||||
});
|
||||
return 1.0 / weight;
|
||||
})
|
||||
.collect::<Vec<f64>>();
|
||||
}
|
||||
}
|
||||
52
lab5/src/gui/data.rs
Normal file
52
lab5/src/gui/data.rs
Normal file
@ -0,0 +1,52 @@
|
||||
use crate::algo::{GeneticSimulationConfig, GeneticSimulationState};
|
||||
use bgtu_ai_utility::UpdatePending;
|
||||
use bgtu_ai_utility::graph::CompleteGraph;
|
||||
use std::pin::Pin;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
pub(crate) struct GeneticVisualisationData {
|
||||
pub config: GeneticSimulationConfig,
|
||||
pub graph: CompleteGraph<()>,
|
||||
}
|
||||
|
||||
pub(crate) enum GeneticVisualisationState<'cfg> {
|
||||
Edit {
|
||||
config: &'cfg mut GeneticSimulationConfig,
|
||||
graph: &'cfg mut CompleteGraph<()>,
|
||||
vertex_update: UpdatePending,
|
||||
population_size: usize,
|
||||
generations_count: usize,
|
||||
},
|
||||
Running {
|
||||
simulation: GeneticSimulationState<'cfg>,
|
||||
generations_done: usize,
|
||||
generations_count: usize,
|
||||
vertex_locations: Vec<(f32, f32)>,
|
||||
},
|
||||
}
|
||||
|
||||
pub(crate) struct GeneticVisualisationApp {
|
||||
pub data: Pin<Box<GeneticVisualisationData>>,
|
||||
pub state: GeneticVisualisationState<'static /* actually not but fuck rust */>,
|
||||
}
|
||||
|
||||
impl GeneticVisualisationApp {
|
||||
pub fn new() -> Self {
|
||||
let mut data = Box::pin(GeneticVisualisationData {
|
||||
config: GeneticSimulationConfig {
|
||||
mutation_chance: 0.1,
|
||||
},
|
||||
graph: CompleteGraph::new(),
|
||||
});
|
||||
|
||||
let state = GeneticVisualisationState::Edit {
|
||||
config: unsafe { NonNull::from_mut(&mut data.config).as_mut() },
|
||||
graph: unsafe { NonNull::from_mut(&mut data.graph).as_mut() },
|
||||
population_size: 1,
|
||||
generations_count: 2,
|
||||
vertex_update: UpdatePending::NoChange,
|
||||
};
|
||||
|
||||
return Self { data, state };
|
||||
}
|
||||
}
|
||||
69
lab5/src/gui/graph.rs
Normal file
69
lab5/src/gui/graph.rs
Normal file
@ -0,0 +1,69 @@
|
||||
use crate::algo::GeneticSimulationState;
|
||||
use bgtu_ai_utility::gui::render_graph;
|
||||
use eframe::egui::Ui;
|
||||
use rand::{Rng, rng};
|
||||
|
||||
pub(crate) fn graph_with_controls(
|
||||
ui: &mut Ui,
|
||||
vertex_locations: &mut [(f32, f32)],
|
||||
data: &mut GeneticSimulationState,
|
||||
generations_left: &mut usize,
|
||||
exit: &mut bool,
|
||||
) {
|
||||
ui.vertical(|ui| {
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button("Exit").clicked() {
|
||||
*exit = true;
|
||||
}
|
||||
|
||||
ui.add_enabled_ui(*generations_left > 0, |ui| {
|
||||
if ui.button("Step").clicked() {
|
||||
data.next_generation(&mut rng());
|
||||
*generations_left -= 1;
|
||||
}
|
||||
});
|
||||
|
||||
ui.label("");
|
||||
});
|
||||
draw_ants(ui, vertex_locations, data);
|
||||
if ui.input(|i| i.viewport().close_requested()) {
|
||||
*exit = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn draw_ants(ui: &mut Ui, vertex_locations: &mut [(f32, f32)], data: &GeneticSimulationState) {
|
||||
let cap = data.population.len() as f64;
|
||||
let mut usage = vec![0usize; data.graph.edges.capacity()];
|
||||
for chromosome in data.population.iter() {
|
||||
chromosome.iter().reduce(|a, b| {
|
||||
match data.graph.vertices[*a]
|
||||
.iter()
|
||||
.find(|e| data.graph.edges[**e].another(*a) == *b)
|
||||
{
|
||||
None => unreachable!(),
|
||||
Some(e) => usage[*e] += 1,
|
||||
};
|
||||
return b;
|
||||
});
|
||||
}
|
||||
|
||||
render_graph(
|
||||
ui,
|
||||
&data.graph.vertices,
|
||||
vertex_locations,
|
||||
&data.graph.edges,
|
||||
|ei, _| usage[ei] as f64 / cap,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn gen_vertex_locations(rng: &mut impl Rng, count: usize) -> Vec<(f32, f32)> {
|
||||
let mut v = Vec::new();
|
||||
for _ in 0..count {
|
||||
v.push((
|
||||
rng.random::<f32>() * 0.8 + 0.1,
|
||||
rng.random::<f32>() * 0.8 + 0.1,
|
||||
));
|
||||
}
|
||||
return v;
|
||||
}
|
||||
60
lab5/src/gui/input.rs
Normal file
60
lab5/src/gui/input.rs
Normal file
@ -0,0 +1,60 @@
|
||||
use crate::algo::GeneticSimulationConfig;
|
||||
use bgtu_ai_utility::gui::const_mut_switch::{
|
||||
ConstMutSwitchUi, RefType, _ConstMutSwitchUiCallback,
|
||||
};
|
||||
use bgtu_ai_utility::gui::graph_lengths_table::{draw_lengths_table, Graph};
|
||||
use bgtu_ai_utility::UpdatePending;
|
||||
|
||||
|
||||
pub(crate) fn input<Ctx: ConstMutSwitchUi>(
|
||||
ctx: &mut Ctx,
|
||||
mut config: <Ctx::RefType as RefType>::Ref<'_, GeneticSimulationConfig>,
|
||||
graph: &mut impl Graph<RefType = Ctx::RefType>,
|
||||
mut population_size: <Ctx::RefType as RefType>::Ref<'_, usize>,
|
||||
mut generations_count: <Ctx::RefType as RefType>::Ref<'_, usize>,
|
||||
mut vertex_update: <Ctx::RefType as RefType>::Ref<'_, UpdatePending>,
|
||||
mut launch: <Ctx::RefType as RefType>::Ref<'_, bool>,
|
||||
) {
|
||||
ctx.labeled_slider("Population size", 1..=100, 1.0, &mut population_size);
|
||||
|
||||
ctx.space();
|
||||
|
||||
ctx.labeled_slider("Generations", 1..=100, 1.0, &mut generations_count);
|
||||
|
||||
ctx.space();
|
||||
|
||||
ctx.labeled_slider(
|
||||
"Mutation chance",
|
||||
0.0..=1.0,
|
||||
0.001,
|
||||
&mut Ctx::RefType::_get(
|
||||
&mut config,
|
||||
|config| &config.mutation_chance,
|
||||
|config| &mut config.mutation_chance,
|
||||
),
|
||||
);
|
||||
|
||||
ctx.space();
|
||||
|
||||
ctx.space();
|
||||
|
||||
ctx.horizontal(ControlsRow {
|
||||
update: &mut vertex_update,
|
||||
run: &mut launch,
|
||||
});
|
||||
|
||||
draw_lengths_table(ctx, graph, vertex_update)
|
||||
}
|
||||
|
||||
struct ControlsRow<'uu, 'u, 'rr, 'r, RT: RefType> {
|
||||
update: &'uu mut RT::Ref<'u, UpdatePending>,
|
||||
run: &'rr mut RT::Ref<'r, bool>,
|
||||
}
|
||||
|
||||
impl<RT: RefType> _ConstMutSwitchUiCallback<RT> for ControlsRow<'_, '_, '_, '_, RT> {
|
||||
fn render(self, ctx: &mut impl ConstMutSwitchUi<RefType = RT>) {
|
||||
ctx.button("Add vertex", self.update, |d| *d = UpdatePending::Add);
|
||||
ctx.separator();
|
||||
ctx.button("Run", self.run, |d| *d = true);
|
||||
}
|
||||
}
|
||||
7
lab5/src/gui/mod.rs
Normal file
7
lab5/src/gui/mod.rs
Normal file
@ -0,0 +1,7 @@
|
||||
mod data;
|
||||
mod input;
|
||||
mod graph;
|
||||
|
||||
pub(crate) use data::{GeneticVisualisationApp, GeneticVisualisationData, GeneticVisualisationState};
|
||||
pub(crate) use input::input;
|
||||
pub(crate) use graph::{gen_vertex_locations, graph_with_controls};
|
||||
254
lab5/src/main.rs
254
lab5/src/main.rs
@ -1,176 +1,128 @@
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||
|
||||
mod algo;
|
||||
mod gui;
|
||||
|
||||
use crate::algo::GeneticSimulationState;
|
||||
use bgtu_ai_utility::UpdatePending;
|
||||
use bgtu_ai_utility::gui::boot_eframe;
|
||||
use bgtu_ai_utility::gui::const_mut_switch::{ConstUI, MutUI};
|
||||
use bgtu_ai_utility::gui::graph_lengths_table::{ConstGraph, MutableGraph};
|
||||
use bgtu_ai_utility::gui::subwindow;
|
||||
use eframe::egui;
|
||||
use eframe::egui::{Frame, Ui};
|
||||
use eframe::emath::Numeric;
|
||||
use std::collections::HashSet;
|
||||
use std::ops::RangeInclusive;
|
||||
use tsp_utility::graph::{EdgesVec, VerticesVec};
|
||||
use tsp_utility::gui::lengths_table::{UpdatePending, draw_lengths_table};
|
||||
use rand::rng;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
fn main() -> eframe::Result {
|
||||
let options = eframe::NativeOptions {
|
||||
viewport: egui::ViewportBuilder::default().with_inner_size([640.0, 400.0]),
|
||||
..Default::default()
|
||||
};
|
||||
eframe::run_native(
|
||||
"Ants simulation",
|
||||
options,
|
||||
Box::new(|_cc| Ok(Box::<MyApp>::default())),
|
||||
)
|
||||
return boot_eframe("Genetic simulation", || gui::GeneticVisualisationApp::new());
|
||||
}
|
||||
|
||||
enum ViewState {
|
||||
Stop,
|
||||
Running { lastUpdateTimestamp: u64 },
|
||||
VertexMove { vertexId: usize },
|
||||
}
|
||||
|
||||
enum GlobalState {
|
||||
Edit {},
|
||||
Running { view_state: ViewState },
|
||||
}
|
||||
|
||||
struct MyApp {
|
||||
edges: EdgesVec<()>,
|
||||
vertices: VerticesVec,
|
||||
vertex_update: UpdatePending,
|
||||
population_size: usize,
|
||||
rounds: usize,
|
||||
mutation_chance: f64,
|
||||
state: GlobalState,
|
||||
}
|
||||
|
||||
impl Default for MyApp {
|
||||
fn default() -> Self {
|
||||
return Self {
|
||||
edges: EdgesVec::new(),
|
||||
vertices: VerticesVec::new(),
|
||||
vertex_update: UpdatePending::NoChange,
|
||||
population_size: 2,
|
||||
rounds: 1,
|
||||
mutation_chance: 0.1,
|
||||
state: GlobalState::Edit {},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn _slider<T: Numeric>(
|
||||
ui: &mut Ui,
|
||||
name: &str,
|
||||
storage: &mut T,
|
||||
range: RangeInclusive<T>,
|
||||
step: f64,
|
||||
) {
|
||||
let label = ui.label(name);
|
||||
|
||||
ui.scope(|ui| {
|
||||
ui.spacing_mut().slider_width = ui.available_width()
|
||||
- ui.spacing().interact_size.x
|
||||
- ui.spacing().button_padding.x * 2.0;
|
||||
ui.add(egui::Slider::new(storage, range).step_by(step))
|
||||
.labelled_by(label.id);
|
||||
});
|
||||
}
|
||||
|
||||
impl eframe::App for MyApp {
|
||||
impl eframe::App for gui::GeneticVisualisationApp {
|
||||
fn update(&mut self, ui: &eframe::egui::Context, _frame: &mut eframe::Frame) {
|
||||
egui::CentralPanel::default().show(ui, |ui| match self.state {
|
||||
GlobalState::Edit {} => {
|
||||
match self.vertex_update {
|
||||
let state_ptr = NonNull::from_mut(&mut self.state);
|
||||
egui::CentralPanel::default().show(ui, |ui| match &mut self.state {
|
||||
gui::GeneticVisualisationState::Edit {
|
||||
config,
|
||||
graph,
|
||||
vertex_update,
|
||||
population_size,
|
||||
generations_count,
|
||||
} => {
|
||||
match vertex_update {
|
||||
UpdatePending::NoChange => {}
|
||||
UpdatePending::Add => {
|
||||
let new_vi = self.vertices.add(HashSet::new());
|
||||
let mut newEdgesSet = HashSet::new();
|
||||
for (vi, v) in self.vertices.iter_indexed_mut() {
|
||||
if (vi == new_vi) {
|
||||
continue;
|
||||
}
|
||||
let ei = self.edges.add(new_vi, vi, 1.0, ());
|
||||
newEdgesSet.insert(ei);
|
||||
v.insert(ei);
|
||||
}
|
||||
self.vertices[new_vi] = newEdgesSet;
|
||||
self.vertex_update = UpdatePending::NoChange;
|
||||
graph.add_vertex(|| ());
|
||||
*vertex_update = UpdatePending::NoChange;
|
||||
}
|
||||
UpdatePending::Remove(vi) => {
|
||||
let mut eis = Vec::with_capacity(self.vertices[vi].len());
|
||||
for ei in self.vertices[vi].iter() {
|
||||
eis.push(*ei)
|
||||
}
|
||||
for ei in eis {
|
||||
self.vertices[self.edges[ei].another(vi)].remove(&ei);
|
||||
self.edges.remove(ei);
|
||||
}
|
||||
self.vertices.remove(vi);
|
||||
self.vertex_update = UpdatePending::NoChange;
|
||||
graph.remove_vertex(*vi);
|
||||
*vertex_update = UpdatePending::NoChange;
|
||||
}
|
||||
}
|
||||
edit_panel(self, ui)
|
||||
|
||||
let mut run = false;
|
||||
gui::input(
|
||||
&mut MutUI { ui },
|
||||
*config,
|
||||
&mut MutableGraph { graph },
|
||||
population_size,
|
||||
generations_count,
|
||||
vertex_update,
|
||||
&mut run,
|
||||
);
|
||||
|
||||
if run {
|
||||
let ns = gui::GeneticVisualisationState::Running {
|
||||
simulation: GeneticSimulationState::new(
|
||||
*config,
|
||||
*graph,
|
||||
graph.vertex_count(),
|
||||
*population_size,
|
||||
&mut rng(),
|
||||
),
|
||||
generations_done: 0,
|
||||
vertex_locations: gui::gen_vertex_locations(
|
||||
&mut rng(),
|
||||
graph.vertices.capacity(),
|
||||
),
|
||||
generations_count: *generations_count,
|
||||
};
|
||||
unsafe {
|
||||
state_ptr.write(ns);
|
||||
}
|
||||
GlobalState::Running { .. } => {
|
||||
ui.add_enabled_ui(false, |ui| edit_panel(self, ui));
|
||||
ui.ctx().show_viewport_immediate(
|
||||
egui::ViewportId::from_hash_of("Visualisation"),
|
||||
egui::ViewportBuilder::default()
|
||||
.with_title("Visualisation")
|
||||
.with_inner_size([640.0, 480.0])
|
||||
.with_resizable(false),
|
||||
|ui, _| {
|
||||
egui::CentralPanel::default()
|
||||
.frame(Frame::default().inner_margin(0.0))
|
||||
.show(ui, |ui| visualization_panel(self, ui));
|
||||
}
|
||||
}
|
||||
gui::GeneticVisualisationState::Running {
|
||||
simulation,
|
||||
generations_done,
|
||||
generations_count,
|
||||
vertex_locations,
|
||||
} => {
|
||||
gui::input(
|
||||
&mut ConstUI { ui },
|
||||
&simulation.config,
|
||||
&mut ConstGraph {
|
||||
graph: &simulation.graph,
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn edit_panel(data: &mut MyApp, ui: &mut Ui) {
|
||||
let run: bool;
|
||||
|
||||
_slider(
|
||||
ui,
|
||||
"Population size",
|
||||
&mut data.population_size,
|
||||
2..=1000,
|
||||
1.0,
|
||||
);
|
||||
ui.label("");
|
||||
_slider(ui, "Rounds", &mut data.rounds, 1..=100, 1.0);
|
||||
ui.label("");
|
||||
_slider(
|
||||
ui,
|
||||
"Mutation chance",
|
||||
&mut data.mutation_chance,
|
||||
0.0..=1.0,
|
||||
0.001,
|
||||
&simulation.population.len(),
|
||||
generations_count,
|
||||
&UpdatePending::NoChange,
|
||||
&false,
|
||||
);
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button("Add vertex").clicked() {
|
||||
data.vertex_update = UpdatePending::Add;
|
||||
}
|
||||
ui.separator();
|
||||
let run = ui.button("Run").clicked();
|
||||
});
|
||||
|
||||
draw_lengths_table(
|
||||
let mut exit = false;
|
||||
let mut generations_left = *generations_count - *generations_done;
|
||||
subwindow(
|
||||
ui,
|
||||
&mut data.vertices,
|
||||
&mut data.edges,
|
||||
&mut data.vertex_update,
|
||||
"visualisation",
|
||||
"Visualisation",
|
||||
|vb| vb.with_inner_size([640.0, 480.0]),
|
||||
|ui| {
|
||||
gui::graph_with_controls(
|
||||
ui,
|
||||
vertex_locations,
|
||||
simulation,
|
||||
&mut generations_left,
|
||||
&mut exit,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
.on_close(|| exit = true);
|
||||
*generations_done = *generations_count - generations_left;
|
||||
|
||||
fn visualization_panel(data: &mut MyApp, ui: &mut Ui) {
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button("Exit").clicked() {}
|
||||
|
||||
if ui.button("Step").clicked() {}
|
||||
ui.label("");
|
||||
if exit {
|
||||
let ns = gui::GeneticVisualisationState::Edit {
|
||||
config: unsafe { NonNull::from_mut(&mut self.data.config).as_mut() },
|
||||
graph: unsafe { NonNull::from_mut(&mut self.data.graph).as_mut() },
|
||||
vertex_update: UpdatePending::NoChange,
|
||||
population_size: simulation.population.len(),
|
||||
generations_count: *generations_count,
|
||||
};
|
||||
unsafe {
|
||||
state_ptr.write(ns);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
36
utility/src/gat_iterator.rs
Normal file
36
utility/src/gat_iterator.rs
Normal file
@ -0,0 +1,36 @@
|
||||
pub trait GatIterator {
|
||||
type Item<'x>
|
||||
where
|
||||
Self: 'x;
|
||||
|
||||
fn next<'s>(&'s mut self) -> Option<Self::Item<'s>>;
|
||||
|
||||
fn forEach(mut self, mut consumer: impl for<'x> FnMut(Self::Item<'x>))
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
loop {
|
||||
match self.next() {
|
||||
None => return,
|
||||
Some(i) => consumer(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*pub fn make_lambda<'z, I: Iterator>(it: I) -> impl for<'x> LambdaIterator<Item<'x> = I::Item> {
|
||||
return LambdaIteratorConverter { it };
|
||||
}
|
||||
|
||||
struct LambdaIteratorConverter<I: Iterator> {
|
||||
it: I,
|
||||
}
|
||||
|
||||
impl<I: Iterator> LambdaIterator for LambdaIteratorConverter<I> {
|
||||
type Item<'x> = I::Item where Self:'x;
|
||||
|
||||
fn next<'s, R>(&mut self, receiver: impl for<'x> FnOnce(I::Item) -> R) -> Option<R> {
|
||||
return self.it.next().map(receiver);
|
||||
}
|
||||
}
|
||||
*/
|
||||
@ -93,6 +93,13 @@ impl<T> _PreserveIndexVec<T> {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn iter_indexes(&self) -> impl Iterator<Item = (usize)> {
|
||||
return self.buffer.iter().enumerate().filter_map(|(i, c)| match c {
|
||||
Cell::Free { .. } => return None,
|
||||
Cell::Value { value } => return Some(i),
|
||||
});
|
||||
}
|
||||
|
||||
pub fn capacity(&self) -> usize {
|
||||
return self.buffer.len();
|
||||
}
|
||||
|
||||
@ -34,6 +34,7 @@ impl<E> CompleteGraph<E> {
|
||||
}
|
||||
self.vertices.remove(vi);
|
||||
}
|
||||
|
||||
pub fn vertex_count(&self) -> usize {
|
||||
return self.vertices.len();
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@ impl<D> EdgesVec<D> {
|
||||
vertex1_index: vertex1,
|
||||
vertex2_index: vertex2,
|
||||
length,
|
||||
extra
|
||||
extra,
|
||||
};
|
||||
return self.data.add(|_, _| data);
|
||||
}
|
||||
@ -47,17 +47,24 @@ impl<D> EdgesVec<D> {
|
||||
pub fn iter(&self) -> impl Iterator<Item = &Edge<D>> {
|
||||
return self.data.iter();
|
||||
}
|
||||
pub fn iter_indexed(&self) -> impl Iterator<Item = (usize, &Edge<D>)> {
|
||||
return self.data.iter_indexed();
|
||||
}
|
||||
|
||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Edge<D>> {
|
||||
return self.data.iter_mut();
|
||||
}
|
||||
|
||||
pub fn iter_indexes(&self) -> impl Iterator<Item = usize> {
|
||||
return self.data.iter_indexes();
|
||||
}
|
||||
|
||||
pub fn capacity(&self) -> usize {
|
||||
return self.data.capacity()
|
||||
return self.data.capacity();
|
||||
}
|
||||
}
|
||||
|
||||
impl <D> Index<usize> for EdgesVec<D> {
|
||||
impl<D> Index<usize> for EdgesVec<D> {
|
||||
type Output = Edge<D>;
|
||||
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
@ -65,7 +72,7 @@ impl <D> Index<usize> for EdgesVec<D> {
|
||||
}
|
||||
}
|
||||
|
||||
impl <D> IndexMut<usize> for EdgesVec<D> {
|
||||
impl<D> IndexMut<usize> for EdgesVec<D> {
|
||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||
return self.data.index_mut(index);
|
||||
}
|
||||
|
||||
@ -1,10 +1,14 @@
|
||||
use super::{_ConstMutSwitchUiCallback, ConstMutSwitchUi, ConstRef, RefType, _ConstMutSwitchUiTableHeaderCallback};
|
||||
use super::{
|
||||
_ConstMutSwitchUiCallback, _ConstMutSwitchUiTableHeaderCallback,
|
||||
_ConstMutSwitchUiTableCallback, ConstMutSwitchUi, ConstRef, MutRef, MutUI, RefType,
|
||||
};
|
||||
use crate::gui::const_mut_switch::table::ConstMutSwitchUiTableImplState;
|
||||
use eframe::egui::{ScrollArea, Ui};
|
||||
use eframe::emath::Numeric;
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
pub struct ConstUI<'ui> {
|
||||
ui: &'ui mut Ui,
|
||||
pub ui: &'ui mut Ui,
|
||||
}
|
||||
|
||||
impl<'ui> ConstUI<'ui> {
|
||||
@ -61,22 +65,22 @@ impl ConstMutSwitchUi for ConstUI<'_> {
|
||||
self.ui.separator();
|
||||
}
|
||||
|
||||
fn scroll_area_2(
|
||||
&mut self,
|
||||
scope: impl _ConstMutSwitchUiCallback<Self::RefType>,
|
||||
) {
|
||||
fn scroll_area_2(&mut self, scope: impl _ConstMutSwitchUiCallback<Self::RefType>) {
|
||||
ScrollArea::both()
|
||||
.auto_shrink([false, false])
|
||||
.show_viewport(self.ui, |ui, _|scope.render(&mut ConstUI { ui }));
|
||||
.show_viewport(self.ui, |ui, _| scope.render(&mut ConstUI { ui }));
|
||||
}
|
||||
|
||||
|
||||
fn table(
|
||||
&mut self,
|
||||
vscroll: bool,
|
||||
columns: usize,
|
||||
header: impl _ConstMutSwitchUiTableHeaderCallback<Self::RefType>,
|
||||
scope: impl _ConstMutSwitchUiTableCallback<Self::RefType>,
|
||||
) {
|
||||
super::render_table::<ConstRef, Self>(self.ui, vscroll, columns, header);
|
||||
scope.render_table(
|
||||
&mut ConstMutSwitchUiTableImplState::<ConstRef, ConstUI>::new(
|
||||
self.ui, vscroll, columns,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,8 +7,10 @@ mod r#trait;
|
||||
pub use r#const::ConstUI;
|
||||
pub use r#mut::MutUI;
|
||||
pub use r#ref::{ConstRef, MutRef, RefType};
|
||||
use table::render_table;
|
||||
use table::ConstMutSwitchUiTableImplState;
|
||||
pub use table::{
|
||||
_ConstMutSwitchUiTableHeaderCallback, _ConstMutSwitchUiTableRowCallback, ConstMutSwitchUiTableRow,
|
||||
_ConstMutSwitchUiTableCallback, _ConstMutSwitchUiTableHeaderCallback,
|
||||
_ConstMutSwitchUiTableRowCallback, _ConstMutSwitchUiTableRowsIterator, ConstMutSwitchUiTable,
|
||||
ConstMutSwitchUiTableRow,
|
||||
};
|
||||
pub use r#trait::{_ConstMutSwitchUiCallback, ConstMutSwitchUi};
|
||||
|
||||
@ -1,11 +1,15 @@
|
||||
use super::{_ConstMutSwitchUiTableHeaderCallback, ConstMutSwitchUi, MutRef, RefType};
|
||||
use super::{
|
||||
_ConstMutSwitchUiTableHeaderCallback, _ConstMutSwitchUiTableCallback, ConstMutSwitchUi,
|
||||
MutRef, RefType,
|
||||
};
|
||||
use crate::gui::const_mut_switch::table::ConstMutSwitchUiTableImplState;
|
||||
use crate::gui::const_mut_switch::r#trait::_ConstMutSwitchUiCallback;
|
||||
use eframe::egui::{ScrollArea, Ui};
|
||||
use eframe::emath::Numeric;
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
pub struct MutUI<'ui> {
|
||||
ui: &'ui mut Ui,
|
||||
pub ui: &'ui mut Ui,
|
||||
}
|
||||
|
||||
impl<'ui> MutUI<'ui> {
|
||||
@ -68,8 +72,10 @@ impl ConstMutSwitchUi for MutUI<'_> {
|
||||
&mut self,
|
||||
vscroll: bool,
|
||||
columns: usize,
|
||||
header: impl _ConstMutSwitchUiTableHeaderCallback<Self::RefType>,
|
||||
scope: impl _ConstMutSwitchUiTableCallback<Self::RefType>,
|
||||
) {
|
||||
super::render_table::<MutRef, Self>(self.ui, vscroll, columns, header);
|
||||
scope.render_table(&mut ConstMutSwitchUiTableImplState::<MutRef, MutUI>::new(
|
||||
self.ui, vscroll, columns,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,20 +3,33 @@
|
||||
use super::{
|
||||
_ConstMutSwitchUiCallback, ConstMutSwitchUi, ConstRef, ConstUI, MutRef, MutUI, RefType,
|
||||
};
|
||||
use crate::LambdaIterator;
|
||||
use crate::{GatIterator, LambdaIterator};
|
||||
use eframe::egui::Ui;
|
||||
use egui_extras::{Column, TableBuilder, TableRow};
|
||||
use egui_extras::{Column, Table, TableBuilder, TableRow};
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::uninitialized;
|
||||
use std::mem::{swap, uninitialized};
|
||||
use std::ptr::NonNull;
|
||||
|
||||
pub trait _ConstMutSwitchUiTableCallback<RefType: super::RefType> {
|
||||
fn render_table(self, ctx: &mut impl ConstMutSwitchUiTable<RefType = RefType>);
|
||||
}
|
||||
|
||||
pub trait ConstMutSwitchUiTable {
|
||||
type RefType: super::RefType;
|
||||
fn header(&mut self, scope: impl _ConstMutSwitchUiTableHeaderCallback<Self::RefType>);
|
||||
fn body(&mut self, scope: impl _ConstMutSwitchUiTableRowsIterator<Self::RefType>);
|
||||
}
|
||||
|
||||
pub trait _ConstMutSwitchUiTableRowsIterator<RefType: super::RefType> {
|
||||
type Item<'x>: _ConstMutSwitchUiTableRowCallback<RefType>
|
||||
where
|
||||
Self: 'x;
|
||||
|
||||
fn next<'s>(&'s mut self) -> Option<Self::Item<'s>>;
|
||||
}
|
||||
|
||||
pub trait _ConstMutSwitchUiTableHeaderCallback<RefType: super::RefType> {
|
||||
type RowRender: _ConstMutSwitchUiTableRowCallback<RefType>;
|
||||
type RowsIterator: LambdaIterator<Item = Self::RowRender>;
|
||||
|
||||
fn render_header(
|
||||
self,
|
||||
ctx: &mut impl ConstMutSwitchUiTableRow<RefType = RefType>,
|
||||
) -> Self::RowsIterator;
|
||||
fn render_header(self, ctx: &mut impl ConstMutSwitchUiTableRow<RefType = RefType>);
|
||||
}
|
||||
|
||||
pub trait _ConstMutSwitchUiTableRowCallback<RefType: super::RefType> {
|
||||
@ -70,36 +83,86 @@ impl __SwitchUiConstructor1<MutRef> for MutUI<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn render_table<
|
||||
RefType: super::RefType,
|
||||
Constructor: __SwitchUiConstructor1<RefType>,
|
||||
>(
|
||||
ui: &mut Ui,
|
||||
vscroll: bool,
|
||||
columnsCount: usize,
|
||||
header_render: impl _ConstMutSwitchUiTableHeaderCallback<RefType>,
|
||||
) {
|
||||
let mut rows_it = unsafe { uninitialized() };
|
||||
pub(super) enum ConstMutSwitchUiTableImplState<
|
||||
'a,
|
||||
RT: RefType,
|
||||
Constructor: __SwitchUiConstructor1<RT>,
|
||||
> {
|
||||
Header(TableBuilder<'a>),
|
||||
Body(Table<'a>),
|
||||
Done(PhantomData<(RT, Constructor)>),
|
||||
}
|
||||
|
||||
impl<'a, RT: RefType, Constructor: __SwitchUiConstructor1<RT>>
|
||||
ConstMutSwitchUiTableImplState<'a, RT, Constructor>
|
||||
{
|
||||
pub fn new(ui: &'a mut Ui, vscroll: bool, columns_count: usize) -> Self {
|
||||
return Self::Header(
|
||||
TableBuilder::new(ui)
|
||||
.striped(true) // Alternating row colors
|
||||
.resizable(true)
|
||||
.vscroll(vscroll)
|
||||
.columns(Column::remainder(), columnsCount)
|
||||
.header(20.0, |row| {
|
||||
rows_it =
|
||||
header_render.render_header(&mut ConstMutSwitchUiTableRowImpl::<_, Constructor> {
|
||||
row,
|
||||
__phantom: PhantomData::default(),
|
||||
});
|
||||
})
|
||||
.body(|mut body| {
|
||||
rows_it.consume(|row_render| {
|
||||
body.row(20.0, |row| {
|
||||
row_render.render_row(&mut ConstMutSwitchUiTableRowImpl::<_, Constructor> {
|
||||
row,
|
||||
__phantom: PhantomData::default(),
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
.columns(Column::remainder(), columns_count),
|
||||
);
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
fn header_map(&mut self, f: impl FnOnce(TableBuilder) -> Table) {
|
||||
let sp = NonNull::from_mut(self);
|
||||
match self {
|
||||
ConstMutSwitchUiTableImplState::Header(h) => {
|
||||
unsafe { sp.write(Self::Body(f(NonNull::from_mut(h).read()))) };
|
||||
}
|
||||
_ => panic!("Not in header state"),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
fn body_map(&mut self, f: impl FnOnce(Table)) {
|
||||
let sp = NonNull::from_mut(self);
|
||||
match self {
|
||||
ConstMutSwitchUiTableImplState::Body(b) => {
|
||||
unsafe {
|
||||
f(NonNull::from_mut(b).read());
|
||||
sp.write(Self::Done(PhantomData::default()))
|
||||
};
|
||||
}
|
||||
_ => panic!("Not in body state"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<RT: RefType, Constructor: __SwitchUiConstructor1<RT>> ConstMutSwitchUiTable
|
||||
for ConstMutSwitchUiTableImplState<'_, RT, Constructor>
|
||||
{
|
||||
type RefType = RT;
|
||||
|
||||
fn header(&mut self, scope: impl _ConstMutSwitchUiTableHeaderCallback<Self::RefType>) {
|
||||
self.header_map(|h| {
|
||||
return h.header(20.0, |row| {
|
||||
scope.render_header(&mut ConstMutSwitchUiTableRowImpl::<_, Constructor> {
|
||||
row,
|
||||
__phantom: PhantomData::default(),
|
||||
})
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
fn body(&mut self, mut scope: impl _ConstMutSwitchUiTableRowsIterator<Self::RefType>) {
|
||||
self.body_map(|body| {
|
||||
body.body(|mut b| {
|
||||
loop {
|
||||
match scope.next() {
|
||||
None => break,
|
||||
Some(rs) => b.row(20.0, |rn| {
|
||||
rs.render_row(&mut ConstMutSwitchUiTableRowImpl::<_, Constructor> {
|
||||
row: rn,
|
||||
__phantom: PhantomData::default(),
|
||||
})
|
||||
}),
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use super::{_ConstMutSwitchUiTableHeaderCallback, RefType};
|
||||
use super::{_ConstMutSwitchUiTableHeaderCallback, RefType, _ConstMutSwitchUiTableCallback};
|
||||
use eframe::emath::Numeric;
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
@ -41,7 +41,7 @@ pub trait ConstMutSwitchUi {
|
||||
&mut self,
|
||||
vscroll: bool,
|
||||
columns: usize,
|
||||
header: impl _ConstMutSwitchUiTableHeaderCallback<Self::RefType>,
|
||||
scope: impl _ConstMutSwitchUiTableCallback<Self::RefType>,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -835,3 +835,232 @@ trait Ctx_Graph<G> {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
## 7
|
||||
Метод `_ConstMutSwitchUiTableHeaderCallback::render_header` принимает в себя контекст отрисовки
|
||||
строки и возвращает `impl Trait`. По умолчанию компилятор считает, что возвращаемое значение
|
||||
заимствует все переданные ссылки. Для более тонкой настройки компилятора есть синтаксис
|
||||
`impl Trait + use<'a, A>`, но так как компилятор не способен реализовать минимум, определяемый
|
||||
спецификацией языка, в `use` должны быть указаны все типовые параметры (даже неявные). В
|
||||
данном случае контекст отрисовки туда попадать не должен, так что пришлось отказаться от короткого
|
||||
и удобно способа и вернуться к этапу `3.1`: ручной вызов отрисовки заголовка и тела таблицы.
|
||||
|
||||
## 8
|
||||
### 8.1
|
||||
|
||||
Попытки победить borrow checker в итераторах привели к идее указывать возвращаемый
|
||||
тип итератора в параметре трейта, а не ассоциированным типом.
|
||||
```rust
|
||||
trait LambdaIterator<Item> {
|
||||
fn next<R>(&mut self, receiver: impl FnOnce(Item) -> R) -> Option<R>;
|
||||
}
|
||||
```
|
||||
Это помогло решить некоторые
|
||||
проблемы, но имплементировать такой трейт всё равно не получилось.
|
||||
|
||||
### 8.2
|
||||
Gemini рассказал про **Higher-Rank Trait Bounds (HRTB)**, и вроде как это решает проблему
|
||||
```rust
|
||||
trait LambdaIterator {
|
||||
type Item<'x>;
|
||||
|
||||
fn next<R>(&mut self, receiver: impl for<'x> FnOnce(Self::Item<'x>) -> R) -> Option<R>;
|
||||
}
|
||||
```
|
||||
|
||||
### 8.3
|
||||
Имплементация итератора в таком варианте выдавала ошибку, которая исправляется вполне логичным
|
||||
дополнением к трейту:
|
||||
```rust
|
||||
trait LambdaIterator {
|
||||
type Item<'x>: where Self: 'x;
|
||||
|
||||
fn next<R>(&mut self, receiver: impl for<'x> FnOnce(Self::Item<'x>) -> R) -> Option<R>;
|
||||
}
|
||||
```
|
||||
|
||||
### 8.4
|
||||
После многочисленных экспериментов был сделан вывод, что язык пока не готов к описанию таких
|
||||
гениальных вещей: или в компиляторе просто с ошибками эти вещи реализованы; или вывод об
|
||||
ошибках недостаточно подробный, чтоб разобраться не употребляя те же вещества, что и создатели.
|
||||
Порождение итератора выглядит следующим образом:
|
||||
```rust
|
||||
trait Ctx_Graph<G> {
|
||||
type RefType: RefType;
|
||||
|
||||
type Vertex<'v>;
|
||||
|
||||
fn iter_vertices<'g>(
|
||||
&mut self,
|
||||
graph: &'g mut G
|
||||
) -> impl for<'v> LambdaIterator<Item<'v>=(&'v mut Self, Self::Vertex<'v>)> + 'g;
|
||||
}
|
||||
```
|
||||
Корректна ли эта запись на практике проверить не удалось, так как в имплементации компилятор
|
||||
просчитывает время жизни лямбды (или её компонентов) совсем не так, как ожидается.
|
||||
|
||||
|
||||
### 8.5
|
||||
Поитогу пришлось откатиться обратно на обычные итераторы. Точнее, на их модифицированную
|
||||
версию, благо знание об HRTB даёт недосающие инструменты:
|
||||
```rust
|
||||
trait GatIterator {
|
||||
type Item<'x>
|
||||
where
|
||||
Self: 'x;
|
||||
|
||||
fn next<'s>(&'s mut self) -> Option<Self::Item<'s>>;
|
||||
|
||||
fn forEach(mut self, mut consumer: impl for<'x> FnMut(Self::Item<'x>))
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
loop {
|
||||
match self.next() {
|
||||
None => return,
|
||||
Some(i) => consumer(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 8.6
|
||||
В целом такая модификация итератора работает сама по себе, но использовать его как часть системы
|
||||
трейтов, которые явно указывают какой тип должен возвращать такой итератор не получается, из-за
|
||||
тех же ошибок про неправильное время жизни ассоциированного типа двоюродного племянника бабушки
|
||||
по папиной/маминой линии детей типового параметра.
|
||||
```rust
|
||||
trait Container {
|
||||
type Item<'x>: Contraint;
|
||||
|
||||
fn iter(&mut self) -> impl for<'x> GatIterator<Item<'x> = Self::Item<'x>>;
|
||||
}
|
||||
```
|
||||
Но если создавать под каждую задачу свой трейт итератора, то это как минимум компилируется, но
|
||||
опять же, только в случаях когда не нужно указывать тип элемента в месте использования. Такой
|
||||
модификации подвергся итератор для строк таблицы:
|
||||
```rust
|
||||
|
||||
pub trait ConstMutSwitchUiTable {
|
||||
// ...
|
||||
|
||||
fn body(&mut self, scope: impl _ConstMutSwitchUiTableRowsIterator<Self::RefType>);
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
pub trait _ConstMutSwitchUiTableRowsIterator<RefType: super::RefType> {
|
||||
type Item<'x>: _ConstMutSwitchUiTableRowCallback<RefType>
|
||||
where
|
||||
Self: 'x;
|
||||
|
||||
fn next<'s>(&'s mut self) -> Option<Self::Item<'s>>;
|
||||
}
|
||||
```
|
||||
|
||||
## 9
|
||||
Контекст для работы с графами пришлось несколько раз декомпозировать и изменять, в основном по
|
||||
той же причине невозможности полноценно использовать `+ use<>`. В конечном итоге он превратился
|
||||
просто в обёртку над графом (и его частями) без вынесения в контекст.
|
||||
|
||||
```rust
|
||||
|
||||
pub trait Graph {
|
||||
type RefType: RefType;
|
||||
|
||||
fn iter_vertices(&mut self) -> impl VerticesIterator<RefType = Self::RefType>;
|
||||
|
||||
fn vertices_count(&self) -> usize;
|
||||
}
|
||||
|
||||
pub trait VerticesIterator {
|
||||
type RefType: RefType;
|
||||
|
||||
type Vertex<'v>: Vertex<RefType = Self::RefType>
|
||||
where
|
||||
Self: 'v;
|
||||
|
||||
fn next<'v>(&'v mut self) -> Option<Self::Vertex<'v>>;
|
||||
}
|
||||
|
||||
pub trait Vertex {
|
||||
type RefType: RefType;
|
||||
|
||||
fn iter_edges_or_nothing_sorted(&mut self) -> impl EdgesIterator<RefType = Self::RefType>;
|
||||
|
||||
fn set_vertex_to_update_state(&self, state: &mut UpdatePending);
|
||||
}
|
||||
|
||||
pub trait EdgesIterator {
|
||||
type RefType: RefType;
|
||||
|
||||
type Edge<'e>: Edge<RefType = Self::RefType>
|
||||
where
|
||||
Self: 'e;
|
||||
|
||||
fn next<'e>(&'e mut self) -> Option<Option<Self::Edge<'e>>>;
|
||||
}
|
||||
|
||||
pub trait Edge {
|
||||
type RefType: RefType;
|
||||
|
||||
fn get_edge_len_ptr<'s>(&'s mut self) -> <Self::RefType as RefType>::Ref<'s, f64>;
|
||||
}
|
||||
```
|
||||
|
||||
## 10
|
||||
Работа с состояниями это отдельный вид искусства. Если внутри енама есть что-то, без поддержки
|
||||
копирования, но это что-то нужно использовать для вычисления следующего состояния, то borrow
|
||||
checker вынудит откатиться в ~~каменный век~~ обратно в C/C++ с ручной реализацией растовских
|
||||
енамов.
|
||||
|
||||
### 10.1
|
||||
Первый опробованный трюк:
|
||||
```rust
|
||||
enum State<AA, BB> {A(AA), B(BB)}
|
||||
|
||||
impl <AA, BB> State<AA, BB> {
|
||||
fn map(&mut self, f: impl FnOnce(AA) -> BB) {
|
||||
match self {
|
||||
Self::A(_) => {
|
||||
let mut local = unsafe { Self::A(uninitialized()) };
|
||||
swap(self, &mut local);
|
||||
if let Self::A(local) = local {
|
||||
*self = Self::BB(f(local))
|
||||
}
|
||||
}
|
||||
_ => todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
успехом не увенчался, в отладочной сборке компилятор кидает панику в районе `swap` из-за того
|
||||
что переменная `local` не инициализированна.
|
||||
|
||||
### 10.2
|
||||
Следующий трюк уже рабочий, но вопросы к безопасности очень большие:
|
||||
```rust
|
||||
enum State<AA, BB> {A(AA), B(BB)}
|
||||
|
||||
impl <AA, BB> State<AA, BB> {
|
||||
fn map(&mut self, f: impl FnOnce(AA) -> BB) {
|
||||
let sp = NonNull::from_mut(self);
|
||||
match self {
|
||||
Self::A(aa) => {
|
||||
unsafe { sp.write(Self::BB(f(NonNull::from_mut(aa).read()))) };
|
||||
}
|
||||
_ => todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Выводы
|
||||
Идея с безопасностью через строгие проверки времени жизни на этапе компиляции интересная, но
|
||||
в текущем виде не рабочая. Язык получился таким же низкоуровневым, как C# или Kotlin/Native:
|
||||
работать с указателями и линковаться напрямую с функциями из C можно, но в любой сколько-нибудь
|
||||
сложной ситуации компилятор вынуждает пользоваться динамической памятью даже там, где можно
|
||||
обойтись без этого или городить костыли, которые сводят на нет всю безопасность языка. Поитогу
|
||||
получился "безопасный" и многословный Python.
|
||||
48
utility/src/gui/graph_lengths_table/ctx.rs
Normal file
48
utility/src/gui/graph_lengths_table/ctx.rs
Normal file
@ -0,0 +1,48 @@
|
||||
use crate::graph::{CompleteGraph, EdgesVec};
|
||||
use crate::gui::const_mut_switch::{MutRef, RefType};
|
||||
use crate::{GatIterator, UpdatePending};
|
||||
use std::collections::HashSet;
|
||||
use std::ops::IndexMut;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
pub trait Graph {
|
||||
type RefType: RefType;
|
||||
|
||||
fn iter_vertices(&mut self) -> impl VerticesIterator<RefType = Self::RefType>;
|
||||
|
||||
fn vertices_count(&self) -> usize;
|
||||
}
|
||||
|
||||
pub trait VerticesIterator {
|
||||
type RefType: RefType;
|
||||
|
||||
type Vertex<'v>: Vertex<RefType = Self::RefType>
|
||||
where
|
||||
Self: 'v;
|
||||
|
||||
fn next<'v>(&'v mut self) -> Option<Self::Vertex<'v>>;
|
||||
}
|
||||
|
||||
pub trait Vertex {
|
||||
type RefType: RefType;
|
||||
|
||||
fn iter_edges_or_nothing_sorted(&mut self) -> impl EdgesIterator<RefType = Self::RefType>;
|
||||
|
||||
fn set_vertex_to_update_state(&self, state: &mut UpdatePending);
|
||||
}
|
||||
|
||||
pub trait EdgesIterator {
|
||||
type RefType: RefType;
|
||||
|
||||
type Edge<'e>: Edge<RefType = Self::RefType>
|
||||
where
|
||||
Self: 'e;
|
||||
|
||||
fn next<'e>(&'e mut self) -> Option<Option<Self::Edge<'e>>>;
|
||||
}
|
||||
|
||||
pub trait Edge {
|
||||
type RefType: RefType;
|
||||
|
||||
fn get_edge_len_ptr<'s>(&'s mut self) -> <Self::RefType as RefType>::Ref<'s, f64>;
|
||||
}
|
||||
123
utility/src/gui/graph_lengths_table/impl_const.rs
Normal file
123
utility/src/gui/graph_lengths_table/impl_const.rs
Normal file
@ -0,0 +1,123 @@
|
||||
use super::{Edge, EdgesIterator, Graph, IteratorWithHole, Vertex, VerticesIterator};
|
||||
use crate::UpdatePending;
|
||||
use crate::graph::{CompleteGraph, EdgesVec};
|
||||
use crate::gui::const_mut_switch::{ConstRef, RefType};
|
||||
use std::collections::HashSet;
|
||||
use std::ops::Index;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
pub struct ConstGraph<'g> {
|
||||
pub graph: &'g CompleteGraph<()>,
|
||||
}
|
||||
|
||||
impl Graph for ConstGraph<'_> {
|
||||
type RefType = ConstRef;
|
||||
|
||||
fn iter_vertices(&mut self) -> impl VerticesIterator<RefType = Self::RefType> {
|
||||
return ConstVerticesIterator {
|
||||
ee: &self.graph.edges,
|
||||
it: self.graph.vertices.iter_indexed(),
|
||||
ordinal: 0,
|
||||
};
|
||||
}
|
||||
|
||||
fn vertices_count(&self) -> usize {
|
||||
return self.graph.vertex_count();
|
||||
}
|
||||
}
|
||||
|
||||
struct ConstVerticesIterator<'g, It: Iterator<Item = (usize, &'g HashSet<usize>)>> {
|
||||
ee: &'g EdgesVec<()>,
|
||||
it: It,
|
||||
ordinal: usize,
|
||||
}
|
||||
|
||||
impl<'g, It: Iterator<Item = (usize, &'g HashSet<usize>)>> VerticesIterator
|
||||
for ConstVerticesIterator<'g, It>
|
||||
{
|
||||
type RefType = ConstRef;
|
||||
type Vertex<'v>
|
||||
= ConstVertex<'v>
|
||||
where
|
||||
Self: 'v;
|
||||
|
||||
fn next<'v>(&'v mut self) -> Option<Self::Vertex<'v>> {
|
||||
return self.it.next().map(|(i, e)| {
|
||||
let v = ConstVertex {
|
||||
id: i,
|
||||
local_edges: e,
|
||||
all_edges: self.ee,
|
||||
ordinal: self.ordinal,
|
||||
};
|
||||
self.ordinal += 1;
|
||||
return v;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
struct ConstVertex<'g> {
|
||||
ordinal: usize,
|
||||
id: usize,
|
||||
local_edges: &'g HashSet<usize>,
|
||||
all_edges: &'g EdgesVec<()>,
|
||||
}
|
||||
|
||||
impl Vertex for ConstVertex<'_> {
|
||||
type RefType = ConstRef;
|
||||
|
||||
fn iter_edges_or_nothing_sorted(&mut self) -> impl EdgesIterator<RefType = Self::RefType> {
|
||||
let mut local_edges = self
|
||||
.local_edges
|
||||
.iter()
|
||||
.map(|i| {
|
||||
(i, unsafe {
|
||||
NonNull::from_ref(self.all_edges.index(*i)).as_ref()
|
||||
})
|
||||
})
|
||||
.map(|(i, e)| (e.another(self.id), i, &e.length))
|
||||
.collect::<Vec<_>>();
|
||||
local_edges.sort_by_key(|(k, _, _)| *k);
|
||||
|
||||
return ConstEdgesIterator {
|
||||
it: IteratorWithHole {
|
||||
it: local_edges.into_iter().map(|(_, _, x)| x),
|
||||
hole: Some(self.ordinal),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn set_vertex_to_update_state(&self, state: &mut UpdatePending) {
|
||||
*state = UpdatePending::Remove(self.id)
|
||||
}
|
||||
}
|
||||
|
||||
struct ConstEdgesIterator<'g, It: Iterator<Item = Option<&'g f64>>> {
|
||||
it: It,
|
||||
}
|
||||
|
||||
impl<'g, It: Iterator<Item = Option<&'g f64>>> EdgesIterator for ConstEdgesIterator<'g, It> {
|
||||
type RefType = ConstRef;
|
||||
type Edge<'x>
|
||||
= ConstEdge<'x>
|
||||
where
|
||||
Self: 'x;
|
||||
|
||||
fn next<'s>(&'s mut self) -> Option<Option<Self::Edge<'s>>> {
|
||||
return self
|
||||
.it
|
||||
.next()
|
||||
.map(|oi| oi.map(|len| ConstEdge { len: len }));
|
||||
}
|
||||
}
|
||||
|
||||
struct ConstEdge<'g> {
|
||||
len: &'g f64,
|
||||
}
|
||||
|
||||
impl Edge for ConstEdge<'_> {
|
||||
type RefType = ConstRef;
|
||||
|
||||
fn get_edge_len_ptr<'s>(&'s mut self) -> <Self::RefType as RefType>::Ref<'s, f64> {
|
||||
return self.len;
|
||||
}
|
||||
}
|
||||
125
utility/src/gui/graph_lengths_table/impl_mut.rs
Normal file
125
utility/src/gui/graph_lengths_table/impl_mut.rs
Normal file
@ -0,0 +1,125 @@
|
||||
use super::{Edge, EdgesIterator, Graph, IteratorWithHole, Vertex, VerticesIterator};
|
||||
use crate::graph::{CompleteGraph, EdgesVec};
|
||||
use crate::gui::const_mut_switch::{MutRef, RefType};
|
||||
use crate::{UpdatePending};
|
||||
use std::collections::HashSet;
|
||||
use std::ops::IndexMut;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
pub struct MutableGraph<'g> {
|
||||
pub graph: &'g mut CompleteGraph<()>,
|
||||
}
|
||||
|
||||
impl Graph for MutableGraph<'_> {
|
||||
type RefType = MutRef;
|
||||
|
||||
fn iter_vertices(&mut self) -> impl VerticesIterator<RefType = Self::RefType> {
|
||||
return MutableVerticesIterator {
|
||||
ee: &mut self.graph.edges,
|
||||
it: self.graph.vertices.iter_indexed_mut(),
|
||||
ordinal: 0,
|
||||
};
|
||||
}
|
||||
|
||||
fn vertices_count(&self) -> usize {
|
||||
return self.graph.vertex_count();
|
||||
}
|
||||
}
|
||||
|
||||
struct MutableVerticesIterator<'g, It: Iterator<Item = (usize, &'g mut HashSet<usize>)>> {
|
||||
ee: &'g mut EdgesVec<()>,
|
||||
it: It,
|
||||
ordinal: usize,
|
||||
}
|
||||
|
||||
impl<'g, It: Iterator<Item = (usize, &'g mut HashSet<usize>)>> VerticesIterator
|
||||
for MutableVerticesIterator<'g, It>
|
||||
{
|
||||
type RefType = MutRef;
|
||||
type Vertex<'v>
|
||||
= MutableVertex<'v>
|
||||
where
|
||||
Self: 'v;
|
||||
|
||||
fn next<'v>(&'v mut self) -> Option<Self::Vertex<'v>> {
|
||||
return self.it.next().map(|(i, e)| {
|
||||
let v = MutableVertex {
|
||||
id: i,
|
||||
local_edges: e,
|
||||
all_edges: self.ee,
|
||||
ordinal: self.ordinal,
|
||||
};
|
||||
self.ordinal += 1;
|
||||
return v;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
struct MutableVertex<'g> {
|
||||
ordinal: usize,
|
||||
id: usize,
|
||||
local_edges: &'g mut HashSet<usize>,
|
||||
all_edges: &'g mut EdgesVec<()>,
|
||||
}
|
||||
|
||||
impl Vertex for MutableVertex<'_> {
|
||||
type RefType = MutRef;
|
||||
|
||||
fn iter_edges_or_nothing_sorted(&mut self) -> impl EdgesIterator<RefType = Self::RefType> {
|
||||
let mut local_edges = self
|
||||
.local_edges
|
||||
.iter()
|
||||
.map(|i| {
|
||||
(i, unsafe {
|
||||
NonNull::from_mut(self.all_edges.index_mut(*i)).as_mut()
|
||||
})
|
||||
})
|
||||
.map(|(i, e)| (e.another(self.id), i, &mut e.length))
|
||||
.collect::<Vec<_>>();
|
||||
local_edges.sort_by_key(|(k, _, _)| *k);
|
||||
|
||||
return MutableEdgesIterator {
|
||||
it: IteratorWithHole {
|
||||
it: local_edges.into_iter().map(|(_, _, x)| x),
|
||||
hole: Some(self.ordinal),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn set_vertex_to_update_state(&self, state: &mut UpdatePending) {
|
||||
*state = UpdatePending::Remove(self.id)
|
||||
}
|
||||
}
|
||||
|
||||
struct MutableEdgesIterator<'g, It: Iterator<Item = Option<&'g mut f64>>> {
|
||||
it: It,
|
||||
}
|
||||
|
||||
impl<'g, It: Iterator<Item = Option<&'g mut f64>>> EdgesIterator
|
||||
for MutableEdgesIterator<'g, It>
|
||||
{
|
||||
type RefType = MutRef;
|
||||
type Edge<'x>
|
||||
= MutableEdge<'x>
|
||||
where
|
||||
Self: 'x;
|
||||
|
||||
fn next<'s>(&'s mut self) -> Option<Option<Self::Edge<'s>>> {
|
||||
return self
|
||||
.it
|
||||
.next()
|
||||
.map(|oi| oi.map(|len| MutableEdge { len: len }));
|
||||
}
|
||||
}
|
||||
|
||||
struct MutableEdge<'g> {
|
||||
len: &'g mut f64,
|
||||
}
|
||||
|
||||
impl Edge for MutableEdge<'_> {
|
||||
type RefType = MutRef;
|
||||
|
||||
fn get_edge_len_ptr<'s>(&'s mut self) -> <Self::RefType as RefType>::Ref<'s, f64> {
|
||||
return self.len;
|
||||
}
|
||||
}
|
||||
36
utility/src/gui/graph_lengths_table/mod.rs
Normal file
36
utility/src/gui/graph_lengths_table/mod.rs
Normal file
@ -0,0 +1,36 @@
|
||||
mod ctx;
|
||||
mod impl_mut;
|
||||
mod ui;
|
||||
mod impl_const;
|
||||
|
||||
pub use ctx::Graph;
|
||||
use ctx::{Edge, EdgesIterator, Vertex, VerticesIterator};
|
||||
pub use impl_mut::MutableGraph;
|
||||
pub use impl_const::ConstGraph;
|
||||
pub use ui::draw_lengths_table;
|
||||
|
||||
|
||||
|
||||
struct IteratorWithHole<E, It: Iterator<Item = E>> {
|
||||
hole: Option<usize>,
|
||||
it: It,
|
||||
}
|
||||
|
||||
impl<E, It: Iterator<Item = E>> Iterator for IteratorWithHole<E, It> {
|
||||
type Item = Option<E>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.hole {
|
||||
None => return self.it.next().map(|e| Some(e)),
|
||||
Some(v) => {
|
||||
if v == 0 {
|
||||
self.hole = None;
|
||||
return Some(None);
|
||||
} else {
|
||||
self.hole = Some(v - 1);
|
||||
return self.it.next().map(|e| Some(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
178
utility/src/gui/graph_lengths_table/ui.rs
Normal file
178
utility/src/gui/graph_lengths_table/ui.rs
Normal file
@ -0,0 +1,178 @@
|
||||
use crate::UpdatePending;
|
||||
use crate::gui::const_mut_switch::{
|
||||
_ConstMutSwitchUiCallback, _ConstMutSwitchUiTableCallback,
|
||||
_ConstMutSwitchUiTableHeaderCallback, _ConstMutSwitchUiTableRowCallback,
|
||||
_ConstMutSwitchUiTableRowsIterator, ConstMutSwitchUi, ConstMutSwitchUiTable,
|
||||
ConstMutSwitchUiTableRow, RefType,
|
||||
};
|
||||
use crate::gui::graph_lengths_table::ctx::EdgesIterator;
|
||||
use crate::gui::graph_lengths_table::ctx::VerticesIterator;
|
||||
use crate::gui::graph_lengths_table::{Edge, Graph, Vertex};
|
||||
|
||||
pub fn draw_lengths_table<G: Graph, CtxUi: ConstMutSwitchUi<RefType = G::RefType>>(
|
||||
ctx_ui: &mut CtxUi,
|
||||
graph: &mut G,
|
||||
update: <CtxUi::RefType as RefType>::Ref<'_, UpdatePending>,
|
||||
) {
|
||||
ctx_ui.scroll_area_2(Root { graph, update });
|
||||
}
|
||||
struct Root<'g, 'u, G: Graph> {
|
||||
graph: &'g mut G,
|
||||
update: <G::RefType as RefType>::Ref<'u, UpdatePending>,
|
||||
}
|
||||
|
||||
impl<G: Graph> _ConstMutSwitchUiCallback<G::RefType> for Root<'_, '_, G> {
|
||||
fn render(self, ctx: &mut impl ConstMutSwitchUi<RefType = G::RefType>) {
|
||||
ctx.table(false, self.graph.vertices_count() + 1, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: Graph> _ConstMutSwitchUiTableCallback<G::RefType> for Root<'_, '_, G> {
|
||||
fn render_table(mut self, ctx: &mut impl ConstMutSwitchUiTable<RefType = G::RefType>) {
|
||||
ctx.header(Header {
|
||||
it: self.graph.iter_vertices(),
|
||||
update: &mut self.update,
|
||||
});
|
||||
|
||||
ctx.body(RowsIterators {
|
||||
vertices: self.graph.iter_vertices(),
|
||||
update: self.update,
|
||||
row_id: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct Header<'u, 'uu, It: VerticesIterator> {
|
||||
it: It,
|
||||
update: &'uu mut <It::RefType as RefType>::Ref<'u, UpdatePending>,
|
||||
}
|
||||
|
||||
impl<It: VerticesIterator> _ConstMutSwitchUiTableHeaderCallback<It::RefType>
|
||||
for Header<'_, '_, It>
|
||||
{
|
||||
fn render_header(mut self, row: &mut impl ConstMutSwitchUiTableRow<RefType = It::RefType>) {
|
||||
row.cell(CornerCell {});
|
||||
|
||||
let mut column_id = 0;
|
||||
loop {
|
||||
match self.it.next() {
|
||||
None => break,
|
||||
Some(mut v) => {
|
||||
column_id += 1;
|
||||
// let update = &mut self.update;
|
||||
let data = TitleCell {
|
||||
row_id: column_id,
|
||||
vertex: &mut v,
|
||||
update: &mut self.update,
|
||||
};
|
||||
row.cell(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
struct RowsIterators<'u, It: VerticesIterator> {
|
||||
vertices: It,
|
||||
update: <It::RefType as RefType>::Ref<'u, UpdatePending>,
|
||||
row_id: usize,
|
||||
}
|
||||
|
||||
impl<'u, It: VerticesIterator> _ConstMutSwitchUiTableRowsIterator<It::RefType>
|
||||
for RowsIterators<'u, It>
|
||||
{
|
||||
type Item<'x>
|
||||
= Row<'x, 'u, It::Vertex<'x>>
|
||||
where
|
||||
Self: 'x;
|
||||
|
||||
fn next<'s>(&'s mut self) -> Option<Self::Item<'s>> {
|
||||
match self.vertices.next() {
|
||||
None => return None,
|
||||
Some(v) => {
|
||||
self.row_id += 1;
|
||||
return Some(Row {
|
||||
vertex: v,
|
||||
row_id: self.row_id,
|
||||
update: &mut self.update,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Row<'uu, 'u: 'uu, V: Vertex> {
|
||||
vertex: V,
|
||||
row_id: usize,
|
||||
update: &'uu mut <V::RefType as RefType>::Ref<'u, UpdatePending>,
|
||||
}
|
||||
|
||||
impl<V: Vertex> _ConstMutSwitchUiTableRowCallback<V::RefType> for Row<'_, '_, V> {
|
||||
fn render_row(mut self, row: &mut impl ConstMutSwitchUiTableRow<RefType = V::RefType>) {
|
||||
row.cell(TitleCell {
|
||||
row_id: self.row_id,
|
||||
vertex: &mut self.vertex,
|
||||
update: self.update,
|
||||
});
|
||||
|
||||
let mut it = self.vertex.iter_edges_or_nothing_sorted();
|
||||
|
||||
loop {
|
||||
match it.next() {
|
||||
None => break,
|
||||
Some(None) => row.cell(EmptyCell {}),
|
||||
Some(Some(mut e)) => row.cell(LengthCell {
|
||||
length: &mut e.get_edge_len_ptr(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CornerCell {}
|
||||
impl<RT: RefType> _ConstMutSwitchUiCallback<RT> for CornerCell {
|
||||
fn render(self, ctx: &mut impl ConstMutSwitchUi<RefType = RT>) {
|
||||
ctx.label("#");
|
||||
}
|
||||
}
|
||||
|
||||
struct TitleCell<'v, 'uu, 'u: 'uu, V: Vertex> {
|
||||
row_id: usize,
|
||||
vertex: &'v mut V,
|
||||
update: &'uu mut <V::RefType as RefType>::Ref<'u, UpdatePending>,
|
||||
}
|
||||
impl<V: Vertex> _ConstMutSwitchUiCallback<V::RefType> for TitleCell<'_, '_, '_, V> {
|
||||
fn render(self, ctx: &mut impl ConstMutSwitchUi<RefType = V::RefType>) {
|
||||
ctx.horizontal(TitleCellH {
|
||||
row_id: self.row_id,
|
||||
vertex: self.vertex,
|
||||
update: self.update,
|
||||
})
|
||||
}
|
||||
}
|
||||
struct TitleCellH<'v, 'uu, 'u: 'uu, V: Vertex> {
|
||||
row_id: usize,
|
||||
vertex: &'v mut V,
|
||||
update: &'uu mut <V::RefType as RefType>::Ref<'u, UpdatePending>,
|
||||
}
|
||||
impl<V: Vertex> _ConstMutSwitchUiCallback<V::RefType> for TitleCellH<'_, '_, '_, V> {
|
||||
fn render(self, ctx: &mut impl ConstMutSwitchUi<RefType = V::RefType>) {
|
||||
ctx.label(self.row_id.to_string().as_str());
|
||||
ctx.button("-", self.update, |s| {
|
||||
self.vertex.set_vertex_to_update_state(s)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
struct LengthCell<'rr, 'r: 'rr, RT: RefType> {
|
||||
length: &'rr mut RT::Ref<'r, f64>,
|
||||
}
|
||||
impl<RT: RefType> _ConstMutSwitchUiCallback<RT> for LengthCell<'_, '_, RT> {
|
||||
fn render(self, ctx: &mut impl ConstMutSwitchUi<RefType = RT>) {
|
||||
ctx.slider(0.0..=10.0, 0.1, self.length);
|
||||
}
|
||||
}
|
||||
|
||||
struct EmptyCell {}
|
||||
impl<RT: RefType> _ConstMutSwitchUiCallback<RT> for EmptyCell {
|
||||
fn render(self, _: &mut impl ConstMutSwitchUi<RefType = RT>) {}
|
||||
}
|
||||
@ -1,201 +0,0 @@
|
||||
use crate::gui::const_mut_switch::{
|
||||
_ConstMutSwitchUiCallback, _ConstMutSwitchUiTableHeaderCallback,
|
||||
_ConstMutSwitchUiTableRowCallback, ConstMutSwitchUi, ConstMutSwitchUiTableRow, RefType,
|
||||
};
|
||||
use crate::{LambdaIterator, UpdatePending};
|
||||
use std::ptr::NonNull;
|
||||
|
||||
pub trait Ctx_Graph<G> {
|
||||
type RefType: RefType;
|
||||
|
||||
type Vertex;
|
||||
type VerticesIterator<'a>: LambdaIterator<Item=(&'a mut Self, Self::Vertex)>
|
||||
where
|
||||
Self: 'a;
|
||||
fn iter_vertices(&mut self, graph: &mut G) -> Self::VerticesIterator<'_>;
|
||||
|
||||
type Edge;
|
||||
fn iter_edges_or_nothing(
|
||||
&mut self,
|
||||
vertex: &mut Self::Vertex,
|
||||
) -> impl LambdaIterator<Item=(&mut Self, Option<Self::Edge>)>;
|
||||
|
||||
fn get_edge_len_ptr(
|
||||
&mut self,
|
||||
edge: &mut Self::Edge,
|
||||
) -> <Self::RefType as RefType>::Ref<'_, f64>;
|
||||
|
||||
fn set_vertex_to_update_state(&self, vertex: &Self::Vertex, state: &mut UpdatePending);
|
||||
|
||||
fn vertices_count(&self) -> usize;
|
||||
}
|
||||
|
||||
pub fn draw_lengths_table<
|
||||
G,
|
||||
CtxUi: ConstMutSwitchUi,
|
||||
CtxGraph: Ctx_Graph<G, RefType=CtxUi::RefType>,
|
||||
>(
|
||||
ctx_ui: &mut CtxUi,
|
||||
ctx_graph: &mut CtxGraph,
|
||||
graph: G,
|
||||
update: <CtxUi::RefType as RefType>::Ref<'_, UpdatePending>,
|
||||
) {
|
||||
ctx_ui.scroll_area_2(ScrollArea {
|
||||
ctx_graph,
|
||||
graph,
|
||||
update,
|
||||
});
|
||||
}
|
||||
struct ScrollArea<'g, 'u, G, CtxGraph: Ctx_Graph<G>> {
|
||||
ctx_graph: &'g mut CtxGraph,
|
||||
graph: G,
|
||||
update: <CtxGraph::RefType as RefType>::Ref<'u, UpdatePending>,
|
||||
}
|
||||
|
||||
impl<G, CtxGraph: Ctx_Graph<G>> _ConstMutSwitchUiCallback<CtxGraph::RefType>
|
||||
for ScrollArea<'_, '_, G, CtxGraph>
|
||||
{
|
||||
fn render(self, ctx: &mut impl ConstMutSwitchUi<RefType=CtxGraph::RefType>) {
|
||||
ctx.table(
|
||||
false,
|
||||
self.ctx_graph.vertices_count(),
|
||||
Header {
|
||||
ctx_graph: self.ctx_graph,
|
||||
graph: self.graph,
|
||||
update: self.update,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct Header<'g, 'u, G, CtxGraph: Ctx_Graph<G>> {
|
||||
ctx_graph: &'g mut CtxGraph,
|
||||
graph: G,
|
||||
update: <CtxGraph::RefType as RefType>::Ref<'u, UpdatePending>,
|
||||
}
|
||||
|
||||
impl<'g, 'u, G, CtxGraph: Ctx_Graph<G>> _ConstMutSwitchUiTableHeaderCallback<CtxGraph::RefType>
|
||||
for Header<'g, 'u, G, CtxGraph>
|
||||
{
|
||||
type RowRender = Row<'g, 'u, G, CtxGraph>;
|
||||
|
||||
type RowsIterator = RowsIterators<'g, 'u, G, CtxGraph>;
|
||||
|
||||
fn render_header(
|
||||
mut self,
|
||||
row: &mut impl ConstMutSwitchUiTableRow<RefType=CtxGraph::RefType>,
|
||||
) -> Self::RowsIterator {
|
||||
row.cell(CornerCell {});
|
||||
|
||||
let mut column_id = 0;
|
||||
self.ctx_graph
|
||||
.iter_vertices(&mut self.graph)
|
||||
.consume(|(ctx_graph, v)| {
|
||||
column_id += 1;
|
||||
// let update = &mut self.update;
|
||||
let data = TitleCell {
|
||||
ctx_graph: ctx_graph,
|
||||
row_id: column_id,
|
||||
vertex: &v,
|
||||
update: &mut self.update,
|
||||
};
|
||||
row.cell(data)
|
||||
});
|
||||
|
||||
return RowsIterators {
|
||||
vertices: self.ctx_graph.iter_vertices(&mut self.graph),
|
||||
update: self.update,
|
||||
row_id: 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
struct RowsIterators<'g, 'u, G, CtxGraph: Ctx_Graph<G> + 'g> {
|
||||
vertices: CtxGraph::VerticesIterator<'g>,
|
||||
update: <CtxGraph::RefType as RefType>::Ref<'u, UpdatePending>,
|
||||
row_id: usize,
|
||||
}
|
||||
|
||||
impl<'g, 'u, G, CtxGraph: Ctx_Graph<G> + 'g> LambdaIterator for RowsIterators<'g, 'u, G, CtxGraph> {
|
||||
type Item = Row<'g, 'u, G, CtxGraph>;
|
||||
|
||||
fn next<R>(&mut self, receiver: impl FnOnce(Self::Item) -> R) -> Option<R> {
|
||||
return self.vertices.next(|(ctx, v)| {
|
||||
self.row_id += 1;
|
||||
return receiver(Row {
|
||||
ctx_graph: ctx,
|
||||
vertex: v,
|
||||
row_id: self.row_id,
|
||||
update: NonNull::from_mut(&mut self.update),
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
struct Row<'g, 'u, G, CtxGraph: Ctx_Graph<G>> {
|
||||
ctx_graph: &'g mut CtxGraph,
|
||||
vertex: CtxGraph::Vertex,
|
||||
row_id: usize,
|
||||
update: NonNull<<CtxGraph::RefType as RefType>::Ref<'u, UpdatePending>>,
|
||||
}
|
||||
|
||||
impl<G, CtxGraph: Ctx_Graph<G>> _ConstMutSwitchUiTableRowCallback<CtxGraph::RefType>
|
||||
for Row<'_, '_, G, CtxGraph>
|
||||
{
|
||||
fn render_row(mut self, row: &mut impl ConstMutSwitchUiTableRow<RefType=CtxGraph::RefType>) {
|
||||
row.cell(TitleCell {
|
||||
ctx_graph: self.ctx_graph,
|
||||
row_id: self.row_id,
|
||||
vertex: &self.vertex,
|
||||
update: unsafe { self.update.as_mut() },
|
||||
});
|
||||
|
||||
self.ctx_graph
|
||||
.iter_edges_or_nothing(&mut self.vertex)
|
||||
.consume(|(ctx_graph, e)| {
|
||||
match e {
|
||||
None => row.cell(EmptyCell {}),
|
||||
Some(mut e) => row.cell(LengthCell {
|
||||
length: &mut ctx_graph.get_edge_len_ptr(&mut e),
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct CornerCell {}
|
||||
impl<RT: RefType> _ConstMutSwitchUiCallback<RT> for CornerCell {
|
||||
fn render(self, ctx: &mut impl ConstMutSwitchUi<RefType=RT>) {
|
||||
ctx.label("#");
|
||||
}
|
||||
}
|
||||
|
||||
struct TitleCell<'g, 'v, 'rr, 'r: 'rr, G, CtxGraph: Ctx_Graph<G>> {
|
||||
ctx_graph: &'g mut CtxGraph,
|
||||
row_id: usize,
|
||||
vertex: &'v CtxGraph::Vertex,
|
||||
update: &'rr mut <CtxGraph::RefType as RefType>::Ref<'r, UpdatePending>,
|
||||
}
|
||||
impl<G, CtxGraph: Ctx_Graph<G>> _ConstMutSwitchUiCallback<CtxGraph::RefType>
|
||||
for TitleCell<'_, '_, '_, '_, G, CtxGraph>
|
||||
{
|
||||
fn render(self, ctx: &mut impl ConstMutSwitchUi<RefType=CtxGraph::RefType>) {
|
||||
ctx.label(self.row_id.to_string().as_str());
|
||||
ctx.button("-", self.update, |s| {
|
||||
self.ctx_graph.set_vertex_to_update_state(self.vertex, s)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
struct LengthCell<'rr, 'r: 'rr, RT: RefType> {
|
||||
length: &'rr mut RT::Ref<'r, f64>,
|
||||
}
|
||||
impl<RT: RefType> _ConstMutSwitchUiCallback<RT> for LengthCell<'_, '_, RT> {
|
||||
fn render(self, ctx: &mut impl ConstMutSwitchUi<RefType=RT>) {
|
||||
ctx.slider(0.0..=10.0, 0.1, self.length);
|
||||
}
|
||||
}
|
||||
|
||||
struct EmptyCell {}
|
||||
impl<RT: RefType> _ConstMutSwitchUiCallback<RT> for EmptyCell {
|
||||
fn render(self, _: &mut impl ConstMutSwitchUi<RefType=RT>) {}
|
||||
}
|
||||
@ -1,9 +1,9 @@
|
||||
mod boot;
|
||||
pub mod const_mut_switch;
|
||||
pub mod lengths_table;
|
||||
mod render_graph;
|
||||
mod slider;
|
||||
mod subwindow;
|
||||
pub mod graph_lengths_table;
|
||||
|
||||
pub use boot::boot_eframe;
|
||||
pub use render_graph::render_graph;
|
||||
|
||||
@ -8,7 +8,7 @@ pub fn render_graph<D>(
|
||||
vertices: &VerticesVec,
|
||||
vertex_locations: &mut [(f32, f32)],
|
||||
edges: &EdgesVec<D>,
|
||||
normalized_intensity: impl Fn(&Edge<D>) -> f64,
|
||||
normalized_intensity: impl Fn(usize, &Edge<D>) -> f64,
|
||||
) {
|
||||
let canvas = ui.painter();
|
||||
let rect = ui.available_size();
|
||||
@ -17,7 +17,7 @@ pub fn render_graph<D>(
|
||||
let rect = Rect::from_min_max(start.min, rect.to_pos2());
|
||||
canvas.rect_filled(rect, CornerRadius::same(0), Color32::from_rgb(0, 0, 0));
|
||||
|
||||
for e in edges.iter() {
|
||||
for (ei, e) in edges.iter_indexed() {
|
||||
let p1 = vertex_locations[e.vertex1_index];
|
||||
let p2 = vertex_locations[e.vertex2_index];
|
||||
|
||||
@ -32,7 +32,7 @@ pub fn render_graph<D>(
|
||||
p2.1 * rect.height() + rect.min.y,
|
||||
),
|
||||
],
|
||||
Stroke::new(1.0, intensity2color(normalized_intensity(e))),
|
||||
Stroke::new(1.0, intensity2color(normalized_intensity(ei, e))),
|
||||
);
|
||||
}
|
||||
let font_id = &ui.style().text_styles[&egui::TextStyle::Body];
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
pub trait LambdaIterator {
|
||||
type Item;
|
||||
type Item<'x>: where Self: 'x;
|
||||
|
||||
fn next<R>(&mut self, receiver: impl FnOnce(Self::Item) -> R) -> Option<R>;
|
||||
fn next<R>(&mut self, receiver: impl for<'x> FnOnce(Self::Item<'x>) -> R) -> Option<R>;
|
||||
|
||||
fn consume(mut self, mut receiver: impl FnMut(Self::Item))
|
||||
fn consume(mut self, mut receiver: impl for<'x> FnMut(Self::Item<'x>))
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
@ -11,7 +11,7 @@ pub trait LambdaIterator {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_lambda<I: Iterator>(it: I) -> impl LambdaIterator<Item = I::Item> {
|
||||
/*pub fn make_lambda<'z, I: Iterator>(it: I) -> impl for<'x> LambdaIterator<Item<'x> = I::Item> {
|
||||
return LambdaIteratorConverter { it };
|
||||
}
|
||||
|
||||
@ -20,9 +20,10 @@ struct LambdaIteratorConverter<I: Iterator> {
|
||||
}
|
||||
|
||||
impl<I: Iterator> LambdaIterator for LambdaIteratorConverter<I> {
|
||||
type Item = I::Item;
|
||||
type Item<'x> = I::Item where Self:'x;
|
||||
|
||||
fn next<R>(&mut self, receiver: impl FnOnce(Self::Item) -> R) -> Option<R> {
|
||||
fn next<'s, R>(&mut self, receiver: impl for<'x> FnOnce(I::Item) -> R) -> Option<R> {
|
||||
return self.it.next().map(receiver);
|
||||
}
|
||||
}
|
||||
*/
|
||||
@ -3,7 +3,9 @@ pub mod gui;
|
||||
mod lambda_iterator;
|
||||
mod update_pending;
|
||||
mod weighted_random;
|
||||
mod gat_iterator;
|
||||
|
||||
pub use lambda_iterator::{LambdaIterator, make_lambda};
|
||||
pub use lambda_iterator::{LambdaIterator};
|
||||
pub use gat_iterator::{GatIterator};
|
||||
pub use update_pending::{UpdatePending, UpdateTarget};
|
||||
pub use weighted_random::{weighted_random, weighted_random_index};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user