finished circle_counting

This commit is contained in:
William Ball 2021-07-06 22:29:22 -04:00
parent 6ca162ec1d
commit 6148ee8e36
10 changed files with 9004 additions and 1553 deletions

File diff suppressed because it is too large Load diff

View file

@ -2,6 +2,15 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "approx" name = "approx"
version = "0.5.0" version = "0.5.0"
@ -11,12 +20,29 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.0.1" version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.0" version = "1.0.0"
@ -27,8 +53,25 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
name = "circle_counting" name = "circle_counting"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"ansi_term",
"linregress", "linregress",
"nalgebra", "nalgebra",
"structopt",
]
[[package]]
name = "clap"
version = "2.33.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
dependencies = [
"ansi_term",
"atty",
"bitflags",
"strsim",
"textwrap",
"unicode-width",
"vec_map",
] ]
[[package]] [[package]]
@ -42,6 +85,24 @@ dependencies = [
"wasi", "wasi",
] ]
[[package]]
name = "heck"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.4.0" version = "1.4.0"
@ -160,6 +221,30 @@ version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.27" version = "1.0.27"
@ -259,6 +344,36 @@ dependencies = [
"rand", "rand",
] ]
[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "structopt"
version = "0.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69b041cdcb67226aca307e6e7be44c8806423d83e018bd662360a93dabce4d71"
dependencies = [
"clap",
"lazy_static",
"structopt-derive",
]
[[package]]
name = "structopt-derive"
version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7813934aecf5f51a54775e00068c237de98489463968231a51746bbbc03f9c10"
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.73" version = "1.0.73"
@ -270,20 +385,75 @@ dependencies = [
"unicode-xid", "unicode-xid",
] ]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
"unicode-width",
]
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.13.0" version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06"
[[package]]
name = "unicode-segmentation"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
[[package]]
name = "unicode-width"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
[[package]] [[package]]
name = "unicode-xid" name = "unicode-xid"
version = "0.2.2" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "version_check"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.10.2+wasi-snapshot-preview1" version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View file

@ -1,6 +1,7 @@
[package] [package]
name = "circle_counting" name = "circle_counting"
version = "0.1.0" version = "0.1.0"
authors = [ "William Ball <wball1@swarthmore.edu> "]
edition = "2018" edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -8,3 +9,5 @@ edition = "2018"
[dependencies] [dependencies]
nalgebra = "*" nalgebra = "*"
linregress = "*" linregress = "*"
structopt = "*"
ansi_term = "*"

View file

@ -0,0 +1,5 @@
{{{1., 0., 0., 0., 0.}, {0., 1., 0., 0., 0.}, {4., 3., 0., -1., 3.}, {4., 2., 0., -1., 4.}, {0., 0., 0., 0., 1.}}, {{1., 0., 0., 0., 0.}, {0., 1., 0., 0., 0.}, {0., 0., 1., 0., 0.}, {4., 3., 3., 0., -1.}, {4., 4., 2., 0., -1.}}, {{1., 0., 0., 0., 0.}, {4., -1., 4., 2., 0.}, {0., 0., 1., 0., 0.}, {0., 0., 0., 1., 0.}, {4., -1., 3., 3., 0.}}, {{1., 0., 0., 0., 0.}, {4., 0., -1., 3., 3.}, {4., 0., -1., 4., 2.}, {0., 0., 0., 1., 0.}, {0., 0., 0., 0., 1.}}, {{-1., 1., 0., 1., 0.}, {0., 1., 0., 0., 0.}, {0., 1., 0., 1., -1.}, {0., 0., 0., 1., 0.}, {0., 0., 0., 0., 1.}}}
{-0.513181, 1.23893, 1.23893, 1.23893, 1.23893}
{{0, 1, 4}, {0, 2, 1}, {0, 3, 2}, {0, 4, 3}, {1, 2, 3, 4}}

View file

@ -0,0 +1,101 @@
use linregress::{FormulaRegressionBuilder, RegressionDataBuilder};
use nalgebra::{DMatrix, DVector};
use ansi_term::Color::Yellow;
pub fn fractal_dimension(
generators: Vec<DMatrix<f64>>,
root: DVector<f64>,
faces: Vec<Vec<usize>>,
upper_bound: f64,
n: usize,
debug: bool,
) -> Result<f64, linregress::Error> {
let mut totals = vec![root.len(); n];
let mut current = vec![(root, std::usize::MAX)];
let mut next = vec![];
let xs: Vec<f64> = (1..=n)
.map(|x| (x as f64 * upper_bound / (n as f64)))
.collect();
let mut i = 0;
loop {
next.clear();
for (tuple, previous_generator) in &current {
for (i, generator) in generators.iter().enumerate() {
if i != *previous_generator {
let new_tuple = generator * tuple;
let mut add = false;
for (j, curvature) in new_tuple.iter().enumerate() {
let mut skip = false;
for face in &faces[i] {
if j == *face {
skip = true;
break;
}
}
if skip {
continue;
}
for (k, max) in xs.iter().enumerate() {
if curvature <= max {
if k == n - 1 {
add = true;
}
totals[k] += 1;
}
}
}
if add {
next.push((new_tuple, i));
}
}
}
}
std::mem::swap(&mut current, &mut next);
i += 1;
if debug {
println!("Generation {}:", i);
println!("\tnumber of leaves:\t{}", current.len());
if !current.is_empty() {
println!("\trandom tuple:\t\t{}", current[current.len() / 2].0);
}
println!();
}
if current.is_empty() {
break;
}
}
if debug {
println!("{}", Yellow.paint("Done counting circles!"));
println!("sample points:\n{:?}", xs);
println!("\nnumber of circles fewer than each of those sample points:\n{:?}", totals);
}
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])
}

View file

@ -1,79 +1,107 @@
use nalgebra::{SMatrix, SVector}; #![allow(dead_code)]
use linregress::{FormulaRegressionBuilder, RegressionDataBuilder};
type Matrix4 = SMatrix<f64, 4, 4>; use crate::{lib::fractal_dimension, parser::read_file};
type Vector4 = SVector<f64, 4>; use std::process;
use structopt::StructOpt;
fn search(generators: &Vec<Matrix4>, root: Vector4, upper_bound: f64) -> usize { use ansi_term::Color::Yellow;
let mut current = vec![(root, 5)];
let mut next = vec![];
let mut total = 0;
loop {
next.clear();
for (tuple, previous_generator) in &current {
for (i, generator) in generators.iter().enumerate() {
let new_tuple = generator * tuple;
if !(i == 0 && *previous_generator == 3) && !(i == 1 && *previous_generator == 2) && i != *previous_generator && new_tuple[i] < upper_bound && new_tuple.iter().sum::<f64>() > tuple.iter().sum() {
next.push((new_tuple, i));
}
}
}
if current.is_empty() { mod lib;
break; mod parser;
}
total += next.len();
std::mem::swap(&mut current, &mut next);
}
2 * (total + root.len())
}
fn fractal_dimension(generators: Vec<Matrix4>, root: Vector4, upper_bound: f64, n: isize) -> Result<f64, linregress::Error> { /// Compute fractal dimension of crystallographic packings via the circle counting method
let xs: Vec<f64> = (1..=n).map(|x| (x as f64 * upper_bound / (n as f64)).ln()).collect(); #[derive(StructOpt)]
let ys: Vec<f64> = xs.iter().map(|upper_bound| (search(&generators, root, upper_bound.exp()) as f64).ln()).collect(); #[structopt(name = "Circle Counter")]
struct Opt {
/// File containing data in the order generators, root, faces
#[structopt(name = "data file")]
data_file: String,
let data = vec![("Y", ys), ("X", xs)]; /// Activate debug mode
let data = RegressionDataBuilder::new().build_from(data)?; #[structopt(short, long)]
debug: bool,
let formula = "Y ~ X"; /// Number of sample points in linear regression
let model = FormulaRegressionBuilder::new() #[structopt(short, long, default_value = "50")]
.data(&data) n: usize,
.formula(formula)
.fit()?;
let parameters = model.parameters; /// Maximum curvature of circles
Ok(parameters.regressor_values[0]) #[structopt(short, long, default_value = "1000000")]
max: f64,
/// Whether or not to time excecution (automatically enabled by --debug)
#[structopt(short, long)]
time: bool,
} }
fn main() { fn main() {
let generators = vec![ let opt = Opt::from_args();
Matrix4::new( let debug = opt.debug;
-1.0, 2.0, 2.0, 0.0, let time = debug || opt.time;
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0,
),
Matrix4::new(
1.0, 0.0, 0.0, 0.0,
2.0, -1.0, 0.0, 2.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0,
),
Matrix4::new(
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
2.0, 0.0, -1.0, 2.0,
0.0, 0.0, 0.0, 1.0,
),
Matrix4::new(
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 2.0, 2.0, -1.0,
),
];
let root = Vector4::new(-2., 4., 5., 9.); let beginning = std::time::Instant::now();
println!("{}", fractal_dimension(generators, root, 10_000_000.0, 50).unwrap()); let (generators, root, faces) = read_file(&opt.data_file).unwrap_or_else(|err| {
eprintln!("{}", err);
process::exit(-1);
});
let after_parsing = std::time::Instant::now();
if time {
let duration = after_parsing.duration_since(beginning);
println!(
"Took {}s to parse {}",
duration.as_secs_f64(),
opt.data_file
);
}
if debug {
println!(
"{} (parsed from command args):\t{}",
Yellow.paint("max"),
opt.max
);
println!(
"{} (parsed from command args):\t{}",
Yellow.paint("n"),
opt.n
);
}
if debug {
println!(
"{} (parsed from file {})",
Yellow.paint("Generators"),
opt.data_file
);
for generator in &generators {
println!("{}", generator);
}
println!(
"{} (parsed from file {}):",
Yellow.paint("Root Tuple"),
opt.data_file
);
println!("{}", root);
println!(
"{} (parsed from file {}):",
Yellow.paint("Faces"),
opt.data_file
);
println!("{:?}\n", faces);
}
let delta = fractal_dimension(generators, root, faces, opt.max, opt.n, debug).unwrap();
let after_computing = std::time::Instant::now();
if time {
let duration1 = after_computing.duration_since(after_parsing);
let duration2 = after_computing.duration_since(beginning);
println!(
"\nTook {}s to compute fractal dimension; {}s total",
duration1.as_secs_f64(),
duration2.as_secs_f64()
);
}
println!("\n{}", delta);
} }

View file

@ -0,0 +1,393 @@
use std::fs;
use nalgebra::{DMatrix, DVector};
#[derive(Debug, PartialEq)]
enum TokenType {
OpenBracket,
CloseBracket,
Number(f64),
Error(String),
Comma,
}
#[derive(Debug, PartialEq)]
struct Token {
ttype: TokenType,
line: usize,
}
impl Token {
#[allow(dead_code)]
fn new(ttype: TokenType, line: usize) -> Token {
Token { ttype, line }
}
}
struct TokenIterator<'a> {
data: std::iter::Peekable<std::str::Chars<'a>>,
line: usize,
}
impl<'a> Iterator for TokenIterator<'a> {
type Item = Token;
fn next(&mut self) -> Option<Self::Item> {
let mut current: char = self.data.next()?;
while current.is_whitespace() {
if current == '\n' {
self.line += 1;
}
current = self.data.next()?;
}
use TokenType::*;
match current {
'{' => {
return Some(Token {
ttype: OpenBracket,
line: self.line,
})
}
'}' => {
return Some(Token {
ttype: CloseBracket,
line: self.line,
})
}
',' => {
return Some(Token {
ttype: Comma,
line: self.line,
})
}
_ => (),
}
if current.is_numeric() || current == '-' {
let mut s: String = "".into();
loop {
s.push(current);
if let Some(c) = self.data.peek() {
current = *c;
} else {
break;
}
if !current.is_numeric() && current != '.' {
break;
}
let _ = self.data.next();
}
Some(Token {
ttype: Number(s.parse().ok()?),
line: self.line,
})
} else {
Some(Token {
ttype: Error(format!("Invalid token {} on line {}", current, self.line)),
line: self.line,
})
}
}
}
fn lex(data: &str) -> TokenIterator {
TokenIterator {
data: data.chars().peekable(),
line: 1,
}
}
#[derive(Debug, PartialEq)]
enum Value {
List(Vec<Value>),
Number(f64),
}
fn eval_full(data: String) -> Result<Vec<Value>, String> {
let mut data = lex(data.as_str()).peekable();
let mut values = vec![];
while data.peek().is_some() {
values.push(eval(&mut data)?);
}
Ok(values)
}
fn eval(data: &mut std::iter::Peekable<TokenIterator>) -> Result<Value, String> {
let token = data
.next()
.unwrap_or_else(|| Token::new(TokenType::Error("Unable to parse!".to_string()), 0));
match token.ttype {
TokenType::OpenBracket => {
let mut list = vec![];
while let Some(token) = data.peek() {
match &token.ttype {
TokenType::CloseBracket => {
data.next();
break;
}
TokenType::Comma => {
return Err(format!("Unexpected ',' on line {}", token.line));
}
TokenType::Error(e) => return Err(e.into()),
_ => list.push(eval(data)?),
};
match data.peek() {
Some(Token {
ttype: TokenType::Comma,
..
}) => {
data.next();
}
Some(Token {
ttype: TokenType::CloseBracket,
..
}) => (),
Some(Token { ttype, line }) => {
return Err(format!(
"Expected ',' or '}}' near line {}; got {:?}",
line, ttype
))
}
None => {
return Err("Unexpected end of file".into());
}
}
}
Ok(Value::List(list))
}
TokenType::CloseBracket => Err(format!("Unexpected '}}' on line {}", token.line)),
TokenType::Number(num) => Ok(Value::Number(num)),
TokenType::Error(err) => Err(err),
TokenType::Comma => Err(format!("Unexpected ',' on line {}", token.line)),
}
}
fn vector_to_rust_value(value: &Value) -> Result<Vec<f64>, String> {
let mut result = vec![];
if let Value::List(data) = value {
for datapoint in data {
if let Value::Number(num) = datapoint {
result.push(*num);
} else {
return Err(format!("Expected a number, got {:?}", datapoint));
}
}
} else {
return Err(format!("Expected a list, got {:?}", value));
}
Ok(result)
}
fn matrix_to_rust_value(value: &Value) -> Result<Vec<Vec<f64>>, String> {
let mut result = vec![];
if let Value::List(data) = value {
for row in data {
if let Value::List(_) = row {
result.push(vector_to_rust_value(row)?);
}
}
} else {
return Err(format!("Expected a list, got {:?}", value));
}
Ok(result)
}
fn matrix_to_rust_value_flat(value: &Value) -> Result<Vec<f64>, String> {
let mut result = vec![];
if let Value::List(data) = value {
for row in data {
if let Value::List(_) = row {
result.append(&mut vector_to_rust_value(row)?);
}
}
} else {
return Err(format!("Expected a list, got {:?}", value));
}
Ok(result)
}
pub type Generator = DMatrix<f64>;
pub type Root = DVector<f64>;
pub type FaceList = Vec<Vec<usize>>;
pub type Data = (Vec<Generator>, Root, FaceList);
pub fn read_file(filename: &str) -> Result<Data, String> {
let contents = match fs::read_to_string(filename) {
Ok(contents) => contents,
_ => return Err(format!("Something went wrong with reading {}", filename)),
};
let results = eval_full(contents)?;
let mut generators = vec![];
if let Value::List(gens) = &results[0] {
for val in gens {
let mat = matrix_to_rust_value(val)?;
let mat2 = matrix_to_rust_value_flat(val)?;
generators.push(DMatrix::from_row_slice(mat.len(), mat[0].len(), &mat2));
}
} else {
return Err(format!(
"Expected first value in file to be the generators; got {:?}",
results[0]
));
}
let root = vector_to_rust_value(&results[1])?;
let faces = matrix_to_rust_value(&results[2])?;
let faces = faces
.iter()
.map(|v| v.iter().map(|x| x.round() as usize).collect())
.collect();
Ok((generators, DVector::from_column_slice(&root), faces))
}
#[cfg(test)]
mod test {
use super::*;
use TokenType::*;
fn tok(ttype: TokenType, line: usize) -> Option<Token> {
Some(Token::new(ttype, line))
}
#[test]
fn parens() {
let mut lex = lex("{}");
assert_eq!(lex.next(), tok(OpenBracket, 1));
assert_eq!(lex.next(), tok(CloseBracket, 1));
assert_eq!(lex.next(), None);
}
#[test]
fn nums() {
let mut lex = lex("1.12341\n3.1415926535");
assert_eq!(lex.next(), tok(Number(1.12341), 1));
assert_eq!(lex.next(), tok(Number(3.1415926535), 2));
assert_eq!(lex.next(), None);
}
#[test]
fn list() {
let mut lex = lex("{1, 2, 3, 4}");
assert_eq!(lex.next(), tok(OpenBracket, 1));
assert_eq!(lex.next(), tok(Number(1.), 1));
assert_eq!(lex.next(), tok(Comma, 1));
assert_eq!(lex.next(), tok(Number(2.), 1));
assert_eq!(lex.next(), tok(Comma, 1));
assert_eq!(lex.next(), tok(Number(3.), 1));
assert_eq!(lex.next(), tok(Comma, 1));
assert_eq!(lex.next(), tok(Number(4.), 1));
assert_eq!(lex.next(), tok(CloseBracket, 1));
}
#[test]
fn nums_eval() {
let res = eval_full("1.23".into()).unwrap();
assert_eq!(res, vec![Value::Number(1.23)]);
}
#[test]
fn empty_list_eval() {
let res = eval_full("{}".into()).unwrap();
assert_eq!(res, vec![Value::List(vec![])]);
}
#[test]
fn simple_list_eval() {
let res = eval_full("{1.1}".into()).unwrap();
assert_eq!(res, vec![Value::List(vec![Value::Number(1.1)])]);
}
#[test]
fn list_eval() {
let res = eval_full("{\n1.23\n,\n2.3\n,\n1.5\n}".into()).unwrap();
assert_eq!(
res,
vec![Value::List(vec![
Value::Number(1.23),
Value::Number(2.3),
Value::Number(1.5),
])]
);
}
#[test]
fn multiple_lines_eval() {
let res = eval_full("1.0 \n {1.0, 2.0}\n".into()).unwrap();
assert_eq!(
res,
vec![
Value::Number(1.0),
Value::List(vec![Value::Number(1.0), Value::Number(2.0)])
]
);
}
#[test]
fn nested_list_eval() {
let res = eval_full("{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}".into()).unwrap();
assert_eq!(
res,
vec![Value::List(vec![
Value::List(vec![
Value::Number(1.0),
Value::Number(0.0),
Value::Number(0.0)
]),
Value::List(vec![
Value::Number(0.0),
Value::Number(1.0),
Value::Number(0.0)
]),
Value::List(vec![
Value::Number(0.0),
Value::Number(0.0),
Value::Number(1.0)
])
])]
);
}
#[test]
fn vector() {
let test = Value::List(vec![Value::Number(1.0), Value::Number(2.0)]);
assert_eq!(vector_to_rust_value(&test).unwrap(), vec![1.0, 2.0]);
}
#[test]
fn matrix() {
let val = Value::List(vec![
Value::List(vec![
Value::Number(1.0),
Value::Number(0.0),
Value::Number(0.0),
]),
Value::List(vec![
Value::Number(0.0),
Value::Number(1.0),
Value::Number(0.0),
]),
Value::List(vec![
Value::Number(0.0),
Value::Number(0.0),
Value::Number(1.0),
]),
]);
let res = matrix_to_rust_value(&val).unwrap();
assert_eq!(
res,
vec![
vec![1.0, 0.0, 0.0],
vec![0.0, 1.0, 0.0],
vec![0.0, 0.0, 1.0]
]
);
}
}

View file

@ -0,0 +1,30 @@
{
{
{-1, 2, 2, 2},
{0, 1, 0, 0},
{0, 0, 1, 0},
{0, 0, 0, 1}
},
{
{1, 0, 0, 0},
{2, -1, 2, 2},
{0, 0, 1, 0},
{0, 0, 0, 1}
},
{
{1, 0, 0, 0},
{0, 1, 0, 0},
{2, 2, -1, 2},
{0, 0, 0, 1}
},
{
{1, 0, 0, 0},
{0, 1, 0, 0},
{0, 0, 1, 0},
{2, 2, 2, -1}
}
}
{-6, 11, 14, 23}
{{1, 2, 3}, {0, 2, 3}, {0, 1, 3}, {0, 1, 2}}

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,7 @@
"cells": [ "cells": [
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 1, "execution_count": 2,
"metadata": { "metadata": {
"executionInfo": { "executionInfo": {
"elapsed": 118, "elapsed": 118,
@ -28,7 +28,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 2, "execution_count": 3,
"metadata": { "metadata": {
"id": "G01gxmY2QI64" "id": "G01gxmY2QI64"
}, },
@ -95,7 +95,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 5, "execution_count": 6,
"metadata": { "metadata": {
"id": "xY_oNcRDl797" "id": "xY_oNcRDl797"
}, },
@ -106,53 +106,35 @@
"text": [ "text": [
"[1]\n", "[1]\n",
"[1, 2]\n", "[1, 2]\n",
"[1, 2, 1]\n",
"[1, 2, 3]\n",
"[1, 2, 4]\n",
"[1, 3]\n", "[1, 3]\n",
"[1, 3, 1]\n", "[1, 3, 1]\n",
"[1, 3, 1, 2]\n",
"[1, 3, 1, 3]\n",
"[1, 3, 1, 4]\n",
"[1, 3, 2]\n", "[1, 3, 2]\n",
"[1, 3, 4]\n", "[1, 3, 4]\n",
"[1, 4]\n", "[1, 4]\n",
"[1, 4, 1]\n",
"[1, 4, 2]\n",
"[1, 4, 3]\n",
"[1, 4, 3, 1]\n",
"[1, 4, 3, 2]\n",
"[1, 4, 3, 4]\n",
"[2]\n", "[2]\n",
"[2, 1]\n", "[2, 1]\n",
"[2, 1, 2]\n",
"[2, 1, 2, 1]\n",
"[2, 1, 2, 3]\n",
"[2, 1, 2, 4]\n",
"[2, 1, 3]\n",
"[2, 1, 3, 1]\n",
"[2, 1, 3, 2]\n",
"[2, 1, 3, 4]\n",
"[2, 1, 4]\n",
"[2, 1, 4, 1]\n",
"[2, 1, 4, 2]\n",
"[2, 1, 4, 3]\n",
"[2, 3]\n", "[2, 3]\n",
"[2, 3, 1]\n",
"[2, 3, 2]\n",
"[2, 3, 4]\n",
"[2, 3, 4, 1]\n",
"[2, 3, 4, 2]\n",
"[2, 3, 4, 3]\n",
"[2, 4]\n", "[2, 4]\n",
"[3]\n", "[3]\n",
"[3, 1]\n", "[3, 1]\n",
"[3, 1, 2]\n", "[3, 1, 2]\n",
"[3, 1, 2, 1]\n",
"[3, 1, 2, 3]\n",
"[3, 1, 2, 3, 1]\n",
"[3, 1, 2, 3, 1, 2]\n",
"[3, 1, 2, 3, 1, 3]\n",
"[3, 1, 2, 3, 1, 4]\n",
"[3, 1, 2, 3, 1, 4, 1]\n",
"[3, 1, 2, 3, 1, 4, 2]\n",
"[3, 1, 2, 3, 1, 4, 3]\n",
"[3, 1, 2, 3, 2]\n",
"[3, 1, 2, 3, 2, 1]\n",
"[3, 1, 2, 3, 2, 3]\n",
"[3, 1, 2, 3, 2, 4]\n",
"[3, 1, 2, 3, 4]\n",
"[3, 1, 2, 4]\n",
"[3, 1, 3]\n", "[3, 1, 3]\n",
"[3, 1, 4]\n", "[3, 1, 4]\n",
"[3, 1, 4, 1]\n",
"[3, 1, 4, 2]\n",
"[3, 1, 4, 3]\n",
"[3, 2]\n", "[3, 2]\n",
"[3, 2, 1]\n", "[3, 2, 1]\n",
"[3, 2, 1, 2]\n", "[3, 2, 1, 2]\n",
@ -162,42 +144,27 @@
"[3, 2, 4]\n", "[3, 2, 4]\n",
"[3, 4]\n", "[3, 4]\n",
"[3, 4, 1]\n", "[3, 4, 1]\n",
"[3, 4, 1, 2]\n",
"[3, 4, 1, 3]\n",
"[3, 4, 1, 3, 1]\n",
"[3, 4, 1, 3, 2]\n",
"[3, 4, 1, 3, 4]\n",
"[3, 4, 1, 3, 4, 1]\n",
"[3, 4, 1, 3, 4, 2]\n",
"[3, 4, 1, 3, 4, 3]\n",
"[3, 4, 1, 4]\n",
"[3, 4, 2]\n", "[3, 4, 2]\n",
"[3, 4, 2, 1]\n",
"[3, 4, 2, 3]\n",
"[3, 4, 2, 4]\n",
"[3, 4, 3]\n", "[3, 4, 3]\n",
"[4]\n", "[4]\n",
"[4, 1]\n", "[4, 1]\n",
"[4, 2]\n", "[4, 2]\n",
"[4, 2, 1]\n", "[4, 2, 1]\n",
"[4, 2, 1, 2]\n",
"[4, 2, 1, 3]\n",
"[4, 2, 1, 4]\n",
"[4, 2, 1, 4, 1]\n",
"[4, 2, 1, 4, 2]\n",
"[4, 2, 1, 4, 3]\n",
"[4, 2, 3]\n", "[4, 2, 3]\n",
"[4, 2, 4]\n", "[4, 2, 4]\n",
"[4, 3]\n", "[4, 2, 4, 1]\n",
"[4, 3, 1]\n", "[4, 2, 4, 2]\n",
"[4, 3, 2]\n", "[4, 2, 4, 2, 1]\n",
"[4, 3, 2, 1]\n", "[4, 2, 4, 2, 3]\n",
"[4, 3, 2, 3]\n", "[4, 2, 4, 2, 4]\n",
"[4, 3, 2, 3, 1]\n", "[4, 2, 4, 3]\n",
"[4, 3, 2, 3, 2]\n", "[4, 3]\n"
"[4, 3, 2, 3, 2, 1]\n",
"[4, 3, 2, 3, 2, 1, 2]\n",
"[4, 3, 2, 3, 2, 1, 3]\n",
"[4, 3, 2, 3, 2, 1, 4]\n",
"[4, 3, 2, 3, 2, 3]\n",
"[4, 3, 2, 3, 2, 4]\n",
"[4, 3, 2, 3, 4]\n",
"[4, 3, 2, 4]\n",
"[4, 3, 4]\n"
] ]
} }
], ],
@ -215,7 +182,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 4, "execution_count": 5,
"metadata": { "metadata": {
"executionInfo": { "executionInfo": {
"elapsed": 490, "elapsed": 490,
@ -271,7 +238,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 6, "execution_count": 7,
"metadata": { "metadata": {
"executionInfo": { "executionInfo": {
"elapsed": 3, "elapsed": 3,
@ -307,7 +274,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 7, "execution_count": 9,
"metadata": { "metadata": {
"colab": { "colab": {
"base_uri": "https://localhost:8080/" "base_uri": "https://localhost:8080/"
@ -331,18 +298,19 @@
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"158\n", "17\n",
"fractal dimension: 1.2179534297610568\n" "[-6, 11, 14, 23, 51, 95, 42, 71, 15, 86, 35, 74, 71, 26, 59, 47, 78]\n",
"fractal dimension: 0.9506030253442043\n"
] ]
} }
], ],
"source": [ "source": [
"root = [-10, 18, 23, 27] #some base tuple, it will change as we go through the words since we are kinda only paying attention to the end of the word\n", "root = [-6, 11, 14, 23] #some base tuple, it will change as we go through the words since we are kinda only paying attention to the end of the word\n",
"circlelist = list(root) #list of the curvatures, it starts with the root stuff and we will add to it \n", "circlelist = list(root) #list of the curvatures, it starts with the root stuff and we will add to it \n",
"word = [1] #word that we are currently considering, it will change as we go through these, the first word we start with is just the word that consists of the first generator\n", "word = [1] #word that we are currently considering, it will change as we go through these, the first word we start with is just the word that consists of the first generator\n",
"recentroot = [] #this will be an array of arrays. the recentroot[i] is the most recent tuple that wasn't too big for word of length i so that when we go back down we know which tuple to operate on\n", "recentroot = [] #this will be an array of arrays. the recentroot[i] is the most recent tuple that wasn't too big for word of length i so that when we go back down we know which tuple to operate on\n",
"recentroot.append(root) #the root thing will be our 0th element of this array\n", "recentroot.append(root) #the root thing will be our 0th element of this array\n",
"bound = 1000 #bound for what we want our curvatures to be under\n", "bound = 100 #bound for what we want our curvatures to be under\n",
"\n", "\n",
"while word: #this runs until you get back to the empty word\n", "while word: #this runs until you get back to the empty word\n",
" #print(\"root : \" + str(root))\n", " #print(\"root : \" + str(root))\n",
@ -365,8 +333,16 @@
"\n", "\n",
"#print(circlelist)\n", "#print(circlelist)\n",
"print(len(circlelist))\n", "print(len(circlelist))\n",
"print(circlelist)\n",
"curvefit(20,bound,circlelist) #this will print our fractal dimension once the circlelist has been made" "curvefit(20,bound,circlelist) #this will print our fractal dimension once the circlelist has been made"
] ]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
} }
], ],
"metadata": { "metadata": {