1% Example 12: Posterior analysis with uncertain parameters
3% This tutorial demonstrates how to analyze queueing models with parameter
4% uncertainty
using the Posterior solver. The Posterior solver works with
5% Prior distributions that represent uncertainty about model parameters,
6% computing posterior distributions of performance metrics.
8% Scenario: An M/M/1 queue where
the service rate
is uncertain. We model
9%
this uncertainty
using a Prior distribution with 30 alternatives,
10% creating a Gaussian-like distribution of possible service rates.
12%% Block 1: Create model with uncertain service rate
13model = Network(
'UncertainServiceModel');
16source = Source(model,
'Source');
17queue = Queue(model,
'Queue', SchedStrategy.FCFS);
18sink = Sink(model,
'Sink');
21jobClass = OpenClass(model,
'Jobs');
23% Set arrival rate (lambda = 0.5)
25source.setArrival(jobClass, Exp(lambda));
27%% Block 2: Define Prior distribution for uncertain service rate
28% Use many alternatives to create a smooth, continuous-looking PDF
29% Service rates range from 0.7 to 2.5 with a Gaussian-like prior
31serviceRates = linspace(0.7, 2.5, numAlternatives);
33% Create Gaussian-like prior probabilities centered at mu=1.3
36priorProbs = exp(-0.5 * ((serviceRates - priorMean) / priorStd).^2);
37priorProbs = priorProbs / sum(priorProbs); % Normalize to sum to 1
39alternatives = cell(1, numAlternatives);
40for i = 1:numAlternatives
41 alternatives{i} = Exp(serviceRates(i));
44prior = Prior(alternatives, priorProbs);
45queue.setService(jobClass, prior);
47%% Block 3: Complete model topology
48model.link(model.serialRouting(source, queue, sink));
50fprintf(
'Model: M/M/1 with uncertain service rate\n');
51fprintf(
'Arrival rate: lambda = %.1f\n', lambda);
52fprintf(
'Number of service rate alternatives: %d\n', numAlternatives);
53fprintf(
'Service rate range: mu in [%.2f, %.2f]\n', min(serviceRates), max(serviceRates));
54fprintf(
'Prior: Gaussian-like centered at mu=%.1f with std=%.1f\n\n', priorMean, priorStd);
56%% Block 4: Solve with Posterior wrapper
using MVA
57post = UQ(model, @MVA);
60%% Block 5: Get prior-weighted average results
61avgTable = post.getAvgTable()
63%% Block 6: Get posterior table with per-alternative results
64postTable = post.getPosteriorTable()
66%% Block 7: Extract posterior distributions
for different metrics
67% Get posterior distribution of response time at
the queue
68respDist = post.getPosteriorDist(
'R', queue, jobClass);
70% Get posterior distribution of queue length at
the queue
71qlenDist = post.getPosteriorDist(
'Q', queue, jobClass);
73% Get posterior distribution of utilization at
the queue
74utilDist = post.getPosteriorDist(
'U', queue, jobClass);
76%% Block 8: Extract values and probabilities from
the EmpiricalCDF objects
78respCdfData = respDist.data; % [CDF, Value]
79respValues = respCdfData(:, 2);
80respCdf = respCdfData(:, 1);
81respProbs = [respCdf(1); diff(respCdf)]; % Convert CDF to PMF
84qlenCdfData = qlenDist.data;
85qlenValues = qlenCdfData(:, 2);
86qlenCdf = qlenCdfData(:, 1);
87qlenProbs = [qlenCdf(1); diff(qlenCdf)];
90utilCdfData = utilDist.data;
91utilValues = utilCdfData(:, 2);
92utilCdf = utilCdfData(:, 1);
93utilProbs = [utilCdf(1); diff(utilCdf)];
95%% Block 9: Print posterior distribution statistics
96% Response time statistics
97expectedR = sum(respValues .* respProbs);
98[~, modeIdxR] = max(respProbs);
99fprintf(
'Response Time (R) at Queue:\n');
100fprintf(
' Expected Value E[R]: %.4f\n', expectedR);
101fprintf(
' Mode (most likely): %.4f\n\n', respValues(modeIdxR));
103% Queue length statistics
104expectedQ = sum(qlenValues .* qlenProbs);
105[~, modeIdxQ] = max(qlenProbs);
106fprintf(
'Queue Length (Q) at Queue:\n');
107fprintf(
' Expected Value E[Q]: %.4f\n', expectedQ);
108fprintf(
' Mode (most likely): %.4f\n\n', qlenValues(modeIdxQ));
110% Utilization statistics
111expectedU = sum(utilValues .* utilProbs);
112[~, modeIdxU] = max(utilProbs);
113fprintf(
'Utilization (U) at Queue:\n');
114fprintf(
' Expected Value E[U]: %.4f\n', expectedU);
115fprintf(
' Mode (most likely): %.4f\n\n', utilValues(modeIdxU));
117% Optional: Find median from CDF
118medianIdx = find(respCdf >= 0.5, 1,
'first');
119if ~isempty(medianIdx)
120 medianR = respValues(medianIdx);
121 fprintf(
'Response Time Median: %.4f\n', medianR);
124%% Block 10: Create PDF plots
125figure(
'Name',
'Posterior Distribution PDFs',
'Position', [100, 100, 1200, 400]);
127% Plot 1: Response Time PDF
129bar(respValues, respProbs, 1.0,
'FaceColor', [0.2, 0.6, 0.8],
'EdgeColor', [0.1, 0.4, 0.6]);
131xline(expectedR,
'r-',
'LineWidth', 2.5);
133xlabel(
'Response Time (R)');
134ylabel(
'Probability');
135title(
'Posterior PDF: Response Time');
136legend({
'P(R)', sprintf(
'E[R] = %.3f', expectedR)},
'Location',
'best');
139% Plot 2: Queue Length PDF
141bar(qlenValues, qlenProbs, 1.0,
'FaceColor', [0.4, 0.8, 0.4],
'EdgeColor', [0.2, 0.6, 0.2]);
143xline(expectedQ,
'r-',
'LineWidth', 2.5);
145xlabel(
'Queue Length (Q)');
146ylabel(
'Probability');
147title(
'Posterior PDF: Queue Length');
148legend({
'P(Q)', sprintf(
'E[Q] = %.3f', expectedQ)},
'Location',
'best');
151% Plot 3: Utilization PDF
153bar(utilValues, utilProbs, 1.0,
'FaceColor', [0.8, 0.4, 0.4],
'EdgeColor', [0.6, 0.2, 0.2]);
155xline(expectedU,
'r-',
'LineWidth', 2.5);
157xlabel(
'Utilization (U)');
158ylabel(
'Probability');
159title(
'Posterior PDF: Utilization');
160legend({
'P(U)', sprintf(
'E[U] = %.3f', expectedU)},
'Location',
'best');
163sgtitle(
'Posterior Distribution PDFs for M/M/1 with Uncertain Service Rate');
165%% Block 11: Posterior PDF (density) of
the response time
166% Difference
the empirical CDF into probability masses, then normalise by
the
167% bin width to obtain a density estimate over
the unequally spaced values.
168figure(
'Name',
'Response Time: Posterior PDF',
'Position', [150, 150, 700, 400]);
170edges = [respValues(1); (respValues(1:end-1) + respValues(2:end)) / 2; respValues(end)];
172density = respProbs ./ widths;
174bar(respValues, density,
'histc');
176xline(expectedR,
'k--',
'LineWidth', 2);
177medianIdx = find(respCdf >= 0.5, 1,
'first');
178if ~isempty(medianIdx)
179 medianR = respValues(medianIdx);
180 xline(medianR,
'r--',
'LineWidth', 2);
181 legend({
'f(R)', sprintf(
'mean = %.3f', expectedR), sprintf(
'median = %.3f', medianR)},
'Location',
'best');
183 legend({
'f(R)', sprintf(
'mean = %.3f', expectedR)},
'Location',
'best');
186xlabel(
'Response Time (R)');
187ylabel(
'Posterior PDF f(R)');
188title(
'Posterior PDF of Response Time');
191sgtitle(
'Response Time Posterior Distribution');