Skip to content
An AI control architecture framework for building autonomous decentralized systems (ADS).
Elixir
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
lib
test
.formatter.exs
.gitignore
License.md
README.md
mix.exs
particles.gif
sequence.png
sup_tree.png

README.md

⦿ | Automata | ⦿ ⦿ ⦿ ⦿ ⦿ ⦿ ⦿ ⦿

An AI control architecture framework for building autonomous decentralized systems (ADS).

Spawn a system of concurrent, distributed, fault tolerant, and highly available intelligent agents for coordinated and/or uncoordinated action in one or many environments with no central point of failure. This project is Open Source.

This project is in the Alpha stage and not ready for production systems. We need Contributors to get to 1.0! Please join the slack channel and/or reach out to ericsteen1@gmail.com if interested!

Implementation Overview

Technologies

Elixir & OTP provide the primitives for robust concurrent, fault-tolerant, highly available, self-healing distributed systems. Based on the Actor model, a singular Elixir Process embodies all 3 essential elements of computation: processing, storage, communications. It does so using very lightweight, isolated processes, each with its own stack, heap, and communications facilities (mailbox). The Erlang VM (BEAM), with pre-emptive scheduling, acts somewhat as on operating system on top of an operating system. Preemption is good because it prevents bad processes from starving the rest of the system, allowing for higher degrees of concurrency and better interactive performance, even if the context switching overhead makes it a bit slower than other scheduler types.

Behavior Trees are increasingly used in place of finite state machines (FSM's) and other AI control architectures due to improved properties of modularity, flexibility, reusability, and efficiency of implementation. They enable design/development scalability and efficiency.

Utility AI is used to keep the automata focused on actions by providing an external system for all decision making support. This significantly reduces the amount of logic/nodes required for an agent and takes the heavy mathematical workload off of action developers.

Requirements

A system is defined as an Autonomous decentralized system if the following 2 properties are satisfied:

  1. Autonomous Controllability: Even if any subsystem fails, is repaired, and/or is newly added, the other subsystems can continue to manage themselves and function.

  2. Autonomous Coordinability: Even if any subsystem fails, is repaired, and/or is newly added, the other subsystems can coordinate their individual objectives among themselves and can function in a coordinated fashion.

    • With Automata, while it is a property of the behavior tree implementation that user-defined nodes are independent, it is left to the designer to ensure coordination independence among all nodes in order to satisfy this property.

Features

Functional Features:

  • User defined behavior trees

    • Control Nodes currently on the roadmap
      • Selector
      • Sequence
      • Parallel
      • Priority
    • Condition nodes
    • In-node Decorators
    • Helper Nodes for accessing utility AI systems
  • A Concurrent, Scalable Blackboard Knowledge System

    • A global blackboard that can coordinate automata without being a central point of failure.
    • Individual automaton blackboards readable by all automata, writeable by owning automaton
    • ETS Implementation?
    • Potentially bringing the code to the data rather than the other way around.

Performance Features:

  • Concurrency
    • News flash! The world is concurrent. For example: we see, hear, and move at the same time. Concurrency was a core factor in the design of the Elixir language and is dead simple to implement.
  • High availability
    • Elixir is capable of 99.9999999% uptime (31 milliseconds/year of downtime). The main point of the Elixir model is an application that can be expected to run forever, as stated by the inventor — Joe Armstrong (RIP). Talk about unstoppable software!
  • Fault Tolerance
    • OTP Supervision Trees and the "fail fast" principle provide strong guarantees for error recovery and self healing systems.
  • Scalability
    • Elixir can handle millions of processes (134 million +/-) utilizing all cores without breaking a sweat on a single machine, and easily distributes work onto multiple machines with its builtin distribution mechanisms, and there is CRDT support with Horde.
    • Behavior trees provide value stream scalability (design/development and operations/testing).
  • Modularity
    • Modular BT's allow the designer to hierarchically combine independently developed, tested, deployed, and reusable unit behaviors that provide more valuable emergent properties in the large.
  • Flexibility
    • A design goal of Automata is to allow high flexibility (supports many use cases)
  • Simplicity of Implementation
    • Elixir's meta-programming facilities enable very user-friendly API's so developers don't need to know the details of BT's or Automata Theory to get things done, and BT's themselves lend efficiency via simplicity to the development value chain.

Applications

  • Trading Systems
  • Swarm Intelligence / Distributed Robotics
  • Intelligent agents with soft realtime multi-dimensional sensory, perception, intuition, and action capabilities
  • Multi-Agent Reinforcement Learning
  • Mixture of Experts Deep Learning Control Systems (python inter-op with erlport)
  • Blockchain Smart Contract Systems
  • Analytics Systems
  • Smart Home / IOT Systems
  • High-Speed Rail Systems (Japan has an ADS railway that learns)
  • Chatbot & Game AI's (esp. MMOG user backends)
  • QA Testing (BT's are particularly suited to combinatorial testing)
  • ? (choose your adventure)

Contributing

Welcome to the Automata project!

We are eager for your contributions and very happy you found yourself here! Here are our current needs:
  • Elixir Design, Architecture & Coding Best Practices Expertise
  • AI, Cognitive Architecture & Behavior Tree Expertise
  • ETS, BlackBoard System, Utility AI Expertise
  • Test Coverage
  • Documentation
  • Senior Code Reviewers to ensure Quality
  • Willingness and motivation to learn it all
Where to get started contributing

A good place to start is in the project kanban. Especially those threads labeled 'good first issue', 'testing', and/or 'documentation'.

Please join the slack channel and/or reach out to ericsteen1@gmail.com if interested!

Open Items for Discussion
  1. Blackboard / Utility Decisioning System. Make optional and configurable? i.e.. allow users to set configure whether or not there is a blackboard / UDS for their BT's, and if so, allow multiple types (basic, etc..)

Current Status

The project is currently in the Research & Prototype Development phase. We are establishing the core concepts, requirements, practices, and standards for the healthy and fruitful governance of the project. Join the conversation on The Automata Project Slack Channel.

Currently Automata is being developed as a single-node (machine) and single automaton system, but the architecture is in place to achieve the goal of a multi-node (full fault tolerance) and multi-automaton (hence the name, automata) distributed system in the not-too-distant future.

Engineering Standards & Best Practices

Check the #dev or #testing channels on slack for questions/info.

Design Standards

  1. Abstraction & Modularity are key. Spend the time and/or ask others to find the right abstraction. In terms of modularity, If its more than 10-20 lines, put it in a unit Function, Module or Struct that is tested and named well (by its role in the context if possible, rather than its data type or random name).
  2. Meta-programming will be heavily used as this is a framework, but it is important to know where it is useful and where its not. It is wise not to overuse clever meta-programming magic (a common complaint about rails). If your not sure, ask. Or use the force Luke (if your a Jedi).
  3. Use function pattern matching over Enum and other forms of enumeration as it is usually faster and cleaner.
  4. If your not sure how to do something, rather than do a hack, put a skeleton in place and submit a PR so a more senior engineer can provide guidance.

Coding Standards

  1. No shortcuts or Rush Jobs. Quality is job #1. We are creating something of very high quality, built to stand the test of time. Strive for 0% technical debt (the best kind of debt). Frameworks are poorly suited to “agile” practices, since they require foresight and a lot of generic capabilities. Today's emphasis on “agile” development is predicated on the developer's ignorance of what is required. Frameworks cannot be developed in that manner, since they are generic and devoid of ultimate functionality. They are all about potential, not actual end-user functionality. If you don't know the best way to do something, ask a core team member, or reach out to the very helpful Elixir community. See the list of resources.
  2. Always think about what can go wrong, what will happen on invalid input, and what might fail, which will help you catch many bugs before they happen.

PR Review Standards

  1. Code Reviews by core team members are required before merging and must be escalated if there is even the slightest concern of a design/logic flaw or incomplete testing. Imagine your building a rocket to mars and putting you and your family on it. Would you commmit that spaghetti code now?
  2. Every PR should have test coverage unless it is a trivial change or is approved by 2 core team members or designated reviewers.
  3. The (BD) — upstarter, is a major stickler when it comes to architecture, design, code quality, proper abstractions, and attention to detail. Be warned and feel entirely free to keep him informed of his failures to follow his own strict quality requirements. 😉

Testing Standards

In Progress. Property Testing? Permutation Testing? Join the conversation on The Automata Project Slack Channel

  1. Unit tests test the unit of behavior, not the unit of implementation. Changing the implementation, without changing the behavior or having to change any of your tests is the goal, although not always possible. So where possible, treat your test objects as black boxes, testing through the public API without calling private methods or tinkering with state.
Where to ask for help:
  1. The Automata Project Slack Channel
  2. Elixir Forum
  3. Elixir Slack Channel
  4. Stack Overflow
  5. Reddit
  6. Quora
  7. Discord

How it works

High Level Overview

The Automata supervision tree(s)

automata supervision tree diagram

There are 3 Layers in the supervision tree below the Application supervisor. The terminal nodes are the AutomatonNodeSupervisor which supervise the user-defined behavior tree nodes with the help of their "brains" – the AutomatonServer. The AutomatonServer currently handles the bulk of the logic of the system, as it is responsible for parsing user-config, and starting and managing the user-defined nodes. It starts the user defined nodes as children of AutomatonNodeSupervisor, which is kept lean for fault tolerance purposes.

The following is a breakdown of roles and responsibilities in the system (corresponding to files in lib/automata/core/):

The Core Supervision Tree (in lib/core/)

This tree is the management & fault tolerance mechanism for the parsing and validation of user config, as well as controlling the instantiation of the user-defined behavior trees.

  • Automata.Supervisor
    • on application start, this supervisor process starts the AutomataSupervisor and it's corresponding Server. It is started with strategy :one_for_one to ensure that the AutomatonSupervisor is independently self-healing
  • Automata.Server
    • acts as the "brains" of the AutomataSupervisor to keep the supervisor lean and mean. It starts the Automata.AutomatonSupervisor, passing the user-defined config.
  • Automata.AutomatonSupervisor
    • this process acts as supervisor to each AutomatonNodeSupervisor and has strategy :one_for_all to ensure that errors restart the entire supervision tree including the GenServers (AutomatonServer). It delegates the spawning of the user-defined BT nodes to the AutomatonServer which currently handles most of the logic.
  • AutomatonNodeSupervisor
    • runs concurrently, independently, and with restart: permanent. This supervisor is the root of the user-defined behavior trees.
  • AutomatonServer
    • this node parses and validates the user configuration and creates and manages OTP event callbacks of the user-defined behavior tree root node.
The Control Supervision Tree (in lib/core/control/)

These are the management & fault tolerance mechanisms for the user-defined behavior tree(s).

  • Automaton.Node
    • this is the most complicated node as it defines the user API and manages and controls the operations of the user-defined behavior trees in a recursive fashion.
  • Automaton.Behavior
    • this is the interface (behaviour in elixir) that is implemented by all user-defined nodes
  • Automaton.Action
    • this is the interface for action(execution) nodes — where the world is perceived and changed, reactively and proactively
The Blackboard
  • Global Blackboard
    • all nodes share this knowledge store
    • the automata will act upon seeing certain data changes in the global blackboard
  • Individual Node Blackboards
    • node blackboards use protected tables for knowledge sharing – all processes can read, one process has write access
    • the automaton will act upon seeing certain data changes in the global blackboard

API

Users may create tree structures of arbitrary depth by defining their own custom modules in the nodes/ directory which use Automaton.Node as a macro. Then, by overriding the update() function and returning a status as one of :running, :failure, or :success, the core system will manage the running of the Behavior Tree they have defined and handle restarting when unexpected errors occur based on their configured restart strategies.

defmodule MyNode do
  use Automaton.Node,

    # required
    # one of :sequence, :selector, :parallel, etc...
    # or type :execution for execution nodes (no children)
    node_type: :selector,

    # the frequency of updates for this node(subtree), in milliseconds
    # the default is an infinite loop (0 ms)
    tick_freq: 200, # 200ms


    # not included for execution nodes
    # list of child control/action(execution) nodes
    # these run in order for type :selector and :sequence nodes
    # and in parallel for type :parallel, and in dynamic priority for :priority
    children: [ChildNode1, ChildNode2, ChildNode3]


    # overrides update function defined in use macro
    # called every tick, returns current status
    def update do
      # reactively and proactively change the world
      {:ok, status}
    end
end

Example

Below is a simplified hypothetical example of a sequence node(subtree) for an autonomous "Forex Trader". The first two leafs are condition nodes, and the last two are action nodes.

automata trader sequence diagram

TODO: how to implement the above scenario.

Where to read about the technologies underlying Automata:

The core architecture
Libraries & Tooling (Still in Discussion)
Behavior Trees
The Blackboard
Utility AI
Other

Installation

If available in Hex, the package can be installed by adding Automata to your list of dependencies in mix.exs:

def deps do
  [
    {:automata, "~> 0.1.0"}
  ]
end

Authors

See also the list of contributors who participated in this project.

License

This project is licensed under the Apache 2.0 License - see the License.md file for details or License

You can’t perform that action at this time.