Giter Site home page Giter Site logo

nengo-rs's Introduction

Nengo RS

Nengo RS is an experimental Nengo backend written in Rust.

This was a purely experimental project that I used to learn Rust (and it really did its job in this regard). It is in no-way suitable for production, missing several features, and not even faster than the Python reference implementation!

Getting started

Clone the repository and run:

pip install maturin
maturin develop

To run the rust tests:

cargo test

To run the bundled Python tests:

pytest

To run the Nengo tests against the provided backend (only a subset will succeed):

pytest --pyargs nengo

To use the Nengo RS backend in your Python code:

import nengo_rs

with nengo_rs.Simulator(model) as sim:
    sim.run(duration)

Be aware that the Simulator interface is only partially implemented. In particular, the seed argument is not respected.

Approach and limitations

To implement a minimal working Nengo backend with reasonable effort, I am using the Python reference backend to build the model, and convert the signals and operators into Rust equivalents. The optimization step is currently skipped as it would require an additional operator (BsrDotInc) to be implemented.

Operator execution is scheduled with asynchronous tasks using async/await which allows to somewhat nicely wait for operators providing dependency signals to be done. However, it is not clear whether this actually improves performance through parallelization or the scheduling overhead is too much.

Though, the largest bottlenecks at the moment, should be the missing support for the optimizer, and that some core operators call back into Python. All of SimNeurons, SimProcess, and SimPyFunc execute within the Python interpreter. While we cannot get around that for SimPyFunc, it would be possible to fully implement SimNeurons and SimProcess in Rust for a given set of processes and neuron types.

One of my major gripes with the current implementation is that it is not well suited for Rusts memory model with ownership and borrow checking. Essentially, each signal is a block of shared memory and not owned by a single operator. Thus, there is certain syntax overhead with that. In addition, the current approach requires to map between the Python signals/operators and the Rust equivalents, adding another level of sharing.

Operators do not only use owned signals, but access views of these signals. For a view in Rust in must be ensured that the owned array outlives the view which is not really possible due to the shared ownership. Thus it is necessary to use a custom struct to track owned arrays and views (ArrayRef) and only resolve these when needed. Gives two arrays/views and an operation, there are four combinations of what is an owned array or view. In effect this leads to a lot of boilerplate that I also do not find highly readable.

I think at least two things are required to remedy this situation:

  1. Implement the builder itself in Rust, so that the signals/operators can fully live in Rust and no mapping with Python instances is required.
  2. Operators do not keep references to their signals, but the "engine" owns the signals and lends them to the operator functions when it is their respective time to run.

Maybe I will try such an implementation one day, but for now I will turn towards other projects.

nengo-rs's People

Contributors

jgosmann avatar

Stargazers

 avatar

Watchers

 avatar  avatar  avatar

nengo-rs's Issues

Implement fallback operator

It might make sense to implement an operator that can be used as drop in for any other operator if there is no Rust implementation. It would need to call out to the original Python operator to do the processing.

build failed with ndarray v0.14.0

Hello, just tried to build it and got build errors, steps to reproduce:

git clone https://github.com/jgosmann/nengo-rs
...
cargo build
...
  Downloaded ndarray v0.14.0
...
   Compiling ndarray v0.13.1
...
   Compiling nengo-rs v0.1.0 (.../github/nengo-rs)
error[E0308]: mismatched types
  --> src/binding/operator.rs:80:13
   |
80 |     {value: value.extract::<&PyArrayDyn<f64>>()?.to_owned_array()}
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `ArrayBase`, found struct `ndarray::ArrayBase`
   |
   = note: expected struct `ArrayBase<OwnedRepr<f64>, Dim<IxDynImpl>>`
              found struct `ndarray::ArrayBase<ndarray::data_repr::OwnedRepr<f64>, ndarray::dimension::dim::Dim<ndarray::dimension::dynindeximpl::IxDynImpl>>`
   = note: perhaps two different versions of crate `ndarray` are being used?

error[E0308]: mismatched types
  --> src/binding/probe.rs:49:52
   |
49 |                 copy.as_array_mut().index_axis_mut(Axis(0), i).assign(x);
   |                                                    ^^^^^^^ expected struct `ndarray::dimension::axis::Axis`, found struct `Axis`
   |
   = note: perhaps two different versions of crate `ndarray` are being used?

error[E0308]: mismatched types
  --> src/binding/probe.rs:49:71
   |
49 |                 copy.as_array_mut().index_axis_mut(Axis(0), i).assign(x);
   |                                                                       ^ expected struct `ndarray::ArrayBase`, found struct `ArrayBase`
   |
   = note: expected reference `&ndarray::ArrayBase<_, _>`
              found reference `&ArrayBase<OwnedRepr<f64>, Dim<IxDynImpl>>`
   = note: perhaps two different versions of crate `ndarray` are being used?

error[E0308]: mismatched types
  --> src/operator/sim_neurons.rs:48:33
   |
48 |         output_sig.assign_array(&output.readonly().as_array());
   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `ArrayBase`, found struct `ndarray::ArrayBase`
   |
   = note: expected reference `&ArrayBase<_, _>`
              found reference `&ndarray::ArrayBase<ndarray::ViewRepr<&_>, ndarray::dimension::dim::Dim<ndarray::dimension::dynindeximpl::IxDynImpl>>`
   = note: perhaps two different versions of crate `ndarray` are being used?
...

Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.