Міністерство загальної та професійної освіти
Північно-Кавказький Державний Технічний Університет
Факультет інформаційних систем і технологій
Кафедра автоматизованих систем обробки інформації та управління
ПОЯСНЮВАЛЬНА ЗАПИСКА
До курсової роботи з дисципліни «Моделювання систем»
На тему_______________________________________________________
(Найменування теми відповідно до завдання)
Студент группи________________
_______________________________ ______________________
(Підпис) (П. І. Б.)
Руководітель___________________ ______________________
(Підпис) (П. І. Б.)
Оценка__________________________
2000
Анотація.
У даному курсовому проекті розглядається задача про машинному моделюванні процесу взаємодії між трьома проектувальниками і центральної ЕОМ. Проводиться аналіз цієї системи і формалізація її в термінах Q-схем, а також наведена програма моделює алгоритму і математичний опис системи. Проводиться порівняльний аналіз аналітичного та імітаційних методів дослідження.
Зміст.
Введення ................................................. .................................................. ............................ 5
Основна частина ................................................ .................................................. ................... 6
Постановка завдання ................................................ .................................................. ......... 6
Можливі шляхи дослідження ............................................... ...................................... 6
Етап моделювання ................................................ .................................................. ..... 7
Розробка Q-схеми системи ............................................. ....................................... 7
Розробка моделюючого алгоритму і машинна реалізація ......................... 10
Математичний опис системи ............................................... ............................. 18
Результати моделювання та аналітичного рішення ............................................ 19
Висновок ................................................. .................................................. ...................... 20
Література ................................................. .................................................. ....................... 21
Програми ................................................. .................................................. ..................... 22
Текст програми ................................................ .................................................. ......... 22
Введення.
У цій курсовій роботі розглядається проблема моделювання процесів в Q-схемах - одному з найважливіших, з точки зору застосування на практиці, класів математичних схем, розроблених для формалізації процесів функціонування систем масового обслуговування (СМО) в теорії масового обслуговування. Предметом вивчення в теорії масового обслуговування є системи, в яких поява заявок (вимог) на обслуговування і завершення обслуговування відбувається у випадкові моменти часу, тобто характер їх функціонування носить стохастичний характер. Слід зазначити, що СМО описують різні по своїй фізичній природі процеси функціонування економічних, виробничих, технічних та інших систем, наприклад потоки поставок продукції деякого підприємству, потоки деталей та комплектуючих виробів на складальному конвеєрі цеху, заявки на обробку інформації в ЕОМ від віддалених терміналів і т . д.
Основна частина. Постановка завдання.
САПР складається з ЕОМ і трьох терміналів. Кожен з проектувальників формує завдання на розрахунок у інтерактивному режимі. Набір рядка завдання займає 10 ± 5 с. Після набору 10 рядків завдання вважається сформованим і надходить на рещеніе, при цьому протягом 10 ± 3с ЕОМ припиняє приймати інші завдання. Аналіз результату займає у проектувальників 30 с, після чого цикл повторюється. Дані по всіх проектувальникам однакові.
Змоделювати роботу системи протягом 6 годин. Визначити імовірність простою проектувальника через зайнятість ЕОМ і коефіцієнт завантаження ЕОМ.
Можливі шляхи дослідження.Для вивчення Q-схем використовуються два підходи: аналітичний та імітаційний. При аналітичному підході підлягає аналізу схема описується за допомогою формул, що відображають залежності між її різними параметрами. Однак, слід зазначити, що розроблені методи аналітичного вивчення Q-схем підходять далеко не для кожної конкретної системи, вони придатні лише для систем загального типу. Тому при аналітичному вивченні систем їх необхродімо спрощувати до систем основних типів, що надалі звичайно-ж позначається на результатах дослідження. При імітаційному підході ставиться експеримент на машинної моделі системи, яка попередньо реалізується на одному з створених спеціально для цього мов імітаційного моделювання (наприклад, SIMULA, SIMSCRIPT, GPSS та ін) або на мові загального призначення (BASIC, PASCAL, FORTRAN, C + + та ін .).
Етап моделювання. Розробка Q-схеми системи.Враховуючи умову, побудуємо структурну схему даної системи.
Рис. 1 Структурна блок-схема системи.
При розгляді структурної схеми можна побудувати тимчасову діаграму, більш наочно відображає процес функціонування системи.
Рис. 2 Тимчасова діаграма.
На часовій діаграмі:
- Осі 1, 2, 3 - виникнення заявки відповідно у 1-го, 2-го або 3-го проектувальника;
- Вісь 4 - обробка заявок проектувальників на ЕОМ.
Дана тимчасова діаграма показує практично всі особливі стани, які можуть статися в системі і які необхідно врахувати при побудові моделюючого алгоритму.
Так як, по суті, описані процеси є процесами масового обслуговування, то для формалізації задачі використовуємо символіку Q-схем [2]. У відповідності з побудованою концептуальною моделлю і символікою Q-схем структурну схему даної СМО (рис. 1) можна представити у вигляді, показаному на рис. 3, де І - джерело, К - канал.
Рис. 3 Структурна схема системи в символіці Q-схем.
Джерела І1, І2, І3 імітують надходження заявок від проектувальників 1,2 і 3 відповідно. Канал К1 імітує процес обробки заявок на центральній ЕОМ. Якщо канал К1 зайнятий, то клапан 1 закритий. Джерела генерують заявки, що йдуть потім на ЕОМ. Якщо ЕОМ зайнята, то заявка залишається у джерелі чекати своєї черги на обробку.
Необхідно відзначити, що у вихідній постановці це завдання можна вирішити тільки методом імітаційного моделювання. Для вирішення одним з аналітичних методом, що базуються на теорії масового обслуговування, її слід попередньо спростити, що, природно, позначиться на точності та достовірності отриманих результатів.
Після формалізації задачі можна переходити до побудови моделюючого алгоритму.
Моделюючий алгоритм повинен адекватно відображати процес функціонування системи і в той же час не створювати труднощів при машинної реалізації моделі. При цьому моделюючий алгоритм повинен відповідати таким основним вимогам:
- Володіти універсальністю щодо структури, алгоритмів функціонування і параметрів системи;
- Забезпечувати одночасну і незалежну роботу необхідної кількості елементів схеми;
- Вкладатися в прийнятні витрати ресурсів ЕОМ для реалізації машинного експерименту;
- Проводити розбиття на автономні логічні частини;
- Гарантувати виконання рекурентного правила - подія, що відбувається в момент часу tk може моделюватися тільки після того, як промодельовані всі події, що відбулися в момент часу, що відбулися у момент часу tk-1 <tk.
При цьому необхідно мати на увазі, що поява одне заявки вхідного потоку в деякий момент часу ti може викликати зміну стану не більш ніж одного з елементів Q-схеми, а закінчення обслуговування заявки в момент часу ti в деякому каналі (К) може призвести в цей момент до послідовного зміни станів декількох елементів (Н і К), тобто буде мати місце процес поширення зміни станів в напрямку, протилежному руху заявок.
Відомо, що існують два основних принципи побудови моделюючих алгоритмів: «принцип Dt» і «принцип dz». При побудові моделюючого алгоритму Q-схеми за «принципом Dt», тобто алгоритму з детермінованим кроком, необхідно для побудови адекватної моделі визначити мінімальний інтервал часу між сусідніми станами Dt '= {ui} (у вхідних потоках і потоках обслуговування) і прийняти, що крок моделювання дорівнює Dt'. У моделюючих алгоритмах, побудованих за «принципом dz», тобто в алгоритмах з випадковим кроком, елементи Q-схеми проглядаються при моделюванні тільки в моменти особливих станів (в моменти появи з І зміни станів К). При цьому тривалість кроку Dt = var залежить як від особливостей самої системи, так і від впливів зовнішнього середовища. Моделюючі алгоритми з випадковим кроком можуть бути реалізовані синхронних і асинхронних способами. При синхронному способі один з елементів Q-схеми вибирається в якості ведучого, і по ньому «синхронізується» весь процес моделювання. При асинхронному способі побудови моделюючого алгоритму ведучий (синхронізуючий) елемент не використовується, а чергового кроку моделювання (перегляду елементів Q-схеми) може відповідати будь-яку особливу стан всього безлічі елементів І, Н, К. при цьому перегляд елеменов Q-схеми організування так, що при кожному особливому стані або циклічно проглядаються всі елементи, або спорадично, - тільки ті, які можуть у цьому випадку змінити свій стан.
Розробка моделюючого алгоритму і машинна реалізація.Розробку моделюючого алгоритму зручно проводити в 2 етапи:
1) розробка укрупненого алгоритму;
2) розробка детального алгоритму.
Укрупнений алгоритм унаочнює принцип функціонування моделі, приховуючи деталі конкретної реалізації та взаємодії окремих блоків схеми, що допомагає побачити загальний напрямок роботи моделі.
Детальний алгоритм більш глибоко відображає функціонування блоків схеми, в ньому більш докладно описуються способи реалізації кожного блоку схеми.
На рис. 4 зображено укрупнена схема моделюючого алгоритму.
Рис. 4 Укрупненная схема моделюючого алгоритму.
Переходячи до опису детальної схеми моделюючого алгоритму не можна не зупинитися на описі технології, за допомогою якого реалізовувався моделюючий алгоритм.
Для опису елементів схеми використовувався об'єктно-орієнтований підхід, основними принципами якого є
- Об'єднання в рамках однієї структури даних полів і методів (процедур), що оперують над ними;
- Успадкування - породження нових класів об'єктів, при цьому спадкоємці отримують ті ж поля і методи, що були оголошені в класі безпосереднього предка і його предків;
- Поліморфізм - можливість зміни (часткового або повного) методів однойменних з методами предків (т.зв. віртуальні методи).
Завдяки цим принципам об'єктно-орієнтований підхід (ООП) став одним з найбільш популярних у цей час, тому що дозволяє програмісту будувати ієрархію класів, яка відображає природну ієрархію, об'єкти реального світу.
Таким чином, в ході побудови моделюючого алгоритму були збудовані такі класи об'єктів.
TQSheme - клас схеми. На нього покладені основні функції з проведення експерименту, а саме:
- Управлінню системним часом
- Знаходженням порядку опитування елементів залежно від структури схеми
- Опитуванням елементів у кожному циклі
- Обліку заявок, що у системі
- Обліку особливих станів, які відбуваються в системі
Так, наприклад, саме клас TQSheme реалізує блоки 2 і 3 укрупненого алгоритму за допомогою своїх методів відповідно InitEmulation і Analize, а також блоки 4-7 за допомогою методу Emulation. Блок-схеми цих методів наведені нижче.
Рис. 5 Блок-схема процедури TQSheme.InitEmulation.
Опис:
- Блок 1 - відбувається ініціалізація змінних, необхідних для аналізу системи;
- Блок 2 - створення об'єктних списків, необхідних для аналізу системи: встановлення кінцевих елементів, встановлення порядку черговості опитування елементів схеми;
- Блок 3 - ініціалізація списків заявок і подій, підготовка їх до майбутнього прогону схеми.
Рис. 6 Блок-схема процедури TQSheme.Analize.
Опис:
- Блок 1 - знаходження порядку опитування елементів із занесенням порядкових номерів елементів в масив порядку опитування FOrder;
- Блок 2 - знаходження найменшого тимчасового інтервалу, необхідного для аналізу схеми за «принципом Dt»
Рис. 7 Блок-схема процедури TQSheme.Emulation.
Опис:
- Блок 1 - процедура ініціалізації процесу моделювання з встановленням початкових значень для всіх змінних;
- Блок 2 - виклик процедури Analize;
- Блок 3 - перевірка закінчення моделювання;
- Блок 4 - перегляд всіх елементів схеми.
Рис. 8 Блок-схема процедури TQSheme.Step
Опис:
- Блок 1 - процедура вилучення заявок з кінцевих елементів схеми;
- Блок 2 - опитування всіх елементів схеми в порядку, зазначеному в масиві FOrder;
- Блок 3 - збільшення системного часу на величину Dt;
Кожен елемент схеми, будь то джерело, накопичувач або канал, також представлений відповідним класом (TSource, TAccumulator, TChannel). Проте всі класи елементів схеми є спадкоємцями одного загального класу TElement, який забезпечує загальну функціональність для всіх типів елементів схеми, а саме:
- Містить інформацію про те, з яких елементів схеми заявки надходять на даний елемент;
- Містить так званий контейнер для заявок;
- Визначає загальний для всіх елементів схеми набір умов для можливості прийняття заявок, а також передачі заявок далі за схемою (за допомогою цього реалізований механізм клапанів)
- Визначає порядок, за яким заявки передаються даному елементу від елементів-джерел. (Алгоритм методу AskForParcels зображений на рис. 4. Цей метод викликається об'єктом класу TQSheme, якому належить цей елемент на етапі моделювання переходу заявок).
Класи TSource, TAccumulator, TChannel доопределяют функції свого загального предка TElement для забезпечення більш конкретної поведінки, характерного для елементів відповідного класу.
Рис. 9 Блок-схема процедури TElement.AskForParcel.
Опис:
- Блок 1 - задається цикл за всіма джерелами для цього елемента;
- Блок 2, 3 - функції визначення виразів для клапанів, встановлені користувачем;
- Блок 4 - перевірка можливості прийняття даним елементом заявки;
- Блок 5 - прийом заявки;
- Блок 6 - відмова заявці в прийомі.
Головне вікно програми показано на малюнку 10.
Рис. 10 Головне вікно програми.
Математичний опис системи.Дана система являє собою одноканальну СМО з відмовами.
Інтенсивність потоку заявок для неї буде визначатися таким виразом:
l = l1 + l2 + l3 (1),
де l1, l2, l3 - інтенсивність потоку заявок від кожного проектувальника відповідно. З урахуванням того, що дані по всіх проектувальникам однакові вираз (1) прийме наступний вигляд:
l = 3l1 (2).
Інтенсивність потоку заявок знайдемо за допомогою виразу
де - Середній час надходження заявок від одного проектувальника, яке в свою чергу з урахуванням умов завдання обчислюється як
(3),
де t1 - середній час набору проектувальником одного рядка завдання,
t2 - час аналізу результату проектувальником
З урахуванням виразів (2), (3) вираз (1) прийме наступний вигляд:
l = 3 / (10t1 + t2) (4).
Інтенсивність потоку обслуговувань для даної системи визначається за формулою
(5),
де - Середній час обробки ЕОМ одного завдання.
Щоб знайти пропускну здатність ЕОМ, скористаємося формулою для пропускної здатності одноканальної СМО з відмовами:
Q = m / (m + l) (6)
Щоб знайти імовірність простою проектувальника, скористаємося формулою для знаходження ймовірності відмови в одноканальної СМО:
Ротко = l / (m + l) (7)
Результати моделювання та аналітичного рішення.Скориставшись вираженіяі (6) і (7), знайдемо коефіцієнт завантаження ЕОМ і імовірність простою проектувальника через зайнятість ЕОМ.
Коефіцієнт завантаження ЕОМ Q = 0,8125
Імовірність простою проектувальника через зайнятість ЕОМ Р = 0,1875.
При моделюванні роботи системи на ЕОМ були отримані наступні результати:
Коефіцієнт завантаження ЕОМ Q = 0,256
Імовірність простою проектувальника через зайнятість ЕОМ Р = 0,1.
Розбіжність результатів аналітичних розрахунків і машинного моделювання пояснюється тим, що в для розрахунку аналітичним методом дана система була спрощена і зведена до вигляду одноканальної СМО з відмовами, що не враховує всіх особливостей функціонування вихідної системи.
Висновок.Результаті даної роботи стала побудова програми, що моделює процес функціонування заданої сітсеми. Були розраховані (аналітично і за допомогою побудованого моделюючого алгоритму) показники ефективності даної системи: коефіцієнт завантаження та імовірність простою проектувальника через зайнятість ЕОМ. Виявлено основні закономірності та способи взаємодії елементів Q-схем, а також причини розбіжності розрахункових показників з результатами прогону моделюючого алгоритму на ЕОМ.
Література.1. Кремер «Дослідження операцій в економіці»-М.: «Економіка» 1997 р.
2. Рад Б.Я., Яковлев С. А. Моделювання систем. - М.: ВШ, 1995.
3. Рад Б.Я., Яковлєв С.О. Моделювання систем. Практикум. - М.: ВШ, 1999.
4. Вентцель Є.С. Теорія ймовірностей. -М.: Наука, 1969.
5. Вентцель Є.С. Дослідження операцій. - М.: Сов. Радіо, 1972.
Програми. Текст програми.unit QSheme;
interface
uses Classes, SysUtils, Forms, QSObjs, QSTypes, Utils, ExtCtrls;
const
MaxElementCount = 10000;
type
TQSheme = class
private
FParcelsClass: TParcelsClass;
FStepCount: integer;
FSysPeriod: TCustTime;
FStepPeriod: TCustTime;
FSysTime: TCustTime;
FElements: TList;
FFinishElements: TList;
FLastElements: TList;
FSourceElements: TList;
FParcels: TList;
FOrderElementCount: integer;
FEventQueue: TList;
FOrder: array [0 .. MaxElementCount-1] of integer;
FDiagram: TPaintBox;
protected
function GetElement (Index: integer): TElement;
function GetElementCount: integer;
procedure InitAnalize;
procedure FreeAnalize;
procedure InitEmulation;
procedure FreeEmulation;
procedure FindFinishElements;
procedure GetRecipientsOrder;
procedure Step;
procedure TakeParcelsFromFinishElements;
function IsFinishElement (Element: TElement): Boolean;
function FastestStepPeriod: TCustTime;
procedure ClearParcelList;
procedure ClearEventQueue;
function GetCounts (Index: integer): integer;
function GetParcelCount: integer;
procedure DrawElementLines;
procedure DisplayEvents;
public
function NewParcel: Pointer;
procedure NewEvent (AEvent: integer; ASender, ASource: TObject; AInfo: TInfo);
procedure RedrawDiagram;
procedure Emulation;
procedure Analize;
constructor Create;
destructor Destroy; override;
procedure AddElement (Element: TElement);
procedure GetOrder;
procedure DelElement (Element: TElement);
property SysTime: TCustTime read FSysTime;
property SysPeriod: TCustTime read FSysPeriod write FSysPeriod;
property StepPeriod: TCustTime read FStepPeriod write FStepPeriod;
property Counts [Index: integer]: integer read GetCounts;
property BornParcelCount: integer index 0 read GetCounts;
property StoreParcelCount: integer index 1 read GetCounts;
property WorkParcelCount: integer index 2 read GetCounts;
property PassedParcelCount: integer index 3 read GetCounts;
property RefusedParcelCount: integer index 4 read GetCounts;
property ParcelCount: integer read GetParcelCount;
property StepCount: integer read FStepCount write FStepCount;
property ParcelsClass: TParcelsClass read FParcelsClass write FParcelsClass;
published
property Diagram: TPaintBox read FDiagram write FDiagram;
property ElementCount: integer read GetElementCount;
property Elements [Index: integer]: TElement read GetElement;
end;
implementation
uses MainFrm;
constructor TQSheme.Create;
begin
FElements: = TList.Create;
FParcelsClass: = TParcel;
FParcels: = TList.Create;
FEventQueue: = TList.Create;
end;
destructor TQSheme.Destroy;
begin
FElements.Free;
ClearEventQueue;
FEventQueue.Free;
ClearParcelList;
FParcels.Free;
inherited;
end;
function TQSheme.GetElement (Index: integer): TElement;
begin
Result: = FElements [Index];
end;
function TQSheme.GetElementCount: integer;
begin
Result: = FElements.Count
end;
procedure TQSheme.AddElement (Element: TElement);
begin
if Assigned (Element) then begin
FElements.Add (Element);
Element.Sheme: = Self;
end;
end;
procedure TQSheme.DelElement (Element: TElement);
var i, j: integer;
begin
if Assigned (Element) then begin
for i: = 0 to ElementCount - 1 do
for j: = Elements [i]. SourceCount-1 downto 0 do
if Elements [i]. Sources [j] = Element then
Elements [i]. DelSource (Element);
FElements.Remove (Element);
end;
end;
function TQSheme.IsFinishElement (Element: TElement): Boolean;
var j, s: integer;
begin
Result: = False;
for j: = 0 to ElementCount-1 do begin
for s: = 0 to Elements [j]. SourceCount-1 do begin
if Element = Elements [j]. Sources [s] then Exit;
end;
end;
Result: = True;
end;
procedure TQSheme.FindFinishElements;
var i: integer;
begin
for i: = 0 to ElementCount-1 do
if IsFinishElement (Elements [i]) then begin
FFinishElements.Add (Elements [i]);
FLastElements.Add (Elements [i]);
end;
end;
function TQSheme.FastestStepPeriod: TCustTime;
var i: integer;
Min: TCustTime;
begin
Min: = FSysPeriod;
for i: = 0 to ElementCount-1 do
if (Elements [i] is TShop) then
with TShop (Elements [i]). Generator do
if Mean-Disp <Min then Min: = Mean-Disp;
{$ Ifndef Precision}
Result: = Min;
{$ Else}
Result: = Min div 10;
{$ Endif}
end;
procedure TQSheme.InitAnalize;
begin
FSysTime: = 0;
FStepCount: = 0;
FOrderElementCount: = 0;
FLastElements: = TList.Create;
FSourceElements: = TList.Create;
end;
procedure TQSheme.FreeAnalize;
begin
FLastElements.Free;
FSourceElements.Free;
end;
procedure TQSheme.GetRecipientsOrder;
var i, s: integer;
LastElement: TElement;
begin
if FLastElements.Count = 0 then Exit;
for i: = 0 to FLastElements.Count-1 do begin
LastElement: = TElement (FLastElements [i]);
FOrder [FOrderElementCount]: = FElements.IndexOf (LastElement);
Inc (FOrderElementCount);
for s: = 0 to LastElement.SourceCount - 1 do
if FSourceElements.IndexOf (LastElement.Sources [s]) <0 then
FSourceElements.Add (LastElement.Sources [s]);
end;
SwapPointers (Pointer (FSourceElements), Pointer (FLastElements));
FSourceElements.Clear;
GetRecipientsOrder;
end;
procedure TQSheme.GetOrder;
begin
FindFinishElements;
GetRecipientsOrder;
end;
procedure TQSheme.TakeParcelsFromFinishElements;
var i: integer;
Parcel: TParcel;
begin
for i: = 0 to FFinishElements.Count-1 do
with TElement (FFinishElements [i]) do
if CanDrop then begin
Parcel: = Container;
NewEvent (EV_PASS, nil, FFinishElements [i], Parcel.Info);
DoBeforeDrop (FFinishElements [i]);
DropParcel;
DoAfterDrop (FFinishElements [i]);
Parcel.State: = psPassed;
end;
end;
procedure TQSheme.Step;
var i: integer;
begin
TakeParcelsFromFinishElements;
for i: = 0 to FOrderElementCount-1 do Elements [FOrder [i]]. AskForParcel;
Form1.Gauge1.Progress: = Round (FSysTime / FSysPeriod * 100);
Inc (FSysTime, FStepPeriod);
Inc (FStepCount);
end;
procedure TQSheme.Analize;
begin
try
try
InitAnalize;
GetOrder;
FStepPeriod: = FastestStepPeriod;
finally
FreeAnalize;
end;
except
on EInvalidPointer do raise;
end;
end;
procedure TQSheme.ClearEventQueue;
var i: integer;
begin
if Assigned (FEventQueue) then begin
for i: = 0 to FEventQueue.Count - 1 do FreeMem (FEventQueue [i], SizeOf (TEventRec));
FEventQueue.Clear;
end;
end;
procedure TQSheme.ClearParcelList;
var i: integer;
begin
if Assigned (FParcels) then begin
for i: = 0 to FParcels.Count - 1 do TParcel (FParcels [i]). Free;
FParcels.Clear;
end;
end;
procedure TQSheme.InitEmulation;
var i: integer;
begin
ClearParcelList;
ClearEventQueue;
for i: = 0 to ElementCount - 1 do
Elements [i]. ClearContainer;
FFinishElements: = TList.Create;
end;
procedure TQSheme.FreeEmulation;
begin
FFinishElements.Free;
end;
procedure TQSheme.Emulation;
begin
try
InitEmulation;
Analize;
while FSysTime <FSysPeriod do Step;
Form1.Gauge1.Progress: = 100;
/ / RedrawDiagram;
finally
FreeEmulation;
end;
end;
function TQSheme.NewParcel: Pointer;
var P: Pointer;
begin
P: = FParcelsClass.Create;
FParcels.Add (P);
Result: = P;
end;
procedure TQSheme.NewEvent (AEvent: Integer; ASender, ASource: TObject; AInfo: TInfo);
var P: PEventRec;
begin
GetMem (P, SizeOf (TEventRec));
with P ^ do begin
Event: = AEvent;
Sender: = ASender;
Source: = ASource;
Info: = AInfo;
SysTime: = FSysTime;
end;
FEventQueue.Add (P);
end;
function TQSheme.GetCounts (Index: integer): integer;
var i: integer;
begin
Result: = 0;
for i: = 0 to FParcels.Count-1 do
if Ord (TParcel (FParcels [i]). State) = Index then Inc (Result);
end;
function TQSheme.GetParcelCount: integer;
begin
Result: = FParcels.Count;
end;
const / / DrawConstants
Top = 20;
Left = 20;
Interval = 20;
procedure TQSheme.DrawElementLines;
var i: integer;
Y: integer;
begin
for i: = 0 to ElementCount-1 do begin
Y: = Top + interval * i;
with Diagram.Canvas do begin
TextOut (0, Y + Font.Height, Elements [i]. Name);
MoveTo (0, Y);
LineTo (Diagram.ClientWidth, Y)
end;
end;
end;
procedure TQSheme.DisplayEvents;
{Var i: integer;
s: string;}
begin
{Form1.mResults.Items.Clear;
for i: = 0 to FEventQueue.Count - 1 do begin
with TEventRec (FEventQueue [i] ^) do begin
case Event of
EV_TAKE: S: ='+++:';
EV_REFUSE: S: ='------:';
EV_PASS: S: = 'PASS:';
end;
S: = S + IntToStr (Info);
S: = S + '[' + IntToStr (SysTime) + ']';
if Assigned (Source) then S: = S + TElement (Source). Name
else S: = S + 'nil';
S: = S +'->';
if Assigned (Sender) then S: = S + TElement (Sender). Name
else S: = S + 'nil';
end;
Form1.mResults.Items.Add (S);
end;}
end;
procedure TQSheme.RedrawDiagram;
/ / Var i: integer;
begin
/ / Diagram.Canvas.FillRect (Rect (0,0, Diagram.Width, Diagram.Height));
/ / DrawElementLines;
DisplayEvents;
end;
initialization
Randomize;
end.
unit QSObjs;
interface
uses Classes, QSTypes, SysUtils, Utils;
type
TElement = class;
TIsRightElement = function (Element: TElement): Boolean of object; / / far;
TBeforeAfterAction = procedure (Sender: TElement) of object;
TElement = class
private
FId: integer;
FName: string;
FSources: TList;
FSheme: TObject;
FContainer: TParcel;
FOnSourceValidate: TIsRightElement;
FOnDestinationValidate: TIsRightElement;
FBeforeTake: TBeforeAfterAction;
FAfterTake: TBeforeAfterAction;
FBeforeDrop: TBeforeAfterAction;
FAfterDrop: TBeforeAfterAction;
procedure SetSheme (ASheme: TObject);
function GetSourceCount: integer;
function GetSource (Index: integer): TElement;
function GetParcelPresent: Boolean;
function GetCanDropParcelFor (Destination: TElement): Boolean;
function GetCanTakeParcelFrom (Source: TElement): Boolean;
procedure Pass (SourceIndex: integer); virtual;
protected
function GetCanTake: Boolean; virtual; abstract;
function GetCanDrop: Boolean; virtual; abstract;
public
constructor Create; virtual;
destructor Destroy; override;
procedure AddSource (Element: TElement);
procedure DelSource (Element: TElement);
procedure AskForParcel; virtual;
procedure ClearContainer; virtual;
procedure RefuseParcel (SourceIndex: integer);
procedure DropParcel; virtual;
procedure TakeParcel (SourceIndex: integer); virtual;
procedure DoBeforeDrop (Sender: TElement);
procedure DoBeforeTake (Sender: TElement);
procedure DoAfterDrop (Sender: TElement);
procedure DoAfterTake (Sender: TElement);
property CanDropParcelFor [Destination: TElement]: Boolean read GetCanDropParcelFor;
property CanTakeParcelFrom [Source: TElement]: Boolean read GetCanTakeParcelFrom;
property Container: TParcel read FContainer write FContainer;
property ParcelPresent: Boolean read GetParcelPresent;
property CanTake: Boolean read GetCanTake;
property CanDrop: Boolean read GetCanDrop;
property Id: integer read FId write FId;
published
property Name: string read FName write FName;
property Sheme: TObject read FSheme write SetSheme;
property SourceCount: integer read GetSourceCount;
property Sources [Index: integer]: TElement read GetSource;
property OnSourceValidate: TIsRightElement read FOnSourceValidate write FOnSourceValidate;
property OnDestinationValidate: TIsRightElement read FOnDestinationValidate write FOnDestinationValidate;
property BeforeTake: TBeforeAfterAction read FBeforeTake write FBeforeTake;
property AfterTake: TBeforeAfterAction read FAfterTake write FAfterTake;
property BeforeDrop: TBeforeAfterAction read FBeforeDrop write FBeforeDrop;
property AfterDrop: TBeforeAfterAction read FAfterDrop write FAfterDrop;
end;
TElementClass = class of TElement;
TGenerator = class
private
FMean: TCustTime;
FDisp: TCustTime;
FRandomType: TRandomType;
function GetRandom: TCustTime;
public
constructor Create;
property Mean: TCustTime read FMean write FMean;
property Disp: TCustTime read FDisp write FDisp;
property RandomType: TRandomType read FRandomType write FRandomType;
property Time: TCustTime read GetRandom;
end;
TShop = class (TElement)
private
FGenerator: TGenerator;
FEndWorkTime: TCustTime;
procedure Pass (SourceIndex: integer); override;
function GetProcessed: Boolean;
protected
function GetCanTake: Boolean; override;
function GetCanDrop: Boolean; override;
property EndWorkTime: TCustTime read FEndWorkTime write FEndWorkTime;
public
constructor Create; override;
destructor Destroy; override;
procedure DropParcel; override;
property Generator: TGenerator read FGenerator;
property Processed: Boolean read GetProcessed;
procedure Work; virtual;
end;
TChannel = class (TShop)
public
procedure Pass (SourceIndex: integer); override;
end;
TSource = class (TShop)
private
procedure TakeParcel (SourceIndex: integer); override;
public
procedure Pass (SourceIndex: integer); override;
procedure AskForParcel; override;
end;
TAccumulator = class (TElement)
private
FParcels: TList;
FLimited: Boolean;
FCapacity: integer;
function GetParcel (Index: integer): TParcel;
function GetFreeSpacePresent: Boolean;
function GetEmpty: Boolean;
procedure SetCapacity (Value: integer);
function GetCapacity: integer;
function GetParcelCount: integer;
procedure Pass (SourceIndex: integer); override;
function GetCanTake: Boolean; override;
function GetCanDrop: Boolean; override;
public
constructor Create; override;
destructor Destroy; override;
procedure ClearContainer; override;
procedure DropParcel; override;
property ParcelCount: integer read GetParcelCount;
property Parcels [Index: integer]: TParcel read GetParcel;
property FreeSpacePresent: Boolean read GetFreeSpacePresent;
property Empty: Boolean read GetEmpty;
procedure TakeParcel (Index: integer); override;
published
property Capacity: integer read GetCapacity write SetCapacity;
property Limited: Boolean read FLimited write FLimited;
end;
TAccumulatorClass = class of TAccumulator;
implementation
uses QSheme;
constructor TElement.Create;
begin
FSources: = TList.Create;
end;
destructor TElement.Destroy;
begin
FSources.Free;
inherited;
end;
procedure TElement.SetSheme (ASheme: TObject);
begin
if Assigned (ASheme) then FSheme: = ASheme;
end;
procedure TElement.AddSource (Element: TElement);
begin
if Assigned (Element) then FSources.Add (Element);
end;
procedure TElement.DelSource (Element: TELement);
begin
if Assigned (Element) then FSources.Remove (Element);
end;
function TElement.GetSourceCount: integer;
begin
Result: = FSources.Count;
end;
function TElement.GetSource (Index: integer): TElement;
begin
Result: = FSources [Index];
end;
procedure TElement.TakeParcel (SourceIndex: integer);
begin
FContainer: = Sources [SourceIndex]. FContainer;
TQSheme (Sheme). NewEvent (EV_TAKE, Self, Sources [SourceIndex], FContainer.Info);
Sources [SourceIndex]. DropParcel;
end;
procedure TElement.Pass (SourceIndex: integer);
var Source: TElement;
begin
if SourceIndex <> -1 then Source: = Sources [SourceIndex];
DoBeforeTake (Self);
if SourceIndex <> -1 then Source.DoBeforeDrop (Source);
TakeParcel (SourceIndex);
DoAfterTake (Self);
if SourceIndex <> -1 then Source.DoAfterDrop (Source);
end;
function TElement.GetCanDropParcelFor (Destination: TElement): Boolean;
begin
Result: = CanDrop;
if Assigned (OnDestinationValidate) then
Result: = Result and OnDestinationValidate (Destination)
end;
function TElement.GetCanTakeParcelFrom (Source: TElement): Boolean;
begin
if Assigned (OnSourceValidate) then
Result: = OnSourceValidate (Source)
else Result: = True;
end;
procedure TElement.AskForParcel;
var i: integer;
Source: TElement;
begin
for i: = 0 to SourceCount - 1 do begin
Source: = Sources [i];
if Source.CanDropParcelFor [Self] and CanTakeParcelFrom [Source] then
if CanTake then begin
Pass (i);
if Self is TShop then Exit;
end
else
if not (Source is TAccumulator) then RefuseParcel (i);
end; / / for
end;
function TElement.GetParcelPresent: Boolean;
begin
Result: = FContainer <> nil;
end;
procedure TElement.ClearContainer;
begin
DropParcel;
end;
procedure TElement.RefuseParcel (SourceIndex: integer);
begin
Sources [SourceIndex]. Container.State: = psRefused;
TQSheme (Sheme). NewEvent (EV_REFUSE, Self, Sources [SourceIndex], Sources [SourceIndex]. Container.Info);
Sources [SourceIndex]. DropParcel;
end;
procedure TElement.DropParcel;
begin
Container: = nil;
end;
procedure TElement.DoBeforeDrop (Sender: TElement);
begin
if Assigned (FBeforeDrop) then FBeforeDrop (Sender);
end;
procedure TElement.DoAfterDrop (Sender: TElement);
begin
if Assigned (FAfterDrop) then FAfterDrop (Sender);
end;
procedure TElement.DoBeforeTake (Sender: TElement);
begin
if Assigned (FBeforeTake) then FBeforeTake (Sender);
end;
procedure TElement.DoAfterTake (Sender: TElement);
begin
if Assigned (FAfterTake) then FAfterTake (Sender);
end;
constructor TGenerator.Create;
begin
inherited;
FRandomType: = rtPlane;
end;
function TGenerator.GetRandom: TCustTime;
var R: single;
begin
case FRandomType of
rtPlane: R: = PlaneRND;
rtNormal: R: = NormRND;
rtExponent: R: = ExpRND
else
R: = Random;
end;
Result: = FMean - FDisp + Round (R * 2 * FDisp);
end;
constructor TShop.Create;
begin
inherited;
FGenerator: = TGenerator.Create;
end;
destructor TShop.Destroy;
begin
FGenerator.Free;
inherited;
end;
procedure TShop.DropParcel;
begin
inherited;
FEndWorkTime: = 0;
end;
procedure TShop.Pass (SourceIndex: integer);
begin
inherited;
Work;
end;
function TShop.GetProcessed: Boolean;
begin
Result: = (TQSheme (Sheme). SysTime> = FEndWorkTime);
end;
function TShop.GetCanTake: Boolean;
begin
Result: = not ParcelPresent and Processed;
end;
function TShop.GetCanDrop: Boolean;
begin
Result: = ParcelPresent and Processed;
end;
procedure TShop.Work;
begin
FEndWorkTime: = TQSheme (Sheme). SysTime + FGenerator.GetRandom;
end;
procedure TChannel.Pass (SourceIndex: integer);
begin
inherited;
Container.State: = psWork;
end;
procedure TSource.TakeParcel (SourceIndex: integer);
begin
Container: = TQSheme (Sheme). NewParcel;
end;
procedure TSource.Pass (SourceIndex: integer);
begin
inherited;
Container.State: = psBorn;
end;
procedure TSource.AskForParcel;
begin
if CanTake then Pass (-1);
end;
constructor TAccumulator.Create;
begin
FLimited: = False;
FParcels: = TList.Create;
inherited;
end;
destructor TAccumulator.Destroy;
begin
FParcels.Free;
end;
function TAccumulator.GetParcel (Index: integer): TParcel;
begin
Result: = FParcels [Index];
end;
function TAccumulator.GetCanDrop: Boolean;
begin
if Empty then AskForParcel;
if not Empty then Container: = FParcels.First;
Result: = not Empty;
end;
function TAccumulator.GetCanTake: Boolean;
begin
Result: = FreeSpacePresent;
end;
function TAccumulator.GetFreeSpacePresent: Boolean;
begin
Result: = (Capacity <> FParcels.Count) or (not Limited);
end;
function TAccumulator.GetEmpty: Boolean;
begin
Result: = FParcels.Count = 0;
/ / If not Result then Container: = FParcels.First;
end;
procedure TAccumulator.DropParcel;
begin
if not Empty then FParcels.Delete (0);
inherited;
end;
function TAccumulator.GetCapacity: integer;
begin
Result: = FCapacity;
end;
function TAccumulator.GetParcelCount: integer;
begin
Result: = FParcels.Count;
end;
procedure TAccumulator.SetCapacity (Value: integer);
begin
FLimited: = True;
FCapacity: = Value;
end;
procedure TAccumulator.ClearContainer;
begin
FParcels.Clear;
inherited;
end;
procedure TAccumulator.Pass (SourceIndex: integer);
begin
inherited;
Container.State: = psStore;
end;
procedure TAccumulator.TakeParcel (Index: integer);
begin
FParcels.Add (Sources [Index]. Container);
TQSheme (Sheme). NewEvent (EV_TAKE, Self, Sources [Index], Sources [Index]. Container.Info);
Container: = FParcels.Last;
Sources [Index]. DropParcel;
end;
end.