+fullfill_links
This commit is contained in:
parent
938cf2de3b
commit
89a2a077c0
4 changed files with 176 additions and 55 deletions
|
@ -1,6 +1,6 @@
|
|||
//! query planning for link derivative computation.
|
||||
|
||||
//use super::Link;
|
||||
use super::Link;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/*
|
||||
|
@ -34,35 +34,86 @@ fn parents(drvs: &[u8]) -> impl Iterator<Item = Box<[u8]>> + '_ {
|
|||
})
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
struct VoteEntry {
|
||||
votes: u16,
|
||||
best_parent: u16,
|
||||
is_used: bool,
|
||||
}
|
||||
|
||||
/// calculate votes for each possible parent
|
||||
fn calculate_votes(mut que: Vec<Box<[u8]>>) -> Vec<BTreeMap<Box<[u8]>, u16>> {
|
||||
fn calculate_votes(mut que: Vec<Box<[u8]>>) -> Vec<BTreeMap<Box<[u8]>, VoteEntry>> {
|
||||
assert!(que.len() <= usize::from(u16::MAX));
|
||||
|
||||
// split que into levels
|
||||
let mut levels = core::iter::repeat_with(BTreeMap::new)
|
||||
.take(que.iter().map(|i| sum(&i[..])).max().map(|i| i.checked_add(1).unwrap()).unwrap_or(0))
|
||||
.collect::<Vec<BTreeMap<Box<[u8]>, u16>>>();
|
||||
.collect::<Vec<BTreeMap<Box<[u8]>, VoteEntry>>>();
|
||||
|
||||
for i in core::mem::replace(&mut que, Vec::new()) {
|
||||
let mut l = &mut levels[sum(&i[..])];
|
||||
l.insert(i, 1);
|
||||
l.insert(i, VoteEntry {
|
||||
votes: 1,
|
||||
best_parent: 0,
|
||||
is_used: true,
|
||||
});
|
||||
}
|
||||
|
||||
// process levels (start from largest)
|
||||
for (lid, i) in levels.iter_mut().enumerate().rev() {
|
||||
// insert queued items into this level
|
||||
for j in core::mem::replace(&mut que, Vec::new()) {
|
||||
assert_eq!(lid, sum(&j[..]));
|
||||
let mut v = i.entry(j).or_default();
|
||||
*v = v.checked_add(1).unwrap();
|
||||
v.votes = v.votes.checked_add(1).unwrap();
|
||||
}
|
||||
|
||||
// handle all items in this level
|
||||
for (j, v) in i.iter_mut() {
|
||||
for j in i.keys() {
|
||||
assert_eq!(lid, sum(&j[..]));
|
||||
que.extend(parents(&j[..]));
|
||||
}
|
||||
}
|
||||
|
||||
// calculate best parent for each entry
|
||||
for lid in (0..levels.len() - 1).rev() {
|
||||
let mut taken = core::mem::take(&mut levels[lid + 1]);
|
||||
let plvl = &mut levels[lid];
|
||||
taken.retain(|_, j| j.is_used);
|
||||
|
||||
for (j, v) in taken.iter_mut() {
|
||||
let mut pbs = None;
|
||||
for k in parents(j) {
|
||||
pbs = Some(match pbs {
|
||||
None => k,
|
||||
Some(x) => {
|
||||
if plvl[&k].votes > plvl[&x].votes {
|
||||
k
|
||||
} else {
|
||||
x
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
let pbs = pbs.unwrap();
|
||||
let pbs_index = {
|
||||
let mut pbsi = j.iter().zip(pbs.iter()).map(|(i, p)| i - p).enumerate().filter(|(_, i)| *i > 0);
|
||||
let pbs_index = pbsi.next().unwrap();
|
||||
assert_eq!(pbsi.next(), None);
|
||||
pbs_index
|
||||
};
|
||||
assert_eq!(pbs_index.1, 1);
|
||||
|
||||
v.best_parent = pbs_index.0.try_into().unwrap();
|
||||
|
||||
// propagate dependency
|
||||
if v.is_used {
|
||||
plvl.get_mut(&pbs).unwrap().is_used = true;
|
||||
}
|
||||
}
|
||||
|
||||
levels[lid + 1] = taken;
|
||||
}
|
||||
|
||||
levels
|
||||
}
|
||||
|
||||
|
@ -70,27 +121,36 @@ fn calculate_votes(mut que: Vec<Box<[u8]>>) -> Vec<BTreeMap<Box<[u8]>, u16>> {
|
|||
/// and compute the parent
|
||||
///
|
||||
/// maximize reuse of the same derivatives
|
||||
/*
|
||||
pub fn fullfill_links(que: Vec<Link>) -> HashMap<u16, Vec<(Box<[u16]>, u16)>> {
|
||||
let mut g = HashMap::<Vec<_>>::new();
|
||||
///
|
||||
/// return value is structures as: `[root variable] [level] [.] -> (derivative, best_parent)`
|
||||
pub fn fullfill_links(que: Vec<Link>) -> Vec<Vec<Vec<(Box<[u8]>, u16)>>> {
|
||||
let mut g = BTreeMap::<u16, Vec<_>>::new();
|
||||
|
||||
// sort the links by root variable
|
||||
for (vid, drv) in que {
|
||||
let mut max_vid = 1;
|
||||
for Link(vid, drv) in que {
|
||||
g.entry(vid).or_default().push(drv);
|
||||
if usize::from(vid) >= max_vid {
|
||||
max_vid = usize::from(vid) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (vid, que) in que {
|
||||
let votes = calculate_votes(que.clone());
|
||||
let mut ret = vec![Vec::new(); max_vid];
|
||||
|
||||
for i in que {
|
||||
|
||||
for j in parents(i) {
|
||||
|
||||
for (vid, que) in g {
|
||||
let mut votes = calculate_votes(que.clone());
|
||||
let mut ret = &mut ret[usize::from(vid)];
|
||||
ret.resize_with(votes.len(), || Vec::new());
|
||||
|
||||
for (i, j) in ret.iter_mut().zip(votes.into_iter()) {
|
||||
for (k, l) in j.into_iter() {
|
||||
i.push((k, l.best_parent));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
*/
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
@ -103,4 +163,12 @@ mod tests {
|
|||
vec![0, 1, 1, 1].into_boxed_slice(),
|
||||
]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fullfill_links() {
|
||||
insta::assert_debug_snapshot!(fullfill_links(vec![
|
||||
Link(0, vec![0, 1, 2, 0].into_boxed_slice()),
|
||||
Link(0, vec![0, 1, 1, 1].into_boxed_slice()),
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ use yz_string_utils::StrLexerBase;
|
|||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Link(pub u16, pub Box<[u8]>);
|
||||
|
||||
pub use linkplan::fullfill_links;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Expr<L> {
|
||||
Const(f64),
|
||||
|
|
|
@ -9,53 +9,35 @@ expression: "calculate_votes(vec![vec![0, 1, 2, 0].into_boxed_slice(),\n
|
|||
0,
|
||||
0,
|
||||
0,
|
||||
]: 3,
|
||||
},
|
||||
{
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
]: 2,
|
||||
[
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]: 3,
|
||||
[
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
]: 2,
|
||||
]: VoteEntry {
|
||||
votes: 3,
|
||||
best_parent: 0,
|
||||
is_used: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
[
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
]: 1,
|
||||
[
|
||||
0,
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
]: 1,
|
||||
[
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
]: 1,
|
||||
]: VoteEntry {
|
||||
votes: 3,
|
||||
best_parent: 2,
|
||||
is_used: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
[
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
]: 2,
|
||||
]: VoteEntry {
|
||||
votes: 2,
|
||||
best_parent: 1,
|
||||
is_used: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
[
|
||||
|
@ -63,12 +45,20 @@ expression: "calculate_votes(vec![vec![0, 1, 2, 0].into_boxed_slice(),\n
|
|||
1,
|
||||
1,
|
||||
1,
|
||||
]: 1,
|
||||
]: VoteEntry {
|
||||
votes: 1,
|
||||
best_parent: 3,
|
||||
is_used: true,
|
||||
},
|
||||
[
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
0,
|
||||
]: 1,
|
||||
]: VoteEntry {
|
||||
votes: 1,
|
||||
best_parent: 2,
|
||||
is_used: true,
|
||||
},
|
||||
},
|
||||
]
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
---
|
||||
source: src/expr/linkplan.rs
|
||||
expression: "fullfill_links(vec![Link(0, vec![0, 1, 2, 0].into_boxed_slice()),\n Link(0, vec![0, 1, 1, 1].into_boxed_slice()),])"
|
||||
---
|
||||
[
|
||||
[
|
||||
[
|
||||
(
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
0,
|
||||
),
|
||||
],
|
||||
[
|
||||
(
|
||||
[
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
],
|
||||
2,
|
||||
),
|
||||
],
|
||||
[
|
||||
(
|
||||
[
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
],
|
||||
1,
|
||||
),
|
||||
],
|
||||
[
|
||||
(
|
||||
[
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
],
|
||||
3,
|
||||
),
|
||||
(
|
||||
[
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
0,
|
||||
],
|
||||
2,
|
||||
),
|
||||
],
|
||||
],
|
||||
]
|
Loading…
Reference in a new issue