Introduction
Warning
The API changes frequently due to ongoing development. Once Quantum
reaches 1.0 we will adhere to semantic versioning. Until that time, all
object interfaces are subject to revision. This warning will remain in place
until a stable version is reached.
Welcome to Quantum’s API reference. This document is intended for those who are
interested in developing for Quantum. If you’re interested in fixing bugs,
creating new plugins, or inventing new functionality in Quantum, then this
document is for you. It provides documentation for all the classes and
functions that make Quantum work. A normal user should not be required to read
this document in order to use Quantum.
To begin development in Quantum, it’s important to understand the structure of
the application and how different objects fit together so I’ve included a
diagram of the architecture.
DIAGRAM PLACEHOLDER
The lowest level of functionality is written in C++. This functionality includes
representation of cell objects (processing nodes), communication of data
between cells, the graph structure of cells (which we call a circuit), and the
calculation of a call schedule for cells within a circuit.
The GUI and runtime are handled in Python which communicates to the C++ layer as
needed. We achieve this by wrapping the C++ code in Cython to produce Python
objects, which are imported into the runtime. Whenever we are handling a Cython
object in Python, we are really executing the underlying C++ code.
The C++ layer was written to be able to handle Python object references and
freely pass these objects around within the C++ layer. This ability is provided
by the excellent boost-python library. The GUI framework is provided by Kivy,
which is an amazing open-source multi-platform framework for Python GUIs and
event handling. There is also an event handling system in the C++ layer written
using an observer pattern and it can propagate signals back and forth between
C++ and Python. So events can be triggered by Python and sent into C++ where
the C++ objects will handle the response. Signals can also be sent the other
way, with an event originating in C++ and handled in Python.
Note
In this document, functions or objects that are normally used
internally by the system are indicated as Internal. You have access to
these functions but should rarely need to use them. Caution is advised if you
are going to call these functions.
Serialization
We do not serialize (write to file) any objects from the runtime. Instead, cells
and their relationships within circuits are mirrored in a graph database
service. When the user requests a save operation, the program simply updates the
database to reflect the current program state. When Quantum is launched, it
rebuilds the internal state by reading the database.
Tip
We can save to file by serializing the database, which will produce
files in various standardized graph representations such as GraphML or
GraphSON.
File Organization
Coming soon.
Unit Testing
Quantum uses nose to perform unit testing. Tests are kept in the tests
subdirectory. You may add your own tests to the directory or create your own
testing subdirectories. Once you provide a directory to nose, it will discover
all the tests within that directory. To run tests:
$ quantum -m nose.core tests
To write your own tests, you can use this as a template replacing XXX and
YYY with your own names:
import unittest
class XXXTestCase(unittest.TestCase):
def setUp(self):
# import class and prepare everything here.
pass
def test_YYY(self):
# place your test case here
a = 1
self.assertEqual(a, 1)
Core API
Quantum is a graph system so at its core is the graph object model. This is
written in C++ to be flexible and performant. The core is inspired by an
existing open-source project called ecto. Quantum would not have been possible
without ecto.
The core includes model representations of cells, circuits, sockets, the
scheduler, observers, and observables. Cells model the nodes of a processing
network. This means they define the interface that includes process()
calls,
which do all the work within a graph processing network.
The scheduler uses open-mp to provide multi-threaded processing of cells. The
allure of graph processing networks are that they are inherently parallel. Cells
can be calculated indepent of any other cell so long as all inputs are
available. The scheduler exploits this inherent parallelism by traversing the
circuit to determine when a cell is ready for processing and if so, schedules
a processing task on the next available processor.
Observers and observables objects are an implementation of the standard observer
design pattern. This provides a signaling system that allows observer objects be
notified when observables broadcast event signals.
These object models are wrapped by Cython in order to expose their interfaces
to Python. In this way, Python is able to execute libraries written in C++. The
observable objects can broadcast signals into the Python environment and
vice-a-versa. This allows our Python user interface to be responsive to what’s
going on at the lowest level of the graph objects.
Warning
Replacement of the Core API is under consideration. There are more
capable open-source graph processing libraries that are now available which
have nice built-in features like GPU accelleration and multiprocessing.
PyTorch or TensorFlow are strong contenders.
Circuit Components
In Python, we interface with the core models through circuit controller objects.
These classes communicate with their C++ counterparts by making calls to the
core objects. The circuit components that we define in Python are cells, pipes,
circuits, and sockets. We also define their UI representation in UI classes.
These UI classes encapsulate all the functionality necessary to draw their
model representations to screen. The controller objects mediate the interaction
between model and ui. This is a classic model-view-controller pattern. An
example of this interaction might go something like this: the user wants to
process a cell, so they click a button in the ui, the controller see’s the
ui activity and understands that it needs to tell the cell model object to begin
processing. The controller listens to events from the cell model in order to
control the ui to indicate to the user what is happening. For example, if it is
a long running computation, the controller might ask the ui to blink the cell
to indicate that it is processing, then stop blinking once processing is
complete.
Command
The command section includes the controller and UI elements of the Python
console. Quantum provides Command
and
SingletonCommand
as base classes that you can derive from to
define new commands. A dictionary of all commands acts as a registry to make
commands available to the system.
Plugins
Quantum can support two types of plugins– those that connect to the C++ layer
to provide new types of cells and those that are written in Python to provide
new GUI functionality. C++ plugins are loaded by the Kernel, which is written in
C++. These plugins should conform to a certain predefined protocol. Python
plugins are simply modules written in Python that program to the runtime API. In
most cases, python plugins will supply new types of panels for user interaction
and these panels are built using the PanelFactory.
Settings and Themes
Coming Soon
Document Model
Coming Soon
Odds and Ends
Coming Soon