#![allow(warnings)]
#![feature(iter_intersperse)]
// New runtime
// requirements:
// pass all tests
// robust units
// all number types
// Unicode
// async blocks
// parallel operators
// rewind capability
// pre-serialized memory layout
// performance target: 10 million updates per 60Hz cycle
// stack allocated tables
// matrix library in std
use std::sync::Arc;
use std::cell::RefCell;
use std::fmt;
use std::ptr;
use std::rc::Rc;
use hashbrown::{HashMap, HashSet};
use std::time::{Instant};
use std::collections::VecDeque;
use mech_core::*;
//use mech_core::function::table;
use nalgebra::*;
use std::fmt::*;
use num_traits::*;
use std::ops::*;
extern crate time;
fn main() -> std::result::Result<(),MechError> {
let n = 10000;
//let x = new_ref(Matrix6::from_element(F64::new(1.0)));
let x = new_ref(DMatrix::from_element(n,4,F64::new(1.0)));
let source = F64::new(5.0);
let source_c = source.clone();
unsafe {
//let sink = x.as_ptr();
let sink = &mut *(x.as_ptr());
let mut column = sink.column_mut(0);
let now = Instant::now();
for _ in 0..1e6 as usize {
for i in 0..n {
//(*sink).column_mut(0)[i] = source_c;
column[i] = source_c;
}
}
let elapsed_time = now.elapsed();
let cycle_duration = elapsed_time.as_nanos() as f64;
println!("{:0.2?} ns", cycle_duration / 1000000.0);
}
/*
//let now = Instant::now();
let n = 1e7 as usize;
let sizes: Vec<usize> = vec![1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7].iter().map(|x| *x as usize).collect();
// Create a core
let mut core = Core::new();
{
// #time/timer += [period: 60Hz]
let mut time_timer = Table::new(hash_str("time/timer"),1,2);
time_timer.set_col_kind(0,ValueKind::f32);
time_timer.set_col_kind(1,ValueKind::f32);
time_timer.set_raw(0,0,Value::f32(60.0));
core.insert_table(time_timer);
// #gravity = 1
let mut gravity = Table::new(hash_str("gravity"),1,1);
gravity.set_col_kind(0,ValueKind::f32);
gravity.set_raw(0,0,Value::f32(1.0));
core.insert_table(gravity);
// -80%
let mut const1 = Table::new(hash_str("-0.8"),1,1);
const1.set_col_kind(0,ValueKind::f32);
const1.set_raw(0,0,Value::f32(-0.8));
core.insert_table(const1);
// 500
let mut const2 = Table::new(hash_str("500.0"),1,1);
const2.set_col_kind(0,ValueKind::f32);
const2.set_raw(0,0,Value::f32(500.0));
core.insert_table(const2);
// 0
let mut const3 = Table::new(hash_str("0.0"),1,1);
const3.set_col_kind(0,ValueKind::f32);
const3.set_raw(0,0,Value::f32(0.0));
core.insert_table(const3);
// Create balls
// #balls = [x: 0:n y: 0:n vx: 3.0 vy: 4.0]
let mut balls = Table::new(hash_str("balls"),n,4);
balls.set_col_kind(0,ValueKind::f32);
balls.set_col_kind(1,ValueKind::f32);
balls.set_col_kind(2,ValueKind::f32);
balls.set_col_kind(3,ValueKind::f32);
for i in 0..n {
balls.set_raw(i,0,Value::f32(i as f32));
balls.set_raw(i,1,Value::f32(i as f32));
balls.set_raw(i,2,Value::f32(3.0));
balls.set_raw(i,3,Value::f32(4.0));
}
core.insert_table(balls);
}
// Table
let (x,y,vx,vy) = {
match core.get_table_by_id(hash_str("balls")) {
Ok(balls_rc) => {
let balls = balls_rc.borrow();
(balls.get_column_unchecked(0),
balls.get_column_unchecked(1),
balls.get_column_unchecked(2),
balls.get_column_unchecked(3))
}
_ => std::process::exit(1),
}
};
let g = {
match core.get_table_by_id(hash_str("gravity")) {
Ok(gravity_rc) => {
let gravity = gravity_rc.borrow();
gravity.get_column_unchecked(0)
}
_ => std::process::exit(1),
}
};
let c1 = {
match core.get_table_by_id(hash_str("-0.8")) {
Ok(const1_rc) => {
let const1 = const1_rc.borrow();
const1.get_column_unchecked(0)
}
_ => std::process::exit(1),
}
};
let c500 = {
match core.get_table_by_id(hash_str("500.0")) {
Ok(const1_rc) => {
let const1 = const1_rc.borrow();
const1.get_column_unchecked(0)
}
_ => std::process::exit(1),
}
};
let c0 = {
match core.get_table_by_id(hash_str("0.0")) {
Ok(const1_rc) => {
let const1 = const1_rc.borrow();
const1.get_column_unchecked(0)
}
_ => std::process::exit(1),
}
};
// Temp Vars
let mut vy2 = Column::f32(ColumnV::new(vec![0.0; n]));
let mut iy = Column::Bool(ColumnV::new((vec![false; n])));
let mut iyy = Column::Bool(ColumnV::new((vec![false; n])));
let mut iy_or = Column::Bool(ColumnV::new((vec![false; n])));
let mut ix = Column::Bool(ColumnV::new((vec![false; n])));
let mut ixx = Column::Bool(ColumnV::new((vec![false; n])));
let mut ix_or = Column::Bool(ColumnV::new((vec![false; n])));
let mut vx2 = Column::f32(ColumnV::new((vec![0.0; n])));
let h = 200;
let mut qq = Table::new(hash_str("foo"),h,h);
qq.set_kind(ValueKind::F32);
for i in 0..h {
for j in 0..h {
qq.set_raw(i,j,Value::F32(F32::new(i as f32)));
}
}
let mut rr = Table::new(hash_str("foo2"),h,h);
rr.set_kind(ValueKind::F32);
for i in 0..h {
for j in 0..h {
rr.set_raw(i,j,Value::F32(F32::new(i as f32)));
}
}
let mut out = Table::new(hash_str("foo3"),h,h);
out.set_kind(ValueKind::F32);
for i in 0..h {
for j in 0..h {
out.set_raw(i,j,Value::F32(F32::new(i as f32)));
}
}
let gen_dmatrix = |table: &Table| -> Rc<RefCell<DMatrix<f32>>> {
let foo = table.collect_columns_f32();
let naltable = foo.iter().cloned().flatten().map(|x| x.unwrap());
let mat = DMatrix::from_iterator(table.rows,table.cols,naltable);
Rc::new(RefCell::new(mat))
};
let qqdm = gen_dmatrix(&qq);
let rrdm = gen_dmatrix(&rr);
let outdm = gen_dmatrix(&out);
out.nalgebra = Some(outdm.clone());
let lhs = { qq.collect_columns_f32() };
let rhs = { rr.collect_columns_f32() };
let out_cols = out.collect_columns_f32();
// Update the block positions on each tick of the timer
let mut block1 = Block::new();
block1.add_tfm(Transformation::NewTable{table_id: TableId::Local(hash_str("block1")), rows: 1, columns: 1});
block1.triggers.insert((TableId::Global(hash_str("time/timer")),RegisterIndex::All,RegisterIndex::All));
block1.input.insert((TableId::Global(hash_str("gravity")),RegisterIndex::All,RegisterIndex::All));
block1.input.insert((TableId::Global(hash_str("ball")),RegisterIndex::All,RegisterIndex::All));
block1.output.insert((TableId::Global(hash_str("ball")),RegisterIndex::All,RegisterIndex::All));
match (&x,&vx,&y,&vy,&g) {
(Column::f32(x),Column::f32(vx),Column::f32(y),Column::f32(vy),Column::f32(g)) => {
// #ball.x := #ball.x + #ball.vx
//block1.plan.push(math::AddVVIP{out: x.clone(), arg: vx.clone()});
// #ball.y := #ball.y + #ball.vy
//block1.plan.push(math::AddVVIP{out: y.clone(), arg: vy.clone()});
// #ball.vy := #ball.vy + #gravity
//block1.plan.push(math::AddVSIP{out: vy.clone(), arg: g.clone()});
}
_ => (),
}
// Keep the balls within the boundary height
let mut block2 = Block::new();
block2.add_tfm(Transformation::NewTable{table_id: TableId::Local(hash_str("block2")), rows: 1, columns: 1});
block2.triggers.insert((TableId::Global(hash_str("time/timer")),RegisterIndex::All,RegisterIndex::All));
block2.input.insert((TableId::Global(hash_str("ball")),RegisterIndex::All,RegisterIndex::All));
block2.output.insert((TableId::Global(hash_str("ball")),RegisterIndex::All,RegisterIndex::All));
match (&y,&iy,&iyy,&iy_or,&c1,&vy2,&vy,&c500,&c0) {
(Column::f32(y),Column::Bool(iy),Column::Bool(iyy),Column::Bool(iy_or),Column::f32(c1),Column::f32(vy2),Column::f32(vy),Column::f32(m500),Column::f32(m0)) => {
// iy = #ball.y > #boundary.height
block2.plan.push(compare::GreaterVS{lhs: (y.clone(),0,y.len()-1), rhs: (m500.clone(),0,0), out: iy.clone()});
// iyy = #ball.y < 0
block2.plan.push(compare::LessVS{lhs: (y.clone(),0,y.len()-1), rhs: (m0.clone(),0,0), out: iyy.clone()});
// #ball.y{iy} := #boundary.height
block2.plan.push(table::SetVSB{arg: m500.clone(), ix: 0, out: y.clone(), oix: iy.clone()});
// #ball.vy{iy | iyy} := #ball.vy * -80%
block2.plan.push(logic::OrVV{lhs: iy.clone(), rhs: iyy.clone(), out: iy_or.clone()});
block2.plan.push(math::MulVS{lhs: vy.clone(), rhs: c1.clone(), out: vy2.clone()});
block2.plan.push(table::SetVVB{arg: vy2.clone(), out: vy.clone(), oix: iy_or.clone()});
}
_ => (),
}
// Keep the balls within the boundary width
let mut block3 = Block::new();
block3.add_tfm(Transformation::NewTable{table_id: TableId::Local(hash_str("block3")), rows: 1, columns: 1});
block3.triggers.insert((TableId::Global(hash_str("time/timer")),RegisterIndex::All,RegisterIndex::All));
block3.input.insert((TableId::Global(hash_str("ball")),RegisterIndex::All,RegisterIndex::All));
block3.output.insert((TableId::Global(hash_str("ball")),RegisterIndex::All,RegisterIndex::All));
match (&x,&ix,&ixx,&ix_or,&vx,&c1,&vx2,&c500,&c0) {
(Column::f32(x),Column::Bool(ix),Column::Bool(ixx),Column::Bool(ix_or),Column::f32(vx),Column::f32(c1),Column::f32(vx2),Column::f32(m500),Column::f32(m0)) => {
// ix = #ball.x > #boundary.width
block3.plan.push(compare::GreaterVS{lhs: (x.clone(),0,x.len()-1), rhs: (m500.clone(),0,0), out: ix.clone()});
// ixx = #ball.x < 0
block3.plan.push(compare::LessVS{lhs: (x.clone(),0,x.len()-1), rhs: (m0.clone(),0,0), out: ixx.clone()});
// #ball.x{ix} := #boundary.width
block3.plan.push(table::SetVSB{arg: m500.clone(), ix: 0, out: x.clone(), oix: ix.clone()});
// #ball.vx{ix | ixx} := #ball.vx * -80%
block3.plan.push(logic::OrVV{lhs: ix.clone(), rhs: ixx.clone(), out: ix_or.clone()});
block3.plan.push(math::MulVS{lhs: vx.clone(), rhs: c1.clone(), out: vx2.clone()});
block3.plan.push(table::SetVVB{arg: vx2.clone(), out: vx.clone(), oix: ix_or.clone()});
}
_ => (),
}
//println!("{:?}", block1);
let block1_ref = Rc::new(RefCell::new(block1));
core.load_block(block1_ref.clone());
//println!("{:?}", block2);
let block2_ref = Rc::new(RefCell::new(block2));
//core.load_block(block2_ref.clone());
//println!("{:?}", block3);
let block3_ref = Rc::new(RefCell::new(block3));
//core.load_block(block3_ref.clone());
core.schedule_blocks();
let mut x: Vec<f32> = vec![10.0;n];
let mut y: Vec<f32> = vec![10.0;n];
let mut vx: Vec<f32> = vec![1.0;n];
let mut vy: Vec<f32> = vec![1.0;n];
let gravity: f32 = 1.0;
//println!("{:?}", core);
let mut total_time = VecDeque::new();
let mut max = 0.0;
let mut min = 1e20;
let tfm = matrix::MatrixMulMM{a: qqdm.clone(), b: rrdm.clone(), c: outdm.clone(),lhs: lhs.clone(), rhs: rhs.clone(), out: out_cols.clone()};
for i in 0..100000 {
let txn = vec![Change::Set((hash_str("time/timer"),
vec![(TableIndex::Index(1), TableIndex::Index(2), Value::f32(i as f32))]))];
let now = Instant::now();
tfm.solve();
/*for i in 0..n {
x[i] = x[i] + vx[i];
y[i] = y[i] + vy[i];
vy[i] = vy[i] + gravity;
if x[i] > 500.0 {
x[i] = 500.0;
vx[i] = vx[i] * -0.8;
}
if x[i] < 0.0 {
x[i] = 0.0;
vx[i] = vx[i] * -0.8;
}
if y[i] < 0.0 {
y[i] = 0.0;
vy[i] = vy[i] * -0.8;
}
if y[i] > 500.0 {
y[i] = 500.0;
vy[i] = vy[i] * -0.8;
}
}*/
//core.process_transaction(&txn)?;
let elapsed_time = now.elapsed();
let cycle_duration = elapsed_time.as_nanos() as f64;
if cycle_duration > max {
max = cycle_duration;
}
if cycle_duration < min {
min = cycle_duration;
}
total_time.push_back(cycle_duration);
if total_time.len() > 1000 {
total_time.pop_front();
}
let average_time: f64 = total_time.iter().sum::<f64>() / total_time.len() as f64;
println!("{:e} - {:0.2?}Hz", n, 1.0 / (average_time / 1_000_000_000.0));
//println!("{:0.2?}", 1.0 / (cycle_duration / 1_000_000_000.0));
}
println!("Max: {:?} Min: {:?}", 1.0 / (max / 1_000_000_000.0), 1.0 / (min / 1_000_000_000.0));
//let average_time: f32 = total_time.iter().sum::<f32>() / total_time.len() as f32;
//println!("{:e} - {:0.2?}Hz", n, 1.0 / (average_time / 1_000_000_000.0));
// let time = (end_ns0 - start_ns0) as f32;
//println!("{:0.4?} s", time / 1e9);
//println!("{:?}", core);
Ok(())
}*/
Ok(())
}