vars no longer have to start with '?'

main
Ziyang Hu 2 years ago
parent cd1d1f63cd
commit 28233f8a54

@ -12,7 +12,7 @@ casey = "0.3.3"
tempfile = "3.3.0" tempfile = "3.3.0"
either = "1.7.0" either = "1.7.0"
rand = "0.8.5" rand = "0.8.5"
miette = "5.3.0" miette = { version = "5.3.0", features = ["fancy"] }
lazy_static = "1.4.0" lazy_static = "1.4.0"
log = "0.4.16" log = "0.4.16"
env_logger = "0.9.0" env_logger = "0.9.0"

@ -20,7 +20,7 @@ LINE_COMMENT = _{ "//" ~ (!"\n" ~ ANY)* }
COMMENT = _{(BLOCK_COMMENT | LINE_COMMENT)} COMMENT = _{(BLOCK_COMMENT | LINE_COMMENT)}
prog_entry = {"?"} prog_entry = {"?"}
var = @{"?" ~ (XID_CONTINUE | "_")*} var = @{(XID_START | "_") ~ (XID_CONTINUE | "_")*}
param = @{"$" ~ (XID_CONTINUE | "_")*} param = @{"$" ~ (XID_CONTINUE | "_")*}
ident = @{XID_START ~ ("_" | XID_CONTINUE)*} ident = @{XID_START ~ ("_" | XID_CONTINUE)*}
algo_ident = @{XID_START ~ ("_" | XID_CONTINUE)* ~ "!"} algo_ident = @{XID_START ~ ("_" | XID_CONTINUE)* ~ "!"}
@ -80,7 +80,7 @@ unary_op = _{ minus | negate }
minus = { "-" } minus = { "-" }
negate = { "!" } negate = { "!" }
term = _{ var | param | grouping | apply | list | literal } term = _{ param | grouping | apply | var | list | literal }
list = { "[" ~ (expr ~ ",")* ~ expr? ~ "]" } list = { "[" ~ (expr ~ ",")* ~ expr? ~ "]" }
grouping = { "(" ~ expr ~ ")" } grouping = { "(" ~ expr ~ ")" }

@ -13,9 +13,66 @@ use crate::data::attr::Attribute;
use crate::data::expr::Expr; use crate::data::expr::Expr;
use crate::data::id::Validity; use crate::data::id::Validity;
use crate::data::symb::{Symbol, PROG_ENTRY}; use crate::data::symb::{Symbol, PROG_ENTRY};
use crate::data::tuple::Tuple;
use crate::data::value::DataValue; use crate::data::value::DataValue;
use crate::parse::query::{ConstRules, QueryOutOptions}; use crate::query::pull::PullSpecs;
use crate::runtime::transact::SessionTx; use crate::runtime::transact::SessionTx;
use crate::runtime::view::ViewRelMetadata;
pub(crate) type ConstRules = BTreeMap<MagicSymbol, Vec<Tuple>>;
pub(crate) type OutSpec = (Vec<(usize, Option<PullSpecs>)>, Option<Vec<String>>);
#[derive(Debug, Clone, Eq, PartialEq)]
pub(crate) struct QueryOutOptions {
pub(crate) out_spec: Option<OutSpec>,
pub(crate) vld: Validity,
pub(crate) limit: Option<usize>,
pub(crate) offset: Option<usize>,
pub(crate) timeout: Option<u64>,
pub(crate) sorters: Vec<(Symbol, SortDir)>,
pub(crate) as_view: Option<(ViewRelMetadata, ViewOp)>,
}
impl Default for QueryOutOptions {
fn default() -> Self {
Self {
out_spec: None,
vld: Validity::current(),
limit: None,
offset: None,
timeout: None,
sorters: vec![],
as_view: None,
}
}
}
impl QueryOutOptions {
pub(crate) fn num_to_take(&self) -> Option<usize> {
match (self.limit, self.offset) {
(None, _) => None,
(Some(i), None) => Some(i),
(Some(i), Some(j)) => Some(i + j),
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub(crate) enum SortDir {
Asc,
Dsc,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub(crate) enum ViewOp {
Create,
Rederive,
Put,
Retract,
}
#[derive(Default)] #[derive(Default)]
pub(crate) struct TempSymbGen { pub(crate) struct TempSymbGen {
@ -148,6 +205,7 @@ impl InputProgram {
} }
} }
pub(crate) fn to_normalized_program(&self, tx: &SessionTx) -> Result<NormalFormProgram> { pub(crate) fn to_normalized_program(&self, tx: &SessionTx) -> Result<NormalFormProgram> {
let default_vld = Validity::current();
let mut prog: BTreeMap<Symbol, _> = Default::default(); let mut prog: BTreeMap<Symbol, _> = Default::default();
for (k, rules_or_algo) in &self.prog { for (k, rules_or_algo) in &self.prog {
match rules_or_algo { match rules_or_algo {
@ -191,7 +249,7 @@ impl InputProgram {
head: new_head.clone(), head: new_head.clone(),
aggr: rule.aggr.clone(), aggr: rule.aggr.clone(),
body, body,
vld: rule.vld, vld: rule.vld.unwrap_or(default_vld),
}; };
collected_rules.push(normalized_rule.convert_to_well_ordered_rule()?); collected_rules.push(normalized_rule.convert_to_well_ordered_rule()?);
} }
@ -366,7 +424,7 @@ pub(crate) struct InputRule {
pub(crate) head: Vec<Symbol>, pub(crate) head: Vec<Symbol>,
pub(crate) aggr: Vec<Option<(Aggregation, Vec<DataValue>)>>, pub(crate) aggr: Vec<Option<(Aggregation, Vec<DataValue>)>>,
pub(crate) body: Vec<InputAtom>, pub(crate) body: Vec<InputAtom>,
pub(crate) vld: Validity, pub(crate) vld: Option<Validity>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]

File diff suppressed because it is too large Load Diff

@ -11,15 +11,10 @@ use crate::algo::AlgoHandle;
use crate::data::aggr::{get_aggr, Aggregation}; use crate::data::aggr::{get_aggr, Aggregation};
use crate::data::expr::Expr; use crate::data::expr::Expr;
use crate::data::id::Validity; use crate::data::id::Validity;
use crate::data::program::{ use crate::data::program::{AlgoApply, AlgoRuleArg, ConstRules, InputAtom, InputAttrTripleAtom, InputProgram, InputRule, InputRuleApplyAtom, InputRulesOrAlgo, InputTerm, InputViewApplyAtom, MagicSymbol, OutSpec, QueryOutOptions, SortDir, TripleDir, Unification, ViewOp};
AlgoApply, AlgoRuleArg, InputAtom, InputAttrTripleAtom, InputProgram, InputRule,
InputRuleApplyAtom, InputRulesOrAlgo, InputTerm, InputViewApplyAtom, MagicSymbol, TripleDir,
Unification,
};
use crate::data::symb::{Symbol, PROG_ENTRY}; use crate::data::symb::{Symbol, PROG_ENTRY};
use crate::data::tuple::Tuple; use crate::data::tuple::Tuple;
use crate::data::value::DataValue; use crate::data::value::DataValue;
use crate::parse::query::{ConstRules, OutSpec, QueryOutOptions, SortDir, ViewOp};
use crate::parse::script::expr::build_expr; use crate::parse::script::expr::build_expr;
use crate::parse::script::{Pair, Pairs, Rule}; use crate::parse::script::{Pair, Pairs, Rule};
use crate::runtime::view::{ViewRelId, ViewRelKind, ViewRelMetadata}; use crate::runtime::view::{ViewRelId, ViewRelKind, ViewRelMetadata};
@ -31,12 +26,11 @@ pub(crate) fn parse_query(
let mut progs: BTreeMap<Symbol, InputRulesOrAlgo> = Default::default(); let mut progs: BTreeMap<Symbol, InputRulesOrAlgo> = Default::default();
let mut const_rules: ConstRules = Default::default(); let mut const_rules: ConstRules = Default::default();
let mut out_opts: QueryOutOptions = Default::default(); let mut out_opts: QueryOutOptions = Default::default();
let default_vld = Validity::current();
for pair in src { for pair in src {
match pair.as_rule() { match pair.as_rule() {
Rule::rule => { Rule::rule => {
let (name, rule) = parse_rule(pair, param_pool, default_vld)?; let (name, rule) = parse_rule(pair, param_pool)?;
match progs.entry(name) { match progs.entry(name) {
Entry::Vacant(e) => { Entry::Vacant(e) => {
e.insert(InputRulesOrAlgo::Rules(vec![rule])); e.insert(InputRulesOrAlgo::Rules(vec![rule]));
@ -189,17 +183,16 @@ fn get_entry_arity(prog: &BTreeMap<Symbol, InputRulesOrAlgo>) -> Result<usize> {
fn parse_rule( fn parse_rule(
src: Pair<'_>, src: Pair<'_>,
param_pool: &BTreeMap<String, DataValue>, param_pool: &BTreeMap<String, DataValue>,
default_vld: Validity,
) -> Result<(Symbol, InputRule)> { ) -> Result<(Symbol, InputRule)> {
let mut src = src.into_inner(); let mut src = src.into_inner();
let head = src.next().unwrap(); let head = src.next().unwrap();
let (name, head, aggr) = parse_rule_head(head, param_pool)?; let (name, head, aggr) = parse_rule_head(head, param_pool)?;
let mut at = default_vld; let mut at = None;
let mut body = src.next().unwrap(); let mut body = src.next().unwrap();
if body.as_rule() == Rule::expr { if body.as_rule() == Rule::expr {
let vld = build_expr(body, param_pool)?.eval_to_const()?; let vld = build_expr(body, param_pool)?.eval_to_const()?;
let vld = Validity::try_from(vld)?; let vld = Validity::try_from(vld)?;
at = vld; at = Some(vld);
body = src.next().unwrap(); body = src.next().unwrap();
} }
let mut body_clauses = vec![]; let mut body_clauses = vec![];
@ -467,7 +460,7 @@ fn str2usize(src: &str) -> Result<usize> {
Ok(usize::from_str(&src.replace('_', "")).into_diagnostic()?) Ok(usize::from_str(&src.replace('_', "")).into_diagnostic()?)
} }
fn parse_out_option(src: Pair<'_>) -> Result<OutSpec> { fn parse_out_option(_src: Pair<'_>) -> Result<OutSpec> {
// Ok(match src.as_rule() { // Ok(match src.as_rule() {
// Rule::out_list_spec => { // Rule::out_list_spec => {
// let l: Vec<_> = src.into_inner().map(parse_pull_spec).try_collect()?; // let l: Vec<_> = src.into_inner().map(parse_pull_spec).try_collect()?;

@ -5,12 +5,9 @@ use itertools::Itertools;
use crate::data::aggr::Aggregation; use crate::data::aggr::Aggregation;
use crate::data::expr::Expr; use crate::data::expr::Expr;
use crate::data::program::{ use crate::data::program::{ConstRules, MagicAlgoApply, MagicAtom, MagicRule, MagicRulesOrAlgo, MagicSymbol, StratifiedMagicProgram};
MagicAlgoApply, MagicAtom, MagicRule, MagicRulesOrAlgo, MagicSymbol, StratifiedMagicProgram,
};
use crate::data::symb::Symbol; use crate::data::symb::Symbol;
use crate::data::value::DataValue; use crate::data::value::DataValue;
use crate::parse::query::ConstRules;
use crate::query::relation::Relation; use crate::query::relation::Relation;
use crate::runtime::derived::DerivedRelStore; use crate::runtime::derived::DerivedRelStore;
use crate::runtime::transact::SessionTx; use crate::runtime::transact::SessionTx;

@ -13,11 +13,11 @@ use crate::data::encode::{
}; };
use crate::data::id::{AttrId, EntityId, Validity}; use crate::data::id::{AttrId, EntityId, Validity};
use crate::data::json::JsonValue; use crate::data::json::JsonValue;
use crate::data::program::{QueryOutOptions, ViewOp};
use crate::data::symb::Symbol; use crate::data::symb::Symbol;
use crate::data::triple::StoreOp; use crate::data::triple::StoreOp;
use crate::data::tuple::Tuple; use crate::data::tuple::Tuple;
use crate::data::value::DataValue; use crate::data::value::DataValue;
use crate::parse::query::{QueryOutOptions, ViewOp};
use crate::query::relation::flatten_err; use crate::query::relation::flatten_err;
use crate::runtime::transact::SessionTx; use crate::runtime::transact::SessionTx;
use crate::runtime::view::ViewRelMetadata; use crate::runtime::view::ViewRelMetadata;

@ -3,11 +3,11 @@ use std::collections::BTreeMap;
use miette::Result; use miette::Result;
use itertools::Itertools; use itertools::Itertools;
use crate::data::program::SortDir;
use crate::data::symb::Symbol; use crate::data::symb::Symbol;
use crate::data::tuple::Tuple; use crate::data::tuple::Tuple;
use crate::data::value::DataValue; use crate::data::value::DataValue;
use crate::parse::query::SortDir;
use crate::runtime::derived::DerivedRelStore; use crate::runtime::derived::DerivedRelStore;
use crate::runtime::transact::SessionTx; use crate::runtime::transact::SessionTx;

@ -22,13 +22,13 @@ use crate::data::encode::{
}; };
use crate::data::id::{AttrId, EntityId, TxId, Validity}; use crate::data::id::{AttrId, EntityId, TxId, Validity};
use crate::data::json::JsonValue; use crate::data::json::JsonValue;
use crate::data::program::ViewOp;
use crate::data::symb::Symbol; use crate::data::symb::Symbol;
use crate::data::triple::StoreOp; use crate::data::triple::StoreOp;
use crate::data::tuple::{rusty_scratch_cmp, EncodedTuple, Tuple, SCRATCH_DB_KEY_PREFIX_LEN}; use crate::data::tuple::{rusty_scratch_cmp, EncodedTuple, Tuple, SCRATCH_DB_KEY_PREFIX_LEN};
use crate::data::value::{DataValue, LARGEST_UTF_CHAR}; use crate::data::value::{DataValue, LARGEST_UTF_CHAR};
use crate::parse::cozoscript::query::{parse_query_to_json, ScriptType}; use crate::parse::cozoscript::query::{parse_query_to_json, ScriptType};
use crate::parse::cozoscript::sys::{CompactTarget, SysOp}; use crate::parse::cozoscript::sys::{CompactTarget, SysOp};
use crate::parse::query::ViewOp;
use crate::parse::schema::AttrTxItem; use crate::parse::schema::AttrTxItem;
use crate::parse::script::{parse_script, CozoScript}; use crate::parse::script::{parse_script, CozoScript};
use crate::query::pull::CurrentPath; use crate::query::pull::CurrentPath;
@ -380,7 +380,7 @@ impl Db {
}; };
Ok(json!({ key: payload })) Ok(json!({ key: payload }))
} }
pub fn run_json_query(&self, payload: &JsonValue) -> Result<JsonValue> { pub fn run_json_query(&self, _payload: &JsonValue) -> Result<JsonValue> {
todo!() todo!()
// let (k, v) = payload // let (k, v) = payload
// .as_object() // .as_object()

@ -70,7 +70,7 @@ fn air_routes() -> Result<()> {
// //
// let view_time = Instant::now(); // let view_time = Instant::now();
// db.run_script(r#" // db.run_script(r#"
// ?[?src, ?dst, ?distance] := [?r route.src ?src], [?r route.dst ?dst], [?r route.distance ?distance]; // ?[src, dst, distance] := [r route.src src], [r route.dst dst], [r route.distance distance];
// :view rederive flies_to; // :view rederive flies_to;
// "#)?; // "#)?;
// //
@ -79,9 +79,9 @@ fn air_routes() -> Result<()> {
// let view_time2 = Instant::now(); // let view_time2 = Instant::now();
// db.run_script( // db.run_script(
// r#" // r#"
// ?[?src_c, ?dst_c, ?distance] := [?r route.src ?src], [?r route.dst ?dst], // ?[src_c, dst_c, distance] := [r route.src src], [r route.dst dst],
// [?r route.distance ?distance], // [r route.distance distance],
// [?src airport.iata ?src_c], [?dst airport.iata ?dst_c]; // [src airport.iata src_c], [dst airport.iata dst_c];
// :view rederive flies_to_code; // :view rederive flies_to_code;
// "#, // "#,
// )?; // )?;
@ -90,7 +90,7 @@ fn air_routes() -> Result<()> {
// let view_time3 = Instant::now(); // let view_time3 = Instant::now();
// db.run_script( // db.run_script(
// r#" // r#"
// ?[?code, ?lat, ?lon] := [?n airport.iata ?code], [?n airport.lat ?lat], [?n airport.lon ?lon]; // ?[code, lat, lon] := [n airport.iata code], [n airport.lat lat], [n airport.lon lon];
// :view rederive code_lat_lon; // :view rederive code_lat_lon;
// "# // "#
// )?; // )?;
@ -109,7 +109,7 @@ fn air_routes() -> Result<()> {
let dfs_time = Instant::now(); let dfs_time = Instant::now();
let res = db.run_script(r#" let res = db.run_script(r#"
starting <- [['PEK']]; starting <- [['PEK']];
? <- dfs!(:flies_to_code[], [?id <airport.iata ?code], starting[], condition: (?code == 'LHR')); ? <- dfs!(:flies_to_code[], [id <airport.iata code], starting[], condition: (code == 'LHR'));
"#)?; "#)?;
dbg!(dfs_time.elapsed()); dbg!(dfs_time.elapsed());
println!("{}", res); println!("{}", res);
@ -117,32 +117,32 @@ fn air_routes() -> Result<()> {
let bfs_time = Instant::now(); let bfs_time = Instant::now();
let res = db.run_script(r#" let res = db.run_script(r#"
starting <- [['PEK']]; starting <- [['PEK']];
? <- bfs!(:flies_to_code[], [?id <airport.iata ?code], starting[], condition: ?code == 'SOU'); ? <- bfs!(:flies_to_code[], [id <airport.iata code], starting[], condition: code == 'SOU');
"#)?; "#)?;
dbg!(bfs_time.elapsed()); dbg!(bfs_time.elapsed());
println!("{}", res); println!("{}", res);
let scc_time = Instant::now(); let scc_time = Instant::now();
let res = db.run_script(r#" let res = db.run_script(r#"
res <- strongly_connected_components!(:flies_to_code[], [?id <airport.iata ?code], mode: 'group_first'); res <- strongly_connected_components!(:flies_to_code[], [id <airport.iata code], mode: 'group_first');
?[?grp, ?code] := res[?grp, ?code], ?grp != 0; ?[grp, code] := res[grp, code], grp != 0;
"#)?; "#)?;
println!("{}", res); println!("{}", res);
dbg!(scc_time.elapsed()); dbg!(scc_time.elapsed());
let cc_time = Instant::now(); let cc_time = Instant::now();
let res = db.run_script(r#" let res = db.run_script(r#"
res <- connected_components!(:flies_to_code[], [?id <airport.iata ?code], mode: 'group_first'); res <- connected_components!(:flies_to_code[], [id <airport.iata code], mode: 'group_first');
?[?grp, ?code] := res[?grp, ?code], ?grp != 0; ?[grp, code] := res[grp, code], grp != 0;
"#)?; "#)?;
println!("{}", res); println!("{}", res);
dbg!(cc_time.elapsed()); dbg!(cc_time.elapsed());
let astar_time = Instant::now(); let astar_time = Instant::now();
let res = db.run_script(r#" let res = db.run_script(r#"
starting[?code, ?lat, ?lon] := ?code <- 'HFE', :code_lat_lon[?code, ?lat, ?lon]; starting[code, lat, lon] := code <- 'HFE', :code_lat_lon[code, lat, lon];
goal[?code, ?lat, ?lon] := ?code <- 'LHR', :code_lat_lon[?code, ?lat, ?lon]; goal[code, lat, lon] := code <- 'LHR', :code_lat_lon[code, lat, lon];
? <- shortest_path_astar!(:flies_to_code[], :code_lat_lon[?node, ?lat1, ?lon1], starting[], goal[?goal, ?lat2, ?lon2], heuristic: haversine_deg_input(?lat1, ?lon1, ?lat2, ?lon2) * 3963); ? <- shortest_path_astar!(:flies_to_code[], :code_lat_lon[node, lat1, lon1], starting[], goal[goal, lat2, lon2], heuristic: haversine_deg_input(lat1, lon1, lat2, lon2) * 3963);
"#)?; "#)?;
println!("{}", res); println!("{}", res);
dbg!(astar_time.elapsed()); dbg!(astar_time.elapsed());
@ -150,9 +150,9 @@ fn air_routes() -> Result<()> {
let deg_centrality_time = Instant::now(); let deg_centrality_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
deg_centrality <- degree_centrality!(:flies_to[?a, ?b]); deg_centrality <- degree_centrality!(:flies_to[a, b]);
?[?total, ?out, ?in] := deg_centrality[?node, ?total, ?out, ?in]; ?[total, out, in] := deg_centrality[node, total, out, in];
:order -?total; :order -total;
:limit 10; :limit 10;
"#, "#,
)?; )?;
@ -170,11 +170,11 @@ fn air_routes() -> Result<()> {
let deg_centrality_ad_hoc_time = Instant::now(); let deg_centrality_ad_hoc_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
flies_to[?a, ?b] := [?r route.src ?ac], [?r route.dst ?bc], flies_to[a, b] := [r route.src ac], [r route.dst bc],
[?ac airport.iata ?a], [?bc airport.iata ?b]; [ac airport.iata a], [bc airport.iata b];
deg_centrality <- degree_centrality!(flies_to[?a, ?b]); deg_centrality <- degree_centrality!(flies_to[a, b]);
?[?node, ?total, ?out, ?in] := deg_centrality[?node, ?total, ?out, ?in]; ?[node, total, out, in] := deg_centrality[node, total, out, in];
:order -?total; :order -total;
:limit 10; :limit 10;
"#, "#,
)?; )?;
@ -197,7 +197,7 @@ fn air_routes() -> Result<()> {
starting <- [['JFK']]; starting <- [['JFK']];
ending <- [['KUL']]; ending <- [['KUL']];
res <- shortest_path_dijkstra!(:flies_to_code[], starting[], ending[]); res <- shortest_path_dijkstra!(:flies_to_code[], starting[], ending[]);
?[?path] := res[?src, ?dst, ?cost, ?path]; ?[path] := res[src, dst, cost, path];
"#, "#,
)?; )?;
@ -219,7 +219,7 @@ fn air_routes() -> Result<()> {
let starts_with_time = Instant::now(); let starts_with_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
?[?code] := [?_ airport.iata ?code], starts_with(?code, 'US'); ?[code] := [_ airport.iata code], starts_with(code, 'US');
"#, "#,
)?; )?;
dbg!(starts_with_time.elapsed()); dbg!(starts_with_time.elapsed());
@ -241,8 +241,8 @@ fn air_routes() -> Result<()> {
let range_check_time = Instant::now(); let range_check_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
r[?code, ?dist] := [?a airport.iata ?code], [?r route.src ?a], [?r route.distance ?dist]; r[code, dist] := [a airport.iata code], [r route.src a], [r route.distance dist];
?[?dist] := r['PEK', ?dist], ?dist > 7000, ?dist <= 7722; ?[dist] := r['PEK', dist], dist > 7000, dist <= 7722;
"#, "#,
)?; )?;
dbg!(range_check_time.elapsed()); dbg!(range_check_time.elapsed());
@ -254,7 +254,7 @@ fn air_routes() -> Result<()> {
let range_check_with_view_time = Instant::now(); let range_check_with_view_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
?[?dist] := [?src airport.iata 'PEK'], :flies_to[?src, ?_, ?dist], ?dist > 7000, ?dist <= 7722; ?[dist] := [src airport.iata 'PEK'], :flies_to[src, _, dist], dist > 7000, dist <= 7722;
"#, "#,
)?; )?;
dbg!(range_check_with_view_time.elapsed()); dbg!(range_check_with_view_time.elapsed());
@ -265,7 +265,7 @@ fn air_routes() -> Result<()> {
let simple_query_time = Instant::now(); let simple_query_time = Instant::now();
let res = db.run_script(r#" let res = db.run_script(r#"
?[?c, ?code, ?desc] := [?c country.code 'CU'] or ?c <- 10000239, [?c country.code ?code], [?c country.desc ?desc]; ?[c, code, desc] := [c country.code 'CU'] or c <- 10000239, [c country.code code], [c country.desc desc];
"#)?; "#)?;
dbg!(simple_query_time.elapsed()); dbg!(simple_query_time.elapsed());
assert_eq!( assert_eq!(
@ -276,7 +276,7 @@ fn air_routes() -> Result<()> {
let no_airports_time = Instant::now(); let no_airports_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
?[?desc] := [?c country.desc ?desc], not [?a airport.country ?c]; ?[desc] := [c country.desc desc], not [a airport.country c];
"#, "#,
)?; )?;
dbg!(no_airports_time.elapsed()); dbg!(no_airports_time.elapsed());
@ -294,7 +294,7 @@ fn air_routes() -> Result<()> {
let no_routes_airport_time = Instant::now(); let no_routes_airport_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
?[?code] := [?a airport.iata ?code], not [?_ route.src ?a], not [?_ route.dst ?a]; ?[code] := [a airport.iata code], not [_ route.src a], not [_ route.dst a];
"#, "#,
)?; )?;
dbg!(no_routes_airport_time.elapsed()); dbg!(no_routes_airport_time.elapsed());
@ -313,7 +313,7 @@ fn air_routes() -> Result<()> {
let runway_distribution_time = Instant::now(); let runway_distribution_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
?[?runways, count(?a)] := [?a airport.runways ?runways]; ?[runways, count(a)] := [a airport.runways runways];
"#, "#,
)?; )?;
dbg!(runway_distribution_time.elapsed()); dbg!(runway_distribution_time.elapsed());
@ -333,9 +333,9 @@ fn air_routes() -> Result<()> {
let most_out_routes_time = Instant::now(); let most_out_routes_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
route_count[?a, count(?r)] := [?r route.src ?a]; route_count[a, count(r)] := [r route.src a];
?[?code, ?n] := route_count[?a, ?n], ?n > 180, [?a airport.iata ?code]; ?[code, n] := route_count[a, n], n > 180, [a airport.iata code];
:sort -?n; :sort -n;
"#, "#,
)?; )?;
dbg!(most_out_routes_time.elapsed()); dbg!(most_out_routes_time.elapsed());
@ -356,9 +356,9 @@ fn air_routes() -> Result<()> {
let most_out_routes_again_time = Instant::now(); let most_out_routes_again_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
route_count[count(?r), ?a] := [?r route.src ?a]; route_count[count(r), a] := [r route.src a];
?[?code, ?n] := route_count[?n, ?a], ?n > 180, [?a airport.iata ?code]; ?[code, n] := route_count[n, a], n > 180, [a airport.iata code];
:sort -?n; :sort -n;
"#, "#,
)?; )?;
dbg!(most_out_routes_again_time.elapsed()); dbg!(most_out_routes_again_time.elapsed());
@ -379,9 +379,9 @@ fn air_routes() -> Result<()> {
let most_out_routes_time_inv = Instant::now(); let most_out_routes_time_inv = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
route_count[count(?r), ?a, ?x] := [?r route.src ?a], ?x <- 1; route_count[count(r), a, x] := [r route.src a], x <- 1;
?[?code, ?n] := route_count[?n, ?a, ?_], ?n > 180, [?a airport.iata ?code]; ?[code, n] := route_count[n, a, _], n > 180, [a airport.iata code];
:sort -?n; :sort -n;
"#, "#,
)?; )?;
dbg!(most_out_routes_time_inv.elapsed()); dbg!(most_out_routes_time_inv.elapsed());
@ -402,9 +402,9 @@ fn air_routes() -> Result<()> {
let most_routes_time = Instant::now(); let most_routes_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
route_count[?a, count(?r)] := [?r route.src ?a] or [?r route.dst ?a]; route_count[a, count(r)] := [r route.src a] or [r route.dst a];
?[?code, ?n] := route_count[?a, ?n], ?n > 400, [?a airport.iata ?code]; ?[code, n] := route_count[a, n], n > 400, [a airport.iata code];
:sort -?n; :sort -n;
"#, "#,
)?; )?;
dbg!(most_routes_time.elapsed()); dbg!(most_routes_time.elapsed());
@ -423,8 +423,8 @@ fn air_routes() -> Result<()> {
let airport_with_one_route_time = Instant::now(); let airport_with_one_route_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
route_count[?a, count(?r)] := [?r route.src ?a]; route_count[a, count(r)] := [r route.src a];
?[count(?a)] := route_count[?a, ?n], ?n == 1; ?[count(a)] := route_count[a, n], n == 1;
"#, "#,
)?; )?;
dbg!(airport_with_one_route_time.elapsed()); dbg!(airport_with_one_route_time.elapsed());
@ -432,11 +432,11 @@ fn air_routes() -> Result<()> {
let single_runway_with_most_routes_time = Instant::now(); let single_runway_with_most_routes_time = Instant::now();
let res = db.run_script(r#" let res = db.run_script(r#"
single_or_lgw[?a] := [?a airport.iata 'LGW'] or [?a airport.runways 1]; single_or_lgw[a] := [a airport.iata 'LGW'] or [a airport.runways 1];
out_counts[?a, count(?r)] := single_or_lgw[?a], [?r route.src ?a]; out_counts[a, count(r)] := single_or_lgw[a], [r route.src a];
?[?code, ?city, ?out_n] := out_counts[?a, ?out_n], [?a airport.city ?city], [?a airport.iata ?code]; ?[code, city, out_n] := out_counts[a, out_n], [a airport.city city], [a airport.iata code];
:order -?out_n; :order -out_n;
:limit 10; :limit 10;
"#)?; "#)?;
dbg!(single_runway_with_most_routes_time.elapsed()); dbg!(single_runway_with_most_routes_time.elapsed());
@ -453,10 +453,10 @@ fn air_routes() -> Result<()> {
let most_routes_in_canada_time = Instant::now(); let most_routes_in_canada_time = Instant::now();
let res = db.run_script(r#" let res = db.run_script(r#"
ca_airports[?a, count(?r)] := [?c country.code 'CA'], [?a airport.country ?c], [?r route.src ?a]; ca_airports[a, count(r)] := [c country.code 'CA'], [a airport.country c], [r route.src a];
?[?code, ?city, ?n_routes] := ca_airports[?a, ?n_routes], [?a airport.iata ?code], [?a airport.city ?city]; ?[code, city, n_routes] := ca_airports[a, n_routes], [a airport.iata code], [a airport.city city];
:order -?n_routes; :order -n_routes;
:limit 10; :limit 10;
"#)?; "#)?;
dbg!(most_routes_in_canada_time.elapsed()); dbg!(most_routes_in_canada_time.elapsed());
@ -478,7 +478,7 @@ fn air_routes() -> Result<()> {
let uk_count_time = Instant::now(); let uk_count_time = Instant::now();
let res = db.run_script(r" let res = db.run_script(r"
?[?region, count(?a)] := [?c country.code 'UK'], [?a airport.country ?c], [?a airport.region ?region]; ?[region, count(a)] := [c country.code 'UK'], [a airport.country c], [a airport.region region];
")?; ")?;
dbg!(uk_count_time.elapsed()); dbg!(uk_count_time.elapsed());
assert_eq!( assert_eq!(
@ -489,12 +489,12 @@ fn air_routes() -> Result<()> {
let airports_by_country = Instant::now(); let airports_by_country = Instant::now();
let res = db.run_script( let res = db.run_script(
r" r"
airports_by_country[?c, count(?a)] := [?a airport.country ?c]; airports_by_country[c, count(a)] := [a airport.country c];
country_count[?c, max(?count)] := airports_by_country[?c, ?count]; country_count[c, max(count)] := airports_by_country[c, count];
?[?code, ?count] := [?c country.code ?code], country_count[?c, ?count]; ?[code, count] := [c country.code code], country_count[c, count];
?[?code, ?count] := [?c country.code ?code], not country_count[?c, ?_], ?count <- 0; ?[code, count] := [c country.code code], not country_count[c, _], count <- 0;
:order ?count; :order count;
", ",
)?; )?;
dbg!(airports_by_country.elapsed()); dbg!(airports_by_country.elapsed());
@ -534,9 +534,9 @@ fn air_routes() -> Result<()> {
let n_airports_by_continent_time = Instant::now(); let n_airports_by_continent_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
airports_by_continent[?c, count(?a)] := [?a airport.iata ?_], [?c geo.contains ?a]; airports_by_continent[c, count(a)] := [a airport.iata _], [c geo.contains a];
?[?cont, max(?count)] := airports_by_continent[?c, ?count], [?c continent.code ?cont]; ?[cont, max(count)] := airports_by_continent[c, count], [c continent.code cont];
?[?cont, max(?count)] := [?_ continent.code ?cont], ?count <- 0; ?[cont, max(count)] := [_ continent.code cont], count <- 0;
"#, "#,
)?; )?;
dbg!(n_airports_by_continent_time.elapsed()); dbg!(n_airports_by_continent_time.elapsed());
@ -551,8 +551,8 @@ fn air_routes() -> Result<()> {
let routes_per_airport_time = Instant::now(); let routes_per_airport_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
routes_count[?a, count(?r)] := given[?code], [?a airport.iata ?code], [?r route.src ?a]; routes_count[a, count(r)] := given[code], [a airport.iata code], [r route.src a];
?[?code, ?n] := routes_count[?a, ?n], [?a airport.iata ?code]; ?[code, n] := routes_count[a, n], [a airport.iata code];
given <- [['A' ++ 'U' ++ 'S'],['AMS'],['JFK'],['DUB'],['MEX']]; given <- [['A' ++ 'U' ++ 'S'],['AMS'],['JFK'],['DUB'],['MEX']];
"#, "#,
@ -569,8 +569,8 @@ fn air_routes() -> Result<()> {
let airports_by_route_number_time = Instant::now(); let airports_by_route_number_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
route_count[?a, count(?r)] := [?r route.src ?a]; route_count[a, count(r)] := [r route.src a];
?[?n, collect(?code)] := route_count[?a, ?n], [?a airport.iata ?code], ?n = 105; ?[n, collect(code)] := route_count[a, n], [a airport.iata code], n = 105;
"#, "#,
)?; )?;
dbg!(airports_by_route_number_time.elapsed()); dbg!(airports_by_route_number_time.elapsed());
@ -578,15 +578,15 @@ fn air_routes() -> Result<()> {
let out_from_aus_time = Instant::now(); let out_from_aus_time = Instant::now();
let res = db.run_script(r#" let res = db.run_script(r#"
out_by_runways[?n_runways, count(?a)] := [?aus airport.iata 'AUS'], out_by_runways[n_runways, count(a)] := [aus airport.iata 'AUS'],
[?r1 route.src ?aus], [r1 route.src aus],
[?r1 route.dst ?a], [r1 route.dst a],
[?a airport.runways ?n_runways]; [a airport.runways n_runways];
two_hops[count(?a)] := [?aus airport.iata 'AUS'], two_hops[count(a)] := [aus airport.iata 'AUS'],
[?r1 route.src ?aus], [r1 route.src aus],
[?r1 route.dst ?a], [r1 route.dst a],
[?r route.src ?a]; [r route.src a];
?[max(?total), collect(?coll)] := two_hops[?total], out_by_runways[?n, ?ct], ?coll <- [?n, ?ct]; ?[max(total), collect(coll)] := two_hops[total], out_by_runways[n, ct], coll <- [n, ct];
"#)?; "#)?;
dbg!(out_from_aus_time.elapsed()); dbg!(out_from_aus_time.elapsed());
assert_eq!( assert_eq!(
@ -598,7 +598,7 @@ fn air_routes() -> Result<()> {
let const_return_time = Instant::now(); let const_return_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
?[?name, count(?a)] := [?a airport.region 'US-OK'], ?name <- 'OK'; ?[name, count(a)] := [a airport.region 'US-OK'], name <- 'OK';
"#, "#,
)?; )?;
dbg!(const_return_time.elapsed()); dbg!(const_return_time.elapsed());
@ -607,14 +607,14 @@ fn air_routes() -> Result<()> {
let multi_res_time = Instant::now(); let multi_res_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
total[count(?a)] := [?a airport.iata ?_]; total[count(a)] := [a airport.iata _];
high[count(?a)] := [?a airport.runways ?n], ?n >= 6; high[count(a)] := [a airport.runways n], n >= 6;
low[count(?a)] := [?a airport.runways ?n], ?n <= 2; low[count(a)] := [a airport.runways n], n <= 2;
four[count(?a)] := [?a airport.runways ?n], ?n = 4; four[count(a)] := [a airport.runways n], n = 4;
france[count(?a)] := [?fr country.code 'FR'], [?a airport.country ?fr]; france[count(a)] := [fr country.code 'FR'], [a airport.country fr];
?[?total, ?high, ?low, ?four, ?france] := total[?total], high[?high], low[?low], ?[total, high, low, four, france] := total[total], high[high], low[low],
four[?four], france[?france]; four[four], france[france];
"#, "#,
)?; )?;
dbg!(multi_res_time.elapsed()); dbg!(multi_res_time.elapsed());
@ -625,8 +625,8 @@ fn air_routes() -> Result<()> {
let multi_unification_time = Instant::now(); let multi_unification_time = Instant::now();
let res = db.run_script(r#" let res = db.run_script(r#"
target_airports[collect(?a, 5)] := [?a airport.iata ?_]; target_airports[collect(a, 5)] := [a airport.iata _];
?[?code, count(?r)] := target_airports[?targets], ?a <- ..?targets, [?a airport.iata ?code], [?r route.src ?a]; ?[code, count(r)] := target_airports[targets], a <- ..targets, [a airport.iata code], [r route.src a];
"#)?; "#)?;
dbg!(multi_unification_time.elapsed()); dbg!(multi_unification_time.elapsed());
assert_eq!( assert_eq!(
@ -640,13 +640,13 @@ fn air_routes() -> Result<()> {
let num_routes_from_eu_to_us_time = Instant::now(); let num_routes_from_eu_to_us_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
routes[unique(?r)] := [?eu continent.code 'EU'], routes[unique(r)] := [eu continent.code 'EU'],
[?us country.code 'US'], [us country.code 'US'],
[?eu geo.contains ?a], [eu geo.contains a],
[?r route.src ?a], [r route.src a],
[?r route.dst ?a2], [r route.dst a2],
[?a2 airport.country ?us]; [a2 airport.country us];
?[?n] := routes[?rs], ?n <- length(?rs); ?[n] := routes[rs], n <- length(rs);
"#, "#,
)?; )?;
dbg!(num_routes_from_eu_to_us_time.elapsed()); dbg!(num_routes_from_eu_to_us_time.elapsed());
@ -655,12 +655,12 @@ fn air_routes() -> Result<()> {
let num_airports_in_us_with_routes_from_eu_time = Instant::now(); let num_airports_in_us_with_routes_from_eu_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
?[count_unique(?a2)] := [?eu continent.code 'EU'], ?[count_unique(a2)] := [eu continent.code 'EU'],
[?us country.code 'US'], [us country.code 'US'],
[?eu geo.contains ?a], [eu geo.contains a],
[?r route.src ?a], [r route.src a],
[?r route.dst ?a2], [r route.dst a2],
[?a2 airport.country ?us]; [a2 airport.country us];
"#, "#,
)?; )?;
dbg!(num_airports_in_us_with_routes_from_eu_time.elapsed()); dbg!(num_airports_in_us_with_routes_from_eu_time.elapsed());
@ -669,14 +669,14 @@ fn air_routes() -> Result<()> {
let num_routes_in_us_airports_from_eu_time = Instant::now(); let num_routes_in_us_airports_from_eu_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
?[?code, count(?r)] := [?eu continent.code 'EU'], ?[code, count(r)] := [eu continent.code 'EU'],
[?us country.code 'US'], [us country.code 'US'],
[?eu geo.contains ?a], [eu geo.contains a],
[?r route.src ?a], [r route.src a],
[?r route.dst ?a2], [r route.dst a2],
[?a2 airport.country ?us], [a2 airport.country us],
[?a2 airport.iata ?code]; [a2 airport.iata code];
:order ?r; :order r;
"#, "#,
)?; )?;
dbg!(num_routes_in_us_airports_from_eu_time.elapsed()); dbg!(num_routes_in_us_airports_from_eu_time.elapsed());
@ -697,15 +697,15 @@ fn air_routes() -> Result<()> {
let routes_from_eu_to_us_starting_with_l_time = Instant::now(); let routes_from_eu_to_us_starting_with_l_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
?[?eu_code, ?us_code] := [?eu continent.code 'EU'], ?[eu_code, us_code] := [eu continent.code 'EU'],
[?us country.code 'US'], [us country.code 'US'],
[?eu geo.contains ?a], [eu geo.contains a],
[?a airport.iata ?eu_code], [a airport.iata eu_code],
starts_with(?eu_code, 'L'), starts_with(eu_code, 'L'),
[?r route.src ?a], [r route.src a],
[?r route.dst ?a2], [r route.dst a2],
[?a2 airport.country ?us], [a2 airport.country us],
[?a2 airport.iata ?us_code]; [a2 airport.iata us_code];
"#, "#,
)?; )?;
dbg!(routes_from_eu_to_us_starting_with_l_time.elapsed()); dbg!(routes_from_eu_to_us_starting_with_l_time.elapsed());
@ -729,11 +729,11 @@ fn air_routes() -> Result<()> {
let len_of_names_count_time = Instant::now(); let len_of_names_count_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
?[sum(?n)] := [?a airport.iata 'AUS'], ?[sum(n)] := [a airport.iata 'AUS'],
[?r route.src ?a], [r route.src a],
[?r route.dst ?a2], [r route.dst a2],
[?a2 airport.city ?city_name], [a2 airport.city city_name],
?n <- length(?city_name); n <- length(city_name);
"#, "#,
)?; )?;
dbg!(len_of_names_count_time.elapsed()); dbg!(len_of_names_count_time.elapsed());
@ -742,11 +742,11 @@ fn air_routes() -> Result<()> {
let group_count_by_out_time = Instant::now(); let group_count_by_out_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
route_count[count(?r), ?a] := [?r route.src ?a]; route_count[count(r), a] := [r route.src a];
rc[max(?n), ?a] := route_count[?n, ?a]; rc[max(n), a] := route_count[n, a];
rc[max(?n), ?a] := [?a airport.iata ?_], ?n <- 0; rc[max(n), a] := [a airport.iata _], n <- 0;
?[?n, count(?a)] := rc[?n, ?a]; ?[n, count(a)] := rc[n, a];
:order ?n; :order n;
:limit 10; :limit 10;
"#, "#,
)?; )?;
@ -762,9 +762,9 @@ fn air_routes() -> Result<()> {
let mean_group_count_time = Instant::now(); let mean_group_count_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
route_count[count(?r), ?a] := [?r route.src ?a]; route_count[count(r), a] := [r route.src a];
rc[max(?n), ?a] := route_count[?n, ?a] or ([?a airport.iata ?_], ?n <- 0); rc[max(n), a] := route_count[n, a] or ([a airport.iata _], n <- 0);
?[mean(?n)] := rc[?n, ?_]; ?[mean(n)] := rc[n, _];
"#, "#,
)?; )?;
dbg!(mean_group_count_time.elapsed()); dbg!(mean_group_count_time.elapsed());
@ -786,7 +786,7 @@ fn air_routes() -> Result<()> {
let n_routes_from_london_uk_time = Instant::now(); let n_routes_from_london_uk_time = Instant::now();
let res = db.run_script(r#" let res = db.run_script(r#"
?[?code, count(?r)] := [?a airport.city 'London'], [?a airport.region 'GB-ENG'], [?r route.src ?a], [?a airport.iata ?code]; ?[code, count(r)] := [a airport.city 'London'], [a airport.region 'GB-ENG'], [r route.src a], [a airport.iata code];
"#)?; "#)?;
dbg!(n_routes_from_london_uk_time.elapsed()); dbg!(n_routes_from_london_uk_time.elapsed());
assert_eq!( assert_eq!(
@ -799,9 +799,9 @@ fn air_routes() -> Result<()> {
let reachable_from_london_uk_in_two_hops_time = Instant::now(); let reachable_from_london_uk_in_two_hops_time = Instant::now();
let res = db.run_script(r#" let res = db.run_script(r#"
lon_uk_airports[?a] := [?a airport.city 'London'], [?a airport.region 'GB-ENG']; lon_uk_airports[a] := [a airport.city 'London'], [a airport.region 'GB-ENG'];
one_hop[?a2] := lon_uk_airports[?a], [?r route.src ?a], [?r route.dst ?a2], not lon_uk_airports[?a2]; one_hop[a2] := lon_uk_airports[a], [r route.src a], [r route.dst a2], not lon_uk_airports[a2];
?[count_unique(?a3)] := one_hop[?a2], [?r2 route.src ?a2], [?r2 route.dst ?a3], not lon_uk_airports[?a3]; ?[count_unique(a3)] := one_hop[a2], [r2 route.src a2], [r2 route.dst a3], not lon_uk_airports[a3];
"#)?; "#)?;
dbg!(reachable_from_london_uk_in_two_hops_time.elapsed()); dbg!(reachable_from_london_uk_in_two_hops_time.elapsed());
assert_eq!(*res.get("rows").unwrap(), json!([[2353]])); assert_eq!(*res.get("rows").unwrap(), json!([[2353]]));
@ -809,9 +809,9 @@ fn air_routes() -> Result<()> {
let routes_within_england_time = Instant::now(); let routes_within_england_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
eng_aps[?a] := [?a airport.region 'GB-ENG']; eng_aps[a] := [a airport.region 'GB-ENG'];
?[?src, ?dst] := eng_aps[?a1], [?r route.src ?a1], [?r route.dst ?a2], eng_aps[?a2], ?[src, dst] := eng_aps[a1], [r route.src a1], [r route.dst a2], eng_aps[a2],
[?a1 airport.iata ?src], [?a2 airport.iata ?dst]; [a1 airport.iata src], [a2 airport.iata dst];
"#, "#,
)?; )?;
dbg!(routes_within_england_time.elapsed()); dbg!(routes_within_england_time.elapsed());
@ -835,10 +835,10 @@ fn air_routes() -> Result<()> {
let routes_within_england_time_no_dup = Instant::now(); let routes_within_england_time_no_dup = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
eng_aps[?a] := [?a airport.region 'GB-ENG']; eng_aps[a] := [a airport.region 'GB-ENG'];
?[?pair] := eng_aps[?a1], [?r route.src ?a1], [?r route.dst ?a2], eng_aps[?a2], ?[pair] := eng_aps[a1], [r route.src a1], [r route.dst a2], eng_aps[a2],
[?a1 airport.iata ?src], [?a2 airport.iata ?dst], [a1 airport.iata src], [a2 airport.iata dst],
?pair <- sorted([?src, ?dst]); pair <- sorted([src, dst]);
"#, "#,
)?; )?;
dbg!(routes_within_england_time_no_dup.elapsed()); dbg!(routes_within_england_time_no_dup.elapsed());
@ -858,13 +858,13 @@ fn air_routes() -> Result<()> {
let hard_route_finding_time = Instant::now(); let hard_route_finding_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
reachable[?a, choice(?p)] := [?s airport.iata 'AUS'], reachable[a, choice(p)] := [s airport.iata 'AUS'],
[?r route.src ?s], [?r route.dst ?a], [r route.src s], [r route.dst a],
[?a airport.iata ?code], ?code != 'YYZ', ?p <- ['AUS', ?code]; [a airport.iata code], code != 'YYZ', p <- ['AUS', code];
reachable[?a, choice(?p)] := reachable[?b, ?prev], reachable[a, choice(p)] := reachable[b, prev],
[?r route.src ?b], [?r route.dst ?a], [?a airport.iata ?code], [r route.src b], [r route.dst a], [a airport.iata code],
?code != 'YYZ', ?p <- append(?prev, ?code); code != 'YYZ', p <- append(prev, code);
?[?p] := reachable[?a, ?p], [?a airport.iata 'YPO']; ?[p] := reachable[a, p], [a airport.iata 'YPO'];
:limit 1; :limit 1;
"#, "#,
@ -881,12 +881,12 @@ fn air_routes() -> Result<()> {
let na_from_india_time = Instant::now(); let na_from_india_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
?[?ind_c, ?na_c] := [?india country.code 'IN'], [?ind_a airport.country ?india], ?[ind_c, na_c] := [india country.code 'IN'], [ind_a airport.country india],
[?r route.src ?ind_a], [?r route.dst ?na_a], [r route.src ind_a], [r route.dst na_a],
[?na_a airport.country ?dst_country], [na_a airport.country dst_country],
[?dst_country country.code ?dst_country_name], [dst_country country.code dst_country_name],
?dst_country_name <- ..['US', 'CA'], dst_country_name <- ..['US', 'CA'],
[?ind_a airport.iata ?ind_c], [?na_a airport.iata ?na_c]; [ind_a airport.iata ind_c], [na_a airport.iata na_c];
"#, "#,
)?; )?;
@ -904,12 +904,12 @@ fn air_routes() -> Result<()> {
let eu_cities_reachable_from_fll_time = Instant::now(); let eu_cities_reachable_from_fll_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
?[?city_name] := [?a airport.iata 'FLL'], ?[city_name] := [a airport.iata 'FLL'],
[?r route.src ?a], [r route.src a],
[?r route.dst ?a2], [r route.dst a2],
[?cont geo.contains ?a2], [cont geo.contains a2],
[?cont continent.code 'EU'], [cont continent.code 'EU'],
[?a2 airport.city ?city_name]; [a2 airport.city city_name];
"#, "#,
)?; )?;
dbg!(eu_cities_reachable_from_fll_time.elapsed()); dbg!(eu_cities_reachable_from_fll_time.elapsed());
@ -925,10 +925,10 @@ fn air_routes() -> Result<()> {
let clt_to_eu_or_sa_time = Instant::now(); let clt_to_eu_or_sa_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
?[?code] := [?a airport.iata 'CLT'], [?r route.src ?a], [?r route.dst ?a2], ?[code] := [a airport.iata 'CLT'], [r route.src a], [r route.dst a2],
[?cont geo.contains ?a2], [?cont continent.code ?c_name], [cont geo.contains a2], [cont continent.code c_name],
?c_name <- ..['EU', 'SA'], c_name <- ..['EU', 'SA'],
[?a2 airport.iata ?code]; [a2 airport.iata code];
"#, "#,
)?; )?;
dbg!(clt_to_eu_or_sa_time.elapsed()); dbg!(clt_to_eu_or_sa_time.elapsed());
@ -943,12 +943,12 @@ fn air_routes() -> Result<()> {
let london_to_us_time = Instant::now(); let london_to_us_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
?[?l_code, ?us_code] := ?l_code <- ..['LHR', 'LCY', 'LGW', 'LTN', 'STN'], ?[l_code, us_code] := l_code <- ..['LHR', 'LCY', 'LGW', 'LTN', 'STN'],
[?a airport.iata ?l_code], [a airport.iata l_code],
[?r route.src ?a], [?r route.dst ?a2], [r route.src a], [r route.dst a2],
[?us country.code 'US'], [us country.code 'US'],
[?a2 airport.country ?us], [a2 airport.country us],
[?a2 airport.iata ?us_code]; [a2 airport.iata us_code];
"#, "#,
)?; )?;
dbg!(london_to_us_time.elapsed()); dbg!(london_to_us_time.elapsed());
@ -972,12 +972,12 @@ fn air_routes() -> Result<()> {
let tx_to_ny_time = Instant::now(); let tx_to_ny_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
?[?tx_code, ?ny_code] := [?a airport.region 'US-TX'], ?[tx_code, ny_code] := [a airport.region 'US-TX'],
[?r route.src ?a], [r route.src a],
[?r route.dst ?a2], [r route.dst a2],
[?a2 airport.region 'US-NY'], [a2 airport.region 'US-NY'],
[?a airport.iata ?tx_code], [a airport.iata tx_code],
[?a2 airport.iata ?ny_code]; [a2 airport.iata ny_code];
"#, "#,
)?; )?;
dbg!(tx_to_ny_time.elapsed()); dbg!(tx_to_ny_time.elapsed());
@ -996,10 +996,10 @@ fn air_routes() -> Result<()> {
let denver_to_mexico_time = Instant::now(); let denver_to_mexico_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
?[?city_name] := [?a airport.iata 'DEN'], [?r route.src ?a], [?r route.dst ?a2], ?[city_name] := [a airport.iata 'DEN'], [r route.src a], [r route.dst a2],
[?a2 airport.country ?ct], [a2 airport.country ct],
[?ct country.code 'MX'], [ct country.code 'MX'],
[?a2 airport.city ?city_name]; [a2 airport.city city_name];
"#, "#,
)?; )?;
dbg!(denver_to_mexico_time.elapsed()); dbg!(denver_to_mexico_time.elapsed());
@ -1016,9 +1016,9 @@ fn air_routes() -> Result<()> {
let three_cities_time = Instant::now(); let three_cities_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
three[?a] := ?city <- ..['London', 'Munich', 'Paris'], [?a airport.city ?city]; three[a] := city <- ..['London', 'Munich', 'Paris'], [a airport.city city];
?[?src, ?dst] := three[?s], [?r route.src ?s], [?r route.dst ?d], three[?d], ?[src, dst] := three[s], [r route.src s], [r route.dst d], three[d],
[?s airport.iata ?src], [?d airport.iata ?dst]; [s airport.iata src], [d airport.iata dst];
"#, "#,
)?; )?;
dbg!(three_cities_time.elapsed()); dbg!(three_cities_time.elapsed());
@ -1038,8 +1038,8 @@ fn air_routes() -> Result<()> {
let long_distance_from_lgw_time = Instant::now(); let long_distance_from_lgw_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
?[?city, ?dist] := [?a airport.iata 'LGW'], [?r route.src ?a], [?r route.dst ?a2], ?[city, dist] := [a airport.iata 'LGW'], [r route.src a], [r route.dst a2],
[?r route.distance ?dist], ?dist > 4000, [?a2 airport.city ?city]; [r route.distance dist], dist > 4000, [a2 airport.city city];
"#, "#,
)?; )?;
dbg!(long_distance_from_lgw_time.elapsed()); dbg!(long_distance_from_lgw_time.elapsed());
@ -1063,9 +1063,9 @@ fn air_routes() -> Result<()> {
let long_routes_one_dir_time = Instant::now(); let long_routes_one_dir_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
?[?src, ?dist, ?dst] := [?r route.distance ?dist], ?dist > 8000, [?r route.src ?s], ?[src, dist, dst] := [r route.distance dist], dist > 8000, [r route.src s],
[?r route.dst ?d], [?s airport.iata ?src], [?d airport.iata ?dst], [r route.dst d], [s airport.iata src], [d airport.iata dst],
?src < ?dst; src < dst;
"#, "#,
)?; )?;
dbg!(long_routes_one_dir_time.elapsed()); dbg!(long_routes_one_dir_time.elapsed());
@ -1087,10 +1087,10 @@ fn air_routes() -> Result<()> {
let longest_routes_time = Instant::now(); let longest_routes_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
?[?src, ?dist, ?dst] := [?r route.distance ?dist], ?dist > 4000, [?r route.src ?s], ?[src, dist, dst] := [r route.distance dist], dist > 4000, [r route.src s],
[?r route.dst ?d], [?s airport.iata ?src], [?d airport.iata ?dst], [r route.dst d], [s airport.iata src], [d airport.iata dst],
?src < ?dst; src < dst;
:sort -?dist; :sort -dist;
:limit 20; :limit 20;
"#, "#,
)?; )?;
@ -1103,9 +1103,9 @@ fn air_routes() -> Result<()> {
let longest_routes_from_each_airports = Instant::now(); let longest_routes_from_each_airports = Instant::now();
let res = db.run_script(r#" let res = db.run_script(r#"
ap[?a, max(?dist)] := [?r route.src ?a], [?r route.distance ?dist]; ap[a, max(dist)] := [r route.src a], [r route.distance dist];
?[?src, ?dist, ?dst] := ap[?a, ?dist], [?r route.src ?a], [?r route.distance ?dist], [?r route.dst ?d], ?[src, dist, dst] := ap[a, dist], [r route.src a], [r route.distance dist], [r route.dst d],
[?a airport.iata ?src], [?d airport.iata ?dst]; [a airport.iata src], [d airport.iata dst];
:limit 10; :limit 10;
"#)?; "#)?;
dbg!(longest_routes_from_each_airports.elapsed()); dbg!(longest_routes_from_each_airports.elapsed());
@ -1116,8 +1116,8 @@ fn air_routes() -> Result<()> {
let total_distance_from_three_cities_time = Instant::now(); let total_distance_from_three_cities_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
three[?a] := ?city <- ..['London', 'Munich', 'Paris'], [?a airport.city ?city]; three[a] := city <- ..['London', 'Munich', 'Paris'], [a airport.city city];
?[sum(?dist)] := three[?a], [?r route.src ?a], [?r route.distance ?dist]; ?[sum(dist)] := three[a], [r route.src a], [r route.distance dist];
"#, "#,
)?; )?;
dbg!(total_distance_from_three_cities_time.elapsed()); dbg!(total_distance_from_three_cities_time.elapsed());
@ -1126,9 +1126,9 @@ fn air_routes() -> Result<()> {
let total_distance_within_three_cities_time = Instant::now(); let total_distance_within_three_cities_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
three[?a] := ?city <- ..['London', 'Munich', 'Paris'], [?a airport.city ?city]; three[a] := city <- ..['London', 'Munich', 'Paris'], [a airport.city city];
?[sum(?dist)] := three[?a], [?r route.src ?a], [?r route.dst ?a2], three[?a2], ?[sum(dist)] := three[a], [r route.src a], [r route.dst a2], three[a2],
[?r route.distance ?dist]; [r route.distance dist];
"#, "#,
)?; )?;
dbg!(total_distance_within_three_cities_time.elapsed()); dbg!(total_distance_within_three_cities_time.elapsed());
@ -1137,8 +1137,8 @@ fn air_routes() -> Result<()> {
let specific_distance_time = Instant::now(); let specific_distance_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
?[?dist] := [?a airport.iata 'AUS'], [?a2 airport.iata 'MEX'], [?r route.src ?a], ?[dist] := [a airport.iata 'AUS'], [a2 airport.iata 'MEX'], [r route.src a],
[?r route.dst ?a2], [?r route.distance ?dist]; [r route.dst a2], [r route.distance dist];
"#, "#,
)?; )?;
dbg!(specific_distance_time.elapsed()); dbg!(specific_distance_time.elapsed());
@ -1147,10 +1147,10 @@ fn air_routes() -> Result<()> {
let n_routes_between_time = Instant::now(); let n_routes_between_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
us_a[?a] := [?us country.code 'US'], [?us geo.contains ?a]; us_a[a] := [us country.code 'US'], [us geo.contains a];
?[count(?r)] := [?r route.distance ?dist], ?dist >= 100, ?dist <= 200, ?[count(r)] := [r route.distance dist], dist >= 100, dist <= 200,
[?r route.src ?s], us_a[?s], [r route.src s], us_a[s],
[?r route.dst ?d], us_a[?d]; [r route.dst d], us_a[d];
"#, "#,
)?; )?;
dbg!(n_routes_between_time.elapsed()); dbg!(n_routes_between_time.elapsed());
@ -1159,11 +1159,11 @@ fn air_routes() -> Result<()> {
let one_stop_distance_time = Instant::now(); let one_stop_distance_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
?[?code, ?dist] := [?s airport.iata 'AUS'], [?r1 route.src ?s], [?r1 route.dst ?a], ?[code, dist] := [s airport.iata 'AUS'], [r1 route.src s], [r1 route.dst a],
[?r2 route.src ?a], [?r2 route.dst ?d], [?d airport.iata 'LHR'], [r2 route.src a], [r2 route.dst d], [d airport.iata 'LHR'],
[?r1 route.distance ?dis1], [?r2 route.distance ?dis2], ?dist <- ?dis1 + ?dis2, [r1 route.distance dis1], [r2 route.distance dis2], dist <- dis1 + dis2,
[?a airport.iata ?code]; [a airport.iata code];
:order ?dist; :order dist;
:limit 10; :limit 10;
"#, "#,
)?; )?;
@ -1181,9 +1181,9 @@ fn air_routes() -> Result<()> {
let airport_most_routes_time = Instant::now(); let airport_most_routes_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
ac[?a, count(?r)] := [?r route.src ?a]; ac[a, count(r)] := [r route.src a];
?[?code, ?n] := ac[?a, ?n], [?a airport.iata ?code]; ?[code, n] := ac[a, n], [a airport.iata code];
:order -?n; :order -n;
:limit 10; :limit 10;
"#, "#,
)?; )?;
@ -1201,7 +1201,7 @@ fn air_routes() -> Result<()> {
let north_of_77_time = Instant::now(); let north_of_77_time = Instant::now();
let res = db.run_script(r#" let res = db.run_script(r#"
?[?city, ?latitude] := [?a airport.lat ?lat], ?lat > 77, [?a airport.city ?city], ?latitude <- round(?lat); ?[city, latitude] := [a airport.lat lat], lat > 77, [a airport.city city], latitude <- round(lat);
"#)?; "#)?;
dbg!(north_of_77_time.elapsed()); dbg!(north_of_77_time.elapsed());
assert_eq!( assert_eq!(
@ -1212,7 +1212,7 @@ fn air_routes() -> Result<()> {
let greenwich_meridian_time = Instant::now(); let greenwich_meridian_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
?[?code] := [?a airport.lon ?lon], ?lon > -0.1, ?lon < 0.1, [?a airport.iata ?code]; ?[code] := [a airport.lon lon], lon > -0.1, lon < 0.1, [a airport.iata code];
"#, "#,
)?; )?;
dbg!(greenwich_meridian_time.elapsed()); dbg!(greenwich_meridian_time.elapsed());
@ -1224,11 +1224,11 @@ fn air_routes() -> Result<()> {
let box_around_heathrow_time = Instant::now(); let box_around_heathrow_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
h_box[?lhr_lon, ?lhr_lat] := [?lhr airport.iata 'LHR'], h_box[lhr_lon, lhr_lat] := [lhr airport.iata 'LHR'],
[?lhr airport.lon ?lhr_lon], [lhr airport.lon lhr_lon],
[?lhr airport.lat ?lhr_lat]; [lhr airport.lat lhr_lat];
?[?code] := h_box[?lhr_lon, ?lhr_lat], [?a airport.lon ?lon], [?a airport.lat ?lat], ?[code] := h_box[lhr_lon, lhr_lat], [a airport.lon lon], [a airport.lat lat],
abs(?lhr_lon - ?lon) < 1, abs(?lhr_lat - ?lat) < 1, [?a airport.iata ?code]; abs(lhr_lon - lon) < 1, abs(lhr_lat - lat) < 1, [a airport.iata code];
"#, "#,
)?; )?;
dbg!(box_around_heathrow_time.elapsed()); dbg!(box_around_heathrow_time.elapsed());
@ -1240,13 +1240,13 @@ fn air_routes() -> Result<()> {
let dfw_by_region_time = Instant::now(); let dfw_by_region_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
?[?region, collect(?code)] := [?dfw airport.iata 'DFW'], ?[region, collect(code)] := [dfw airport.iata 'DFW'],
[?us country.code 'US'], [us country.code 'US'],
[?r route.src ?dfw], [r route.src dfw],
[?r route.dst ?a], [?a airport.country ?us], [r route.dst a], [a airport.country us],
?region <- ..['US-CA', 'US-TX', 'US-FL', 'US-CO', 'US-IL'], region <- ..['US-CA', 'US-TX', 'US-FL', 'US-CO', 'US-IL'],
[?a airport.region ?region], [a airport.region region],
[?a airport.iata ?code]; [a airport.iata code];
"#, "#,
)?; )?;
dbg!(dfw_by_region_time.elapsed()); dbg!(dfw_by_region_time.elapsed());
@ -1262,9 +1262,9 @@ fn air_routes() -> Result<()> {
let great_circle_distance = Instant::now(); let great_circle_distance = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
?[?deg_diff] := [?a airport.iata 'SFO'], [?a airport.lat ?a_lat], [?a airport.lon ?a_lon], ?[deg_diff] := [a airport.iata 'SFO'], [a airport.lat a_lat], [a airport.lon a_lon],
[?b airport.iata 'NRT'], [?b airport.lat ?b_lat], [?b airport.lon ?b_lon], [b airport.iata 'NRT'], [b airport.lat b_lat], [b airport.lon b_lon],
?deg_diff <- round(haversine_deg_input(?a_lat, ?a_lon, ?b_lat, ?b_lon)); deg_diff <- round(haversine_deg_input(a_lat, a_lon, b_lat, b_lon));
"#, "#,
)?; )?;
dbg!(great_circle_distance.elapsed()); dbg!(great_circle_distance.elapsed());
@ -1273,17 +1273,17 @@ fn air_routes() -> Result<()> {
let aus_to_edi_time = Instant::now(); let aus_to_edi_time = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
us_uk_airports[?a] := [?c country.code 'UK'], [?a airport.country ?c]; us_uk_airports[a] := [c country.code 'UK'], [a airport.country c];
us_uk_airports[?a] := [?c country.code 'US'], [?a airport.country ?c]; us_uk_airports[a] := [c country.code 'US'], [a airport.country c];
routes[?a2, shortest(?path)] := [?a airport.iata 'AUS'], [?r route.src ?a], routes[a2, shortest(path)] := [a airport.iata 'AUS'], [r route.src a],
[?r route.dst ?a2], us_uk_airports[?a2], [r route.dst a2], us_uk_airports[a2],
[?a2 airport.iata ?dst], [a2 airport.iata dst],
?path <- ['AUS', ?dst]; path <- ['AUS', dst];
routes[?a2, shortest(?path)] := routes[?a, ?prev], [?r route.src ?a], routes[a2, shortest(path)] := routes[a, prev], [r route.src a],
[?r route.dst ?a2], us_uk_airports[?a2], [r route.dst a2], us_uk_airports[a2],
[?a2 airport.iata ?dst], [a2 airport.iata dst],
?path <- append(?prev, ?dst); path <- append(prev, dst);
?[?path] := [?edi airport.iata 'EDI'], routes[?edi, ?path]; ?[path] := [edi airport.iata 'EDI'], routes[edi, path];
"#, "#,
)?; )?;
dbg!(aus_to_edi_time.elapsed()); dbg!(aus_to_edi_time.elapsed());
@ -1292,17 +1292,17 @@ fn air_routes() -> Result<()> {
let reachable_from_lhr = Instant::now(); let reachable_from_lhr = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
routes[?a2, shortest(?path)] := [?a airport.iata 'LHR'], [?r route.src ?a], routes[a2, shortest(path)] := [a airport.iata 'LHR'], [r route.src a],
[?r route.dst ?a2], [r route.dst a2],
[?a2 airport.iata ?dst], [a2 airport.iata dst],
?path <- ['LHR', ?dst]; path <- ['LHR', dst];
routes[?a2, shortest(?path)] := routes[?a, ?prev], [?r route.src ?a], routes[a2, shortest(path)] := routes[a, prev], [r route.src a],
[?r route.dst ?a2], [r route.dst a2],
[?a2 airport.iata ?dst], [a2 airport.iata dst],
?path <- append(?prev, ?dst); path <- append(prev, dst);
?[?len, ?path] := routes[?_, ?path], ?len <- length(?path); ?[len, path] := routes[_, path], len <- length(path);
:order -?len; :order -len;
:limit 10; :limit 10;
"#, "#,
)?; )?;
@ -1325,21 +1325,21 @@ fn air_routes() -> Result<()> {
let furthest_from_lhr = Instant::now(); let furthest_from_lhr = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
routes[?a2, min_cost(?cost_pair)] := [?a airport.iata 'LHR'], [?r route.src ?a], routes[a2, min_cost(cost_pair)] := [a airport.iata 'LHR'], [r route.src a],
[?r route.dst ?a2], [r route.dst a2],
[?r route.distance ?dist], [r route.distance dist],
[?a2 airport.iata ?dst], [a2 airport.iata dst],
?path <- ['LHR', ?dst], path <- ['LHR', dst],
?cost_pair <- [?path, ?dist]; cost_pair <- [path, dist];
routes[?a2, min_cost(?cost_pair)] := routes[?a, ?prev], [?r route.src ?a], routes[a2, min_cost(cost_pair)] := routes[a, prev], [r route.src a],
[?r route.dst ?a2], [r route.dst a2],
[?r route.distance ?dist], [r route.distance dist],
[?a2 airport.iata ?dst], [a2 airport.iata dst],
?path <- append(first(?prev), ?dst), path <- append(first(prev), dst),
?cost_pair <- [?path, last(?prev) + ?dist]; cost_pair <- [path, last(prev) + dist];
?[?cost, ?path] := routes[?dst, ?cost_pair], ?cost <- last(?cost_pair), ?path <- first(?cost_pair); ?[cost, path] := routes[dst, cost_pair], cost <- last(cost_pair), path <- first(cost_pair);
:order -?cost; :order -cost;
:limit 10; :limit 10;
"#, "#,
)?; )?;
@ -1361,17 +1361,17 @@ fn air_routes() -> Result<()> {
let furthest_from_lhr_view = Instant::now(); let furthest_from_lhr_view = Instant::now();
let res = db.run_script( let res = db.run_script(
r#" r#"
routes[?a2, min_cost(?cost_pair)] := [?a airport.iata 'LHR'], :flies_to[?a, ?a2, ?dist], routes[a2, min_cost(cost_pair)] := [a airport.iata 'LHR'], :flies_to[a, a2, dist],
[?a2 airport.iata ?dst], [a2 airport.iata dst],
?path <- ['LHR', ?dst], path <- ['LHR', dst],
?cost_pair <- [?path, ?dist]; cost_pair <- [path, dist];
routes[?a2, min_cost(?cost_pair)] := routes[?a, ?prev], :flies_to[?a, ?a2, ?dist], routes[a2, min_cost(cost_pair)] := routes[a, prev], :flies_to[a, a2, dist],
[?a2 airport.iata ?dst], [a2 airport.iata dst],
?path <- append(first(?prev), ?dst), path <- append(first(prev), dst),
?cost_pair <- [?path, last(?prev) + ?dist]; cost_pair <- [path, last(prev) + dist];
?[?cost, ?path] := routes[?dst, ?cost_pair], ?cost <- last(?cost_pair), ?path <- first(?cost_pair); ?[cost, path] := routes[dst, cost_pair], cost <- last(cost_pair), path <- first(cost_pair);
:order -?cost; :order -cost;
:limit 10; :limit 10;
"#, "#,
)?; )?;

Loading…
Cancel
Save