Сообщество Engee

Оптимизация СМО

Автор
avatar-artpgchartpgch
Notebook

Оптимизация распределения потоков в системах массового обслуживания

В современном цифровом мире — от глобальных сетей передачи данных до логистических цепочек и систем обработки транзакций — мы постоянно сталкиваемся с необходимостью эффективного управления потоками. Как обеспечить бесперебойную работу интернет-соединений при пиковых нагрузках? Как оптимизировать маршруты доставки товаров в мегаполисе? Как спроектировать call-центр, чтобы клиенты не ждали ответа? Ответы на эти вопросы лежат в области теории массового обслуживания — математической дисциплины, изучающей системы, где заявки (пакеты данных, клиенты, транспортные средства) поступают на обслуживание, образуя очереди.

Система массового обслуживания (СМО) представляет собой математическую модель, состоящую из обслуживающих устройств (каналов, серверов, узлов) и потока заявок, которые эти устройства обрабатывают. Особый интерес представляет система M/M/1 — фундаментальная модель, где входящий поток заявок имеет пуассоновский характер (случайные, независимые события с постоянной средней интенсивностью), а время обслуживания подчиняется экспоненциальному распределению (характеризующемуся свойством "отсутствия памяти"). Эта простая, но глубокая модель раскрывает парадоксальную природу очередей: при приближении нагрузки к 100% длина очереди растёт гиперболически, а не линейно, делая оптимизацию не просто желательной, а критически необходимой.

Сетевые СМО — следующий уровень сложности, где множество обслуживающих узлов соединены в сеть. Такая система естественно описывается направленным графом, где узлы представляют точки обработки, а ветви — каналы связи с ограниченной пропускной способностью. Для математического представления структуры сети используются матрица смежности (описывающая наличие связей между узлами) и матрица инцидентности (фиксирующая направления этих связей). Именно эти математические объекты становятся строительными блоками для постановки задачи оптимизации.

Но как найти оптимальное распределение потоков в сложной сети? Как направить информационные потоки или транспортные средства так, чтобы минимизировать среднее время ожидания в системе, не допуская при этом перегрузки отдельных каналов? Эта задача решается с помощью нелинейной оптимизации, где целевая функция — сумма средних чисел заявок во всех каналах (выведенная из формулы для M/M/1), а ограничения включают баланс потоков в узлах и физические ограничения пропускных способностей.

В данной работе мы представляем полный цикл анализа и оптимизации сетевой СМО — от теоретических основ до практической реализации в среде Engee. Вы увидите, как:

  • Преобразовать реальные данные о пропускных способностях и потоках в математические модели;

  • Визуализировать сложные сетевые структуры с помощью графов;

  • Сформулировать задачу оптимизации с сотнями переменных и ограничений;

  • Решить её с использованием современных алгоритмов нелинейной оптимизации;

  • Проанализировать результаты через интерактивные визуализации и количественные метрики.

В данном примере мы не ограничиваемся теоретическими выкладками, а проходим через весь процесс — от исходных данных в формате Excel до готовых рекомендаций по оптимизации сети, сопровождая каждый шаг наглядными графиками и подробными объяснениями. Использование Julia, языка, сочетающего скорость C с выразительностью Python, делает решение одновременно эффективным и прозрачным.

Присоединим необходимые библиотеки.

In [ ]:
using XLSX, JuMP, Ipopt, DataFrames, Graphs, SimpleWeightedGraphs, Colors, Printf, LinearAlgebra, Printf, GraphPlot

Присоединим необходимые файлы с функциями.

In [ ]:
foreach(include, ("opti1.jl", "opti2.jl", "opti3.jl", "opti4.jl", "opti5.jl", "opti6.jl", "opti7.jl", "opti8.jl", "opti9.jl", "flowDir.jl", "optiwrite.jl", "lfwrite.jl"))
foreach(include, ("readqs.jl", "flowGraph.jl", "flGplot.jl", "netGraph.jl", "simpGraph.jl", "sGplot.jl","nGplot.jl"))

Структура СМО

Структуру системы массового обслуживания можно представить в виде квадратной матрицы сети с нулевой диагональю размером :

Где – количество узлов в сети, – суммарная пропускная способность каналов связи (ветвей графа), соединяющих узлы и направленных от узла с номером к узлу с номером , а нулевая диагональ подразумевает отсутствие каналов для потоков информации от узла, адресованных самому себе.

Направление потоков в системах массового обслуживания можно так же представить в виде квадратной матрицы с нулевой диагональю размером :

Где – количество узлов в сети, – величина потока, направленного от узла с номером к узлу с номером . Нулевая диагональ в матрице подразумевает отсутствие потоков от узла, адресованных самому себе.

Потоки и пропускные способности (ёмкости), могут быть представлены любой единицей измерения, применяемой в системах массового обслуживания, например: Мбит/c, количество продукции в час; количество товаров, перевозимых в сутки; количество транспорта, проезжаемого за час, количество заявок в сутки, и т.д..

Исходные данные

В нашем примере исходные данные представлены в виде xlsx-таблиц. NetMatrix.xlsx — пропускная способность и направление линий связи, FlowMatrix.xlsx — интенсивность и направление потоков.

Прочитаем исходные данные.

In [ ]:
СМО = readqs("NetMatrix.xlsx", 1);
Потоки = readqs("FlowMatrix.xlsx", 1);

Отобразим ёмкости линий связи в виде матрицы.

In [ ]:
display(СМО)
8×8 Matrix{Float64}:
  0.0  50.0   0.0  30.0  25.0   0.0   0.0   0.0
 80.0   0.0  70.0   0.0   0.0  75.0   0.0   0.0
  0.0  75.0   0.0  25.0   0.0   0.0  20.0   0.0
 65.0   0.0  90.0   0.0   0.0   0.0   0.0  25.0
 45.0   0.0   0.0   0.0   0.0  45.0   0.0  70.0
  0.0  85.0   0.0   0.0  90.0   0.0  60.0   0.0
  0.0   0.0  80.0   0.0   0.0  85.0   0.0  20.0
  0.0   0.0   0.0  80.0  95.0   0.0  70.0   0.0

Отобразим потоки в виде матрицы.

In [ ]:
display(Потоки)
8×8 Matrix{Float64}:
 0.0  0.0  0.0   0.0   0.0  0.0  78.0  0.0
 0.0  0.0  0.0   0.0   0.0  0.0   0.0  0.0
 0.0  0.0  0.0   0.0  48.0  0.0   0.0  0.0
 0.0  0.0  0.0   0.0   0.0  0.0   0.0  0.0
 0.0  0.0  0.0   0.0   0.0  0.0   0.0  0.0
 0.0  0.0  0.0  61.0   0.0  0.0   0.0  0.0
 0.0  0.0  0.0   0.0   0.0  0.0   0.0  0.0
 0.0  0.0  0.0   0.0   0.0  0.0   0.0  0.0

На основании исходных данных, определим количество узлов, потоков, и линий связи в исследуемой СМО.

In [ ]:
узлов = size(СМО, 1);
линий = count(!iszero, СМО);
потоков = count(!iszero, Потоки);
println("В системе  массового обслуживания\n\nузлов: $узлов\nпотоков: $потоков\nлиний связи: $линий")
В системе  массового обслуживания

узлов: 8
потоков: 3
линий связи: 24

Визуализация СМО

Отобразим структуру СМО в виде графа. Для наглядности на данном графе не будем учитывать направления и интенсивности линий связи.

In [ ]:
и, п = simpGraph(СМО);
Граф = sGplot(и, п)
display(Граф)
1 2 3 4 5 6 7 8 Упрощённый вид структуры СМО

С помощью указания номеров узлов, величин интенсивности и стрелок, отобразим направления потоков.

In [ ]:
nfl, nl, flG, flI = flowGraph(Потоки);
ГрафПотоков = flGplot(flG, flI, nl, "Направления потоков");
display(ГрафПотоков)
78 48 61 1 7 3 5 6 4 Направления потоков

Теперь отобразим полную структуру СМО в виде направленного графа с указанием номеров узлов, направлений и ёмкостей линий связи.

In [ ]:
s, t, bW = netGraph(СМО);
ГрафСМО = nGplot(s, t, bW, "Структура системы массового обслуживания");
display(ГрафСМО)
50 30 25 80 70 75 75 25 20 65 90 25 45 45 70 85 90 60 80 85 20 80 95 70 1 2 3 4 5 6 7 8 Структура системы массового обслуживания

Система M/M/1

Рассмотрим систему M/M/1, в которой входящий поток заявок имеет пуассоновское распределение, а распределение времени обслуживания экспоненциальное, тогда среднее число заявок, находящихся в системе определяется формулой:

Где – интенсивность поступления заявок, – пропускная способность линий связи. Эта формула возникает из-за случайности в моментах прихода и обслуживания заявок. Когда система работает близко к пределу своей мощности (нагрузка приближается к 100%), даже небольшие случайные задержки начинают накапливаться, вызывая гиперболический, а не линейный, рост очереди. Математически это является следствием геометрического распределения количества заявок в системе, среднее значение для которого и определяется данным выражением. В дальнейшем на основании данной формулы будет формироваться целевая функция для оптимизаци.

Преобразование исходных данных

Для дальнейшего решения, преобразуем матрицу пропускных способностей в 3 вектора:

  • список источников;
  • список приёмников;
  • список пропускных способностей (ёмкостей).
In [ ]:
источник, приёмник, ёмкость = opti1(СМО, узлов, линий);

В процессе оптимизации для обхода загруженных линий связи, потоки могут разделиться на доли. Структуру долей потоков можно представить в виде системы матриц в количестве размера :

Где – количество узлов, – количество потоков, – величина доли потока номер , проходящая через линию, направленную от узла номер к узлу номер .

Матрица инцидентности

На основе матрицы смежности, создадим матрицу инцидентности.

Каждый столбец соответствует ветви графа: в строке источника ставится -1, в строке приёмника — +1. Матрица имеет размер узлов × линий и описывает, какие узлы соединены каждым ребром и направление линий.

In [ ]:
МатрицаИнцидентности = opti2(узлов, линий, источник, приёмник);
display(МатрицаИнцидентности)
8×24 Matrix{Float64}:
 -1.0  -1.0  -1.0   1.0   0.0   0.0  …   0.0   0.0   0.0   0.0   0.0   0.0
  1.0   0.0   0.0  -1.0  -1.0  -1.0      0.0   0.0   0.0   0.0   0.0   0.0
  0.0   0.0   0.0   0.0   1.0   0.0      1.0   0.0   0.0   0.0   0.0   0.0
  0.0   1.0   0.0   0.0   0.0   0.0      0.0   0.0   0.0   1.0   0.0   0.0
  0.0   0.0   1.0   0.0   0.0   0.0      0.0   0.0   0.0   0.0   1.0   0.0
  0.0   0.0   0.0   0.0   0.0   1.0  …   0.0   1.0   0.0   0.0   0.0   0.0
  0.0   0.0   0.0   0.0   0.0   0.0     -1.0  -1.0  -1.0   0.0   0.0   1.0
  0.0   0.0   0.0   0.0   0.0   0.0      0.0   0.0   1.0  -1.0  -1.0  -1.0

Ограничения потоков

Преобразуем матрицу потоков в 3 вектора:

  • список отправителей;

  • список получателей;

  • список интенсивностей потоков.

In [ ]:
исток, приток, интенсивность = opti3(Потоки, узлов, потоков);

Создадим матрицу, обозначающую величины интенсивностей исходящих потоков из узлов-источников и входящих потоков в узлы-приёмники. Количество строк равно количеству узлов, а количество столбцов равно количеству потоков. Отрицательная величина обозначает исходящий поток из узла-источника, положительная величина обозначает входящий поток в узел-приёмник. Номера строк соответствуют номерам узлов.

In [ ]:
исток_приток = opti4(узлов, потоков, исток, приток, интенсивность);
display(исток_приток)
10×3 Matrix{Float64}:
 -78.0    0.0    0.0
   0.0    0.0    0.0
   0.0  -48.0    0.0
   0.0    0.0   61.0
   0.0   48.0    0.0
   0.0    0.0  -61.0
  78.0    0.0    0.0
   0.0    0.0    0.0
   0.0    0.0    0.0
   0.0    0.0    0.0

Создадим трёхмерный массив, обозначающий направления потока в каждой линии связи. Количество строк равно двум (исток и приток), количество столбцов соответствует количеству линий связи линий, а количество двумерных матриц соответствует количеству потоков потоков. Данный массив будет использован для блокирования входящих потоков в узлы-источники и исходящих из узлов-приёмников.

In [ ]:
ограничения = opti5(линий, потоков, источник, приёмник, исток, приток);
display(ограничения)
2×24×3 Array{Float64, 3}:
[:, :, 1] =
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  …  0.0  1.0  1.0  1.0  0.0  0.0  0.0
 0.0  0.0  0.0  1.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0

[:, :, 2] =
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  …  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  1.0  0.0  0.0  0.0     0.0  1.0  0.0  0.0  0.0  0.0  0.0

[:, :, 3] =
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  …  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  1.0  0.0  0.0     0.0  0.0  1.0  0.0  0.0  0.0  0.0

Уравнения и неравенства

На основе матрицы инцидентности и массива направления потоков, создадим трёхмерный массив, обозначающий знаки (-1 или 0 или +1) долей потоков для уравнений ограничений оптимизации СМО. Количество строк соответствует количеству узлов плюс два, так как в количестве равном количеству узлов обозначают ограничения в промежуточных линиях связи, а последние две в оконечных, которые блокируют входящие потоки в узлы-источники и исходящие из узлов-приёмников. Данные массивы будут использованы для создания уравнений ограничений оптимизации.

In [ ]:
Уравнения = opti6(узлов, МатрицаИнцидентности, линий, потоков, ограничения, исток_приток);
display(Уравнения)
10×24×3 Array{Int64, 3}:
[:, :, 1] =
 -1  -1  -1   0   0   0   0   0   0  …   0   0   0   0  0  0  0   0   0   0
  1   0   0  -1  -1  -1   1   0   0      0   1   0   0  0  0  0   0   0   0
  0   0   0   0   1   0  -1  -1  -1      0   0   0   0  1  0  0   0   0   0
  0   1   0   0   0   0   0   1   0      0   0   0   0  0  0  0   1   0   0
  0   0   1   0   0   0   0   0   0     -1   0   1   0  0  0  0   0   1   0
  0   0   0   0   0   1   0   0   0  …   0  -1  -1  -1  0  1  0   0   0   0
  0   0   0   0   0   0   0   0   1      0   0   0   1  0  0  0   0   0   1
  0   0   0   0   0   0   0   0   0      1   0   0   0  0  0  1  -1  -1  -1
  0   0   0   0   0   0   0   0   0      0   0   0   0  1  1  1   0   0   0
  0   0   0   1   0   0   0   0   0      0   0   0   0  0  0  0   0   0   0

[:, :, 2] =
 -1  -1  -1   1   0   0   0   0   0  …   0   0   0   0   0   0   0   0   0
  1   0   0  -1  -1  -1   1   0   0      1   0   0   0   0   0   0   0   0
  0   0   0   0   0   0  -1  -1  -1      0   0   0   0   0   0   0   0   0
  0   1   0   0   0   0   0   1   0      0   0   0   0   0   0   1   0   0
  0   0   1   0   0   0   0   0   0      0   1   0   0   0   0   0   1   0
  0   0   0   0   0   1   0   0   0  …  -1  -1  -1   0   1   0   0   0   0
  0   0   0   0   0   0   0   0   1      0   0   1  -1  -1  -1   0   0   1
  0   0   0   0   0   0   0   0   0      0   0   0   0   0   1  -1  -1  -1
  0   0   0   0   0   0   0   0   0      0   0   0   0   0   0   0   0   0
  0   0   0   0   1   0   0   0   0      0   0   0   1   0   0   0   0   0

[:, :, 3] =
 -1  -1  -1   1   0   0   0   0   0  1  …   0   0   0   0   0   0   0   0   0
  1   0   0  -1  -1  -1   1   0   0  0      1   0   0   0   0   0   0   0   0
  0   0   0   0   1   0  -1  -1  -1  0      0   0   0   1   0   0   0   0   0
  0   1   0   0   0   0   0   1   0  0      0   0   0   0   0   0   1   0   0
  0   0   1   0   0   0   0   0   0  0      0   1   0   0   0   0   0   1   0
  0   0   0   0   0   0   0   0   0  0  …  -1  -1  -1   0   0   0   0   0   0
  0   0   0   0   0   0   0   0   1  0      0   0   1  -1  -1  -1   0   0   1
  0   0   0   0   0   0   0   0   0  0      0   0   0   0   0   1  -1  -1  -1
  0   0   0   0   0   0   0   0   0  1      0   0   0   0   0   0   0   0   0
  0   0   0   0   0   1   0   0   0  0      0   0   0   0   1   0   0   0   0

Поэлементно умножив полученный массив на переменные, обозначающие доли потоков, получим системы уравнений.

Рассмотрим, как формируется уравнение для узла 1, потока . Представляя доли потоков в виде матрицы:

Возьмём элемент матрицы с индексом , который равен нулю. Элементы первой строки подставляются в уравнение со знаком минус, элементы первого столбца подставляются в уравнение со знаком плюс. Получаем уравнение:

Для следующих узлов, возьмём индексы , и повторяем составление уравнений. Данные уравнения вводят ограничения, которые обозначают то, что сумма входящих и исходящих потоков в промежуточных узлах равна нулю.

Для наглядности, составим систему уравнений ограничений оптимизации в общем виде на примере узлов: и потока :

Где – количество узлов, – количество потоков.

Помимо систем уравнений, необходимым ограничением является максимальная интенсивность долей потоков в линиях связи, которая не должна превышать их пропускные способности. Для СМО, состоящей из 8 узлов и 24 линий связи, данное ограничение будет представлено следующей системой неравенств:

Преобразуем полученные результаты в исходные данные для выполнения задачи оптимизации.

In [ ]:
А, Б, λ0, а, б = opti7(узлов, потоков, линий, Уравнения, исток_приток, ёмкость);
display(А)
display(Б)
30×72 Matrix{Float64}:
 -1.0  -1.0  -1.0   0.0   0.0   0.0  …   0.0   0.0   0.0   0.0   0.0   0.0
  1.0   0.0   0.0  -1.0  -1.0  -1.0      0.0   0.0   0.0   0.0   0.0   0.0
  0.0   0.0   0.0   0.0   1.0   0.0      0.0   0.0   0.0   0.0   0.0   0.0
  0.0   1.0   0.0   0.0   0.0   0.0      0.0   0.0   0.0   0.0   0.0   0.0
  0.0   0.0   1.0   0.0   0.0   0.0      0.0   0.0   0.0   0.0   0.0   0.0
  0.0   0.0   0.0   0.0   0.0   1.0  …   0.0   0.0   0.0   0.0   0.0   0.0
  0.0   0.0   0.0   0.0   0.0   0.0      0.0   0.0   0.0   0.0   0.0   0.0
  0.0   0.0   0.0   0.0   0.0   0.0      0.0   0.0   0.0   0.0   0.0   0.0
  0.0   0.0   0.0   0.0   0.0   0.0      0.0   0.0   0.0   0.0   0.0   0.0
  0.0   0.0   0.0   1.0   0.0   0.0      0.0   0.0   0.0   0.0   0.0   0.0
  0.0   0.0   0.0   0.0   0.0   0.0  …   0.0   0.0   0.0   0.0   0.0   0.0
  0.0   0.0   0.0   0.0   0.0   0.0      0.0   0.0   0.0   0.0   0.0   0.0
  0.0   0.0   0.0   0.0   0.0   0.0      0.0   0.0   0.0   0.0   0.0   0.0
  ⋮                             ⋮    ⋱                           ⋮    
  0.0   0.0   0.0   0.0   0.0   0.0      0.0   0.0   0.0   0.0   0.0   0.0
  0.0   0.0   0.0   0.0   0.0   0.0      0.0   0.0   0.0   0.0   0.0   0.0
  0.0   0.0   0.0   0.0   0.0   0.0  …   0.0   0.0   0.0   0.0   0.0   0.0
  0.0   0.0   0.0   0.0   0.0   0.0      0.0   0.0   0.0   0.0   0.0   0.0
  0.0   0.0   0.0   0.0   0.0   0.0      1.0   0.0   0.0   0.0   0.0   0.0
  0.0   0.0   0.0   0.0   0.0   0.0      0.0   0.0   0.0   1.0   0.0   0.0
  0.0   0.0   0.0   0.0   0.0   0.0      0.0   0.0   0.0   0.0   1.0   0.0
  0.0   0.0   0.0   0.0   0.0   0.0  …   0.0   0.0   0.0   0.0   0.0   0.0
  0.0   0.0   0.0   0.0   0.0   0.0     -1.0  -1.0  -1.0   0.0   0.0   1.0
  0.0   0.0   0.0   0.0   0.0   0.0      0.0   0.0   1.0  -1.0  -1.0  -1.0
  0.0   0.0   0.0   0.0   0.0   0.0      0.0   0.0   0.0   0.0   0.0   0.0
  0.0   0.0   0.0   0.0   0.0   0.0      0.0   1.0   0.0   0.0   0.0   0.0
30-element Vector{Float64}:
 -78.0
   0.0
   0.0
   0.0
   0.0
   0.0
  78.0
   0.0
   0.0
   0.0
   0.0
   0.0
 -48.0
   ⋮
   0.0
   0.0
   0.0
   0.0
   0.0
  61.0
   0.0
 -61.0
   0.0
   0.0
   0.0
   0.0

Целевая функция

На основании структуры матрицы пропускных способностей и матрицы потоков, составим целевую функцию. Для СМО, состоящей из 8 узлов, 24 линий связи и 3 потоков, целевая функция будет иметь следующий вид:

Целевую функцию можно представить в общем виде:

где – значение среднего количества заявок в системе массового обслуживания, – количество линий связи – количество потоков, – величина пропускной способности линии связи, направленной от узла к узлу , – искомая оптимальная интенсивность доли потока направленного от узла к узлу , являющегося частью потока .

Задача оптимизации свидится к следующей цели: найти такие значения , при которых примет минимальное значение.

Оптимизация

Сформируем целевую функцию и выполним задачу оптимизации.

In [ ]:
T, λ, нагрузка = opti8(А, Б, λ0, а, б, ёмкость, потоков);
******************************************************************************
This program contains Ipopt, a library for large-scale nonlinear optimization.
 Ipopt is released as open source code under the Eclipse Public License (EPL).
         For more information visit https://github.com/coin-or/Ipopt
******************************************************************************

This is Ipopt version 3.14.19, running with linear solver MUMPS 5.8.1.

Number of nonzeros in equality constraint Jacobian...:      144
Number of nonzeros in inequality constraint Jacobian.:      144
Number of nonzeros in Lagrangian Hessian.............:      144

Total number of variables............................:       72
                     variables with only lower bounds:        0
                variables with lower and upper bounds:        0
                     variables with only upper bounds:        0
Total number of equality constraints.................:       30
Total number of inequality constraints...............:       96
        inequality constraints with only lower bounds:       72
   inequality constraints with lower and upper bounds:        0
        inequality constraints with only upper bounds:       24

iter    objective    inf_pr   inf_du lg(mu)  ||d||  lg(rg) alpha_du alpha_pr  ls
   0  0.0000000e+00 7.80e+01 1.00e+00  -1.0 0.00e+00    -  0.00e+00 0.00e+00   0
   1  1.5361809e-02 7.79e+01 4.01e+00  -1.0 4.24e+01    -  3.82e-04 1.55e-03h  1
   2  5.7118271e-02 7.76e+01 4.00e+00  -1.0 4.52e+01    -  1.54e-03 3.16e-03h  1
   3  3.9900603e+01 3.60e+01 3.45e+01  -1.0 5.09e+01    -  4.75e-03 5.37e-01h  1
   4  3.9720194e+01 3.24e+01 3.11e+01  -1.0 5.00e+01    -  2.93e-01 9.96e-02f  1
   5  3.9526678e+01 2.48e+01 2.38e+01  -1.0 4.53e+01    -  7.62e-01 2.35e-01f  1
   6  3.9278463e+01 1.96e+01 2.64e+01  -1.0 3.58e+01    -  7.27e-01 2.10e-01h  1
   7  4.3666794e+01 5.50e+00 1.54e+01  -1.0 3.43e+01    -  9.19e-01 7.19e-01h  1
   8  5.1326302e+01 1.54e-01 4.41e+00  -1.0 1.13e+01    -  1.00e+00 9.72e-01h  1
   9  5.1085967e+01 1.26e-01 3.61e+03  -1.0 9.81e-01    -  1.00e+00 1.83e-01h  1
iter    objective    inf_pr   inf_du lg(mu)  ||d||  lg(rg) alpha_du alpha_pr  ls
  10  5.0623582e+01 1.78e-05 5.98e-01  -1.0 9.23e-01    -  1.00e+00 1.00e+00f  1
  11  4.8428633e+01 1.78e-07 7.96e+00  -2.5 2.18e+00    -  8.97e-01 1.00e+00f  1
  12  4.8269414e+01 4.88e-07 3.58e-03  -2.5 1.11e+00    -  1.00e+00 1.00e+00f  1
  13  4.8197205e+01 1.31e-08 9.31e-04  -5.7 4.58e-01    -  9.70e-01 9.73e-01f  1
  14  4.8194182e+01 1.33e-10 2.03e-06  -5.7 8.58e-02    -  1.00e+00 1.00e+00f  1
  15  4.8194113e+01 1.74e-10 1.21e-09  -8.6 2.11e-03    -  1.00e+00 1.00e+00h  1
  16  4.8194113e+01 1.75e-10 1.69e-12 -10.7 4.19e-05    -  1.00e+00 1.00e+00h  1

Number of Iterations....: 16

                                   (scaled)                 (unscaled)
Objective...............:   4.8194113307753497e+01    4.8194113307753497e+01
Dual infeasibility......:   1.6852994694227519e-12    1.6852994694227519e-12
Constraint violation....:   1.7463496219893658e-10    1.7463496219893658e-10
Variable bound violation:   0.0000000000000000e+00    0.0000000000000000e+00
Complementarity.........:   2.7491011849489282e-11    2.7491011849489282e-11
Overall NLP error.......:   1.7463496219893658e-10    1.7463496219893658e-10


Number of objective function evaluations             = 17
Number of objective gradient evaluations             = 17
Number of equality constraint evaluations            = 17
Number of inequality constraint evaluations          = 17
Number of equality constraint Jacobian evaluations   = 1
Number of inequality constraint Jacobian evaluations = 1
Number of Lagrangian Hessian evaluations             = 16
Total seconds in IPOPT                               = 6.133

EXIT: Optimal Solution Found.

Результаты оптимизации

Преобразуем данные для отображения в виде графов и вывода в виде xlsx-таблиц. И в случае успешной оптимизации, выведем матрицы оптимальных распределений потоков.

In [ ]:
Оптимальные, НагрузкаСистемы = opti9(потоков, линий, λ, узлов, источник, приёмник, ёмкость);
if T #нагрузка > 0
display(Оптимальные)
end
8×8×3 Array{Float64, 3}:
[:, :, 1] =
 0.0  38.6682   0.0     19.5557  19.7761   0.0       0.0      0.0
 0.0   0.0     14.5631   0.0      0.0     24.1052    0.0      0.0
 0.0   0.0      0.0      0.0      0.0      0.0      14.5631   0.0
 0.0   0.0      0.0      0.0      0.0      0.0       0.0     19.5557
 0.0   0.0      0.0      0.0      0.0      4.97722   0.0     14.7989
 0.0   0.0      0.0      0.0      0.0      0.0      29.0824   0.0
 0.0   0.0      0.0      0.0      0.0      0.0       0.0      0.0
 0.0   0.0      0.0      0.0      0.0      0.0      34.3545   0.0

[:, :, 2] =
 0.0       0.0    0.0  0.0       1.45932   0.0     0.0      0.0
 1.45932   0.0    0.0  0.0       0.0      43.5827  0.0      0.0
 0.0      45.042  0.0  1.16997   0.0       0.0     1.78799  0.0
 0.0       0.0    0.0  0.0       0.0       0.0     0.0      1.16997
 0.0       0.0    0.0  0.0       0.0       0.0     0.0      0.0
 0.0       0.0    0.0  0.0      43.5827    0.0     0.0      0.0
 0.0       0.0    0.0  0.0       0.0       0.0     0.0      1.78799
 0.0       0.0    0.0  0.0       2.95796   0.0     0.0      0.0

[:, :, 3] =
 0.0       0.0      0.0      2.80826   0.0     0.0   0.0      0.0
 2.80826   0.0     16.6279   0.0       0.0     0.0   0.0      0.0
 0.0       0.0      0.0     16.6279    0.0     0.0   0.0      0.0
 0.0       0.0      0.0      0.0       0.0     0.0   0.0      0.0
 0.0       0.0      0.0      0.0       0.0     0.0   0.0     30.9302
 0.0      19.4362   0.0      0.0      30.9302  0.0  10.6336   0.0
 0.0       0.0      0.0      0.0       0.0     0.0   0.0     10.6336
 0.0       0.0      0.0     41.5638    0.0     0.0   0.0      0.0

Выведем результаты оптимизации.

In [ ]:
nl = flowDir(Потоки);
if T
    optiwrite(Оптимальные, потоков)
    println("\nОптимизация выполнена.\n")
    println("\nСреднее количество заявок в системе: $нагрузка\n")
else 
    println("\nОптимизация невыполнима при данных интенсивностях потоков и ёмкостях линий связи.\n")
end
Оптимизация выполнена.


Среднее количество заявок в системе: 48.1941133077535

Создадим xlsx-файл и выведем матрицу с коэффициентами загрузки линий связи.

In [ ]:
lfwrite(НагрузкаСистемы)
display(НагрузкаСистемы)
8×8 Matrix{Float64}:
 0.0        0.773365  0.0       0.745464  …  0.0       0.0       0.0
 0.0533447  0.0       0.445585  0.0          0.902505  0.0       0.0
 0.0        0.600561  0.0       0.711915     0.0       0.817553  0.0
 0.0        0.0       0.0       0.0          0.0       0.0       0.829026
 0.0        0.0       0.0       0.0          0.110605  0.0       0.653273
 0.0        0.228661  0.0       0.0       …  0.0       0.661933  0.0
 0.0        0.0       0.0       0.0          0.0       0.0       0.62108
 0.0        0.0       0.0       0.519548     0.0       0.490779  0.0

Визуализация оптимальных потоков

Если оптимизация выполнена, отобразим оптимальное распределение интенсивностей потоков в виде графов.

In [ ]:
if T
    fnums = reshape(nl, (2, потоков));
    for m in 1:потоков
    optiname = "Распределение потоков от узла $(fnums[1, m]) к узлу $(fnums[2, m])"
    и, п, ё = netGraph(readqs("OptiFlows.xlsx", m));
    ОптГраф(m) = nGplot(и, п, ё, optiname);
    display(ОптГраф(m))
    end
else 
    println("\nНеобходимо увеличить пропускные линий связи или уменьшить интенсивность потоков.\n")
end
38.668 19.556 19.776 14.563 24.105 14.563 19.556 4.977 14.799 29.082 34.355 1 2 3 4 5 6 7 8 Распределение потоков от узла 1 к узлу 7
1.459 1.459 43.583 45.042 1.170 1.788 1.170 43.583 1.788 2.958 1 2 3 4 5 6 7 8 Распределение потоков от узла 3 к узлу 5
2.808 2.808 16.628 16.628 30.930 19.436 30.930 10.634 10.634 41.564 1 2 3 4 5 6 7 8 Распределение потоков от узла 6 к узлу 4

Визуализация загруженности линий

Отобразим коэффициенты загрузки линий связи в виде графа. На основании данного графа можно проанализировать, требуется ли определённым линиям связи увеличение пропускной способности. В случае, если оптимизация невыполнима при данной пропускной способности линий связи, коэффициенты загрузки, превышающие единицу обозначают во сколько раз нужно увеличить данную линию связи для того, чтобы оптимизация стала возможной.

In [ ]:
lM = readqs("LoadFactors.xlsx", 1);
s1, t1, bW1 = netGraph(lM);
ГрафНагрузки = nGplot(s1, t1, bW1, "Загруженность линий сязи");
display(ГрафНагрузки)
0.773 0.745 0.849 0.053 0.446 0.903 0.601 0.712 0.818 0.829 0.111 0.653 0.229 0.828 0.662 0.621 0.520 0.031 0.491 1 2 3 4 5 6 7 8 Загруженность линий сязи

Помимо представленных графов, в качестве результатов вычислений, мы получили xlsx-таблицы с матрицами оптимального распределения потоков (OptiFlows.xlsx) и загруженности линий связи при данных величинах потоков и ёмкостях линий связи (LoadFactors), которые будут удобны в использовании для дальнейших вычислений и исследований.

Оптимизируйте собственную систему

С помощью представленного алгоритма вы можете оптимизировать вашу собственную систему массового обслуживания, для этого:

  1. Подготовьте двух стандартизированных файлов в формате Excel:

    • NetMatrix.xlsx — матрица направлений и пропускных способностей линий связи

    • FlowMatrix.xlsx — матрица направлений и интенсивностей обслуживаемых потоков

  2. Загрузите их в интерактивную вычислительную среду

  3. Инициируйте аналитический процесс с получением комплексного результата:

    • Матрицы оптимального распределения для каждого потока

    • Графическое представление коэффициентов загрузки каналов

    • Визуализация топологии сети и конфигурации потоков

    • Количественные показатели параметров системы

Вне зависимости от масштаба и специфики системы — будь то муниципальная транспортная инфраструктура, корпоративная вычислительная сеть или производственно-логистический комплекс — представленный инструмент обеспечивает адаптивный анализ на основе предоставленных данных. Методология позволяет идентифицировать критические элементы, работающие на пределе пропускной способности, выявлять недостаточно загруженные маршруты и определять оптимальные схемы распределения потоков.

Следует отметить, что оптимизация сетевых структур более не является исключительной компетенцией специалистов с доступом к специализированному программному обеспечению. В настоящее время это становится стандартизированной процедурой, в которой сложные вычислительные алгоритмы реализованы в интуитивно понятном интерфейсе, а глубина аналитики органично сочетается с наглядностью представления.

Рекомендуется апробация методологии на актуальных данных. Загрузка матриц конкретной системы в среду Engee позволит наблюдать практическую реализацию принципов теории массового обслуживания, обнаруживать скрытые резервы в существующих конфигурациях и находить эффективные решения для оптимизационных задач.

Следует рассматривать оптимизацию не как разовое мероприятие, а как непрерывный процесс совершенствования. Представленный инструментарий обеспечивает его системность, наглядность и результативность, формируя основу для принятия обоснованных управленческих решений в условиях динамичной среды функционирования сложных сетевых систем.

Заключение

Настоящее исследование продемонстрировало методологический переход от фундаментальных принципов теории массового обслуживания к практической реализации комплексной оптимизации сетевых структур. На примере системы, включающей 8 узлов, 24 канала связи и 3 потока обслуживания, была проиллюстрирована трансформация математических концепций — пуассоновских потоков, экспоненциальных распределений, матриц смежности и инцидентности — в эффективный инструментарий решения прикладных задач. Модель M/M/1, являющаяся классическим объектом теоретического рассмотрения, была успешно применена в качестве основы для построения целевой функции, минимизирующей среднее количество заявок в распределённой сети.

Центральный результат проведённой работы заключается в демонстрации того, что оптимизация сетевых структур представляет собой системный процесс с четко определёнными этапами: математическое моделирование, визуальное представление, формализация ограничений, численное решение и аналитическая интерпретация результатов. Экспериментально подтверждено, что даже в сетях умеренной сложности информационные потока закономерно распределяются по альтернативным маршрутам, демонстрируя адаптивность к потенциальным перегрузкам критических элементов. Визуализация результатов посредством направленных графов обеспечила не только представление итоговых значений, но и понимание причинно-следственных связей в системе.

Наиболее значимым аспектом является практическая доступность представленной методологии. Для специалистов, решающих задачи проектирования телекоммуникационных сетей, оптимизации логистических маршрутов, распределения вычислительных ресурсов или управления информационными потоками, предлагается готовое инструментальное решение.