Skip to content

Commit

Permalink
backup: one-contour algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
drmingdrmer committed Sep 8, 2024
1 parent d180d30 commit 1a02514
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 88 deletions.
153 changes: 81 additions & 72 deletions src/list/raxos/evolution/src/contour.rs
Original file line number Diff line number Diff line change
@@ -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);
Expand All @@ -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(())
}
}
Expand All @@ -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::<f64>();

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::<f64>() * (prob_move + prob_add + prob_remove);

if rand < prob_move {
// move a point
let i = (rand::random::<u64>() as usize) % self.points.len();
Expand Down Expand Up @@ -84,73 +80,85 @@ impl Contour {

let mut points = self.points.clone();

let p = Point::new(
rand::random::<f64>() * (x_right - x_left) + x_left,
rand::random::<f64>() * (y_high - y_low) + y_low,
);
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);
}
points[i] = p;
Self { points }
} else {
let add_remove = rand::random::<f64>();
if add_remove > 0.5 {
// Add a new point

// 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)
} 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::<f64>() * (x_right - x_left) + x_left,
rand::random::<f64>() * (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::<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)
} 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::<u64>() 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::<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 }
} 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();
}

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

Expand Down Expand Up @@ -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);
}
}
}
Expand Down
81 changes: 67 additions & 14 deletions src/list/raxos/evolution/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use plotters::prelude::*;
use plotters::prelude::*;

use point::Point;
use scene::Scene;
Expand Down Expand Up @@ -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::<Vec<_>>();
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<Contour>) -> Vec<Contour> {
let n = contour.len();

let mut cc = contour
.into_iter()
.map(|c| (c.clone(), self.count_conflict(&c)))
.collect::<Vec<_>>();
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 {
Expand All @@ -97,14 +135,15 @@ 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();

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::<Vec<_>>();
cc.extend(new_cc);
Expand All @@ -126,10 +165,24 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {

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::<f64>() * 10f64;
let y = 1.0 / x;
(x, y)
})
.chain([(1.0, 1.0)])
.collect::<Vec<_>>();

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(())
Expand Down
2 changes: 1 addition & 1 deletion src/list/raxos/evolution/src/point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/list/raxos/evolution/src/scene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<f64>() * x, rand::random::<f64>() * y);
let xx = rand::random::<f64>() * x;
let yy = rand::random::<f64>() * y;
scene.add_point(xx, yy);
}
scene
}
Expand Down

0 comments on commit 1a02514

Please sign in to comment.