diff --git a/src/list/raxos/evolution/src/contour.rs b/src/list/raxos/evolution/src/contour.rs index fabb516..375becb 100644 --- a/src/list/raxos/evolution/src/contour.rs +++ b/src/list/raxos/evolution/src/contour.rs @@ -1,5 +1,6 @@ use std::fmt; +use crate::display_slice::DisplaySliceExt; use crate::point::Point; pub struct CC<'a>(pub &'a Contour, pub usize); @@ -20,12 +21,7 @@ pub struct Contour { impl fmt::Display for Contour { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for (i, p) in self.points.iter().enumerate() { - if i > 0 { - write!(f, ", ")?; - } - write!(f, "{}", p)?; - } + write!(f, "{}", self.points.display_n::<30>())?; Ok(()) } } @@ -41,17 +37,17 @@ 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) -> Self { + pub fn rand_update(&self, prob_move: f64, prob_add: f64, mut prob_remove: f64) -> Self { let l = self.points.len(); - // Generate a rand number between 0 and 1 - let mut rand = rand::random::(); - if l <= 3 { // always move - rand = 0.0; + prob_remove = 0.0; } + // Generate a rand number between 0 and 1 + let mut rand = rand::random::() * (prob_move + prob_add + prob_remove); + if rand < prob_move { // move a point let i = (rand::random::() as usize) % self.points.len(); @@ -84,73 +80,85 @@ impl Contour { let mut points = self.points.clone(); - let p = Point::new( - rand::random::() * (x_right - x_left) + x_left, - rand::random::() * (y_high - y_low) + y_low, - ); + let x = rand::random::() * (x_right - x_left) + x_left; + let y = rand::random::() * (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); } points[i] = p; Self { points } - } else { - let add_remove = rand::random::(); - if add_remove > 0.5 { - // Add a new point - - // The index of point before which to add new point - let i = (rand::random::() 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) - } else if i == self.points.len() { - let left_sibling = self.points[i - 1].x; - (left_sibling, (left_sibling * 1.5f64)) - } else { - (self.points[i - 1].x, self.points[i].x) - }; - - let (y_low, y_high) = if i == 0 { - let right_sibling = self.points[i].y; - (right_sibling, (right_sibling * 1.5f64)) - } else if i == self.points.len() { - let last = self.points[i - 1].y; - (0.0, last) - } else { - (self.points[i].y, self.points[i - 1].y) - }; - - let mut points = self.points.clone(); - let p = Point::new( - rand::random::() * (x_right - x_left) + x_left, - rand::random::() * (y_high - y_low) + y_low, - ); - // println!("Add point {}/{l} at {}", i, p); - if i == l { - println!("Add point {}/{l} at {}", i, p); - } - points.insert(i, p); - Self { points } + } else if rand < prob_move + prob_add { + // Add a new point + + // The index of point before which to add new point + let i = (rand::random::() 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) + } else if i == self.points.len() { + let left_sibling = self.points[i - 1].x; + (left_sibling, (left_sibling * 1.5f64)) } else { - // remove a point - let i = (rand::random::() as usize) % self.points.len(); - if self.points[i] == Point::new(1f64, 1f64) { - // The unit point should not be removed - return self.clone(); - } - - 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[i - 1].x, self.points[i].x) + }; + + let x = rand::random::() * (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::() * (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 } + } else { + // remove a point + let i = (rand::random::() as usize) % self.points.len(); + if self.points[i] == Point::new(1f64, 1f64) { + // The unit point should not be removed + return self.clone(); } + + 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 } } } @@ -202,8 +210,9 @@ impl Contour { .is_some()); for i in 1..self.points.len() { - assert!(self.points[i - 1].x < self.points[i].x); - assert!(self.points[i - 1].y > self.points[i].y); + assert!(self.points[i - 1].x < self.points[i].x, "{:?}", self.points); + + assert!(self.points[i - 1].y > self.points[i].y, "{:?}", self.points); } } } diff --git a/src/list/raxos/evolution/src/main.rs b/src/list/raxos/evolution/src/main.rs index 00af7c3..5e4e37b 100644 --- a/src/list/raxos/evolution/src/main.rs +++ b/src/list/raxos/evolution/src/main.rs @@ -1,5 +1,4 @@ use plotters::prelude::*; -use plotters::prelude::*; use point::Point; use scene::Scene; @@ -50,38 +49,77 @@ impl Evolution { contour.cross_product_x(&b_in_normalized_by_a) < 0f64 } - /// Count the number of conflicting point pairs - pub fn count_conflict(&self, contour: &Contour) -> usize { + /// Count the number of conflicting point pairs. + /// + /// Return the total number of conflicts and list of conflict count for each point, + /// sorted by conflict count. + pub fn count_conflict(&self, contour: &Contour) -> (usize, Vec<(usize, usize)>) { contour.validate(); + let mut per_point_count = vec![0; self.points_len()]; + let mut conflicts = 0; for i in 0..self.points_len() { for j in (i + 1)..self.points_len() { if self.is_below(i, j, contour) && self.is_below(j, i, contour) || self.is_above(i, j, contour) && self.is_above(j, i, contour) { + per_point_count[i] += 1; + per_point_count[j] += 1; conflicts += 1; + + println!( + "conflict: {} {} and {} {}", + i, self.scene.points[i], j, self.scene.points[j] + ); + + println!("normalize to a: {}", self.normalized[i].points[j]); + println!("normalize to b: {}", self.normalized[j].points[i]); + + panic!("wow") } } } - conflicts + let mut per_point_count = per_point_count + .into_iter() + .enumerate() + .map(|(point_index, count)| (count, point_index)) + .filter(|(count, _)| *count > 0) + .collect::>(); + per_point_count.sort_by(|a, b| b.0.cmp(&a.0)); + // println!( + // "conflict count: {} {:?}", + // per_point_count.len(), + // per_point_count + // ); + + (conflicts, per_point_count) } - /// Eliminate half of the contours that have the most conflicts + /// Eliminate the contours that have the most conflicts pub fn eliminates(&self, contour: Vec) -> Vec { let n = contour.len(); - let mut cc = contour - .into_iter() - .map(|c| (c.clone(), self.count_conflict(&c))) - .collect::>(); + let mut contour_and_conflict = vec![]; + for c in contour { + let (conflicts, count_and_point_index) = self.count_conflict(&c); + contour_and_conflict.push((c, conflicts)); + } - cc.sort_by(|a, b| a.1.cmp(&b.1)); - for x in cc.iter() { + contour_and_conflict.sort_by(|a, b| a.1.cmp(&b.1)); + for x in contour_and_conflict.iter().take(10) { println!("rank: {}: {}", x.1, x.0); } - cc.into_iter().take(3).map(|(c, _)| c).collect() + // Keep the first several contours that have less than 120% of the conflicts of the first contour + let first_rank = contour_and_conflict[0].1; + + contour_and_conflict + .into_iter() + .take_while(|(c, r)| *r < first_rank * 120 / 100) + .take(8) + .map(|(c, _)| c) + .collect() } pub fn evolve(&self, contour: Contour, round: usize) -> Contour { @@ -97,6 +135,7 @@ impl Evolution { draw_contour(format!("{pref}-0000.png"), &self.scene, &cc[0]).unwrap(); for i in 1..=round { + println!("round {}", i); cc = self.eliminates(cc); draw_contour(format!("{pref}-{i:0>4}.png"), &self.scene, &cc[0]).unwrap(); @@ -104,7 +143,7 @@ impl Evolution { let new_cc = cc .iter() .cycle() - .map(|c| c.rand_update(0.7)) + .map(|c| c.rand_update(7.0, 7.0, 7.0)) .take(n_spawn) .collect::>(); cc.extend(new_cc); @@ -126,10 +165,24 @@ fn main() -> Result<(), Box> { let c = contour([(0.5, 1.5), (1.0, 1.0), (1.5, 0.5)]); + let mut ps = (0..200) + .map(|_| { + let x = rand::random::() * 10f64; + let y = 1.0 / x; + (x, y) + }) + .chain([(1.0, 1.0)]) + .collect::>(); + + ps.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(std::cmp::Ordering::Equal)); + println!("{:?}", ps); + + let c = contour(ps); + let scene = Scene::rand_scene(10f64, 10f64, 200); let evolution = Evolution::new(scene); - let got = evolution.evolve(c, 500); + let got = evolution.evolve(c, 1_000); // draw_contour("contour.png", &scene, &c)?; Ok(()) diff --git a/src/list/raxos/evolution/src/point.rs b/src/list/raxos/evolution/src/point.rs index 6b9cf11..737b026 100644 --- a/src/list/raxos/evolution/src/point.rs +++ b/src/list/raxos/evolution/src/point.rs @@ -10,7 +10,7 @@ pub struct Point { impl fmt::Display for Point { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "({:.4}, {:.4})", self.x, self.y) + write!(f, " {:.3}={:.3}x{:.3}", self.x * self.y, self.x, self.y) } } diff --git a/src/list/raxos/evolution/src/scene.rs b/src/list/raxos/evolution/src/scene.rs index 1379f09..36e04bc 100644 --- a/src/list/raxos/evolution/src/scene.rs +++ b/src/list/raxos/evolution/src/scene.rs @@ -13,7 +13,9 @@ impl Scene { pub fn rand_scene(x: f64, y: f64, n: usize) -> Scene { let mut scene = Scene::new(); for _ in 0..n { - scene.add_point(rand::random::() * x, rand::random::() * y); + let xx = rand::random::() * x; + let yy = rand::random::() * y; + scene.add_point(xx, yy); } scene }