Skip to content

Commit

Permalink
QTPartialHazard slim down
Browse files Browse the repository at this point in the history
  • Loading branch information
JeroenGar committed Feb 7, 2024
1 parent 4171b16 commit df7a0de
Show file tree
Hide file tree
Showing 16 changed files with 69 additions and 81 deletions.
4 changes: 2 additions & 2 deletions jaguars/src/collision_detection/cd_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ impl CDEngine {
GeoRelation::Enclosed => (haz_shape, shape), //inclusion possible
GeoRelation::Disjoint | GeoRelation::Intersecting => {
//no inclusion is possible
return match haz.entity.presence() {
return match haz.entity.position() {
GeoPosition::Interior => false,
GeoPosition::Exterior => true,
}
Expand All @@ -332,7 +332,7 @@ impl CDEngine {
}
let inclusion = s_omega.collides_with(&s_mu.poi().center);

match haz.entity.presence() {
match haz.entity.position() {
GeoPosition::Interior => inclusion,
GeoPosition::Exterior => !inclusion,
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::cmp::Ordering;
use log::{error, warn};
use log::{debug};

use crate::collision_detection::hazard::Hazard;
use crate::geometry::geo_traits::{DistanceFrom, Shape};
Expand Down Expand Up @@ -39,7 +39,7 @@ pub fn generate(bbox: AARectangle, hazards: &[Hazard], target_n_cells: usize) ->
}
}
if n_iters >= 25 {
warn!("grid generation is taking too long, aborting after 25 iterations ({} cells instead of target {})", cells.len(), target_n_cells);
debug!("grid generation is taking too long, aborting after 25 iterations ({} cells instead of target {})", cells.len(), target_n_cells);
break;
}

Expand Down Expand Up @@ -75,7 +75,7 @@ pub fn generate(bbox: AARectangle, hazards: &[Hazard], target_n_cells: usize) ->
fn distance_to_hazard<'a, I>(point: &Point, hazards: I) -> f64 where I: Iterator<Item=&'a Hazard> {
hazards.map(|haz| {
let (pos, prox) = haz.shape.distance_from_border(point);
match pos == haz.entity.presence() {
match pos == haz.entity.position() {
true => -prox, //cell in hazard, negative distance
false => prox
}
Expand Down
6 changes: 3 additions & 3 deletions jaguars/src/collision_detection/haz_prox_grid/hpg_cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl HPGCell {

for hazard in static_hazards {
let (pos, distance) = hazard.shape.distance_from_border(&centroid);
let prox = match pos == hazard.entity.presence() {
let prox = match pos == hazard.entity.position() {
true => Proximity::new(GeoPosition::Interior, distance), //cell in hazard, negative distance
false => Proximity::new(GeoPosition::Exterior, distance)
};
Expand Down Expand Up @@ -74,7 +74,7 @@ impl HPGCell {
let mut bounding_pole_distances: Vec<(&Hazard, Option<Proximity>)> = to_register
.filter(|haz| haz.active)
.map(|haz| {
match haz.entity.presence() {
match haz.entity.position() {
GeoPosition::Exterior => (haz, None), //bounding poles only applicable for hazard inside the shape
GeoPosition::Interior => {
let pole_bounding_circle = &haz.shape.surrogate().poles_bounding_circle;
Expand Down Expand Up @@ -116,7 +116,7 @@ impl HPGCell {
let current_prox = self.universal_hazard_proximity().0;

//For dynamic hazard_filters, the surrogate poles are used to calculate the distance to the hazard (overestimation, but fast)
let haz_prox = match to_register.entity.presence() {
let haz_prox = match to_register.entity.position() {
GeoPosition::Interior => distance_to_surrogate_poles_border(self, &to_register.shape.surrogate().poles),
GeoPosition::Exterior => unreachable!("No implementation yet for dynamic exterior hazards")
};
Expand Down
2 changes: 1 addition & 1 deletion jaguars/src/collision_detection/hazard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub enum HazardEntity {
impl HazardEntity {

/// Returns whether the entity induces an Interior or Exterior hazard
pub fn presence(&self) -> GeoPosition {
pub fn position(&self) -> GeoPosition {
match self {
HazardEntity::PlacedItem(_) => GeoPosition::Interior,
HazardEntity::BinExterior => GeoPosition::Exterior,
Expand Down
30 changes: 10 additions & 20 deletions jaguars/src/collision_detection/quadtree/qt_hazard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::geometry::geo_traits::{CollidesWith, Shape};
use crate::geometry::primitives::aa_rectangle::AARectangle;

//Hazards in a QTNode
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Debug)]
pub struct QTHazard {
pub entity: HazardEntity,
pub presence: QTHazPresence,
Expand Down Expand Up @@ -67,8 +67,7 @@ impl QTHazard {
QTHazPresence::Partial(
QTPartialHazard::new(
partial_haz.shape(),
partial_haz.position(),
EdgeIndices::Some(vec![]),
EdgeIndices::Some(vec![])
)
)
);
Expand Down Expand Up @@ -111,7 +110,7 @@ impl QTHazard {
}
_ => {
let point_to_test = quadrants[i].centroid();
match (partial_haz.position(), shape.collides_with(&point_to_test)) {
match (self.entity.position(), shape.collides_with(&point_to_test)) {
(GeoPosition::Interior, true) => Some(QTHazPresence::Entire),
(GeoPosition::Exterior, false) => Some(QTHazPresence::Entire),
_ => Some(QTHazPresence::None),
Expand Down Expand Up @@ -142,28 +141,19 @@ impl QTHazard {
// 2 | 3
const CHILD_NEIGHBORS: [[usize; 2]; 4] = [[1, 2], [0, 3], [0, 3], [1, 2]];

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Debug)]
pub enum QTHazPresence {
None,
Partial(QTPartialHazard),
Entire
}

impl PartialOrd for QTHazPresence {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
fn to_int(presence: &QTHazPresence) -> u8 {
match presence {
QTHazPresence::None => 0,
QTHazPresence::Partial(_) => 1,
QTHazPresence::Entire => 2,
}
impl Into<u8> for &QTHazPresence {
fn into(self) -> u8 {
match self {
QTHazPresence::None => 0,
QTHazPresence::Partial(_) => 1,
QTHazPresence::Entire => 2,
}
Some(to_int(self).cmp(&to_int(other)))
}
}

impl Ord for QTHazPresence {
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(other).unwrap()
}
}
11 changes: 8 additions & 3 deletions jaguars/src/collision_detection/quadtree/qt_hazard_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,17 @@ impl QTHazardVec {
}

pub fn has_only_entire_hazards(&self) -> bool {
self.hazards.iter().all(|hz| &hz.presence == &QTHazPresence::Entire)
self.hazards.iter().all(|hz| matches!(hz.presence,QTHazPresence::Entire))
}

fn order_stronger(qth1: &QTHazard, qth2: &QTHazard) -> Ordering {
//sort by active, then by presence, so that the active hazards are always in front of inactive hazards, and Entire hazards are always in front of Partial hazards
(qth1.active.cmp(&qth2.active).reverse())
.then(qth1.presence.cmp(&qth2.presence).reverse())
match qth1.active.cmp(&qth2.active).reverse() {
Ordering::Equal => {
let (p1,p2): (u8, u8) = ((&qth1.presence).into(), (&qth2.presence).into());
p1.cmp(&p2).reverse()
},
other => other,
}
}
}
48 changes: 16 additions & 32 deletions jaguars/src/collision_detection/quadtree/qt_partial_hazard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ use std::sync::{Arc, Weak};

use crate::collision_detection::hazard::Hazard;
use crate::geometry::geo_enums::GeoPosition;
use crate::geometry::geo_traits::CollidesWith;
use crate::geometry::geo_traits::{CollidesWith, Shape};
use crate::geometry::primitives::circle::Circle;
use crate::geometry::primitives::edge::Edge;
use crate::geometry::primitives::simple_polygon::SimplePolygon;


/// QTPartialHazards define a set of edges from a hazard that cross the QTNode.
#[derive(Clone, Debug)]
pub struct QTPartialHazard {
shape: Weak<SimplePolygon>,
position: GeoPosition,
edge_indices: EdgeIndices,
}

Expand All @@ -26,18 +27,16 @@ impl<T> From<T> for QTPartialHazard where T: Borrow<Hazard> {
fn from(hazard: T) -> Self {
Self {
shape: Arc::downgrade(&hazard.borrow().shape),
position: hazard.borrow().entity.presence(),
edge_indices: EdgeIndices::All,
}
}
}

impl QTPartialHazard {

pub fn new(shape: Arc<SimplePolygon>, presence: GeoPosition, edge_indices: EdgeIndices) -> Self {
pub fn new(shape: Arc<SimplePolygon>, edge_indices: EdgeIndices) -> Self {
Self {
shape: Arc::downgrade(&shape),
position: presence,
edge_indices,
}
}
Expand All @@ -50,10 +49,6 @@ impl QTPartialHazard {
self.shape.upgrade().expect("polygon reference is not alive")
}

pub fn position(&self) -> GeoPosition {
self.position
}

pub fn edge_indices(&self) -> &EdgeIndices{
&self.edge_indices
}
Expand All @@ -72,15 +67,17 @@ impl QTPartialHazard {
}

}

impl CollidesWith<Edge> for QTPartialHazard {
fn collides_with(&self, edge: &Edge) -> bool {
let shape = self.shape.upgrade().expect("polygon reference is not alive");
match self.edge_indices() {
EdgeIndices::All => {
shape.edge_iter().any(|e| {
edge.collides_with(&e)
})
match shape.bbox().collides_with(edge) {
false => false,
true => shape.edge_iter().any(|e| {
edge.collides_with(&e)
})
}
},
EdgeIndices::Some(indices) => {
indices.iter().any(|&i| {
Expand All @@ -96,9 +93,12 @@ impl CollidesWith<Circle> for QTPartialHazard {
let shape = self.shape.upgrade().expect("polygon reference is not alive");
match self.edge_indices() {
EdgeIndices::All => {
shape.edge_iter().any(|e| {
circle.collides_with(&e)
})
match circle.collides_with(&shape.bbox()) {
false => false,
true => shape.edge_iter().any(|e| {
circle.collides_with(&e)
})
}
},
EdgeIndices::Some(indices) => {
indices.iter().any(|&i| {
Expand All @@ -108,19 +108,3 @@ impl CollidesWith<Circle> for QTPartialHazard {
}
}
}

impl PartialEq for QTPartialHazard {
fn eq(&self, other: &Self) -> bool {
self.position == other.position &&
self.edge_indices == other.edge_indices
}
}

impl Eq for QTPartialHazard {}

impl Hash for QTPartialHazard {
fn hash<H: Hasher>(&self, state: &mut H) {
self.position.hash(state);
self.edge_indices.hash(state);
}
}
8 changes: 5 additions & 3 deletions jaguars/src/util/assertions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,12 +246,14 @@ fn qt_nodes_match(qn1: Option<&QTNode>, qn2: Option<&QTNode>) -> bool {
let hv1 = qn1.hazards();
let hv2 = qn2.hazards();

//collect active hazard_filters to hashsets
//collect active hazards to hashsets
let active_haz_1 = hv1.active_hazards().iter()
.collect::<HashSet<_>>();
.map(|h| (&h.entity, h.active, (&h.presence).into()))
.collect::<HashSet<(&HazardEntity, bool, u8)>>();

let active_haz_2 = hv2.active_hazards().iter()
.collect::<HashSet<_>>();
.map(|h| (&h.entity, h.active, (&h.presence).into()))
.collect::<HashSet<(&HazardEntity, bool, u8)>>();

let active_in_1_but_not_2 = active_haz_1.difference(&active_haz_2).collect::<HashSet<_>>();
let active_in_2_but_not_1 = active_haz_2.difference(&active_haz_1).collect::<HashSet<_>>();
Expand Down
16 changes: 11 additions & 5 deletions lbf/benches/fast_fail_bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use lbf::io;
use lbf::io::layout_to_svg::layout_to_svg;
use lbf::io::svg_util::SvgDrawOptions;
use lbf::lbf_optimizer::LBFOptimizer;
use lbf::samplers::hpg_sampler::HPGSampler;
use lbf::samplers::uniform_rect_sampler::UniformAARectSampler;
use crate::util::{create_base_config, N_ITEMS_REMOVED, N_SAMPLES, SWIM_PATH};

Expand Down Expand Up @@ -77,10 +78,15 @@ fn fast_fail_query_bench(c: &mut Criterion) {
}).collect_vec();

let layout = problem.get_layout(LayoutIndex::Existing(0));
let sampler = UniformAARectSampler::new(layout.bin().bbox(), instance.item(0));
let samples = (0..N_SAMPLES).map(
|_| sampler.sample(&mut rng).compose()
).collect_vec();
let samples = (0..N_ITEMS_REMOVED)
.map(|i| selected_pi_uids[i].item_id)
.map(|item_id| {
let item = instance.item(item_id);
let sampler = HPGSampler::new(item, layout).unwrap();
(0..N_SAMPLES).map(
|_| sampler.sample(&mut rng)
).collect_vec()
}).collect_vec();

let mut n_invalid: i64 = 0;
let mut n_valid : i64 = 0;
Expand All @@ -92,7 +98,7 @@ fn fast_fail_query_bench(c: &mut Criterion) {
let item = instance.item(pi_uid.item_id);
let surrogate = &custom_surrogates[i];
let mut buffer_shape = item.shape().clone();
for transf in &samples {
for transf in samples[i].iter() {
let collides = match layout.cde().surrogate_collides(surrogate, transf, &[]) {
true => true,
false => {
Expand Down
6 changes: 4 additions & 2 deletions lbf/benches/quadtree_bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ use lbf::samplers::uniform_rect_sampler::UniformAARectSampler;
use crate::util::{create_base_config, N_ITEMS_REMOVED, N_SAMPLES, SWIM_PATH};

criterion_main!(benches);
criterion_group!(benches, quadtree_query_update_1000_1, quadtree_query_bench, quadtree_update_bench);
//criterion_group!(benches, quadtree_query_update_1000_1, quadtree_query_bench, quadtree_update_bench);
criterion_group!(benches,quadtree_query_bench);


mod util;

Expand Down Expand Up @@ -121,7 +123,7 @@ fn quadtree_query_bench(c: &mut Criterion) {
}
})
});
println!("n_invalid: {}, n_valid: {}", n_invalid, n_valid);
println!("valid: {:.3}%", n_valid as f64 / (n_valid + n_invalid) as f64 * 100.0);
}
group.finish();
}
Expand Down
6 changes: 3 additions & 3 deletions lbf/benches/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ use lbf::lbf_optimizer::LBFOptimizer;

pub const SWIM_PATH: &str = "../assets/swim.json";
pub const N_ITEMS_REMOVED: usize = 5;
pub const N_SAMPLES: usize = 10000;
pub const N_SAMPLES: usize = 10_000;

pub const N_VALID_SAMPLES: usize = 10000;
pub const N_VALID_SAMPLES: usize = 10_000;

pub fn create_instance(json_instance: &JsonInstance, cde_config: CDEConfig, poly_simpl_config: PolySimplConfig) -> Arc<Instance> {
let parser = Parser::new(poly_simpl_config, cde_config, true);
Expand Down Expand Up @@ -58,7 +58,7 @@ pub fn create_blf_problem(instance: Arc<Instance>, config: Config, n_items_remov

{
let draw_options = SvgDrawOptions{
quadtree: false,
quadtree: true,
surrogate: false,
haz_prox_grid: false,
..SvgDrawOptions::default()
Expand Down
1 change: 1 addition & 0 deletions lbf/src/lbf_optimizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub struct LBFOptimizer {
instance: Arc<Instance>,
problem: ProblemEnum,
config: Config,
/// SmallRng is a fast, non-crypographic PRNG https://rust-random.github.io/book/guide-rngs.html
rng: SmallRng,
}

Expand Down
2 changes: 1 addition & 1 deletion lbf/src/samplers/hpg_sampler.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use itertools::Itertools;
use log::{debug};

use rand::prelude::{SliceRandom, SmallRng};
use rand::prelude::{SliceRandom};
use rand::Rng;

use jaguars::entities::item::Item;
Expand Down
1 change: 0 additions & 1 deletion lbf/src/samplers/ls_sampler.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use rand::distributions::Distribution;
use rand::prelude::SmallRng;
use rand::Rng;
use rand_distr::Normal;

Expand Down
Loading

0 comments on commit df7a0de

Please sign in to comment.