multi encapsulators:

multiple inputs and multiple outputs

See IoTPy/IoTPy/agent_types/multi.py

Multi encapsulators are generalizations of the op, merge, and split agents because multi agents operate on a list of input streams and produce a list of output streams. By contrast, op encapsulators operate on a single input stream and produce a single output stream; merge encapsulators operate on a list of input streams and produce a single output streams; split encapsulators operate on a single input stream and produce a list of output streams. Applications can be built without multi encapsulators; however, they are convenient in some cases.

Multi agents have the following form:

encapsulator_name(func, in_streams, out_streams,
   state=None, name=None, **kwargs)

where:

  • func is a function that reads an input list and returns an output list. The length of the input list must equal the number of input streams. The j-th element of the input list consists of one element from the j-th input stream for the case of multi_element and is a list of elements from the j-th input stream for multi_list. The length of the output list must equal the number of output streams; the j-th element of the output list is appended to the j-th output stream. This is a terminating function that is encapsulated to create a non-terminating agent.

  • in_streams is a list of input streams

  • out_streams is a list of output streams

  • state is an optional argument for func for the case where the function has state.

  • name: optional string which is the name given to the agent. The name can be helpful for debugging.

  • kwargs: optional additional keyword arguments for func. We begin by considering the case where these keyword arguments are constants and later consider the case where they are variables.

The package has several multi agents including:

  • multi_element

  • multi_list

  • multi_window

These agents are exactly like map_element, map_list and map_window except that the multi version has a list of input streams and a list of output streams whereas the map versions have a single input stream and a single output stream. 

multi_element

multi_element(func, in_streams, out_streams,
  state=None, name=None, **kwargs)

Example

In the code below, the parameter lst of function f is a 2-element list consisting of one element of stream u and one element of stream v. The function returns a 2-element list with the first element of the list appended to stream x and the second element appended to stream y.

u = Stream('u')
v = Stream('v')
x = Stream('x')
y = Stream('y')

def f(lst):
    return [max(lst), sum(lst)]

multi_element(f, [u,v], [x,y])

In the example, above, x[j] = max(u[j], v[j]) and y[j] = u[j] + v[j], for all j.

example

This example is to illustrate the similarities between multi and op agents. Consider a single-input and single-output agent. The obvious way to implement this agent is as an operator (op) with a single input stream and a single output stream. You can also implement this agent as a multi agent in which case the input is a list consisting of a single input stream and the output is list consisting of a single output stream in multi agents.

In the example below, function f reads a singleton list and returns a singleton list.

u = Stream('u')
x = Stream('x')
    
def f(lst): return [lst[0]*2]

multi_element(f, [u], [x])

 

multi_list

multi_list(func, in_streams, out_streams,
  state=None, name=None, **kwargs)

In the above code skeleton, the function func operates on a list of lists containing one list for each input stream, and it returns a list with one element for each output stream.

Example

u = Stream('u')
v = Stream('v')
x = Stream('x')
y = Stream('y')

def f(list_of_lists):
    return ([sum(lst) for lst in zip(*list_of_lists)],
            [min(lst) for lst in zip(*list_of_lists)]
            )

 multi_list(f, [u,v], [x,y])

Note: In the above example, if stream u is [0, 4, 8, 12, 16, .....] and stream v is [10, 0, 10, 0, ....] then zip(*list_of_lists) is [(0, 10), (4, 0), (8, 10), (12, 0), ....] and  so stream x becomes [10, 4, 18, 12, ....] and stream y becomes [0, 0, 8, 0, ....]

multi_window

multi_window(func, in_streams, out_streams, window_size, step_size,
        state=None, name=None, **kwargs)

In the above, the function func reads a list of windows with one window for each input stream. The length of the window is window_size. The window is moved forward by step_size on each step. The function returns a list with one element appended to each output stream.

example

u = Stream('u')
v = Stream('v')
x = Stream('x')
y = Stream('y')

def f(list_of_windows):
    return (min([sum(window) for window in list_of_windows]),
            max([sum(window) for window in list_of_windows])
            )

multi_window(f, [u,v], [x,y], window_size=2, step_size=2)

In the above example:

x = [min(u[0]+u[1], v[0]+v[1]), min(u[2]+u[3], v[2]+v[3]), min(u[4]+u[5], v[4]+v[5]), ....]

y = [max(u[0]+u[1], v[0]+v[1]), max(u[2]+u[3], v[2]+v[3]), max(u[4]+u[5], v[4]+v[5]), ....]

code repository

The code for multi is in agent_types/multi.py and tests are tests/multi_test.py

next: Simple testing

previous: agent_types. sink. single input, no outputs