2023-11-16 19:45:13 -07:00
|
|
|
use rand::Rng;
|
|
|
|
use rand_distr::Distribution;
|
|
|
|
|
2023-11-16 16:27:03 -07:00
|
|
|
use crate::params::Params;
|
|
|
|
use crate::ast::{
|
2023-11-16 19:45:13 -07:00
|
|
|
Expr,
|
2023-11-17 14:50:06 -07:00
|
|
|
Stat,
|
2023-11-16 16:27:03 -07:00
|
|
|
Quantifier,
|
|
|
|
BaseType,
|
|
|
|
GlobalBlock,
|
|
|
|
Block,
|
|
|
|
Literal,
|
|
|
|
Declaration,
|
2023-11-16 19:45:13 -07:00
|
|
|
DeclarationBuilder,
|
2023-11-16 16:27:03 -07:00
|
|
|
Variable,
|
2023-11-16 19:45:13 -07:00
|
|
|
VariableBuilder,
|
2023-11-16 16:27:03 -07:00
|
|
|
BinaryOperator,
|
|
|
|
};
|
|
|
|
|
|
|
|
pub struct AstBuilder {
|
|
|
|
params: Params,
|
|
|
|
ast: GlobalBlock,
|
2023-11-16 19:45:13 -07:00
|
|
|
name_counter: u64,
|
|
|
|
rng: rand::rngs::ThreadRng,
|
2023-11-16 21:24:05 -07:00
|
|
|
rng_float: FloatGenerator,
|
2023-11-16 21:47:27 -07:00
|
|
|
rng_int: IntGenerator,
|
2023-11-16 16:27:03 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl AstBuilder {
|
|
|
|
pub fn from(params: Params) -> Self {
|
|
|
|
Self {
|
|
|
|
ast: GlobalBlock::default(),
|
2023-11-16 21:24:05 -07:00
|
|
|
name_counter: 0,
|
|
|
|
rng: rand::thread_rng(),
|
|
|
|
rng_float: FloatGenerator::new(¶ms),
|
2023-11-16 21:47:27 -07:00
|
|
|
rng_int: IntGenerator::new(¶ms),
|
2023-11-16 21:24:05 -07:00
|
|
|
params,
|
2023-11-16 16:27:03 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-16 19:45:13 -07:00
|
|
|
pub fn generate(&mut self) {
|
|
|
|
let mut p: f64;
|
|
|
|
|
|
|
|
loop {
|
|
|
|
p = self.rng.gen();
|
|
|
|
|
|
|
|
if p < self.params.global_flow.end_generation {
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
let decl = self.gen_decl();
|
|
|
|
self.ast.push(decl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-17 14:50:06 -07:00
|
|
|
fn gen_decl(&mut self) -> Stat {
|
2023-11-16 21:27:59 -07:00
|
|
|
let p: f64 = self.rng.gen();
|
|
|
|
let ps = &self.params.statements.gen_decl;
|
|
|
|
|
2023-11-17 14:50:06 -07:00
|
|
|
let t: BaseType;
|
|
|
|
let assn: Expr;
|
|
|
|
|
|
|
|
if p < ps.gen_integer {
|
|
|
|
t = BaseType::Int;
|
|
|
|
assn = self.gen_integer();
|
2023-11-16 21:27:59 -07:00
|
|
|
} else {
|
2023-11-17 14:50:06 -07:00
|
|
|
t = BaseType::Real;
|
|
|
|
assn = self.gen_real();
|
|
|
|
}
|
2023-11-16 21:27:59 -07:00
|
|
|
|
2023-11-16 19:45:13 -07:00
|
|
|
let v = self.gen_variable_quantified(t, Quantifier::Const);
|
|
|
|
|
2023-11-17 14:50:06 -07:00
|
|
|
Stat::new_decl(
|
2023-11-16 19:45:13 -07:00
|
|
|
DeclarationBuilder::default()
|
|
|
|
.variable(v)
|
2023-11-17 14:50:06 -07:00
|
|
|
.assn(Some(assn))
|
2023-11-16 19:45:13 -07:00
|
|
|
.build()
|
|
|
|
.unwrap()
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn gen_variable_quantified(&mut self, t: BaseType, q: Quantifier) -> Variable {
|
|
|
|
VariableBuilder::default()
|
|
|
|
.type_(t)
|
|
|
|
.name(self.gen_name())
|
2023-11-17 14:50:06 -07:00
|
|
|
.quantifier(q)
|
2023-11-16 19:45:13 -07:00
|
|
|
.build()
|
|
|
|
.unwrap()
|
|
|
|
}
|
|
|
|
|
2023-11-17 14:50:06 -07:00
|
|
|
fn gen_integer(&mut self) -> Expr {
|
|
|
|
Expr::new_literal(self.gen_literal(BaseType::Int))
|
2023-11-16 19:45:13 -07:00
|
|
|
}
|
|
|
|
|
2023-11-17 14:50:06 -07:00
|
|
|
fn gen_real(&mut self) -> Expr {
|
|
|
|
Expr::new_literal(self.gen_literal(BaseType::Real))
|
|
|
|
}
|
2023-11-16 19:45:13 -07:00
|
|
|
|
|
|
|
fn gen_literal(&mut self, t: BaseType) -> Literal {
|
|
|
|
match t {
|
|
|
|
BaseType::Int => {
|
2023-11-16 21:47:27 -07:00
|
|
|
let i = self.rng_int.sample(&mut self.rng);
|
2023-11-16 19:45:13 -07:00
|
|
|
Literal::Int(i)
|
|
|
|
}
|
2023-11-16 21:24:05 -07:00
|
|
|
BaseType::Real => {
|
|
|
|
let f = self.rng_float.sample(&mut self.rng);
|
|
|
|
Literal::Real(f)
|
|
|
|
}
|
2023-11-16 19:45:13 -07:00
|
|
|
BaseType::Never => panic!("Attempted to generate literal of type Never"),
|
|
|
|
BaseType::Unset => panic!("Attempted to generate literal of type Unset"),
|
|
|
|
}
|
2023-11-16 16:27:03 -07:00
|
|
|
}
|
2023-11-17 14:50:06 -07:00
|
|
|
|
|
|
|
fn gen_name(&mut self) -> String {
|
|
|
|
let s = format!("_{}", self.name_counter);
|
|
|
|
self.name_counter += 1;
|
|
|
|
s
|
|
|
|
}
|
2023-11-16 16:27:03 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ToString for AstBuilder {
|
|
|
|
fn to_string(&self) -> String {
|
|
|
|
let mut s = format!("// Generated by {} v{}\n",
|
|
|
|
env!("CARGO_PKG_NAME"),
|
|
|
|
env!("CARGO_PKG_VERSION"),
|
|
|
|
);
|
|
|
|
|
|
|
|
s.push_str(&self.ast.to_string());
|
|
|
|
s
|
|
|
|
}
|
|
|
|
}
|
2023-11-16 21:24:05 -07:00
|
|
|
|
2023-11-16 21:47:27 -07:00
|
|
|
/// Generates values from regions of interest for an integer
|
|
|
|
///
|
|
|
|
/// These are concentrated around i32::MIN, 0, and i32::MAX, though any i32 value is possible
|
|
|
|
struct IntGenerator {
|
|
|
|
distro_pos: rand_distr::Normal<f32>,
|
|
|
|
distro_zero: rand_distr::Normal<f32>,
|
|
|
|
distro_neg: rand_distr::Normal<f32>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl IntGenerator {
|
|
|
|
fn new(p: &Params) -> Self {
|
|
|
|
Self {
|
|
|
|
distro_pos: rand_distr::Normal::new(0.0, p.dev.int_gen_distro_pos_stddiv).unwrap(),
|
|
|
|
distro_zero: rand_distr::Normal::new(0.0, 3.0).unwrap(),
|
|
|
|
distro_neg: rand_distr::Normal::new(0.0, p.dev.int_gen_distro_neg_stddiv).unwrap(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Distribution<i32> for IntGenerator {
|
|
|
|
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> i32 {
|
|
|
|
let p: f64 = rng.gen();
|
|
|
|
|
2023-11-17 14:50:06 -07:00
|
|
|
if p < 0.3 {
|
2023-11-16 21:47:27 -07:00
|
|
|
i32::MAX - (self.distro_pos.sample(rng).abs() as i32)
|
2023-11-17 14:50:06 -07:00
|
|
|
} else if p < 0.7 {
|
2023-11-16 21:47:27 -07:00
|
|
|
self.distro_zero.sample(rng) as i32
|
|
|
|
} else {
|
|
|
|
-1 * (i32::MAX - (self.distro_pos.sample(rng).abs() as i32))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-11-17 14:50:06 -07:00
|
|
|
|
2023-11-16 21:24:05 -07:00
|
|
|
/// Generates values from regions of interest for a float
|
|
|
|
///
|
|
|
|
/// These are concentrated around f32::MIN, 0, and f32::MAX, though any f32 value is possible
|
|
|
|
struct FloatGenerator {
|
|
|
|
distro_pos: rand_distr::Normal<f32>,
|
|
|
|
distro_zero: rand_distr::Normal<f32>,
|
|
|
|
distro_neg: rand_distr::Normal<f32>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FloatGenerator {
|
|
|
|
fn new(p: &Params) -> Self {
|
2023-11-16 21:47:27 -07:00
|
|
|
Self {
|
2023-11-16 21:24:05 -07:00
|
|
|
distro_pos: rand_distr::Normal::new(1.0, p.dev.float_gen_distro_pos_stddiv).unwrap(),
|
|
|
|
distro_zero: rand_distr::Normal::new(0.0, 3.0).unwrap(),
|
|
|
|
distro_neg: rand_distr::Normal::new(1.0, p.dev.float_gen_distro_neg_stddiv).unwrap(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Distribution<f32> for FloatGenerator {
|
|
|
|
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f32 {
|
|
|
|
let p: f64 = rng.gen();
|
|
|
|
|
|
|
|
if p < 0.33 {
|
|
|
|
f32::MAX - self.distro_pos.sample(rng).abs()
|
|
|
|
} else if p < 0.66 {
|
|
|
|
self.distro_zero.sample(rng)
|
|
|
|
} else {
|
|
|
|
-1.0 * (f32::MAX - self.distro_neg.sample(rng).abs())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|