CSIT-986: Use MLRsearch from pip 97/13097/2
authorVratko Polak <vrpolak@cisco.com>
Mon, 18 Jun 2018 14:00:06 +0000 (16:00 +0200)
committerVratko Polak <vrpolak@cisco.com>
Mon, 18 Jun 2018 14:22:22 +0000 (16:22 +0200)
+ Delete resources/libraries/python/search/.
+ Add MLRsearch==0.1.1 to requirements.txt.
+ Bump PyPI/MLRsearch version to 0.1.2.

Change-Id: I1f86d75ac8eb90ee3946dbac8c56280f39302f4d
Signed-off-by: Vratko Polak <vrpolak@cisco.com>
PyPI/MLRsearch/setup.py
requirements.txt
resources/libraries/python/TrafficGenerator.py
resources/libraries/python/search/AbstractMeasurer.py [deleted file]
resources/libraries/python/search/AbstractSearchAlgorithm.py [deleted file]
resources/libraries/python/search/MultipleLossRatioSearch.py [deleted file]
resources/libraries/python/search/NdrPdrResult.py [deleted file]
resources/libraries/python/search/ReceiveRateInterval.py [deleted file]
resources/libraries/python/search/ReceiveRateMeasurement.py [deleted file]
resources/libraries/python/search/__init__.py [deleted file]

index 2411f47..ab8c6d8 100644 (file)
@@ -14,7 +14,7 @@ with open(path.join(here, "README.rst"), encoding="utf-8") as f:
 
 setup(
     name="MLRsearch",
-    version="0.1.1",  # This is currently the only place listing the version.
+    version="0.1.2",  # This is currently the only place listing the version.
     description="Library for speeding up binary search using shorter measurements.",
     long_description=long_description,
     long_description_content_type="text/x-rst",
index 11caf5d..558b2c8 100644 (file)
@@ -1,3 +1,4 @@
+MLRsearch==0.1.1
 robotframework==2.9.2
 paramiko==1.16.0
 scp==0.10.2
index ee65c1b..b27260e 100644 (file)
@@ -22,9 +22,9 @@ from .ssh import SSH
 from .topology import NodeType
 from .topology import NodeSubTypeTG
 from .topology import Topology
-from .search.AbstractMeasurer import AbstractMeasurer
-from .search.MultipleLossRatioSearch import MultipleLossRatioSearch
-from .search.ReceiveRateMeasurement import ReceiveRateMeasurement
+from MLRsearch.AbstractMeasurer import AbstractMeasurer
+from MLRsearch.MultipleLossRatioSearch import MultipleLossRatioSearch
+from MLRsearch.ReceiveRateMeasurement import ReceiveRateMeasurement
 
 __all__ = ['TGDropRateSearchImpl', 'TrafficGenerator', 'OptimizedSearch']
 
diff --git a/resources/libraries/python/search/AbstractMeasurer.py b/resources/libraries/python/search/AbstractMeasurer.py
deleted file mode 100644 (file)
index b972c4e..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright (c) 2018 Cisco and/or its affiliates.
-# 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.
-
-"""Module defining AbstractMeasurer class."""
-
-from abc import ABCMeta, abstractmethod
-
-
-class AbstractMeasurer(object):
-    """Abstract class defining common API for measurement providers."""
-
-    __metaclass__ = ABCMeta
-
-    @abstractmethod
-    def measure(self, duration, transmit_rate):
-        """Perform trial measurement and return the result.
-
-        :param duration: Trial duration [s].
-        :param transmit_rate: Target transmit rate [pps].
-        :type duration: float
-        :type transmit_rate: float
-        :returns: Structure containing the result of the measurement.
-        :rtype: ReceiveRateMeasurement
-        """
-        pass
diff --git a/resources/libraries/python/search/AbstractSearchAlgorithm.py b/resources/libraries/python/search/AbstractSearchAlgorithm.py
deleted file mode 100644 (file)
index 538322a..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-# Copyright (c) 2018 Cisco and/or its affiliates.
-# 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.
-
-"""Module defining AbstractSearchAlgorithm class."""
-
-from abc import ABCMeta, abstractmethod
-
-
-class AbstractSearchAlgorithm(object):
-    """Abstract class defining common API for search algorithms."""
-
-    __metaclass__ = ABCMeta
-
-    def __init__(self, measurer):
-        """Store the rate provider.
-
-        :param measurer: Object able to perform trial or composite measurements.
-        :type measurer: AbstractMeasurer
-        """
-        # TODO: Type check for AbstractMeasurer?
-        self.measurer = measurer
-
-    @abstractmethod
-    def narrow_down_ndr_and_pdr(
-            self, fail_rate, line_rate, packet_loss_ratio):
-        """Perform measurements to narrow down intervals, return them.
-
-        This will be renamed when custom loss ratio lists are supported.
-
-        :param fail_rate: Minimal target transmit rate [pps].
-        :param line_rate: Maximal target transmit rate [pps].
-        :param packet_loss_ratio: Fraction of packets lost, for PDR [1].
-        :type fail_rate: float
-        :type line_rate: float
-        :type packet_loss_ratio: float
-        :returns: Structure containing narrowed down intervals
-            and their measurements.
-        :rtype: NdrPdrResult
-        """
-        # TODO: Do we agree on arguments related to precision or trial duration?
-        pass
diff --git a/resources/libraries/python/search/MultipleLossRatioSearch.py b/resources/libraries/python/search/MultipleLossRatioSearch.py
deleted file mode 100644 (file)
index 0eb1d7d..0000000
+++ /dev/null
@@ -1,501 +0,0 @@
-# Copyright (c) 2018 Cisco and/or its affiliates.
-# 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.
-
-"""Module defining MultipleLossRatioSearch class."""
-
-import logging
-import math
-import time
-
-from AbstractSearchAlgorithm import AbstractSearchAlgorithm
-from NdrPdrResult import NdrPdrResult
-from ReceiveRateInterval import ReceiveRateInterval
-
-
-class MultipleLossRatioSearch(AbstractSearchAlgorithm):
-    """Optimized binary search algorithm for finding NDR and PDR bounds.
-
-    Traditional binary search algorithm needs initial interval
-    (lower and upper bound), and returns final interval after bisecting
-    (until some exit condition is met).
-    The exit condition is usually related to the interval width,
-    (upper bound value minus lower bound value).
-
-    The optimized algorithm contains several improvements
-    aimed to reduce overall search time.
-
-    One improvement is searching for two intervals at once.
-    The intervals are for NDR (No Drop Rate) and PDR (Partial Drop Rate).
-
-    Next improvement is that the initial interval does not need to be valid.
-    Imagine initial interval (10, 11) where 11 is smaller
-    than the searched value.
-    The algorithm will try (11, 13) interval next, and if 13 is still smaller,
-    (13, 17) and so on, doubling width until the upper bound is valid.
-    The part when interval expands is called external search,
-    the part when interval is bisected is called internal search.
-
-    Next improvement is that trial measurements at small trial duration
-    can be used to find a reasonable interval for full trial duration search.
-    This results in more trials performed, but smaller overall duration
-    in general.
-
-    Next improvement is bisecting in logarithmic quantities,
-    so that exit criteria can be independent of measurement units.
-
-    Next improvement is basing the initial interval on receive rates.
-
-    Final improvement is exiting early if the minimal value
-    is not a valid lower bound.
-
-    The complete search consist of several phases,
-    each phase performing several trial measurements.
-    Initial phase creates initial interval based on receive rates
-    at maximum rate and at maximum receive rate (MRR).
-    Final phase and preceding intermediate phases are performing
-    external and internal search steps,
-    each resulting interval is the starting point for the next phase.
-    The resulting interval of final phase is the result of the whole algorithm.
-
-    Each non-initial phase uses its own trial duration and width goal.
-    Any non-initial phase stops searching (for NDR or PDR independently)
-    when minimum is not a valid lower bound (at current duration),
-    or all of the following is true:
-    Both bounds are valid, bound bounds are measured at the current phase
-    trial duration, interval width is less than the width goal
-    for current phase.
-
-    TODO: Review and update this docstring according to rst docs.
-    TODO: Support configurable number of Packet Loss Ratios.
-    """
-
-    class ProgressState(object):
-        """Structure containing data to be passed around in recursion."""
-
-        def __init__(
-                self, result, phases, duration, width_goal, packet_loss_ratio,
-                minimum_transmit_rate, maximum_transmit_rate):
-            """Convert and store the argument values.
-
-            :param result: Current measured NDR and PDR intervals.
-            :param phases: How many intermediate phases to perform
-                before the current one.
-            :param duration: Trial duration to use in the current phase [s].
-            :param width_goal: The goal relative width for the curreent phase.
-            :param packet_loss_ratio: PDR fraction for the current search.
-            :param minimum_transmit_rate: Minimum target transmit rate
-                for the current search [pps].
-            :param maximum_transmit_rate: Maximum target transmit rate
-                for the current search [pps].
-            :type result: NdrPdrResult
-            :type phases: int
-            :type duration: float
-            :type width_goal: float
-            :type packet_loss_ratio: float
-            :type minimum_transmit_rate: float
-            :type maximum_transmit_rate: float
-            """
-            self.result = result
-            self.phases = int(phases)
-            self.duration = float(duration)
-            self.width_goal = float(width_goal)
-            self.packet_loss_ratio = float(packet_loss_ratio)
-            self.minimum_transmit_rate = float(minimum_transmit_rate)
-            self.maximum_transmit_rate = float(maximum_transmit_rate)
-
-    def __init__(self, measurer, final_relative_width=0.005,
-                 final_trial_duration=30.0, initial_trial_duration=1.0,
-                 number_of_intermediate_phases=2, timeout=600.0):
-        """Store the measurer object and additional arguments.
-
-        :param measurer: Rate provider to use by this search object.
-        :param final_relative_width: Final lower bound transmit rate
-            cannot be more distant that this multiple of upper bound [1].
-        :param final_trial_duration: Trial duration for the final phase [s].
-        :param initial_trial_duration: Trial duration for the initial phase
-            and also for the first intermediate phase [s].
-        :param number_of_intermediate_phases: Number of intermediate phases
-            to perform before the final phase [1].
-        :param timeout: The search will fail itself when not finished
-            before this overall time [s].
-        :type measurer: AbstractMeasurer
-        :type final_relative_width: float
-        :type final_trial_duration: float
-        :type initial_trial_duration: int
-        :type number_of_intermediate_phases: int
-        :type timeout: float
-        """
-        super(MultipleLossRatioSearch, self).__init__(measurer)
-        self.final_trial_duration = float(final_trial_duration)
-        self.final_relative_width = float(final_relative_width)
-        self.number_of_intermediate_phases = int(number_of_intermediate_phases)
-        self.initial_trial_duration = float(initial_trial_duration)
-        self.timeout = float(timeout)
-
-
-    @staticmethod
-    def double_relative_width(relative_width):
-        """Return relative width corresponding to double logarithmic width.
-
-        :param relative_width: The base relative width to double.
-        :type relative_width: float
-        :returns: The relative width of double logarithmic size.
-        :rtype: float
-        """
-        return 1.999 * relative_width - relative_width * relative_width
-        # The number should be 2.0, but we want to avoid rounding errors,
-        # and ensure half of double is not larger than the original value.
-
-    @staticmethod
-    def double_step_down(relative_width, current_bound):
-        """Return rate of double logarithmic width below.
-
-        :param relative_width: The base relative width to double.
-        :param current_bound: The current target transmit rate to move [pps].
-        :type relative_width: float
-        :type current_bound: float
-        :returns: Transmit rate smaller by logarithmically double width [pps].
-        :rtype: float
-        """
-        return current_bound * (
-            1.0 - MultipleLossRatioSearch.double_relative_width(
-                relative_width))
-
-    @staticmethod
-    def double_step_up(relative_width, current_bound):
-        """Return rate of double logarithmic width above.
-
-        :param relative_width: The base relative width to double.
-        :param current_bound: The current target transmit rate to move [pps].
-        :type relative_width: float
-        :type current_bound: float
-        :returns: Transmit rate larger by logarithmically double width [pps].
-        :rtype: float
-        """
-        return current_bound / (
-            1.0 - MultipleLossRatioSearch.double_relative_width(
-                relative_width))
-
-    @staticmethod
-    def half_relative_width(relative_width):
-        """Return relative width corresponding to half logarithmic width.
-
-        :param relative_width: The base relative width to halve.
-        :type relative_width: float
-        :returns: The relative width of half logarithmic size.
-        :rtype: float
-        """
-        return 1.0 - math.sqrt(1.0 - relative_width)
-
-    @staticmethod
-    def half_step_up(relative_width, current_bound):
-        """Return rate of half logarithmic width above.
-
-        :param relative_width: The base relative width to halve.
-        :param current_bound: The current target transmit rate to move [pps].
-        :type relative_width: float
-        :type current_bound: float
-        :returns: Transmit rate larger by logarithmically half width [pps].
-        :rtype: float
-        """
-        return current_bound / (
-            1.0 - MultipleLossRatioSearch.half_relative_width(relative_width))
-
-    def narrow_down_ndr_and_pdr(
-            self, minimum_transmit_rate, maximum_transmit_rate,
-            packet_loss_ratio):
-        """Perform initial phase, create state object, proceed with next phases.
-
-        :param minimum_transmit_rate: Minimal target transmit rate [pps].
-        :param maximum_transmit_rate: Maximal target transmit rate [pps].
-        :param packet_loss_ratio: Fraction of packets lost, for PDR [1].
-        :type minimum_transmit_rate: float
-        :type maximum_transmit_rate: float
-        :type packet_loss_ratio: float
-        :returns: Structure containing narrowed down intervals
-            and their measurements.
-        :rtype: NdrPdrResult
-        :raises RuntimeError: If total duration is larger than timeout.
-        """
-        minimum_transmit_rate = float(minimum_transmit_rate)
-        maximum_transmit_rate = float(maximum_transmit_rate)
-        packet_loss_ratio = float(packet_loss_ratio)
-        line_measurement = self.measurer.measure(
-            self.initial_trial_duration, maximum_transmit_rate)
-        initial_width_goal = self.final_relative_width
-        for _ in range(self.number_of_intermediate_phases):
-            initial_width_goal = self.double_relative_width(initial_width_goal)
-        max_lo = maximum_transmit_rate * (1.0 - initial_width_goal)
-        mrr = max(
-            minimum_transmit_rate,
-            min(max_lo, line_measurement.receive_rate))
-        mrr_measurement = self.measurer.measure(
-            self.initial_trial_duration, mrr)
-        # Attempt to get narrower width.
-        if mrr_measurement.loss_fraction > 0.0:
-            max2_lo = mrr * (1.0 - initial_width_goal)
-            mrr2 = min(max2_lo, mrr_measurement.receive_rate)
-        else:
-            mrr2 = mrr / (1.0 - initial_width_goal)
-        if mrr2 > minimum_transmit_rate and mrr2 < maximum_transmit_rate:
-            line_measurement = mrr_measurement
-            mrr_measurement = self.measurer.measure(
-                self.initial_trial_duration, mrr2)
-            if mrr2 > mrr:
-                buf = line_measurement
-                line_measurement = mrr_measurement
-                mrr_measurement = buf
-        starting_interval = ReceiveRateInterval(
-            mrr_measurement, line_measurement)
-        starting_result = NdrPdrResult(starting_interval, starting_interval)
-        state = self.ProgressState(
-            starting_result, self.number_of_intermediate_phases,
-            self.final_trial_duration, self.final_relative_width,
-            packet_loss_ratio, minimum_transmit_rate, maximum_transmit_rate)
-        state = self.ndrpdr(state)
-        return state.result
-
-    def _measure_and_update_state(self, state, transmit_rate):
-        """Perform trial measurement, update bounds, return new state.
-
-        :param state: State before this measurement.
-        :param transmit_rate: Target transmit rate for this measurement [pps].
-        :type state: ProgressState
-        :type transmit_rate: float
-        :returns: State after the measurement.
-        :rtype: ProgressState
-        """
-        # TODO: Implement https://stackoverflow.com/a/24683360
-        # to avoid the string manipulation if log verbosity is too low.
-        logging.info("result before update: %s", state.result)
-        logging.debug(
-            "relative widths in goals: %s", state.result.width_in_goals(
-                self.final_relative_width))
-        measurement = self.measurer.measure(state.duration, transmit_rate)
-        ndr_interval = self._new_interval(
-            state.result.ndr_interval, measurement, 0.0)
-        pdr_interval = self._new_interval(
-            state.result.pdr_interval, measurement, state.packet_loss_ratio)
-        state.result = NdrPdrResult(ndr_interval, pdr_interval)
-        return state
-
-    @staticmethod
-    def _new_interval(old_interval, measurement, packet_loss_ratio):
-        """Return new interval with bounds updated according to the measurement.
-
-        :param old_interval: The current interval before the measurement.
-        :param measurement: The new meaqsurement to take into account.
-        :param packet_loss_ratio: Fraction for PDR (or zero for NDR).
-        :type old_interval: ReceiveRateInterval
-        :type measurement: ReceiveRateMeasurement
-        :type packet_loss_ratio: float
-        :returns: The updated interval.
-        :rtype: ReceiveRateInterval
-        """
-        old_lo, old_hi = old_interval.measured_low, old_interval.measured_high
-        # Priority zero: direct replace if the target Tr is the same.
-        if measurement.target_tr in (old_lo.target_tr, old_hi.target_tr):
-            if measurement.target_tr == old_lo.target_tr:
-                return ReceiveRateInterval(measurement, old_hi)
-            else:
-                return ReceiveRateInterval(old_lo, measurement)
-        # Priority one: invalid lower bound allows only one type of update.
-        if old_lo.loss_fraction > packet_loss_ratio:
-            # We can only expand down, old bound becomes valid upper one.
-            if measurement.target_tr < old_lo.target_tr:
-                return ReceiveRateInterval(measurement, old_lo)
-            else:
-                return old_interval
-        # Lower bound is now valid.
-        # Next priorities depend on target Tr.
-        if measurement.target_tr < old_lo.target_tr:
-            # Lower external measurement, relevant only
-            # if the new measurement has high loss rate.
-            if measurement.loss_fraction > packet_loss_ratio:
-                # Returning the broader interval as old_lo
-                # would be invalid upper bound.
-                return ReceiveRateInterval(measurement, old_hi)
-        elif measurement.target_tr > old_hi.target_tr:
-            # Upper external measurement, only relevant for invalid upper bound.
-            if old_hi.loss_fraction <= packet_loss_ratio:
-                # Old upper bound becomes valid new lower bound.
-                return ReceiveRateInterval(old_hi, measurement)
-        else:
-            # Internal measurement, replaced boundary
-            # depends on measured loss fraction.
-            if measurement.loss_fraction > packet_loss_ratio:
-                # We have found a narrow valid interval,
-                # regardless of whether old upper bound was valid.
-                return ReceiveRateInterval(old_lo, measurement)
-            else:
-                # In ideal world, we would not want to shrink interval
-                # if upper bound is not valid.
-                # In the real world, we want to shrink it for
-                # "invalid upper bound at maximal rate" case.
-                return ReceiveRateInterval(measurement, old_hi)
-        # Fallback, the interval is unchanged by the measurement.
-        return old_interval
-
-    def ndrpdr(self, state):
-        """Pefrom trials for this phase. Return the new state when done.
-
-        :param state: State before this phase.
-        :type state: ProgressState
-        :returns: The updated state.
-        :rtype: ProgressState
-        :raises RuntimeError: If total duration is larger than timeout.
-        """
-        start_time = time.time()
-        if state.phases > 0:
-            # We need to finish preceding intermediate phases first.
-            saved_phases = state.phases
-            state.phases -= 1
-            # Preceding phases have shorter duration.
-            saved_duration = state.duration
-            duration_multiplier = state.duration / self.initial_trial_duration
-            phase_exponent = float(state.phases) / saved_phases
-            state.duration = self.initial_trial_duration * math.pow(
-                duration_multiplier, phase_exponent)
-            # Shorter durations do not need that narrow widths.
-            saved_width = state.width_goal
-            state.width_goal = self.double_relative_width(state.width_goal)
-            # Recurse.
-            state = self.ndrpdr(state)
-            # Restore the state for current phase.
-            state.duration = saved_duration
-            state.width_goal = saved_width
-            state.phases = saved_phases  # Not needed, but just in case.
-        logging.info(
-            "starting iterations with duration %s and relative width goal %s",
-            state.duration, state.width_goal)
-        while 1:
-            if time.time() > start_time + self.timeout:
-                raise RuntimeError("Optimized search takes too long.")
-            # Order of priorities: invalid bounds (nl, pl, nh, ph),
-            # then narrowing relative Tr widths.
-            # Durations are not priorities yet,
-            # they will settle on their own hopefully.
-            ndr_lo = state.result.ndr_interval.measured_low
-            ndr_hi = state.result.ndr_interval.measured_high
-            pdr_lo = state.result.pdr_interval.measured_low
-            pdr_hi = state.result.pdr_interval.measured_high
-            ndr_rel_width = max(
-                state.width_goal, state.result.ndr_interval.rel_tr_width)
-            pdr_rel_width = max(
-                state.width_goal, state.result.pdr_interval.rel_tr_width)
-            # If we are hitting maximal or minimal rate, we cannot shift,
-            # but we can re-measure.
-            if ndr_lo.loss_fraction > 0.0:
-                if ndr_lo.target_tr > state.minimum_transmit_rate:
-                    new_tr = max(
-                        state.minimum_transmit_rate,
-                        self.double_step_down(ndr_rel_width, ndr_lo.target_tr))
-                    logging.info("ndr lo external %s", new_tr)
-                    state = self._measure_and_update_state(state, new_tr)
-                    continue
-                elif ndr_lo.duration < state.duration:
-                    logging.info("ndr lo minimal re-measure")
-                    state = self._measure_and_update_state(
-                        state, state.minimum_transmit_rate)
-                    continue
-            if pdr_lo.loss_fraction > state.packet_loss_ratio:
-                if pdr_lo.target_tr > state.minimum_transmit_rate:
-                    new_tr = max(
-                        state.minimum_transmit_rate,
-                        self.double_step_down(pdr_rel_width, pdr_lo.target_tr))
-                    logging.info("pdr lo external %s", new_tr)
-                    state = self._measure_and_update_state(state, new_tr)
-                    continue
-                elif pdr_lo.duration < state.duration:
-                    logging.info("pdr lo minimal re-measure")
-                    state = self._measure_and_update_state(
-                        state, state.minimum_transmit_rate)
-                    continue
-            if ndr_hi.loss_fraction <= 0.0:
-                if ndr_hi.target_tr < state.maximum_transmit_rate:
-                    new_tr = min(
-                        state.maximum_transmit_rate,
-                        self.double_step_up(ndr_rel_width, ndr_hi.target_tr))
-                    logging.info("ndr hi external %s", new_tr)
-                    state = self._measure_and_update_state(state, new_tr)
-                    continue
-                elif ndr_hi.duration < state.duration:
-                    logging.info("ndr hi maximal re-measure")
-                    state = self._measure_and_update_state(
-                        state, state.maximum_transmit_rate)
-                    continue
-            if pdr_hi.loss_fraction <= state.packet_loss_ratio:
-                if pdr_hi.target_tr < state.maximum_transmit_rate:
-                    new_tr = min(
-                        state.maximum_transmit_rate,
-                        self.double_step_up(pdr_rel_width, pdr_hi.target_tr))
-                    logging.info("pdr hi external %s", new_tr)
-                    state = self._measure_and_update_state(state, new_tr)
-                    continue
-                elif pdr_hi.duration < state.duration:
-                    logging.info("ndr hi maximal re-measure")
-                    state = self._measure_and_update_state(
-                        state, state.maximum_transmit_rate)
-                    continue
-            # If we are hitting maximum_transmit_rate,
-            # it is still worth narrowing width,
-            # hoping large enough loss fraction will happen.
-            # But if we are hitting the minimal rate (at current duration),
-            # no additional measurement will help with that,
-            # so we can stop narrowing in this phase.
-            if (ndr_lo.target_tr <= state.minimum_transmit_rate
-                    and ndr_lo.loss_fraction > 0.0):
-                ndr_rel_width = 0.0
-            if (pdr_lo.target_tr <= state.minimum_transmit_rate
-                    and pdr_lo.loss_fraction > state.packet_loss_ratio):
-                pdr_rel_width = 0.0
-            if ndr_rel_width > state.width_goal:
-                # We have to narrow NDR width first, as NDR internal search
-                # can invalidate PDR (but not vice versa).
-                new_tr = self.half_step_up(ndr_rel_width, ndr_lo.target_tr)
-                logging.info("Bisecting for NDR at %s", new_tr)
-                state = self._measure_and_update_state(state, new_tr)
-                continue
-            if pdr_rel_width > state.width_goal:
-                # PDR iternal search.
-                new_tr = self.half_step_up(pdr_rel_width, pdr_lo.target_tr)
-                logging.info("Bisecting for PDR at %s", new_tr)
-                state = self._measure_and_update_state(state, new_tr)
-                continue
-            # We do not need to improve width, but there still might be
-            # some measurements with smaller duration.
-            # We need to re-measure with full duration, possibly
-            # creating invalid bounds to resolve (thus broadening width).
-            if ndr_lo.duration < state.duration:
-                logging.info("re-measuring NDR lower bound")
-                self._measure_and_update_state(state, ndr_lo.target_tr)
-                continue
-            if pdr_lo.duration < state.duration:
-                logging.info("re-measuring PDR lower bound")
-                self._measure_and_update_state(state, pdr_lo.target_tr)
-                continue
-            # Except when lower bounds have high loss fraction, in that case
-            # we do not need to re-measure _upper_ bounds.
-            if ndr_hi.duration < state.duration and ndr_rel_width > 0.0:
-                logging.info("re-measuring NDR upper bound")
-                self._measure_and_update_state(state, ndr_hi.target_tr)
-                continue
-            if pdr_hi.duration < state.duration and pdr_rel_width > 0.0:
-                logging.info("re-measuring PDR upper bound")
-                self._measure_and_update_state(state, pdr_hi.target_tr)
-                continue
-            # Widths are narrow (or lower bound minimal), bound measurements
-            # are long enough, we can return.
-            logging.info("phase done")
-            break
-        return state
diff --git a/resources/libraries/python/search/NdrPdrResult.py b/resources/libraries/python/search/NdrPdrResult.py
deleted file mode 100644 (file)
index b69a57e..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-# Copyright (c) 2018 Cisco and/or its affiliates.
-# 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.
-
-"""Module defining NdrPdrResult class."""
-
-from ReceiveRateInterval import ReceiveRateInterval
-
-
-class NdrPdrResult(object):
-    """Two measurement intervals, return value of search algorithms.
-
-    Partial fraction is NOT part of the result. Pdr interval should be valid
-    for all partial fractions implied by the interval."""
-
-    def __init__(self, ndr_interval, pdr_interval):
-        """Store the measured intervals after checking argument types.
-
-        :param ndr_interval: Object containing data for NDR part of the result.
-        :param pdr_interval: Object containing data for PDR part of the result.
-        :type ndr_interval: ReceiveRateInterval
-        :type pdr_interval: ReceiveRateInterval
-        """
-        # TODO: Type checking is not very pythonic,
-        # perhaps users can fix wrong usage without it?
-        if not isinstance(ndr_interval, ReceiveRateInterval):
-            raise TypeError("ndr_interval, is not a ReceiveRateInterval: "
-                            "{ndr!r}".format(ndr=ndr_interval))
-        if not isinstance(pdr_interval, ReceiveRateInterval):
-            raise TypeError("pdr_interval, is not a ReceiveRateInterval: "
-                            "{pdr!r}".format(pdr=pdr_interval))
-        self.ndr_interval = ndr_interval
-        self.pdr_interval = pdr_interval
-
-    def width_in_goals(self, relative_width_goal):
-        """Return a debug string related to current widths in logarithmic scale.
-
-        :param relative_width_goal: Upper bound times this is the goal
-            difference between upper bound and lower bound.
-        :type relative_width_goal: float
-        :returns: Message containing NDR and PDR widths in goals.
-        :rtype: str
-        """
-        return "ndr {ndr_in_goals}; pdr {pdr_in_goals}".format(
-            ndr_in_goals=self.ndr_interval.width_in_goals(relative_width_goal),
-            pdr_in_goals=self.pdr_interval.width_in_goals(relative_width_goal))
-
-    def __str__(self):
-        """Return string as tuple of named values."""
-        return "NDR={ndr!s};PDR={pdr!s}".format(
-            ndr=self.ndr_interval, pdr=self.pdr_interval)
-
-    def __repr__(self):
-        """Return string evaluable as a constructor call."""
-        return "NdrPdrResult(ndr_interval={ndr!r},pdr_interval={pdr!r})".format(
-            ndr=self.ndr_interval, pdr=self.pdr_interval)
diff --git a/resources/libraries/python/search/ReceiveRateInterval.py b/resources/libraries/python/search/ReceiveRateInterval.py
deleted file mode 100644 (file)
index 05e0f10..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-# Copyright (c) 2018 Cisco and/or its affiliates.
-# 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.
-
-"""Module defining ReceiveRateInterval class."""
-
-import math
-
-from ReceiveRateMeasurement import ReceiveRateMeasurement
-
-
-class ReceiveRateInterval(object):
-    """Structure defining two Rr measurements, and their relation."""
-
-    def __init__(self, measured_low, measured_high):
-        """Store the bound measurements after checking argument types.
-
-        :param measured_low: Measurement for the lower bound.
-        :param measured_high: Measurement for the upper bound.
-        :type measured_low: ReceiveRateMeasurement
-        :type measured_high: ReceiveRateMeasurement
-        """
-        # TODO: Type checking is not very pythonic,
-        # perhaps users can fix wrong usage without it?
-        if not isinstance(measured_low, ReceiveRateMeasurement):
-            raise TypeError("measured_low is not a ReceiveRateMeasurement: "
-                            "{low!r}".format(low=measured_low))
-        if not isinstance(measured_high, ReceiveRateMeasurement):
-            raise TypeError("measured_high is not a ReceiveRateMeasurement: "
-                            "{high!r}".format(high=measured_high))
-        self.measured_low = measured_low
-        self.measured_high = measured_high
-        # Declare secondary quantities to appease pylint.
-        self.abs_tr_width = None
-        """Absolute width of target transmit rate. Upper minus lower."""
-        self.rel_tr_width = None
-        """Relative width of target transmit rate. Absolute divided by upper."""
-        self.sort()
-
-    def sort(self):
-        """Sort bounds by target Tr, compute secondary quantities."""
-        if self.measured_low.target_tr > self.measured_high.target_tr:
-            self.measured_low, self.measured_high = (
-                self.measured_high, self.measured_low)
-        self.abs_tr_width = (
-            self.measured_high.target_tr - self.measured_low.target_tr)
-        self.rel_tr_width = self.abs_tr_width / self.measured_high.target_tr
-
-    def width_in_goals(self, relative_width_goal):
-        """Return float value.
-
-        Relative width goal is some (negative) value on logarithmic scale.
-        Current relative width is another logarithmic value.
-        Return the latter divided by the former.
-        This is useful when investigating how did surprising widths come to be.
-
-        :param relative_width_goal: Upper bound times this is the goal
-            difference between upper bound and lower bound.
-        :type relative_width_goal: float
-        :returns: Current width as logarithmic multiple of goal width [1].
-        :rtype: float
-        """
-        return math.log(1.0 - self.rel_tr_width) / math.log(
-            1.0 - relative_width_goal)
-
-    def __str__(self):
-        """Return string as half-open interval."""
-        return "[{low!s};{high!s})".format(
-            low=self.measured_low, high=self.measured_high)
-
-    def __repr__(self):
-        """Return string evaluable as a constructor call."""
-        return ("ReceiveRateInterval(measured_low={low!r}"
-                ",measured_high={high!r})".format(
-                    low=self.measured_low, high=self.measured_high))
diff --git a/resources/libraries/python/search/ReceiveRateMeasurement.py b/resources/libraries/python/search/ReceiveRateMeasurement.py
deleted file mode 100644 (file)
index d052ebd..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-# Copyright (c) 2018 Cisco and/or its affiliates.
-# 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.
-
-"""Module defining ReceiveRateMeasurement class."""
-
-
-class ReceiveRateMeasurement(object):
-    """Structure defining the result of single Rr measurement."""
-
-    def __init__(self, duration, target_tr, transmit_count, loss_count):
-        """Constructor, normalize primary and compute secondary quantities.
-
-        :param duration: Measurement duration [s].
-        :param target_tr: Target transmit rate [pps].
-            If bidirectional traffic is measured, this is bidirectional rate.
-        :param transmit_count: Number of packets transmitted [1].
-        :param loss_count: Number of packets transmitted but not received [1].
-        :type duration: float
-        :type target_tr: float
-        :type transmit_count: int
-        :type loss_count: int
-        """
-        self.duration = float(duration)
-        self.target_tr = float(target_tr)
-        self.transmit_count = int(transmit_count)
-        self.loss_count = int(loss_count)
-        self.receive_count = transmit_count - loss_count
-        self.transmit_rate = transmit_count / self.duration
-        self.loss_rate = loss_count / self.duration
-        self.receive_rate = self.receive_count / self.duration
-        self.loss_fraction = float(self.loss_count) / self.transmit_count
-        # TODO: Do we want to store also the real time (duration + overhead)?
-
-    def __str__(self):
-        """Return string reporting input and loss fraction."""
-        return "d={dur!s},Tr={rate!s},Df={frac!s}".format(
-            dur=self.duration, rate=self.target_tr, frac=self.loss_fraction)
-
-    def __repr__(self):
-        """Return string evaluable as a constructor call."""
-        return ("ReceiveRateMeasurement(duration={dur!r},target_tr={rate!r}"
-                ",transmit_count={trans!r},loss_count={loss!r})".format(
-                    dur=self.duration, rate=self.target_tr,
-                    trans=self.transmit_count, loss=self.loss_count))
diff --git a/resources/libraries/python/search/__init__.py b/resources/libraries/python/search/__init__.py
deleted file mode 100644 (file)
index 4cc8158..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright (c) 2018 Cisco and/or its affiliates.
-# 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.
-
-"""
-__init__ file for Python package "MLRsearch"
-"""