Compare commits
2 commits
89a2a077c0
...
07b5cd8e6a
Author | SHA1 | Date | |
---|---|---|---|
|
07b5cd8e6a | ||
|
5d84b017b9 |
5 changed files with 128 additions and 60 deletions
|
@ -15,9 +15,9 @@ struct PreHasseNode {
|
|||
|
||||
/* fullfillment of links is sort-of complicated, because the tree of possiblities is really large
|
||||
|
||||
* start by splitting links according to their roots (the variable of which derivative of such is taken)
|
||||
* split the derivation-vectors into levels (sum of their components)
|
||||
*/
|
||||
* start by splitting links according to their roots (the variable of which derivative of such is taken)
|
||||
* split the derivation-vectors into levels (sum of their components)
|
||||
*/
|
||||
|
||||
fn sum(drvs: &[u8]) -> usize {
|
||||
drvs.iter().copied().map(usize::from).sum::<usize>()
|
||||
|
@ -47,24 +47,32 @@ fn calculate_votes(mut que: Vec<Box<[u8]>>) -> Vec<BTreeMap<Box<[u8]>, VoteEntry
|
|||
|
||||
// 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))
|
||||
.take(
|
||||
que.iter()
|
||||
.map(|i| sum(&i[..]))
|
||||
.max()
|
||||
.map(|i| i.checked_add(1).unwrap())
|
||||
.unwrap_or(0),
|
||||
)
|
||||
.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, VoteEntry {
|
||||
votes: 1,
|
||||
best_parent: 0,
|
||||
is_used: true,
|
||||
});
|
||||
for i in core::mem::take(&mut que) {
|
||||
levels[sum(&i[..])].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()) {
|
||||
let mut v = i.entry(j).or_default();
|
||||
v.votes = v.votes.checked_add(1).unwrap();
|
||||
for j in core::mem::take(&mut que) {
|
||||
let votes = &mut i.entry(j).or_default().votes;
|
||||
*votes = votes.checked_add(1).unwrap();
|
||||
}
|
||||
|
||||
// handle all items in this level
|
||||
|
@ -91,12 +99,17 @@ fn calculate_votes(mut que: Vec<Box<[u8]>>) -> Vec<BTreeMap<Box<[u8]>, VoteEntry
|
|||
} 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 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
|
||||
|
@ -138,9 +151,9 @@ pub fn fullfill_links(que: Vec<Link>) -> Vec<Vec<Vec<(Box<[u8]>, u16)>>> {
|
|||
let mut ret = vec![Vec::new(); max_vid];
|
||||
|
||||
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());
|
||||
let votes = calculate_votes(que.clone());
|
||||
let 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() {
|
||||
|
|
|
@ -33,12 +33,14 @@ pub enum Expr<L> {
|
|||
impl<L: Clone + Eq + Ord> Expr<L> {
|
||||
fn extract_links_intern(&self, out: &mut Vec<L>) {
|
||||
match self {
|
||||
Expr::Const(_) => {},
|
||||
Expr::Const(_) => {}
|
||||
Expr::Link(l) => out.push(l.clone()),
|
||||
Expr::Sum(xs) => xs.iter().for_each(|i| i.extract_links_intern(out)),
|
||||
Expr::Prod(xs) => xs.iter().for_each(|i| i.extract_links_intern(out)),
|
||||
|
||||
Expr::Sine(x) | Expr::Cosine(x) | Expr::Tangens(x) | Expr::ArcTan(x) => x.extract_links_intern(out),
|
||||
Expr::Sine(x) | Expr::Cosine(x) | Expr::Tangens(x) | Expr::ArcTan(x) => {
|
||||
x.extract_links_intern(out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,8 +72,12 @@ pub struct System {
|
|||
impl System {
|
||||
pub fn extract_links(&self) -> Vec<Link> {
|
||||
let mut ret = Vec::new();
|
||||
self.vs.iter().for_each(|i| i.extract_links_intern(&mut ret));
|
||||
self.mons.iter().for_each(|i| i.1.extract_links_intern(&mut ret));
|
||||
self.vs
|
||||
.iter()
|
||||
.for_each(|i| i.extract_links_intern(&mut ret));
|
||||
self.mons
|
||||
.iter()
|
||||
.for_each(|i| i.1.extract_links_intern(&mut ret));
|
||||
ret.sort_unstable();
|
||||
ret.dedup();
|
||||
ret
|
||||
|
@ -79,7 +85,9 @@ impl System {
|
|||
|
||||
// this is invoked for each time step times points in space for which the links can be computed
|
||||
pub fn interp_vs(&self, link_data: &BTreeMap<Link, f64>, out: &mut [f64]) {
|
||||
self.vs.iter().zip(out.iter_mut()).for_each(|(x, y)| { *y = x.interp(link_data); });
|
||||
self.vs.iter().zip(out.iter_mut()).for_each(|(x, y)| {
|
||||
*y = x.interp(link_data);
|
||||
});
|
||||
}
|
||||
|
||||
// this is invoked once per time step
|
||||
|
@ -97,14 +105,16 @@ impl System {
|
|||
}
|
||||
|
||||
pub fn interp_mons_data(&self, link_data: &BTreeMap<Link, f64>, out: &mut [f64]) {
|
||||
self.mons.iter().zip(out.iter_mut()).for_each(|(x, y)| { *y = x.1.interp(link_data); });
|
||||
self.mons.iter().zip(out.iter_mut()).for_each(|(x, y)| {
|
||||
*y = x.1.interp(link_data);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, thiserror::Error)]
|
||||
pub enum ParseError {
|
||||
#[error("unexpected end of expression")]
|
||||
EmptyExpr,
|
||||
UnexpectedEol,
|
||||
|
||||
#[error("unexpected invalid char '{0}'")]
|
||||
InvalidChar(char),
|
||||
|
@ -131,14 +141,14 @@ pub enum ParseError {
|
|||
Float(#[from] std::num::ParseFloatError),
|
||||
}
|
||||
|
||||
trait ParseLink: Sized {
|
||||
pub trait ParseLink: Sized {
|
||||
fn parse_link(slb: &mut StrLexerBase<'_>) -> Result<Option<Self>, ParseError>;
|
||||
}
|
||||
|
||||
impl ParseLink for () {
|
||||
fn parse_link(slb: &mut StrLexerBase<'_>) -> Result<Option<Self>, ParseError> {
|
||||
if slb.inp.is_empty() {
|
||||
Err(ParseError::EmptyExpr)
|
||||
Err(ParseError::UnexpectedEol)
|
||||
} else if slb.inp.starts_with('.') {
|
||||
slb.consume(1);
|
||||
Ok(Some(()))
|
||||
|
@ -151,9 +161,9 @@ impl ParseLink for () {
|
|||
impl ParseLink for Link {
|
||||
fn parse_link(slb: &mut StrLexerBase<'_>) -> Result<Option<Self>, ParseError> {
|
||||
if slb.inp.is_empty() {
|
||||
Err(ParseError::EmptyExpr)
|
||||
Err(ParseError::UnexpectedEol)
|
||||
} else {
|
||||
let mut new_slb = (*slb).clone();
|
||||
let mut new_slb = *slb;
|
||||
let var = new_slb.consume_select(|i| i.is_ascii_digit());
|
||||
if var.is_empty() {
|
||||
return Ok(None);
|
||||
|
@ -186,9 +196,12 @@ fn parse_expr<L: Clone + ParseLink>(slb: &mut StrLexerBase<'_>) -> Result<Expr<L
|
|||
return Ok(Expr::Link(x));
|
||||
}
|
||||
|
||||
if slb.inp.starts_with(|i: char| i == '-' || i.is_ascii_digit()) {
|
||||
if slb
|
||||
.inp
|
||||
.starts_with(|i: char| i == '-' || i.is_ascii_digit())
|
||||
{
|
||||
// float
|
||||
let mut new_slb = (*slb).clone();
|
||||
let mut new_slb = *slb;
|
||||
|
||||
let neg = new_slb.inp.bytes().next() == Some(b'-');
|
||||
if neg {
|
||||
|
@ -205,7 +218,7 @@ fn parse_expr<L: Clone + ParseLink>(slb: &mut StrLexerBase<'_>) -> Result<Expr<L
|
|||
|
||||
let ident = slb.consume_select(|i| i.is_ascii_alphanumeric());
|
||||
if slb.inp.is_empty() {
|
||||
return Err(ParseError::EmptyExpr);
|
||||
return Err(ParseError::UnexpectedEol);
|
||||
}
|
||||
if ident.is_empty() {
|
||||
let c = slb.inp.chars().next().unwrap();
|
||||
|
@ -213,7 +226,7 @@ fn parse_expr<L: Clone + ParseLink>(slb: &mut StrLexerBase<'_>) -> Result<Expr<L
|
|||
}
|
||||
|
||||
// parse nesting...
|
||||
if slb.inp.chars().next() != Some('(') {
|
||||
if !slb.inp.starts_with('(') {
|
||||
let c = slb.inp.chars().next().unwrap();
|
||||
return Err(ParseError::InvalidChar(c));
|
||||
}
|
||||
|
@ -223,13 +236,17 @@ fn parse_expr<L: Clone + ParseLink>(slb: &mut StrLexerBase<'_>) -> Result<Expr<L
|
|||
loop {
|
||||
args.push(parse_expr::<L>(slb)?);
|
||||
slb.consume_select(|i| i.is_whitespace());
|
||||
if slb.inp.chars().next() != Some(',') {
|
||||
if !slb.inp.starts_with(',') {
|
||||
break;
|
||||
}
|
||||
slb.consume(1);
|
||||
}
|
||||
|
||||
if slb.inp.chars().next() != Some(')') {
|
||||
if slb.inp.is_empty() {
|
||||
return Err(ParseError::UnexpectedEol);
|
||||
}
|
||||
|
||||
if !slb.inp.starts_with(')') {
|
||||
let c = slb.inp.chars().next().unwrap();
|
||||
return Err(ParseError::InvalidChar(c));
|
||||
}
|
||||
|
@ -242,12 +259,16 @@ fn parse_expr<L: Clone + ParseLink>(slb: &mut StrLexerBase<'_>) -> Result<Expr<L
|
|||
("cos", [arg]) => Ok(Expr::Cosine(Box::new(arg.clone()))),
|
||||
("tan", [arg]) => Ok(Expr::Tangens(Box::new(arg.clone()))),
|
||||
("atan", [arg]) => Ok(Expr::ArcTan(Box::new(arg.clone()))),
|
||||
("sin" | "cos" | "tan" | "atan", _) => Err(ParseError::InvalidArgCount(ident.to_string(), args.len())),
|
||||
("sin" | "cos" | "tan" | "atan", _) => {
|
||||
Err(ParseError::InvalidArgCount(ident.to_string(), args.len()))
|
||||
}
|
||||
_ => Err(ParseError::UnknownFun(ident.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_expr_final<L: Clone + ParseLink>(slb: &mut StrLexerBase) -> Result<Expr<L>, ParseError> {
|
||||
pub fn parse_expr_final<L: Clone + ParseLink>(
|
||||
slb: &mut StrLexerBase,
|
||||
) -> Result<Expr<L>, ParseError> {
|
||||
let x = parse_expr(slb)?;
|
||||
if !slb.inp.is_empty() {
|
||||
return Err(ParseError::InvalidTrail);
|
||||
|
@ -314,7 +335,7 @@ pub fn parse_system(s: &str) -> Result<System, ((usize, usize), ParseError)> {
|
|||
[x] => (0, x),
|
||||
[x, y] => {
|
||||
match x.parse::<usize>() {
|
||||
Ok(xid) if xid == ret.vs.len() => {},
|
||||
Ok(xid) if xid == ret.vs.len() => {}
|
||||
_ => return Err(((lnr, 0), ParseError::InvalidStmtId)),
|
||||
}
|
||||
(x.len() + 1, y)
|
||||
|
@ -333,7 +354,10 @@ pub fn parse_system(s: &str) -> Result<System, ((usize, usize), ParseError)> {
|
|||
if parts.len() < 2 {
|
||||
return Err(((lnr, 0), ParseError::InvalidLineFormat));
|
||||
}
|
||||
let mut slb = StrLexerBase { inp: parts[0], offset: 0 };
|
||||
let mut slb = StrLexerBase {
|
||||
inp: parts[0],
|
||||
offset: 0,
|
||||
};
|
||||
let valxp = match parse_expr_final::<Link>(&mut slb) {
|
||||
Ok(x) => x,
|
||||
Err(e) => return Err(((lnr, slb.offset), e)),
|
||||
|
@ -363,17 +387,25 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn example0_fail() {
|
||||
assert_eq!(parse_system("
|
||||
assert_eq!(
|
||||
parse_system(
|
||||
"
|
||||
%vs
|
||||
# u_t + 0.11 u_x = 0
|
||||
0; -0.11 0_0_
|
||||
|
||||
"), Err(((3, 8), ParseError::InvalidTrail)));
|
||||
"
|
||||
),
|
||||
Err(((3, 8), ParseError::InvalidTrail))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn example0() {
|
||||
println!("{:?}", parse_system("
|
||||
println!(
|
||||
"{:?}",
|
||||
parse_system(
|
||||
"
|
||||
%vs
|
||||
# u_t + 0.11 u_x = 0
|
||||
0; prod(-0.11, 0_1_)
|
||||
|
@ -381,6 +413,9 @@ mod tests {
|
|||
%mons
|
||||
# monitor u @ 1 + sin(t)
|
||||
0_0; sum(1.0, sin(.))
|
||||
").unwrap());
|
||||
"
|
||||
)
|
||||
.unwrap()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
18
src/main.rs
18
src/main.rs
|
@ -42,12 +42,17 @@ fn main() {
|
|||
// parse system
|
||||
let system = {
|
||||
let system = std::fs::read(&cli.system).expect("unable to read system to render");
|
||||
let system = std::str::from_utf8(&*system).expect("unable to interpret system description as UTF-8");
|
||||
let system =
|
||||
std::str::from_utf8(&system).expect("unable to interpret system description as UTF-8");
|
||||
expr::parse_system(system).expect("unable to parse system")
|
||||
};
|
||||
|
||||
// parse init function
|
||||
let init = expr::parse_expr_final::<expr::Link>(&mut yz_string_utils::StrLexerBase { inp: &cli.init, offset: 0 }).expect("unable to parse init function");
|
||||
let init = expr::parse_expr_final::<expr::Link>(&mut yz_string_utils::StrLexerBase {
|
||||
inp: &cli.init,
|
||||
offset: 0,
|
||||
})
|
||||
.expect("unable to parse init function");
|
||||
|
||||
// construct shape
|
||||
let shape = mesh::grid::Shape(cli.shape);
|
||||
|
@ -61,7 +66,12 @@ fn main() {
|
|||
// check monitor consistency with shape
|
||||
for (n, (i, _)) in system.mons[..].iter().enumerate() {
|
||||
if i.len() != shape.0.len() {
|
||||
panic!("monitor {} has incompatible dimension {} vs {}", n, i.len(), shape.0.len());
|
||||
panic!(
|
||||
"monitor {} has incompatible dimension {} vs {}",
|
||||
n,
|
||||
i.len(),
|
||||
shape.0.len()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,7 +92,7 @@ fn main() {
|
|||
let mut grid = nalgebra::DMatrix::<f64>::zeros(shape_amount, system.vs.len());
|
||||
let mut grid_stage = nalgebra::DMatrix::<f64>::zeros(shape_amount, system.vs.len());
|
||||
|
||||
// data =
|
||||
// data =
|
||||
|
||||
let mut grid_next = grid.clone();
|
||||
|
||||
|
|
|
@ -18,16 +18,19 @@ struct ForEachStencilData<'a, F> {
|
|||
|
||||
impl<F: FnMut(&[u16])> ForEachStencilData<'_, F> {
|
||||
fn fe_st_intern(&mut self, shape: &[u16]) {
|
||||
let prefix: usize = self.buf.len().checked_sub(shape.len()).expect("buffer too small");
|
||||
let prefix: usize = self
|
||||
.buf
|
||||
.len()
|
||||
.checked_sub(shape.len())
|
||||
.expect("buffer too small");
|
||||
|
||||
// recurse over `this`
|
||||
if let Some(&fi) = shape.get(0) {
|
||||
if let Some(&fi) = shape.first() {
|
||||
let shnext = &shape[1..];
|
||||
for i in self.stencil_start .. (fi + 1 - self.stencil_end) {
|
||||
for i in self.stencil_start..(fi + 1 - self.stencil_end) {
|
||||
self.buf[prefix] = i;
|
||||
self.fe_st_intern(shnext);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
(*self.f)(self.buf);
|
||||
}
|
||||
|
@ -37,12 +40,14 @@ impl<F: FnMut(&[u16])> ForEachStencilData<'_, F> {
|
|||
impl Shape {
|
||||
pub fn amount(&self) -> Option<usize> {
|
||||
assert!(self.0.len() <= usize::from(u16::MAX));
|
||||
self.0.iter()
|
||||
.try_fold(1, |acc: usize, &i| acc.checked_mul(usize::from(i).checked_add(1)?))
|
||||
self.0.iter().try_fold(1, |acc: usize, &i| {
|
||||
acc.checked_mul(usize::from(i).checked_add(1)?)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn decode_pos_with_ret(&self, x: usize, out: &mut [u16]) {
|
||||
self.0.iter()
|
||||
self.0
|
||||
.iter()
|
||||
.map(|&i| usize::from(i) + 1)
|
||||
.zip(out.iter_mut())
|
||||
.fold(x, |x: usize, (i, o)| {
|
||||
|
@ -59,7 +64,8 @@ impl Shape {
|
|||
}
|
||||
|
||||
pub fn encode_pos(&self, x: &[u16]) -> Option<usize> {
|
||||
self.0.iter()
|
||||
self.0
|
||||
.iter()
|
||||
.map(|&i| usize::from(i) + 1)
|
||||
.zip(x.iter().map(|&i| usize::from(i)))
|
||||
.rev()
|
||||
|
@ -68,11 +74,15 @@ impl Shape {
|
|||
return None;
|
||||
}
|
||||
// (v, acc) = (x % s, x / s)
|
||||
Some(acc.checked_mul(s)?.checked_add(v)?)
|
||||
acc.checked_mul(s)?.checked_add(v)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn for_each_stencil(&self, stencil: core::ops::RangeInclusive<i16>, mut f: impl FnMut(&[u16])) {
|
||||
pub fn for_each_stencil(
|
||||
&self,
|
||||
stencil: core::ops::RangeInclusive<i16>,
|
||||
mut f: impl FnMut(&[u16]),
|
||||
) {
|
||||
assert!(*stencil.start() <= 0);
|
||||
assert!(*stencil.end() >= 0);
|
||||
assert!(self.0.len() <= usize::from(u16::MAX));
|
||||
|
@ -82,7 +92,8 @@ impl Shape {
|
|||
stencil_end: *stencil.end() as u16,
|
||||
buf: &mut buf[..],
|
||||
f: &mut f,
|
||||
}.fe_st_intern(&self.0[..])
|
||||
}
|
||||
.fe_st_intern(&self.0[..])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
* SPDX-License-Identifier: EUPL-1.2
|
||||
*/
|
||||
/// pdxdrive meshes
|
||||
|
||||
pub mod grid;
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue