[lab5] Simulation and visualization
This commit is contained in:
parent
0e735f4db5
commit
dab2d16e38
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 product;
|
||||||
mod mutate;
|
mod mutate;
|
||||||
mod simulation;
|
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()
|
||||||
|
.position(|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
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||||
|
|
||||||
mod algo;
|
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;
|
||||||
use eframe::egui::{Frame, Ui};
|
use rand::rng;
|
||||||
use eframe::emath::Numeric;
|
use std::ptr::NonNull;
|
||||||
use std::collections::HashSet;
|
|
||||||
use std::ops::RangeInclusive;
|
|
||||||
use tsp_utility::graph::{EdgesVec, VerticesVec};
|
|
||||||
use tsp_utility::gui::lengths_table::{UpdatePending, draw_lengths_table};
|
|
||||||
|
|
||||||
fn main() -> eframe::Result {
|
fn main() -> eframe::Result {
|
||||||
let options = eframe::NativeOptions {
|
return boot_eframe("Genetic simulation", || gui::GeneticVisualisationApp::new());
|
||||||
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())),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ViewState {
|
impl eframe::App for gui::GeneticVisualisationApp {
|
||||||
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 {
|
|
||||||
fn update(&mut self, ui: &eframe::egui::Context, _frame: &mut eframe::Frame) {
|
fn update(&mut self, ui: &eframe::egui::Context, _frame: &mut eframe::Frame) {
|
||||||
egui::CentralPanel::default().show(ui, |ui| match self.state {
|
let state_ptr = NonNull::from_mut(&mut self.state);
|
||||||
GlobalState::Edit {} => {
|
egui::CentralPanel::default().show(ui, |ui| match &mut self.state {
|
||||||
match self.vertex_update {
|
gui::GeneticVisualisationState::Edit {
|
||||||
|
config,
|
||||||
|
graph,
|
||||||
|
vertex_update,
|
||||||
|
population_size,
|
||||||
|
generations_count,
|
||||||
|
} => {
|
||||||
|
match vertex_update {
|
||||||
UpdatePending::NoChange => {}
|
UpdatePending::NoChange => {}
|
||||||
UpdatePending::Add => {
|
UpdatePending::Add => {
|
||||||
let new_vi = self.vertices.add(HashSet::new());
|
graph.add_vertex(|| ());
|
||||||
let mut newEdgesSet = HashSet::new();
|
*vertex_update = UpdatePending::NoChange;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
UpdatePending::Remove(vi) => {
|
UpdatePending::Remove(vi) => {
|
||||||
let mut eis = Vec::with_capacity(self.vertices[vi].len());
|
graph.remove_vertex(*vi);
|
||||||
for ei in self.vertices[vi].iter() {
|
*vertex_update = UpdatePending::NoChange;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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(
|
gui::GeneticVisualisationState::Running {
|
||||||
egui::ViewportId::from_hash_of("Visualisation"),
|
simulation,
|
||||||
egui::ViewportBuilder::default()
|
generations_done,
|
||||||
.with_title("Visualisation")
|
generations_count,
|
||||||
.with_inner_size([640.0, 480.0])
|
vertex_locations,
|
||||||
.with_resizable(false),
|
} => {
|
||||||
|ui, _| {
|
gui::input(
|
||||||
egui::CentralPanel::default()
|
&mut ConstUI { ui },
|
||||||
.frame(Frame::default().inner_margin(0.0))
|
&simulation.config,
|
||||||
.show(ui, |ui| visualization_panel(self, ui));
|
&mut ConstGraph {
|
||||||
|
graph: &simulation.graph,
|
||||||
},
|
},
|
||||||
);
|
&simulation.population.len(),
|
||||||
}
|
generations_count,
|
||||||
});
|
&UpdatePending::NoChange,
|
||||||
}
|
&false,
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
let mut exit = false;
|
||||||
if ui.button("Add vertex").clicked() {
|
let mut generations_left = *generations_count - *generations_done;
|
||||||
data.vertex_update = UpdatePending::Add;
|
subwindow(
|
||||||
}
|
|
||||||
ui.separator();
|
|
||||||
let run = ui.button("Run").clicked();
|
|
||||||
});
|
|
||||||
|
|
||||||
draw_lengths_table(
|
|
||||||
ui,
|
ui,
|
||||||
&mut data.vertices,
|
"visualisation",
|
||||||
&mut data.edges,
|
"Visualisation",
|
||||||
&mut data.vertex_update,
|
|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) {
|
if exit {
|
||||||
ui.horizontal(|ui| {
|
let ns = gui::GeneticVisualisationState::Edit {
|
||||||
if ui.button("Exit").clicked() {}
|
config: unsafe { NonNull::from_mut(&mut self.data.config).as_mut() },
|
||||||
|
graph: unsafe { NonNull::from_mut(&mut self.data.graph).as_mut() },
|
||||||
if ui.button("Step").clicked() {}
|
vertex_update: UpdatePending::NoChange,
|
||||||
ui.label("");
|
population_size: simulation.population.len(),
|
||||||
|
generations_count: *generations_count,
|
||||||
|
};
|
||||||
|
unsafe {
|
||||||
|
state_ptr.write(ns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user