From ea2127fcfdb85c54bd8e6dec1d8dc42229df5e30 Mon Sep 17 00:00:00 2001 From: Cole Mathis Date: Thu, 18 Sep 2025 22:17:12 +0000 Subject: [PATCH 01/23] Update readme to link to dashboard --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 0cd6f21..c6a43e2 100644 --- a/README.md +++ b/README.md @@ -26,3 +26,8 @@ Documentation: * Help: `cargo run -- --help` The documentation for the configuration file is in the `Config` object. + + +# Interactive Dashboard + +Can be found here: https://github.com/mathis-group/Alchemy-Dashboard \ No newline at end of file From c3a6626cc5b635713315376be0bd157ea76eddd9 Mon Sep 17 00:00:00 2001 From: Cole Mathis Date: Tue, 23 Sep 2025 12:41:04 -0700 Subject: [PATCH 02/23] Cherry picked relevant files from --- Cargo.toml | 20 +++- pyproject.toml | 12 ++ src/lib.rs | 301 +++++++++++++++++++++++++++++++++++++++++++++--- test_alchemy.py | 80 +++++++++++++ 4 files changed, 397 insertions(+), 16 deletions(-) create mode 100644 pyproject.toml create mode 100644 test_alchemy.py diff --git a/Cargo.toml b/Cargo.toml index 5e446cb..27b52b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,17 +3,33 @@ name = "alchemy" version = "0.1.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +name = "alchemy" +crate-type = ["cdylib"] + +[package.metadata.maturin] +name = "alchemy" +python-source = "python" [dependencies] +pyo3 = { version = "0.22", features = ["extension-module", "abi3-py37"] } async-std = "1.12.0" clap = { version = "4.5.4", features = ["derive"] } futures = "0.3.30" -lambda_calculus = {git = "https://github.com/agentelement/lambda_calculus", branch = "size-feat"} +lambda_calculus = { git = "https://github.com/agentelement/lambda_calculus", branch = "size-feat" } +plotters = "0.3.6" rand = "0.8" rand_chacha = "0.3.1" serde = { version = "1.0.202", features = ["derive"] } serde_json = "1.0.117" +tokio = "1.39.2" + +[build-dependencies] +pyo3-build-config = "0.22" + +[features] +extension-module = ["pyo3/extension-module"] +default = ["extension-module"] [profile.profiling] inherits = "release" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..08d8da4 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,12 @@ +[build-system] +requires = ["maturin>=1,<2"] +build-backend = "maturin" + +[project] +name = "alchemy" +requires-python = ">=3.7" +classifiers = [ + "Programming Language :: Rust", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", +] \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 57d720a..0c8a047 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,20 +1,293 @@ -/// Simulation analysis -pub mod analysis; +use pyo3::prelude::*; +use pyo3::wrap_pyfunction; +use serde::{Deserialize, Serialize}; -/// Global configuration -pub mod config; -/// Random expression generators -pub mod generators; +// --- Module Imports --- +mod config; +mod soup; +mod experiments; +mod generators; +mod utils; +mod analysis; -/// Main AlChemy simulation module -pub mod supercollider; +use lambda_calculus::{parse, term::Notation::Classic, Term}; +use std::io::{self, BufRead}; -/// Experimental stuff -pub mod experiments; +pub fn read_inputs() -> impl Iterator { + io::stdin() + .lock() + .lines() + .filter_map(|line| line.ok()) + .filter_map(|line| parse(&line, Classic).ok()) +} -/// Utilities -pub mod utils; -/// Lambda-calculus stuff -pub mod lambda; +// --- Exposing Core Configurations --- +use crate::config::{Reactor as RustReactor, ConfigSeed}; +use crate::soup::{Soup, ReactionError}; +use crate::generators::{BTreeGen as RustBTreeGen, FontanaGen as RustFontanaGen, Standardization as RustStandardization}; +use crate::utils::{decode_hex, encode_hex}; +use crate::experiments::{look_for_add, entropy_series, entropy_test, sync_entropy_test}; + + +// --- Error Handling Wrappers --- +#[pyclass] +#[derive(Debug, Clone)] +pub struct PyReactionError { + kind: ReactionErrorKind, +} + +#[derive(Debug, Clone)] +pub enum ReactionErrorKind { + ExceedsReductionLimit, + NotEnoughExpressions, + IsIdentity, + IsParent, + HasFreeVariables, + ExceedsDepthLimit, +} + +impl From for PyReactionError { + fn from(error: ReactionError) -> Self { + let kind = match error { + ReactionError::ExceedsReductionLimit => ReactionErrorKind::ExceedsReductionLimit, + ReactionError::NotEnoughExpressions => ReactionErrorKind::NotEnoughExpressions, + ReactionError::IsIdentity => ReactionErrorKind::IsIdentity, + ReactionError::IsParent => ReactionErrorKind::IsParent, + ReactionError::HasFreeVariables => ReactionErrorKind::HasFreeVariables, + ReactionError::ExceedsDepthLimit => ReactionErrorKind::ExceedsDepthLimit, + }; + PyReactionError { kind } + } +} + +// --- Reactor Wrapper --- +#[pyclass] +pub struct PyReactor { + inner: RustReactor, +} + +#[pymethods] +impl PyReactor { + #[new] + fn new() -> Self { + PyReactor { + inner: RustReactor::new(), + } + } +} + +// --- Standardization Wrapper --- +#[pyclass] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PyStandardization { + standardization: RustStandardization, +} + +#[pymethods] +impl PyStandardization { + #[new] + fn new(kind: &str) -> PyResult { + let standardization = match kind { + "prefix" => RustStandardization::Prefix, + "postfix" => RustStandardization::Postfix, + "none" => RustStandardization::None, + _ => return Err(pyo3::exceptions::PyValueError::new_err("Invalid standardization type")) + }; + Ok(PyStandardization { standardization }) + } +} + +impl From for RustStandardization { + fn from(py_std: PyStandardization) -> Self { + py_std.standardization + } +} + +// --- Soup Wrapper --- +#[pyclass] +pub struct PySoup { + inner: Soup, +} + +#[pymethods] +impl PySoup { + #[new] + fn new() -> Self { + PySoup { inner: Soup::new() } + } + + #[staticmethod] + fn from_config(cfg: &PyReactor) -> Self { + PySoup { inner: Soup::from_config(&cfg.inner) } + } + + fn set_limit(&mut self, limit: usize) { + self.inner.set_limit(limit); + } + + fn perturb(&mut self, expressions: Vec) -> PyResult<()> { + let terms = expressions + .into_iter() + .filter_map(|s| parse(&s, Classic).ok()); + self.inner.perturb(terms); // Pass iterator directly + Ok(()) + } + + fn simulate_for(&mut self, n: usize, log: bool) -> usize { + self.inner.simulate_for(n, log) + } + + fn expressions(&self) -> Vec { + self.inner + .expressions() + .map(|term| term.to_string()) + .collect() + } + + fn len(&self) -> usize { + self.inner.len() + } + + fn collisions(&self) -> usize { + self.inner.collisions() + } + + fn unique_expressions(&self) -> Vec { + self.inner + .unique_expressions() + .into_iter() + .map(|term| term.to_string()) + .collect() + } + + fn expression_counts(&self) -> Vec<(String, u32)> { + self.inner + .expression_counts() + .into_iter() + .map(|(term, count)| (term.to_string(), count)) + .collect() + } + + fn population_entropy(&self) -> f32 { + self.inner.population_entropy() + } +} + +// --- BTreeGen Wrapper --- +#[pyclass] +pub struct PyBTreeGen { + inner: RustBTreeGen, +} + +#[pymethods] +impl PyBTreeGen { + #[new] + fn new() -> Self { + PyBTreeGen { inner: RustBTreeGen::new() } + } + + #[staticmethod] + fn from_config(size: u32, freevar_generation_probability: f64, max_free_vars: u32, std: PyStandardization) -> Self { + let config = config::BTreeGen { + size, + freevar_generation_probability, + n_max_free_vars: max_free_vars, + standardization: std.into(), + seed: ConfigSeed(Some([0; 32])), + }; + PyBTreeGen { inner: RustBTreeGen::from_config(&config) } + } + + fn generate(&mut self) -> String { + self.inner.generate().to_string() + } + + fn generate_n(&mut self, n: usize) -> Vec { + self.inner.generate_n(n).into_iter().map(|t| t.to_string()).collect() + } +} + +// --- FontanaGen Wrapper --- +#[pyclass] +pub struct PyFontanaGen { + inner: RustFontanaGen, +} + +#[pymethods] +impl PyFontanaGen { + #[staticmethod] + fn from_config(abs_range: (f64, f64), app_range: (f64, f64), max_depth: u32, max_free_vars: u32) -> Self { + let config = config::FontanaGen { + abstraction_prob_range: abs_range, + application_prob_range: app_range, + max_depth, + n_max_free_vars: max_free_vars, + seed: ConfigSeed(Some([0; 32])), + }; + PyFontanaGen { inner: RustFontanaGen::from_config(&config) } + } + + fn generate(&self) -> Option { + self.inner.generate().map(|term| term.to_string()) + } +} + +// --- Utilities --- +#[pyfunction] +fn decode_hex_py(hex_string: &str) -> PyResult> { + decode_hex(hex_string).map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string())) +} + +#[pyfunction] +fn encode_hex_py(bytes: Vec) -> String { + encode_hex(&bytes) +} + +// --- Experiment Functions --- +#[pyfunction] +fn run_look_for_add() -> PyResult<()> { + async_std::task::block_on(look_for_add()); + Ok(()) +} + +#[pyfunction] +fn run_entropy_series() -> PyResult<()> { + async_std::task::block_on(entropy_series()); + Ok(()) +} + +#[pyfunction] +fn run_entropy_test() -> PyResult<()> { + async_std::task::block_on(entropy_test()); + Ok(()) +} + +#[pyfunction] +fn run_sync_entropy_test() -> PyResult<()> { + sync_entropy_test(); + Ok(()) +} + +// --- Python Module Initialization --- +#[pymodule] +fn alchemy(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { + // Register classes + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + + // Register functions + m.add_function(wrap_pyfunction!(decode_hex_py, m)?)?; + m.add_function(wrap_pyfunction!(encode_hex_py, m)?)?; + m.add_function(wrap_pyfunction!(run_look_for_add, m)?)?; + m.add_function(wrap_pyfunction!(run_entropy_series, m)?)?; + m.add_function(wrap_pyfunction!(run_entropy_test, m)?)?; + m.add_function(wrap_pyfunction!(run_sync_entropy_test, m)?)?; + + Ok(()) +} diff --git a/test_alchemy.py b/test_alchemy.py new file mode 100644 index 0000000..4addacd --- /dev/null +++ b/test_alchemy.py @@ -0,0 +1,80 @@ +import sys +sys.path.append('/Users/ridhamap/Python_wrapper_alchemy/alchemy-reimplemented/alchemy_new/lib/python3.12/site-packages') +import alchemy + +def test_reactor(): + print("Testing PyReactor:") + reactor = alchemy.PyReactor() + print("PyReactor instance created successfully.") + +def test_standardization(): + print("Testing PyStandardization:") + try: + std = alchemy.PyStandardization("prefix") + print("Standardization created with 'prefix':", std) + except ValueError as e: + print("Error in creating Standardization:", e) + +def test_soup(): + print("Testing PySoup:") + soup = alchemy.PySoup() + print("Empty PySoup instance created.") + print("Initial length of soup:", soup.len()) + + valid_expressions = ["λx.x", "λx.λy.xy", "(λx.x) y", "λx.λy.(yx)", "λf.λx.(f (f x))"] + soup.perturb(valid_expressions) + + print("Soup after perturbation:", soup.expressions()) + print("Unique expressions:", soup.unique_expressions()) + print("Population entropy:", soup.population_entropy()) + + +def test_btree_gen(): + print("Testing PyBTreeGen:") + # Change "postfix" to a supported type, such as "prefix" + gen = alchemy.PyBTreeGen.from_config(5, 0.5, 3, alchemy.PyStandardization("prefix")) + print("BTreeGen instance created.") + print("Generated expression:", gen.generate()) + print("Generated 3 expressions:", gen.generate_n(3)) + + +def test_fontana_gen(): + print("Testing PyFontanaGen:") + fontana_gen = alchemy.PyFontanaGen.from_config((0.1, 0.5), (0.2, 0.6), 5, 2) + print("FontanaGen instance created.") + result = fontana_gen.generate() + print("Generated expression from FontanaGen:", result) + +def test_utilities(): + print("Testing Utilities:") + encoded = alchemy.encode_hex_py([104, 101, 108, 108, 111]) + print("Encoded hex:", encoded) + try: + decoded = alchemy.decode_hex_py(encoded) + print("Decoded hex:", decoded) + except ValueError as e: + print("Error in decoding hex:", e) + +def test_experiments(): + print("Testing Experiment Functions:") + try: + + #alchemy.run_look_for_add() + #print("run_look_for_add executed successfully.") + alchemy.run_entropy_series() + print("run_entropy_series executed successfully.") + alchemy.run_entropy_test() + print("run_entropy_test executed successfully.") + alchemy.run_sync_entropy_test() + print("run_sync_entropy_test executed successfully.") + except Exception as e: + print("Error in running experiment functions:", e) + +if __name__ == "__main__": + test_reactor() + test_standardization() + test_soup() + test_btree_gen() + test_fontana_gen() + test_utilities() + test_experiments() From d28b42666f9bb3ddc4d792e8faf63d51ad0957a1 Mon Sep 17 00:00:00 2001 From: devyanshnegi Date: Thu, 25 Sep 2025 14:44:45 -0700 Subject: [PATCH 03/23] Fix clippy warnings- Removed src/expirements from clippy Added default controucters for LambdaSoup, BTreeGen Implemented Rust Suggestions Renamed lambda module name to core Temporarily Suppressed dead code warning for FontanaGen --- src/experiments/discovery.rs | 3 +++ src/experiments/distribution.rs | 3 +++ src/experiments/entropy.rs | 3 +++ src/experiments/kinetics.rs | 3 +++ src/experiments/magic_test_function.rs | 3 +++ src/experiments/mod.rs | 3 +++ src/experiments/search_by_behavior.rs | 3 +++ src/generators.rs | 7 +++++++ src/lambda/{lambda.rs => core.rs} | 6 ++++++ src/lambda/mod.rs | 2 +- src/lambda/recursive.rs | 8 ++++---- src/supercollider.rs | 4 ++++ src/utils.rs | 4 ++-- 13 files changed, 45 insertions(+), 7 deletions(-) rename src/lambda/{lambda.rs => core.rs} (99%) diff --git a/src/experiments/discovery.rs b/src/experiments/discovery.rs index fd7266b..63c2b48 100644 --- a/src/experiments/discovery.rs +++ b/src/experiments/discovery.rs @@ -1,3 +1,6 @@ +#![allow(clippy::all)] +#![allow(warnings)] + use async_std::task::{block_on, spawn}; use futures::stream::{FuturesUnordered, StreamExt}; use lambda_calculus::{ diff --git a/src/experiments/distribution.rs b/src/experiments/distribution.rs index 268a2bb..feb37eb 100644 --- a/src/experiments/distribution.rs +++ b/src/experiments/distribution.rs @@ -1,3 +1,6 @@ +#![allow(clippy::all)] +#![allow(warnings)] + use std::collections::HashMap; use lambda_calculus::Term; diff --git a/src/experiments/entropy.rs b/src/experiments/entropy.rs index 35901bb..326c177 100644 --- a/src/experiments/entropy.rs +++ b/src/experiments/entropy.rs @@ -1,3 +1,6 @@ +#![allow(clippy::all)] +#![allow(warnings)] + use async_std::task::{block_on, spawn}; use futures::{stream::FuturesUnordered, StreamExt}; use lambda_calculus::Term; diff --git a/src/experiments/kinetics.rs b/src/experiments/kinetics.rs index d4a4efe..6f0087c 100644 --- a/src/experiments/kinetics.rs +++ b/src/experiments/kinetics.rs @@ -1,3 +1,6 @@ +#![allow(clippy::all)] +#![allow(warnings)] + use async_std::task::{block_on, spawn}; use futures::stream::{FuturesUnordered, StreamExt}; use lambda_calculus::{data::num::church::succ, Term}; diff --git a/src/experiments/magic_test_function.rs b/src/experiments/magic_test_function.rs index 251cac3..5a647ff 100644 --- a/src/experiments/magic_test_function.rs +++ b/src/experiments/magic_test_function.rs @@ -1,3 +1,6 @@ +#![allow(clippy::all)] +#![allow(warnings)] + use async_std::task::{block_on, spawn}; use futures::{stream::FuturesUnordered, StreamExt}; use lambda_calculus::reduction::Order::HAP; diff --git a/src/experiments/mod.rs b/src/experiments/mod.rs index 32beb14..c00ea94 100644 --- a/src/experiments/mod.rs +++ b/src/experiments/mod.rs @@ -1,3 +1,6 @@ +#![allow(clippy::all)] +#![allow(warnings)] + pub mod entropy; pub mod search_by_behavior; diff --git a/src/experiments/search_by_behavior.rs b/src/experiments/search_by_behavior.rs index 9b26b0c..07794f3 100644 --- a/src/experiments/search_by_behavior.rs +++ b/src/experiments/search_by_behavior.rs @@ -1,3 +1,6 @@ +#![allow(clippy::all)] +#![allow(warnings)] + use async_std::task::{block_on, spawn}; use futures::{stream::FuturesUnordered, StreamExt}; use lambda_calculus::{app, Term}; diff --git a/src/generators.rs b/src/generators.rs index cb89954..bed0c75 100644 --- a/src/generators.rs +++ b/src/generators.rs @@ -82,6 +82,12 @@ pub struct BTreeGen { rng: ChaCha8Rng, } +impl Default for BTreeGen { + fn default() -> BTreeGen { + Self::new() + } +} + impl BTreeGen { pub fn new() -> BTreeGen { BTreeGen::from_config(&config::BTreeGen::new()) @@ -146,6 +152,7 @@ impl BTreeGen { } } +#[allow(dead_code)] pub struct FontanaGen { abs_range: (f64, f64), app_range: (f64, f64), diff --git a/src/lambda/lambda.rs b/src/lambda/core.rs similarity index 99% rename from src/lambda/lambda.rs rename to src/lambda/core.rs index 6f84c72..186962e 100644 --- a/src/lambda/lambda.rs +++ b/src/lambda/core.rs @@ -247,6 +247,12 @@ impl fmt::Display for LambdaParticle { } } +impl Default for LambdaSoup { + fn default() -> Self { + Self::new() + } +} + impl LambdaSoup { /// Generate an empty soup with the following configuration options: pub fn new() -> Self { diff --git a/src/lambda/mod.rs b/src/lambda/mod.rs index 3cebbaa..f93920c 100644 --- a/src/lambda/mod.rs +++ b/src/lambda/mod.rs @@ -1,4 +1,4 @@ -pub mod lambda; +pub mod core; pub mod recursive; diff --git a/src/lambda/recursive.rs b/src/lambda/recursive.rs index 91bc317..5a7404e 100644 --- a/src/lambda/recursive.rs +++ b/src/lambda/recursive.rs @@ -94,8 +94,8 @@ fn uses_both_arguments_helper(expr: &Term, depth: usize) -> (bool, bool) { Term::Abs(ref boxed) => uses_both_arguments_helper(boxed, depth + 1), Term::App(ref boxed) => { let (ref left, ref right) = **boxed; - let (l0, l1) = uses_both_arguments_helper(&left, depth); - let (r0, r1) = uses_both_arguments_helper(&right, depth); + let (l0, l1) = uses_both_arguments_helper(left, depth); + let (r0, r1) = uses_both_arguments_helper(right, depth); (l0 || r0, l1 || r1) } Term::Var(n) => (*n == depth, *n == depth - 1), @@ -257,11 +257,11 @@ impl Collider for Alche left: LambdaParticle, right: LambdaParticle, ) -> Result { - return if left.recursive { + if left.recursive { self.recursive_collide(left, right) } else { self.nonrecursive_collide(left, right) - }; + } } } diff --git a/src/supercollider.rs b/src/supercollider.rs index 31fb7f4..772177d 100644 --- a/src/supercollider.rs +++ b/src/supercollider.rs @@ -223,6 +223,10 @@ where self.expressions.len() } + pub fn is_empty(&self) -> bool { + self.expressions.is_empty() + } + /// Get the number of successful collisions pub fn collisions(&self) -> usize { self.n_collisions diff --git a/src/utils.rs b/src/utils.rs index c8b3544..70c17ef 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -97,7 +97,7 @@ where U: Ord, { fn partial_cmp(&self, other: &Self) -> Option { - Some(self.priority.cmp(&other.priority)) + Some(self.cmp(other)) } } @@ -144,6 +144,6 @@ where for i in series { write!(file, "{:?}; ", i)?; } - write!(file, "\n")?; + writeln!(file)?; Ok(()) } From 9e0044543dcdf51abe63ff47043c7d5ab42b638f Mon Sep 17 00:00:00 2001 From: Cole Mathis Date: Thu, 25 Sep 2025 15:34:34 -0700 Subject: [PATCH 04/23] Working on integrating changes from functional super collider into python bindings --- Cargo.lock | 808 +++++++++++++++++++++++++++++++++++++++++++++++++- src/config.rs | 2 +- src/lib.rs | 82 ++--- 3 files changed, 844 insertions(+), 48 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b0b69a0..4df5bda 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,21 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "alchemy" @@ -10,10 +25,23 @@ dependencies = [ "clap", "futures", "lambda_calculus", + "plotters", + "pyo3", + "pyo3-build-config", "rand", "rand_chacha", "serde", "serde_json", + "tokio", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", ] [[package]] @@ -219,6 +247,21 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "backtrace" +version = "0.3.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -250,18 +293,47 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "bytemuck" +version = "1.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" + [[package]] name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "cc" +version = "1.2.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" +dependencies = [ + "find-msvc-tools", + "shlex", +] + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", +] + [[package]] name = "clap" version = "4.5.15" @@ -302,6 +374,12 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + [[package]] name = "colorchoice" version = "1.0.2" @@ -317,12 +395,115 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core-graphics" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "libc", +] + +[[package]] +name = "core-text" +version = "20.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9d2790b5c08465d49f8dc05c8bcae9fea467855947db39b0f8145c091aaced5" +dependencies = [ + "core-foundation", + "core-graphics", + "foreign-types", + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + [[package]] name = "crossbeam-utils" version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.59.0", +] + +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading", +] + +[[package]] +name = "dwrote" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20c93d234bac0cdd0e2ac08bc8a5133f8df2169e95b262dfcea5e5cb7855672f" +dependencies = [ + "lazy_static", + "libc", + "winapi", + "wio", +] + [[package]] name = "errno" version = "0.3.9" @@ -375,6 +556,100 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" + +[[package]] +name = "flate2" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "float-ord" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce81f49ae8a0482e4c55ea62ebbd7e5a686af544c00b9d090bba3ff9be97b3d" + +[[package]] +name = "font-kit" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c7e611d49285d4c4b2e1727b72cf05353558885cc5252f93707b845dfcaf3d3" +dependencies = [ + "bitflags 2.6.0", + "byteorder", + "core-foundation", + "core-graphics", + "core-text", + "dirs", + "dwrote", + "float-ord", + "freetype-sys", + "lazy_static", + "libc", + "log", + "pathfinder_geometry", + "pathfinder_simd", + "walkdir", + "winapi", + "yeslogic-fontconfig-sys", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "freetype-sys" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7edc5b9669349acfda99533e9e0bcf26a51862ab43b08ee7745c55d28eb134" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "futures" version = "0.3.30" @@ -503,6 +778,22 @@ dependencies = [ "wasi", ] +[[package]] +name = "gif" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + [[package]] name = "gloo-timers" version = "0.2.6" @@ -533,6 +824,50 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +[[package]] +name = "iana-time-zone" +version = "0.1.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "image" +version = "0.24.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "jpeg-decoder", + "num-traits", + "png", +] + +[[package]] +name = "indoc" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" + [[package]] name = "instant" version = "0.1.13" @@ -553,6 +888,17 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "io-uring" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "libc", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -565,6 +911,12 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "jpeg-decoder" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07" + [[package]] name = "js-sys" version = "0.3.70" @@ -588,11 +940,37 @@ name = "lambda_calculus" version = "3.3.0" source = "git+https://github.com/agentelement/lambda_calculus?branch=size-feat#8346381fc0df29f3ed5022913d58d3a5244c22e7" +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" -version = "0.2.155" +version = "0.2.176" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "libredox" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +dependencies = [ + "bitflags 2.6.0", + "libc", +] [[package]] name = "linux-raw-sys" @@ -621,18 +999,91 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.59.0", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "parking" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +[[package]] +name = "pathfinder_geometry" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b7e7b4ea703700ce73ebf128e1450eb69c3a8329199ffbfb9b2a0418e5ad3" +dependencies = [ + "log", + "pathfinder_simd", +] + +[[package]] +name = "pathfinder_simd" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf9027960355bf3afff9841918474a81a5f972ac6d226d518060bba758b5ad57" +dependencies = [ + "rustc_version", +] + [[package]] name = "pin-project-lite" version = "0.2.14" @@ -656,6 +1107,71 @@ dependencies = [ "futures-io", ] +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "chrono", + "font-kit", + "image", + "lazy_static", + "num-traits", + "pathfinder_geometry", + "plotters-backend", + "plotters-bitmap", + "plotters-svg", + "ttf-parser", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-bitmap" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ce181e3f6bf82d6c1dc569103ca7b1bd964c60ba03d7e6cdfbb3e3eb7f7405" +dependencies = [ + "gif", + "image", + "plotters-backend", +] + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + [[package]] name = "polling" version = "2.8.0" @@ -687,6 +1203,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "portable-atomic" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + [[package]] name = "ppv-lite86" version = "0.2.20" @@ -698,13 +1220,76 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] +[[package]] +name = "pyo3" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f402062616ab18202ae8319da13fa4279883a2b8a9d9f83f20dbade813ce1884" +dependencies = [ + "cfg-if", + "indoc", + "libc", + "memoffset", + "once_cell", + "portable-atomic", + "pyo3-build-config", + "pyo3-ffi", + "pyo3-macros", + "unindent", +] + +[[package]] +name = "pyo3-build-config" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b14b5775b5ff446dd1056212d778012cbe8a0fbffd368029fd9e25b514479c38" +dependencies = [ + "once_cell", + "target-lexicon", +] + +[[package]] +name = "pyo3-ffi" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ab5bcf04a2cdcbb50c7d6105de943f543f9ed92af55818fd17b660390fc8636" +dependencies = [ + "libc", + "pyo3-build-config", +] + +[[package]] +name = "pyo3-macros" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fd24d897903a9e6d80b968368a34e1525aeb719d568dba8b3d4bfa5dc67d453" +dependencies = [ + "proc-macro2", + "pyo3-macros-backend", + "quote", + "syn", +] + +[[package]] +name = "pyo3-macros-backend" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c011a03ba1e50152b4b394b479826cad97e7a21eb52df179cd91ac411cbfbe" +dependencies = [ + "heck", + "proc-macro2", + "pyo3-build-config", + "quote", + "syn", +] + [[package]] name = "quote" version = "1.0.36" @@ -744,6 +1329,32 @@ dependencies = [ "getrandom", ] +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.37.27" @@ -777,6 +1388,21 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + [[package]] name = "serde" version = "1.0.207" @@ -809,6 +1435,18 @@ dependencies = [ "serde", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "slab" version = "0.4.9" @@ -836,15 +1474,55 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.74" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[package]] +name = "thiserror" +version = "2.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio" +version = "1.47.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +dependencies = [ + "backtrace", + "io-uring", + "libc", + "mio", + "pin-project-lite", + "slab", +] + [[package]] name = "tracing" version = "0.1.40" @@ -861,12 +1539,24 @@ version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +[[package]] +name = "ttf-parser" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unindent" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3" + [[package]] name = "utf8parse" version = "0.2.2" @@ -885,6 +1575,16 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -968,6 +1668,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "weezl" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" + [[package]] name = "winapi" version = "0.3.9" @@ -984,12 +1690,80 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.62.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + +[[package]] +name = "windows-result" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -1138,6 +1912,26 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "wio" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5" +dependencies = [ + "winapi", +] + +[[package]] +name = "yeslogic-fontconfig-sys" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "503a066b4c037c440169d995b869046827dbc71263f6e8f3be6d77d4f3229dbd" +dependencies = [ + "dlib", + "once_cell", + "pkg-config", +] + [[package]] name = "zerocopy" version = "0.7.35" diff --git a/src/config.rs b/src/config.rs index e0ab01a..1a4ccde 100644 --- a/src/config.rs +++ b/src/config.rs @@ -225,7 +225,7 @@ impl Config { /// to ser/de to/from a hex string. #[warn(missing_docs)] #[derive(Debug, Clone, Copy)] -pub struct ConfigSeed(Option<[u8; 32]>); +pub struct ConfigSeed(pub Option<[u8; 32]>); impl ConfigSeed { /// Get the seed item diff --git a/src/lib.rs b/src/lib.rs index 0c8a047..6691434 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,11 +5,13 @@ use serde::{Deserialize, Serialize}; // --- Module Imports --- mod config; -mod soup; +mod supercollider; mod experiments; mod generators; mod utils; mod analysis; +mod lambda; + use lambda_calculus::{parse, term::Notation::Classic, Term}; use std::io::{self, BufRead}; @@ -25,17 +27,17 @@ pub fn read_inputs() -> impl Iterator { // --- Exposing Core Configurations --- use crate::config::{Reactor as RustReactor, ConfigSeed}; -use crate::soup::{Soup, ReactionError}; +use crate::supercollider::Soup; use crate::generators::{BTreeGen as RustBTreeGen, FontanaGen as RustFontanaGen, Standardization as RustStandardization}; use crate::utils::{decode_hex, encode_hex}; -use crate::experiments::{look_for_add, entropy_series, entropy_test, sync_entropy_test}; - +//use crate::experiments::{look_for_add, entropy_series, entropy_test, sync_entropy_test}; +use crate::lambda::lambda::LambdaCollisionError; // --- Error Handling Wrappers --- #[pyclass] #[derive(Debug, Clone)] pub struct PyReactionError { - kind: ReactionErrorKind, + kind: LambdaCollisionError, } #[derive(Debug, Clone)] @@ -48,15 +50,15 @@ pub enum ReactionErrorKind { ExceedsDepthLimit, } -impl From for PyReactionError { - fn from(error: ReactionError) -> Self { +impl From for PyReactionError { + fn from(error: LambdaCollisionError) -> Self { let kind = match error { - ReactionError::ExceedsReductionLimit => ReactionErrorKind::ExceedsReductionLimit, - ReactionError::NotEnoughExpressions => ReactionErrorKind::NotEnoughExpressions, - ReactionError::IsIdentity => ReactionErrorKind::IsIdentity, - ReactionError::IsParent => ReactionErrorKind::IsParent, - ReactionError::HasFreeVariables => ReactionErrorKind::HasFreeVariables, - ReactionError::ExceedsDepthLimit => ReactionErrorKind::ExceedsDepthLimit, + LambdaCollisionError::ExceedsReductionLimit => ReactionErrorKind::ExceedsReductionLimit, + LambdaCollisionError::NotEnoughExpressions => ReactionErrorKind::NotEnoughExpressions, + LambdaCollisionError::IsIdentity => ReactionErrorKind::IsIdentity, + LambdaCollisionError::IsParent => ReactionErrorKind::IsParent, + LambdaCollisionError::HasFreeVariables => ReactionErrorKind::HasFreeVariables, + LambdaCollisionError::ExceedsDepthLimit => ReactionErrorKind::ExceedsDepthLimit, }; PyReactionError { kind } } @@ -246,29 +248,29 @@ fn encode_hex_py(bytes: Vec) -> String { } // --- Experiment Functions --- -#[pyfunction] -fn run_look_for_add() -> PyResult<()> { - async_std::task::block_on(look_for_add()); - Ok(()) -} - -#[pyfunction] -fn run_entropy_series() -> PyResult<()> { - async_std::task::block_on(entropy_series()); - Ok(()) -} - -#[pyfunction] -fn run_entropy_test() -> PyResult<()> { - async_std::task::block_on(entropy_test()); - Ok(()) -} - -#[pyfunction] -fn run_sync_entropy_test() -> PyResult<()> { - sync_entropy_test(); - Ok(()) -} +// #[pyfunction] +// fn run_look_for_add() -> PyResult<()> { +// async_std::task::block_on(look_for_add()); +// Ok(()) +// } + +// #[pyfunction] +// fn run_entropy_series() -> PyResult<()> { +// async_std::task::block_on(entropy_series()); +// Ok(()) +// } + +// #[pyfunction] +// fn run_entropy_test() -> PyResult<()> { +// async_std::task::block_on(entropy_test()); +// Ok(()) +// } + +// #[pyfunction] +// fn run_sync_entropy_test() -> PyResult<()> { +// sync_entropy_test(); +// Ok(()) +// } // --- Python Module Initialization --- #[pymodule] @@ -284,10 +286,10 @@ fn alchemy(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { // Register functions m.add_function(wrap_pyfunction!(decode_hex_py, m)?)?; m.add_function(wrap_pyfunction!(encode_hex_py, m)?)?; - m.add_function(wrap_pyfunction!(run_look_for_add, m)?)?; - m.add_function(wrap_pyfunction!(run_entropy_series, m)?)?; - m.add_function(wrap_pyfunction!(run_entropy_test, m)?)?; - m.add_function(wrap_pyfunction!(run_sync_entropy_test, m)?)?; + // m.add_function(wrap_pyfunction!(run_look_for_add, m)?)?; + // m.add_function(wrap_pyfunction!(run_entropy_series, m)?)?; + // m.add_function(wrap_pyfunction!(run_entropy_test, m)?)?; + // m.add_function(wrap_pyfunction!(run_sync_entropy_test, m)?)?; Ok(()) } From 9047adf1333f96cb6e56780a26c1c49f804af22d Mon Sep 17 00:00:00 2001 From: devyanshnegi Date: Thu, 2 Oct 2025 09:17:29 -0700 Subject: [PATCH 05/23] Fonatana Gen Implementation --- src/config.rs | 37 ++++++++------ src/generators.rs | 126 ++++++++++++++++++++++++++++++++++++++++++---- src/main.rs | 8 +-- 3 files changed, 142 insertions(+), 29 deletions(-) diff --git a/src/config.rs b/src/config.rs index e0ab01a..af324f3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -107,7 +107,6 @@ pub struct BTreeGen { pub standardization: Standardization, } -/// Configuration for Fontana's generator #[warn(missing_docs)] #[derive(Serialize, Deserialize, Debug)] pub struct FontanaGen { @@ -115,6 +114,12 @@ pub struct FontanaGen { /// randomly. Default: `None` pub seed: ConfigSeed, + /// Minimum depth before leaf nodes can be generated + pub min_depth: u32, + + /// Maximum depth of the generated trees + pub max_depth: u32, + /// Probability range of an abstraction being generated. Linearly changes from start to end, /// varying with depth pub abstraction_prob_range: (f64, f64), @@ -123,13 +128,28 @@ pub struct FontanaGen { /// varying with depth pub application_prob_range: (f64, f64), - /// Maximum depth of the generated trees - pub max_depth: u32, + /// Probability that a leaf vertex is a free variable + pub free_variable_probability: f64, /// Size of the free variable palette pub n_max_free_vars: u32, } +impl GenConfig for FontanaGen { + fn new() -> Self { + FontanaGen { + seed: ConfigSeed(None), + min_depth: 0, + max_depth: 10, + n_max_free_vars: 6, + application_prob_range: (0.3, 0.5), + abstraction_prob_range: (0.5, 0.3), + free_variable_probability: 0.0, + } + } +} + + impl Reactor { /// Produce a new `ReactorConfig` struct with default values. pub fn new() -> Self { @@ -169,17 +189,6 @@ impl GenConfig for BTreeGen { } } -impl GenConfig for FontanaGen { - fn new() -> Self { - FontanaGen { - max_depth: 10, - n_max_free_vars: 6, - application_prob_range: (0.3, 0.5), - abstraction_prob_range: (0.5, 0.3), - seed: ConfigSeed(None), - } - } -} impl Config { /// Create a config object from a string diff --git a/src/generators.rs b/src/generators.rs index cb89954..13437d1 100644 --- a/src/generators.rs +++ b/src/generators.rs @@ -147,31 +147,135 @@ impl BTreeGen { } pub struct FontanaGen { - abs_range: (f64, f64), - app_range: (f64, f64), - depth_cutoff: u32, - free_vars_count: u32, + min_depth: u32, + max_depth: u32, + + abs_prob: (f32, f32), + app_prob: (f32, f32), + + abs_incr: f32, + app_incr: f32, + + free_prob: f32, + max_vars: u32, seed: [u8; 32], rng: ChaCha8Rng, } impl FontanaGen { + pub fn new( + min_depth: u32, + max_depth: u32, + abs_prob: (f32, f32), + app_prob: (f32, f32), + free_prob: f32, + max_vars: u32, + seed: [u8; 32], + ) -> FontanaGen { + let abs_incr = (abs_prob.1 - abs_prob.0) / ((max_depth - 1) as f32); + let app_incr = (app_prob.1 - app_prob.0) / ((max_depth - 1) as f32); + + FontanaGen { + min_depth, + max_depth, + abs_prob, + app_prob, + abs_incr, + app_incr, + free_prob, + max_vars, + seed, + rng: ChaCha8Rng::from_seed(seed), + } + } + pub fn from_config(cfg: &config::FontanaGen) -> FontanaGen { let seed = cfg.seed.get(); let rng = ChaCha8Rng::from_seed(seed); + + let abs_incr: f32 = ((cfg.abstraction_prob_range.1 - cfg.abstraction_prob_range.0) + / ((cfg.max_depth - 1) as f64)) as f32; + let app_incr: f32 = ((cfg.application_prob_range.1 - cfg.application_prob_range.0) + / ((cfg.max_depth - 1) as f64)) as f32; + FontanaGen { - abs_range: cfg.abstraction_prob_range, - app_range: cfg.application_prob_range, - depth_cutoff: cfg.max_depth, - free_vars_count: cfg.n_max_free_vars, + min_depth: 0, + max_depth: cfg.max_depth, + + abs_prob: (cfg.abstraction_prob_range.0 as f32, cfg.abstraction_prob_range.1 as f32), + app_prob: (cfg.application_prob_range.0 as f32, cfg.application_prob_range.1 as f32), + + abs_incr, + app_incr, + free_prob: 0.0, + max_vars: cfg.n_max_free_vars, + seed, - rng, + rng: ChaCha8Rng::from_seed(seed), } } - pub fn generate(&self) -> Option { - None + pub fn generate(&mut self) -> Term{ + self.rand_lambda(0, self.abs_prob.0, self.app_prob.0) + } + + pub fn generate_n(&mut self, n: usize) -> Vec { + let mut v = Vec::with_capacity(n); + for _ in 0..n { + v.push(self.generate()) + } + v + } + + pub fn seed(&self) -> [u8; 32] { + self.seed + } + + pub fn rand_lambda(&mut self, depth: u32, p_abs: f32, p_app: f32) -> Term { + if depth >= self.max_depth { // over max depth generating leaf + let var = if self.rng.gen_bool(self.free_prob as f64) || depth == 0 { + depth + self.rng.gen_range(1..=self.max_vars) + } else { + self.rng.gen_range(1..=depth) + }; + return Term::Var(var as usize); + } else if depth < self.min_depth { // under min length will not generate leaf + let coin = self.rng.gen_bool(0.5); + if coin { + let n_abs = p_abs + self.abs_incr; + let n_app = p_app + self.app_incr; + return Term::Abs(Box::new(self.rand_lambda(depth + 1, n_abs, n_app))); + } else { + let n_abs = p_abs + self.abs_incr; + let n_app = p_app + self.app_incr; + return Term::App(Box::new(( + self.rand_lambda(depth+1, n_abs, n_app), + self.rand_lambda(depth+1, n_abs, n_app), + ))); + }; + } else { + let coin: f32 = self.rng.gen(); + if coin <= p_abs { + let n_abs = p_abs + self.abs_incr; + let n_app = p_app + self.app_incr; + return Term::Abs(Box::new(self.rand_lambda(depth + 1, n_abs, n_app))); + } else if coin <= p_abs + p_app { + let n_abs = p_abs + self.abs_incr; + let n_app = p_app + self.app_incr; + return Term::App(Box::new(( + self.rand_lambda(depth+1, n_abs, n_app), + self.rand_lambda(depth+1, n_abs, n_app), + ))); + } else { + let var = if self.rng.gen_bool(self.free_prob as f64) || depth == 0 { + depth + self.rng.gen_range(1..=self.max_vars) + } else { + self.rng.gen_range(1..=depth) + }; + return Term::Var(var as usize); + } + } } } diff --git a/src/main.rs b/src/main.rs index 66f9ad6..df293fd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -124,10 +124,10 @@ pub fn generate_expressions_and_seed_soup(cfg: &config::Config) -> lambda::recur gen.generate_n(cfg.sample_size) } config::Generator::Fontana(gen_cfg) => { - let gen = generators::FontanaGen::from_config(gen_cfg); - std::iter::from_fn(move || gen.generate()) - .take(cfg.sample_size) - .collect::>() + let mut gen = generators::FontanaGen::from_config(gen_cfg); + gen.generate_n(cfg.sample_size); + + } }; let mut soup = lambda::recursive::LambdaSoup::from_config(&cfg.reactor_config); From 99c0a50ee59fac7a9ed60d26f7feb2e2b3cc2b01 Mon Sep 17 00:00:00 2001 From: Devyansh <67937759+devyanshnegi@users.noreply.github.com> Date: Thu, 2 Oct 2025 09:20:00 -0700 Subject: [PATCH 06/23] Update main.rs Fixed syntax error --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index df293fd..3581afe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -125,7 +125,7 @@ pub fn generate_expressions_and_seed_soup(cfg: &config::Config) -> lambda::recur } config::Generator::Fontana(gen_cfg) => { let mut gen = generators::FontanaGen::from_config(gen_cfg); - gen.generate_n(cfg.sample_size); + gen.generate_n(cfg.sample_size) } From 0d530dc99b233014e38f9386c31b87a2f9b068d3 Mon Sep 17 00:00:00 2001 From: "ridham.patel" Date: Thu, 16 Oct 2025 13:47:52 -0700 Subject: [PATCH 07/23] lib: make modules public; add rlib crate-type; fix PySoup.perturb API; wire CLI --- Cargo.toml | 4 +- src/lib.rs | 464 +++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 399 insertions(+), 69 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 27b52b8..94c62ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,9 +3,11 @@ name = "alchemy" version = "0.1.0" edition = "2021" + [lib] name = "alchemy" -crate-type = ["cdylib"] +path = "src/lib.rs" +crate-type = ["cdylib", "rlib"] [package.metadata.maturin] name = "alchemy" diff --git a/src/lib.rs b/src/lib.rs index 6691434..9045cfd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,16 +1,317 @@ +// use pyo3::prelude::*; +// use pyo3::wrap_pyfunction; +// use serde::{Deserialize, Serialize}; + + +// // --- Module Imports --- +// mod config; +// mod supercollider; +// mod experiments; +// mod generators; +// mod utils; +// mod analysis; +// mod lambda; + + +// use lambda_calculus::{parse, term::Notation::Classic, Term}; +// use std::io::{self, BufRead}; + +// pub fn read_inputs() -> impl Iterator { +// io::stdin() +// .lock() +// .lines() +// .filter_map(|line| line.ok()) +// .filter_map(|line| parse(&line, Classic).ok()) +// } + + +// // --- Exposing Core Configurations --- +// use crate::config::{Reactor as RustReactor, ConfigSeed}; +// //use crate::supercollider::Soup; +// use crate::generators::{BTreeGen as RustBTreeGen, FontanaGen as RustFontanaGen, Standardization as RustStandardization}; +// use crate::utils::{decode_hex, encode_hex}; +// //use crate::experiments::{look_for_add, entropy_series, entropy_test, sync_entropy_test}; +// //use crate::lambda::lambda::LambdaCollisionError; + +// use crate::supercollider::Soup as GenericSoup; +// use crate::lambda::recursive::{ +// LambdaParticle, AlchemyCollider, LambdaCollisionOk, LambdaCollisionError, +// }; +// type RustSoup = GenericSoup; + +// // --- Error Handling Wrappers --- +// #[pyclass] +// #[derive(Debug, Clone)] +// pub struct PyReactionError { +// kind: LambdaCollisionError, +// } + +// #[derive(Debug, Clone)] +// pub enum ReactionErrorKind { +// ExceedsReductionLimit, +// NotEnoughExpressions, +// IsIdentity, +// IsParent, +// HasFreeVariables, +// ExceedsDepthLimit, +// } + +// impl From for PyReactionError { +// fn from(error: LambdaCollisionError) -> Self { +// let kind = match error { +// LambdaCollisionError::ExceedsReductionLimit => ReactionErrorKind::ExceedsReductionLimit, +// LambdaCollisionError::NotEnoughExpressions => ReactionErrorKind::NotEnoughExpressions, +// LambdaCollisionError::IsIdentity => ReactionErrorKind::IsIdentity, +// LambdaCollisionError::IsParent => ReactionErrorKind::IsParent, +// LambdaCollisionError::HasFreeVariables => ReactionErrorKind::HasFreeVariables, +// LambdaCollisionError::ExceedsDepthLimit => ReactionErrorKind::ExceedsDepthLimit, +// }; +// PyReactionError { kind } +// } +// } + +// // --- Reactor Wrapper --- +// #[pyclass] +// pub struct PyReactor { +// inner: RustReactor, +// } + +// #[pymethods] +// impl PyReactor { +// #[new] +// fn new() -> Self { +// PyReactor { +// inner: RustReactor::new(), +// } +// } +// } + +// // --- Standardization Wrapper --- +// #[pyclass] +// #[derive(Debug, Clone, Serialize, Deserialize)] +// pub struct PyStandardization { +// standardization: RustStandardization, +// } + +// #[pymethods] +// impl PyStandardization { +// #[new] +// fn new(kind: &str) -> PyResult { +// let standardization = match kind { +// "prefix" => RustStandardization::Prefix, +// "postfix" => RustStandardization::Postfix, +// "none" => RustStandardization::None, +// _ => return Err(pyo3::exceptions::PyValueError::new_err("Invalid standardization type")) +// }; +// Ok(PyStandardization { standardization }) +// } +// } + +// impl From for RustStandardization { +// fn from(py_std: PyStandardization) -> Self { +// py_std.standardization +// } +// } + +// // --- Soup Wrapper --- +// #[pyclass] +// pub struct PySoup { +// inner: Soup, +// } + +// #[pymethods] +// impl PySoup { +// #[new] +// fn new() -> Self { +// PySoup { inner: Soup::new() } +// } + +// #[staticmethod] +// fn from_config(cfg: &PyReactor) -> Self { +// PySoup { inner: Soup::from_config(&cfg.inner) } +// } + +// fn set_limit(&mut self, limit: usize) { +// self.inner.set_limit(limit); +// } + +// fn perturb(&mut self, expressions: Vec) -> PyResult<()> { +// let terms = expressions +// .into_iter() +// .filter_map(|s| parse(&s, Classic).ok()); +// self.inner.perturb(terms); // Pass iterator directly +// Ok(()) +// } + +// fn simulate_for(&mut self, n: usize, log: bool) -> usize { +// self.inner.simulate_for(n, log) +// } + +// fn expressions(&self) -> Vec { +// self.inner +// .expressions() +// .map(|term| term.to_string()) +// .collect() +// } + +// fn len(&self) -> usize { +// self.inner.len() +// } + +// fn collisions(&self) -> usize { +// self.inner.collisions() +// } + +// fn unique_expressions(&self) -> Vec { +// self.inner +// .unique_expressions() +// .into_iter() +// .map(|term| term.to_string()) +// .collect() +// } + +// fn expression_counts(&self) -> Vec<(String, u32)> { +// self.inner +// .expression_counts() +// .into_iter() +// .map(|(term, count)| (term.to_string(), count)) +// .collect() +// } + +// fn population_entropy(&self) -> f32 { +// self.inner.population_entropy() +// } +// } + +// // --- BTreeGen Wrapper --- +// #[pyclass] +// pub struct PyBTreeGen { +// inner: RustBTreeGen, +// } + +// #[pymethods] +// impl PyBTreeGen { +// #[new] +// fn new() -> Self { +// PyBTreeGen { inner: RustBTreeGen::new() } +// } + +// #[staticmethod] +// fn from_config(size: u32, freevar_generation_probability: f64, max_free_vars: u32, std: PyStandardization) -> Self { +// let config = config::BTreeGen { +// size, +// freevar_generation_probability, +// n_max_free_vars: max_free_vars, +// standardization: std.into(), +// seed: ConfigSeed(Some([0; 32])), +// }; +// PyBTreeGen { inner: RustBTreeGen::from_config(&config) } +// } + +// fn generate(&mut self) -> String { +// self.inner.generate().to_string() +// } + +// fn generate_n(&mut self, n: usize) -> Vec { +// self.inner.generate_n(n).into_iter().map(|t| t.to_string()).collect() +// } +// } + +// // --- FontanaGen Wrapper --- +// #[pyclass] +// pub struct PyFontanaGen { +// inner: RustFontanaGen, +// } + +// #[pymethods] +// impl PyFontanaGen { +// #[staticmethod] +// fn from_config(abs_range: (f64, f64), app_range: (f64, f64), max_depth: u32, max_free_vars: u32) -> Self { +// let config = config::FontanaGen { +// abstraction_prob_range: abs_range, +// application_prob_range: app_range, +// max_depth, +// n_max_free_vars: max_free_vars, +// seed: ConfigSeed(Some([0; 32])), +// }; +// PyFontanaGen { inner: RustFontanaGen::from_config(&config) } +// } + +// fn generate(&self) -> Option { +// self.inner.generate().map(|term| term.to_string()) +// } +// } + +// // --- Utilities --- +// #[pyfunction] +// fn decode_hex_py(hex_string: &str) -> PyResult> { +// decode_hex(hex_string).map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string())) +// } + +// #[pyfunction] +// fn encode_hex_py(bytes: Vec) -> String { +// encode_hex(&bytes) +// } + +// // --- Experiment Functions --- +// // #[pyfunction] +// // fn run_look_for_add() -> PyResult<()> { +// // async_std::task::block_on(look_for_add()); +// // Ok(()) +// // } + +// // #[pyfunction] +// // fn run_entropy_series() -> PyResult<()> { +// // async_std::task::block_on(entropy_series()); +// // Ok(()) +// // } + +// // #[pyfunction] +// // fn run_entropy_test() -> PyResult<()> { +// // async_std::task::block_on(entropy_test()); +// // Ok(()) +// // } + +// // #[pyfunction] +// // fn run_sync_entropy_test() -> PyResult<()> { +// // sync_entropy_test(); +// // Ok(()) +// // } + +// // --- Python Module Initialization --- +// #[pymodule] +// fn alchemy(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { +// // Register classes +// m.add_class::()?; +// m.add_class::()?; +// m.add_class::()?; +// m.add_class::()?; +// m.add_class::()?; +// m.add_class::()?; + +// // Register functions +// m.add_function(wrap_pyfunction!(decode_hex_py, m)?)?; +// m.add_function(wrap_pyfunction!(encode_hex_py, m)?)?; +// // m.add_function(wrap_pyfunction!(run_look_for_add, m)?)?; +// // m.add_function(wrap_pyfunction!(run_entropy_series, m)?)?; +// // m.add_function(wrap_pyfunction!(run_entropy_test, m)?)?; +// // m.add_function(wrap_pyfunction!(run_sync_entropy_test, m)?)?; + +// Ok(()) +// } + use pyo3::prelude::*; use pyo3::wrap_pyfunction; use serde::{Deserialize, Serialize}; - // --- Module Imports --- -mod config; -mod supercollider; -mod experiments; -mod generators; -mod utils; -mod analysis; -mod lambda; +pub mod config; +pub mod experiments; +pub mod generators; +pub mod utils; +pub mod analysis; +pub mod lambda; +pub mod supercollider; use lambda_calculus::{parse, term::Notation::Classic, Term}; @@ -24,20 +325,31 @@ pub fn read_inputs() -> impl Iterator { .filter_map(|line| parse(&line, Classic).ok()) } - // --- Exposing Core Configurations --- use crate::config::{Reactor as RustReactor, ConfigSeed}; -use crate::supercollider::Soup; -use crate::generators::{BTreeGen as RustBTreeGen, FontanaGen as RustFontanaGen, Standardization as RustStandardization}; +use crate::generators::{ + BTreeGen as RustBTreeGen, FontanaGen as RustFontanaGen, Standardization as RustStandardization, +}; use crate::utils::{decode_hex, encode_hex}; -//use crate::experiments::{look_for_add, entropy_series, entropy_test, sync_entropy_test}; -use crate::lambda::lambda::LambdaCollisionError; +// use crate::experiments::{look_for_add, entropy_series, entropy_test, sync_entropy_test}; + +// Bring in the concrete lambda types so we can fully specify Soup. +use crate::lambda::recursive::{ + AlchemyCollider, LambdaCollisionError, LambdaCollisionOk, LambdaParticle, +}; + +// Create a concrete alias for the generic Soup. Without this, the compiler +// complains about missing generic parameters and ambiguous new()/from_config() impls. +use crate::supercollider::Soup as GenericSoup; +type RustSoup = + GenericSoup; // --- Error Handling Wrappers --- #[pyclass] #[derive(Debug, Clone)] pub struct PyReactionError { - kind: LambdaCollisionError, + // Store the kind you map to below rather than LambdaCollisionError itself. + kind: ReactionErrorKind, } #[derive(Debug, Clone)] @@ -48,17 +360,26 @@ pub enum ReactionErrorKind { IsParent, HasFreeVariables, ExceedsDepthLimit, + RecursiveArgument, + BadArgument, } +// Map the recursive LambdaCollisionError into your public PyReactionError. impl From for PyReactionError { fn from(error: LambdaCollisionError) -> Self { let kind = match error { - LambdaCollisionError::ExceedsReductionLimit => ReactionErrorKind::ExceedsReductionLimit, - LambdaCollisionError::NotEnoughExpressions => ReactionErrorKind::NotEnoughExpressions, + LambdaCollisionError::ExceedsReductionLimit => { + ReactionErrorKind::ExceedsReductionLimit + } + LambdaCollisionError::NotEnoughExpressions => { + ReactionErrorKind::NotEnoughExpressions + } LambdaCollisionError::IsIdentity => ReactionErrorKind::IsIdentity, LambdaCollisionError::IsParent => ReactionErrorKind::IsParent, LambdaCollisionError::HasFreeVariables => ReactionErrorKind::HasFreeVariables, LambdaCollisionError::ExceedsDepthLimit => ReactionErrorKind::ExceedsDepthLimit, + LambdaCollisionError::RecursiveArgument => ReactionErrorKind::RecursiveArgument, + LambdaCollisionError::BadArgument => ReactionErrorKind::BadArgument, }; PyReactionError { kind } } @@ -95,7 +416,11 @@ impl PyStandardization { "prefix" => RustStandardization::Prefix, "postfix" => RustStandardization::Postfix, "none" => RustStandardization::None, - _ => return Err(pyo3::exceptions::PyValueError::new_err("Invalid standardization type")) + _ => { + return Err(pyo3::exceptions::PyValueError::new_err( + "Invalid standardization type", + )) + } }; Ok(PyStandardization { standardization }) } @@ -110,44 +435,40 @@ impl From for RustStandardization { // --- Soup Wrapper --- #[pyclass] pub struct PySoup { - inner: Soup, + inner: RustSoup, } #[pymethods] impl PySoup { #[new] fn new() -> Self { - PySoup { inner: Soup::new() } + PySoup { + inner: RustSoup::new(), + } } #[staticmethod] fn from_config(cfg: &PyReactor) -> Self { - PySoup { inner: Soup::from_config(&cfg.inner) } - } - - fn set_limit(&mut self, limit: usize) { - self.inner.set_limit(limit); + PySoup { + inner: RustSoup::from_config(&cfg.inner), + } } fn perturb(&mut self, expressions: Vec) -> PyResult<()> { - let terms = expressions - .into_iter() - .filter_map(|s| parse(&s, Classic).ok()); - self.inner.perturb(terms); // Pass iterator directly - Ok(()) + // Parse incoming strings to Terms… + let terms = expressions + .into_iter() + .filter_map(|s| parse(&s, Classic).ok()); + + // …and let LambdaSoup wrap them into LambdaParticle (recursive = false) + self.inner.add_lambda_expressions(terms); + Ok(()) } fn simulate_for(&mut self, n: usize, log: bool) -> usize { self.inner.simulate_for(n, log) } - fn expressions(&self) -> Vec { - self.inner - .expressions() - .map(|term| term.to_string()) - .collect() - } - fn len(&self) -> usize { self.inner.len() } @@ -156,6 +477,15 @@ impl PySoup { self.inner.collisions() } + /// Return the list of expressions in the soup in Church notation. + fn expressions(&self) -> Vec { + self.inner + .lambda_expressions() + .map(|term| term.to_string()) + .collect() + } + + /// Return the set of unique expressions (each term converted to a string). fn unique_expressions(&self) -> Vec { self.inner .unique_expressions() @@ -164,6 +494,7 @@ impl PySoup { .collect() } + /// Return a (term, count) list giving population counts for each unique term. fn expression_counts(&self) -> Vec<(String, u32)> { self.inner .expression_counts() @@ -172,6 +503,7 @@ impl PySoup { .collect() } + /// Return the Shannon-like entropy of the current population (base‑10 logarithm). fn population_entropy(&self) -> f32 { self.inner.population_entropy() } @@ -187,11 +519,18 @@ pub struct PyBTreeGen { impl PyBTreeGen { #[new] fn new() -> Self { - PyBTreeGen { inner: RustBTreeGen::new() } + PyBTreeGen { + inner: RustBTreeGen::new(), + } } #[staticmethod] - fn from_config(size: u32, freevar_generation_probability: f64, max_free_vars: u32, std: PyStandardization) -> Self { + fn from_config( + size: u32, + freevar_generation_probability: f64, + max_free_vars: u32, + std: PyStandardization, + ) -> Self { let config = config::BTreeGen { size, freevar_generation_probability, @@ -199,7 +538,9 @@ impl PyBTreeGen { standardization: std.into(), seed: ConfigSeed(Some([0; 32])), }; - PyBTreeGen { inner: RustBTreeGen::from_config(&config) } + PyBTreeGen { + inner: RustBTreeGen::from_config(&config), + } } fn generate(&mut self) -> String { @@ -207,7 +548,11 @@ impl PyBTreeGen { } fn generate_n(&mut self, n: usize) -> Vec { - self.inner.generate_n(n).into_iter().map(|t| t.to_string()).collect() + self.inner + .generate_n(n) + .into_iter() + .map(|t| t.to_string()) + .collect() } } @@ -220,7 +565,12 @@ pub struct PyFontanaGen { #[pymethods] impl PyFontanaGen { #[staticmethod] - fn from_config(abs_range: (f64, f64), app_range: (f64, f64), max_depth: u32, max_free_vars: u32) -> Self { + fn from_config( + abs_range: (f64, f64), + app_range: (f64, f64), + max_depth: u32, + max_free_vars: u32, + ) -> Self { let config = config::FontanaGen { abstraction_prob_range: abs_range, application_prob_range: app_range, @@ -228,7 +578,9 @@ impl PyFontanaGen { n_max_free_vars: max_free_vars, seed: ConfigSeed(Some([0; 32])), }; - PyFontanaGen { inner: RustFontanaGen::from_config(&config) } + PyFontanaGen { + inner: RustFontanaGen::from_config(&config), + } } fn generate(&self) -> Option { @@ -247,34 +599,9 @@ fn encode_hex_py(bytes: Vec) -> String { encode_hex(&bytes) } -// --- Experiment Functions --- -// #[pyfunction] -// fn run_look_for_add() -> PyResult<()> { -// async_std::task::block_on(look_for_add()); -// Ok(()) -// } - -// #[pyfunction] -// fn run_entropy_series() -> PyResult<()> { -// async_std::task::block_on(entropy_series()); -// Ok(()) -// } - -// #[pyfunction] -// fn run_entropy_test() -> PyResult<()> { -// async_std::task::block_on(entropy_test()); -// Ok(()) -// } - -// #[pyfunction] -// fn run_sync_entropy_test() -> PyResult<()> { -// sync_entropy_test(); -// Ok(()) -// } - // --- Python Module Initialization --- #[pymodule] -fn alchemy(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { +fn alchemy(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { // Register classes m.add_class::()?; m.add_class::()?; @@ -293,3 +620,4 @@ fn alchemy(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { Ok(()) } + From 7bb481b330ca1e045a79ee78f0573f5b9fe92994 Mon Sep 17 00:00:00 2001 From: jjoseph12 <72823288+jjoseph12@users.noreply.github.com> Date: Thu, 16 Oct 2025 14:19:45 -0700 Subject: [PATCH 08/23] fixed some generator.rs and other issues, check updated_readme --- .DS_Store | Bin 0 -> 6148 bytes README.md | 33 ------ src/Updated_ReadMe.md | 50 ++++++++ src/config.rs | 3 +- src/experiments/kinetics.rs | 9 +- src/experiments/magic_test_function.rs | 90 +-------------- src/experiments/search_by_behavior.rs | 4 +- src/generators.rs | 153 +++++++++++++------------ src/main.rs | 19 ++- 9 files changed, 159 insertions(+), 202 deletions(-) create mode 100644 .DS_Store delete mode 100644 README.md create mode 100644 src/Updated_ReadMe.md diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..7ee4e6bc875973af9673761425ac798ed4ec2a58 GIT binary patch literal 6148 zcmeHK%TB{E5FED^eMzWCj`@O0{6Q#1s24!u#0~nOpaz2akT~YfKky5DA19c#EfhN~ zM}(@~${yF=@p>nU9Ro0f&GZ=P0cf!ZHae`fn2bxQSk3oziN?;6qmK+ZCRkLwwL=w9 z1^$}?^6qwUiaRVZ=bQWU{*JPIGS2cb$7ORkVd;NaV=LyY$$UZ2cNc*-^LWN1UPD%G9h-8xv=D*&;9|u_#29`(K&x&-C(+QydDmil0RE3$;nxpu-vkUiC^K+Qds%p*f!)SK4P)Pu|yig U)MMe0Jv99gurg?+3jC=8-~4Z$c>n+a literal 0 HcmV?d00001 diff --git a/README.md b/README.md deleted file mode 100644 index c6a43e2..0000000 --- a/README.md +++ /dev/null @@ -1,33 +0,0 @@ -A reimplementation of Walter Fontana's Alchemy. Pipe lambda expressions into -`stdin` to start a default simulation. - -Usage: - -`alchemy` - -Build: - -`cargo build` - -Testing: - -`cargo run -- {args}` - -With the binary tree generators from the -[lambda-btree](https://github.com/AgentElement/lambda-btree) crate, you can -run a simple alchemy simulation with the following command. - -`python /path/to/src/fontana_generator.py | cargo run -- {args}` - - -Documentation: - -* Full documentation: `cargo doc --open` -* Help: `cargo run -- --help` - -The documentation for the configuration file is in the `Config` object. - - -# Interactive Dashboard - -Can be found here: https://github.com/mathis-group/Alchemy-Dashboard \ No newline at end of file diff --git a/src/Updated_ReadMe.md b/src/Updated_ReadMe.md new file mode 100644 index 0000000..963fa5e --- /dev/null +++ b/src/Updated_ReadMe.md @@ -0,0 +1,50 @@ +# Modern AlChemy – Current Issues (fontanagen branch) + +##### How to Run +- **Build:** `cargo build` +- **Run default simulation:** `cargo run` +- **Fontana generator demo:** `cargo run -- --config-file /path/to/fontana_config.json` +- **Dump default config:** `cargo run -- --dump-config` +- **Dump default config with CL:** cargo run -- --config-file /tmp/fontana_cfg.json --generate 3 +- **Run experiments:** `cargo run -- --experiment ` (not sure how to run this part) + +##### Currently Resolved + +##### Fontana generator looks at configuration +- `src/generators.rs`: `FontanaGen::from_config` now uses `min_depth`, `max_depth`, and `free_variable_probability`, clamps probability ranges, checks depth bounds, and removed the unused local RNG binding. +- Added a defensive helpers to avoid divide-by-zero (`max_depth` guard), empty ranges when depth is zero, and runaway probabilities (clamped per depth). Generation can now use the configured `n_max_free_vars` safely. +- CLI `--generate` now obeys the active generator in the loaded config, so Fontana samples can be printed without editing source. + +##### Previous issue: + +- `src/generators.rs:202-217`: `min_depth` and `free_prob` are hard-coded to `0`, ignoring `config::FontanaGen.min_depth` and `.free_variable_probability`. (but it seems like in config.rs it matches the same values? do we hard code or use that?) +- `src/generators.rs:197-200`: the local `rng` binding is never used; we instantiate the struct with `ChaCha8Rng::from_seed(seed)` directly, so this variable only triggers warnings. +- `src/generators.rs:197-200`: division by `cfg.max_depth - 1` won't work if `max_depth <= 1`. +- `src/generators.rs:236-279`: `p_abs`/`p_app` can exceed `1.0`, meaning leaf nodes might never be produced before hitting maximum depth; when `depth == 0`, `rng.gen_range(1..=depth)` is an empty range. +- `src/main.rs:156`: `--generate` always uses `BTreeGen`. Need to do for FontanaGen + + +##### Warning cleanup +- Removed unused helper functions and tightened imports in `src/experiments/magic_test_function.rs`; wrapped tests in `#[cfg(test)]` to avoid dev-build noise. +- Added documentation for `config::FontanaGen`, so the `#[warn(missing_docs)]` lint is satisfied. +- `cargo build` and `cargo test` now run warning-free. + +##### Remaining Known Issues + +##### Postfix standardization unimplemented +- `src/generators.rs:134-136`: `postfix_standardize` calls `unimplemented!`. +- Any config selecting `Standardization::Postfix` crashes. +- Need to add the transformation or disable the option in configs/CLI until ready. + +##### Collision metrics mislabelled +- `src/lambda/recursive.rs:227-232`: tuples are pushed as `(expr, size, reductions)` but collected as reductions → `t.1`, sizes → `t.2`, swapping the data. +- **Does this imapct antyhing? does it affect the analytics and experiment outputs report incorrect reduction counts vs sizes. + +##### Jacard metric incorrect +- `src/analysis.rs:57-68`: calculates `intersection / (|A| + |B|)` +- should be divded by A U B + +##### Documentation +- `scripts/discovery.sh:15` (and similar files): `cd ~/cwd/functional-supercollider`, which doesn’t exist here. + + diff --git a/src/config.rs b/src/config.rs index af324f3..318580c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -109,6 +109,7 @@ pub struct BTreeGen { #[warn(missing_docs)] #[derive(Serialize, Deserialize, Debug)] +/// Generator-specific configuration derived from Walter Fontana's original scheme. pub struct FontanaGen { /// The seed for the lambda expression generator. If set to `None`, then a seed is chosen /// randomly. Default: `None` @@ -149,7 +150,6 @@ impl GenConfig for FontanaGen { } } - impl Reactor { /// Produce a new `ReactorConfig` struct with default values. pub fn new() -> Self { @@ -189,7 +189,6 @@ impl GenConfig for BTreeGen { } } - impl Config { /// Create a config object from a string pub fn from_config_str(s: &str) -> Config { diff --git a/src/experiments/kinetics.rs b/src/experiments/kinetics.rs index d4a4efe..89d9575 100644 --- a/src/experiments/kinetics.rs +++ b/src/experiments/kinetics.rs @@ -131,8 +131,13 @@ pub fn kinetic_succ_experiment() { let mut futures = FuturesUnordered::new(); let sample_size = 5000; - let good_fracs = [0.0, 0.0002, 0.0004, 0.0008, 0.0016, 0.0032, 0.0064, 0.0128, 0.0256, 0.0512, 0.1024]; - let test_fracs = [0.0, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.50, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80]; + let good_fracs = [ + 0.0, 0.0002, 0.0004, 0.0008, 0.0016, 0.0032, 0.0064, 0.0128, 0.0256, 0.0512, 0.1024, + ]; + let test_fracs = [ + 0.0, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.50, 0.55, 0.60, 0.65, 0.70, + 0.75, 0.80, + ]; for (i, good_frac) in good_fracs.iter().enumerate() { for (j, test_frac) in test_fracs.iter().enumerate() { diff --git a/src/experiments/magic_test_function.rs b/src/experiments/magic_test_function.rs index 251cac3..f624de6 100644 --- a/src/experiments/magic_test_function.rs +++ b/src/experiments/magic_test_function.rs @@ -4,10 +4,7 @@ use lambda_calculus::reduction::Order::HAP; use lambda_calculus::{ abs, app, combinators::{I, K, S}, - data::{ - boolean::{self, and}, - num::church::{add, eq, succ}, - }, + data::num::church::{add, eq, succ}, parse, term::Notation::Classic, IntoChurchNum, @@ -17,7 +14,6 @@ use rand::random; use crate::{ config::{self, ConfigSeed}, - generators::BTreeGen, lambda::recursive::{has_two_args, is_truthy, uses_both_arguments, LambdaSoup}, utils::{dump_series_to_file, read_inputs}, }; @@ -46,31 +42,10 @@ pub fn addtwo() -> Term { comp } -// Triplet permutation combinators -fn p123() -> Term { - abs!(3, app!(Var(1), Var(2), Var(3))) -} - fn p132() -> Term { abs!(3, app!(Var(1), Var(3), Var(2))) } -fn p213() -> Term { - abs!(3, app!(Var(2), Var(1), Var(3))) -} - -fn p231() -> Term { - abs!(3, app!(Var(2), Var(3), Var(1))) -} - -fn p312() -> Term { - abs!(3, app!(Var(3), Var(1), Var(2))) -} - -fn p321() -> Term { - abs!(3, app!(Var(3), Var(2), Var(1))) -} - pub(super) fn test_add(a: usize, b: usize) -> Term { let mut test = parse(r"\eq. \a. \b. \ab. \f. (eq (f a b) ab)", Classic).unwrap(); test = app!( @@ -85,23 +60,6 @@ pub(super) fn test_add(a: usize, b: usize) -> Term { test } -fn test_add_seq(pairs: impl Iterator) -> Term { - let mut test = parse(r"\f. \a. \b. a", Classic).unwrap(); - for (u, v) in pairs { - let gut = parse( - r"\and. \test. \testadd. \f. and (test f) (testadd f)", - Classic, - ) - .unwrap(); - test = app!(gut, and(), test, test_add(u, v)); - } - test.reduce(lambda_calculus::HAP, 0); - let mut comp = app!(test.clone(), add()); - comp.reduce(lambda_calculus::HAP, 0); - assert!(comp.is_isomorphic_to(&boolean::tru())); - test -} - pub(super) fn test_succ(a: usize) -> Term { let mut test = parse(r"\eq. \a. \asucc. \f. (eq (f a) asucc)", Classic).unwrap(); test = app!(test, eq(), a.into_church(), (a + 1).into_church()); @@ -110,23 +68,6 @@ pub(super) fn test_succ(a: usize) -> Term { test } -pub(super) fn test_succ_seq(nums: impl Iterator) -> Term { - let mut test = parse(r"\f. \a. \b. a", Classic).unwrap(); - for u in nums { - let gut = parse( - r"\and. \test. \testscc. \f. and (test f) (testscc f)", - Classic, - ) - .unwrap(); - test = app!(gut, and(), test, test_succ(u)); - } - test.reduce(lambda_calculus::HAP, 0); - let mut comp = app!(test.clone(), succ()); - comp.reduce(lambda_calculus::HAP, 0); - assert!(comp.is_isomorphic_to(&boolean::tru())); - test -} - pub fn test_addtwo(a: usize) -> Term { let mut test = parse(r"\eq. \a. \asucc. \f. (eq (f a) asucc)", Classic).unwrap(); test = app!(test, eq(), a.into_church(), (a + 2).into_church()); @@ -135,28 +76,6 @@ pub fn test_addtwo(a: usize) -> Term { test } -fn generate_sample_for_addsearch(seed: ConfigSeed) -> Vec { - let mut sample = vec![S(); 200]; - sample.append(&mut vec![K(); 100]); - sample.append(&mut vec![I(); 100]); - for size in 5..12 { - let mut gen = BTreeGen::from_config(&config::BTreeGen { - size, - freevar_generation_probability: 0.2, - standardization: crate::generators::Standardization::Prefix, - n_max_free_vars: 6, - seed, - }); - let n_samples = match size { - 5..=7 => 800, - 8..=10 => 400, - _ => 200, - }; - sample.append(&mut gen.generate_n(n_samples)) - } - sample -} - pub(super) fn asymmetric_skip_sample() -> Vec { let mut sample = vec![]; sample.append(&mut vec![S(); 10]); @@ -367,12 +286,11 @@ pub fn succ_search_with_test() { } } +#[cfg(test)] mod tests { - use lambda_calculus::{ - app, data::boolean::tru, data::num::church::add, reduction::Order::HNO, IntoChurchNum, - }; + use lambda_calculus::{app, data::boolean::tru, data::num::church::add, reduction::Order::HNO}; - use crate::experiments::magic_test_function::{addtwo, test_addtwo, test_succ}; + use crate::experiments::magic_test_function::{addtwo, test_addtwo}; use super::test_add; diff --git a/src/experiments/search_by_behavior.rs b/src/experiments/search_by_behavior.rs index 9b26b0c..0d8018d 100644 --- a/src/experiments/search_by_behavior.rs +++ b/src/experiments/search_by_behavior.rs @@ -124,7 +124,7 @@ pub fn look_for_xorset() { i, run_length, polling_interval, - xorset_test + xorset_test, ))); } @@ -153,7 +153,7 @@ pub fn look_for_not_xorset() { i, run_length, polling_interval, - not_xorset_test + not_xorset_test, ))); } diff --git a/src/generators.rs b/src/generators.rs index 13437d1..7cf02fb 100644 --- a/src/generators.rs +++ b/src/generators.rs @@ -166,18 +166,28 @@ pub struct FontanaGen { impl FontanaGen { pub fn new( min_depth: u32, - max_depth: u32, - abs_prob: (f32, f32), - app_prob: (f32, f32), - free_prob: f32, - max_vars: u32, + mut max_depth: u32, + mut abs_prob: (f32, f32), + mut app_prob: (f32, f32), + mut free_prob: f32, + mut max_vars: u32, seed: [u8; 32], ) -> FontanaGen { - let abs_incr = (abs_prob.1 - abs_prob.0) / ((max_depth - 1) as f32); - let app_incr = (app_prob.1 - app_prob.0) / ((max_depth - 1) as f32); + // Sanitise configuration so generation never panics. + max_depth = max_depth.max(1); + max_vars = max_vars.max(1); + free_prob = free_prob.clamp(0.0, 1.0); + abs_prob.0 = abs_prob.0.clamp(0.0, 1.0); + abs_prob.1 = abs_prob.1.clamp(0.0, 1.0); + app_prob.0 = app_prob.0.clamp(0.0, 1.0); + app_prob.1 = app_prob.1.clamp(0.0, 1.0); + + let steps = (max_depth - 1).max(1); + let abs_incr = (abs_prob.1 - abs_prob.0) / (steps as f32); + let app_incr = (app_prob.1 - app_prob.0) / (steps as f32); FontanaGen { - min_depth, + min_depth: min_depth.min(max_depth.saturating_sub(1)), max_depth, abs_prob, app_prob, @@ -192,32 +202,25 @@ impl FontanaGen { pub fn from_config(cfg: &config::FontanaGen) -> FontanaGen { let seed = cfg.seed.get(); - let rng = ChaCha8Rng::from_seed(seed); - - let abs_incr: f32 = ((cfg.abstraction_prob_range.1 - cfg.abstraction_prob_range.0) - / ((cfg.max_depth - 1) as f64)) as f32; - let app_incr: f32 = ((cfg.application_prob_range.1 - cfg.application_prob_range.0) - / ((cfg.max_depth - 1) as f64)) as f32; - - FontanaGen { - min_depth: 0, - max_depth: cfg.max_depth, - - abs_prob: (cfg.abstraction_prob_range.0 as f32, cfg.abstraction_prob_range.1 as f32), - app_prob: (cfg.application_prob_range.0 as f32, cfg.application_prob_range.1 as f32), - - abs_incr, - app_incr, - free_prob: 0.0, - max_vars: cfg.n_max_free_vars, - + FontanaGen::new( + cfg.min_depth, + cfg.max_depth, + ( + cfg.abstraction_prob_range.0 as f32, + cfg.abstraction_prob_range.1 as f32, + ), + ( + cfg.application_prob_range.0 as f32, + cfg.application_prob_range.1 as f32, + ), + cfg.free_variable_probability as f32, + cfg.n_max_free_vars, seed, - rng: ChaCha8Rng::from_seed(seed), - } + ) } - pub fn generate(&mut self) -> Term{ + pub fn generate(&mut self) -> Term { self.rand_lambda(0, self.abs_prob.0, self.app_prob.0) } @@ -234,48 +237,56 @@ impl FontanaGen { } pub fn rand_lambda(&mut self, depth: u32, p_abs: f32, p_app: f32) -> Term { - if depth >= self.max_depth { // over max depth generating leaf - let var = if self.rng.gen_bool(self.free_prob as f64) || depth == 0 { - depth + self.rng.gen_range(1..=self.max_vars) - } else { - self.rng.gen_range(1..=depth) - }; - return Term::Var(var as usize); - } else if depth < self.min_depth { // under min length will not generate leaf - let coin = self.rng.gen_bool(0.5); - if coin { - let n_abs = p_abs + self.abs_incr; - let n_app = p_app + self.app_incr; - return Term::Abs(Box::new(self.rand_lambda(depth + 1, n_abs, n_app))); - } else { - let n_abs = p_abs + self.abs_incr; - let n_app = p_app + self.app_incr; - return Term::App(Box::new(( - self.rand_lambda(depth+1, n_abs, n_app), - self.rand_lambda(depth+1, n_abs, n_app), - ))); - }; - } else { - let coin: f32 = self.rng.gen(); - if coin <= p_abs { - let n_abs = p_abs + self.abs_incr; - let n_app = p_app + self.app_incr; - return Term::Abs(Box::new(self.rand_lambda(depth + 1, n_abs, n_app))); - } else if coin <= p_abs + p_app { - let n_abs = p_abs + self.abs_incr; - let n_app = p_app + self.app_incr; - return Term::App(Box::new(( - self.rand_lambda(depth+1, n_abs, n_app), - self.rand_lambda(depth+1, n_abs, n_app), - ))); - } else { - let var = if self.rng.gen_bool(self.free_prob as f64) || depth == 0 { - depth + self.rng.gen_range(1..=self.max_vars) - } else { - self.rng.gen_range(1..=depth) - }; - return Term::Var(var as usize); + let (p_abs_eff, p_app_eff) = Self::clamp_probabilities(p_abs, p_app); + + if depth >= self.max_depth { + return self.sample_variable(depth); + } + + let next_abs = p_abs + self.abs_incr; + let next_app = p_app + self.app_incr; + + if depth < self.min_depth { + if self.rng.gen_bool(0.5) { + return Term::Abs(Box::new(self.rand_lambda(depth + 1, next_abs, next_app))); } + return Term::App(Box::new(( + self.rand_lambda(depth + 1, next_abs, next_app), + self.rand_lambda(depth + 1, next_abs, next_app), + ))); + } + + let coin: f32 = self.rng.gen(); + if coin <= p_abs_eff { + return Term::Abs(Box::new(self.rand_lambda(depth + 1, next_abs, next_app))); + } + if coin <= p_abs_eff + p_app_eff { + return Term::App(Box::new(( + self.rand_lambda(depth + 1, next_abs, next_app), + self.rand_lambda(depth + 1, next_abs, next_app), + ))); } + + self.sample_variable(depth) + } + + fn clamp_probabilities(p_abs: f32, p_app: f32) -> (f32, f32) { + let abs = p_abs.clamp(0.0, 1.0); + let remaining = 1.0 - abs; + let app = p_app.clamp(0.0, remaining); + (abs, app) + } + + fn sample_variable(&mut self, depth: u32) -> Term { + let free_choice = self.rng.gen_bool(self.free_prob as f64) || depth == 0; + let max_vars = self.max_vars.max(1); + let value = if free_choice { + let offset = self.rng.gen_range(1..=max_vars); + depth.saturating_add(offset) as usize + } else { + let upper = depth.max(1); + self.rng.gen_range(1..=upper) as usize + }; + Term::Var(value) } } diff --git a/src/main.rs b/src/main.rs index 3581afe..d985097 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,6 @@ use experiments::{ discovery, distribution, entropy, kinetics, magic_test_function, search_by_behavior, }; use generators::BTreeGen; -use lambda_calculus::Term; use std::fs::{read_to_string, File}; use std::io::Write; @@ -126,8 +125,6 @@ pub fn generate_expressions_and_seed_soup(cfg: &config::Config) -> lambda::recur config::Generator::Fontana(gen_cfg) => { let mut gen = generators::FontanaGen::from_config(gen_cfg); gen.generate_n(cfg.sample_size) - - } }; let mut soup = lambda::recursive::LambdaSoup::from_config(&cfg.reactor_config); @@ -153,9 +150,19 @@ fn main() -> std::io::Result<()> { } if let Some(n) = cli.generate { - let mut gen = BTreeGen::new(); - for _ in 0..n { - println!("{:?}", gen.generate()) + match &config.generator_config { + config::Generator::BTree(gen_cfg) => { + let mut gen = BTreeGen::from_config(gen_cfg); + for _ in 0..n { + println!("{:?}", gen.generate()) + } + } + config::Generator::Fontana(gen_cfg) => { + let mut gen = generators::FontanaGen::from_config(gen_cfg); + for _ in 0..n { + println!("{:?}", gen.generate()) + } + } } return Ok(()); } From 3881abc96cfae85afd774d1c687cd85ab7709a0e Mon Sep 17 00:00:00 2001 From: Joel Joseph <72823288+jjoseph12@users.noreply.github.com> Date: Thu, 16 Oct 2025 14:21:37 -0700 Subject: [PATCH 09/23] Update README with current and resolved issues Added documentation for current issues, resolved problems, and remaining known issues in the README. --- README.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..963fa5e --- /dev/null +++ b/README.md @@ -0,0 +1,50 @@ +# Modern AlChemy – Current Issues (fontanagen branch) + +##### How to Run +- **Build:** `cargo build` +- **Run default simulation:** `cargo run` +- **Fontana generator demo:** `cargo run -- --config-file /path/to/fontana_config.json` +- **Dump default config:** `cargo run -- --dump-config` +- **Dump default config with CL:** cargo run -- --config-file /tmp/fontana_cfg.json --generate 3 +- **Run experiments:** `cargo run -- --experiment ` (not sure how to run this part) + +##### Currently Resolved + +##### Fontana generator looks at configuration +- `src/generators.rs`: `FontanaGen::from_config` now uses `min_depth`, `max_depth`, and `free_variable_probability`, clamps probability ranges, checks depth bounds, and removed the unused local RNG binding. +- Added a defensive helpers to avoid divide-by-zero (`max_depth` guard), empty ranges when depth is zero, and runaway probabilities (clamped per depth). Generation can now use the configured `n_max_free_vars` safely. +- CLI `--generate` now obeys the active generator in the loaded config, so Fontana samples can be printed without editing source. + +##### Previous issue: + +- `src/generators.rs:202-217`: `min_depth` and `free_prob` are hard-coded to `0`, ignoring `config::FontanaGen.min_depth` and `.free_variable_probability`. (but it seems like in config.rs it matches the same values? do we hard code or use that?) +- `src/generators.rs:197-200`: the local `rng` binding is never used; we instantiate the struct with `ChaCha8Rng::from_seed(seed)` directly, so this variable only triggers warnings. +- `src/generators.rs:197-200`: division by `cfg.max_depth - 1` won't work if `max_depth <= 1`. +- `src/generators.rs:236-279`: `p_abs`/`p_app` can exceed `1.0`, meaning leaf nodes might never be produced before hitting maximum depth; when `depth == 0`, `rng.gen_range(1..=depth)` is an empty range. +- `src/main.rs:156`: `--generate` always uses `BTreeGen`. Need to do for FontanaGen + + +##### Warning cleanup +- Removed unused helper functions and tightened imports in `src/experiments/magic_test_function.rs`; wrapped tests in `#[cfg(test)]` to avoid dev-build noise. +- Added documentation for `config::FontanaGen`, so the `#[warn(missing_docs)]` lint is satisfied. +- `cargo build` and `cargo test` now run warning-free. + +##### Remaining Known Issues + +##### Postfix standardization unimplemented +- `src/generators.rs:134-136`: `postfix_standardize` calls `unimplemented!`. +- Any config selecting `Standardization::Postfix` crashes. +- Need to add the transformation or disable the option in configs/CLI until ready. + +##### Collision metrics mislabelled +- `src/lambda/recursive.rs:227-232`: tuples are pushed as `(expr, size, reductions)` but collected as reductions → `t.1`, sizes → `t.2`, swapping the data. +- **Does this imapct antyhing? does it affect the analytics and experiment outputs report incorrect reduction counts vs sizes. + +##### Jacard metric incorrect +- `src/analysis.rs:57-68`: calculates `intersection / (|A| + |B|)` +- should be divded by A U B + +##### Documentation +- `scripts/discovery.sh:15` (and similar files): `cd ~/cwd/functional-supercollider`, which doesn’t exist here. + + From 6c4b984e0ffc83705e6139fc12f094ab5be37c83 Mon Sep 17 00:00:00 2001 From: "ridham.patel" Date: Thu, 16 Oct 2025 17:06:12 -0700 Subject: [PATCH 10/23] refactor(pyo3): move Python bindings to src/python.rs and register from lib.rs --- src/lib.rs | 605 +------------------------------------------------- src/python.rs | 219 ++++++++++++++++++ 2 files changed, 226 insertions(+), 598 deletions(-) create mode 100644 src/python.rs diff --git a/src/lib.rs b/src/lib.rs index 9045cfd..35b1f04 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,310 +1,7 @@ -// use pyo3::prelude::*; -// use pyo3::wrap_pyfunction; -// use serde::{Deserialize, Serialize}; - - -// // --- Module Imports --- -// mod config; -// mod supercollider; -// mod experiments; -// mod generators; -// mod utils; -// mod analysis; -// mod lambda; - - -// use lambda_calculus::{parse, term::Notation::Classic, Term}; -// use std::io::{self, BufRead}; - -// pub fn read_inputs() -> impl Iterator { -// io::stdin() -// .lock() -// .lines() -// .filter_map(|line| line.ok()) -// .filter_map(|line| parse(&line, Classic).ok()) -// } - - -// // --- Exposing Core Configurations --- -// use crate::config::{Reactor as RustReactor, ConfigSeed}; -// //use crate::supercollider::Soup; -// use crate::generators::{BTreeGen as RustBTreeGen, FontanaGen as RustFontanaGen, Standardization as RustStandardization}; -// use crate::utils::{decode_hex, encode_hex}; -// //use crate::experiments::{look_for_add, entropy_series, entropy_test, sync_entropy_test}; -// //use crate::lambda::lambda::LambdaCollisionError; - -// use crate::supercollider::Soup as GenericSoup; -// use crate::lambda::recursive::{ -// LambdaParticle, AlchemyCollider, LambdaCollisionOk, LambdaCollisionError, -// }; -// type RustSoup = GenericSoup; - -// // --- Error Handling Wrappers --- -// #[pyclass] -// #[derive(Debug, Clone)] -// pub struct PyReactionError { -// kind: LambdaCollisionError, -// } - -// #[derive(Debug, Clone)] -// pub enum ReactionErrorKind { -// ExceedsReductionLimit, -// NotEnoughExpressions, -// IsIdentity, -// IsParent, -// HasFreeVariables, -// ExceedsDepthLimit, -// } - -// impl From for PyReactionError { -// fn from(error: LambdaCollisionError) -> Self { -// let kind = match error { -// LambdaCollisionError::ExceedsReductionLimit => ReactionErrorKind::ExceedsReductionLimit, -// LambdaCollisionError::NotEnoughExpressions => ReactionErrorKind::NotEnoughExpressions, -// LambdaCollisionError::IsIdentity => ReactionErrorKind::IsIdentity, -// LambdaCollisionError::IsParent => ReactionErrorKind::IsParent, -// LambdaCollisionError::HasFreeVariables => ReactionErrorKind::HasFreeVariables, -// LambdaCollisionError::ExceedsDepthLimit => ReactionErrorKind::ExceedsDepthLimit, -// }; -// PyReactionError { kind } -// } -// } - -// // --- Reactor Wrapper --- -// #[pyclass] -// pub struct PyReactor { -// inner: RustReactor, -// } - -// #[pymethods] -// impl PyReactor { -// #[new] -// fn new() -> Self { -// PyReactor { -// inner: RustReactor::new(), -// } -// } -// } - -// // --- Standardization Wrapper --- -// #[pyclass] -// #[derive(Debug, Clone, Serialize, Deserialize)] -// pub struct PyStandardization { -// standardization: RustStandardization, -// } - -// #[pymethods] -// impl PyStandardization { -// #[new] -// fn new(kind: &str) -> PyResult { -// let standardization = match kind { -// "prefix" => RustStandardization::Prefix, -// "postfix" => RustStandardization::Postfix, -// "none" => RustStandardization::None, -// _ => return Err(pyo3::exceptions::PyValueError::new_err("Invalid standardization type")) -// }; -// Ok(PyStandardization { standardization }) -// } -// } - -// impl From for RustStandardization { -// fn from(py_std: PyStandardization) -> Self { -// py_std.standardization -// } -// } - -// // --- Soup Wrapper --- -// #[pyclass] -// pub struct PySoup { -// inner: Soup, -// } - -// #[pymethods] -// impl PySoup { -// #[new] -// fn new() -> Self { -// PySoup { inner: Soup::new() } -// } - -// #[staticmethod] -// fn from_config(cfg: &PyReactor) -> Self { -// PySoup { inner: Soup::from_config(&cfg.inner) } -// } - -// fn set_limit(&mut self, limit: usize) { -// self.inner.set_limit(limit); -// } - -// fn perturb(&mut self, expressions: Vec) -> PyResult<()> { -// let terms = expressions -// .into_iter() -// .filter_map(|s| parse(&s, Classic).ok()); -// self.inner.perturb(terms); // Pass iterator directly -// Ok(()) -// } - -// fn simulate_for(&mut self, n: usize, log: bool) -> usize { -// self.inner.simulate_for(n, log) -// } - -// fn expressions(&self) -> Vec { -// self.inner -// .expressions() -// .map(|term| term.to_string()) -// .collect() -// } - -// fn len(&self) -> usize { -// self.inner.len() -// } - -// fn collisions(&self) -> usize { -// self.inner.collisions() -// } - -// fn unique_expressions(&self) -> Vec { -// self.inner -// .unique_expressions() -// .into_iter() -// .map(|term| term.to_string()) -// .collect() -// } - -// fn expression_counts(&self) -> Vec<(String, u32)> { -// self.inner -// .expression_counts() -// .into_iter() -// .map(|(term, count)| (term.to_string(), count)) -// .collect() -// } - -// fn population_entropy(&self) -> f32 { -// self.inner.population_entropy() -// } -// } - -// // --- BTreeGen Wrapper --- -// #[pyclass] -// pub struct PyBTreeGen { -// inner: RustBTreeGen, -// } - -// #[pymethods] -// impl PyBTreeGen { -// #[new] -// fn new() -> Self { -// PyBTreeGen { inner: RustBTreeGen::new() } -// } - -// #[staticmethod] -// fn from_config(size: u32, freevar_generation_probability: f64, max_free_vars: u32, std: PyStandardization) -> Self { -// let config = config::BTreeGen { -// size, -// freevar_generation_probability, -// n_max_free_vars: max_free_vars, -// standardization: std.into(), -// seed: ConfigSeed(Some([0; 32])), -// }; -// PyBTreeGen { inner: RustBTreeGen::from_config(&config) } -// } - -// fn generate(&mut self) -> String { -// self.inner.generate().to_string() -// } - -// fn generate_n(&mut self, n: usize) -> Vec { -// self.inner.generate_n(n).into_iter().map(|t| t.to_string()).collect() -// } -// } - -// // --- FontanaGen Wrapper --- -// #[pyclass] -// pub struct PyFontanaGen { -// inner: RustFontanaGen, -// } - -// #[pymethods] -// impl PyFontanaGen { -// #[staticmethod] -// fn from_config(abs_range: (f64, f64), app_range: (f64, f64), max_depth: u32, max_free_vars: u32) -> Self { -// let config = config::FontanaGen { -// abstraction_prob_range: abs_range, -// application_prob_range: app_range, -// max_depth, -// n_max_free_vars: max_free_vars, -// seed: ConfigSeed(Some([0; 32])), -// }; -// PyFontanaGen { inner: RustFontanaGen::from_config(&config) } -// } - -// fn generate(&self) -> Option { -// self.inner.generate().map(|term| term.to_string()) -// } -// } - -// // --- Utilities --- -// #[pyfunction] -// fn decode_hex_py(hex_string: &str) -> PyResult> { -// decode_hex(hex_string).map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string())) -// } - -// #[pyfunction] -// fn encode_hex_py(bytes: Vec) -> String { -// encode_hex(&bytes) -// } - -// // --- Experiment Functions --- -// // #[pyfunction] -// // fn run_look_for_add() -> PyResult<()> { -// // async_std::task::block_on(look_for_add()); -// // Ok(()) -// // } - -// // #[pyfunction] -// // fn run_entropy_series() -> PyResult<()> { -// // async_std::task::block_on(entropy_series()); -// // Ok(()) -// // } - -// // #[pyfunction] -// // fn run_entropy_test() -> PyResult<()> { -// // async_std::task::block_on(entropy_test()); -// // Ok(()) -// // } - -// // #[pyfunction] -// // fn run_sync_entropy_test() -> PyResult<()> { -// // sync_entropy_test(); -// // Ok(()) -// // } - -// // --- Python Module Initialization --- -// #[pymodule] -// fn alchemy(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { -// // Register classes -// m.add_class::()?; -// m.add_class::()?; -// m.add_class::()?; -// m.add_class::()?; -// m.add_class::()?; -// m.add_class::()?; - -// // Register functions -// m.add_function(wrap_pyfunction!(decode_hex_py, m)?)?; -// m.add_function(wrap_pyfunction!(encode_hex_py, m)?)?; -// // m.add_function(wrap_pyfunction!(run_look_for_add, m)?)?; -// // m.add_function(wrap_pyfunction!(run_entropy_series, m)?)?; -// // m.add_function(wrap_pyfunction!(run_entropy_test, m)?)?; -// // m.add_function(wrap_pyfunction!(run_sync_entropy_test, m)?)?; - -// Ok(()) -// } - +// src/lib.rs use pyo3::prelude::*; -use pyo3::wrap_pyfunction; -use serde::{Deserialize, Serialize}; -// --- Module Imports --- +// Re-export your Rust modules for the CLI and for external users pub mod config; pub mod experiments; pub mod generators; @@ -313,7 +10,10 @@ pub mod analysis; pub mod lambda; pub mod supercollider; +// New Python wrapper module +mod python; +// If you still need this for the CLI, keep it here: use lambda_calculus::{parse, term::Notation::Classic, Term}; use std::io::{self, BufRead}; @@ -325,299 +25,8 @@ pub fn read_inputs() -> impl Iterator { .filter_map(|line| parse(&line, Classic).ok()) } -// --- Exposing Core Configurations --- -use crate::config::{Reactor as RustReactor, ConfigSeed}; -use crate::generators::{ - BTreeGen as RustBTreeGen, FontanaGen as RustFontanaGen, Standardization as RustStandardization, -}; -use crate::utils::{decode_hex, encode_hex}; -// use crate::experiments::{look_for_add, entropy_series, entropy_test, sync_entropy_test}; - -// Bring in the concrete lambda types so we can fully specify Soup. -use crate::lambda::recursive::{ - AlchemyCollider, LambdaCollisionError, LambdaCollisionOk, LambdaParticle, -}; - -// Create a concrete alias for the generic Soup. Without this, the compiler -// complains about missing generic parameters and ambiguous new()/from_config() impls. -use crate::supercollider::Soup as GenericSoup; -type RustSoup = - GenericSoup; - -// --- Error Handling Wrappers --- -#[pyclass] -#[derive(Debug, Clone)] -pub struct PyReactionError { - // Store the kind you map to below rather than LambdaCollisionError itself. - kind: ReactionErrorKind, -} - -#[derive(Debug, Clone)] -pub enum ReactionErrorKind { - ExceedsReductionLimit, - NotEnoughExpressions, - IsIdentity, - IsParent, - HasFreeVariables, - ExceedsDepthLimit, - RecursiveArgument, - BadArgument, -} - -// Map the recursive LambdaCollisionError into your public PyReactionError. -impl From for PyReactionError { - fn from(error: LambdaCollisionError) -> Self { - let kind = match error { - LambdaCollisionError::ExceedsReductionLimit => { - ReactionErrorKind::ExceedsReductionLimit - } - LambdaCollisionError::NotEnoughExpressions => { - ReactionErrorKind::NotEnoughExpressions - } - LambdaCollisionError::IsIdentity => ReactionErrorKind::IsIdentity, - LambdaCollisionError::IsParent => ReactionErrorKind::IsParent, - LambdaCollisionError::HasFreeVariables => ReactionErrorKind::HasFreeVariables, - LambdaCollisionError::ExceedsDepthLimit => ReactionErrorKind::ExceedsDepthLimit, - LambdaCollisionError::RecursiveArgument => ReactionErrorKind::RecursiveArgument, - LambdaCollisionError::BadArgument => ReactionErrorKind::BadArgument, - }; - PyReactionError { kind } - } -} - -// --- Reactor Wrapper --- -#[pyclass] -pub struct PyReactor { - inner: RustReactor, -} - -#[pymethods] -impl PyReactor { - #[new] - fn new() -> Self { - PyReactor { - inner: RustReactor::new(), - } - } -} - -// --- Standardization Wrapper --- -#[pyclass] -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct PyStandardization { - standardization: RustStandardization, -} - -#[pymethods] -impl PyStandardization { - #[new] - fn new(kind: &str) -> PyResult { - let standardization = match kind { - "prefix" => RustStandardization::Prefix, - "postfix" => RustStandardization::Postfix, - "none" => RustStandardization::None, - _ => { - return Err(pyo3::exceptions::PyValueError::new_err( - "Invalid standardization type", - )) - } - }; - Ok(PyStandardization { standardization }) - } -} - -impl From for RustStandardization { - fn from(py_std: PyStandardization) -> Self { - py_std.standardization - } -} - -// --- Soup Wrapper --- -#[pyclass] -pub struct PySoup { - inner: RustSoup, -} - -#[pymethods] -impl PySoup { - #[new] - fn new() -> Self { - PySoup { - inner: RustSoup::new(), - } - } - - #[staticmethod] - fn from_config(cfg: &PyReactor) -> Self { - PySoup { - inner: RustSoup::from_config(&cfg.inner), - } - } - - fn perturb(&mut self, expressions: Vec) -> PyResult<()> { - // Parse incoming strings to Terms… - let terms = expressions - .into_iter() - .filter_map(|s| parse(&s, Classic).ok()); - - // …and let LambdaSoup wrap them into LambdaParticle (recursive = false) - self.inner.add_lambda_expressions(terms); - Ok(()) - } - - fn simulate_for(&mut self, n: usize, log: bool) -> usize { - self.inner.simulate_for(n, log) - } - - fn len(&self) -> usize { - self.inner.len() - } - - fn collisions(&self) -> usize { - self.inner.collisions() - } - - /// Return the list of expressions in the soup in Church notation. - fn expressions(&self) -> Vec { - self.inner - .lambda_expressions() - .map(|term| term.to_string()) - .collect() - } - - /// Return the set of unique expressions (each term converted to a string). - fn unique_expressions(&self) -> Vec { - self.inner - .unique_expressions() - .into_iter() - .map(|term| term.to_string()) - .collect() - } - - /// Return a (term, count) list giving population counts for each unique term. - fn expression_counts(&self) -> Vec<(String, u32)> { - self.inner - .expression_counts() - .into_iter() - .map(|(term, count)| (term.to_string(), count)) - .collect() - } - - /// Return the Shannon-like entropy of the current population (base‑10 logarithm). - fn population_entropy(&self) -> f32 { - self.inner.population_entropy() - } -} - -// --- BTreeGen Wrapper --- -#[pyclass] -pub struct PyBTreeGen { - inner: RustBTreeGen, -} - -#[pymethods] -impl PyBTreeGen { - #[new] - fn new() -> Self { - PyBTreeGen { - inner: RustBTreeGen::new(), - } - } - - #[staticmethod] - fn from_config( - size: u32, - freevar_generation_probability: f64, - max_free_vars: u32, - std: PyStandardization, - ) -> Self { - let config = config::BTreeGen { - size, - freevar_generation_probability, - n_max_free_vars: max_free_vars, - standardization: std.into(), - seed: ConfigSeed(Some([0; 32])), - }; - PyBTreeGen { - inner: RustBTreeGen::from_config(&config), - } - } - - fn generate(&mut self) -> String { - self.inner.generate().to_string() - } - - fn generate_n(&mut self, n: usize) -> Vec { - self.inner - .generate_n(n) - .into_iter() - .map(|t| t.to_string()) - .collect() - } -} - -// --- FontanaGen Wrapper --- -#[pyclass] -pub struct PyFontanaGen { - inner: RustFontanaGen, -} - -#[pymethods] -impl PyFontanaGen { - #[staticmethod] - fn from_config( - abs_range: (f64, f64), - app_range: (f64, f64), - max_depth: u32, - max_free_vars: u32, - ) -> Self { - let config = config::FontanaGen { - abstraction_prob_range: abs_range, - application_prob_range: app_range, - max_depth, - n_max_free_vars: max_free_vars, - seed: ConfigSeed(Some([0; 32])), - }; - PyFontanaGen { - inner: RustFontanaGen::from_config(&config), - } - } - - fn generate(&self) -> Option { - self.inner.generate().map(|term| term.to_string()) - } -} - -// --- Utilities --- -#[pyfunction] -fn decode_hex_py(hex_string: &str) -> PyResult> { - decode_hex(hex_string).map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string())) -} - -#[pyfunction] -fn encode_hex_py(bytes: Vec) -> String { - encode_hex(&bytes) -} - -// --- Python Module Initialization --- +// Python module entry point stays tiny and delegates to python::register #[pymodule] fn alchemy(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { - // Register classes - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - - // Register functions - m.add_function(wrap_pyfunction!(decode_hex_py, m)?)?; - m.add_function(wrap_pyfunction!(encode_hex_py, m)?)?; - // m.add_function(wrap_pyfunction!(run_look_for_add, m)?)?; - // m.add_function(wrap_pyfunction!(run_entropy_series, m)?)?; - // m.add_function(wrap_pyfunction!(run_entropy_test, m)?)?; - // m.add_function(wrap_pyfunction!(run_sync_entropy_test, m)?)?; - - Ok(()) + python::register(m) } - diff --git a/src/python.rs b/src/python.rs new file mode 100644 index 0000000..9ec5119 --- /dev/null +++ b/src/python.rs @@ -0,0 +1,219 @@ +// src/python.rs +use pyo3::prelude::*; +use pyo3::wrap_pyfunction; +use serde::{Deserialize, Serialize}; + +use lambda_calculus::{parse, term::Notation::Classic, Term}; + +use crate::config::{self, ConfigSeed, Reactor as RustReactor}; +use crate::generators::{ + BTreeGen as RustBTreeGen, FontanaGen as RustFontanaGen, Standardization as RustStandardization, +}; +use crate::lambda::recursive::{ + AlchemyCollider, LambdaCollisionError, LambdaCollisionOk, LambdaParticle, +}; +use crate::supercollider::Soup as GenericSoup; +use crate::utils::{decode_hex, encode_hex}; + +// Concrete soup alias for the recursive lambda flavor +type RustSoup = + GenericSoup; + +// ============ Errors exposed to Python ============ + +#[pyclass] +#[derive(Debug, Clone)] +pub struct PyReactionError { + kind: ReactionErrorKind, +} + +#[derive(Debug, Clone)] +pub enum ReactionErrorKind { + ExceedsReductionLimit, + NotEnoughExpressions, + IsIdentity, + IsParent, + HasFreeVariables, + ExceedsDepthLimit, + RecursiveArgument, + BadArgument, +} + +impl From for PyReactionError { + fn from(error: LambdaCollisionError) -> Self { + let kind = match error { + LambdaCollisionError::ExceedsReductionLimit => ReactionErrorKind::ExceedsReductionLimit, + LambdaCollisionError::NotEnoughExpressions => ReactionErrorKind::NotEnoughExpressions, + LambdaCollisionError::IsIdentity => ReactionErrorKind::IsIdentity, + LambdaCollisionError::IsParent => ReactionErrorKind::IsParent, + LambdaCollisionError::HasFreeVariables => ReactionErrorKind::HasFreeVariables, + LambdaCollisionError::ExceedsDepthLimit => ReactionErrorKind::ExceedsDepthLimit, + LambdaCollisionError::RecursiveArgument => ReactionErrorKind::RecursiveArgument, + LambdaCollisionError::BadArgument => ReactionErrorKind::BadArgument, + }; + PyReactionError { kind } + } +} + +// ============ Reactor wrapper ============ + +#[pyclass] +pub struct PyReactor { + pub(crate) inner: RustReactor, +} + +#[pymethods] +impl PyReactor { + #[new] + fn new() -> Self { + PyReactor { inner: RustReactor::new() } + } +} + +// ============ Standardization wrapper ============ + +#[pyclass] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PyStandardization { + standardization: RustStandardization, +} + +#[pymethods] +impl PyStandardization { + #[new] + fn new(kind: &str) -> PyResult { + let standardization = match kind { + "prefix" => RustStandardization::Prefix, + "postfix" => RustStandardization::Postfix, + "none" => RustStandardization::None, + _ => return Err(pyo3::exceptions::PyValueError::new_err("Invalid standardization type")), + }; + Ok(PyStandardization { standardization }) + } +} + +impl From for RustStandardization { + fn from(py_std: PyStandardization) -> Self { py_std.standardization } +} + +// ============ Soup wrapper ============ + +#[pyclass] +pub struct PySoup { + inner: RustSoup, +} + +#[pymethods] +impl PySoup { + #[new] + fn new() -> Self { PySoup { inner: RustSoup::new() } } + + #[staticmethod] + fn from_config(cfg: &PyReactor) -> Self { + PySoup { inner: RustSoup::from_config(&cfg.inner) } + } + + fn perturb(&mut self, expressions: Vec) -> PyResult<()> { + let terms = expressions.into_iter().filter_map(|s| parse(&s, Classic).ok()); + self.inner.add_lambda_expressions(terms); + Ok(()) + } + + fn simulate_for(&mut self, n: usize, log: bool) -> usize { self.inner.simulate_for(n, log) } + fn len(&self) -> usize { self.inner.len() } + fn collisions(&self) -> usize { self.inner.collisions() } + + fn expressions(&self) -> Vec { + self.inner.lambda_expressions().map(|t| t.to_string()).collect() + } + fn unique_expressions(&self) -> Vec { + self.inner.unique_expressions().into_iter().map(|t| t.to_string()).collect() + } + fn expression_counts(&self) -> Vec<(String, u32)> { + self.inner.expression_counts().into_iter().map(|(t, c)| (t.to_string(), c)).collect() + } + fn population_entropy(&self) -> f32 { self.inner.population_entropy() } +} + +// ============ Generators ============ + +#[pyclass] +pub struct PyBTreeGen { inner: RustBTreeGen } + +#[pymethods] +impl PyBTreeGen { + #[new] + fn new() -> Self { PyBTreeGen { inner: RustBTreeGen::new() } } + + #[staticmethod] + fn from_config( + size: u32, + freevar_generation_probability: f64, + max_free_vars: u32, + std: PyStandardization, + ) -> Self { + let cfg = config::BTreeGen { + size, + freevar_generation_probability, + n_max_free_vars: max_free_vars, + standardization: std.into(), + seed: ConfigSeed(Some([0; 32])), + }; + PyBTreeGen { inner: RustBTreeGen::from_config(&cfg) } + } + + fn generate(&mut self) -> String { self.inner.generate().to_string() } + + fn generate_n(&mut self, n: usize) -> Vec { + self.inner.generate_n(n).into_iter().map(|t| t.to_string()).collect() + } +} + +#[pyclass] +pub struct PyFontanaGen { inner: RustFontanaGen } + +#[pymethods] +impl PyFontanaGen { + #[staticmethod] + fn from_config( + abs_range: (f64, f64), + app_range: (f64, f64), + max_depth: u32, + max_free_vars: u32, + ) -> Self { + let cfg = config::FontanaGen { + abstraction_prob_range: abs_range, + application_prob_range: app_range, + max_depth, + n_max_free_vars: max_free_vars, + seed: ConfigSeed(Some([0; 32])), + }; + PyFontanaGen { inner: RustFontanaGen::from_config(&cfg) } + } + + fn generate(&self) -> Option { self.inner.generate().map(|t| t.to_string()) } +} + +// ============ Utilities ============ + +#[pyfunction] +fn decode_hex_py(hex_string: &str) -> PyResult> { + decode_hex(hex_string).map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string())) +} + +#[pyfunction] +fn encode_hex_py(bytes: Vec) -> String { encode_hex(&bytes) } + +// ============ Public registration hook ============ + +pub fn register(m: &Bound<'_, PyModule>) -> PyResult<()> { + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_function(wrap_pyfunction!(decode_hex_py, m)?)?; + m.add_function(wrap_pyfunction!(encode_hex_py, m)?)?; + Ok(()) +} From fbdc8c23895c97411c446c923df88bbbb6ca0715 Mon Sep 17 00:00:00 2001 From: "ridham.patel" Date: Thu, 16 Oct 2025 17:27:10 -0700 Subject: [PATCH 11/23] python bindings: split into python.rs; add PyFontanaGen; tests; tidy lib.rs --- .gitignore | 1 + src/lib.rs | 1 + src/python.rs | 8 ++- test_alchemy.py | 175 ++++++++++++++++++++++++++++++------------------ 4 files changed, 117 insertions(+), 68 deletions(-) diff --git a/.gitignore b/.gitignore index a9e7e65..e87b436 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target /scratchpad /result +.DS_Store diff --git a/src/lib.rs b/src/lib.rs index 35b1f04..e7949d0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,3 +30,4 @@ pub fn read_inputs() -> impl Iterator { fn alchemy(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { python::register(m) } + diff --git a/src/python.rs b/src/python.rs index 9ec5119..14ace23 100644 --- a/src/python.rs +++ b/src/python.rs @@ -174,8 +174,9 @@ pub struct PyFontanaGen { inner: RustFontanaGen } #[pymethods] impl PyFontanaGen { + /// Build a Fontana generator from config values #[staticmethod] - fn from_config( + pub fn from_config( abs_range: (f64, f64), app_range: (f64, f64), max_depth: u32, @@ -191,7 +192,10 @@ impl PyFontanaGen { PyFontanaGen { inner: RustFontanaGen::from_config(&cfg) } } - fn generate(&self) -> Option { self.inner.generate().map(|t| t.to_string()) } + /// Generate one lambda term; returns `None` when the generator yields nothing + pub fn generate(&self) -> Option { + self.inner.generate().map(|t| t.to_string()) + } } // ============ Utilities ============ diff --git a/test_alchemy.py b/test_alchemy.py index 4addacd..b7e9a73 100644 --- a/test_alchemy.py +++ b/test_alchemy.py @@ -1,80 +1,123 @@ +#!/usr/bin/env python3 +# test_alchemy.py + import sys -sys.path.append('/Users/ridhamap/Python_wrapper_alchemy/alchemy-reimplemented/alchemy_new/lib/python3.12/site-packages') -import alchemy +import traceback + +def main(): + try: + import alchemy + except Exception as e: + print("❌ Failed to import 'alchemy' Python module.") + traceback.print_exc() + sys.exit(1) + + print("✅ Imported alchemy") + + # ---------- Utilities ---------- + try: + raw = b"\x00\x01\xab\xcd" + hx = alchemy.decode_hex_py("0001abcd") + assert bytes(hx) == raw, f"decode_hex_py mismatch: {hx}" + re_hx = alchemy.encode_hex_py(list(raw)) + assert re_hx.lower() == "0001abcd", f"encode_hex_py mismatch: {re_hx}" + print("✅ Utilities: decode_hex_py / encode_hex_py") + except Exception: + print("❌ Utilities failed") + traceback.print_exc() + sys.exit(1) + + # ---------- Standardization ---------- + try: + std_prefix = alchemy.PyStandardization("prefix") + std_postfix = alchemy.PyStandardization("postfix") + std_none = alchemy.PyStandardization("none") + print("✅ PyStandardization constructed (prefix/postfix/none)") + except Exception: + print("❌ PyStandardization construction failed") + traceback.print_exc() + sys.exit(1) -def test_reactor(): - print("Testing PyReactor:") - reactor = alchemy.PyReactor() - print("PyReactor instance created successfully.") + # ---------- Generators: BTreeGen ---------- + try: + # BTreeGen::from_config(size, freevar_prob, max_free_vars, std) + bt = alchemy.PyBTreeGen.from_config( + size=6, + freevar_generation_probability=0.3, + max_free_vars=3, + std=std_prefix + ) + one = bt.generate() + many = bt.generate_n(5) + assert isinstance(one, str) and len(one) > 0, "BTreeGen.generate must return string term" + assert isinstance(many, list) and len(many) == 5 and all(isinstance(x, str) for x in many) + print("✅ PyBTreeGen.generate / generate_n OK") + except Exception: + print("❌ PyBTreeGen tests failed") + traceback.print_exc() + sys.exit(1) -def test_standardization(): - print("Testing PyStandardization:") + # ---------- Soup: basic lifecycle ---------- try: - std = alchemy.PyStandardization("prefix") - print("Standardization created with 'prefix':", std) - except ValueError as e: - print("Error in creating Standardization:", e) + # Path 1: default config + soup1 = alchemy.PySoup() + assert soup1.len() == 0, "New soup should be empty" -def test_soup(): - print("Testing PySoup:") - soup = alchemy.PySoup() - print("Empty PySoup instance created.") - print("Initial length of soup:", soup.len()) - - valid_expressions = ["λx.x", "λx.λy.xy", "(λx.x) y", "λx.λy.(yx)", "λf.λx.(f (f x))"] - soup.perturb(valid_expressions) - - print("Soup after perturbation:", soup.expressions()) - print("Unique expressions:", soup.unique_expressions()) - print("Population entropy:", soup.population_entropy()) + # Path 2: from reactor config + reactor = alchemy.PyReactor() + soup2 = alchemy.PySoup.from_config(reactor) + assert soup2.len() == 0, "Soup.from_config should start empty" + # Seed soup2 with 10 generated expressions from BTreeGen + exprs = bt.generate_n(10) + soup2.perturb(exprs) + assert soup2.len() == 10, f"After perturb, expected 10 expressions, got {soup2.len()}" -def test_btree_gen(): - print("Testing PyBTreeGen:") - # Change "postfix" to a supported type, such as "prefix" - gen = alchemy.PyBTreeGen.from_config(5, 0.5, 3, alchemy.PyStandardization("prefix")) - print("BTreeGen instance created.") - print("Generated expression:", gen.generate()) - print("Generated 3 expressions:", gen.generate_n(3)) + # Simulate a few steps, ensure the API responds + steps = soup2.simulate_for(25, False) + assert isinstance(steps, int), "simulate_for should return usize (int in Python)" + # Read back data + all_exprs = soup2.expressions() + uniq = soup2.unique_expressions() + counts = soup2.expression_counts() + ent = soup2.population_entropy() + col = soup2.collisions() + ln = soup2.len() -def test_fontana_gen(): - print("Testing PyFontanaGen:") - fontana_gen = alchemy.PyFontanaGen.from_config((0.1, 0.5), (0.2, 0.6), 5, 2) - print("FontanaGen instance created.") - result = fontana_gen.generate() - print("Generated expression from FontanaGen:", result) + assert isinstance(all_exprs, list) + assert isinstance(uniq, list) + assert isinstance(counts, list) and all( + isinstance(p, (tuple, list)) and len(p) == 2 and isinstance(p[0], str) and isinstance(p[1], int) + for p in counts + ) + assert isinstance(ent, float) + assert isinstance(col, int) + assert isinstance(ln, int) + print(f"✅ PySoup lifecycle OK | len={ln}, uniq={len(uniq)}, collisions={col}, entropy={ent:.4f}") + except Exception: + print("❌ PySoup tests failed") + traceback.print_exc() + sys.exit(1) -def test_utilities(): - print("Testing Utilities:") - encoded = alchemy.encode_hex_py([104, 101, 108, 108, 111]) - print("Encoded hex:", encoded) + # ---------- FontanaGen (may legitimately return None) ---------- try: - decoded = alchemy.decode_hex_py(encoded) - print("Decoded hex:", decoded) - except ValueError as e: - print("Error in decoding hex:", e) + fg = alchemy.PyFontanaGen.from_config( + abs_range=(0.2, 0.6), + app_range=(0.2, 0.6), + max_depth=5, + max_free_vars=3 + ) + maybe = fg.generate() + # Current Rust stub returns None; accept either None or str + assert (maybe is None) or isinstance(maybe, str) + print(f"✅ PyFontanaGen.generate OK (returned {type(maybe).__name__})") + except Exception: + print("❌ PyFontanaGen tests failed") + traceback.print_exc() + sys.exit(1) -def test_experiments(): - print("Testing Experiment Functions:") - try: - - #alchemy.run_look_for_add() - #print("run_look_for_add executed successfully.") - alchemy.run_entropy_series() - print("run_entropy_series executed successfully.") - alchemy.run_entropy_test() - print("run_entropy_test executed successfully.") - alchemy.run_sync_entropy_test() - print("run_sync_entropy_test executed successfully.") - except Exception as e: - print("Error in running experiment functions:", e) + print("\n🎉 All python.rs bindings exercised successfully.") if __name__ == "__main__": - test_reactor() - test_standardization() - test_soup() - test_btree_gen() - test_fontana_gen() - test_utilities() - test_experiments() + main() From fe0e5d08f1fe55767d2d75f2665f17a3843526b6 Mon Sep 17 00:00:00 2001 From: "ridham.patel" Date: Thu, 16 Oct 2025 18:30:05 -0700 Subject: [PATCH 12/23] Bindings + config updates: FontanaGen fields, Py wrappers, pyproject dynamic version, tests --- README.md | 31 +++++++++- pyproject.toml | 10 +++- src/config.rs | 42 +++++++------ src/generators.rs | 150 +++++++++++++++++++++++++++++++++++++++------- src/lib.rs | 13 ++-- src/main.rs | 8 +-- src/python.rs | 23 ++++--- test_alchemy.py | 78 ++++++++++++------------ 8 files changed, 258 insertions(+), 97 deletions(-) diff --git a/README.md b/README.md index c6a43e2..830d65f 100644 --- a/README.md +++ b/README.md @@ -30,4 +30,33 @@ The documentation for the configuration file is in the `Config` object. # Interactive Dashboard -Can be found here: https://github.com/mathis-group/Alchemy-Dashboard \ No newline at end of file +Can be found here: https://github.com/mathis-group/Alchemy-Dashboard + + +# Steps to run updated + +# 0) Pick & activate the EXACT Python you will use (avoid shim confusion) +# (choose one) +# — pyenv: +pyenv shell 3.11.9 + +# — OR virtualenv: +# python3.11 -m venv .venv && source .venv/bin/activate + +# 1) Show which Python we’re about to use +python -c 'import sys,platform; print(sys.executable); print(platform.python_version(), platform.machine())' + +# 2) Clean previous artifacts +cargo clean +python -m pip uninstall -y alchemy || true +rm -rf target + +# 3) Build & install the package *editable* via the PEP 517 backend (maturin) +python -m pip install -e . + +# 4) Sanity-check the import (this uses the same interpreter as above) +python - <<'PY' +import alchemy, sys +print("OK :", alchemy.__file__) +print("Py :", sys.executable) +PY diff --git a/pyproject.toml b/pyproject.toml index 08d8da4..9e91d0a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,9 +4,17 @@ build-backend = "maturin" [project] name = "alchemy" +dynamic = ["version"] # ← pull version from Cargo.toml requires-python = ">=3.7" classifiers = [ "Programming Language :: Rust", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", -] \ No newline at end of file +] + +[tool.maturin] +# maturin will use the crate name & version from Cargo.toml +# (Optional) If your Python sources live in ./python/, you can mirror your Cargo metadata: +# python-source = "python" +# (Optional) Explicit module name if you want to force it: +# module-name = "alchemy" diff --git a/src/config.rs b/src/config.rs index 1a4ccde..f45792e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -107,14 +107,20 @@ pub struct BTreeGen { pub standardization: Standardization, } -/// Configuration for Fontana's generator #[warn(missing_docs)] #[derive(Serialize, Deserialize, Debug)] +/// Generator-specific configuration derived from Walter Fontana's original scheme. pub struct FontanaGen { /// The seed for the lambda expression generator. If set to `None`, then a seed is chosen /// randomly. Default: `None` pub seed: ConfigSeed, + /// Minimum depth before leaf nodes can be generated + pub min_depth: u32, + + /// Maximum depth of the generated trees + pub max_depth: u32, + /// Probability range of an abstraction being generated. Linearly changes from start to end, /// varying with depth pub abstraction_prob_range: (f64, f64), @@ -123,13 +129,27 @@ pub struct FontanaGen { /// varying with depth pub application_prob_range: (f64, f64), - /// Maximum depth of the generated trees - pub max_depth: u32, + /// Probability that a leaf vertex is a free variable + pub free_variable_probability: f64, /// Size of the free variable palette pub n_max_free_vars: u32, } +impl GenConfig for FontanaGen { + fn new() -> Self { + FontanaGen { + seed: ConfigSeed(None), + min_depth: 0, + max_depth: 10, + n_max_free_vars: 6, + application_prob_range: (0.3, 0.5), + abstraction_prob_range: (0.5, 0.3), + free_variable_probability: 0.0, + } + } +} + impl Reactor { /// Produce a new `ReactorConfig` struct with default values. pub fn new() -> Self { @@ -169,18 +189,6 @@ impl GenConfig for BTreeGen { } } -impl GenConfig for FontanaGen { - fn new() -> Self { - FontanaGen { - max_depth: 10, - n_max_free_vars: 6, - application_prob_range: (0.3, 0.5), - abstraction_prob_range: (0.5, 0.3), - seed: ConfigSeed(None), - } - } -} - impl Config { /// Create a config object from a string pub fn from_config_str(s: &str) -> Config { @@ -225,7 +233,7 @@ impl Config { /// to ser/de to/from a hex string. #[warn(missing_docs)] #[derive(Debug, Clone, Copy)] -pub struct ConfigSeed(pub Option<[u8; 32]>); +pub struct ConfigSeed(Option<[u8; 32]>); impl ConfigSeed { /// Get the seed item @@ -276,4 +284,4 @@ impl<'de> Deserialize<'de> for ConfigSeed { ConfigSeed::blank() }) } -} +} \ No newline at end of file diff --git a/src/generators.rs b/src/generators.rs index bed0c75..73bb151 100644 --- a/src/generators.rs +++ b/src/generators.rs @@ -82,12 +82,6 @@ pub struct BTreeGen { rng: ChaCha8Rng, } -impl Default for BTreeGen { - fn default() -> BTreeGen { - Self::new() - } -} - impl BTreeGen { pub fn new() -> BTreeGen { BTreeGen::from_config(&config::BTreeGen::new()) @@ -152,33 +146,147 @@ impl BTreeGen { } } -#[allow(dead_code)] pub struct FontanaGen { - abs_range: (f64, f64), - app_range: (f64, f64), - depth_cutoff: u32, - free_vars_count: u32, + min_depth: u32, + max_depth: u32, + + abs_prob: (f32, f32), + app_prob: (f32, f32), + + abs_incr: f32, + app_incr: f32, + + free_prob: f32, + max_vars: u32, seed: [u8; 32], rng: ChaCha8Rng, } impl FontanaGen { + pub fn new( + min_depth: u32, + mut max_depth: u32, + mut abs_prob: (f32, f32), + mut app_prob: (f32, f32), + mut free_prob: f32, + mut max_vars: u32, + seed: [u8; 32], + ) -> FontanaGen { + // Sanitise configuration so generation never panics. + max_depth = max_depth.max(1); + max_vars = max_vars.max(1); + free_prob = free_prob.clamp(0.0, 1.0); + abs_prob.0 = abs_prob.0.clamp(0.0, 1.0); + abs_prob.1 = abs_prob.1.clamp(0.0, 1.0); + app_prob.0 = app_prob.0.clamp(0.0, 1.0); + app_prob.1 = app_prob.1.clamp(0.0, 1.0); + + let steps = (max_depth - 1).max(1); + let abs_incr = (abs_prob.1 - abs_prob.0) / (steps as f32); + let app_incr = (app_prob.1 - app_prob.0) / (steps as f32); + + FontanaGen { + min_depth: min_depth.min(max_depth.saturating_sub(1)), + max_depth, + abs_prob, + app_prob, + abs_incr, + app_incr, + free_prob, + max_vars, + seed, + rng: ChaCha8Rng::from_seed(seed), + } + } + pub fn from_config(cfg: &config::FontanaGen) -> FontanaGen { let seed = cfg.seed.get(); - let rng = ChaCha8Rng::from_seed(seed); - FontanaGen { - abs_range: cfg.abstraction_prob_range, - app_range: cfg.application_prob_range, - depth_cutoff: cfg.max_depth, - free_vars_count: cfg.n_max_free_vars, + FontanaGen::new( + cfg.min_depth, + cfg.max_depth, + ( + cfg.abstraction_prob_range.0 as f32, + cfg.abstraction_prob_range.1 as f32, + ), + ( + cfg.application_prob_range.0 as f32, + cfg.application_prob_range.1 as f32, + ), + cfg.free_variable_probability as f32, + cfg.n_max_free_vars, seed, - rng, + ) + } + + pub fn generate(&mut self) -> Term { // <-- not Option + self.rand_lambda(0, self.abs_prob.0, self.app_prob.0) + } + + pub fn generate_n(&mut self, n: usize) -> Vec { + let mut v = Vec::with_capacity(n); + for _ in 0..n { + v.push(self.generate()) } + v } - pub fn generate(&self) -> Option { - None + pub fn seed(&self) -> [u8; 32] { + self.seed } -} + + pub fn rand_lambda(&mut self, depth: u32, p_abs: f32, p_app: f32) -> Term { + let (p_abs_eff, p_app_eff) = Self::clamp_probabilities(p_abs, p_app); + + if depth >= self.max_depth { + return self.sample_variable(depth); + } + + let next_abs = p_abs + self.abs_incr; + let next_app = p_app + self.app_incr; + + if depth < self.min_depth { + if self.rng.gen_bool(0.5) { + return Term::Abs(Box::new(self.rand_lambda(depth + 1, next_abs, next_app))); + } + return Term::App(Box::new(( + self.rand_lambda(depth + 1, next_abs, next_app), + self.rand_lambda(depth + 1, next_abs, next_app), + ))); + } + + let coin: f32 = self.rng.gen(); + if coin <= p_abs_eff { + return Term::Abs(Box::new(self.rand_lambda(depth + 1, next_abs, next_app))); + } + if coin <= p_abs_eff + p_app_eff { + return Term::App(Box::new(( + self.rand_lambda(depth + 1, next_abs, next_app), + self.rand_lambda(depth + 1, next_abs, next_app), + ))); + } + + self.sample_variable(depth) + } + + fn clamp_probabilities(p_abs: f32, p_app: f32) -> (f32, f32) { + let abs = p_abs.clamp(0.0, 1.0); + let remaining = 1.0 - abs; + let app = p_app.clamp(0.0, remaining); + (abs, app) + } + + fn sample_variable(&mut self, depth: u32) -> Term { + let free_choice = self.rng.gen_bool(self.free_prob as f64) || depth == 0; + let max_vars = self.max_vars.max(1); + let value = if free_choice { + let offset = self.rng.gen_range(1..=max_vars); + depth.saturating_add(offset) as usize + } else { + let upper = depth.max(1); + self.rng.gen_range(1..=upper) as usize + }; + Term::Var(value) + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index e7949d0..e1a22b5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,10 +13,17 @@ pub mod supercollider; // New Python wrapper module mod python; +#[pymodule] +fn alchemy(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { + python::register(m) +} + // If you still need this for the CLI, keep it here: use lambda_calculus::{parse, term::Notation::Classic, Term}; use std::io::{self, BufRead}; + + pub fn read_inputs() -> impl Iterator { io::stdin() .lock() @@ -25,9 +32,3 @@ pub fn read_inputs() -> impl Iterator { .filter_map(|line| parse(&line, Classic).ok()) } -// Python module entry point stays tiny and delegates to python::register -#[pymodule] -fn alchemy(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { - python::register(m) -} - diff --git a/src/main.rs b/src/main.rs index 66f9ad6..b886aaa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -117,6 +117,7 @@ fn get_config(cli: &Cli) -> std::io::Result { Ok(config) } +// main.rs pub fn generate_expressions_and_seed_soup(cfg: &config::Config) -> lambda::recursive::LambdaSoup { let expressions = match &cfg.generator_config { config::Generator::BTree(gen_cfg) => { @@ -124,10 +125,8 @@ pub fn generate_expressions_and_seed_soup(cfg: &config::Config) -> lambda::recur gen.generate_n(cfg.sample_size) } config::Generator::Fontana(gen_cfg) => { - let gen = generators::FontanaGen::from_config(gen_cfg); - std::iter::from_fn(move || gen.generate()) - .take(cfg.sample_size) - .collect::>() + let mut gen = generators::FontanaGen::from_config(gen_cfg); + gen.generate_n(cfg.sample_size) // ← returns Vec } }; let mut soup = lambda::recursive::LambdaSoup::from_config(&cfg.reactor_config); @@ -135,6 +134,7 @@ pub fn generate_expressions_and_seed_soup(cfg: &config::Config) -> lambda::recur soup } + fn main() -> std::io::Result<()> { let cli = Cli::parse(); diff --git a/src/python.rs b/src/python.rs index 14ace23..f835a3a 100644 --- a/src/python.rs +++ b/src/python.rs @@ -3,7 +3,7 @@ use pyo3::prelude::*; use pyo3::wrap_pyfunction; use serde::{Deserialize, Serialize}; -use lambda_calculus::{parse, term::Notation::Classic, Term}; +use lambda_calculus::{parse, term::Notation::Classic}; use crate::config::{self, ConfigSeed, Reactor as RustReactor}; use crate::generators::{ @@ -157,7 +157,7 @@ impl PyBTreeGen { freevar_generation_probability, n_max_free_vars: max_free_vars, standardization: std.into(), - seed: ConfigSeed(Some([0; 32])), + seed:ConfigSeed::new([0; 32]), }; PyBTreeGen { inner: RustBTreeGen::from_config(&cfg) } } @@ -174,27 +174,36 @@ pub struct PyFontanaGen { inner: RustFontanaGen } #[pymethods] impl PyFontanaGen { - /// Build a Fontana generator from config values + /// Build a Fontana generator from config values (matches the new struct) #[staticmethod] pub fn from_config( abs_range: (f64, f64), app_range: (f64, f64), + min_depth: u32, max_depth: u32, + free_variable_probability: f64, max_free_vars: u32, ) -> Self { let cfg = config::FontanaGen { abstraction_prob_range: abs_range, application_prob_range: app_range, + min_depth, max_depth, + free_variable_probability, n_max_free_vars: max_free_vars, - seed: ConfigSeed(Some([0; 32])), + seed: ConfigSeed::new([0; 32]), }; PyFontanaGen { inner: RustFontanaGen::from_config(&cfg) } } - /// Generate one lambda term; returns `None` when the generator yields nothing - pub fn generate(&self) -> Option { - self.inner.generate().map(|t| t.to_string()) + /// Generate a single lambda term (now always returns a term) + pub fn generate(&mut self) -> String { + self.inner.generate().to_string() + } + + /// Convenience: generate N terms + pub fn generate_n(&mut self, n: usize) -> Vec { + self.inner.generate_n(n).into_iter().map(|t| t.to_string()).collect() } } diff --git a/test_alchemy.py b/test_alchemy.py index b7e9a73..9f1f03d 100644 --- a/test_alchemy.py +++ b/test_alchemy.py @@ -4,15 +4,23 @@ import sys import traceback + +def die(msg: str): + print(msg) + sys.exit(1) + + def main(): + # ---------- Import ---------- try: import alchemy - except Exception as e: - print("❌ Failed to import 'alchemy' Python module.") - traceback.print_exc() - sys.exit(1) - - print("✅ Imported alchemy") + import inspect + print("✅ Imported alchemy") + print(" module:", getattr(alchemy, "__file__", "")) + print(" PyFontanaGen.from_config signature:", + inspect.signature(alchemy.PyFontanaGen.from_config)) + except Exception: + die("❌ Failed to import 'alchemy'\n" + traceback.format_exc()) # ---------- Utilities ---------- try: @@ -21,63 +29,53 @@ def main(): assert bytes(hx) == raw, f"decode_hex_py mismatch: {hx}" re_hx = alchemy.encode_hex_py(list(raw)) assert re_hx.lower() == "0001abcd", f"encode_hex_py mismatch: {re_hx}" - print("✅ Utilities: decode_hex_py / encode_hex_py") + print("✅ Utilities OK (decode_hex_py / encode_hex_py)") except Exception: - print("❌ Utilities failed") - traceback.print_exc() - sys.exit(1) + die("❌ Utilities failed\n" + traceback.format_exc()) # ---------- Standardization ---------- try: std_prefix = alchemy.PyStandardization("prefix") std_postfix = alchemy.PyStandardization("postfix") std_none = alchemy.PyStandardization("none") + for s in (std_prefix, std_postfix, std_none): + assert s is not None print("✅ PyStandardization constructed (prefix/postfix/none)") except Exception: - print("❌ PyStandardization construction failed") - traceback.print_exc() - sys.exit(1) + die("❌ PyStandardization construction failed\n" + traceback.format_exc()) # ---------- Generators: BTreeGen ---------- try: - # BTreeGen::from_config(size, freevar_prob, max_free_vars, std) bt = alchemy.PyBTreeGen.from_config( size=6, freevar_generation_probability=0.3, max_free_vars=3, - std=std_prefix + std=std_prefix, ) one = bt.generate() many = bt.generate_n(5) - assert isinstance(one, str) and len(one) > 0, "BTreeGen.generate must return string term" - assert isinstance(many, list) and len(many) == 5 and all(isinstance(x, str) for x in many) + assert isinstance(one, str) and len(one) > 0, "BTreeGen.generate must return a non-empty string" + assert isinstance(many, list) and len(many) == 5 and all(isinstance(x, str) and x for x in many) print("✅ PyBTreeGen.generate / generate_n OK") except Exception: - print("❌ PyBTreeGen tests failed") - traceback.print_exc() - sys.exit(1) + die("❌ PyBTreeGen tests failed\n" + traceback.format_exc()) - # ---------- Soup: basic lifecycle ---------- + # ---------- Soup lifecycle ---------- try: - # Path 1: default config soup1 = alchemy.PySoup() assert soup1.len() == 0, "New soup should be empty" - # Path 2: from reactor config reactor = alchemy.PyReactor() soup2 = alchemy.PySoup.from_config(reactor) assert soup2.len() == 0, "Soup.from_config should start empty" - # Seed soup2 with 10 generated expressions from BTreeGen exprs = bt.generate_n(10) soup2.perturb(exprs) assert soup2.len() == 10, f"After perturb, expected 10 expressions, got {soup2.len()}" - # Simulate a few steps, ensure the API responds steps = soup2.simulate_for(25, False) - assert isinstance(steps, int), "simulate_for should return usize (int in Python)" + assert isinstance(steps, int) - # Read back data all_exprs = soup2.expressions() uniq = soup2.unique_expressions() counts = soup2.expression_counts() @@ -96,28 +94,28 @@ def main(): assert isinstance(ln, int) print(f"✅ PySoup lifecycle OK | len={ln}, uniq={len(uniq)}, collisions={col}, entropy={ent:.4f}") except Exception: - print("❌ PySoup tests failed") - traceback.print_exc() - sys.exit(1) + die("❌ PySoup tests failed\n" + traceback.format_exc()) - # ---------- FontanaGen (may legitimately return None) ---------- + # ---------- FontanaGen (new API + always returns str) ---------- try: fg = alchemy.PyFontanaGen.from_config( abs_range=(0.2, 0.6), app_range=(0.2, 0.6), - max_depth=5, - max_free_vars=3 + min_depth=1, # test minimum nesting before allowing variables + max_depth=5, # cap depth growth + free_variable_probability=0.25, + max_free_vars=3, ) - maybe = fg.generate() - # Current Rust stub returns None; accept either None or str - assert (maybe is None) or isinstance(maybe, str) - print(f"✅ PyFontanaGen.generate OK (returned {type(maybe).__name__})") + term = fg.generate() + assert isinstance(term, str) and term, "FontanaGen.generate must return a non-empty string" + terms = fg.generate_n(5) + assert isinstance(terms, list) and len(terms) == 5 and all(isinstance(t, str) and t for t in terms) + print("✅ PyFontanaGen.from_config / generate / generate_n OK") except Exception: - print("❌ PyFontanaGen tests failed") - traceback.print_exc() - sys.exit(1) + die("❌ PyFontanaGen tests failed\n" + traceback.format_exc()) print("\n🎉 All python.rs bindings exercised successfully.") + if __name__ == "__main__": main() From 302f800e7b22550f5faa60053a69c1aedb8b856a Mon Sep 17 00:00:00 2001 From: Cole Mathis Date: Thu, 23 Oct 2025 14:29:35 -0700 Subject: [PATCH 13/23] Remove plotters dependency --- Cargo.lock | 599 ----------------------------------------------------- Cargo.toml | 1 - 2 files changed, 600 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4df5bda..0068620 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,7 +25,6 @@ dependencies = [ "clap", "futures", "lambda_calculus", - "plotters", "pyo3", "pyo3-build-config", "rand", @@ -35,15 +34,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - [[package]] name = "anstream" version = "0.6.15" @@ -293,47 +283,18 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" -[[package]] -name = "bytemuck" -version = "1.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" - [[package]] name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" -[[package]] -name = "cc" -version = "1.2.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" -dependencies = [ - "find-msvc-tools", - "shlex", -] - [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "chrono" -version = "0.4.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" -dependencies = [ - "iana-time-zone", - "js-sys", - "num-traits", - "wasm-bindgen", - "windows-link", -] - [[package]] name = "clap" version = "4.5.15" @@ -374,12 +335,6 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" -[[package]] -name = "color_quant" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" - [[package]] name = "colorchoice" version = "1.0.2" @@ -395,115 +350,12 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "core-graphics" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-graphics-types", - "foreign-types", - "libc", -] - -[[package]] -name = "core-graphics-types" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "libc", -] - -[[package]] -name = "core-text" -version = "20.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9d2790b5c08465d49f8dc05c8bcae9fea467855947db39b0f8145c091aaced5" -dependencies = [ - "core-foundation", - "core-graphics", - "foreign-types", - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" -dependencies = [ - "cfg-if", -] - [[package]] name = "crossbeam-utils" version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" -[[package]] -name = "dirs" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" -dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys 0.59.0", -] - -[[package]] -name = "dlib" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" -dependencies = [ - "libloading", -] - -[[package]] -name = "dwrote" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20c93d234bac0cdd0e2ac08bc8a5133f8df2169e95b262dfcea5e5cb7855672f" -dependencies = [ - "lazy_static", - "libc", - "winapi", - "wio", -] - [[package]] name = "errno" version = "0.3.9" @@ -556,100 +408,6 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" -[[package]] -name = "fdeflate" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" -dependencies = [ - "simd-adler32", -] - -[[package]] -name = "find-msvc-tools" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" - -[[package]] -name = "flate2" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "float-ord" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce81f49ae8a0482e4c55ea62ebbd7e5a686af544c00b9d090bba3ff9be97b3d" - -[[package]] -name = "font-kit" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c7e611d49285d4c4b2e1727b72cf05353558885cc5252f93707b845dfcaf3d3" -dependencies = [ - "bitflags 2.6.0", - "byteorder", - "core-foundation", - "core-graphics", - "core-text", - "dirs", - "dwrote", - "float-ord", - "freetype-sys", - "lazy_static", - "libc", - "log", - "pathfinder_geometry", - "pathfinder_simd", - "walkdir", - "winapi", - "yeslogic-fontconfig-sys", -] - -[[package]] -name = "foreign-types" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" -dependencies = [ - "foreign-types-macros", - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-macros" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "foreign-types-shared" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" - -[[package]] -name = "freetype-sys" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7edc5b9669349acfda99533e9e0bcf26a51862ab43b08ee7745c55d28eb134" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - [[package]] name = "futures" version = "0.3.30" @@ -778,16 +536,6 @@ dependencies = [ "wasi", ] -[[package]] -name = "gif" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045" -dependencies = [ - "color_quant", - "weezl", -] - [[package]] name = "gimli" version = "0.31.1" @@ -824,44 +572,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" -[[package]] -name = "iana-time-zone" -version = "0.1.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "image" -version = "0.24.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" -dependencies = [ - "bytemuck", - "byteorder", - "color_quant", - "jpeg-decoder", - "num-traits", - "png", -] - [[package]] name = "indoc" version = "2.0.6" @@ -911,12 +621,6 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" -[[package]] -name = "jpeg-decoder" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07" - [[package]] name = "js-sys" version = "0.3.70" @@ -940,38 +644,12 @@ name = "lambda_calculus" version = "3.3.0" source = "git+https://github.com/agentelement/lambda_calculus?branch=size-feat#8346381fc0df29f3ed5022913d58d3a5244c22e7" -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - [[package]] name = "libc" version = "0.2.176" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" -[[package]] -name = "libloading" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" -dependencies = [ - "cfg-if", - "windows-link", -] - -[[package]] -name = "libredox" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" -dependencies = [ - "bitflags 2.6.0", - "libc", -] - [[package]] name = "linux-raw-sys" version = "0.3.8" @@ -1015,7 +693,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", - "simd-adler32", ] [[package]] @@ -1029,15 +706,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - [[package]] name = "object" version = "0.36.7" @@ -1053,37 +721,12 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - [[package]] name = "parking" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" -[[package]] -name = "pathfinder_geometry" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b7e7b4ea703700ce73ebf128e1450eb69c3a8329199ffbfb9b2a0418e5ad3" -dependencies = [ - "log", - "pathfinder_simd", -] - -[[package]] -name = "pathfinder_simd" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf9027960355bf3afff9841918474a81a5f972ac6d226d518060bba758b5ad57" -dependencies = [ - "rustc_version", -] - [[package]] name = "pin-project-lite" version = "0.2.14" @@ -1107,71 +750,6 @@ dependencies = [ "futures-io", ] -[[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - -[[package]] -name = "plotters" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" -dependencies = [ - "chrono", - "font-kit", - "image", - "lazy_static", - "num-traits", - "pathfinder_geometry", - "plotters-backend", - "plotters-bitmap", - "plotters-svg", - "ttf-parser", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "plotters-backend" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" - -[[package]] -name = "plotters-bitmap" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ce181e3f6bf82d6c1dc569103ca7b1bd964c60ba03d7e6cdfbb3e3eb7f7405" -dependencies = [ - "gif", - "image", - "plotters-backend", -] - -[[package]] -name = "plotters-svg" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" -dependencies = [ - "plotters-backend", -] - -[[package]] -name = "png" -version = "0.17.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" -dependencies = [ - "bitflags 1.3.2", - "crc32fast", - "fdeflate", - "flate2", - "miniz_oxide", -] - [[package]] name = "polling" version = "2.8.0" @@ -1329,32 +907,12 @@ dependencies = [ "getrandom", ] -[[package]] -name = "redox_users" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" -dependencies = [ - "getrandom", - "libredox", - "thiserror", -] - [[package]] name = "rustc-demangle" version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - [[package]] name = "rustix" version = "0.37.27" @@ -1388,21 +946,6 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "semver" -version = "1.0.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" - [[package]] name = "serde" version = "1.0.207" @@ -1435,18 +978,6 @@ dependencies = [ "serde", ] -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "simd-adler32" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" - [[package]] name = "slab" version = "0.4.9" @@ -1489,26 +1020,6 @@ version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" -[[package]] -name = "thiserror" -version = "2.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "tokio" version = "1.47.1" @@ -1539,12 +1050,6 @@ version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -[[package]] -name = "ttf-parser" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4" - [[package]] name = "unicode-ident" version = "1.0.12" @@ -1575,16 +1080,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1668,12 +1163,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "weezl" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" - [[package]] name = "winapi" version = "0.3.9" @@ -1690,80 +1179,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" -dependencies = [ - "windows-sys 0.59.0", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-core" -version = "0.62.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-implement" -version = "0.60.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-interface" -version = "0.59.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-link" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" - -[[package]] -name = "windows-result" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" -dependencies = [ - "windows-link", -] - [[package]] name = "windows-sys" version = "0.48.0" @@ -1912,26 +1333,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "wio" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5" -dependencies = [ - "winapi", -] - -[[package]] -name = "yeslogic-fontconfig-sys" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "503a066b4c037c440169d995b869046827dbc71263f6e8f3be6d77d4f3229dbd" -dependencies = [ - "dlib", - "once_cell", - "pkg-config", -] - [[package]] name = "zerocopy" version = "0.7.35" diff --git a/Cargo.toml b/Cargo.toml index 94c62ca..b00535a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,6 @@ async-std = "1.12.0" clap = { version = "4.5.4", features = ["derive"] } futures = "0.3.30" lambda_calculus = { git = "https://github.com/agentelement/lambda_calculus", branch = "size-feat" } -plotters = "0.3.6" rand = "0.8" rand_chacha = "0.3.1" serde = { version = "1.0.202", features = ["derive"] } From e17498018b58b98f910ffa696032d9880d919936 Mon Sep 17 00:00:00 2001 From: Cole Mathis Date: Thu, 23 Oct 2025 14:38:38 -0700 Subject: [PATCH 14/23] trying to debug the fmt error --- src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index b886aaa..aa268ba 100644 --- a/src/main.rs +++ b/src/main.rs @@ -134,7 +134,6 @@ pub fn generate_expressions_and_seed_soup(cfg: &config::Config) -> lambda::recur soup } - fn main() -> std::io::Result<()> { let cli = Cli::parse(); From 6b05cfed28d080c4a5f65434dd75692a0368a890 Mon Sep 17 00:00:00 2001 From: Cole Mathis Date: Thu, 23 Oct 2025 14:40:56 -0700 Subject: [PATCH 15/23] Updating lib file, should not have Cli in it --- src/lib.rs | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e1a22b5..74882e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,13 +2,13 @@ use pyo3::prelude::*; // Re-export your Rust modules for the CLI and for external users +pub mod analysis; pub mod config; pub mod experiments; pub mod generators; -pub mod utils; -pub mod analysis; pub mod lambda; pub mod supercollider; +pub mod utils; // New Python wrapper module mod python; @@ -18,17 +18,3 @@ fn alchemy(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { python::register(m) } -// If you still need this for the CLI, keep it here: -use lambda_calculus::{parse, term::Notation::Classic, Term}; -use std::io::{self, BufRead}; - - - -pub fn read_inputs() -> impl Iterator { - io::stdin() - .lock() - .lines() - .filter_map(|line| line.ok()) - .filter_map(|line| parse(&line, Classic).ok()) -} - From 140c5b0f56108c283b23a18914c171414ac436c7 Mon Sep 17 00:00:00 2001 From: Cole Mathis Date: Thu, 23 Oct 2025 14:49:36 -0700 Subject: [PATCH 16/23] modify cargo to allow build, this probably breaks maturin --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b00535a..c6fed8b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [lib] name = "alchemy" path = "src/lib.rs" -crate-type = ["cdylib", "rlib"] +crate-type = ["rlib"] [package.metadata.maturin] name = "alchemy" From 3e4c3cefc5c0a6c2dc9f74d8cfb80e28199592a2 Mon Sep 17 00:00:00 2001 From: Cole Mathis Date: Thu, 23 Oct 2025 14:51:58 -0700 Subject: [PATCH 17/23] fmt --- src/config.rs | 2 +- src/generators.rs | 5 ++- src/lib.rs | 1 - src/python.rs | 105 ++++++++++++++++++++++++++++++++++++---------- 4 files changed, 86 insertions(+), 27 deletions(-) diff --git a/src/config.rs b/src/config.rs index f45792e..318580c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -284,4 +284,4 @@ impl<'de> Deserialize<'de> for ConfigSeed { ConfigSeed::blank() }) } -} \ No newline at end of file +} diff --git a/src/generators.rs b/src/generators.rs index 73bb151..776aa35 100644 --- a/src/generators.rs +++ b/src/generators.rs @@ -220,7 +220,8 @@ impl FontanaGen { ) } - pub fn generate(&mut self) -> Term { // <-- not Option + pub fn generate(&mut self) -> Term { + // <-- not Option self.rand_lambda(0, self.abs_prob.0, self.app_prob.0) } @@ -289,4 +290,4 @@ impl FontanaGen { }; Term::Var(value) } -} \ No newline at end of file +} diff --git a/src/lib.rs b/src/lib.rs index 74882e8..28b8923 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,4 +17,3 @@ mod python; fn alchemy(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { python::register(m) } - diff --git a/src/python.rs b/src/python.rs index f835a3a..45159d0 100644 --- a/src/python.rs +++ b/src/python.rs @@ -66,7 +66,9 @@ pub struct PyReactor { impl PyReactor { #[new] fn new() -> Self { - PyReactor { inner: RustReactor::new() } + PyReactor { + inner: RustReactor::new(), + } } } @@ -86,14 +88,20 @@ impl PyStandardization { "prefix" => RustStandardization::Prefix, "postfix" => RustStandardization::Postfix, "none" => RustStandardization::None, - _ => return Err(pyo3::exceptions::PyValueError::new_err("Invalid standardization type")), + _ => { + return Err(pyo3::exceptions::PyValueError::new_err( + "Invalid standardization type", + )) + } }; Ok(PyStandardization { standardization }) } } impl From for RustStandardization { - fn from(py_std: PyStandardization) -> Self { py_std.standardization } + fn from(py_std: PyStandardization) -> Self { + py_std.standardization + } } // ============ Soup wrapper ============ @@ -106,44 +114,77 @@ pub struct PySoup { #[pymethods] impl PySoup { #[new] - fn new() -> Self { PySoup { inner: RustSoup::new() } } + fn new() -> Self { + PySoup { + inner: RustSoup::new(), + } + } #[staticmethod] fn from_config(cfg: &PyReactor) -> Self { - PySoup { inner: RustSoup::from_config(&cfg.inner) } + PySoup { + inner: RustSoup::from_config(&cfg.inner), + } } fn perturb(&mut self, expressions: Vec) -> PyResult<()> { - let terms = expressions.into_iter().filter_map(|s| parse(&s, Classic).ok()); + let terms = expressions + .into_iter() + .filter_map(|s| parse(&s, Classic).ok()); self.inner.add_lambda_expressions(terms); Ok(()) } - fn simulate_for(&mut self, n: usize, log: bool) -> usize { self.inner.simulate_for(n, log) } - fn len(&self) -> usize { self.inner.len() } - fn collisions(&self) -> usize { self.inner.collisions() } + fn simulate_for(&mut self, n: usize, log: bool) -> usize { + self.inner.simulate_for(n, log) + } + fn len(&self) -> usize { + self.inner.len() + } + fn collisions(&self) -> usize { + self.inner.collisions() + } fn expressions(&self) -> Vec { - self.inner.lambda_expressions().map(|t| t.to_string()).collect() + self.inner + .lambda_expressions() + .map(|t| t.to_string()) + .collect() } fn unique_expressions(&self) -> Vec { - self.inner.unique_expressions().into_iter().map(|t| t.to_string()).collect() + self.inner + .unique_expressions() + .into_iter() + .map(|t| t.to_string()) + .collect() } fn expression_counts(&self) -> Vec<(String, u32)> { - self.inner.expression_counts().into_iter().map(|(t, c)| (t.to_string(), c)).collect() + self.inner + .expression_counts() + .into_iter() + .map(|(t, c)| (t.to_string(), c)) + .collect() + } + fn population_entropy(&self) -> f32 { + self.inner.population_entropy() } - fn population_entropy(&self) -> f32 { self.inner.population_entropy() } } // ============ Generators ============ #[pyclass] -pub struct PyBTreeGen { inner: RustBTreeGen } +pub struct PyBTreeGen { + inner: RustBTreeGen, +} #[pymethods] impl PyBTreeGen { #[new] - fn new() -> Self { PyBTreeGen { inner: RustBTreeGen::new() } } + fn new() -> Self { + PyBTreeGen { + inner: RustBTreeGen::new(), + } + } #[staticmethod] fn from_config( @@ -157,20 +198,30 @@ impl PyBTreeGen { freevar_generation_probability, n_max_free_vars: max_free_vars, standardization: std.into(), - seed:ConfigSeed::new([0; 32]), + seed: ConfigSeed::new([0; 32]), }; - PyBTreeGen { inner: RustBTreeGen::from_config(&cfg) } + PyBTreeGen { + inner: RustBTreeGen::from_config(&cfg), + } } - fn generate(&mut self) -> String { self.inner.generate().to_string() } + fn generate(&mut self) -> String { + self.inner.generate().to_string() + } fn generate_n(&mut self, n: usize) -> Vec { - self.inner.generate_n(n).into_iter().map(|t| t.to_string()).collect() + self.inner + .generate_n(n) + .into_iter() + .map(|t| t.to_string()) + .collect() } } #[pyclass] -pub struct PyFontanaGen { inner: RustFontanaGen } +pub struct PyFontanaGen { + inner: RustFontanaGen, +} #[pymethods] impl PyFontanaGen { @@ -193,7 +244,9 @@ impl PyFontanaGen { n_max_free_vars: max_free_vars, seed: ConfigSeed::new([0; 32]), }; - PyFontanaGen { inner: RustFontanaGen::from_config(&cfg) } + PyFontanaGen { + inner: RustFontanaGen::from_config(&cfg), + } } /// Generate a single lambda term (now always returns a term) @@ -203,7 +256,11 @@ impl PyFontanaGen { /// Convenience: generate N terms pub fn generate_n(&mut self, n: usize) -> Vec { - self.inner.generate_n(n).into_iter().map(|t| t.to_string()).collect() + self.inner + .generate_n(n) + .into_iter() + .map(|t| t.to_string()) + .collect() } } @@ -215,7 +272,9 @@ fn decode_hex_py(hex_string: &str) -> PyResult> { } #[pyfunction] -fn encode_hex_py(bytes: Vec) -> String { encode_hex(&bytes) } +fn encode_hex_py(bytes: Vec) -> String { + encode_hex(&bytes) +} // ============ Public registration hook ============ From f624dfed4327a03d1d68dd96f2900ccadfdf2e59 Mon Sep 17 00:00:00 2001 From: Cole Mathis Date: Thu, 23 Oct 2025 14:53:11 -0700 Subject: [PATCH 18/23] Fmt experiments files --- src/experiments/kinetics.rs | 9 +++++++-- src/experiments/search_by_behavior.rs | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/experiments/kinetics.rs b/src/experiments/kinetics.rs index 6f0087c..5709060 100644 --- a/src/experiments/kinetics.rs +++ b/src/experiments/kinetics.rs @@ -134,8 +134,13 @@ pub fn kinetic_succ_experiment() { let mut futures = FuturesUnordered::new(); let sample_size = 5000; - let good_fracs = [0.0, 0.0002, 0.0004, 0.0008, 0.0016, 0.0032, 0.0064, 0.0128, 0.0256, 0.0512, 0.1024]; - let test_fracs = [0.0, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.50, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80]; + let good_fracs = [ + 0.0, 0.0002, 0.0004, 0.0008, 0.0016, 0.0032, 0.0064, 0.0128, 0.0256, 0.0512, 0.1024, + ]; + let test_fracs = [ + 0.0, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.50, 0.55, 0.60, 0.65, 0.70, + 0.75, 0.80, + ]; for (i, good_frac) in good_fracs.iter().enumerate() { for (j, test_frac) in test_fracs.iter().enumerate() { diff --git a/src/experiments/search_by_behavior.rs b/src/experiments/search_by_behavior.rs index 07794f3..e180b28 100644 --- a/src/experiments/search_by_behavior.rs +++ b/src/experiments/search_by_behavior.rs @@ -127,7 +127,7 @@ pub fn look_for_xorset() { i, run_length, polling_interval, - xorset_test + xorset_test, ))); } @@ -156,7 +156,7 @@ pub fn look_for_not_xorset() { i, run_length, polling_interval, - not_xorset_test + not_xorset_test, ))); } From 3fafcbfbf092f683085fc478b1e685e7b7bd2df5 Mon Sep 17 00:00:00 2001 From: "ridham.patel" Date: Thu, 30 Oct 2025 10:53:59 -0700 Subject: [PATCH 19/23] Fix PyReactionError dead_code warning and update Cargo.toml --- Cargo.toml | 2 +- src/python.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c6fed8b..50741a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [lib] name = "alchemy" path = "src/lib.rs" -crate-type = ["rlib"] +crate-type = ["rlib","cdylib"] [package.metadata.maturin] name = "alchemy" diff --git a/src/python.rs b/src/python.rs index 45159d0..a7a60a6 100644 --- a/src/python.rs +++ b/src/python.rs @@ -23,6 +23,7 @@ type RustSoup = #[pyclass] #[derive(Debug, Clone)] +#[allow(dead_code)] pub struct PyReactionError { kind: ReactionErrorKind, } From 29dc1d652dac042a2bbb81c9333172e4e0a79dee Mon Sep 17 00:00:00 2001 From: jjoseph12 <72823288+jjoseph12@users.noreply.github.com> Date: Wed, 5 Nov 2025 14:15:52 -0700 Subject: [PATCH 20/23] Updated message --- build.rs | 4 ++++ src/generators.rs | 6 ++++++ uv.lock | 7 +++++++ 3 files changed, 17 insertions(+) create mode 100644 build.rs create mode 100644 uv.lock diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..033c3cc --- /dev/null +++ b/build.rs @@ -0,0 +1,4 @@ +fn main() { + // Ensure correct linker arguments for PyO3 extension modules on all platforms. + pyo3_build_config::add_extension_module_link_args(); +} diff --git a/src/generators.rs b/src/generators.rs index 776aa35..ed6b3fd 100644 --- a/src/generators.rs +++ b/src/generators.rs @@ -82,6 +82,12 @@ pub struct BTreeGen { rng: ChaCha8Rng, } +impl Default for BTreeGen { + fn default() -> Self { + Self::new() + } +} + impl BTreeGen { pub fn new() -> BTreeGen { BTreeGen::from_config(&config::BTreeGen::new()) diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..7c4d26c --- /dev/null +++ b/uv.lock @@ -0,0 +1,7 @@ +version = 1 +revision = 3 +requires-python = ">=3.7" + +[[package]] +name = "alchemy" +source = { editable = "." } From d3446aa52d4700ad4e173ae00b9a38a52fff8c4d Mon Sep 17 00:00:00 2001 From: devyanshnegi Date: Thu, 13 Nov 2025 05:06:53 -0700 Subject: [PATCH 21/23] Added Abs standardization for Fontana Gen and Fixed Clippy Errors --- Cargo.lock | 803 ++++++++++++++-------------------------------- Cargo.toml | 4 +- src/generators.rs | 22 +- 3 files changed, 268 insertions(+), 561 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0068620..fe8f4d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,21 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - [[package]] name = "alchemy" version = "0.1.0" @@ -36,9 +21,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", @@ -51,36 +36,37 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "once_cell_polyfill", + "windows-sys 0.60.2", ] [[package]] @@ -96,9 +82,9 @@ dependencies = [ [[package]] name = "async-channel" -version = "2.3.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" dependencies = [ "concurrent-queue", "event-listener-strategy", @@ -108,14 +94,15 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.13.0" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7ebdfa2ebdab6b1760375fa7d6f382b9f486eac35fc994625a00e89280bdbb7" +checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" dependencies = [ "async-task", "concurrent-queue", - "fastrand 2.1.0", - "futures-lite 2.3.0", + "fastrand", + "futures-lite", + "pin-project-lite", "slab", ] @@ -125,89 +112,59 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ - "async-channel 2.3.1", + "async-channel 2.5.0", "async-executor", - "async-io 2.3.4", - "async-lock 3.4.0", + "async-io", + "async-lock", "blocking", - "futures-lite 2.3.0", + "futures-lite", "once_cell", ] [[package]] name = "async-io" -version = "1.13.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" dependencies = [ - "async-lock 2.8.0", "autocfg", "cfg-if", "concurrent-queue", - "futures-lite 1.13.0", - "log", - "parking", - "polling 2.8.0", - "rustix 0.37.27", - "slab", - "socket2", - "waker-fn", -] - -[[package]] -name = "async-io" -version = "2.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" -dependencies = [ - "async-lock 3.4.0", - "cfg-if", - "concurrent-queue", "futures-io", - "futures-lite 2.3.0", + "futures-lite", "parking", - "polling 3.7.3", - "rustix 0.38.34", + "polling", + "rustix", "slab", - "tracing", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "async-lock" -version = "2.8.0" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" dependencies = [ - "event-listener 2.5.3", -] - -[[package]] -name = "async-lock" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" -dependencies = [ - "event-listener 5.3.1", + "event-listener 5.4.1", "event-listener-strategy", "pin-project-lite", ] [[package]] name = "async-std" -version = "1.12.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +checksum = "2c8e079a4ab67ae52b7403632e4618815d6db36d2a010cfe41b02c1b1578f93b" dependencies = [ "async-channel 1.9.0", "async-global-executor", - "async-io 1.13.0", - "async-lock 2.8.0", + "async-io", + "async-lock", "crossbeam-utils", "futures-channel", "futures-core", "futures-io", - "futures-lite 1.13.0", + "futures-lite", "gloo-timers", "kv-log-macro", "log", @@ -233,73 +190,46 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" - -[[package]] -name = "backtrace" -version = "0.3.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - -[[package]] -name = "bitflags" -version = "1.3.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "blocking" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" dependencies = [ - "async-channel 2.3.1", + "async-channel 2.5.0", "async-task", "futures-io", - "futures-lite 2.3.0", + "futures-lite", "piper", ] [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "clap" -version = "4.5.15" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d8838454fda655dafd3accb2b6e2bea645b9e4078abe84a22ceb947235c5cc" +checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" dependencies = [ "clap_builder", "clap_derive", @@ -307,9 +237,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.15" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" +checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" dependencies = [ "anstream", "anstyle", @@ -319,9 +249,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.13" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" dependencies = [ "heck", "proc-macro2", @@ -331,15 +261,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "concurrent-queue" @@ -352,18 +282,18 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -374,9 +304,9 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" -version = "5.3.1" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" dependencies = [ "concurrent-queue", "parking", @@ -385,34 +315,25 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.5.2" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ - "event-listener 5.3.1", + "event-listener 5.4.1", "pin-project-lite", ] [[package]] name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - -[[package]] -name = "fastrand" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -425,9 +346,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -435,15 +356,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -452,32 +373,17 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" -version = "1.13.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" dependencies = [ - "fastrand 1.9.0", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] - -[[package]] -name = "futures-lite" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" -dependencies = [ - "fastrand 2.1.0", + "fastrand", "futures-core", "futures-io", "parking", @@ -486,9 +392,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", @@ -497,21 +403,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -527,26 +433,20 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", "wasi", ] -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - [[package]] name = "gloo-timers" -version = "0.2.6" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" dependencies = [ "futures-channel", "futures-core", @@ -562,71 +462,38 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "hermit-abi" -version = "0.4.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "indoc" -version = "2.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" - -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi 0.3.9", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "io-uring" -version = "0.7.10" +version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" dependencies = [ - "bitflags 2.6.0", - "cfg-if", - "libc", + "rustversion", ] [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -646,36 +513,30 @@ source = "git+https://github.com/agentelement/lambda_calculus?branch=size-feat#8 [[package]] name = "libc" -version = "0.2.176" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "linux-raw-sys" -version = "0.3.8" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - -[[package]] -name = "linux-raw-sys" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "log" -version = "0.4.22" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" dependencies = [ "value-bag", ] [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "memoffset" @@ -687,51 +548,28 @@ dependencies = [ ] [[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", -] - -[[package]] -name = "mio" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" -dependencies = [ - "libc", - "wasi", - "windows-sys 0.59.0", -] - -[[package]] -name = "object" -version = "0.36.7" +name = "once_cell" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] -name = "once_cell" -version = "1.19.0" +name = "once_cell_polyfill" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "parking" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -746,39 +584,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" dependencies = [ "atomic-waker", - "fastrand 2.1.0", + "fastrand", "futures-io", ] [[package]] name = "polling" -version = "2.8.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" dependencies = [ - "autocfg", - "bitflags 1.3.2", "cfg-if", "concurrent-queue", - "libc", - "log", + "hermit-abi", "pin-project-lite", - "windows-sys 0.48.0", -] - -[[package]] -name = "polling" -version = "3.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" -dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi 0.4.0", - "pin-project-lite", - "rustix 0.38.34", - "tracing", - "windows-sys 0.59.0", + "rustix", + "windows-sys 0.61.2", ] [[package]] @@ -789,27 +610,27 @@ checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ "zerocopy", ] [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] [[package]] name = "pyo3" -version = "0.22.6" +version = "0.23.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f402062616ab18202ae8319da13fa4279883a2b8a9d9f83f20dbade813ce1884" +checksum = "7778bffd85cf38175ac1f545509665d0b9b92a198ca7941f131f85f7a4f9a872" dependencies = [ "cfg-if", "indoc", @@ -825,9 +646,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.22.6" +version = "0.23.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b14b5775b5ff446dd1056212d778012cbe8a0fbffd368029fd9e25b514479c38" +checksum = "94f6cbe86ef3bf18998d9df6e0f3fc1050a8c5efa409bf712e661a4366e010fb" dependencies = [ "once_cell", "target-lexicon", @@ -835,9 +656,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.22.6" +version = "0.23.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ab5bcf04a2cdcbb50c7d6105de943f543f9ed92af55818fd17b660390fc8636" +checksum = "e9f1b4c431c0bb1c8fb0a338709859eed0d030ff6daa34368d3b152a63dfdd8d" dependencies = [ "libc", "pyo3-build-config", @@ -845,9 +666,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.22.6" +version = "0.23.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fd24d897903a9e6d80b968368a34e1525aeb719d568dba8b3d4bfa5dc67d453" +checksum = "fbc2201328f63c4710f68abdf653c89d8dbc2858b88c5d88b0ff38a75288a9da" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -857,9 +678,9 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.22.6" +version = "0.23.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c011a03ba1e50152b4b394b479826cad97e7a21eb52df179cd91ac411cbfbe" +checksum = "fca6726ad0f3da9c9de093d6f116a93c1a38e417ed73bf138472cf4064f72028" dependencies = [ "heck", "proc-macro2", @@ -870,9 +691,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.36" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] @@ -907,59 +728,55 @@ dependencies = [ "getrandom", ] -[[package]] -name = "rustc-demangle" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" - [[package]] name = "rustix" -version = "0.37.27" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "bitflags 1.3.2", + "bitflags", "errno", - "io-lifetimes", "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", + "linux-raw-sys", + "windows-sys 0.61.2", ] [[package]] -name = "rustix" -version = "0.38.34" +name = "rustversion" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" -dependencies = [ - "bitflags 2.6.0", - "errno", - "libc", - "linux-raw-sys 0.4.14", - "windows-sys 0.52.0", -] +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "serde" -version = "1.0.207" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5665e14a49a4ea1b91029ba7d3bca9f299e1f7cfa194388ccc20f14743e784f2" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.207" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aea2634c86b0e8ef2cfdc0c340baede54ec27b1e46febd7f80dffb2aa44a00e" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -968,34 +785,22 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.124" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66ad62847a56b3dba58cc891acd13884b9c61138d330c0d7b6181713d4fce38d" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "socket2" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "strsim" @@ -1005,9 +810,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.106" +version = "2.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" dependencies = [ "proc-macro2", "quote", @@ -1022,39 +827,18 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tokio" -version = "1.47.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" -dependencies = [ - "backtrace", - "io-uring", - "libc", - "mio", - "pin-project-lite", - "slab", -] - -[[package]] -name = "tracing" -version = "0.1.40" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ "pin-project-lite", - "tracing-core", ] -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" - [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unindent" @@ -1070,65 +854,47 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "value-bag" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" - -[[package]] -name = "waker-fn" -version = "1.2.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" +checksum = "943ce29a8a743eb10d6082545d861b24f9d1b160b7d741e0f2cdf726bec909c5" [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.43" +version = "0.4.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1136,218 +902,139 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" +dependencies = [ + "unicode-ident", +] [[package]] name = "web-sys" -version = "0.3.70" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" dependencies = [ "js-sys", "wasm-bindgen", ] [[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" +name = "windows-link" +version = "0.2.1" 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" - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-sys" -version = "0.52.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-link", ] [[package]] name = "windows-targets" -version = "0.52.6" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows-link", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" -version = "0.48.5" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" -version = "0.48.5" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" -version = "0.52.6" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" -version = "0.48.5" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" -version = "0.52.6" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "zerocopy" -version = "0.7.35" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ - "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 50741a6..57b9d35 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ name = "alchemy" python-source = "python" [dependencies] -pyo3 = { version = "0.22", features = ["extension-module", "abi3-py37"] } +pyo3 = { version = "0.23.5", features = ["extension-module", "abi3-py37"] } async-std = "1.12.0" clap = { version = "4.5.4", features = ["derive"] } futures = "0.3.30" @@ -26,7 +26,7 @@ serde_json = "1.0.117" tokio = "1.39.2" [build-dependencies] -pyo3-build-config = "0.22" +pyo3-build-config = "0.23.5" [features] extension-module = ["pyo3/extension-module"] diff --git a/src/generators.rs b/src/generators.rs index ed6b3fd..9ba7a27 100644 --- a/src/generators.rs +++ b/src/generators.rs @@ -167,6 +167,8 @@ pub struct FontanaGen { seed: [u8; 32], rng: ChaCha8Rng, + + std: Standardization, } impl FontanaGen { @@ -203,6 +205,7 @@ impl FontanaGen { max_vars, seed, rng: ChaCha8Rng::from_seed(seed), + std: Standardization::Prefix, } } @@ -228,7 +231,13 @@ impl FontanaGen { pub fn generate(&mut self) -> Term { // <-- not Option - self.rand_lambda(0, self.abs_prob.0, self.app_prob.0) + let lambda = self.rand_lambda(0, self.abs_prob.0, self.app_prob.0); + + match self.std { + Standardization::Prefix => Self::prefix_standardize(lambda), + Standardization::Postfix => Self::postfix_standardize(lambda), + Standardization::None => lambda, + } } pub fn generate_n(&mut self, n: usize) -> Vec { @@ -296,4 +305,15 @@ impl FontanaGen { }; Term::Var(value) } + + fn prefix_standardize(mut t: Term) -> Term { + while t.has_free_variables() { + t = Term::Abs(Box::new(t)) + } + t +} + + fn postfix_standardize(_t: Term) -> Term { + unimplemented!("Postfix standardization is unimplemented!!!!") + } } From b1eda985010cbd02150741b33d4a9c2e5144fde2 Mon Sep 17 00:00:00 2001 From: jjoseph12 <72823288+jjoseph12@users.noreply.github.com> Date: Thu, 13 Nov 2025 12:38:04 -0700 Subject: [PATCH 22/23] fix(lambda): correct collision metrics tuple order in nonrecursive colliders (#8) - Store tuple as (expr, reductions, size) to align with collectors - Affects src/lambda/recursive.rs and src/lambda/core.rs --- src/lambda/core.rs | 2 +- src/lambda/recursive.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lambda/core.rs b/src/lambda/core.rs index 186962e..13b8a8e 100644 --- a/src/lambda/core.rs +++ b/src/lambda/core.rs @@ -157,7 +157,7 @@ impl AlchemyCollider { let expr = LambdaParticle { expr }; - collision_results.push((expr, size, n)) + collision_results.push((expr, n, size)) } Ok(LambdaCollisionOk { results: collision_results.iter().map(|t| t.0.clone()).collect(), diff --git a/src/lambda/recursive.rs b/src/lambda/recursive.rs index 5a7404e..76c5016 100644 --- a/src/lambda/recursive.rs +++ b/src/lambda/recursive.rs @@ -224,7 +224,7 @@ impl AlchemyCollider { recursive: false, }; - collision_results.push((expr, size, n)) + collision_results.push((expr, n, size)) } Ok(LambdaCollisionOk { results: collision_results.iter().map(|t| t.0.clone()).collect(), From 1e9dc6c45aef9725557d58281063aa27f1698329 Mon Sep 17 00:00:00 2001 From: jjoseph12 <72823288+jjoseph12@users.noreply.github.com> Date: Thu, 13 Nov 2025 12:38:05 -0700 Subject: [PATCH 23/23] fix(analysis): use multiset Jaccard union for denominator (#9) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Union = |A| + |B| - |A ∩ B| - Guard empty-empty case to return 1.0 --- src/analysis.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/analysis.rs b/src/analysis.rs index 5a08dcf..79b83a3 100644 --- a/src/analysis.rs +++ b/src/analysis.rs @@ -58,12 +58,19 @@ impl LambdaSoup { let selfcounts = self.expression_counts(); let othercounts = other.expression_counts(); - let mut intersection = 0; + let mut intersection: u32 = 0; for (k, v) in selfcounts { if let Some(c) = othercounts.get(&k) { intersection += c.min(&v); } } - (intersection as f32) / ((self.len() + other.len()) as f32) + // Jaccard for multisets: |A ∩ B| / |A ∪ B|, + // where ∩ is sum of mins and ∪ is sum of maxes. + // Using identity: sum(max) = |A| + |B| - sum(min). + let union = self.len() + other.len() - intersection as usize; + if union == 0 { + return 1.0; // both empty → treat as identical + } + (intersection as f32) / (union as f32) } }