Compare commits

..

5 Commits

34 changed files with 1508 additions and 559 deletions

View File

@ -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);
}
}
}

View File

@ -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 };
}
}

View File

@ -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;
}

View File

@ -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);
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", &mut clojure.1, |d| *d = true);
ctx.button("Run", self.run, |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;
}*/
}

View File

@ -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;

View File

@ -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
View File

@ -0,0 +1,3 @@
pub struct GeneticSimulationConfig {
pub mutation_chance: f64,
}

View File

@ -1,3 +1,7 @@
mod product;
mod mutate;
mod simulation;
mod config;
pub use config::GeneticSimulationConfig;
pub use simulation::GeneticSimulationState;

View File

@ -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
View 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
View 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
View 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
View 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};

View File

@ -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;
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);
}
}
}
fn visualization_panel(data: &mut MyApp, ui: &mut Ui) {
ui.horizontal(|ui| {
if ui.button("Exit").clicked() {}
if ui.button("Step").clicked() {}
ui.label("");
});
}
}

View 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);
}
}
*/

View File

@ -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();
}

View File

@ -34,6 +34,7 @@ impl<E> CompleteGraph<E> {
}
self.vertices.remove(vi);
}
pub fn vertex_count(&self) -> usize {
return self.vertices.len();
}

View File

@ -36,7 +36,7 @@ impl<D> EdgesVec<D> {
vertex1_index: vertex1,
vertex2_index: vertex2,
length,
extra
extra,
};
return self.data.add(|_, _| data);
}
@ -47,13 +47,20 @@ 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();
}
}

View File

@ -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 }));
}
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,
),
);
}
}

View File

@ -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};

View File

@ -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,
));
}
}

View File

@ -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(),
})
}),
}
}
});
})
}
}

View File

@ -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>,
);
}

View File

@ -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.

View 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>;
}

View 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;
}
}

View 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;
}
}

View 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));
}
}
}
}
}

View 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>) {}
}

View File

@ -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>) {}
}

View File

@ -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;

View File

@ -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];

View File

@ -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);
}
}
*/

View File

@ -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};