x = Stream('x')
y = Stream('y')
z = Stream('z')
print_stream(x)
print_stream(y)
print_stream(z)

def h(window, window_size, step_size, threshold, min_window_size):
    mx = max(window)
    mn =  min(window)
    dif = mx - mn
    if dif < threshold:
        window_size += 1
        step_size += 1
    elif window_size > min_window_size:
        window_size -= 1
        step_size -= 1

    # print to help understand the program
    print 'dif = ', dif, 'window_size = ', window_size

    return ([mx, mn, dif], window_size, step_size)

initial_window_size = 6
initial_step_size = 6

awf(w, [x,y,z], h, initial_window_size, initial_step_size,
    threshold=15, min_window_size=1)

w.extend([randint(0, 20) for _ in range(60)])
    avg = np.mean([np.mean(window) for window in list_of_windows])
    std = np.mean([np.std(window) for window in list_of_windows])
    if std > ratio * avg:
        window_size += 1
        step_size += 1
    elif window_size > min_window_size:
        window_size -= 1
        step_size -= 1

    print 'std/avg = ', std/avg, 'window_size = ', window_size
    return ([avg, std], window_size, step_size)

initial_window_size = 6
initial_step_size = 6

awf([u,v], [y,z], h, initial_window_size, initial_step_size,
    call_streams=[a], ratio=0.6, min_window_size=4)

u.extend([randint(0, 20) for _ in range(15)])
v.extend([randint(0, 20) for _ in range(15)])
print 'UNPROCESSED INPUT \n'
# Agent does not execute though it has unprocessed input.

u.extend([randint(0, 20) for _ in range(15)])
v.extend([randint(0, 20) for _ in range(15)])
print 'MORE UNPROCESSED INPUT \n'
print 'INPUT IS PROCESSED WHEN VALUE APPEARS IN CALL STREAM.'
a.append(1)
# Agent processes unprocessed input.

u.extend([randint(0, 20) for _ in range(15)])
v.extend([randint(0, 20) for _ in range(15)])
from Stream import Stream
from Operators import stream_agent, adjustable_window_agent, awf
from examples_element_wrapper import print_stream
import numpy as np
from random import randint
""".Example illustrating continuously adjustable windows
using awf: adjustable window function.
Parameters of awf are:
  inputs, outputs, func, window_size, step_size,
  state=None, call_streams=None, **kwargs
The parameters of func are:
  list or list of lists, window_size, step_size
and func returns:
  output or list of outputs, new window_size, new step_size.

In this example, func is h. The first parameter of h is
lst, a single list. This is because awf creates an agent with
a single input.
h returns a tuple: sum(lst) which is the next element of the
output stream and the new window and step sizes.
In this example, h has no state or call streams.

awf(x, y, h, initial_window_size, initial_step_size) creates
an agent with input stream x, output stream y, func h, and
with the specified initial window and step sizes.

"""

x = Stream('x')
y = Stream('y')
print_stream(x)
# Function used by awf
def h(list_of_windows, window_size, step_size, last_output,
      percent_increase, min_window_size):
    next_output =  max([np.std(window) for window in list_of_windows])
    if next_output > (1 + percent_increase/100.0) * last_output:
        window_size += 1
        step_size += 1
    elif window_size > min_window_size:
        window_size -= 1
        step_size -= 1
    print 'window_size', window_size
    # return output, next window size, next step size, next state
    return (next_output, window_size, step_size, next_output)

initial_window_size = 5
initial_step_size = 5
last_output = 0

# Input streams: u, v
# Output stream: y
# Function: h
# state is last_output
# Create agent
awf([u,v], y, h, initial_window_size, initial_step_size, last_output,
    percent_increase=5.0, min_window_size=4)

# Put data into the input streams.
u.extend([randint(0, 20) for _ in range(60)])
v.extend([randint(0, 20) for _ in range(60)])