Esempio n. 1
0
def test_tandem_with_different_services():
    stime_limit = 20000
    n = 3
    services = [Exponential(5), Exponential(8), Exponential(4)]
    arrivals = [Exponential(10), None, None]

    simret = tandem_queue_network(arrivals, services, None, stime_limit)

    rhos = [services[i].mean() / arrivals[0].mean() for i in range(n)]
    sizes = [r / (1 - r) for r in rhos]
    delays = [sz * arrivals[0].mean() for sz in sizes]
    end_to_end_delay = sum(delays)

    assert_allclose(simret.nodes[0].delay.mean(), end_to_end_delay, rtol=0.25)
Esempio n. 2
0
def test__as_ph__mixture_with_non_markovian_state_raise_runtime_error():
    """
    Validate that MixtureDistribution.as_ph() raises ValueError if one of
    the states is not Markovian (e.g., normal or uniform distribution).
    """
    dist = MixtureDistribution(
        [Exponential(1.0),
         Exponential(8.0),
         Normal(1.0, 0.5)],
        weights=[0.495, 0.495, 0.01])
    with pytest.raises(RuntimeError):
        dist.as_ph()
    # However, converting this distribution to PH with min_prob=0.1 is OK:
    ph = dist.as_ph(min_prob=0.1)
    assert_allclose(ph.s, [[-1, 0], [0, -8]])
    assert_allclose(ph.p, [0.5, 0.5])
Esempio n. 3
0
    def __init__(self, rate: float, factory: RandomsFactory = None):
        """
        Constructor.

        Parameters
        ----------
        rate : float
            Rate (1 / mean) of exponential distribution.
        """
        if rate <= 0.0:
            raise ValueError(f"positive rate expected, {rate} found")
        super().__init__(Exponential(rate), factory)
Esempio n. 4
0
def test_tandem_with_fixed_service():
    stime_limit = 20000
    n = 3
    service = Exponential(5)
    arrivals = [Exponential(10), None, None]

    simret = tandem_queue_network_with_fixed_service(arrivals, service, None,
                                                     stime_limit)

    print(simret)
    service_means = [simret.nodes[i].service.mean() for i in range(n)]

    n_services = len(simret.nodes[-1].service.as_tuple())
    assert_allclose(
        simret.nodes[0].service.as_tuple()[:n_services],
        simret.nodes[1].service.as_tuple()[:n_services],
    )
    assert_allclose(
        simret.nodes[0].service.as_tuple()[:n_services],
        simret.nodes[2].service.as_tuple()[:n_services],
    )

    assert_allclose(service_means[0], service.mean(), rtol=0.1)
Esempio n. 5
0
import pytest
from numpy.testing import assert_allclose
from pydesim import simulate

from pyqumo.random import Exponential, PhaseType
from pyqumo.qsim import QueueingSystem, QueueingTandemNetwork, \
    tandem_queue_network, tandem_queue_network_with_fixed_service


@pytest.mark.parametrize('arrival,service,stime_limit', [
    (Exponential(5), Exponential(1), 12000),
    (Exponential(3), Exponential(2), 12000),
    (PhaseType.exponential(10.0), PhaseType.exponential(48.0), 4000),
])
def test_mm1_model(arrival, service, stime_limit):
    ret = simulate(QueueingSystem,
                   stime_limit=stime_limit,
                   params={
                       'arrival': arrival,
                       'service': service,
                       'queue_capacity': None,
                   })

    busy_rate = ret.data.server.busy_trace.timeavg()
    system_size = ret.data.system_size_trace.timeavg()
    est_arrival_mean = ret.data.source.intervals.statistic().mean()
    est_departure_mean = ret.data.sink.arrival_intervals.statistic().mean()
    est_service_mean = ret.data.server.service_intervals.mean()
    est_delay = ret.data.source.delays.mean()
    est_sys_wait = ret.data.system_wait_intervals.mean()
    est_queue_wait = ret.data.queue.wait_intervals.mean()
Esempio n. 6
0
def test_exponential_fit(avg):
    dist = Exponential.fit(avg)
    assert_allclose(dist.mean, avg)
Esempio n. 7
0
 'dist, m1, m2, m3, m4, string, atol, rtol',
 [
     # Constant distribution:
     (Const(2), 2, 4, 8, 16, '(Const: value=2)', 1e-2, 2e-2),
     (Const(3), 3, 9, 27, 81, '(Const: value=3)', 1e-2, 2e-2),
     # Uniform distribution:
     (Uniform(0, 1), 0.5, 1 / 3, 1 / 4, 1 / 5, '(Uniform: a=0, b=1)', 1e-2,
      2e-2),
     (Uniform(
         2, 10), 6, 124 / 3, 312, 2499.2, '(Uniform: a=2, b=10)', .01, .02),
     # Normal distribution:
     (Normal(0, 1), 0, 1, 0, 3, '(Normal: mean=0, std=1)', 1e-2, 2e-2),
     (Normal(1, 0.5), 1, 1.25, 1.75, 2.6875, '(Normal: mean=1, std=0.5)',
      1e-2, 2e-2),
     # Exponential distribution:
     (Exponential(1.0), 1, 2, 6, 24, '(Exp: rate=1)', 1e-2, 2e-2),
     (Exponential(2.0), 1 / 2, 1 / 2, 6 / 8, 24 / 16, '(Exp: rate=2)', 1e-2,
      2e-2),
     # Erlang distribution:
     (Erlang(1, 1), 1, 2, 6, 24, '(Erlang: shape=1, rate=1)', 1e-2, 2e-2),
     (Erlang(5, param=2.5), 2, 4.8, 13.44, 43.008,
      '(Erlang: shape=5, rate=2.5)', 1e-2, 2e-2),
     # Hyperexponential distribution
     (HyperExponential([1], [1]), 1, 2, 6, 24,
      '(HyperExponential: probs=[1], rates=[1])', 1e-2, 2e-2),
     (HyperExponential([2, 3, 4], probs=[0.5, 0.2, 0.3]), 0.39167, 0.33194,
      0.4475694, 0.837384,
      '(HyperExponential: probs=[0.5, 0.2, 0.3], rates=[2, 3, 4])', 1e-2,
      2e-2),
     # Hypererlang distribution
     (HyperErlang([1], [1], [1]), 1, 2, 6, 24,

@pytest.mark.parametrize('props', [
    GG1Props(arrival=Poisson(2),
             service=Poisson(5),
             queue_capacity=4,
             system_size_avg=0.642,
             system_size_std=0.981,
             queue_size_avg=0.2444,
             queue_size_std=0.6545,
             loss_prob=0.0062,
             utilization=0.3975,
             departure_rate=1.9877,
             response_time_avg=0.323,
             wait_time_avg=0.123),
    GG1Props(arrival=Exponential(42),
             service=Exponential(34),
             queue_capacity=7,
             system_size_avg=5.3295,
             system_size_std=5.6015**0.5,
             queue_size_avg=4.3708,
             queue_size_std=5.2010**0.5,
             loss_prob=0.2239,
             utilization=0.9587,
             departure_rate=32.5959,
             response_time_avg=0.163,
             wait_time_avg=0.134,
             max_packets=int(1e5)),
    GG1Props(arrival=Poisson(1),
             service=Exponential(2),
             queue_capacity=np.inf,
Esempio n. 9
0
     busy_avg=[0.5, 0.5, 0.5],
     busy_std=[0.5, 0.5, 0.5],
     # Scalar probabilities and rates:
     drop_prob=[0, 0, 0],
     delivery_prob=[1, 1, 1],
     utilization=[.5, .5, .5],
     # Intervals:
     departure_avg=[1, 1, 1],
     arrival_avg=[1, 1, 1],
     response_time_avg=[1, 1, 1],
     wait_time_avg=[.5, .5, .5],
     delivery_delay_avg=[3, 0, 0]),
 TandemProps(
     arrival=[Poisson(1), Poisson(2),
              Poisson(7)],
     service=[Exponential(10),
              Exponential(6),
              Exponential(40)],
     queue_capacity=np.inf,
     num_stations=3,
     # System and queue sizes:
     system_size_avg=[1 / 9, 1, 1 / 3],
     system_size_std=[np.sqrt(10) / 9,
                      np.sqrt(2), 2 / 3],
     queue_size_avg=[1 / 90, 1 / 2, 1 / 12],
     queue_size_std=[
         np.sqrt(109) / 90,
         np.sqrt(5) / 2,
         np.sqrt(19) / 12
     ],
     busy_avg=[1 / 10, 1 / 2, 1 / 4],
Esempio n. 10
0
    wait_time_avg: float

    # Test parameters:
    tol: float = 1e-1
    max_packets: int = int(1e5)


@pytest.mark.parametrize('props', [
    GG1Props(
        arrival=Poisson(2), service=Poisson(5), queue_capacity=4,
        system_size_avg=0.642, system_size_std=0.981,
        queue_size_avg=0.2444, queue_size_std=0.6545,
        loss_prob=0.0062, utilization=0.3975, departure_rate=1.9877,
        response_time_avg=0.323, wait_time_avg=0.123),
    GG1Props(
        arrival=Exponential(42), service=Exponential(34),
        queue_capacity=7,
        system_size_avg=5.3295, system_size_std=5.6015**0.5,
        queue_size_avg=4.3708, queue_size_std=5.2010**0.5,
        loss_prob=0.2239, utilization=0.9587, departure_rate=32.5959,
        response_time_avg=0.163, wait_time_avg=0.134,
        max_packets=int(1e5)
    ),
    GG1Props(
        arrival=Poisson(1), service=Exponential(2),
        queue_capacity=np.inf,
        system_size_avg=1, system_size_std=2.0**0.5,
        queue_size_avg=0.5, queue_size_std=1.25**0.5,
        loss_prob=0, utilization=0.5, departure_rate=1.0,
        response_time_avg=1.0, wait_time_avg=0.5, max_packets=int(1e5)
    )
Esempio n. 11
0
    def __init__(self,
                 d0: Union[np.ndarray, Sequence[Sequence[float]]],
                 d1: Union[np.ndarray, Sequence[Sequence[float]]],
                 safe: bool = False,
                 tol: float = 1e-3,
                 factory: RandomsFactory = None):
        """
        Create MAP process with the given D0 and D1 matrices.

        If `safe = False` is set (this is default), we validate matrices
        D0 and D1. These matrices must comply three requirements:

        1) Sum `D0 + D1` must be an infinitesimal matrix
        2) All elements of D1 must be non-negative
        3) All elements of D0 except the main diagonal must be non-negative

        To avoid problems with "1e-12 is not zero", constructor accepts
        parameters `tol` (tolerance). If matrices D0 and D1 fail the check,
        it tries to fix them using `fix_markovian_arrival()` call with this
        tolerance.

        Sometimes it is useful to avoid matrices validation (e.g., when MAP
        matrices are obtained as a result of another computation). To disable
        validation, set `safe = True`.

        Parameters
        ----------
        d0 : array_like
            Matrix D0, it must be subinfinitesimal
        d1 : array_like
            Matrix D1, all its elements must be non-negative
        safe : bool, optional
            Flag indicating whether not to validate or try to fix matrices D0
            and D1 if they don't satisfy requirements. By default, `False`.
        tol : float, optional
            If `safe = False` and matrices D0 and D1 violate requirements,
            try to fix errors those are less then `tol`. If `safe = True`
            this parameter is ignored. Default: 1e-3.
        """
        super().__init__(factory)
        need_copy = [False, False]
        matrices = [d0, d1]

        for i in range(2):
            if not isinstance(matrices[i], np.ndarray):
                matrices[i] = np.asarray(matrices[i])
            else:
                need_copy[i] = True

        if not safe and not check_markovian_arrival(matrices):
            matrices, _ = fix_markovian_arrival(matrices, tol=tol)
            # Since matrices are re-built, no need to copy them:
            for i in range(2):
                need_copy[i] = False

        # Copy matrices if needed:
        for i in range(2):
            if need_copy[i]:
                matrices[i] = matrices[i].copy()

        # Extract matrices:
        self._matrices = tuple(matrices)
        self._generator = sum(self._matrices)
        self._order = order_of(self._matrices[0])
        self._inv_d0 = np.linalg.inv(self._matrices[0])

        # Since we will use Mmap for data generation, we need to generate
        # special matrices for transitions probabilities and rates.

        # 1) We need to store rates (we will use them when choosing random
        #    time we spend in the state):
        self._rates = -self._matrices[0].diagonal()

        # 2) Then, we need to store cumulative transition probabilities P.
        #    We store them in a stochastic matrix of shape N x (K*N):
        #      P[I, J] is a probability, that:
        #      - new state will be J (mod N), and
        #      - if J < N, then no packet is generated, or
        #      - if J >= N, then packet of type J // N is generated.
        # self._trans_pmf = np.hstack((
        #     self._matrices[0] + np.diag(self._rates),
        #     self._matrices[1]
        # )) / self._rates[:, None]

        # Build embedded DTMC and CTMC:
        self._ctmc = ContinuousTimeMarkovChain(self._generator, safe=True)
        self._dtmc = DiscreteTimeMarkovChain(-self._inv_d0.dot(self.d1),
                                             safe=True)
        self._states = [
            Exponential(rate, factory=factory) for rate in self._rates
        ]