示例#1
0
def GM1FundamentalMatrix(A,
                         precision=1e-14,
                         maxNumIt=50,
                         method="ShiftPWCR",
                         dual="R",
                         maxNumRoot=2048,
                         shiftType="one"):
    """
    Returns matrix R corresponding to the G/M/1 type Markov
    chain given by matrices A.
    
    Matrix R is the minimal non-negative solution of the 
    following matrix equation:
    
    .. math::
        R = A_0 + R A_1 + R^2 A_2 + R^3 A_3 + \dots.
    
    The implementation is based on [1]_, please cite it if
    you use this method.
    
    Parameters
    ----------
    A : length(M) list of matrices of shape (N,N)
        Matrix blocks of the G/M/1 type generator in the 
        regular part, from 0 to M-1.
    precision : double, optional
        Matrix R is computed iteratively up to this
        precision. The default value is 1e-14
    maxNumIt : int, optional
        The maximal number of iterations. The default value
        is 50.
    method : {"CR", "RR", "NI", "FI", "IS"}, optional
        The method used to solve the matrix-quadratic
        equation (CR: cyclic reduction, RR: Ramaswami
        reduction, NI: Newton iteration, FI: functional
        iteration, IS: invariant subspace method). The 
        default is "CR".
    
    Returns
    -------
    R : matrix, shape (N,N)
        The R matrix of the G/M/1 type Markov chain.
    
    References
    ----------
    .. [1] Bini, D. A., Meini, B., Steffé, S., Van Houdt,
           B. (2006, October). Structured Markov chains 
           solver: software tools. In Proceeding from the
           2006 workshop on Tools for solving structured 
           Markov chains (p. 14). ACM.
    """

    A = np.hstack(A)
    m = A.shape[0]
    I = ml.eye(m)
    dega = A.shape[1] // m - 1

    # compute invariant vector of A and the drift
    # drift > 1: positive recurrent GIM1, drift < 1: transient GIM1
    sumA = A[:, dega * m:]
    beta = np.sum(sumA, 1)
    # beta = (A_maxd)e + (A_maxd + A_maxd-1)e + ... + (Amaxd+...+A1)e
    for i in range(dega - 1, 0, -1):
        sumA = sumA + A[:, i * m:(i + 1) * m]
        beta = beta + np.sum(sumA, 1)

    sumA = sumA + A[:, :m]
    theta = DTMCSolve(sumA)
    drift = theta * beta

    if dual == "R" or (dual == "A" and drift <= 1):  # RAM dual
        # compute the RAM Dual process
        for i in range(dega + 1):
            A[:, i * m:(i + 1) *
              m] = Diag(1.0 / theta) * A[:, i * m:(i + 1) * m].T * Diag(theta)
    else:  # Bright dual
        if drift > 1:  # A -> positive recurrent GIM1
            # compute the Caudal characteristic of A
            eta, v = GM1TypeCaudal(A)
        else:  # A -> transient GIM1 (=recurrent MG1)
            eta, v = MG1TypeDecay(A)
        # compute invariant vector of A0+A1*eta+A2*eta^2+...+Amax*eta^max
        sumAeta = eta**dega * A[:, dega * m:]
        for i in range(dega - 1, -1, -1):
            sumAeta = sumAeta + eta**i * A[:, i * m:(i + 1) * m]
        theta = DRPSolve(sumAeta + (1.0 - eta) * I)
        # compute the Bright Dual process
        for i in range(dega + 1):
            A[:, i * m:(i + 1) * m] = eta**(i - 1) * Diag(
                1.0 / theta) * A[:, i * m:(i + 1) * m].T * Diag(theta)

    G = MG1FundamentalMatrix(A, precision, maxNumIt, method, maxNumRoot,
                             shiftType)

    if dual == "R" or (dual == "A" and drift <= 1):  # RAM dual
        return Diag(1.0 / theta) * G.T * Diag(theta)
    else:  # Bright dual
        return Diag(1.0 / theta) * G.T * Diag(theta) * eta
示例#2
0
def RandomDPH(order, mean=10.0, zeroEntries=0, maxTrials=1000, prec=1e-7):
    """
    Returns a random discrete phase-type distribution with a 
    given mean value.
    
    Parameters
    ----------
    order : int
        The size of the discrete phase-type distribution
    mean : double, optional
        The mean of the discrete phase-type distribution 
    zeroEntries : int, optional
        The number of zero entries in the initial vector, 
        generator matrix and closing vector
    maxTrials : int, optional
        The maximum number of trials to find a proper DPH 
        (that has an irreducible phase process and none of 
        its parameters is all-zero). The default value is 
        1000.
    prec : double, optional
        Numerical precision for checking the irreducibility.
        The default value is 1e-14.
    
    Returns
    -------
    alpha : vector, shape (1,M)
        The initial probability vector of the phase-type 
        distribution.
    A : matrix, shape (M,M)
        The transient generator matrix of the phase-type 
        distribution.
    
    Notes
    -----
    If the procedure fails, try to increase the 'maxTrials'
    parameter, or increase the mean value.
    """

    if zeroEntries > (order + 1) * (order - 1):
        raise Exception(
            "RandomDPH: Too many zero entries requested! Try to decrease the zero entries number!"
        )

    # distribute the zero entries among the rows
    def allZeroDistr(states, zeros):
        if states == 1:
            return [[zeros]]
        else:
            o = []
            for i in range(zeros + 1):
                x = allZeroDistr(states - 1, zeros - i)
                for j in range(len(x)):
                    xt = x[j]
                    xt.append(i)
                    xt.sort()
                    # check if we have it already
                    if o.count(xt) == 0:
                        o.append(xt)
            return o

    zeroDistr = allZeroDistr(order, zeroEntries)

    trials = 1
    while trials < maxTrials:
        # select a configuration from zeroDistr: it is a list describing the zero entries in each row
        zdix = np.random.permutation(len(zeroDistr))
        for k in range(len(zeroDistr)):
            zDistr = zeroDistr[zdix[k]]

            B = np.zeros((order, order + 2))
            for i in range(order):
                rp = np.random.permutation(order + 1)
                a = np.zeros(order + 1)
                for j in range(order + 1 - zDistr[i]):
                    a[rp[j]] = np.random.rand()
                B[i, 0:i] = a[0:i]
                B[i, i + 1:] = a[i:]
            # construct DPH parameters
            A = ml.matrix(B[:, :order])
            a = ml.matrix(B[:, order + 1]).T

            sc = np.sum(A, 1) + a.A
            if np.any(sc == 0):
                continue
            A = Diag(1 / sc) * A
            a = Diag(1 / sc) * a
            alpha = ml.matrix(B[:, order])
            # check if it is a proper PH (irreducible phase process & no full zero matrix)
            if np.all(A == 0.0) or np.all(alpha == 0.0) or np.all(a == 0.0):
                continue
            alpha = alpha / np.sum(alpha)
            if la.matrix_rank(ml.eye(order) - A) == order:
                if np.min(np.abs(alpha * la.inv(ml.eye(order) - A))) > prec:
                    # diagonals of matrix A:
                    d = np.random.rand(order)
                    # scale to the mean value
                    m = MomentsFromDPH(alpha, Diag(1 - d) * A + Diag(d), 1)[0]
                    d = 1 - (1 - d) * m / mean
                    A = Diag(1 - d) * A + Diag(d)
                    if CheckDPHRepresentation(alpha, A, prec):
                        return (alpha, A)
            trials += 1
    raise Exception("No feasible random PH found with such many zero entries!")
示例#3
0
def MAPMAP1(D0, D1, S0, S1, *argv):
    """
    Returns various performane measures of a continuous time
    MAP/MAP/1 queue.
    
    In a MAP/MAP/1 queue both the arrival and the service
    processes are characterized by Markovian arrival 
    processes.
    
    Parameters
    ----------
    D0 : matrix, shape(N,N)
        The transitions of the arrival MAP not accompanied by
        job arrivals
    D1 : matrix, shape(N,N)
        The transitions of the arrival MAP accompanied by
        job arrivals
    S0 : matrix, shape(N,N)
        The transitions of the service MAP not accompanied by
        job service
    S1 : matrix, shape(N,N)
        The transitions of the service MAP accompanied by
        job service
    further parameters : 
        The rest of the function parameters specify the options
        and the performance measures to be computed.
    
        The supported performance measures and options in this 
        function are:
    
        +----------------+--------------------+----------------------------------------+
        | Parameter name | Input parameters   | Output                                 |
        +================+====================+========================================+
        | "ncMoms"       | Number of moments  | The moments of the number of customers |
        +----------------+--------------------+----------------------------------------+
        | "ncDistr"      | Upper limit K      | The distribution of the number of      |
        |                |                    | customers from level 0 to level K-1    |
        +----------------+--------------------+----------------------------------------+
        | "ncDistrMG"    | None               | The vector-matrix parameters of the    |
        |                |                    | matrix-geometric distribution of the   |
        |                |                    | number of customers in the system      |
        +----------------+--------------------+----------------------------------------+
        | "ncDistrDPH"   | None               | The vector-matrix parameters of the    |
        |                |                    | matrix-geometric distribution of the   |
        |                |                    | number of customers in the system,     |
        |                |                    | converted to a discrete PH             |
        |                |                    | representation                         |
        +----------------+--------------------+----------------------------------------+
        | "stMoms"       | Number of moments  | The sojourn time moments               |
        +----------------+--------------------+----------------------------------------+
        | "stDistr"      | A vector of points | The sojourn time distribution at the   |
        |                |                    | requested points (cummulative, cdf)    |
        +----------------+--------------------+----------------------------------------+
        | "stDistrME"    | None               | The vector-matrix parameters of the    |
        |                |                    | matrix-exponentially distributed       |
        |                |                    | sojourn time distribution              |
        +----------------+--------------------+----------------------------------------+
        | "stDistrPH"    | None               | The vector-matrix parameters of the    |
        |                |                    | matrix-exponentially distributed       |
        |                |                    | sojourn time distribution, converted   |
        |                |                    | to a continuous PH representation      |
        +----------------+--------------------+----------------------------------------+
        | "prec"         | The precision      | Numerical precision used as a stopping |
        |                |                    | condition when solving the             |
        |                |                    | matrix-quadratic equation              |
        +----------------+--------------------+----------------------------------------+
        
        (The quantities related to the number of customers in 
        the system include the customer in the server, and the 
        sojourn time related quantities include the service 
        times as well)
    
    Returns
    -------
    Ret : list of the performance measures
        Each entry of the list corresponds to a performance 
        measure requested. If there is just a single item, 
        then it is not put into a list.
        Notes
    -----
    "ncDistrMG" and "stDistrME" behave much better numerically than 
    "ncDistrDPH" and "stDistrPH".
    """

    # parse options
    prec = 1e-14
    needST = False
    eaten = []
    for i in range(len(argv)):
        if argv[i] == "prec":
            prec = argv[i + 1]
            eaten.append(i)
            eaten.append(i + 1)
        elif type(argv[i]) is str and len(
                argv[i]) > 2 and argv[i][0:2] == "st":
            needST = True

    if butools.checkInput and not CheckMAPRepresentation(D0, D1):
        raise Exception(
            'MAPMAP1: The arrival process (D0,D1) is not a valid MAP representation!'
        )

    if butools.checkInput and not CheckMAPRepresentation(S0, S1):
        raise Exception(
            'MAPMAP1: The service process (S0,S1) is not a valid MAP representation!'
        )

    IA = ml.eye(D0.shape[0])
    IS = ml.eye(S0.shape[0])

    B = np.kron(IA, S1)
    L = np.kron(D0, IS) + np.kron(IA, S0)
    F = np.kron(D1, IS)
    L0 = np.kron(D0, IS)

    pi0, R = QBDSolve(B, L, F, L0, prec)
    N = pi0.shape[1]
    I = ml.eye(N)

    if needST:
        # calculate the distribution of the age at departures
        U = L + R * B
        Rh = -U.I * F
        T = np.kron(IA, S0) + Rh * B
        eta = pi0 * F * (I - Rh).I
        eta = eta / np.sum(eta)

    Ret = []
    argIx = 0
    while argIx < len(argv):
        if argIx in eaten:
            argIx += 1
            continue
        elif type(argv[argIx]) is str and argv[argIx] == "ncDistrDPH":
            # transform it to DPH
            alpha = pi0 * R * (I - R).I
            A = Diag(alpha).I * R.T * Diag(alpha)
            Ret.append(alpha)
            Ret.append(A)
        elif type(argv[argIx]) is str and argv[argIx] == "ncDistrMG":
            # transform it to MG
            B = SimilarityMatrixForVectors(np.sum((I - R).I * R, 1),
                                           np.ones((N, 1)))
            Bi = B.I
            A = B * R * Bi
            alpha = pi0 * Bi
            Ret.append(alpha)
            Ret.append(A)
        elif type(argv[argIx]) is str and argv[argIx] == "ncMoms":
            numOfMoms = argv[argIx + 1]
            argIx += 1
            moms = []
            iR = (I - R).I
            for m in range(1, numOfMoms + 1):
                moms.append(
                    math.factorial(m) * np.sum(pi0 * iR**(m + 1) * R**m))
            Ret.append(MomsFromFactorialMoms(moms))
        elif type(argv[argIx]) is str and argv[argIx] == "ncDistr":
            numOfQLProbs = argv[argIx + 1]
            argIx += 1
            values = np.empty(numOfQLProbs)
            values[0] = np.sum(pi0)
            RPow = I
            for p in range(numOfQLProbs - 1):
                RPow = RPow * R
                values[p + 1] = np.sum(pi0 * RPow)
            Ret.append(values)
        elif type(argv[argIx]) is str and argv[argIx] == "stDistrPH":
            # transform it to PH representation
            beta = CTMCSolve(S0 + S1)
            theta = DTMCSolve(-D0.I * D1)
            vv = np.kron(theta, beta)
            ix = np.arange(N)
            nz = ix[vv.flat > prec]
            delta = Diag(vv[:, nz])
            alpha = ml.ones((1, N)) * B[nz, :].T * delta / np.sum(beta * S1)
            A = delta.I * T[nz, :][:, nz].T * delta
            Ret.append(alpha)
            Ret.append(A)
        elif type(argv[argIx]) is str and argv[argIx] == "stDistrME":
            Ret.append(eta)
            Ret.append(T)
        elif type(argv[argIx]) is str and argv[argIx] == "stMoms":
            numOfMoms = argv[argIx + 1]
            argIx += 1
            moms = []
            iT = -T.I
            for m in range(1, numOfMoms + 1):
                moms.append(math.factorial(m) * np.sum(eta * iT**m))
            Ret.append(moms)
        elif type(argv[argIx]) is str and argv[argIx] == "stDistr":
            points = argv[argIx + 1]
            argIx += 1
            values = np.empty(points.shape)
            for p in range(len(points.flat)):
                values.flat[p] = 1.0 - np.sum(
                    eta * la.expm(T * points.flat[p]))
            Ret.append(values)
        else:
            raise Exception("MAPMAP1: Unknown parameter " + str(argv[argIx]))
        argIx += 1
    if len(Ret) == 1:
        return Ret[0]
    else:
        return Ret
示例#4
0
def RandomDMMAP(order,
                types,
                mean=10.0,
                zeroEntries=0,
                maxTrials=1000,
                prec=1e-7):
    """
    Returns a random discrete Markovian arrival process.
    
    Parameters
    ----------
    order : int
        The size of the DMAP
    mean : double, optional
        The mean inter-arrival times of the DMMAP
    types : int
        The number of different arrival types
    zeroEntries : int, optional
        The number of zero entries in the D0 and D1 matrices
    maxTrials : int, optional
        The maximum number of trials to find a proper DMMAP 
        (that has an irreducible phase process and none of 
        its parameters is all-zero)
    prec : double, optional
        Numerical precision for checking the irreducibility.
        The default value is 1e-14.
    
    Returns
    -------
    D : list/cell of matrices of shape(M,M), length(types+1)
        The D0...Dtypes matrices of the DMMAP 
    
    Notes
    -----
    If it fails, try to increase the 'maxTrials' parameter,
    or/and the 'mean' parameter.
    """

    # distribute the zero entries among the rows
    def allZeroDistr(states, zeros):
        if states == 1:
            return [[zeros]]
        else:
            o = []
            for i in range(zeros + 1):
                x = allZeroDistr(states - 1, zeros - i)
                for j in range(len(x)):
                    xt = x[j]
                    xt.append(i)
                    xt.sort()
                    # check if we have it already
                    if o.count(xt) == 0:
                        o.append(xt)
            return o

    if zeroEntries > (types + 1) * order * order - 2 * order:
        raise Exception(
            "RandomDMAP/DMMAP: Too many zero entries requested! Try to decrease the zeroEntries parameter!"
        )

    zeroDistr = allZeroDistr(order, zeroEntries)

    trials = 1
    while trials < maxTrials:
        # select a configuration from zeroDistr: it is a list describing the zero entries in each row
        zdix = np.random.permutation(len(zeroDistr))
        for k in range(len(zeroDistr)):
            zDistr = zeroDistr[zdix[k]]
            bad = False
            for d in zDistr:
                if d >= (types + 1) * order - 1:
                    bad = True
                    break
            if bad:
                continue
            B = np.zeros((order, (types + 1) * order))
            for i in range(order):
                rp = np.random.permutation((types + 1) * order - 1)
                a = np.zeros((types + 1) * order - 1)
                for j in range((types + 1) * order - 1 - zDistr[i]):
                    a[rp[j]] = np.random.rand()
                B[i, 0:i] = a[0:i]
                B[i, i + 1:] = a[i:]
            # construct DMMAP matrices
            D = []
            sc = np.zeros(order)
            for i in range(types + 1):
                Di = ml.matrix(B[:, i * order:(i + 1) * order])
                D.append(Di)
                sc += np.sum(Di, 1).A.flatten()
            if np.any(sc == 0):
                continue
            for i in range(types + 1):
                D[i] = Diag(1.0 / sc) * D[i]
            # check if it is a proper DMAP (irreducible phase process & no full zero matrix)
            sumD = SumMatrixList(D)
            if la.matrix_rank(D[0]) == order and la.matrix_rank(
                    ml.eye(D[0].shape[0]) - sumD) == order - 1:
                alpha = DTMCSolve(sumD)
                if np.min(np.abs(alpha)) > prec:
                    fullZero = False
                    for Di in D:
                        if np.all(Di == 0.0):
                            fullZero = True
                            break
                    if not fullZero:
                        # diagonals of matrix A:
                        d = np.random.rand(order)
                        # scale to the mean value
                        Dv = []
                        for i in range(types + 1):
                            Dv.append(Diag(1 - d) * D[i])
                        Dv[0] = Dv[0] + Diag(d)
                        try:
                            m = MarginalMomentsFromDMMAP(Dv, 1)[0]
                            d = 1 - (1 - d) * m / mean
                            for i in range(types + 1):
                                D[i] = Diag(1 - d) * D[i]
                            D[0] = D[0] + Diag(d)
                            if CheckDMMAPRepresentation(D):
                                return D
                        except:
                            pass
            trials += 1
    raise Exception(
        "No feasible random DMAP/DMMAP found with such many zero entries! Try to increase the maxTrials parameter!"
    )
示例#5
0
def QBDQueue(B, L, F, L0, *argv):
    """
    Returns various performane measures of a continuous time
    QBD queue.
    
    QBD queues have a background continuous time Markov chain
    with generator Q whose the transitions can be partitioned
    into three sets: transitions accompanied by an arrival
    of a new job (F, forward), transitions accompanied by 
    the service of the current job in the server (B, 
    backward) and internal transitions (L, local). 
    Thus we have Q=B+L+F. L0 is the matrix of local 
    transition rates if the queue is empty.
    
    Parameters
    ----------
    B : matrix, shape(N,N)
        Transitions of the background process accompanied by 
        the service of the current job in the server
    L : matrix, shape(N,N)
        Internal transitions of the background process 
        that do not generate neither arrival nor service
    F : matrix, shape(N,N)
        Transitions of the background process accompanied by 
        an arrival of a new job
    L0 : matrix, shape(N,N)
        Internal transitions of the background process when
        there are no jobs in the queue
    further parameters : 
        The rest of the function parameters specify the options
        and the performance measures to be computed.
    
        The supported performance measures and options in this 
        function are:
        
        +----------------+--------------------+----------------------------------------+
        | Parameter name | Input parameters   | Output                                 |
        +================+====================+========================================+
        | "ncMoms"       | Number of moments  | The moments of the number of customers |
        +----------------+--------------------+----------------------------------------+
        | "ncDistr"      | Upper limit K      | The distribution of the number of      |
        |                |                    | customers from level 0 to level K-1    |
        +----------------+--------------------+----------------------------------------+
        | "ncDistrMG"    | None               | The vector-matrix parameters of the    |
        |                |                    | matrix-geometric distribution of the   |
        |                |                    | number of customers in the system      |
        +----------------+--------------------+----------------------------------------+
        | "ncDistrDPH"   | None               | The vector-matrix parameters of the    |
        |                |                    | matrix-geometric distribution of the   |
        |                |                    | number of customers in the system,     |
        |                |                    | converted to a discrete PH             |
        |                |                    | representation                         |
        +----------------+--------------------+----------------------------------------+
        | "stMoms"       | Number of moments  | The sojourn time moments               |
        +----------------+--------------------+----------------------------------------+
        | "stDistr"      | A vector of points | The sojourn time distribution at the   |
        |                |                    | requested points (cummulative, cdf)    |
        +----------------+--------------------+----------------------------------------+
        | "stDistrME"    | None               | The vector-matrix parameters of the    |
        |                |                    | matrix-exponentially distributed       |
        |                |                    | sojourn time distribution              |
        +----------------+--------------------+----------------------------------------+
        | "stDistrPH"    | None               | The vector-matrix parameters of the    |
        |                |                    | matrix-exponentially distributed       |
        |                |                    | sojourn time distribution, converted   |
        |                |                    | to a continuous PH representation      |
        +----------------+--------------------+----------------------------------------+
        | "prec"         | The precision      | Numerical precision used as a stopping |
        |                |                    | condition when solving the             |
        |                |                    | matrix-quadratic equation              |
        +----------------+--------------------+----------------------------------------+
        
        (The quantities related to the number of customers in 
        the system include the customer in the server, and the 
        sojourn time related quantities include the service 
        times as well)
        
    Returns
    -------
    Ret : list of the performance measures
        Each entry of the list corresponds to a performance 
        measure requested. If there is just a single item, 
        then it is not put into a list.
    
    Notes
    -----
    "ncDistrMG" and "stDistrMG" behave much better numerically than 
    "ncDistrDPH" and "stDistrPH".
    """

    # parse options
    prec = 1e-14
    needST = False
    eaten = []
    for i in range(len(argv)):
        if argv[i] == "prec":
            prec = argv[i + 1]
            eaten.append(i)
            eaten.append(i + 1)
        elif type(argv[i]) is str and len(
                argv[i]) > 2 and argv[i][0:2] == "st":
            needST = True

    if butools.checkInput and not CheckGenerator(B + L + F):
        raise Exception(
            'QBDQueue: The matrix sum (B+L+F) is not a valid generator of a Markov chain!'
        )

    if butools.checkInput and not CheckGenerator(L0 + F):
        raise Exception(
            'QBDQueue: The matrix sum (L0+F) is not a valid generator of a Markov chain!'
        )

    pi0, R = QBDSolve(B, L, F, L0, prec)
    N = pi0.shape[1]
    I = ml.eye(N)

    if needST:
        U = L + R * B
        Rh = (-U).I * F
        eta = pi0 * F * (I - Rh).I
        eta = eta / np.sum(eta)
        z = np.reshape(I, (N * N, 1), 'F')

    Ret = []
    argIx = 0
    while argIx < len(argv):
        if argIx in eaten:
            argIx += 1
            continue
        elif type(argv[argIx]) is str and argv[argIx] == "ncDistrDPH":
            # transform it to DPH
            alpha = pi0 * R * (I - R).I
            A = Diag(alpha).I * R.T * Diag(alpha)
            Ret.append(alpha)
            Ret.append(A)
        elif type(argv[argIx]) is str and argv[argIx] == "ncDistrMG":
            # transform it to MG
            B = SimilarityMatrixForVectors(np.sum((I - R).I * R, 1),
                                           np.ones((N, 1)))
            Bi = B.I
            A = B * R * Bi
            alpha = pi0 * Bi
            Ret.append(alpha)
            Ret.append(A)
        elif type(argv[argIx]) is str and argv[argIx] == "ncMoms":
            numOfMoms = argv[argIx + 1]
            argIx += 1
            moms = []
            iR = (I - R).I
            for m in range(1, numOfMoms + 1):
                moms.append(
                    math.factorial(m) * np.sum(pi0 * iR**(m + 1) * R**m))
            Ret.append(MomsFromFactorialMoms(moms))
        elif type(argv[argIx]) is str and argv[argIx] == "ncDistr":
            numOfQLProbs = argv[argIx + 1]
            argIx += 1
            values = np.empty(numOfQLProbs)
            values[0] = np.sum(pi0)
            RPow = I
            for p in range(numOfQLProbs - 1):
                RPow = RPow * R
                values[p + 1] = np.sum(pi0 * RPow)
            Ret.append(values)
        elif type(argv[argIx]) is str and argv[argIx] == "stDistrPH":
            # transform to ph distribution
            ix = np.arange(N)
            nz = ix[eta.flat > prec]
            Delta = Diag(eta)
            A = np.kron(L + F, I[nz, :][:, nz]) + np.kron(
                B, Delta[nz, :][:, nz].I * Rh[nz, :][:, nz].T *
                Delta[nz, :][:, nz])
            alpha = z.T * np.kron(I, Delta[:, nz])
            Ret.append(alpha)
            Ret.append(A)
        elif type(argv[argIx]) is str and argv[argIx] == "stDistrME":
            # transform it such that the closing vector is a vector of ones
            # this is the way butools accepts ME distributions
            Bm = SimilarityMatrixForVectors(z, np.ones(z.shape))
            Bmi = Bm.I
            A = Bm * (np.kron(L.T + F.T, I) + np.kron(B.T, Rh)) * Bmi
            alpha = np.kron(ml.ones((1, N)), eta) * Bmi
            Ret.append(alpha)
            Ret.append(A)
        elif type(argv[argIx]) is str and argv[argIx] == "stMoms":
            numOfMoms = argv[argIx + 1]
            argIx += 1
            moms = []
            Z = np.kron(L.T + F.T, I) + np.kron(B.T, Rh)
            iZ = -Z.I
            for m in range(1, numOfMoms + 1):
                moms.append(
                    math.factorial(m) * np.sum(
                        np.kron(ml.ones(
                            (1, N)), eta) * iZ**(m + 1) * (-Z) * z))
            Ret.append(moms)
        elif type(argv[argIx]) is str and argv[argIx] == "stDistr":
            points = argv[argIx + 1]
            argIx += 1
            values = np.empty(points.shape)
            Z = np.kron(L.T + F.T, I) + np.kron(B.T, Rh)
            for p in range(len(points.flat)):
                values.flat[p] = 1.0 - np.sum(
                    np.kron(ml.ones(
                        (1, N)), eta) * la.expm(Z * points.flat[p]) * z)
            Ret.append(values)
        else:
            raise Exception("QBDQueue: Unknown parameter " + str(argv[argIx]))
        argIx += 1
    if len(Ret) == 1:
        return Ret[0]
    else:
        return Ret
示例#6
0
def FluFluQueue(Qin, Rin, Qout, Rout, srv0stop, *argv):
    """
    Returns various performane measures of a fluid queue
    with independent fluid arrival and service processes.
    
    Two types of boundary behavior is available. If 
    srv0stop=false, the output process evolves continuously
    even if the queue is empty. If srv0stop=true, the 
    output process slows down if there is fewer fluid in
    the queue than it can serve. If the queue is empty
    and the fluid input rate is zero, the output process
    freezes till fluid arrives.
    
    Parameters
    ----------
    Qin : matrix, shape (N,N)
        The generator of the background Markov chain 
        corresponding to the input process
    Rin : matrix, shape (N,N)
        Diagonal matrix containing the fluid input rates
        associated to the states of the input background 
        process
    Qout : matrix, shape (N,N)
        The generator of the background Markov chain 
        corresponding to the output process
    Rout : matrix, shape (N,N)
        Diagonal matrix containing the fluid output rates
        associated to the states of the input background 
        process
    srv0stop : bool
        If true, the service output process slows down if
        there is fewer fluid in the queue than it can 
        serve. If false, the output process evolves 
        continuously.
    further parameters : 
        The rest of the function parameters specify the options
        and the performance measures to be computed.
    
        The supported performance measures and options in this 
        function are:
        
        +----------------+--------------------+--------------------------------------+
        | Parameter name | Input parameters   | Output                               |
        +================+====================+======================================+
        | "flMoms"       | Number of moments  | The moments of the fluid level       |
        +----------------+--------------------+--------------------------------------+
        | "flDistr"      | A vector of points | The fluid level distribution at      |
        |                |                    | the requested points (cdf)           |
        +----------------+--------------------+--------------------------------------+
        | "flDistrME"    | None               | The vector-matrix parameters of the  |
        |                |                    | matrix-exponentially distributed     |
        |                |                    | fluid level distribution             |
        +----------------+--------------------+--------------------------------------+
        | "flDistrPH"    | None               | The vector-matrix parameters of the  |
        |                |                    | matrix-exponentially distributed     |
        |                |                    | fluid level distribution, converted  |
        |                |                    | to a PH representation               |
        +----------------+--------------------+--------------------------------------+
        | "stMoms"       | Number of moments  | The sojourn time moments of fluid    |
        |                |                    | drops                                |
        +----------------+--------------------+--------------------------------------+
        | "stDistr"      | A vector of points | The sojourn time distribution at the |
        |                |                    | requested points (cummulative, cdf)  |
        +----------------+--------------------+--------------------------------------+
        | "stDistrME"    | None               | The vector-matrix parameters of the  |
        |                |                    | matrix-exponentially distributed     |
        |                |                    | sojourn time distribution            |
        +----------------+--------------------+--------------------------------------+
        | "stDistrPH"    | None               | The vector-matrix parameters of the  |
        |                |                    | matrix-exponentially distributed     |
        |                |                    | sojourn time distribution, converted |
        |                |                    | to a PH representation               |
        +----------------+--------------------+--------------------------------------+
        | "prec"         | The precision      | Numerical precision to check if the  |
        |                |                    | input is valid and it is also used   |
        |                |                    | as a stopping condition when solving |
        |                |                    | the Riccati equation                 |
        +----------------+--------------------+--------------------------------------+
    
    Returns
    -------
    Ret : list of the performance measures
        Each entry of the list corresponds to a performance 
        measure requested. If there is just a single item, 
        then it is not put into a list.
    
    Notes
    -----
    "flDistrME" and "stDistrME" behave much better numerically than 
    "flDistrPH" and "stDistrPH".
    
    References
    ----------
    .. [1] Horvath G, Telek M, "Sojourn times in fluid queues 
           with independent and dependent input and output 
           processes PERFORMANCE EVALUATION 79: pp. 160-181, 2014.
    """

    # parse options
    prec = 1e-14
    needST = False
    needQL = False
    Q0 = []
    eaten = []
    for i in range(len(argv)):
        if type(argv[i]) is str and argv[i]=="prec":
            prec = argv[i+1]
            eaten.append(i)
            eaten.append(i+1)
        elif type(argv[i]) is str and len(argv[i])>2 and argv[i][0:2]=="st":
            needST = True
        elif type(argv[i]) is str and len(argv[i])>2 and argv[i][0:2]=="fl":
            needQL = True

    if butools.checkInput and not CheckGenerator(Qin,False):
        raise Exception('FluFluQueue: Generator matrix Qin is not Markovian!')

    if butools.checkInput and not CheckGenerator(Qout,False):
        raise Exception('FluFluQueue: Generator matrix Qout is not Markovian!')

    if butools.checkInput and (np.any(np.diag(Rin)<-butools.checkPrecision) or np.any(np.diag(Rout)<-butools.checkPrecision)):
        raise Exception('FluFluQueue: Fluid rates Rin and Rout must be non-negative !')

    Iin = ml.eye(Qin.shape[0])
    Iout = ml.eye(Qout.shape[0])

    if needQL:
        Q = np.kron(Qin,Iout)+np.kron(Iin,Qout)
        if srv0stop:
            Q0 = np.kron(Qin,Iout)+np.kron(Rin, la.pinv(Rout)*Qout)
        else:
            Q0 = Q
        mass0, ini, K, clo = GeneralFluidSolve (Q, np.kron(Rin,Iout)-np.kron(Iin,Rout), Q0, prec)

    if needST:
        Rh = np.kron(Rin,Iout) - np.kron(Iin,Rout)
        Qh = np.kron(Qin, Rout) + np.kron(Rin, Qout)
        massh, inih, Kh, cloh = GeneralFluidSolve (Qh, Rh, prec=prec)

        # sojourn time density in case of 
        # srv0stop = false: inih*expm(Kh*x)*cloh*kron(Rin,Iout)/lambda
        # srv0stop = true: inih*expm(Kh*x)*cloh*kron(Rin,Rout)/lambda/mu    
        lambd = np.sum(CTMCSolve(Qin)*Rin)
        mu = np.sum(CTMCSolve(Qout)*Rout)
    
    Ret = []
    argIx = 0
    while argIx<len(argv):
        if argIx in eaten:
            argIx += 1
            continue
        elif type(argv[argIx]) is str and argv[argIx]=='flDistrPH':
            # transform it to PH
            Delta = Diag(Linsolve(K.T,-ini.T)) # Delta = diag (ini*inv(-K));
            A = Delta.I*K.T*Delta
            alpha = np.sum(clo,1).T*Delta
            Ret.append(alpha)
            Ret.append(A)
        elif type(argv[argIx]) is str and argv[argIx]=='flDistrME':
            # transform it to ME
            B = SimilarityMatrixForVectors((-K).I*np.sum(clo,1), np.ones((K.shape[0],1)))
            Bi = B.I
            alpha = ini*Bi
            A = B*K*Bi
            Ret.append(alpha)
            Ret.append(A)
        elif type(argv[argIx]) is str and argv[argIx]=='flMoms':
            numOfMoms = argv[argIx+1]
            argIx += 1
            moms = []
            iK = -K.I
            for m in range(1,numOfMoms+1):
                moms.append(math.factorial(m)*np.sum(ini*iK**(m+1)*clo))
            Ret.append(moms)
        elif type(argv[argIx]) is str and argv[argIx]=='flDistr':
            points = argv[argIx+1]
            argIx += 1
            values = np.empty(points.shape)
            iK = -K.I
            for p in range(len(points.flat)):
                values.flat[p] = np.sum(mass0) + np.sum(ini*(ml.eye(K.shape[0])-la.expm(K*points.flat[p]))*iK*clo)
            Ret.append (values)
        elif type(argv[argIx]) is str and argv[argIx]=='stDistrPH':
            # convert result to PH representation
            Delta = Diag(Linsolve(Kh.T,-inih.T)) # Delta = diag (inih*inv(-Kh));
            A = Delta.I*Kh.T*Delta
            if not srv0stop:
                alpha = np.sum(Delta*cloh*np.kron(Rin,Iout)/lambd,1).T
            else:
                alpha = np.sum(Delta*cloh*np.kron(Rin,Rout)/lambd/mu,1).T
            Ret.append(alpha)
            Ret.append(A)
        elif type(argv[argIx]) is str and argv[argIx]=='stDistrME':
            # convert result to ME representation
            if not srv0stop:
                B = SimilarityMatrixForVectors(np.sum(cloh*np.kron(Rin,Iout)/lambd,1), np.ones((Kh.shape[0],1)))
            else:
                B = SimilarityMatrixForVectors(np.sum(cloh*np.kron(Rin,Rout)/lambd/mu,1), np.ones((Kh.shape[0],1)))
            iB = B.I
            A = B*Kh*iB
            alpha = inih*(-Kh).I*iB
            Ret.append(alpha)
            Ret.append(A)
        elif type(argv[argIx]) is str and argv[argIx]=='stMoms':
            numOfMoms = argv[argIx+1]
            argIx += 1
            moms = []
            if srv0stop:
                kclo = cloh*np.kron(Rin,Rout)/lambd/mu
            else:
                kclo = cloh*np.kron(Rin,Iout)/lambd
            iKh = -Kh.I
            for m in range(1,numOfMoms+1):
                moms.append(math.factorial(m)*np.sum(inih*iKh**(m+1)*kclo))
            Ret.append(moms)
        elif type(argv[argIx]) is str and argv[argIx]=='stDistr':
            points = argv[argIx+1]
            argIx += 1
            values = np.empty(points.shape)
            if srv0stop:
                kclo = cloh*np.kron(Rin,Rout)/lambd/mu
            else:
                kclo = cloh*np.kron(Rin,Iout)/lambd
            iKh = -Kh.I
            for p in range(len(points.flat)):
                values.flat[p] = 1.0-np.sum(inih*la.expm(Kh*points.flat[p])*iKh*kclo)
            Ret.append(values)
        else:
            raise Exception ("FluFluQueue: Unknown parameter "+str(argv[argIx]))
        argIx += 1

    if len(Ret)==1:
        return Ret[0]
    else:
        return Ret
示例#7
0
def FluidQueue (Q, Rin, Rout, *argv):
    """
    Returns various performane measures of a fluid queue.
    
    In a fluid queue there is a background continuous time
    Markov chain (given by generator Q), and diagonal
    matrix Rin (Rout) whose ith entry provides the 
    fluid rate at which fluid enters the queue (can be 
    served) while the background process is in state i.
    
    Parameters
    ----------
    Q : matrix, shape (N,N)
        The generator of the background Markov chain
    Rin : matrix, shape (N,N)
        Diagonal matrix containing the fluid input rates
        associated to the states of the background process
    Rout : matrix, shape (N,N)
        Diagonal matrix containing the fluid output rates
        associated to the states of the background process
    further parameters : 
        The rest of the function parameters specify the options
        and the performance measures to be computed.
    
        The supported performance measures and options in this 
        function are:
    
        +----------------+--------------------+--------------------------------------+
        | Parameter name | Input parameters   | Output                               |
        +================+====================+======================================+
        | "flMoms"       | Number of moments  | The moments of the fluid level       |
        +----------------+--------------------+--------------------------------------+
        | "flDistr"      | A vector of points | The fluid level distribution at      |
        |                |                    | the requested points (cdf)           |
        +----------------+--------------------+--------------------------------------+
        | "flDistrME"    | None               | The vector-matrix parameters of the  |
        |                |                    | matrix-exponentially distributed     |
        |                |                    | fluid level distribution             |
        +----------------+--------------------+--------------------------------------+
        | "flDistrPH"    | None               | The vector-matrix parameters of the  |
        |                |                    | matrix-exponentially distributed     |
        |                |                    | fluid level distribution, converted  |
        |                |                    | to a PH representation               |
        +----------------+--------------------+--------------------------------------+
        | "stMoms"       | Number of moments  | The sojourn time moments of fluid    |
        |                |                    | drops                                |
        +----------------+--------------------+--------------------------------------+
        | "stDistr"      | A vector of points | The sojourn time distribution at the |
        |                |                    | requested points (cummulative, cdf)  |
        +----------------+--------------------+--------------------------------------+
        | "stDistrME"    | None               | The vector-matrix parameters of the  |
        |                |                    | matrix-exponentially distributed     |
        |                |                    | sojourn time distribution            |
        +----------------+--------------------+--------------------------------------+
        | "stDistrPH"    | None               | The vector-matrix parameters of the  |
        |                |                    | matrix-exponentially distributed     |
        |                |                    | sojourn time distribution, converted |
        |                |                    | to a PH representation               |
        +----------------+--------------------+--------------------------------------+
        | "prec"         | The precision      | Numerical precision to check if the  |
        |                |                    | input is valid and it is also used   |
        |                |                    | as a stopping condition when solving |
        |                |                    | the Riccati equation                 |
        +----------------+--------------------+--------------------------------------+
        | "Q0"           | Matrix, shape(N,N) | The generator of the background      |
        |                |                    | Markov chain when the fluid level is |
        |                |                    | zero. If not given, Q0=Q is assumed  |
        +----------------+--------------------+--------------------------------------+
    
    Returns
    -------
    Ret : list of the performance measures
        Each entry of the list corresponds to a performance 
        measure requested. If there is just a single item, 
        then it is not put into a list.
    
    Notes
    -----
    "flDistrME" and "stDistrME" behave much better numerically than 
    "flDistrPH" and "stDistrPH".
    """

    # parse options
    prec = 1e-14
    needST = False
    Q0 = []
    eaten = []
    for i in range(len(argv)):
        if type(argv[i]) is str and argv[i]=="prec":
            prec = argv[i+1]
            eaten.append(i)
            eaten.append(i+1)
        elif type(argv[i]) is str and argv[i]=="Q0":
            Q0 = argv[i+1]
            eaten.append(i)
            eaten.append(i+1)
        elif type(argv[i]) is str and len(argv[i])>2 and argv[i][0:2]=="st":
            needST = True

    if butools.checkInput and not CheckGenerator(Q,False):
        raise Exception('FluidQueue: Generator matrix Q is not Markovian!')

    if butools.checkInput and len(Q0)>0 and not CheckGenerator(Q0,False):
        raise Exception('FluidQueue: Generator matrix Q0 is not Markovian!')

    if butools.checkInput and (np.any(np.diag(Rin)<-butools.checkPrecision) or np.any(np.diag(Rout)<-butools.checkPrecision)):
        raise Exception('FluidQueue: Fluid rates Rin and Rout must be non-negative !')

    mass0, ini, K, clo = GeneralFluidSolve (Q, Rin-Rout, Q0, prec)
    if needST:
        N = Q.shape[0]
        iniKi = Linsolve(K.T,-ini.T).T # iniki = ini*inv(-K);
        lambd = np.sum(mass0*Rin + iniKi*clo*Rin)
    
    Ret = []
    argIx = 0
    while argIx<len(argv):
        if argIx in eaten:
            argIx += 1
            continue
        elif type(argv[argIx]) is str and argv[argIx]=='flDistrPH':
            # transform it to PH
            Delta = Diag(Linsolve(K.T,-ini.T)) # Delta = diag (ini*inv(-K));
            A = Delta.I*K.T*Delta
            alpha = np.sum(clo,1).T*Delta
            Ret.append(alpha)
            Ret.append(A)
        elif type(argv[argIx]) is str and argv[argIx]=='flDistrME':
            # transform it to ME
            B = SimilarityMatrixForVectors((-K).I*np.sum(clo,1), np.ones((K.shape[0],1)))
            Bi = B.I
            alpha = ini*Bi
            A = B*K*Bi
            Ret.append(alpha)
            Ret.append(A)
        elif type(argv[argIx]) is str and argv[argIx]=='flMoms':
            numOfMoms = argv[argIx+1]
            argIx += 1
            moms = []
            iK = -K.I
            for m in range(1,numOfMoms+1):
                moms.append(math.factorial(m)*np.sum(ini*iK**(m+1)*clo))
            Ret.append(moms)
        elif type(argv[argIx]) is str and argv[argIx]=='flDistr':
            points = argv[argIx+1]
            argIx += 1
            values = np.empty(points.shape)
            iK = -K.I
            for p in range(len(points.flat)):
                values.flat[p] = np.sum(mass0) + np.sum(ini*(ml.eye(K.shape[0])-la.expm(K*points.flat[p]))*iK*clo)
            Ret.append (values)
        elif type(argv[argIx]) is str and argv[argIx]=='stDistrPH':
            # transform it to PH
            Delta = Diag(iniKi/lambd)
            alpha = np.reshape(clo*Rin,(1,N*len(ini.flat)),'F')*np.kron(ml.eye(N),Delta)
            A = np.kron(Rout, Delta.I*K.T*Delta) + np.kron(Q, ml.eye(K.shape[0]))
            Ret.append(alpha)
            Ret.append(A)
        elif type(argv[argIx]) is str and argv[argIx]=='stDistrME':
            B = SimilarityMatrixForVectors(np.reshape(-K.I*clo*Rin,(N*ini.size,1),'F'), np.ones((N*ini.size,1)))
            Bi = B.I
            alpha = np.kron(ml.ones((1,N)), ini/lambd)*Bi
            A = B*(np.kron(Q.T,ml.eye(K.shape[0])) + np.kron(Rout,K))*Bi        
            Ret.append(alpha)
            Ret.append(A)
        elif type(argv[argIx]) is str and argv[argIx]=='stMoms':
            numOfMoms = argv[argIx+1]
            argIx += 1
            moms = []
            Z = np.kron(Q.T,ml.eye(K.shape[0])) + np.kron(Rout,K)
            iZ = -Z.I
            kini = np.kron(ml.ones((1,N)), ini/lambd)
            kclo = np.reshape(-K.I*clo*Rin,(N*ini.size,1),'F')
            for m in range(1,numOfMoms+1):
                moms.append(math.factorial(m)*np.sum(kini*iZ**(m+1)*(-Z)*kclo))
            Ret.append(moms)
        elif type(argv[argIx]) is str and argv[argIx]=='stDistr':
            points = argv[argIx+1]
            argIx += 1
            values = np.empty(points.shape)
            Z = np.kron(Q.T,ml.eye(K.shape[0])) + np.kron(Rout,K)
            kini = np.kron(ml.ones((1,N)), ini/lambd)
            kclo = np.reshape(-K.I*clo*Rin,(N*ini.size,1),'F')
            for p in range(len(points.flat)):
                values.flat[p] = 1.0-np.sum(kini*la.expm(Z*points.flat[p])*kclo)
            Ret.append(values)
        else:
            raise Exception ("FluidQueue: Unknown parameter "+str(argv[argIx]))
        argIx += 1

    if len(Ret)==1:
        return Ret[0]
    else:
        return Ret
示例#8
0
def MMAPPH1FCFS(D, sigma, S, *argv):
    """
    Returns various performane measures of a MMAP[K]/PH[K]/1 
    first-come-first-serve queue, see [1]_.
    
    Parameters
    ----------
    D : list of matrices of shape (N,N), length (K+1)
        The D0...DK matrices of the arrival process.
    sigma : list of row vectors, length (K)
        The list containing the initial probability vectors of the service
        time distributions of the various customer types. The length of the
       vectors does not have to be the same.
    S : list of square matrices, length (K)
        The transient generators of the phase type distributions representing
        the service time of the jobs belonging to various types.
    further parameters : 
        The rest of the function parameters specify the options
        and the performance measures to be computed.
    
        The supported performance measures and options in this 
        function are:
    
        +----------------+--------------------+----------------------------------------+
        | Parameter name | Input parameters   | Output                                 |
        +================+====================+========================================+
        | "ncMoms"       | Number of moments  | The moments of the number of customers |
        +----------------+--------------------+----------------------------------------+
        | "ncDistr"      | Upper limit K      | The distribution of the number of      |
        |                |                    | customers from level 0 to level K-1    |
        +----------------+--------------------+----------------------------------------+
        | "stMoms"       | Number of moments  | The sojourn time moments               |
        +----------------+--------------------+----------------------------------------+
        | "stDistr"      | A vector of points | The sojourn time distribution at the   |
        |                |                    | requested points (cummulative, cdf)    |
        +----------------+--------------------+----------------------------------------+
        | "stDistrME"    | None               | The vector-matrix parameters of the    |
        |                |                    | matrix-exponentially distributed       |
        |                |                    | sojourn time distribution              |
        +----------------+--------------------+----------------------------------------+
        | "stDistrPH"    | None               | The vector-matrix parameters of the    |
        |                |                    | matrix-exponentially distributed       |
        |                |                    | sojourn time distribution, converted   |
        |                |                    | to a continuous PH representation      |
        +----------------+--------------------+----------------------------------------+
        | "prec"         | The precision      | Numerical precision used as a stopping |
        |                |                    | condition when solving the Riccati     |
        |                |                    | equation                               |
        +----------------+--------------------+----------------------------------------+
        | "classes"      | Vector of integers | Only the performance measures          |
        |                |                    | belonging to these classes are         |
        |                |                    | returned. If not given, all classes    |
        |                |                    | are analyzed.                          |
        +----------------+--------------------+----------------------------------------+
        
        (The quantities related to the number of customers in 
        the system include the customer in the server, and the 
        sojourn time related quantities include the service 
        times as well)
    
    Returns
    -------
    Ret : list of the performance measures
        Each entry of the list corresponds to a performance 
        measure requested. Each entry is a matrix, where the
        columns belong to the various job types.
        If there is just a single item, 
        then it is not put into a list.
    
    References
    ----------
    .. [1] Qiming He, "Analysis of a continuous time 
           SM[K]/PH[K]/1/FCFS queue: Age process, sojourn times,
           and queue lengths", Journal of Systems Science and 
           Complexity, 25(1), pp 133-155, 2012.
    """

    K = len(D) - 1

    # parse options
    eaten = []
    precision = 1e-14
    classes = np.arange(0, K)
    for i in range(len(argv)):
        if argv[i] == "prec":
            precision = argv[i + 1]
            eaten.append(i)
            eaten.append(i + 1)
        elif argv[i] == "classes":
            classes = np.array(argv[i + 1]) - 1
            eaten.append(i)
            eaten.append(i + 1)

    if butools.checkInput and not CheckMMAPRepresentation(D):
        raise Exception(
            'MMAPPH1FCFS: The arrival process is not a valid MMAP representation!'
        )

    if butools.checkInput:
        for k in range(K):
            if not CheckPHRepresentation(sigma[k], S[k]):
                raise Exception(
                    'MMAPPH1FCFS: the vector and matrix describing the service times is not a valid PH representation!'
                )

    # some preparation
    D0 = D[0]
    N = D0.shape[0]
    Ia = ml.eye(N)
    Da = ml.zeros((N, N))
    for q in range(K):
        Da += D[q + 1]
    theta = CTMCSolve(D0 + Da)
    beta = [CTMCSolve(S[k] + ml.sum(-S[k], 1) * sigma[k]) for k in range(K)]
    lambd = [np.sum(theta * D[k + 1]) for k in range(K)]
    mu = [np.sum(beta[k] * (-S[k])) for k in range(K)]
    Nsk = [S[k].shape[0] for k in range(K)]
    ro = np.sum(np.array(lambd) / np.array(mu))
    alpha = theta * Da / sum(lambd)
    D0i = (-D0).I

    Sa = S[0]
    sa = [ml.zeros(sigma[0].shape)] * K
    sa[0] = sigma[0]
    ba = [ml.zeros(beta[0].shape)] * K
    ba[0] = beta[0]
    sv = [ml.zeros((Nsk[0], 1))] * K
    sv[0] = ml.sum(-S[0], 1)
    Pk = [D0i * D[q + 1] for q in range(K)]

    for k in range(1, K):
        Sa = la.block_diag(Sa, S[k])
        for q in range(K):
            if q == k:
                sa[q] = ml.hstack((sa[q], sigma[k]))
                ba[q] = ml.hstack((ba[q], beta[k]))
                sv[q] = ml.vstack((sv[q], -np.sum(S[k], 1)))
            else:
                sa[q] = ml.hstack((sa[q], ml.zeros(sigma[k].shape)))
                ba[q] = ml.hstack((ba[q], ml.zeros(beta[k].shape)))
                sv[q] = ml.vstack((sv[q], ml.zeros((Nsk[k], 1))))
    Sa = ml.matrix(Sa)
    P = D0i * Da
    iVec = ml.kron(D[1], sa[0])
    for k in range(1, K):
        iVec += ml.kron(D[k + 1], sa[k])
    Ns = Sa.shape[0]
    Is = ml.eye(Ns)

    # step 1. solve the age process of the queue
    # ==========================================

    # solve Y0 and calculate T
    Y0 = FluidFundamentalMatrices(ml.kron(Ia, Sa), ml.kron(Ia, -ml.sum(Sa, 1)),
                                  iVec, D0, "P", precision)
    T = ml.kron(Ia, Sa) + Y0 * iVec

    # calculate pi0 and v0
    pi0 = ml.zeros((1, T.shape[0]))
    for k in range(K):
        pi0 += ml.kron(theta * D[k + 1], ba[k] / mu[k])
    pi0 = -pi0 * T

    iT = (-T).I
    oa = ml.ones((N, 1))

    # step 2. calculate performance measures
    # ======================================
    Ret = []
    for k in classes:
        argIx = 0
        clo = iT * ml.kron(oa, sv[k])
        while argIx < len(argv):
            if argIx in eaten:
                argIx += 1
                continue
            elif type(argv[argIx]) is str and argv[argIx] == "stMoms":
                numOfSTMoms = argv[argIx + 1]
                rtMoms = []
                for m in range(1, numOfSTMoms + 1):
                    rtMoms.append(
                        math.factorial(m) * np.sum(pi0 * iT**m * clo /
                                                   (pi0 * clo)))
                Ret.append(rtMoms)
                argIx += 1
            elif type(argv[argIx]) is str and argv[argIx] == "stDistr":
                stCdfPoints = argv[argIx + 1]
                cdf = []
                for t in stCdfPoints:
                    pr = 1 - np.sum(pi0 * la.expm(T * t) * clo / (pi0 * clo))
                    cdf.append(pr)
                Ret.append(np.array(cdf))
                argIx += 1
            elif type(argv[argIx]) is str and argv[argIx] == "stDistrME":
                Bm = SimilarityMatrixForVectors(clo / (pi0 * clo),
                                                ml.ones((N * Ns, 1)))
                Bmi = Bm.I
                A = Bm * T * Bmi
                alpha = pi0 * Bmi
                Ret.append(alpha)
                Ret.append(A)
            elif type(argv[argIx]) is str and argv[argIx] == "stDistrPH":
                vv = pi0 * iT
                ix = np.arange(N * Ns)
                nz = ix[vv.flat > precision]
                delta = Diag(vv[:, nz])
                cl = -T * clo / (pi0 * clo)
                alpha = cl[nz, :].T * delta
                A = delta.I * T[nz, :][:, nz].T * delta
                Ret.append(alpha)
                Ret.append(A)
            elif type(argv[argIx]) is str and argv[argIx] == "ncDistr":
                numOfQLProbs = argv[argIx + 1]
                argIx += 1
                values = np.empty(numOfQLProbs)
                jm = ml.zeros((Ns, 1))
                jm[np.sum(Nsk[0:k]):np.sum(Nsk[0:k + 1]), :] = 1
                jmc = ml.ones((Ns, 1))
                jmc[np.sum(Nsk[0:k]):np.sum(Nsk[0:k + 1]), :] = 0
                LmCurr = la.solve_sylvester(T, ml.kron(D0 + Da - D[k + 1], Is),
                                            -ml.eye(N * Ns))
                values[0] = 1 - ro + np.sum(pi0 * LmCurr * ml.kron(oa, jmc))
                for i in range(1, numOfQLProbs):
                    LmPrev = LmCurr
                    LmCurr = la.solve_sylvester(
                        T, ml.kron(D0 + Da - D[k + 1], Is),
                        -LmPrev * ml.kron(D[k + 1], Is))
                    values[i] = np.sum(pi0 * LmCurr * ml.kron(oa, jmc) +
                                       pi0 * LmPrev * ml.kron(oa, jm))
                Ret.append(values)
            elif type(argv[argIx]) is str and argv[argIx] == "ncMoms":
                numOfQLMoms = argv[argIx + 1]
                argIx += 1
                jm = ml.zeros((Ns, 1))
                jm[np.sum(Nsk[0:k]):np.sum(Nsk[0:k + 1]), :] = 1
                ELn = [
                    la.solve_sylvester(T, ml.kron(D0 + Da, Is),
                                       -ml.eye(N * Ns))
                ]
                qlMoms = []
                for n in range(1, numOfQLMoms + 1):
                    bino = 1
                    Btag = ml.zeros((N * Ns, N * Ns))
                    for i in range(n):
                        Btag += bino * ELn[i]
                        bino *= (n - i) / (i + 1)
                    ELn.append(
                        la.solve_sylvester(T, ml.kron(D0 + Da, Is),
                                           -Btag * ml.kron(D[k + 1], Is)))
                    qlMoms.append(
                        np.sum(pi0 * ELn[n]) +
                        np.sum(pi0 * Btag * ml.kron(oa, jm)))
                Ret.append(qlMoms)
            else:
                raise Exception("MMAPPH1FCFS: Unknown parameter " +
                                str(argv[argIx]))
            argIx += 1

    if len(Ret) == 1:
        return Ret[0]
    else:
        return Ret
示例#9
0
def RandomMMAP(order,
               types,
               mean=1.0,
               zeroEntries=0,
               maxTrials=1000,
               prec=1e-7):
    """
    Returns a random Markovian arrival process with given mean 
    value.
    
    Parameters
    ----------
    order : int
        The size of the MAP
    types : int
        The number of different arrival types
    mean : double, optional
        The mean inter-arrival times of the MMAP
    zeroEntries : int, optional
        The number of zero entries in the D0 and D1 matrices
    maxTrials : int, optional
        The maximum number of trials to find a proper MMAP 
        (that has an irreducible phase process and none of 
        its parameters is all-zero)
    prec : double, optional
        Numerical precision for checking the irreducibility.
        The default value is 1e-14.
    
    Returns
    -------
    D : list/cell of matrices of shape(M,M), length(types+1)
        The D0...Dtypes matrices of the MMAP 
    """

    # distribute the zero entries among the rows
    def allZeroDistr(states, zeros):
        if states == 1:
            return [[zeros]]
        else:
            o = []
            for i in range(zeros + 1):
                x = allZeroDistr(states - 1, zeros - i)
                for j in range(len(x)):
                    xt = x[j]
                    xt.append(i)
                    xt.sort()
                    # check if we have it already
                    if o.count(xt) == 0:
                        o.append(xt)
            return o

    if zeroEntries > (types + 1) * order * order - 2 * order:
        raise Exception(
            "RandomMAP/MMAP: Too many zero entries requested! Try to decrease the zeroEntries parameter!"
        )

    zeroDistr = allZeroDistr(order, zeroEntries)

    trials = 1
    while trials < maxTrials:
        # select a configuration from zeroDistr: it is a list describing the zero entries in each row
        zdix = np.random.permutation(len(zeroDistr))
        for k in range(len(zeroDistr)):
            zDistr = zeroDistr[zdix[k]]
            bad = False
            for d in zDistr:
                if d >= (types + 1) * order - 1:
                    bad = True
                    break
            if bad:
                continue
            B = np.zeros((order, (types + 1) * order))
            for i in range(order):
                rp = np.random.permutation((types + 1) * order - 1)
                a = np.zeros((types + 1) * order - 1)
                for j in range((types + 1) * order - 1 - zDistr[i]):
                    a[rp[j]] = np.random.rand()
                B[i, 0:i] = a[0:i]
                B[i, i + 1:] = a[i:]
            # construct MMAP matrices
            D = []
            for i in range(types + 1):
                Di = ml.matrix(B[:, i * order:(i + 1) * order])
                D.append(Di)
            D[0] -= Diag(np.sum(B, 1))
            # check if it is a proper MAP (irreducible phase process & no full zero matrix)
            sumD = ml.zeros((order, order))
            for i in range(len(D)):
                sumD += D[i]
            if la.matrix_rank(
                    D[0]) == order and la.matrix_rank(sumD) == order - 1:
                alpha = CTMCSolve(sumD)
                if np.min(np.abs(alpha)) > prec:
                    fullZero = False
                    for Di in D:
                        if np.all(Di == 0.0):
                            fullZero = True
                            break
                    if not fullZero:
                        # scale to the mean value
                        m = MarginalMomentsFromMMAP(D, 1)[0]
                        for i in range(types + 1):
                            D[i] *= m / mean
                        return D
            trials += 1
    raise Exception(
        "No feasible random MAP/MMAP found with such many zero entries! Try to increase the maxTrials parameter!"
    )