terracotta/neat/locals/overload/mhod/multisize_estimation.py
2012-09-25 15:59:45 +10:00

334 lines
9.8 KiB
Python

# Copyright 2012 Anton Beloglazov
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
""" Multisize sliding window workload estimation functions.
"""
from contracts import contract
from neat.contracts_extra import *
from itertools import islice
from collections import deque
import logging
log = logging.getLogger(__name__)
@contract
def mean(data, window_size):
""" Get the data mean according to the window size.
:param data: A list of values.
:type data: list(number)
:param window_size: A window size.
:type window_size: int,>0
:return: The mean value.
:rtype: float
"""
return float(sum(data)) / window_size
@contract
def variance(data, window_size):
""" Get the data variance according to the window size.
:param data: A list of values.
:type data: list(number)
:param window_size: A window size.
:type window_size: int,>0
:return: The variance value.
:rtype: float
"""
m = mean(data, window_size)
return float(sum((x - m) ** 2 for x in data)) / (window_size - 1)
@contract
def acceptable_variance(probability, window_size):
""" Get the acceptable variance.
:param probability: The probability to use.
:type probability: number,>=0,<=1
:param window_size: A window size.
:type window_size: int,>0
:return: The acceptable variance.
:rtype: float
"""
return float(probability * (1 - probability)) / window_size
@contract
def estimate_probability(data, window_size, state):
""" Get the estimated probability.
:param data: A list of data values.
:type data: list(number)
:param window_size: The window size.
:type window_size: int,>0
:param state: The current state.
:type state: int,>=0
:return: The estimated probability.
:rtype: float,>=0
"""
return float(data.count(state)) / window_size
@contract
def update_request_windows(request_windows, previous_state, current_state):
""" Update and return the updated request windows.
:param request_windows: The previous request windows.
:type request_windows: list(deque)
:param previous_state: The previous state.
:type previous_state: int,>=0
:param current_state: The current state.
:type current_state: int,>=0
:return: The updated request windows.
:rtype: list(deque)
"""
request_windows[previous_state].append(current_state)
return request_windows
@contract
def update_estimate_windows(estimate_windows, request_windows,
previous_state):
""" Update and return the updated estimate windows.
:param estimate_windows: The previous estimate windows.
:type estimate_windows: list(list(dict))
:param request_windows: The current request windows.
:type request_windows: list(deque)
:param previous_state: The previous state.
:type previous_state: int,>=0
:return: The updated estimate windows.
:rtype: list(list(dict))
"""
request_window = request_windows[previous_state]
state_estimate_windows = estimate_windows[previous_state]
for state, estimate_window in enumerate(state_estimate_windows):
for window_size, estimates in estimate_window.items():
slice_from = len(request_window) - window_size
if slice_from < 0:
slice_from = 0
estimates.append(
estimate_probability(
list(islice(request_window, slice_from, None)),
window_size, state))
return estimate_windows
@contract
def update_variances(variances, estimate_windows, previous_state):
""" Updated and return the updated variances.
:param variances: The previous variances.
:type variances: list(list(dict))
:param estimate_windows: The current estimate windows.
:type estimate_windows: list(list(dict))
:param previous_state: The previous state.
:type previous_state: int,>=0
:return: The updated variances.
:rtype: list(list(dict))
"""
estimate_window = estimate_windows[previous_state]
for state, variance_map in enumerate(variances[previous_state]):
for window_size in variance_map:
estimates = estimate_window[state][window_size]
if len(estimates) < window_size:
variance_map[window_size] = 1.0
else:
variance_map[window_size] = variance(
list(estimates), window_size)
return variances
@contract
def update_acceptable_variances(acceptable_variances, estimate_windows, previous_state):
""" Update and return the updated acceptable variances.
:param acceptable_variances: The previous acceptable variances.
:type acceptable_variances: list(list(dict))
:param estimate_windows: The current estimate windows.
:type estimate_windows: list(list(dict))
:param previous_state: The previous state.
:type previous_state: int,>=0
:return: The updated acceptable variances.
:rtype: list(list(dict))
"""
estimate_window = estimate_windows[previous_state]
state_acc_variances = acceptable_variances[previous_state]
for state, acceptable_variance_map in enumerate(state_acc_variances):
for window_size in acceptable_variance_map:
estimates = estimate_window[state][window_size]
acceptable_variance_map[window_size] = acceptable_variance(
estimates[-1], window_size)
return acceptable_variances
@contract
def select_window(variances, acceptable_variances, window_sizes):
""" Select window sizes according to the acceptable variances.
:param variances: The variances.
:type variances: list(list(dict))
:param acceptable_variances: The acceptable variances.
:type acceptable_variances: list(list(dict))
:param window_sizes: The available window sizes.
:type window_sizes: list(int)
:return: The selected window sizes.
:rtype: list(list(int))
"""
n = len(variances)
selected_windows = []
for i in range(n):
selected_windows.append([])
for j in range(n):
selected_size = window_sizes[0]
for window_size in window_sizes:
if variances[i][j][window_size] > \
acceptable_variances[i][j][window_size]:
break
selected_size = window_size
selected_windows[i].append(selected_size)
return selected_windows
@contract
def select_best_estimates(estimate_windows, selected_windows):
""" Select the best estimates according to the selected windows.
:param estimate_windows: The estimate windows.
:type estimate_windows: list(list(dict))
:param selected_windows: The selected window sizes.
:type selected_windows: list(list(int))
:return: The selected best estimates.
:rtype: list(list(number))
"""
n = len(estimate_windows)
selected_estimates = []
for i in range(n):
selected_estimates.append([])
for j in range(n):
estimates = estimate_windows[i][j][selected_windows[i][j]]
if estimates:
selected_estimates[i].append(estimates[-1])
else:
selected_estimates[i].append(0.0)
return selected_estimates
@contract
def init_request_windows(number_of_states):
""" Initialize a request window data structure.
:param number_of_states: The number of states.
:type number_of_states: int,>0
:return: The initialized request windows data structure.
:rtype: list(deque)
"""
return number_of_states * [deque()]
@contract
def init_variances(window_sizes, number_of_states):
""" Initialize a variances data structure.
:param window_sizes: The required window sizes.
:type window_sizes: list(int)
:param number_of_states: The number of states.
:type number_of_states: int,>0
:return: The initialized variances data structure.
:rtype: list(list(dict))
"""
data = dict(zip(window_sizes, len(window_sizes) * [1.0]))
variances = []
for i in range(number_of_states):
variances.append([])
for j in range(number_of_states):
variances[i].append(dict(data))
return variances
@contract
def init_deque_structure(window_sizes, number_of_states):
""" Initialize a 3 level deque data structure.
:param window_sizes: The required window sizes.
:type window_sizes: list(int)
:param number_of_states: The number of states.
:type number_of_states: int,>0
:return: The initialized 3 level deque data structure.
:rtype: list(list(dict))
"""
data = dict((size, deque([], size)) for size in window_sizes)
structure = []
for i in range(number_of_states):
structure.append([])
for j in range(number_of_states):
structure[i].append(dict(data))
return structure
@contract
def init_selected_window_sizes(window_sizes, number_of_states):
""" Initialize a selected window sizes data structure.
:param window_sizes: The required window sizes.
:type window_sizes: list(int)
:param number_of_states: The number of states.
:type number_of_states: int,>0
:return: The initialized selected window sizes data structure.
:rtype: list(list(int))
"""
structure = []
for i in range(number_of_states):
structure.append([])
for j in range(number_of_states):
structure[i].append(window_sizes[0])
return structure