Circle-Packings/fractal_dimension/circle_counting_new/src/lib.rs

132 lines
4.3 KiB
Rust
Raw Normal View History

2021-07-15 10:50:33 -07:00
use ansi_term::Color::Yellow;
2021-07-06 19:29:22 -07:00
use linregress::{FormulaRegressionBuilder, RegressionDataBuilder};
use nalgebra::{DMatrix, DVector};
pub fn fractal_dimension(
generators: Vec<DMatrix<f64>>,
root: DVector<f64>,
faces: Vec<Vec<usize>>,
upper_bound: f64,
n: usize,
debug: bool,
2021-07-11 11:11:03 -07:00
generations: usize,
orthogonal_generators: Vec<Vec<usize>>,
2021-07-06 19:29:22 -07:00
) -> Result<f64, linregress::Error> {
let mut totals = vec![root.len(); n];
2021-07-07 12:42:51 -07:00
let mut current = vec![(root, std::usize::MAX, false)];
2021-07-06 19:29:22 -07:00
let mut next = vec![];
2021-07-17 07:50:31 -07:00
let mut nodes: u64 = 1;
2021-07-06 19:29:22 -07:00
let xs: Vec<f64> = (1..=n)
2021-07-15 14:15:05 -07:00
// .map(|x| (x as f64 * upper_bound / (n as f64)))
.map(|x| (x as f64 * upper_bound / (2.0 * n as f64) + upper_bound / 2.0))
2021-07-06 19:29:22 -07:00
.collect();
let mut i = 0;
2021-07-07 10:38:30 -07:00
2021-07-06 19:29:22 -07:00
loop {
next.clear();
2021-07-07 12:42:51 -07:00
for (tuple, previous_generator, bad) in &current {
2021-07-06 19:29:22 -07:00
for (i, generator) in generators.iter().enumerate() {
2021-07-11 11:11:03 -07:00
let mut skip = false;
for orthogonal_pairs in &orthogonal_generators {
if i == orthogonal_pairs[1] && *previous_generator == orthogonal_pairs[0] {
skip = true;
break;
}
}
if skip {
continue;
}
2021-07-06 19:29:22 -07:00
if i != *previous_generator {
let new_tuple = generator * tuple;
2021-07-11 11:11:03 -07:00
if new_tuple.iter().sum::<f64>() <= tuple.iter().sum() {
continue;
}
2021-07-06 19:29:22 -07:00
let mut add = false;
for (j, curvature) in new_tuple.iter().enumerate() {
let mut skip = false;
2021-07-07 07:39:06 -07:00
for vertex in &faces[i] {
if j == *vertex {
2021-07-06 19:29:22 -07:00
skip = true;
break;
}
}
if skip {
continue;
}
for (k, max) in xs.iter().enumerate() {
if curvature <= max {
2021-07-07 12:42:51 -07:00
add = true;
2021-07-06 19:29:22 -07:00
totals[k] += 1;
}
}
}
if add {
2021-07-07 12:42:51 -07:00
next.push((new_tuple, i, false));
2021-07-15 14:15:05 -07:00
nodes += 1;
2021-07-07 12:42:51 -07:00
} else {
2021-07-15 10:50:33 -07:00
if !bad {
2021-07-07 12:42:51 -07:00
next.push((new_tuple, i, true));
2021-07-15 14:15:05 -07:00
nodes += 1;
2021-07-07 12:42:51 -07:00
}
2021-07-06 19:29:22 -07:00
}
}
}
}
std::mem::swap(&mut current, &mut next);
2021-07-15 10:50:33 -07:00
2021-07-06 19:29:22 -07:00
i += 1;
2021-07-06 21:37:50 -07:00
if generations != 0 && i > generations {
break;
}
2021-07-06 19:29:22 -07:00
if debug {
println!("Generation {}:", i);
println!("\tnumber of leaves:\t{}", current.len());
if !current.is_empty() {
2021-07-08 09:31:54 -07:00
let tuple = &current[current.len() / 2];
println!("\trandom tuple:\t\t{}", tuple.0);
2021-07-06 19:29:22 -07:00
}
println!();
}
if current.is_empty() {
break;
}
}
if debug {
println!("{}", Yellow.paint("Done counting circles!"));
println!("sample points:\n{:?}", xs);
2021-07-15 10:50:33 -07:00
println!(
"\nnumber of circles fewer than each of those sample points:\n{:?}",
totals
);
2021-07-15 14:15:05 -07:00
println!("\nTotal number of nodes:\t{}", nodes);
2021-07-06 19:29:22 -07:00
}
let xs: Vec<f64> = xs.iter().map(|x| x.ln()).collect();
let ys: Vec<f64> = totals.iter().map(|x| (*x as f64).ln()).collect();
let data = vec![("Y", ys), ("X", xs)];
let data = RegressionDataBuilder::new().build_from(data)?;
let formula = "Y ~ X";
let model = FormulaRegressionBuilder::new()
.data(&data)
.formula(formula)
.fit()?;
if debug {
println!("\n{}", Yellow.paint("Built regression model!"));
println!("Model info:");
println!("\tr^2:\t\t{}", model.rsquared);
println!("\tp-value:\t{}", model.pvalues.pairs()[0].1);
println!("\tintercept:\t{}", model.parameters.intercept_value);
println!("\tslope:\t{}", model.parameters.regressor_values[0]);
}
let parameters = model.parameters;
Ok(parameters.regressor_values[0])
}