Initial files added

This commit is contained in:
Diane Blackwood 2025-09-24 01:07:28 -04:00
parent 84cdfe83c4
commit d3d0b9ba83
22 changed files with 629 additions and 1 deletions

View File

@ -0,0 +1,26 @@
{
"name": "MabeLabRS Dev",
"dockerComposeFile": "../docker-compose.yml",
"service": "dev",
"workspaceFolder": "/work",
"features": {
"ghcr.io/devcontainers/features/common-utils:2": {}
},
"settings": {
"terminal.integrated.defaultProfile.linux": "bash",
"rust-analyzer.cargo.useRustcWrapperForBuildScripts": true
},
"customizations": {
"vscode": {
"extensions": [
"rust-lang.rust-analyzer",
"tamasfe.even-better-toml",
"serayuzgur.crates",
"matklad.rust-analyzer",
"ms-azuretools.vscode-docker"
]
}
},
"remoteUser": "dev"
}

14
.dockerignore Normal file
View File

@ -0,0 +1,14 @@
target
**/target
**/*.rs.bk
**/*.swp
**/*.swo
**/.DS_Store
.git
.gitignore
.forgejo
node_modules
.idea
.vscode
**/.cache
.sccache

24
.forgejo/workflows/ci.yml Normal file
View File

@ -0,0 +1,24 @@
name: CI
on:
push:
branches: [ main, porting ]
pull_request:
branches: [ main, porting ]
jobs:
rust:
runs-on: docker
container:
image: mabelabrs-dev:latest
# If your Forgejo runner can't pull local images, add a previous step
# to `docker build -f Dockerfile.dev -t mabelabrs-dev:latest .`
steps:
- uses: actions/checkout@v4
- name: Build
run: cargo build --workspace --all-targets
- name: Clippy
run: cargo clippy --workspace --all-targets -- -D warnings
- name: Test
run: cargo test --workspace --all-features --no-fail-fast

17
ACKNOWLEDGEMENTS.md Normal file
View File

@ -0,0 +1,17 @@
# Acknowledgements
MabeLabRS is a Rust port inspired by:
- **MABE2** (https://github.com/mercere99/MABE2)
Copyright (c) 2016present Charles Ofria and MABE contributors
Licensed under the MIT License.
- **Empirical** (https://github.com/devosoft/Empirical)
Copyright (c) 2014present Charles Ofria and Empirical contributors
Licensed under the MIT License.
This project is independent and not officially affiliated with the upstream
projects, but it draws architectural concepts and design inspiration from them.
We gratefully acknowledge the work of the original authors and contributors.

10
Cargo.toml Normal file
View File

@ -0,0 +1,10 @@
[workspace]
members = [
"crates/mabelabrs-core",
"crates/mabelabrs-world",
"crates/mabelabrs-eval",
"crates/mabelabrs-io",
"crates/mabelabrs-utils",
"crates/mabelabrs-ffi",
]
resolver = "2"

24
DETERMINISM.md Normal file
View File

@ -0,0 +1,24 @@
# Determinism Policy
MabeLabRS emphasizes reproducibility of artificial life experiments.
## Randomness
- Use `rand_chacha::ChaCha8Rng` (fast, reproducible).
- Seeds must be explicit and logged in experiment manifests.
## Floating-point
- Default: `f64`.
- Avoid nondeterministic parallel reductions; when needed, gate behind
the `fast-math` feature.
- Golden tests should tolerate ≤ 1e-12 relative error in float comparisons.
## Collections
- Use `BTreeMap`/`BTreeSet` when deterministic ordering is required.
- Use `indexmap::IndexMap`/`IndexSet` for hash-backed structures
that preserve insertion order.
## Parallelism
- Sequential by default.
- `rayon` parallelism only behind `parallel` feature flag.
- Golden tests must run with `--no-default-features` to guarantee determinism.

35
Dockerfile.dev Normal file
View File

@ -0,0 +1,35 @@
# Developer image: Rust + build tools + sccache + minimal deps
FROM rust:1-bookworm
# Install useful build deps and tooling
RUN apt-get update && apt-get install -y --no-install-recommends \
clang cmake pkg-config libssl-dev git ca-certificates curl \
&& rm -rf /var/lib/apt/lists/*
# sccache speeds up incremental builds across container runs
ENV SCCACHE_DIR=/root/.cache/sccache
RUN cargo install sccache
# Configure rustc to use sccache by default
ENV RUSTC_WRAPPER=/usr/local/cargo/bin/sccache
ENV CARGO_INCREMENTAL=0
# Optional: set a default toolchain (can be overridden by rust-toolchain.toml)
RUN rustup component add clippy rustfmt
# Create a non-root user (optional; comment out if you prefer root)
RUN useradd -m -u 1000 dev
USER dev
WORKDIR /work
# Cache hints: create empty project files so first build primes caches
COPY --chown=dev:dev Cargo.toml ./
COPY --chown=dev:dev crates/mabelabrs-core/Cargo.toml crates/mabelabrs-core/Cargo.toml
COPY --chown=dev:dev crates/mabelabrs-world/Cargo.toml crates/mabelabrs-world/Cargo.toml
COPY --chown=dev:dev crates/mabelabrs-eval/Cargo.toml crates/mabelabrs-eval/Cargo.toml
COPY --chown=dev:dev crates/mabelabrs-io/Cargo.toml crates/mabelabrs-io/Cargo.toml
COPY --chown=dev:dev crates/mabelabrs-utils/Cargo.toml crates/mabelabrs-utils/Cargo.toml
COPY --chown=dev:dev crates/mabelabrs-ffi/Cargo.toml crates/mabelabrs-ffi/Cargo.toml
# Final copy happens at runtime via bind mount; this stage just primes caches.

44
Dockerfile.release Normal file
View File

@ -0,0 +1,44 @@
# Build stage
FROM rust:1-bookworm as builder
RUN apt-get update && apt-get install -y --no-install-recommends \
clang cmake pkg-config libssl-dev git ca-certificates curl \
&& rm -rf /var/lib/apt/lists/*
# sccache optional in release, but still useful for CI
RUN cargo install sccache
ENV RUSTC_WRAPPER=/usr/local/cargo/bin/sccache
WORKDIR /work
# Copy manifests first to leverage Docker layer caching
COPY Cargo.toml Cargo.lock ./
COPY crates/mabelabrs-core/Cargo.toml crates/mabelabrs-core/Cargo.toml
COPY crates/mabelabrs-world/Cargo.toml crates/mabelabrs-world/Cargo.toml
COPY crates/mabelabrs-eval/Cargo.toml crates/mabelabrs-eval/Cargo.toml
COPY crates/mabelabrs-io/Cargo.toml crates/mabelabrs-io/Cargo.toml
COPY crates/mabelabrs-utils/Cargo.toml crates/mabelabrs-utils/Cargo.toml
COPY crates/mabelabrs-ffi/Cargo.toml crates/mabelabrs-ffi/Cargo.toml
# Create empty src to allow dependency build caching
RUN mkdir -p crates/mabelabrs-utils/src && echo "fn main(){}" > crates/mabelabrs-utils/src/main.rs
# Build deps
RUN cargo build -p mabelabrs-utils --release || true
# Now copy the whole source and do the real build
COPY . .
RUN cargo build -p mabelabrs-utils --release
# Runtime stage (distroless-ish; use slim for better debugability)
FROM debian:bookworm-slim
# If your CLI needs SSL/DNS, keep these minimal libs
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates libssl3 && rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY --from=builder /work/target/release/mabelabrs-utils /usr/local/bin/mabelabrs-utils
ENTRYPOINT ["/usr/local/bin/mabelabrs-utils"]
CMD ["--help"]

20
LICENSE-Apache Normal file
View File

@ -0,0 +1,20 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
Copyright 2025 Wesley R. Elsberry and MabeLabRS Contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

22
LICENSE-MIT Normal file
View File

@ -0,0 +1,22 @@
MIT License
Copyright (c) 2025 Wesley R. Elsberry and MabeLabRS Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

29
Makefile Normal file
View File

@ -0,0 +1,29 @@
SHELL := /bin/bash
.PHONY: build test clippy fmt ci shell clean release
# Open an interactive shell in the dev container
shell:
\tdocker compose run --rm dev bash
build:
\tdocker compose run --rm dev bash -lc "cargo build --workspace --all-targets"
test:
\tdocker compose run --rm dev bash -lc "cargo test --workspace --all-features --no-fail-fast"
clippy:
\tdocker compose run --rm dev bash -lc "cargo clippy --workspace --all-targets -- -D warnings"
fmt:
\tdocker compose run --rm dev bash -lc "cargo fmt --all"
ci: fmt clippy build test
release:
\tdocker compose build release
clean:
\trm -rf target || true
\tdocker compose down --volumes --remove-orphans || true

180
README.md
View File

@ -1,2 +1,180 @@
# MABELab-RS
# MabeLabRS — a Rust port of MABE2
**MabeLabRS** is a Rust re-implementation of the MSU **MABE2** artificial life framework, aiming for:
- **API parity** where sensible, with a modern Rust design (traits, enums, safe concurrency).
- **Determinism** for research reproducibility (seeded RNG, stable iteration order).
- **Portability** to the web (WASM) for teaching demos (evo-edu.org) and outreach (TalkOrigins).
> Upstream: MABE2 (C++, MIT) — https://github.com/mercere99/MABE2
> This project is an independent port; see **License & Attribution** below.
---
## Project status
- 🚧 **Pre-alpha (porting in progress)** — core traits and module skeletons are landing first.
- 🎯 Goals: organism + genome abstractions, worlds/topologies, evaluators, experiment runner, config I/O, parity tests.
---
## Workspace layout
- mabelabrs/
- ├─ Cargo.toml # [workspace]
- ├─ rust-toolchain.toml # pin stable or MSRV
- ├─ LICENSE-APACHE
- ├─ LICENSE-MIT
- ├─ ACKNOWLEDGEMENTS.md
- ├─ README.md
- ├─ crates/
- │ ├─ mabelabrs-core/ # genomes, organisms, traits, RNG & schedulers
- │ ├─ mabelabrs-world/ # populations, environments, spatial/graph topologies
- │ ├─ mabelabrs-eval/ # tasks, fitness functions, analyzers
- │ ├─ mabelabrs-io/ # serde configs, logging, (bincode/json) state
- │ ├─ mabelabrs-utils/ # CLI runner, experiment manifests
- │ └─ mabelabrs-ffi/ # optional C++ bridge to MABE2 for parity (feature-gated)
- ├─ tests/
- │ ├─ golden/ # small deterministic fixtures
- │ └─ parity/ # cross-lang checks (behind ffi feature)
- ├─ benches/ # criterion benches for hotspots
- └─ porting/ # LLM-driven port tooling (only on porting branch)
- ├─ TRANSLATION_GLOSSARY.md
- ├─ STYLE.md
- ├─ DETERMINISM.md
- ├─ UNSAFE_POLICY.md
- ├─ prompts/
- └─ tools/ # scripts to run local LLM, compile, test, open PRs
---
## Why Rust?
- **Memory safety** and clear ownership models for complex evolutionary simulations.
- **Deterministic** iteration and seeded RNG for reproducibility.
- **Great tooling** (cargo, clippy, criterion, proptest) and easy WASM targets for classroom demos.
---
## Quick start
```bash
# clone
git clone <your-forgejo-url>/MabeLabRS.git
cd MabeLabRS
# build all crates
cargo build
# run tests
cargo test
# optional parity tests (requires C++ MABE2 + ffi feature)
cargo test -p mabelabrs-ffi --features ffi
Feature flags:
ffi — enable C++ bridge for cross-language parity tests.
fast-math — allow non-deterministic float reductions (off by default).
Determinism
RNG: rand_chacha (documented seed in experiment manifest).
Order-sensitive collections: indexmap where iteration order matters.
Parallelism: gated by feature flags (rayon), default serial to preserve bit-for-bit comparable runs.
Using with evo-edu.org / TalkOrigins
WASM builds will be provided as examples under examples/wasm/ for web-hosted demos and teaching modules.
Naming and metadata optimized for search discoverability: MabeLabRS / mabelabrs-* crates.
Contributing
Discuss issues in the tracker; claim a module before starting.
Follow STYLE.md and UNSAFE_POLICY.md.
Every PR must:
compile (cargo check),
be formatted (cargo fmt),
lint cleanly (cargo clippy -- -D warnings),
include tests for added behavior.
Deterministic tests belong in tests/golden/. Heavier regression and parity tests go in tests/parity/.
We welcome LLM-assisted contributions only if the result compiles and includes tests. Please include the prompt and model info in the PR description for provenance.
Branch strategy
main: always buildable; docs + examples meant for users.
porting: long-lived branch for translation scripts, FFI harnesses, and staged module ports.
Feature branches: feat/<module> or fix/<area>; merge into porting, and periodically milestone-merge porting → main when a vertical slice is stable (e.g., genome+mutation+simple world).
Protect main and porting with required checks.
License & Attribution
Port license: Dual MIT OR Apache-2.0 (choose at your option).
See LICENSE-MIT and LICENSE-APACHE.
Upstream attribution:
This project is a Rust port inspired by MABE2 (MIT) and conceptually by the Empirical library (MIT).
Copyright and license notices from upstream are preserved in ACKNOWLEDGEMENTS.md.
You may use MabeLabRS under the terms of MIT or Apache-2.0.
Citation
If you use MabeLabRS in academic work, please cite MABE2 as appropriate and this repository (commit or release tag). A CITATION.cff will be added at first release.
Roadmap (short)
Core traits: Genome, Organism, Evaluator, World, Scheduler
Config & manifests (serde + JSON/TOML)
Minimal world & evaluator example with golden tests
Optional ffi parity tests against MABE2
WASM demo example for evo-edu.org
First alpha release on crates.io
---
## Container-first workflow
This repo ships with a containerized toolchain for **development**, **testing**, and **releases**.
### Quick start (Dev container)
```bash
# one-time build of the dev image (with Rust toolchain, sccache, tools)
docker compose build dev
# launch an interactive dev shell with your repo mounted at /work
docker compose run --rm dev bash
# inside the container
cargo build
cargo test
cargo clippy -- -D warnings
# Generative AI Notice
This project is planned to be largely conducted through the use of generative AI tools,
including OpenAI ChatGPT. While the plan is to conduct testing, be aware that
generative AI may not be entirely accurate in its outputs, and determine suitability
to purpose incorporating this information.

28
STYLE.md Normal file
View File

@ -0,0 +1,28 @@
# MabeLabRS Style Guide
## Code formatting
- Use `cargo fmt` with `rustfmt.toml` in repo root.
- Line width: 100.
- Always use `#[derive(Debug, Clone, PartialEq, Eq)]` on simple data types.
## Naming
- Crates: `mabelabrs-*` prefix.
- Traits: `CamelCase`, no `I` prefix.
- Structs: `CamelCase`.
- Enums: `CamelCase` with variant `CamelCase`.
- Functions: `snake_case`.
## Error handling
- Return `Result<T, E>` from fallible functions.
- Use `thiserror` for error enums.
- Avoid panics, except in tests or truly unrecoverable states.
## Documentation
- All public items must have `///` doc comments.
- Modules should have a top-level `//!` doc comment.
## Testing
- Unit tests inline in modules (`#[cfg(test)]`).
- Integration tests in `/tests`.
- Deterministic golden tests in `/tests/golden`.

35
TRANSLATION_GLOSSARY.md Normal file
View File

@ -0,0 +1,35 @@
# Translation Glossary: C++ → Rust
This glossary defines consistent mappings from MABE2 / Empirical idioms
to MabeLabRS Rust code. It should be updated as the port progresses.
## Memory / Pointers
- `std::unique_ptr<T>``Box<T>`
- `std::shared_ptr<T>``Arc<T>` (multi-thread safe), or `Rc<T>` (single-thread)
- `std::weak_ptr<T>``Weak<T>` (Arc/Rc)
- raw pointer (owning) → `Box<T>`
- raw pointer (borrowed) → `&T` or `&mut T`
## Optional / Variants
- `std::optional<T>``Option<T>`
- `std::variant<A,B>``enum { A(A), B(B) }`
## Containers
- `std::vector<T>``Vec<T>`
- `std::map<K,V>``BTreeMap<K,V>` (ordered, deterministic)
- `std::unordered_map<K,V>``HashMap<K,V>` or `IndexMap<K,V>` (deterministic)
- `std::set<T>``BTreeSet<T>`
## Interfaces / Inheritance
- C++ abstract base class → Rust `trait`
- C++ pure virtual function → `fn ...;` in trait
- C++ virtual function → default method in trait
## Errors
- Error codes / exceptions → `Result<T, E>` with `thiserror` derive
## Utilities
- C++ RNG (emp::Random) → `rand_chacha::ChaCha8Rng` seeded via manifest
- Empirical Config → `serde` + `toml/json`
- Empirical Signals/Actions → strongly typed Rust event bus (observer pattern)

16
UNSAFE_POLICY.md Normal file
View File

@ -0,0 +1,16 @@
# Unsafe Code Policy
MabeLabRS is committed to safe Rust. Unsafe is allowed only when:
- It is proven necessary for performance in critical loops, and
- There is no safe alternative without excessive overhead, and
- The code is isolated in a single module with:
- Comments explaining invariants,
- Unit tests covering invariants,
- Reviewed by at least one maintainer.
All unsafe blocks must be justified with a doc comment.
Tools:
- Run `cargo geiger` in CI to track unsafe usage.

View File

@ -0,0 +1,12 @@
[package]
name = "mabelabrs-core"
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "Core traits and data structures for MabeLabRS"
[dependencies]
serde = { version = "1.0", features = ["derive"] }
thiserror = "1.0"
rand_chacha = "0.3"

View File

@ -0,0 +1,10 @@
//! Evaluator abstraction.
use crate::organism::Organism;
use crate::genome::Genome;
/// Trait for evaluating organisms in a population.
pub trait Evaluator<G: Genome, O: Organism<G>> {
/// Evaluate fitness of an organism.
fn evaluate(&self, organism: &O) -> f64;
}

View File

@ -0,0 +1,16 @@
//! Genome abstraction.
use serde::{Serialize, Deserialize};
/// Trait representing a genome in MabeLabRS.
pub trait Genome: Serialize + for<'de> Deserialize<'de> + Clone {
/// Mutate this genome in-place.
fn mutate(&mut self);
/// Return a deep copy of this genome.
fn copy(&self) -> Self;
/// Return a human-readable description.
fn describe(&self) -> String;
}

View File

@ -0,0 +1,9 @@
//! Core traits and data structures for MabeLabRS.
pub mod genome;
pub mod organism;
pub mod evaluator;
/// A unique identifier for genomes.
pub type GenomeId = u64;

View File

@ -0,0 +1,16 @@
//! Organism abstraction.
use crate::genome::Genome;
use serde::{Serialize, Deserialize};
/// Trait representing an organism composed of a genome.
pub trait Organism<G: Genome>: Serialize + for<'de> Deserialize<'de> {
/// Return a reference to the genome.
fn genome(&self) -> &G;
/// Return a mutable reference to the genome.
fn genome_mut(&mut self) -> &mut G;
/// Express the phenotype (to be defined by evaluator).
fn express(&self) -> String;
}

View File

@ -0,0 +1,6 @@
deploy:
resources:
reservations:
devices:
- capabilities: ["gpu"]

37
docker-compose.yml Normal file
View File

@ -0,0 +1,37 @@
version: "3.9"
services:
dev:
build:
context: .
dockerfile: Dockerfile.dev
image: mabelabrs-dev:latest
container_name: mabelabrs-dev
working_dir: /work
volumes:
- ./:/work
- sccache:/root/.cache/sccache
- cargo-registry:/usr/local/cargo/registry
- cargo-git:/usr/local/cargo/git
- target:/work/target
tty: true
environment:
- RUSTC_WRAPPER=/usr/local/cargo/bin/sccache
- CARGO_HOME=/usr/local/cargo
- RUST_LOG=info
release:
build:
context: .
dockerfile: Dockerfile.release
image: mabelabrs:latest
container_name: mabelabrs
# no source mount; uses built artifact
entrypoint: ["/usr/local/bin/mabelabrs-utils"]
command: ["--help"]
volumes:
sccache:
cargo-registry:
cargo-git:
target: