[lab3] Ants similar visualization
This commit is contained in:
parent
6b74ba6590
commit
d2ba913525
@ -9,10 +9,4 @@ pub struct EdgeExtraData {
|
||||
|
||||
pub type Edge = _BaseEdge<EdgeExtraData>;
|
||||
pub type EdgesVec = _BaseEdgesVec<EdgeExtraData>;
|
||||
|
||||
pub struct AntsSimulationConfig {
|
||||
pub ferment_weight: f64,
|
||||
pub heuristic_coefficient: f64,
|
||||
pub q: f64,
|
||||
pub r: f64,
|
||||
}
|
||||
pub use state::{AntsSimulationConfig, AntsSimulationState, updateState, Ant};
|
||||
@ -1,6 +1,8 @@
|
||||
use super::EdgesVec;
|
||||
use rand::Rng;
|
||||
use std::collections::HashSet;
|
||||
use std::ops::Mul;
|
||||
use tsp_utility::graph::VerticesVec;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum AntDirection {
|
||||
@ -8,11 +10,24 @@ pub enum AntDirection {
|
||||
ToFirst,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Ant {
|
||||
allowed_vertices: HashSet<usize>,
|
||||
location: AntLocation,
|
||||
}
|
||||
|
||||
impl Ant {
|
||||
pub fn new(vertex: usize, allowed_vertices: HashSet<usize>) -> Self {
|
||||
return Self {
|
||||
allowed_vertices: allowed_vertices,
|
||||
location: AntLocation::OnVertex {
|
||||
vertex_index: vertex,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum AntLocation {
|
||||
OnEdge {
|
||||
edge_index: usize,
|
||||
@ -24,20 +39,32 @@ pub enum AntLocation {
|
||||
},
|
||||
}
|
||||
|
||||
pub struct AntsSimulationState<'a, Rng: rand::Rng> {
|
||||
rng: Rng,
|
||||
vertices: &'a Vec<HashSet<usize>>,
|
||||
edges: &'a mut EdgesVec,
|
||||
ants: &'a mut [Ant],
|
||||
pub struct AntsSimulationState {
|
||||
pub vertices: VerticesVec,
|
||||
pub edges: EdgesVec,
|
||||
pub ants: Vec<Ant>,
|
||||
}
|
||||
|
||||
pub fn updateState<Rng: rand::Rng>(
|
||||
state: &mut AntsSimulationState<Rng>,
|
||||
ferment_weight: f64,
|
||||
heuristic_coefficient: f64,
|
||||
q: f64,
|
||||
r: f64,
|
||||
speed: u16,
|
||||
pub struct AntsSimulationConfig {
|
||||
pub ferment_weight: f64,
|
||||
pub heuristic_coefficient: f64,
|
||||
pub q: f64,
|
||||
pub r: f64,
|
||||
}
|
||||
|
||||
pub fn updateState(
|
||||
state: &mut AntsSimulationState,
|
||||
cfg: &AntsSimulationConfig,
|
||||
rng: &mut impl Rng,
|
||||
) {
|
||||
_updateState(state, cfg, rng);
|
||||
_updateState(state, cfg, rng);
|
||||
}
|
||||
|
||||
fn _updateState(
|
||||
state: &mut AntsSimulationState,
|
||||
cfg: &AntsSimulationConfig,
|
||||
rng: &mut impl Rng,
|
||||
) -> bool {
|
||||
let mut finished_ants_count = 0usize;
|
||||
for ant in state.ants.iter_mut() {
|
||||
@ -46,11 +73,9 @@ pub fn updateState<Rng: rand::Rng>(
|
||||
edge_index,
|
||||
offset,
|
||||
direction,
|
||||
} => match offset.checked_add(speed) {
|
||||
Some(newOffset) => *offset = newOffset,
|
||||
None => {
|
||||
} => {
|
||||
let edge = &mut state.edges[*edge_index];
|
||||
edge.extra.ferment_intensity += (q / edge.length) * r;
|
||||
edge.extra.ferment_intensity += (cfg.q / edge.length) * cfg.r;
|
||||
let vertex_index;
|
||||
match direction {
|
||||
AntDirection::ToSecond => vertex_index = edge.vertex2_index,
|
||||
@ -58,7 +83,6 @@ pub fn updateState<Rng: rand::Rng>(
|
||||
}
|
||||
ant.location = AntLocation::OnVertex { vertex_index }
|
||||
}
|
||||
},
|
||||
AntLocation::OnVertex { vertex_index } => {
|
||||
let allowed_outbounds = state.vertices[*vertex_index]
|
||||
.iter()
|
||||
@ -75,8 +99,8 @@ pub fn updateState<Rng: rand::Rng>(
|
||||
return (
|
||||
e.0,
|
||||
(e.2, e.3),
|
||||
e.1.extra.ferment_intensity.powf(ferment_weight)
|
||||
* (1.0 / e.1.length).powf(heuristic_coefficient),
|
||||
e.1.extra.ferment_intensity.powf(cfg.ferment_weight)
|
||||
* (1.0 / e.1.length).powf(cfg.heuristic_coefficient),
|
||||
);
|
||||
})
|
||||
.collect::<Vec<(usize, (usize, AntDirection), f64)>>();
|
||||
@ -84,7 +108,7 @@ pub fn updateState<Rng: rand::Rng>(
|
||||
let mut accumulator: f64 = allowed_outbounds
|
||||
.iter()
|
||||
.fold(0.0, |a, e| a + e.2)
|
||||
.mul(state.rng.random::<f64>());
|
||||
.mul(rng.random::<f64>());
|
||||
let target_vertex_index = allowed_outbounds.iter().find(|e| {
|
||||
accumulator -= e.2;
|
||||
return accumulator <= 0.0;
|
||||
|
||||
137
lab3/src/main.rs
137
lab3/src/main.rs
@ -2,13 +2,18 @@
|
||||
|
||||
mod algo;
|
||||
|
||||
use crate::algo::{AntsSimulationConfig, EdgeExtraData, EdgesVec, VerticesVec};
|
||||
use crate::algo::{
|
||||
Ant, AntsSimulationConfig, AntsSimulationState, EdgeExtraData, EdgesVec, VerticesVec,
|
||||
updateState,
|
||||
};
|
||||
use eframe::egui;
|
||||
use eframe::egui::{Frame, Ui};
|
||||
use eframe::emath::Numeric;
|
||||
use std::cmp::max;
|
||||
use std::collections::HashSet;
|
||||
use std::ops::RangeInclusive;
|
||||
use tsp_utility::gui::lengths_table::{draw_lengths_table, UpdatePending};
|
||||
use tsp_utility::gui::lengths_table::{UpdatePending, draw_lengths_table};
|
||||
use tsp_utility::gui::render::render_graph;
|
||||
|
||||
fn main() -> eframe::Result {
|
||||
let options = eframe::NativeOptions {
|
||||
@ -22,33 +27,29 @@ fn main() -> eframe::Result {
|
||||
)
|
||||
}
|
||||
|
||||
enum ViewState {
|
||||
Stop,
|
||||
Running { lastUpdateTimestamp: u64 },
|
||||
VertexMove { vertexId: usize },
|
||||
}
|
||||
|
||||
enum GlobalState {
|
||||
Edit {},
|
||||
Running { view_state: ViewState },
|
||||
Edit,
|
||||
Running,
|
||||
}
|
||||
|
||||
struct MyApp {
|
||||
edges: EdgesVec,
|
||||
vertices: VerticesVec,
|
||||
simulation: AntsSimulationState,
|
||||
config: AntsSimulationConfig,
|
||||
vertex_update: UpdatePending,
|
||||
speed: u32,
|
||||
state: GlobalState,
|
||||
vertex_locations: Vec<(f32, f32)>,
|
||||
ants_per_vertex: usize,
|
||||
}
|
||||
|
||||
impl Default for MyApp {
|
||||
fn default() -> Self {
|
||||
return Self {
|
||||
simulation: AntsSimulationState {
|
||||
edges: EdgesVec::new(),
|
||||
vertices: VerticesVec::new(),
|
||||
ants: Vec::new(),
|
||||
},
|
||||
vertex_update: UpdatePending::NoChange,
|
||||
speed: 1,
|
||||
config: AntsSimulationConfig {
|
||||
ferment_weight: 0.5,
|
||||
heuristic_coefficient: 0.5,
|
||||
@ -56,6 +57,8 @@ impl Default for MyApp {
|
||||
r: 0.5,
|
||||
},
|
||||
state: GlobalState::Edit {},
|
||||
vertex_locations: Vec::new(),
|
||||
ants_per_vertex: 1,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -85,13 +88,13 @@ impl eframe::App for MyApp {
|
||||
match self.vertex_update {
|
||||
UpdatePending::NoChange => {}
|
||||
UpdatePending::Add => {
|
||||
let new_vi = self.vertices.add(HashSet::new());
|
||||
let new_vi = self.simulation.vertices.add(HashSet::new());
|
||||
let mut newEdgesSet = HashSet::new();
|
||||
for (vi, v) in self.vertices.iter_indexed_mut() {
|
||||
for (vi, v) in self.simulation.vertices.iter_indexed_mut() {
|
||||
if (vi == new_vi) {
|
||||
continue;
|
||||
}
|
||||
let ei = self.edges.add(
|
||||
let ei = self.simulation.edges.add(
|
||||
new_vi,
|
||||
vi,
|
||||
1.0,
|
||||
@ -102,19 +105,20 @@ impl eframe::App for MyApp {
|
||||
newEdgesSet.insert(ei);
|
||||
v.insert(ei);
|
||||
}
|
||||
self.vertices[new_vi] = newEdgesSet;
|
||||
self.simulation.vertices[new_vi] = newEdgesSet;
|
||||
self.vertex_update = UpdatePending::NoChange;
|
||||
}
|
||||
UpdatePending::Remove(vi) => {
|
||||
let mut eis = Vec::with_capacity(self.vertices[vi].len());
|
||||
for ei in self.vertices[vi].iter() {
|
||||
let mut eis = Vec::with_capacity(self.simulation.vertices[vi].len());
|
||||
for ei in self.simulation.vertices[vi].iter() {
|
||||
eis.push(*ei)
|
||||
}
|
||||
for ei in eis {
|
||||
self.vertices[self.edges[ei].another(vi)].remove(&ei);
|
||||
self.edges.remove(ei);
|
||||
self.simulation.vertices[self.simulation.edges[ei].another(vi)]
|
||||
.remove(&ei);
|
||||
self.simulation.edges.remove(ei);
|
||||
}
|
||||
self.vertices.remove(vi);
|
||||
self.simulation.vertices.remove(vi);
|
||||
self.vertex_update = UpdatePending::NoChange;
|
||||
}
|
||||
}
|
||||
@ -140,7 +144,7 @@ impl eframe::App for MyApp {
|
||||
}
|
||||
|
||||
fn edit_panel(data: &mut MyApp, ui: &mut Ui) {
|
||||
let run: bool;
|
||||
let mut run: bool = false;
|
||||
|
||||
_slider(
|
||||
ui,
|
||||
@ -162,30 +166,97 @@ fn edit_panel(data: &mut MyApp, ui: &mut Ui) {
|
||||
ui.label("");
|
||||
_slider(ui, "r", &mut data.config.r, 0.0..=1.0, 0.001);
|
||||
ui.label("");
|
||||
_slider(
|
||||
ui,
|
||||
"Ants per vertex",
|
||||
&mut data.ants_per_vertex,
|
||||
1..=100,
|
||||
1.0,
|
||||
);
|
||||
ui.label("");
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button("Add vertex").clicked() {
|
||||
data.vertex_update = UpdatePending::Add;
|
||||
}
|
||||
ui.separator();
|
||||
let run = ui.button("Run").clicked();
|
||||
run = ui.button("Run").clicked();
|
||||
});
|
||||
|
||||
draw_lengths_table(
|
||||
ui,
|
||||
&mut data.vertices,
|
||||
&mut data.edges,
|
||||
&mut data.simulation.vertices,
|
||||
&mut data.simulation.edges,
|
||||
&mut data.vertex_update,
|
||||
);
|
||||
|
||||
if run {
|
||||
let mut coords = vec![(0.0, 0.0); data.simulation.vertices.capacity()];
|
||||
|
||||
for (i, _) in data.simulation.vertices.iter_indexed() {
|
||||
coords[i] = (
|
||||
rand::random::<f32>() * 0.8 + 0.1,
|
||||
rand::random::<f32>() * 0.8 + 0.1,
|
||||
)
|
||||
}
|
||||
|
||||
fn visualization_panel(data: &mut MyApp, ui: &mut Ui) {
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button("Exit").clicked() {}
|
||||
data.state = GlobalState::Running;
|
||||
data.vertex_locations = coords;
|
||||
|
||||
if ui.button("Pause").clicked() {}
|
||||
let allowed_locations = data
|
||||
.simulation
|
||||
.vertices
|
||||
.iter_indexed()
|
||||
.map(|(i, _)| i)
|
||||
.collect::<HashSet<usize>>();
|
||||
|
||||
let mut ants = Vec::new();
|
||||
for (i, _) in data.simulation.vertices.iter_indexed() {
|
||||
for _ in 0..data.ants_per_vertex {
|
||||
ants.push(Ant::new(i, allowed_locations.clone()))
|
||||
}
|
||||
}
|
||||
data.simulation.ants = ants;
|
||||
}
|
||||
}
|
||||
|
||||
fn visualization_panel(data: &mut MyApp, ui: &mut Ui) {
|
||||
ui.vertical(|ui| {
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button("Exit").clicked() {
|
||||
data.state = GlobalState::Edit
|
||||
}
|
||||
|
||||
if ui.button("Step").clicked() {
|
||||
updateState(&mut data.simulation, &mut data.config, &mut rand::rng());
|
||||
}
|
||||
ui.label("");
|
||||
_slider(ui, "Ant speed", &mut data.speed, 1..=10, 1.0);
|
||||
});
|
||||
draw_ants(data, ui);
|
||||
if ui.input(|i| i.viewport().close_requested()) {
|
||||
data.state = GlobalState::Edit
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn draw_ants(data: &mut MyApp, ui: &mut Ui) {}
|
||||
fn draw_ants(data: &mut MyApp, ui: &mut Ui) {
|
||||
let mut cap: f64 = 0.000000000001;
|
||||
|
||||
for w in data
|
||||
.simulation
|
||||
.edges
|
||||
.iter()
|
||||
.map(|e| e.extra.ferment_intensity)
|
||||
{
|
||||
if w > cap {
|
||||
cap = w
|
||||
}
|
||||
}
|
||||
|
||||
render_graph(
|
||||
ui,
|
||||
&data.simulation.vertices,
|
||||
data.vertex_locations.as_mut_slice(),
|
||||
&data.simulation.edges,
|
||||
|e| e.extra.ferment_intensity / cap,
|
||||
)
|
||||
}
|
||||
|
||||
@ -91,6 +91,10 @@ impl<T> _PreserveIndexVec<T> {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn capacity(&self) -> usize {
|
||||
return self.buffer.len();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Index<usize> for _PreserveIndexVec<T> {
|
||||
|
||||
@ -51,6 +51,10 @@ impl<D> EdgesVec<D> {
|
||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Edge<D>> {
|
||||
return self.data.iter_mut();
|
||||
}
|
||||
|
||||
pub fn capacity(&self) -> usize {
|
||||
return self.data.capacity()
|
||||
}
|
||||
}
|
||||
|
||||
impl <D> Index<usize> for EdgesVec<D> {
|
||||
|
||||
@ -33,6 +33,10 @@ impl VerticesVec {
|
||||
pub fn iter_indexed_mut(&mut self) -> impl Iterator<Item = (usize, &mut HashSet<usize>)> {
|
||||
return self.data.iter_indexed_mut();
|
||||
}
|
||||
|
||||
pub fn capacity(&self) -> usize {
|
||||
return self.data.capacity()
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<usize> for VerticesVec {
|
||||
|
||||
@ -1 +1,2 @@
|
||||
pub mod lengths_table;
|
||||
pub mod render;
|
||||
|
||||
66
tsp-utility/src/gui/render.rs
Normal file
66
tsp-utility/src/gui/render.rs
Normal file
@ -0,0 +1,66 @@
|
||||
use crate::graph::{Edge, EdgesVec, VerticesVec};
|
||||
use eframe::egui::{Color32, Pos2, Rect, Ui};
|
||||
use eframe::epaint::{CornerRadius, Stroke};
|
||||
|
||||
pub fn render_graph<D>(
|
||||
ui: &mut Ui,
|
||||
vertices: &VerticesVec,
|
||||
vertex_locations: &mut [(f32, f32)],
|
||||
edges: &EdgesVec<D>,
|
||||
normalized_intensity: impl Fn(&Edge<D>) -> f64,
|
||||
) {
|
||||
let canvas = ui.painter();
|
||||
let rect = ui.available_size();
|
||||
let start = ui.cursor();
|
||||
|
||||
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() {
|
||||
let p1 = vertex_locations[e.vertex1_index];
|
||||
let p2 = vertex_locations[e.vertex2_index];
|
||||
|
||||
canvas.line_segment(
|
||||
[
|
||||
Pos2::new(
|
||||
p1.0 * rect.width() + rect.min.x,
|
||||
p1.1 * rect.height() + rect.min.y,
|
||||
),
|
||||
Pos2::new(
|
||||
p2.0 * rect.width() + rect.min.x,
|
||||
p2.1 * rect.height() + rect.min.y,
|
||||
),
|
||||
],
|
||||
Stroke::new(1.0, intensity2color(normalized_intensity(e))),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn intensity2color(intensity: f64) -> Color32 {
|
||||
let scale = |base: f64, coefficient: u8| -> u8 {
|
||||
return ((intensity - base) * 5.0 * (coefficient as f64)) as u8;
|
||||
};
|
||||
|
||||
match intensity {
|
||||
f64::NEG_INFINITY..0.2 => {
|
||||
return Color32::from_rgb(
|
||||
50 - scale(0.0, 50),
|
||||
50 - scale(0.0, 50),
|
||||
50 + scale(0.0, 155),
|
||||
);
|
||||
}
|
||||
0.2..0.4 => {
|
||||
return Color32::from_rgb(0, scale(0.2, 255), 255);
|
||||
}
|
||||
0.4..0.6 => {
|
||||
return Color32::from_rgb(0, 255, 255 - scale(0.4, 255));
|
||||
}
|
||||
0.6..0.8 => {
|
||||
return Color32::from_rgb(scale(0.6, 255) as u8, 255, 0);
|
||||
}
|
||||
0.8..f64::INFINITY => {
|
||||
return Color32::from_rgb(255, 255 - scale(0.8, 255), 0);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user