Skip to content

Commit

Permalink
bkp: contour per point
Browse files Browse the repository at this point in the history
A contour is bound to a point, and only use this contour to compare this
point with other point.

This result in a solution every contour just does not have touch.
Not enough
  • Loading branch information
drmingdrmer committed Sep 8, 2024
1 parent 57f548a commit 4eb576b
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 94 deletions.
101 changes: 39 additions & 62 deletions src/list/raxos/evolution/src/contour.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,6 @@ use std::fmt;
use crate::display_slice::DisplaySliceExt;
use crate::point::Point;

pub struct CC<'a>(pub &'a Contour, pub usize);

impl<'a> fmt::Display for CC<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}:{}", self.1, self.0)
}
}

/// The Contour line of all the points that have the same value
///
/// This is not an accurate line.
Expand All @@ -37,14 +29,24 @@ impl Contour {
///
/// `prob_move` is the chance of moving a point.
/// `1 - prob_move` is the chance of adding a new point.
pub fn rand_update(&self, prob_move: f64, prob_add: f64, mut prob_remove: f64) -> Self {
pub fn rand_update(
&self,
prob_move: f64,
mut prob_add: f64,
mut prob_remove: f64,
) -> (Self, String) {
let l = self.points.len();

if l <= 3 {
// always move
prob_remove = 0.0;
}

if l >= 20 {
// always remove
prob_add = 0.0;
}

// Generate a rand number between 0 and 1
let mut rand = rand::random::<f64>() * (prob_move + prob_add + prob_remove);

Expand All @@ -53,11 +55,9 @@ impl Contour {
let i = (rand::random::<u64>() as usize) % self.points.len();
if self.points[i] == Point::new(1f64, 1f64) {
// The unit point should not be moved
return self.clone();
return (self.clone(), "Nothing".to_string());
}

let p0 = self.points[i];

let (x_left, x_right) = if i == 0 {
let right_sibling = self.points[i + 1].x;
(0.0, right_sibling)
Expand All @@ -83,82 +83,59 @@ impl Contour {
let x = rand::random::<f64>() * (x_right - x_left) + x_left;
let y = rand::random::<f64>() * (y_high - y_low) + y_low;
let p = Point::new(x, y);
// println!("Move point {}/{l} {} to {}", i, p0, p);
// if i == l - 1 {
// println!("Move point {}/{l} {} to {}", i, p0, p);
// }

let p0 = points[i];
points[i] = p;
Self { points }
(Self { points }, format!("Move {i}: from {p0} to {p}"))
} else if rand < prob_move + prob_add {
// Add a new point

let p1 = Point::new(1f64, 1f64);
let position = self.points.iter().position(|p| *p == p1).unwrap();

let i = loop {
let i = (rand::random::<u64>() as usize) % (self.points.len() + 1);
if i > position && position < l / 2 || i <= position && position >= l / 2 {
// The unit point should not be moved
continue;
}

break i;
};

// The index of point before which to add new point
let i = (rand::random::<u64>() as usize) % (self.points.len() + 1);

let (x_left, x_right) = if i == 0 {
let right_sibling = self.points[i].x;
(0.0, right_sibling)
let (x_left, x_right, y_low, y_high) = if i == 0 {
let right = self.points[i];
(0.0, right.x, right.y, right.y * 1.5)
} else if i == self.points.len() {
let left_sibling = self.points[i - 1].x;
(left_sibling, (left_sibling * 1.5f64))
let left = self.points[i - 1];
(left.x, left.x * 1.5, 0.0, left.y)
} else {
(self.points[i - 1].x, self.points[i].x)
let left = self.points[i - 1];
let right = self.points[i];
(left.x, right.x, right.y, left.y)
};

let x = rand::random::<f64>() * (x_right - x_left) + x_left;

// let (frm, to) = if i == 0 {
// let frm = self.points[1];
// let to = self.points[0];
// (frm, to)
// } else if i == l {
// let fmt = self.points[l - 2];
// let to = self.points[l - 1];
// (fmt, to)
// } else {
// let frm = self.points[i - 1];
// let to = self.points[i];
// (frm, to)
// };
//
// let y = (to.y - frm.y) / (to.x - frm.x) * (x - frm.x) + frm.y;

let (y_low, y_high) = if i == 0 {
let right_sibling = self.points[i].y;
(right_sibling, (right_sibling * 1.5f64))
} else if i == l {
let last = self.points[i - 1].y;
(0.0, last)
} else {
(self.points[i].y, self.points[i - 1].y)
};
let y = rand::random::<f64>() * (y_high - y_low) + y_low;

let mut points = self.points.clone();
let p = Point::new(x, y);
// println!("Add point {}/{l} at {}", i, p);
// if i == l {
// println!("Add point {}/{l} at {}", i, p);
// }
points.insert(i, p);
Self { points }
(Self { points }, format!("Add {p} before {i}"))
} else {
// remove a point
let i = (rand::random::<u64>() as usize) % self.points.len();
if self.points[i] == Point::new(1f64, 1f64) {
// The unit point should not be removed
return self.clone();
return (self.clone(), "Nothing".to_string());
}

let mut points = self.points.clone();
// println!("Remove point at {}/{l} {}", i, points[i]);

// if i == l - 1 {
// println!("Remove point at {}/{l} {}", i, points[i]);
// }

points.remove(i);
Self { points }
(Self { points }, format!("Remove {i}"))
}
}

Expand Down
84 changes: 52 additions & 32 deletions src/list/raxos/evolution/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::collections::BTreeMap;

use plotters::prelude::*;

use config::Config;
Expand Down Expand Up @@ -25,7 +27,7 @@ pub struct Evolution {
contours: Vec<Contour>,

/// (point index, point conflict)
point_conflicts: Vec<(usize, usize)>,
contour_conflicts: BTreeMap<usize, usize>,
}

impl Evolution {
Expand All @@ -38,14 +40,15 @@ impl Evolution {

let contours = scene.points.iter().map(build_contour).collect::<Vec<_>>();

let point_conflicts = (0..scene.points.len()).map(|i| (i, 0)).collect::<Vec<_>>();
let n = scene.points.len();
let point_conflicts = (0..scene.points.len()).map(|i| (i, n)).collect();

Self {
config,
scene,
normalized,
contours,
point_conflicts,
contour_conflicts: point_conflicts,
}
}

Expand All @@ -71,6 +74,11 @@ impl Evolution {
contour.cross_product_x(&b_in_normalized_by_a) < 0f64
}

pub fn product(&self, unit: usize, p: usize, contour: &Contour) -> f64 {
let b_in_normalized_by_a = self.normalized[unit].points[p];
contour.cross_product_x(&b_in_normalized_by_a)
}

/// Count the number of conflicting point pairs.
///
/// Return the total number of conflicts found for point `p`, using contour `contour`.
Expand All @@ -83,11 +91,18 @@ impl Evolution {
continue;
}

if self.is_below(p, i, contour) && self.is_below(i, p, &self.contours[i])
|| self.is_above(p, i, contour) && self.is_above(i, p, &self.contours[i])
{
let product_at_p = self.product(p, i, contour);
let product_at_i = self.product(i, p, &self.contours[i]);

if product_at_p * product_at_i > 0.0 {
conflicts += 1;
}

// if self.is_below(p, i, contour) && self.is_below(i, p, &self.contours[i])
// || self.is_above(p, i, contour) && self.is_above(i, p, &self.contours[i])
// {
// conflicts += 1;
// }
}
conflicts
}
Expand All @@ -101,18 +116,20 @@ impl Evolution {
let conflict = self.count_conflict(p, &contour);

let mut best = (contour.clone(), conflict);
if best.1 == 0 {
return best;
}
// if best.1 == 0 {
// return best;
// }
// println!("optimize: init: {} {}", best.1, best.0);

for _i in 0..self.config.n_spawn {
let new = contour.rand_update(w.0, w.1, w.2);
let (new, action) = contour.rand_update(w.0, w.1, w.2);
let conflict = self.count_conflict(p, &new);

// Find the first better solution
if conflict < best.1 {
return (new, conflict);
println!("point-{p} optimize action: {}", action);
println!("point-{p} contour: {}: {}", conflict, new);
best = (new, conflict);
}
}

Expand All @@ -121,18 +138,17 @@ impl Evolution {
}

pub fn evolve_one_round(&mut self) {
let mut next_generation = vec![];
let mut point_conflict = vec![];
for (p, _old_conflict) in self.point_conflicts.iter() {
let mut next_generation = self.contours.clone();
let mut contour_conflicts = BTreeMap::new();

for (p, _old_conflict) in self.contour_conflicts.iter().rev() {
let (new_contour, new_conflict) = self.find_better_contour(*p);
next_generation.push(new_contour);
point_conflict.push((*p, new_conflict));
next_generation[*p] = new_contour;
contour_conflicts.insert(*p, new_conflict);
}

self.contours = next_generation;
point_conflict.sort_by(|a, b| b.1.cmp(&a.1));
self.point_conflicts = point_conflict;
println!("point_conflicts: {:?}", self.point_conflicts);
self.contour_conflicts = contour_conflicts;
}

pub fn evolve(&mut self) {
Expand All @@ -152,6 +168,10 @@ impl Evolution {
if t0.elapsed().as_secs() > 1 {
t0 = std::time::Instant::now();
draw_contour(format!("{pref}-{i:0>4}.png"), &self.scene, &self.contours).unwrap();

for (i, x) in self.contours.iter().enumerate() {
println!("point-{i} contour: {}: {}", self.contour_conflicts[&i], x);
}
}
// draw_contour(format!("{pref}-{i:0>4}.png"), &self.scene, &self.contours).unwrap();
}
Expand All @@ -166,10 +186,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let c = contour([(0.5, 1.5), (1.0, 1.0), (1.5, 0.5)]);

let config = Config {
n_points_per_scene: 1000,
n_round: 1_000,
n_spawn: 1_000,
variant_weight: (5.0, 10.0, 5.0),
n_points_per_scene: 200,
n_round: 10_000,
n_spawn: 50,
variant_weight: (5.0, 5.0, 5.0),
};
let scene = Scene::rand_scene(10f64, 10f64, config.n_points_per_scene);

Expand All @@ -186,7 +206,7 @@ fn draw_contour(
) -> Result<(), Box<dyn std::error::Error>> {
let path = path.to_string();
// 创建一个800x600像素的PNG文件
let root = BitMapBackend::new(&path, (800, 600)).into_drawing_area();
let root = BitMapBackend::new(&path, (400, 400)).into_drawing_area();
root.fill(&WHITE)?;

// 创建图表上下文
Expand All @@ -195,17 +215,17 @@ fn draw_contour(
.margin(5)
.x_label_area_size(30)
.y_label_area_size(30)
.build_cartesian_2d(0f64..10f64, 0f64..10f64)?;
.build_cartesian_2d(0f64..5f64, 0f64..5f64)?;

// 配置坐标轴
chart.configure_mesh().draw()?;

// Scene
let ps = scene
.points
.iter()
.map(|p| Circle::new((p.x, p.y), 3, &BLUE.mix(0.5)));
chart.draw_series(ps)?;
// // Scene
// let ps = scene
// .points
// .iter()
// .map(|p| Circle::new((p.x, p.y), 3, &BLUE.mix(0.5)));
// chart.draw_series(ps)?;

let l = contours.len() as f64;
for (i, contour) in contours.iter().enumerate() {
Expand All @@ -215,7 +235,7 @@ fn draw_contour(
let ps = contour
.points
.iter()
.map(|p| Circle::new((p.x, p.y), 3, &color.mix(0.5)));
.map(|p| Circle::new((p.x, p.y), 1, &color.mix(0.5)));
chart.draw_series(ps)?;
}

Expand Down

0 comments on commit 4eb576b

Please sign in to comment.