{"id":19289912,"url":"https://github.com/asynchronics/nexosim","last_synced_at":"2025-04-22T05:32:06.047Z","repository":{"id":65330921,"uuid":"549993272","full_name":"asynchronics/nexosim","owner":"asynchronics","description":"High-performance asynchronous computation framework for system simulation","archived":false,"fork":false,"pushed_at":"2025-04-14T10:16:35.000Z","size":807,"stargazers_count":214,"open_issues_count":3,"forks_count":13,"subscribers_count":8,"default_branch":"main","last_synced_at":"2025-04-14T11:28:36.512Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/asynchronics.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-10-12T03:30:20.000Z","updated_at":"2025-04-14T10:16:39.000Z","dependencies_parsed_at":"2024-05-28T01:29:26.848Z","dependency_job_id":"1f88308b-5b6f-4c3f-ad6c-080f61a66ec6","html_url":"https://github.com/asynchronics/nexosim","commit_stats":{"total_commits":50,"total_committers":3,"mean_commits":"16.666666666666668","dds":0.14,"last_synced_commit":"4039d96127764be32c976adc2a8da06613fa9ba4"},"previous_names":["asynchronics/nexosim","asynchronics/asynchronix"],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asynchronics%2Fnexosim","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asynchronics%2Fnexosim/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asynchronics%2Fnexosim/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asynchronics%2Fnexosim/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/asynchronics","download_url":"https://codeload.github.com/asynchronics/nexosim/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250175077,"owners_count":21387133,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T22:17:24.816Z","updated_at":"2025-04-22T05:32:06.034Z","avatar_url":"https://github.com/asynchronics.png","language":"Rust","funding_links":[],"categories":["Uncategorized","\u003ca name=\"Rust\"\u003e\u003c/a\u003eRust"],"sub_categories":["Uncategorized"],"readme":"# NeXosim\n\nNeXosim (né Asynchronix) is a developer-friendly, highly optimized\ndiscrete-event simulation framework written in Rust. It is meant to scale from\nsmall, simple simulations to very large simulation benches with complex\ntime-driven state machines.\n\n\n## 🎉🥳 NeXosim 0.3.1 is out! 🚀🛰️\n\nSee the [changelog](CHANGELOG.md) for a summary of new features, or head to the extensive [API documentation][API] for the details.\n\n[![Cargo](https://img.shields.io/crates/v/nexosim.svg)](https://crates.io/crates/nexosim)\n[![Documentation](https://docs.rs/nexosim/badge.svg)](https://docs.rs/nexosim)\n[![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)](https://github.com/asynchronics/nexosim#license)\n\n\n## Overview\n\nNeXosim is a simulator that leverages asynchronous programming to\ntransparently and efficiently auto-parallelize simulations by means of a custom\nmulti-threaded executor.\n\nIt promotes a component-oriented architecture that is familiar to system\nengineers and closely resembles [flow-based programming][FBP]: a model is\nessentially an isolated entity with a fixed set of typed inputs and outputs,\ncommunicating with other models through message passing via connections defined\nduring bench assembly.\n\nAlthough the main impetus for its development was the need for simulators able\nto handle large cyberphysical systems, NeXosim is a general-purpose\ndiscrete-event simulator expected to be suitable for a wide range of simulation\nactivities. It draws from experience on spacecraft real-time simulators but\ndiffers from existing tools in the space industry in a number of respects,\nincluding:\n\n1) *performance*: by taking advantage of Rust's excellent support for\n   multithreading and asynchronous programming, simulation models can run\n   efficiently in parallel with all required synchronization being transparently\n   handled by the simulator,\n2) *developer-friendliness*: an ergonomic API and Rust's support for algebraic\n   types make it ideal for the \"cyber\" part in cyberphysical, i.e. for modelling\n   digital devices with even very complex state machines,\n3) *open-source*: last but not least, NeXosim is distributed under the very\n   permissive MIT and Apache 2 licenses, with the explicit intent to foster an\n   ecosystem where models can be easily exchanged without reliance on\n   proprietary APIs.\n\n[FBP]: https://en.wikipedia.org/wiki/Flow-based_programming\n\n\n## Documentation\n\nThe [API] documentation is relatively exhaustive and includes a practical\noverview which should provide all necessary information to get started.\n\nMore fleshed out examples can also be found in the dedicated\n[simulator](nexosim/examples) and [utilities](nexosim-util/examples)\ndirectories.\n\n[API]: https://docs.rs/nexosim\n\n\n## Usage\n\nTo use the latest version, add to your `Cargo.toml`:\n\n```toml\n[dependencies]\nnexosim = \"0.3.1\"\n```\n\n\n## Example\n\n```rust\n// A system made of 2 identical models.\n// Each model is a 2× multiplier with an output delayed by 1s.\n//\n//              ┌──────────────┐      ┌──────────────┐\n//              │              │      │              │\n// Input ●─────►│ multiplier 1 ├─────►│ multiplier 2 ├─────► Output\n//              │              │      │              │\n//              └──────────────┘      └──────────────┘\nuse std::time::Duration;\n\nuse nexosim::model::{Context, Model};\nuse nexosim::ports::{EventSlot, Output};\nuse nexosim::simulation::{Mailbox, SimInit, SimulationError};\nuse nexosim::time::MonotonicTime;\n\n// A model that doubles its input and forwards it with a 1s delay.\n#[derive(Default)]\npub struct DelayedMultiplier {\n    pub output: Output\u003cf64\u003e,\n}\nimpl DelayedMultiplier {\n    pub fn input(\u0026mut self, value: f64, ctx: \u0026mut Context\u003cSelf\u003e) {\n        ctx.schedule_event(Duration::from_secs(1), Self::send, 2.0 * value)\n            .unwrap();\n    }\n    async fn send(\u0026mut self, value: f64) {\n        self.output.send(value).await;\n    }\n}\nimpl Model for DelayedMultiplier {}\n\nfn main() -\u003e Result\u003c(), SimulationError\u003e {\n    // Instantiate models and their mailboxes.\n    let mut multiplier1 = DelayedMultiplier::default();\n    let mut multiplier2 = DelayedMultiplier::default();\n    let multiplier1_mbox = Mailbox::new();\n    let multiplier2_mbox = Mailbox::new();\n\n    // Connect the output of `multiplier1` to the input of `multiplier2`.\n    multiplier1\n        .output\n        .connect(DelayedMultiplier::input, \u0026multiplier2_mbox);\n\n    // Keep handles to the main input and output.\n    let mut output_slot = EventSlot::new();\n    multiplier2.output.connect_sink(\u0026output_slot);\n    let input_address = multiplier1_mbox.address();\n\n    // Instantiate the simulator\n    let t0 = MonotonicTime::EPOCH; // arbitrary start time\n    let mut simu = SimInit::new()\n        .add_model(multiplier1, multiplier1_mbox, \"multiplier 1\")\n        .add_model(multiplier2, multiplier2_mbox, \"multiplier 2\")\n        .init(t0)?\n        .0;\n\n    // Send a value to the first multiplier.\n    simu.process_event(DelayedMultiplier::input, 3.5, \u0026input_address)?;\n\n    // Advance time to the next event.\n    simu.step()?;\n    assert_eq!(simu.time(), t0 + Duration::from_secs(1));\n    assert_eq!(output_slot.next(), None);\n\n    // Advance time to the next event.\n    simu.step()?;\n    assert_eq!(simu.time(), t0 + Duration::from_secs(2));\n    assert_eq!(output_slot.next(), Some(14.0));\n\n    Ok(())\n}\n```\n\n# Implementation notes\n\nUnder the hood, NeXosim is based on an asynchronous implementation of the\n[actor model][actor_model], where each simulation model is an actor. The\nmessages actually exchanged between models are `async` closures which capture\nthe event's or request's value and take the model as `\u0026mut self` argument. The\nmailbox associated to a model and to which closures are forwarded is the\nreceiver of an async, bounded MPSC channel.\n\nComputations proceed at discrete times. When executed, models can request the\nscheduler to send an event (or rather, a closure capturing such event) at a\ncertain simulation time. Whenever computations for the current time complete,\nthe scheduler selects the nearest future time at which one or several events are\nscheduled (*next event increment*), thus triggering another set of computations.\n\nThis computational process makes it difficult to use general-purposes\nasynchronous runtimes such as [Tokio][tokio], because the end of a set of\ncomputations is technically a deadlock: the computation completes when all model\nhave nothing left to do and are blocked on an empty mailbox. Also, instead of\nmanaging a conventional reactor, the runtime manages a priority queue containing\nthe posted events. For these reasons, NeXosim relies on a fully custom\nruntime.\n\nEven though the runtime was largely influenced by Tokio, it features additional\noptimizations that make its faster than any other multi-threaded Rust executor\non the typically message-passing-heavy workloads seen in discrete-event\nsimulation (see [benchmark]). NeXosim also improves over the state of the\nart with a very fast custom MPSC channel, which performance has been\ndemonstrated through [Tachyonix][tachyonix], a general-purpose offshoot of this\nchannel.\n\n[actor_model]: https://en.wikipedia.org/wiki/Actor_model\n\n[tokio]: https://github.com/tokio-rs/tokio\n\n[tachyonix]: https://github.com/asynchronics/tachyonix\n\n[benchmark]: https://github.com/asynchronics/tachyobench\n\n\n## License\n\nThis software is licensed under the [Apache License, Version 2.0](LICENSE-APACHE) or the\n[MIT license](LICENSE-MIT), at your option.\n\n\n## Contribution\n\nUnless you explicitly state otherwise, any contribution intentionally submitted\nfor inclusion in the work by you, as defined in the Apache-2.0 license, shall be\ndual licensed as above, without any additional terms or conditions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fasynchronics%2Fnexosim","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fasynchronics%2Fnexosim","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fasynchronics%2Fnexosim/lists"}