# Path: philharmonic/utils.py
# def deprecated(func):
#     """This is a decorator which can be used to mark functions
#     as deprecated. It will result in a warning being emmitted
#     when the function is used."""
#     def newFunc(*args, **kwargs):
#         warnings.warn("Call to deprecated function %s." % func.__name__,
#                       category=DeprecationWarning)
#         return func(*args, **kwargs)
#     newFunc.__name__ = func.__name__
#     newFunc.__doc__ = func.__doc__
#     newFunc.__dict__.update(func.__dict__)
#     return newFunc
# 
# class CommonEqualityMixin(object):
# 
#     def __eq__(self, other):
#         return (isinstance(other, self.__class__)
#             and self.__dict__ == other.__dict__)
# 
#     def __ne__(self, other):
#         return not self.__eq__(other)
# 
#     def __hash__(self):
#         """Override the default hash behavior
#         (that returns the id or the object)"""
#         return hash(tuple(sorted(self.__dict__.items())))


import copy
import itertools
import pandas as pd
from philharmonic.utils import deprecated, CommonEqualityMixin
from . import visualiser
        penalty = pd.Series(ratio_overcap).mean()
        if penalty > 1.:
            penalty = 1.
        return penalty

    def ratio_within_capacity(self): # TODO: by resource overflows
        """Ratio of servers that are within capacity."""
        num_ok = 0
        for s in self.servers:
            if self.within_capacity(s):
                num_ok += 1
        if len(self.servers) == 0:
            return 1.0
        ratio = float(num_ok) / len(self.servers)
        return ratio

    def server_free(self, s):
        """True if there are no VMs allocated to server @param s."""
        return len(self._alloc[s]) == 0

    def underutilised(self, s, threshold = 0.25):
        """If the server is non-empty and utilisation below threshold."""
        return not self.server_free(s) and self.utilisation(s) < threshold

# The ranking determines which the order in which to apply the actions,
# given the same timestamps.
actions = ['boot', 'delete', 'increase_freq', 'decrease_freq',
           'migrate', 'pause', 'unpause']
action_rank = dict(zip(actions, range(len(actions))))


# Path: philharmonic/utils.py
# def deprecated(func):
#     """This is a decorator which can be used to mark functions
#     as deprecated. It will result in a warning being emmitted
#     when the function is used."""
#     def newFunc(*args, **kwargs):
#         warnings.warn("Call to deprecated function %s." % func.__name__,
#                       category=DeprecationWarning)
#         return func(*args, **kwargs)
#     newFunc.__name__ = func.__name__
#     newFunc.__doc__ = func.__doc__
#     newFunc.__dict__.update(func.__dict__)
#     return newFunc
# 
# class CommonEqualityMixin(object):
# 
#     def __eq__(self, other):
#         return (isinstance(other, self.__class__)
#             and self.__dict__ == other.__dict__)
# 
#     def __ne__(self, other):
#         return not self.__eq__(other)
# 
#     def __hash__(self):
#         """Override the default hash behavior
#         (that returns the id or the object)"""
#         return hash(tuple(sorted(self.__dict__.items())))


# Path: philharmonic/cloud/model.py
import copy
import itertools
import pandas as pd
from philharmonic.utils import deprecated, CommonEqualityMixin
from . import visualiser

        penalty = pd.Series(ratio_overcap).mean()
        if penalty > 1.:
            penalty = 1.
        return penalty

    def ratio_within_capacity(self): # TODO: by resource overflows
        """Ratio of servers that are within capacity."""
        num_ok = 0
        for s in self.servers:
            if self.within_capacity(s):
                num_ok += 1
        if len(self.servers) == 0:
            return 1.0
        ratio = float(num_ok) / len(self.servers)
        return ratio

    def server_free(self, s):
        """True if there are no VMs allocated to server @param s."""
        return len(self._alloc[s]) == 0

    def underutilised(self, s, threshold = 0.25):
        """If the server is non-empty and utilisation below threshold."""
        return not self.server_free(s) and self.utilisation(s) < threshold

# The ranking determines which the order in which to apply the actions,
# given the same timestamps.
actions = ['boot', 'delete', 'increase_freq', 'decrease_freq',
           'migrate', 'pause', 'unpause']
action_rank = dict(zip(actions, range(len(actions))))


class Action(CommonEqualityMixin):