Introduce Label for search within id

This allows to define a volume using an indexed object.
This commit is contained in:
2019-11-18 11:21:44 +01:00
parent 0dc31c65c6
commit e2ea5c9ba4
8 changed files with 128 additions and 60 deletions

View File

@@ -19,6 +19,7 @@ bag_expression
// Spatial Operators
| inside
| outside
//| shape
;
/**********************************************************************/
@@ -113,6 +114,11 @@ inside
: 'inside' '(' shapes ')'
;
/* Returns the set of positions inside the shape, (face included) */
shape
: 'shape' '(' shapes ')'
;
/**********************************************************************/
/* SHAPES */
/**********************************************************************/

View File

@@ -18,7 +18,7 @@ projection_operators
*
* If it is provided, it MUST resolve to a NUMBER. */
nifti_operator
: 'nifti' '(' ( STRING ',' )? ( selector ',' )? bag_expression ')'
: 'nifti' '(' ( selector ',' )? bag_expression ( ',' STRING )? ')'
;
json_operator

View File

@@ -80,33 +80,68 @@ fn distinct<'c>(
}
}
}
fn filter_helper<'c>(
predicate: &Predicate,
bag: &Bag,
core_id: &str,
parameters: &CoreQueryParameters<'c>,
) -> mercator_db::ResultSet<'c> {
match bag.execute(core_id, parameters) {
e @ Err(_) => e,
Ok(results) => Ok(results
.into_iter()
.filter_map(|(space, positions)| {
let filtered = positions
.into_iter()
.filter(|(position, properties)| predicate.eval((space, position, properties)))
.collect::<Vec<_>>();
if filtered.is_empty() {
None
} else {
Some((space, filtered))
}
})
.collect::<Vec<_>>()),
}
}
fn filter<'c>(
core_id: &str,
parameters: &CoreQueryParameters<'c>,
predicate: &Option<Predicate>,
bag: &Bag,
bag: &Option<Box<Bag>>,
) -> mercator_db::ResultSet<'c> {
match predicate {
None => bag.execute(core_id, parameters),
Some(predicate) => match bag.execute(core_id, parameters) {
e @ Err(_) => e,
Ok(results) => Ok(results
.into_iter()
.filter_map(|(space, positions)| {
let filtered = positions
.into_iter()
.filter(|(position, properties)| {
predicate.eval((space, position, properties))
})
.collect::<Vec<_>>();
if filtered.is_empty() {
None
} else {
Some((space, filtered))
}
})
.collect::<Vec<_>>()),
None => {
if let Some(bag) = bag {
bag.execute(core_id, parameters)
} else {
Err("Filter without predicate nor data set.".to_string())
}
}
Some(predicate) => match bag {
None => {
let (low, high) = space::Space::universe().bounding_box();
let low: Vec<_> = low.into();
let high: Vec<_> = high.into();
let shape = Shape::HyperRectangle(
space::Space::universe().name().clone(),
vec![
LiteralPosition(
low.into_iter()
.map(LiteralNumber::Float)
.collect::<Vec<_>>(),
),
LiteralPosition(
high.into_iter()
.map(LiteralNumber::Float)
.collect::<Vec<_>>(),
),
],
);
filter_helper(predicate, &Bag::Inside(shape), core_id, parameters)
}
Some(bag) => filter_helper(predicate, bag.as_ref(), core_id, parameters),
},
}
}
@@ -248,6 +283,10 @@ fn inside<'c>(
//FIXME: RADIUS IS A LENGTH, HOW TO ENCODE IT INTO THE SPACE?
Ok((space_id, space::Shape::HyperSphere(position, radius)))
}
Shape::Label(_, id) => {
// Not a real shape, so short circuit and return.
return core.get_by_label(parameters, id);
}
Shape::Nifti(_space_id) => Err("Inside-Nifti: not yet implemented".to_string()),
};
@@ -310,6 +349,7 @@ fn outside<'c>(
Ok(inside) => complement_helper(core, parameters, space_id, inside),
}
}
Shape::Label(_, _) => Err("Label: not yet implemented".to_string()),
Shape::Nifti(_space_id) => Err("Outside-nifti: not yet implemented".to_string()),
}
}

View File

@@ -94,7 +94,7 @@ fn main() {
}
if let Ok(r) = execute {
//let r = mercator_db::json::model::to_spatial_objects(&db, r);
//let r = mercator_db::json::model::to_spatial_objects(r);
info!("Execution: \n{:#?}", r);
info!("NB results: {:?}", r.len());
} else {

View File

@@ -1,3 +1,4 @@
use mercator_db::space;
use mercator_db::DataBase;
use super::expressions::Predictor;
@@ -17,7 +18,10 @@ impl Predictor for Bag {
match self {
Bag::ViewPort(bag) => bag.predict(db),
Bag::Distinct(bag) => bag.predict(db),
Bag::Filter(_, bag) => bag.predict(db),
Bag::Filter(_, bag) => match bag {
None => Ok(db.space(space::Space::universe().name())?.volume()),
Some(b) => b.predict(db),
},
Bag::Complement(bag) => Ok(db.space(bag.space())?.volume() - bag.predict(db)?),
Bag::Intersection(lh, rh) => {
let l = lh.predict(db)?;

View File

@@ -153,6 +153,8 @@ Bags: symbols::Bag = {
// Spatial Operators
Inside,
Outside,
// returns the positions or volume of the shape, instead of the data points in or outside it.
//Shape,
};
//*********************************************************************/
@@ -187,9 +189,13 @@ Union: symbols::Bag = {
Filter: symbols::Bag = {
// "filter" "(" <p:Predicates> "," <b:Bags> ")" =>
"filter" "(" <b:Bags> ")" =>
symbols::Bag::Filter(None, Box::new(b)),
symbols::Bag::Filter(None, Some(Box::new(b))),
"filter" "(" <p:Predicates> <b:("," <Bags> )?> ")" =>
symbols::get_filter(p, b)
match b {
None => symbols::Bag::Filter(Some(p), None),
Some(b) => symbols::Bag::Filter(Some(p), Some(Box::new(b))),
}
};
Predicates: symbols::Predicate = {
@@ -272,6 +278,12 @@ Inside: symbols::Bag = {
symbols::Bag::Inside(<>)
};
//FIXME: ADD A SHAPE VARIANT WHICH JUST RETURNS ALL THE POSITIONS OF THAT SHAPE
//Shape: symbols::Bag = {
// <Shapes> =>
// symbols::Bag::Shape(<>)
//}
//*********************************************************************/
// SHAPES */
//*********************************************************************/
@@ -282,6 +294,7 @@ Shapes: symbols::Shape = {
Point,
HyperRectangle,
HyperSphere,
Label,
Nifti
};
@@ -333,6 +346,21 @@ Point: symbols::Shape = {
}
};
// Filter by Label, a.k.a use an ID to define a volume, and use that volume to
// select data points.
Label: symbols::Shape = {
"label" "{"
<id:String>
<rs:( "," <String> )?>
"}" => {
let space_id = match rs {
Some(id) => id,
None => Space::universe().name().clone(),
};
symbols::Shape::Label(space_id, id)
}
};
// Define a shape as the non-zero values in a NIfTI object, defined by
// nifti{
// spaceId: string,

View File

@@ -61,7 +61,7 @@ pub enum Bag {
ViewPort(Box<Bag>),
// Bags
Distinct(Box<Bag>),
Filter(Option<Predicate>, Box<Bag>),
Filter(Option<Predicate>, Option<Box<Bag>>),
Complement(Box<Bag>),
Intersection(Box<Bag>, Box<Bag>),
Union(Box<Bag>, Box<Bag>),
@@ -77,7 +77,10 @@ impl Bag {
match self {
Bag::ViewPort(bag) => bag.space(),
Bag::Distinct(bag) => bag.space(),
Bag::Filter(_, bag) => bag.space(),
Bag::Filter(_, bag) => match bag {
None => space::Space::universe().name(),
Some(b) => b.space(),
},
Bag::Complement(bag) => bag.space(),
Bag::Intersection(lh, _) => {
// We are assuming lh and rh are in the same space.
@@ -124,6 +127,7 @@ pub enum Shape {
Point(String, LiteralPosition),
HyperRectangle(String, Vec<LiteralPosition>),
HyperSphere(String, LiteralPosition, LiteralNumber),
Label(String, String),
Nifti(String),
}
@@ -133,6 +137,7 @@ impl Shape {
Shape::Point(space, _) => space,
Shape::HyperRectangle(space, _) => space,
Shape::HyperSphere(space, _, _) => space,
Shape::Label(space, _) => space,
Shape::Nifti(space) => space,
}
}
@@ -201,9 +206,17 @@ impl Shape {
a * radius.powi(i as i32)
}
Shape::Nifti(_) => unimplemented!(),
Shape::Label(_, _) => {
// FIXME: Needs to find a way to figure out the approximate volume of this specific ID, or return MAX or MIN..
std::f64::EPSILON
}
Shape::Nifti(_) => unimplemented!("Nifti"),
}
}
pub fn rasterize<'e>(&self) -> mercator_db::ResultSet<'e> {
unimplemented!("rasterize")
}
}
/**********************************************************************/
@@ -426,37 +439,7 @@ impl LiteralSelector {
}
println!("LiteralSelector.str(): {:?}", self);
unimplemented!();
}
}
// The logic was getting a bit too complex to be embedded directly into the
// grammar definition.
pub fn get_filter(p: Predicate, b: Option<Bag>) -> Bag {
match b {
Some(b) => Bag::Filter(Some(p), Box::new(b)),
None => {
let (low, high) = space::Space::universe().bounding_box();
let low: Vec<_> = low.into();
let high: Vec<_> = high.into();
let bb = Shape::HyperRectangle(
space::Space::universe().name().clone(),
vec![
LiteralPosition(
low.into_iter()
.map(LiteralNumber::Float)
.collect::<Vec<_>>(),
),
LiteralPosition(
high.into_iter()
.map(LiteralNumber::Float)
.collect::<Vec<_>>(),
),
],
);
Bag::Filter(Some(p), Box::new(Bag::Inside(bb)))
}
unimplemented!("Unknown Field");
}
}

View File

@@ -56,7 +56,10 @@ impl Validator for Bag {
match self {
Bag::ViewPort(bag) => bag.validate(),
Bag::Distinct(bag) => bag.validate(),
Bag::Filter(_, bag) => bag.validate(),
Bag::Filter(_, bag) => match bag {
None => Ok(LiteralPosition(vec![]).get_type()),
Some(b) => b.validate(),
},
Bag::Complement(bag) => bag.validate(),
Bag::Intersection(lh, rh) => compare_bag_types(lh, rh),
Bag::Union(lh, rh) => compare_bag_types(lh, rh),
@@ -149,6 +152,10 @@ impl Validator for Shape {
}
}
Shape::HyperSphere(_, pos, _) => pos.validate(),
Shape::Label(_, _) => {
// FIXME: Quick Hack, we need to fix this and return the effective type of the object Id.
Ok(LiteralPosition(vec![]).get_type())
}
Shape::Nifti(_) => Err("not yet implemented".to_string()),
}
}