|
|
v1=
|
v2=
|
…
|
vk=
|
W=
|
|
|
--…
|
-1
|
|
|
|
-u1
|
=…
|
1
|
|
|
|
|
-u2
|
=…
|
1
|
|
|
|
|
…
|
…
|
.
|
.
|
.
|
.
|
.
|
-uk
|
=…
|
1
|
|
|
|
|
1
|
Z =
|
-1
|
-1
|
…
|
-1
|
0
|
Розв’язавши цю
задачу і отримавши оптимальні значення max(Z) = min(W), що досягаються
при значеннях змінних двоїстої задачі , можна обчислити вагові
коефіцієнти для
компромісного розв’язку багатокритеріальної задачі:
,
Компромісний вектор
значень змінних для багатокритеріальної задачі є лінійною комбінацією
оптимальних векторів кожної функції мети. Це сума векторів, що помножені кожен
на свій ваговий коефіцієнт:
Підставивши цей
компромісний вектор в кожну функцію мети багатокритеріальної задачі отримуємо
компромісні значення цих функцій.
3.
Вирішування
Рівняння,
нерівності та функції записуються у таблицю:
Розв’язування
задачі ЛП для кожної функції мети окремо:
Пошук
оптимального розв’язку для функції Z1
Задача
для симплекс-метода з функцією Z1
Незалежних
змінних немає.
Виключення
0-рядків: немає.
Опорний
розв’язок: готовий (усі вільні члени невід’ємні).
Пошук
оптимального розв’язку:
Результат для прямої
задачі:
У рядку-заголовку:
x1 = 0;
y2 = 0;
y1 = 0;
y3 = 0;
У стовпці-заголовку:=
2,33333333333333;= 4,55555555555556;= 1,88888888888889;
Функція мети: Z1 =
11,4444444444444.
Пошук оптимального
розв’язку для функції Z2
Функцію Z2, що мінімізується,
замінили на протилежну їй - Z2, що максимізується. Запис для вирішування симплекс-методом
максимізації
Незалежних змінних
немає.
-рядків немає.
Опорний розв’язок:
готовий.
Пошук оптимального:
Після отримання
розв’язку максимізації для - Z2, взято протилежну до неї функцію Z2, і отримано розв’язок мінімізації для неї
Результат для прямої
задачі:
У рядку-заголовку:
x1 = 0;
y2 = 0;
x3 = 0;
y3 = 0;
У стовпці-заголовку:=
14;= 5,33333333333333;= 0,333333333333333;
Функція мети: Z2 =
-10,3333333333333.
Пошук оптимального
розв’язку для функції Z3
Задача для
симплекс-методу максимізації
Незалежних змінних і
0-рядків немає.
Опорний розв’язок вже
готовий.
Пошук оптимального:
Результат для прямої задачі:
У рядку-заголовку:
x1 = 0;
x2 = 0;
y1 = 0;
x4 = 0;
У стовпці-заголовку:=
3,33333333333333;= 1,66666666666667;= 18,6666666666667;
Функція мети: Z3 =
3,33333333333333.
Підрахунок мір
неоптимальності
Матриця мір
неоптимальності та рядок функції мети, стовпець вільних членів і заголовки
задачі ЛП, що будуть використані далі
До
мір додана найбільша за модулем міра . Матриця у формі задачі
ЛП
Розв’язування
ігрової задачі:
Незалежних
змінних немає.
-рядків немає.
Опорний розв’язок
вже готовий.
Пошук
оптимального розв’язку:
Результат для двоїстої
задачі (відносно розв'язаної):
У рядку-заголовку:=
0,402684563758389;= 0,174496644295302;= 0,319280641167655;
У стовпці-заголовку:
v3 = 0;
v2 = 0;
u2 = 0;
Функція мети: Z =
0,577181208053691.
############
Вагові коефіцієнти
(Li[Func]=ui/W(U)):[Z1] = 0,697674418604651[Z2] = 0[Z3] = 0,302325581395349
Компромісні значення
змінних= 0= 3,17829457364341= 2,63565891472868= 1,31782945736434
Компромісні значення
функцій мети:= 8,9922480620155= -2,4031007751938= 0,775193798449612
Вирішування закінчено.
Успішно.
4. Текст програми
Модуль опису класу, що
виконує роботу з задачами ЛП:
unit UnMMDOpr;
SysUtils, Types,
Classes, Forms, Controls, StdCtrls, Dialogs, Graphics,, UControlsSizes,
Menus;sc_CrLf=Chr(13)+Chr(10);_Minus='-';_Plus='+';_Equal='=';_NotEqual='<>';_Mul='*';_Space='
';_KrKm=';';_BrOp=' ('; sc_BrCl=')';
_XVarName='x';_YFuncName='y';_DualTaskFuncNameStart='v';_DualTaskVarNameStart='u';
_RightSideValsHdr='1';
_DestFuncHdr='Z';_DualDestFuncHdr='W';
_TriSpot='…';
sc_Spot='.';_DoubleSpot=':';_DoubleQuot='"';
_DependentColor:TColor=$02804000;_IndependentColor:TColor=$02FF8000;_RightSideColColor:TColor=$02FFD7AE;_HeadColColor:TColor=$02808040;_FuncRowColor:TColor=$02C080FF;_DestFuncToMaxNameColor:TColor=$024049FF;_DestFuncToMinNameColor:TColor=$02FF4940;_DestFuncValColor:TColor=$02A346FF;_ValInHeadColOrRowColor:TColor=$025A5A5A;
_SolveColColor:TColor=$02AAFFFF;_SolveRowColor:TColor=$02AAFFFF;_SolveCellColor:TColor=$0200FFFF;
_FixedRows=2;
bc_FixedCols=1;
{Кількість стовпців
перед стовпцями змінних та після них,
які можна редагувати,
для редагування таблиці задачі
лінійного програмування
(максимізації чи мінімізації функції):}_LTaskColsBeforeVars=1;
bc_LTaskColsAfterVars=1;_LTaskRowsBeforeVars=bc_LTaskColsBeforeVars;
_LineEqM1ColsBeforeVars=1;_LineEqM2ColsAfterVars=1;
_NotColored=-1;
_Negative=-1; bc_Zero=0;
bc_Positive=1;
_MenuItemColorCircleDiameter=10;
_DependentVar='Залежна
змінна (>=0)';_IndependentVar='Незалежна змінна (будь-яке дійсне
число)';_FreeMembers='Вільні члени (праві сторони
рівнянь)';_InequalFuncName='Назва функції
умови-нерівності';_DestFuncCoefs='Рядок коефіцієнтів функції
мети';_DestFuncName='Назва функції мети';_DestFuncToMaxName=sc_DestFuncName+',
що максимізується';_DestFuncToMinName=sc_DestFuncName+', що
мінімізується';_OtherType='Інший тип';_DestFuncVal='Значення функції
мети';_ValInHeadColOrRow='Число у заголовку
таблиці';_SolveCol='Розв''язувальний стовпець';_SolveRow='Розв''язувальний
рядок';_SolveCell='Розв''язувальна комірка';
=Extended; {тип
дійсних чисел, що використовуються}
=-1..1;
{Ідентифікатор для типу
елемента масиву чисел та імен змінних.
Типи змінних: залежні,
незалежні, функції (умови-нерівності).
Залежні змінні - це
змінні, для яких діє умова невід'ємності:}=(bc_IndependentVar, bc_DependentVar, bc_FuncVal,
bc_Number,_DestFuncToMax, bc_DestFuncToMin, bc_OtherType);=set of
THeadLineElmType;
=String[7]; {короткий
рядок для імені змінної}=record {Елемент-число або назва змінної:}:THeadLineElmType;byte
of
: (AsNumber:TWorkFloat);
{для запису числа}
:
(AsVarName:TVarNameStr; {для запису назви змінної}
{Для запису номера
змінної по порядку в умові задачі (в рядку
чи стовпці-заголовку):}: Integer;
{Відмітка про те, що
змінна була у рядку-заголовку (True), або
у стовпцю-заголовку
(False):}: Boolean);;
=array of TValOrName; {тип
масиву для заголовків матриці}
=array of TWorkFloat; {тип
масиву дійсних чисел}=array of TFloatArr; {тип матриці чисел}
=array of Byte; {масив
байтів - для поміток для змінних}=array of TByteArr;
{Стани об'єкта
форматування таблиці у GrowingStringGrid:}=(fs_EnteringEqs, fs_EnteringLTask, fs_SolvingEqsM1,_SolvingEqsM2,
fs_SolvingLTask,_NoFormatting, fs_FreeEdit);
{Тип переходу до
двоїстої задачі: від задачі максимізації до
задачі мінімізації, або
навпаки. Ці два переходи виконуються за
різними правилами (різні
правила зміни знаків «<=» та «>=»
при переході від
нерівностей до залежних змінних, і від залежних змінних
до нерівностей). І
двоїсті задачі для максимізації і мінімізації
виходять різні…}=(dt_MaxToMin, dt_MinToMax);
{Процедури для
форматування екранної таблиці GrowingStringGrid під час
роботи з нею у
потрібному форматі, а також для вирішування
задач ЛП і відображення
проміжних чи кінцевих результатів у
такій таблиці:}=class(TObject)
{Робочі масиви:}, CurHeadCol:TValOrNameMas; {заголовки таблиці}:TFloatMatrix;
{таблиця}
{Масиви для зберігання
умови (використовуються для
багатокритеріальної
задачі):},
CopyHeadCol:TValOrNameMas; {заголовки таблиці}:TFloatMatrix; {таблиця}
, SolWasFound,
WasNoRoots, WasManyRoots,TaskPrepared, EqM2TaskPrepared, LTaskPrepared:
Boolean;
{Прапорець про те, що
вміст CurGrid ще не був прочитаний
даним об'єктом з часу
останнього редагування його користуваем:}: Boolean;
{В режимах розв'язування
(CurFormatState=fs_SolvingEqsM1,_SolvingEqsM2, fs_SolvingLTask)
координати
розв'язувальної комірки у GrowingStringGrid
(відносно екранної
таблиці);
в режимах редагування
(CurFormatState=fs_EnteringEqs, fs_EnteringLTask)
координати комірки, для
якої викликано контекстне меню
(відносно верхньої лівої
комірки таблиці коефіцієнтів (що має
тут координати [0,0])):}, CurGridSolveRow: Integer;
{Номери стовпця і рядка-заголовків
у CurGrid:}, CHeadRowNum: Integer;
{Режим форматування і
редагування чи розв'язування задачі:}:TTableFormatState;
{Екранна таблиця для
редагування чи відображення результатів:}:TGrowingStringGrid;:TMemo; {поле для відображення повідомлень}
{Адреси обробників подій
екранної таблиці CurGrid, які цей
об'єкт заміняє своїми
власними:}:TNewColEvent;:TNewRowEvent;:TDrawCellEvent;:TNotifyEvent;:TMouseEvent;:TSetEditEvent;
{Процедура встановлює
довжину рядка-заголовка CurHeadRow відповідно
до ширини екранної
таблиці CurGrid і заповнює нові елементи
значеннями за
змовчуванням. Використовується при зміні розмірів
екранної таблиці. Після
її виклику можна вказувати типи змінних
у рядку-заголовку
(користувач вибирає залежні та незалежні):}UpdateLTaskHeadRowToStrGrid (SGrid:TStringGrid);
{Процедура для підтримки
масиву стовпця-заголовка під час
редагування таблиці.
Встановлює довжину масиву відповідно до висоти
екранної таблиці і
координат вписування в неї таблиці задачі,
заповнює нові комірки
значеннями за змовчуванням:}UpdateLTaskHeadColToStrGrid
(SGrid:TStringGrid;: array of Integer);
{Функції для переходів з
одного режиму до іншого:}SetNewState
(Value:TTableFormatState);PrepareToSolveEqsWithM1:
Boolean;PrepareToSolveEqsWithM2: Boolean;PrepareToSolveLTask: Boolean;
SetNewGrid
(Value:TGrowingStringGrid); {перехід до нового CurGrid}SetNewMemo
(Value:TMemo); {перехід до нового CurOutConsole}
{Процедури форматування
GrowingStringGrid для набору таблиці
лінійних рівнянь:}EditLineEqsOnNewRow (Sender: TObject; NewRows: array of
Integer);EditLineEqsOnNewCol (Sender: TObject; NewCols: array of
Integer);EditLineEqsOnDrawCell (Sender: TObject; ACol, ARow: Integer;: TRect;
State: TGridDrawState);
{Процедура форматування
GrowingStringGrid відображення таблиці
у процесі розв'язання
системи рівнянь способом 1 і 2:}SolveLineEqsM1OrM2OnDrawCell
(Sender: TObject;, ARow: Integer; Rect: TRect; State: TGridDrawState);
{Процедури форматування
GrowingStringGrid для набору таблиці
задачі максимізації чи
мінімізації лінійної форми (функції з
умовами-нерівностями чи
рівняннями):}EdLineTaskOnNewRow
(Sender: TObject; NewRows: array of Integer);EdLineTaskOnNewCol (Sender:
TObject; NewCols: array of Integer);EdLineTaskOnDrawCell (Sender: TObject;
ACol, ARow: Integer;: TRect; State: TGridDrawState);EdLineTaskOnDblClick
(Sender: TObject);
{Процедура реагує на
відпускання правої кнопки миші на
комірках рядка-заголовка
та стовпця-заголовка таблиці.
Формує та відкриває
контекстне меню для вибору типу комірки із можливих
типів для цієї комірки:}EdLineTaskOnMouseUp (Sender: TObject;: TMouseButton; Shift:
TShiftState; X, Y: Integer);
{Процедура перевіряє
наявність об'єкта TPopupMenu. Якщо його немає
(SGrid. PopupMenu=Nil),
то створює новий.
Видаляє усі пунтки
(елементи, теми) з меню:}InitGridPopupMenu
(SGrid:TStringGrid);
{Додає пункт меню для
вибору типу комірки в таблиці з заданим
написом SCaption і
кругом того кольору, що асоційований з даним
типом SAssocType. Для
нового пункту меню настроює виклик
процедури обробки
комірки для задавання їй обраного типу SAssocType.
Значення SAssocType
записує у поле Tag об'єкта пункту меню:}AddCellTypeItemToMenu (SMenu:TPopupMenu;: String; IsCurrentItem:
Boolean; SAssocType:THeadLineElmType;: Boolean=True);
{Обробник вибору пункту
в меню типів для комірки
рядка - чи
стовпця-заголовка.}ProcOnCellTypeSelInMenu
(Sender: TObject);
{Процедури для нумерації
рядків і стовпців при відображенні
таблиць у ході вирішення
задачі, або з результатами. Лише
проставляють номери у
першому стовпцю і першому рядку:}NumerationOnNewRow
(Sender: TObject; NewRows: array of Integer);NumerationOnNewCol (Sender:
TObject; NewCols: array of Integer);
{Процедура для
реагування на редагування вмісту комірок
під час редагування
вхідних даних. Встановлює прапорець:=True про те, що екранна таблиця має
зміни:}ReactOnSetEditText
(Sender: TObject; ACol, ARow: Longint;Value: string);
{Зчитує комірку з
екранної таблиці в рядок-заголовок.
Вхідні дані:- номер
комірки у рядку-заголовку.
Для екранної таблиці
використовуються координати комірки відповідно до
координат
рядка-заголовка та стовпця заголовка (верхнього лівого кута
таблиці з заголовками):
HeadColNumInGrid і HeadRowNumInGrid:}ReadHeadRowCell
(SCol: Integer);
{Зчитує комірку з
екранної таблиці в стовпець-заголовок.
Вхідні дані:- номер
комірки у стовпці-заголовку.
Для екранної таблиці
використовуються координати комірки відповідно до
координат
рядка-заголовка та стовпця заголовка (верхнього лівого кута
таблиці з заголовками):
HeadColNumInGrid і HeadRowNumInGrid:}ReadHeadColCell
(SRow: Integer);
{Процедура для
зчитування таблиці та її заголовків із CurGrid:}ReadTableFromGrid: Boolean;
{Процедура для
відображення таблиці та її заголовків у CurGrid:}WriteTableToGrid (SHeadColNum, SHeadRowNum: Integer;:
Boolean=True):Boolean;
{Визначення розмірів
таблиці задачі, і корегування довжини
заголовків таблиці та
зовнішнього масиву таблиці (масиву масивів):}GetTaskSizes (Var DWidth, DHeight: Integer);
{Жорданове виключення за
заданим розв'язувальним елементом матриці:}GI (RozElmCol, RozElmRow: Integer;SDHeadRow,
SDHeadCol:TValOrNameMas; Var SDMatrix:TFloatMatrix;DColDeleted: Boolean;
ToDoMGI: Boolean=False;: Boolean=True):Boolean;
{Відображення таблиці,
обробка віконних подій доки користувач не
скомандує наступний крок
(якщо користувач не скомандував вирішувати
до кінця):}WaitForNewStep (HeadColNum, HeadRowNum: Integer);
{Пошук ненульової
розв'язувальної комірки для вирішування системи
рівнянь (починаючи з
комірки [CurRowNum, CurColNum]):}SearchNozeroSolveCell
(CurRowNum,, MaxRow, MaxCol: Integer;, HeadColNum: Integer;:
Boolean=True):Boolean;
{Зміна знаків у рядку
таблиці і відповідній комірці у
стовпці-заголовку:}ChangeSignsInRow (CurRowNum: Integer);
{Зміна знаків у стовпці
таблиці і відповідній комірці у
рядку-заголовку:}ChangeSignsInCol (CurColNum: Integer);
{Функція переміщує рядки
таблиці CurTable (разом із відповідними
комірками у
стовпці-заголовку CurHeadCol) з заданими типами комірок
стовпця-заголовка вгору.
Повертає номер найвищого
рядка із тих, що не було задано
переміщувати вгору (вище
нього - ті, що переміщені вгору):}ShiftRowsUp
(SHeadColElmTypes:THeadLineElmTypes;: Boolean=False):Integer;
{Аналогічна до
ShiftRowsUp, але переміщує вниз.
Повертає номер найвищого
рядка із тих, що переміщені вниз (вище
нього - рядки тих типів,
що не було задано переміщувати донизу):}ShiftRowsDown (:THeadLineElmTypes;: Boolean=False):Integer;
{Вирішування системи
лінійних рівнянь способом 1:}SolveEqsWithM1:
Boolean;
{Вирішування системи
лінійних рівнянь способом 2:}SolveEqsWithM2:
Boolean;
{Вирішування задачі
максимізації лінійної форми (що містить
умови-нерівності,
рівняння та умови на невід'ємність окремих
змінних і одну функцію
мети, для якої треба знайти максимальне
значення):}SolveLTaskToMax (DualTaskVals: Boolean):Boolean;
PrepareDFuncForSimplexMaximize:
Boolean;
PrepareDestFuncInMultiDFuncLTask
(SFuncRowNum,: Integer):Boolean;
{Процедура зчитує
значення функції мети у таблиці розв'язаної
однокритеріальної
задачі, і значення усіх змінних або функцій
в цьому розв'язку. Відображає
значення цих змінних,
функцій-нерівностей, і
функції мети в Self. CurOutConsole:}ShowLTaskResultCalc
(DualTaskVals: Boolean);
{Процедура зчитує
значення функції мети у таблиці розв'язаної
однокритеріальної
задачі, і значення усіх змінних або функцій в
цьому розв'язку:}ReadCurFuncSolution (Var
SDValVecs:TFloatMatrix;SDDestFuncVals:TFloatArr; SVecRow: Integer;: Boolean;
DualTaskVals: Boolean);BuildPaymentTaskOfOptim (SOptimXVecs:TFloatMatrix; Const
SOptimFuncVals:TFloatArr;: Integer);
CalcComprVec (Const
SVarVecs:TFloatMatrix;SWeightCoefs:TFloatArr; Var DComprVec:TFloatArr);
CalcDFuncVal (Const
SVarVec:TFloatArr;: Integer):TWorkFloat;
{Вирішування задачі
багатокритеріальної оптимізації лінійної
форми з використанням
теоретико-ігрового підходу.
Умовою задачі є
умови-нерівності, рівняння та умови на
невід'ємність окремих
змінних, і декілька функцій мети, для
яких треба знайти
якомога більші чи менші значення.
Функція повертає ознаку
успішності вирішування:}SolveMultiCritLTask:
Boolean;
{Процедури для зміни
позиціювання таблиці з заголовками у
екранній таблиці
CurGrid. Працюють лише у режимі fs_FreeEdit:}SetHeadColNum (Value: Integer);SetHeadRowNum (Value: Integer);
{Прапорці для керування
кроками вирішування:- продовжити на один крок;- при продовженні йти всі кроки
до кінця вирішування без
відображення таблиці на
кожному кроці;- припинити вирішування.
Для керування прапорці
можуть встановлюватися іншими потоками
програми, або і тим
самим потоком (коли процедури даного класу
викликають Application.
ProcessMessages):}, GoToEnd, Stop:
Boolean;
{Властивість для
керуання станом форматування:}TableFormatState:TTableFormatState
read CurFormatStateSetNewState default fs_NoFormatting;
{Прапорець про те, що
зараз задача у ході вирішування
(між кроками
вирішування):}Solving: Boolean
read InSolving;
SolutionFound: Boolean
read SolWasFound;NoRoots: Boolean read WasNoRoots;ManyRoots: Boolean read
WasManyRoots;
{Властивість для
задавання екранної таблиці:}StringGrid:TGrowingStringGrid
read CurGrid write SetNewGridNil;
{Поле для відображення
повідомлень:}MemoForOutput:TMemo read
CurOutConsole write SetNewMemoNil;
{Номери стовпця і
рядка-заголовків у CurGrid. Змінювати можна
тільки у режимі
fs_FreeEdit. В інших режимах зміна ігнорується:}HeadColNumInGrid: Integer read CHeadColNum write
SetHeadColNum;HeadRowNumInGrid: Integer read CHeadRowNum write SetHeadRowNum;
{Таблиця і її заголовки
у пам'яті:}Table:TFloatMatrix read
CurTable;HeadRow:TValOrNameMas read CurHeadRow;HeadCol:TValOrNameMas read
CurHeadCol;
{Читання і запис таблиці
та режиму редагування у файл
(тільки у режимах
редагування):}ReadFromFile (Const
SPath: String):Boolean;SaveToFile (Const SPath: String):Boolean;
{Процедури для читання і
зміни таблиці і її заголовків.
Не рекомендується
застосовувати під час вирішування
(при Solving=True):}SetTable (Const SHeadRow,
SHeadCol:TValOrNameMas;STable:TFloatMatrix);GetTable (Var DHeadRow,
DHeadCol:TValOrNameMas;DTable:TFloatMatrix);
{Вибір кольору для фону
комірки за типом елемента
стовпця - або
рядка-заголовка:}GetColorByElmType
(CurType:THeadLineElmType):TColor;
{Вибір назви комірки за
типом елемента
стовпця - або
рядка-заголовка:}GetNameByElmType
(CurType:THeadLineElmType):String;
{Зчитування умови задачі
із CurGrid та відображення прочитаного
на тому ж місці, де воно
було. Працює у режимах_EnteringEqs і fs_EnteringLTask.}GetTask (ToPrepareGrid: Boolean=True):Boolean;
{Приймає останні зміни
при редагуванні і відображає таблицю:}Refresh;ResetModified; {скидає прапорець зміненого стану}UndoChanges;
{відкидає останні зміни (ResetModified+Refresh)}
{Перехід від зчитаної
умови задачі максимізації чи мінімізації
задачі
максимізації-мінімізації (fs_EnteringLTask):}MakeDualLTask: Boolean;
{Розміри прочитаної
таблиці задачі:}TaskWidth:
Integer;TaskHeight: Integer;
{Запускач вирішування.
Працює у режимах fs_SolvingEqsM1,_SolvingEqsM2, fs_SolvingLTask:}Solve (ToGoToEnd: Boolean=False):Boolean;
Create;Free;;
{Визначає знак дійсного
числа:}ValSign (Const
Value:TWorkFloat):TSignVal; overload;ValSign (Const Value:TValOrName):TSignVal;
overload;
GetValOrNameAsStr (Const
Value:TValOrName):String;
ChangeSignForValOrVarName
(Var SDValOrName:TValOrName);
DeleteFromArr (Var
SArr:TValOrNameMas; Index, Count: Integer);;DeleteFromArr (Var SArr:TFloatArr;
Index, Count: Integer); overload;DelColsFromMatr (Var SDMatrix:TFloatMatrix;
ColIndex, Count: Integer);DelRowsFromMatr (Var SDMatrix:TFloatMatrix; RowIndex,
Count: Integer);
ChangeRowsPlaces (Var
SDMatr:TFloatMatrix; Row1, Row2: Integer);;ChangeRowsPlaces (Var
SDMatr:TFloatMatrix;SDHeadCol:TValOrNameMas; Row1, Row2: Integer;:
Boolean=False); overload;ChangeColsPlaces (Var SDMatr:TFloatMatrix; Col1, Col2:
Integer);;ChangeColsPlaces (Var SDMatr:TFloatMatrix;SDHeadRow:TValOrNameMas; Col1,
Col2: Integer;: Boolean=False); overload;
{Транспонування
двовимірної матриці:}Transpose
(Var SDMatrix:TFloatMatrix);
_InvCoordsOfResolvingElm=
'Немає розв''язуючого
елемента з такими координатами';_ZeroResolvingElm='Розв''язуючий елемент рівний
нулю';_MatrixSize='Розміри матриці';_NoGrowingStringGrid='GrowingStringGrid не
заданий' + sc_TriSpot;_UnknownVarType='Невідомий тип
змінної';_TableIsNotReady=': таблиця не готова' + sc_TriSpot;_WrongEditMode=':
не той режим редагування'+
' задачі. Не можу перейти
до розв''язування' + sc_TriSpot;_EmptyTable=': таблиця пуста' +
sc_TriSpot;_CantReadTaskInCurMode=
': у поточному режимі
умова задачі не зчитується';_CantWriteTaskInCurMode=
': не можу записати
умову задачі з поточного режиму'+sc_TriSpot;_CantCloseFile=': не можу закрити
файл:'+sc_DoubleQuot;
_StartSolving=': починаю
розв''язування' + sc_TriSpot;_ZeroKoef=': нульовий
коефіцієнт';_SearchingOther=' шукаю інший' + sc_TriSpot;_AllKoefIsZeroForVar=':
усі коефіцієнти є нулі для змінної';_AllKoefIsZero=': усі коефіцієнти для
потрібних змінних є нулі'+sc_TriSpot;_FreeVar=': вільна змінна (у її стовпці
лише нулі, не впливає на результат)';
_NoRoots='Коренів
немає.';_NoVals='Значень немає.';_ManyRoots='Коренів
безліч.';_UnlimitedFunc='Функція мети не обмежена.';_SolutionFound='Корені
знайдено.';_ValFound='Значення знайдено.';_SolvingStopped=': розв''язування
припинено' + sc_TriSpot;
_ExcludingFreeVars=':
виключаю незалежні змінні' + sc_TriSpot;_CantExcludeFreeVars=': не можу
виключити усі незалежні змінні.'+_Space+sc_UnlimitedFunc;_AllFreeVarsExcluded=':
усі незалежні змінні виключені.';_NoTableAreaToWork=
': Увага! У таблиці
більше немає комірок для наступної обробки'+sc_TriSpot;
_ExcludingZeroRows=':
виключаю 0-рядки' + sc_TriSpot;_AllZeroInRow=': усі елементи - нулі у
рядку';_NoMNN=': не можу знайти МНВ для стовпця';_AllZeroRowsExcluded=': усі
0-рядки виключені.';
_SearchingBaseSolve=':
шукаю опорний розв''язок' + sc_TriSpot;_BaseSolveFound=': опорний розв''язок
знайдено.';_SearchingOptimSolve=': шукаю оптимальний розв''язок' + sc_TriSpot;
_NoSolveMode=': поточний
режим не є режимом для розв''язування'+sc_TriSpot;_ValNotAvail='значення не
доступно' + sc_TriSpot;_ResultIs='Результат ';_ForDualTask='для двоїстої задачі
(відносно розв''язаної):';_ForDirectTask='для прямої задачі:';
_InHeadRow='У
рядку-заголовку:';_InHeadCol='У стовпці-заголовку:';_ResFunc='Функція мети:';
_CanMakeOnlyInELTaskMode='до
двоїстої задачі можна переходити лише у '+
'режимі
fs_EnteringLTask' + sc_TriSpot;_CanMakeDTaskOnlyForOneDFunc=': можу переходити
до двоїстої задачі ' +
'тільки від
однокритеріальної задачі ЛП (з одною функцією мети). '+
'Всього функцій мети: ';
_CantChangeStateInSolving=
': не можу міняти режим
під час розв''язування…';
_CantDetMenuItem=': не
визначено пункт меню, який викликав процедуру…';_UnknownObjectCall=': невідомий
об''єкт, який викликав процедуру: клас ';_NoCellOrNotSupported=': комірка не
підтримується або не існує: ';_Row='Рядок'; sc_Col='Стовпець';
_CantOpenFile=': не можу
відкрити файл: «';_EmptyFileOrCantRead=': файл пустий або не читається:
«';_FileNotFullOrHasWrongFormat=': файл не повний або не того формату:
«';_CantReadFile=': файл не читається: «';_CantCreateFile=': не можу створити
файл: «';_CantWriteFile=': файл не вдається записати: «';
_CurRowNotMarkedAsDestFunc=
': заданий рядок не
помічений як функція мети: рядок ';_RowNumsIsOutOfTable=': задані номери рядків
виходять за межі таблиці!..';_NoDestFuncs=': немає рядків функцій мети! Задачу
не розумію…';_OnlyDestFuncsPresent=': у таблиці всі рядки є записами функцій
мети!..';_ForDestFunc=': для функції: ';_SearchingMin='шукаю
мінімум';_SearchingMax='шукаю максимум';
_CalculatingNoOptMeasures=':
підраховую міри неоптимальності…';_AllMeasurIsZero=': усі міри рівні нулю,
додаю до них одиницю…';_UniqueMeasureCantSetZero=': є тільки одна міра
оптимальності (і одна'+
' функція мети).
Максимальна за модулем - вона ж. Додавання цієї'+
' максимальної величини
замінить її на нуль. Тому заміняю на одиницю…';
_WeightCoefs='Вагові
коефіцієнти (Li[Func]=ui/W(U)):';_ComprVarVals='Компромісні значення
змінних';_DestFuncComprVals='Компромісні значення функцій мети:';
ValSign (Const
Value:TWorkFloat):TSignVal; overload;Res1:TSignVal;:=bc_Zero;Value<0 then
Res1:=bc_Negativeif Value>0 then Res1:=bc_Positive;:=Res1;;
ValSign (Const
Value:TValOrName):TSignVal; overload;Res1:TSignVal;Value. ElmType=bc_Number
then:=ValSign (Value. AsNumber)Pos (sc_Minus, Value. AsVarName)=1 then
Res1:=bc_NegativeRes1:=bc_Positive;;:=Res1;;
GetValOrNameAsStr (Const
Value:TValOrName):String;Value. ElmType=bc_Number then:=FloatToStr (Value.
AsNumber)GetValOrNameAsStr:=Value. AsVarName;;
DeleteFromArr (Var
SArr:TValOrNameMas; Index, Count: Integer); overload;
{Процедура для видалення
з одновимірного масиву чисел чи назв змінниходного або більше елементів, починаючи
з елемента з номером Index.
Видаляється Count
елементів (якщо вони були у масиві починаючи із елемента
з номером Index).}CurElm: Integer;Count<=0 then Exit; {якщо немає елементів
для видалення}
{Якщо є хоч один елемент
із заданих для видалення:}Length(SArr)>=(Index+1)
then
{Якщо у масиві немає так
багато елементів, скільки холіли видалити, то
коригуємо кількість тих,
що видаляємо:}(Index+Count)>Length(SArr)
then Count:=Length(SArr) - Index;
{Зсуваємо елементи
масиву вліво, що залишаються справа після видалення
заданих:}CurElm:=Index to (Length(SArr) - 1-Count) do[CurElm]:=SArr
[CurElm+Count];
{Видаляємо з масиву
зайві елементи справа:}(SArr,
Length(SArr) - Count);;;
DeleteFromArr (Var
SArr:TFloatArr; Index, Count: Integer); overload;
{Процедура для видалення
з одновимірного масиву дійсних чиселодного або більше елементів, починаючи з
елемента з номером Index.
Видаляється Count
елементів (якщо вони були у масиві починаючи із елемента
з номером Index).}CurElm: Integer;Count<=0 then Exit; {якщо немає елементів
для видалення}
{Якщо є хоч один елемент
із заданих для видалення:}Length(SArr)>=(Index+1)
then
{Якщо у масиві немає так
багато елементів, скільки холіли видалити, то
коригуємо кількість тих,
що видаляємо:}(Index+Count)>Length(SArr)
then Count:=Length(SArr) - Index;
{Зсуваємо елементи
масиву вліво, що залишаються справа після видалення
заданих:}CurElm:=Index to (Length(SArr) - 1-Count) do[CurElm]:=SArr
[CurElm+Count];
{Видаляємо з масиву
зайві елементи справа:}(SArr,
Length(SArr) - Count);;;
DelColsFromMatr (Var
SDMatrix:TFloatMatrix; ColIndex, Count: Integer);
{Процедура для видалення
із матриці дійсних чиселодного або більше стовпців, починаючи зі стовпця з
номером ColIndex.
Видаляється Count
стовпців (якщо вони були у матриці починаючи зі стовпця
з номером ColIndex).}CurRow: Integer;Count<=0 then Exit; {якщо немає елементів
для видалення}
{Видаляємо елементи у
вказаних стовпцях з кожного рядка. Так
видалимо стовпці:}CurRow:=0 to (Length(SDMatrix) - 1) do(SDMatrix[CurRow], ColIndex,
Count);;;
DelRowsFromMatr (Var
SDMatrix:TFloatMatrix; RowIndex, Count: Integer);
{Процедура для видалення
із матриці дійсних чиселодного або більше рядків, починаючи з рядка з номером
RowIndex.
Видаляється Count рядків
(якщо вони були у матриці починаючи з рядка
з номером RowIndex).}CurElm: Integer;Count<=0 then Exit; {якщо немає елементів
для видалення}
{Якщо є хоч один рядок
із заданих для видалення:}Length(SDMatrix)>=(RowIndex+1)
then
{Якщо у матриці немає
так багато рядків, скільки холіли видалити, то
коригуємо кількість тих,
що видаляємо:}(RowIndex+Count)>Length(SDMatrix)
then Count:=Length(SDMatrix) - RowIndex;
{Зсуваємо рядки матриці
вгору, що залишаються знизу після видалення
заданих:}CurElm:=RowIndex to (Length(SDMatrix) - 1-Count) do[CurElm]:=SDMatrix
[CurElm+Count];
{Видаляємо з матриці
зайві рядки знизу:}(SDMatrix,
Length(SDMatrix) - Count);;;
ChangeSignForValOrVarName
(Var SDValOrName:TValOrName);
{Зміна знаку числа або
перед іменем змінної:}SDValOrName.
ElmType=bc_Number then {для числа:}. AsNumber:=-SDValOrName. AsNumber{для
рядка-назви:}Pos (sc_Minus, SDValOrName. AsVarName)=1 then(SDValOrName.
AsVarName, 1, Length (sc_Minus))SDValOrName. AsVarName:=sc_Minus+SDValOrName.
AsVarName;;;
{Жорданове виключення за
заданим розв'язувальним елементом матриці:}TGridFormattingProcs.GI (RozElmCol, RozElmRow: Integer;SDHeadRow,
SDHeadCol:TValOrNameMas; Var SDMatrix:TFloatMatrix;DColDeleted: Boolean;:
Boolean=False; {прапорець на модифіковане Жорданове виключення}:
Boolean=True):Boolean;
{Функція виконує
Жорданове виключення для елемента матриціз координатами (RozElmCol, RozElmRow).
Окрім обробки матриці,
здійснюється заміна
місцями елементів у рядку і стовпцю-заголовках
матриці (SDHeadRow,
SDHeadCol).
Вхідні дані:- номер
стовпця матриці, у якому лежить розв'язувальний елемент.
нумерація з нуля;- номер
рядка матриці, у якому лежить розв'язувальний елемент.
нумерація з нуля.
Розв'язувальний елемент
не повинен бути рівним нулю, інакше виконання
Жорданового виключення
не можливе;, SDHeadCol - рядок і стовпець-заголовки матриці.
Рядок-заголовокповинен мати не менше елементів, ніж є ширина матриці. Він
містить множники.
Стовпець-заголовок SDHeadCol повинен бути не коротшим
за висоту матриці. Він
містить праві частини рівнянь (чи нерівностей)
системи. Рівняння
полягають у тому що значення елементів
стовпця-заголовка
прирівнюються до суми добутків елементів відповідного
рядка матриці і
елементів рядка-заголовка. Елементи у цих заголовках
можуть бути числами або
рядками-іменами змінних. Якщо довжина
рядка-заголовка менша за
ширину або стовпця-заголовка менша за висоту
матриці, то частина
комірок матриці, що виходять за ці межі, буде
проігнорована;- матриця,
у якій виконується Жорданове виключення;- прапорець, що вмикає режим
модифікованого Жорданового виключення
(при ToDoMGI=True
здійснюється модифіковане, інакше - звичайне).
Модифіковане Жорданове
виключення використовується для матриці, у якій
було змінено знак
початкових елементів, і змінено знаки елементів-
множників у
рядку-заголовку. Використовується для симплекс-методу.- прапорець, що вмикає
видалення стовпця матриці із
розв'язувальним
елементом, якщо після здійснення жорданівського
виключення у
рядок-заголовок зі стовпця-заголовка записується число нуль.
Вихідні дані:, SDHeadCol
- змінені рядок та стовпець-заголовки. У них
міняються місцями
елементи, що стоять навпроти розв'язувального елемента
(у його стовпці (для
заголовка-рядка) і рядку (для заголовка-стовпця).
У заголовку-рядку такий
елемент після цього може бути видалений, якщо
він рівний нулю і
ToDelColIfZeroInHRow=True.
Тобто Жорданове
виключення змінює ролями ці елементи (виражає один
через інший у лінійних
рівняннях чи нерівностях);- матриця після виконання Жорданового виключення;-
ознака того, що при виконанні Жорданового виключення
був видалений
розв'язувальний стовпець із матриці (у його комірці
у рядку-заголовку став
був нуль).
Функція повертає ознаку
успішності виконання Жорданового виключення.
}
Var CurRow, CurCol,
RowCount, ColCount: Integer;:TValOrName;:TWorkFloat;: String;
{Визначаємо кількість
рядків і стовпців, які можна обробити:}:=Length(SDMatrix);RowCount<=0 then Begin GI:=False; Exit;
End;:=Length (SDMatrix[0]);
Length(SDHeadCol)<RowCount
then RowCount:=Length(SDHeadCol);Length(SDHeadRow)<ColCount then
ColCount:=Length(SDHeadRow);
(RowCount<=0) or
(ColCount<=0) then Begin GI:=False; Exit; End;
{Перевіряємо наявність
розв'язуючого елемента у матриці (за координатами):}(RozElmCol>(ColCount-1)) or (RozElmRow>(RowCount-1))
then:=sc_InvCoordsOfResolvingElm+': ['+IntToStr (RozElmCol+1)+';'+(RozElmRow+1)+']'+sc_CrLf+_MatrixSize+':
['+IntToStr(ColCount)+';'+IntToStr(RowCount)+']';
Self.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add(CurMessage);
(CurMessage, mtError,
[mbOk], 0);:=False; Exit;;
{Якщо розв'язуючий
елемент рівний нулю, то виконати Жорданове виключення
неможливо:}SDMatrix [RozElmRow, RozElmCol]=0 then:=sc_ZeroResolvingElm+':
['+IntToStr (RozElmCol+1)+';'+(RozElmRow+1)+']='+FloatToStr
(SDMatrix[RozElmRow, RozElmCol]);
Self.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add(CurMessage);
(CurMessage, mtError,
[mbOk], 0);:=False; Exit;;
{Виконуємо Жорданове
виключення у матриці:}
{Обробляємо усі елементи
матриці, що не належать до рядка і стовпця
розв'язуючого елемента:}CurRow:=0 to RowCount-1 doCurCol:=0 to ColCount-1 do(CurRow<>RozElmRow)
and (CurCol<>RozElmCol) then[CurRow, CurCol]:=
(SDMatrix [CurRow,
CurCol]*SDMatrix [RozElmRow, RozElmCol] -[CurRow, RozElmCol]*SDMatrix
[RozElmRow, CurCol]) /[RozElmRow, RozElmCol];;
{+1, якщо задано зробити
звичайне Жорданове виключення;
- якщо задано
модифіковане:}:=(1-2*Abs
(Ord(ToDoMGI)));
{Елементи стовпця
розв'язуючого елемента (окрім його самого)
ділимо на розв'язуючий
елемент:}CurRow:=0 to RowCount-1
doCurRow<>RozElmRow then[CurRow, RozElmCol]:=MultiplierIfMGI*SDMatrix
[CurRow, RozElmCol]/[RozElmRow, RozElmCol];
{Елементи рядка
розв'язуючого елемента (окрім його самого)
ділимо на розв'язуючий
елемент з протилежним знаком:}CurCol:=0
to ColCount-1 doCurCol<>RozElmCol then[RozElmRow,
CurCol]:=-MultiplierIfMGI*SDMatrix [RozElmRow, CurCol]/[RozElmRow, RozElmCol];
{Заміняємо розв'язуючий
елемент на обернене до нього число:}[RozElmRow,
RozElmCol]:=1/SDMatrix [RozElmRow, RozElmCol];
{Міняємо місцями
елементи рядка і стовпця-заголовків, що стоять у
стовпці і рядку
розв'язуючого елемента:}:=
SDHeadRow[RozElmCol];[RozElmCol]:=SDHeadCol[RozElmRow];[RozElmRow]:=SafeHeadElm;
{Якщо виконуємо
модиівковане Жорданове виключення, то змінюють
знаки і ці елементи, що
помінялись місцями:}ToDoMGI
then(SDHeadRow[RozElmCol]);(SDHeadCol[RozElmRow]);;
:=False;
{Якщо у рядку-заголовку
навпроти розв'язуючого елемента опинився нуль,
і задано видаляти у
такому випадку цей елемент разом із стовпцем
розв'язуючого елемента у
матриці, то видаляємо:}ToDelColIfZeroInHRow
and (SDHeadRow[RozElmCol].ElmType=bc_Number) thenSDHeadRow[RozElmCol].AsNumber=0
then(SDHeadRow, RozElmCol, 1);(SDMatrix, RozElmCol, 1);:=True;;
:=True;;
ChangeRowsPlaces (Var
SDMatr:TFloatMatrix; Row1, Row2:
Integer);;SafeCurRow:TFloatArr;:=SDMatr[Row1];[Row1]:=SDMatr[Row2];[Row2]:=SafeCurRow;;
ChangeRowsPlaces (Var
SDMatr:TFloatMatrix; Var SDHeadCol:TValOrNameMas;, Row2: Integer;
ToChangeInitPosNums: Boolean=False); overload;
{Процедура міняє місцями
рядки у таблиці зі стовпцем-заголовком.
Вхідні дані:- таблиця;-
стовпець-заголовок таблиці;, Row2 - рядки, що треба поміняти місцями;- вмикач
зміни номерів по порядку у
стовпці-заголовку. Якщо
рівний True, то рядки, що помінялися місцями,
міняються також і
позначками про номер по порядку та розміщення
як рядка чи стовпця (що
присвоювалися їм при створенні).
Вихідні дані:- таблиця;-
стовпець-заголовок таблиці.}SafeCurHeadCell:TValOrName;:=SDHeadCol[Row1];[Row1]:=SDHeadCol[Row2];[Row2]:=SafeCurHeadCell;
ToChangeInitPosNums
then[Row2].VarInitPos:=SDHeadCol[Row1].VarInitPos;[Row2].VarInitInRow:=SDHeadCol[Row1].VarInitInRow;[Row1].VarInitPos:=SafeCurHeadCell.
VarInitPos;[Row1].VarInitInRow:=SafeCurHeadCell. VarInitInRow;;
(SDMatr, Row1, Row2);;
ChangePlaces (Var
SDMas:TFloatArr; Elm1, Elm2:
Integer);SafeElm:TWorkFloat;:=SDMas[Elm1];[Elm1]:=SDMas[Elm2];[Elm2]:=SafeElm;;
ChangeColsPlaces (Var
SDMatr:TFloatMatrix; Col1, Col2: Integer);;CurRow: Integer;CurRow:=0 to
Length(SDMatr) - 1 do(SDMatr[CurRow], Col1, Col2);;
ChangeColsPlaces (Var
SDMatr:TFloatMatrix; Var SDHeadRow:TValOrNameMas;, Col2: Integer;
ToChangeInitPosNums: Boolean=False); overload;
{Процедура міняє місцями
стовпці у таблиці з рядком-заголовком.
Вхідні дані:- таблиця;-
рядок-заголовок таблиці;, Row2 - рядки, що треба поміняти місцями;- вмикач
зміни номерів по порядку у
стовпці-заголовку. Якщо
рівний True, то рядки, що помінялися місцями,
міняються також і
позначками про номер по порядку та розміщення
як рядка чи стовпця (що
присвоювалися їм при створенні).
Вихідні дані:- таблиця;-
рядок-заголовок таблиці.}SafeCurHeadCell:TValOrName;:=SDHeadRow[Col1];[Col1]:=SDHeadRow[Col2];[Col2]:=SafeCurHeadCell;
ToChangeInitPosNums
then[Col2].VarInitPos:=SDHeadRow[Col1].VarInitPos;[Col2].VarInitInRow:=SDHeadRow[Col1].VarInitInRow;[Col1].VarInitPos:=SafeCurHeadCell.
VarInitPos;[Col1].VarInitInRow:=SafeCurHeadCell. VarInitInRow;;
(SDMatr, Col1, Col2);;
TGridFormattingProcs.
WaitForNewStep (HeadColNum, HeadRowNum: Integer);
{Зупиняє хід
вирішування, відображає поточний стан таблиці, і чекає,
доки не буде
встановлений один з прапорців:. Continue, Self. GoToEnd або Self. Stop.
Якщо прапорці Self.
GoToEnd або Self. Stop вже були встановлені до
виклику цієї процедури,
то процедура не чекає встановлення прапорців.}
{Якщо процедуру
викликали, то треба почекати, доки не встановиться. Continue=True, незважаючи
на поточний стан цього прапорця:}.
Continue:=False;
{Відображаємо поточний
стан таблиці, якщо не ввімкнено режим
роботи без зупинок:}Not (Self. GoToEnd) then. WriteTableToGrid (HeadColNum,
HeadRowNum, True);
{Чекаємо підтвердження
для наступного кроку, або переривання
розв'язування:}Not (Self. Continue or Self. GoToEnd or Self. Stop) do.
ProcessMessages;;
TGridFormattingProcs.
SearchNozeroSolveCell (CurRowNum,, MaxRow, MaxCol: Integer;, HeadColNum:
Integer;: Boolean=True):Boolean;
{Пошук ненульової
розв'язувальної комірки для вирішування системи рівнянь
або при вирішуванні
задачі максимізації/мінімізації лінійної форми
симплекс-методом
(починаючи з комірки [CurRowNum, CurColNum]).}sc_CurProcName='SearchNozeroSolveCell';CurSearchRowNum,
CurSearchColNum: Integer;: String;
{Якщо комірка, що хотіли
взяти розв'язувальною, рівна нулю:}Self.
CurTable [CurRowNum, CurColNum]=0 thenSelf. CurOutConsole<>Nil then.
CurOutConsole. Lines. Add (sc_CurProcName+sc_ZeroKoef+
' ['+IntToStr
(CurColNum+1)+'; '+IntToStr (CurRowNum+1)+']'+_SearchingOther);
:=MaxRow+1;
{Шукаємо ненульову
комірку в заданій області (або в одному
її стовпці CurColNum,
якщо ToSearchInRightColsToo=False):}CurSearchColNum:=CurColNum
to MaxCol do
{Шукаємо ненульову
комірку знизу у тому ж стовпцю:}CurSearchRowNum:=CurRowNum+1
to MaxRow doSelf. CurTable [CurSearchRowNum, CurSearchColNum]<>0 then
Break;;
{Якщо немає ненульових,
то змінна вільна:}CurSearchRowNum>MaxRow
thenSelf. CurOutConsole<>Nil
then:=sc_CurProcName+sc_AllKoefIsZeroForVar;Self.
CurHeadRow[CurSearchColNum].ElmType=bc_Number then:=st1+sc_Space+(Self.
CurHeadRow[CurSearchColNum].AsNumber)st1:=st1+sc_Space+_DoubleQuot+Self.
CurHeadRow[CurSearchColNum].AsVarName+_DoubleQuot;
. CurOutConsole. Lines.
Add(st1);;
{Якщо потрібна комірка
тільки у даному стовпці (для даної змінної),
то в інших стовцях не
шукаємо:}Not(ToSearchInRightColsToo)
then Break; {For CurSearchColNum…}{Якщо знайдено ненульовий:}.
WaitForNewStep (HeadColNum, HeadRowNum);
{Якщо дано команду
перервати розв'язування:}Self.
Stop then:=True; Exit;;
{Ставимо рядок із
знайденим ненульовим замість поточного:}(Self. CurTable, Self. CurHeadCol, CurRowNum,);
{Якщо знайдена комірка у
іншому стовпці, то міняємо місцями стовпці:}CurColNum<>CurSearchColNum then(Self. CurTable, Self.
CurHeadRow, CurColNum,);
; {For CurSearchColNum:=CurColNum
to MaxCol do…};; {For CurSearchColNum:=CurColNum to MaxCol do…}
{Якщо ненульову комірку
не знайдено:}(CurSearchColNum>MaxCol)
or (CurSearchRowNum>MaxRow) thenSelf. CurOutConsole<>Nil then.
CurOutConsole. Lines. Add (sc_CurProcName+sc_AllKoefIsZero);
:=False;; {задача не
має розв'язків, або має їх безліч…};; {If Self. CurTable [CurRowNum,
CurColNum]=0 then…}:=True;;
{Вирішування системи
лінійних рівнянь способом 1:}TGridFormattingProcs.
SolveEqsWithM1: Boolean;
{Для таблиці виду:x2 x3…
xn
…}sc_CurProcName='SolveEqsWithM1';CurRowNum, CurColNum: Integer;:
String;, HeadColNum: Integer;: Boolean;
ShowResultCalc;
{Відображає записи про
обчислення значень змінних (у текстовому полі)
такого зказка:
<стовп1>=<a11>*<ряд1>
+ <a12>*<ряд2> +… + <a1n>*<рядn>;
…
<стовпm>=<am1>*<ряд1>
+ <am2>*<ряд2> +… + <amn>*<рядn>;
І підраховує значення,
якщо можливо:
<стовп1>=<значення1>;
…
<стовпm>=<значенняm>}CurRowN, CurColN: Integer; ValueAvail: Boolean;:TWorkFloat;:
String;, NoRoots: Boolean;Self. CurOutConsole<>Nil then. CurOutConsole.
Lines. Add (sc_ResultIs+sc_DoubleSpot);
:=False;
CurRowN:=0 to Length
(Self. CurHeadCol) - 1 do:=''; ValueAvail:=True; CurVal:=0;Self.
CurOutConsole<>Nil then
{<стовп i>=…:}Self. CurHeadCol[CurRowN].ElmType=bc_Number then:=st2+FloatToStr
(Self. CurHeadCol[CurRowN].AsNumber):=st2+Self. CurHeadCol[CurRowN].AsVarName;
:=st2;:=st1+sc_Space+sc_Equal+sc_Space;
{=};
CurColN:=0 to Length
(Self. CurHeadRow) - 1 do{(aij*:)Self. CurOutConsole<>Nil
then:=st1+sc_BrOp+FloatToStr (Self. CurTable [CurRowN, CurColN])+sc_Mul;
{рядj:}Self. CurHeadRow[CurColN].ElmType=bc_Number thenSelf.
CurOutConsole<>Nil then:=st1+FloatToStr (Self.
CurHeadRow[CurColN].AsNumber);
ValueAvail then
CurVal:=CurVal +. CurTable [CurRowN, CurColN]*Self. CurHeadRow[CurColN].AsNumber;Self.
CurOutConsole<>Nil then:=st1+Self.
CurHeadRow[CurColN].AsVarName;:=False;;Self. CurOutConsole<>Nil
then:=st1+sc_BrCl; {)}CurColN<>(Length (Self. CurHeadRow) - 1)
then:=st1+sc_Space+sc_Plus+sc_Space {+}st1:=st1+sc_KrKm; {;};;
Self. CurOutConsole<>Nil
then. CurOutConsole. Lines. Add(st1);:=st2;;
ValueAvail
then:=False;Self. CurHeadCol[CurRowN].ElmType=bc_Number thenSelf.
CurHeadCol[CurRowN].AsNumber<>CurVal thenNoRoots:=True; NotEqual:=True;
End;;
Self.
CurOutConsole<>Nil thenNotEqual then:=st1+sc_Space+sc_NotEqual+sc_Space {<>}st1:=st1+sc_Space+sc_Equal+sc_Space;
{=}
:=st1+FloatToStr(CurVal)+sc_KrKm;
{<стовп i><V><значення>;};Self.
CurOutConsole<>Nil then st1:=st1+sc_Space+sc_ValNotAvail;.
WasManyRoots:=True;;
Self.
CurOutConsole<>Nil then Self. CurOutConsole. Lines. Add(st1);;
NoRoots thenSelf.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add (sc_NoRoots);.
WasManyRoots:=False;if Not (Self. WasManyRoots) then Self. SolWasFound:=True;.
WasNoRoots:=NoRoots;;LStopLabel;Self. TaskWidth<=0 then {Якщо таблиця
пуста, то задача пуста:}Self. CurOutConsole<>Nil then. CurOutConsole.
Lines. Add (sc_CurProcName + sc_EmptyTable);:=False;;;
:=Self.CHeadRowNum;:=Self.CHeadColNum;
If Self.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add (sc_CurProcName +
sc_StartSolving);
:=0; {починаємо з
першого рядка}
{Проходимо по усіх
стовпцях (по усіх змінних), намагаючись брати
розв'язувальні комірки
по головній діагоналі. Якщо серед таких зустрінеться
нуль, спробуємо знайти
ненульову комірку нижче, і поміняти рядки нульової
з ненульовою, щоб
ненульова стала на головній діагоналі:}:=0;(CurColNum<Length (Self. CurHeadRow)) and
(CurRowNum<Length
(Self. CurHeadCol)) do
{Координати
розв'язувальної комірки для помітки кольором в екранній
таблиці:}. CurGridSolveCol:=CurColNum+HeadColNum+bc_LTaskColsBeforeVars;.
CurGridSolveRow:=CurRowNum+HeadRowNum+bc_LTaskRowsBeforeVars;
{Перевіряємо, чи не є
поточна комірка нулем, і при потребі шукаємо
ненульову:}Not (Self. SearchNozeroSolveCell (CurRowNum, CurColNum,(Self.
CurHeadCol) - 1, Length (Self. CurHeadRow) - 1,, HeadColNum)) then; {якщо не
знайдено…}Self. Stop then Goto LStopLabel;
(HeadColNum,
HeadRowNum);
{Якщо дано команду
перервати розв'язування:}Self.
Stop then Goto LStopLabel;
:=False;
{Обробляємо таблицю
звичайним Жордановим виключенням:}Not
(Self.GI (CurColNum, CurRowNum, Self. CurHeadRow, Self. CurHeadCol,. CurTable,
ColDeleted, False, True)) then:=False;;;
{Переходимо до
наступного рядка, так як у цьому вже виразили одну із
змінних:}(CurRowNum);Not(ColDeleted) then Inc(CurColNum);;
;
:=True;;
:Self.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add (sc_CurProcName +
sc_SolvingStopped);
:=False;;;
{Вирішування системи
лінійних рівнянь способом 2:}TGridFormattingProcs.
SolveEqsWithM2: Boolean;
{Для таблиці виду:x2 x3…
xn 1
…
}sc_CurProcName='SolveEqsWithM2';CurRowNum, CurColNum: Integer;:
String;, HeadColNum: Integer;: Boolean;
ShowResultCalc;
{Відображає записи
значень змінних (у текстовому полі)
такого зказка:
<стовп1>=<значення1>;
…
<стовпm>=<значенняm>;
та відображає
повідомлення про наявність коренів і їх визначеність.}CurRowN, CurColN: Integer;:TWorkFloat;, NoRoots, FreeRoots:
Boolean;Self. CurOutConsole<>Nil then. CurOutConsole. Lines. Add
(sc_ResultIs+sc_DoubleSpot);
NoRoots:=False;
CurRowN:=0 to Length
(Self. CurHeadCol) - 1 doSelf. CurOutConsole<>Nil then:='';
{<стовп i>=…:}Self. CurHeadCol[CurRowN].ElmType=bc_Number then:=st1+FloatToStr
(Self. CurHeadCol[CurRowN].AsNumber):=st1+Self. CurHeadCol[CurRowN].AsVarName;;
:=False;:=Self. CurTable
[CurRowN, Length (Self. CurHeadRow) - 1];Self.
CurHeadCol[CurRowN].ElmType=bc_Number thenSelf.
CurHeadCol[CurRowN].AsNumber<>CurVal thenNoRoots:=True; NotEqual:=True;
End;;
Self.
CurOutConsole<>Nil thenNotEqual then:=st1+sc_Space+sc_NotEqual+sc_Space {<>}st1:=st1+sc_Space+sc_Equal+sc_Space;
{=}
:=st1+FloatToStr(CurVal)+sc_KrKm;
{<стовп i><V><значення>;}. CurOutConsole. Lines.
Add(st1);;; {For CurRowN:=0 to Length (Self. CurHeadCol) - 1 do…}
{Переріряємо, чи
залишилися змінні у рядку-заголовку. Якщо так, то
корені вільні, і якщо
система сумісна, то їх безліч:}:=False;CurColN:=0
to Length (Self. CurHeadRow) - 1 doSelf.
CurHeadRow[CurColN].ElmType<>bc_Number thenFreeRoots:=True; Break; End;;
NoRoots thenSelf.
CurOutConsole<>Nil then Self. CurOutConsole. Lines. Add (sc_NoRoots);.
WasNoRoots:=True;if FreeRoots thenSelf. CurOutConsole<>Nil then.
CurOutConsole. Lines. Add (sc_ManyRoots);. WasManyRoots:=True;Self.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add (sc_SolutionFound);.
SolWasFound:=True;;;LStopLabel;Self. TaskWidth<=0 then {Якщо таблиця
пуста, то задача пуста:}Self. CurOutConsole<>Nil then. CurOutConsole.
Lines. Add (sc_CurProcName + sc_EmptyTable);:=False;;;
:=Self.CHeadRowNum;:=Self.CHeadColNum;
Self.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add (sc_CurProcName +
sc_StartSolving);
:=0; {починаємо з
першого рядка}
{Проходимо по усіх
стовпцях (по усіх змінних), намагаючись брати
розв'язувальні комірки
по головній діагоналі. Якщо серед таких зустрінеться
нуль, спробуємо знайти
ненульову комірку нижче, і поміняти рядки нульової
з ненульовою, щоб
ненульова стала на головній діагоналі.
При цьому останній
стовпець не беремо (у ньому вільні члени -
праві частини рівнянь):}:=0;(CurColNum<(Length (Self. CurHeadRow) - 1)) and {останній
стовпець не беремо}
(CurRowNum<Length
(Self. CurHeadCol)) do
{Координати
розв'язувальної комірки для помітки кольором в екранній
таблиці:}. CurGridSolveCol:=CurColNum+HeadColNum+bc_LTaskColsBeforeVars;.
CurGridSolveRow:=CurRowNum+HeadRowNum+bc_LTaskRowsBeforeVars;
{Перевіряємо, чи не є
поточна комірка нулем, і при потребі шукаємо
ненульову серед
коефіцієнтів, окрім стовпця вільних членів
(що є останнім):}Not (Self. SearchNozeroSolveCell (CurRowNum, CurColNum,(Self.
CurHeadCol) - 1, Length (Self. CurHeadRow) - 2,, HeadColNum)) then; {якщо не
знайдено…}Self. Stop then Goto LStopLabel;
(HeadColNum,
HeadRowNum);
{Якщо дано команду
перервати розв'язування:}Self.
Stop then Goto LStopLabel;
:=False;
{Обробляємо таблицю
звичайним Жордановим виключенням:}Not
(Self.GI (CurColNum, CurRowNum, Self. CurHeadRow, Self. CurHeadCol,. CurTable,
ColDeleted, False, True)) then:=False;;;
{Переходимо до
наступного рядка, так як у цьому вже виразили одну із
змінних:}(CurRowNum);Not(ColDeleted) then Inc(CurColNum);;
;
:=True;;
:Self.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add (sc_CurProcName +
sc_SolvingStopped);
:=False;;;
{Запускач вирішування.
Працює у режимах fs_SolvingEqsM1,_SolvingEqsM2, fs_SolvingLTask:}TGridFormattingProcs. Solve (ToGoToEnd:
Boolean=False):Boolean;sc_CurProcName='Solve';: Boolean;: String;.
InSolving:=True;. WasNoRoots:=False; Self. WasManyRoots:=False; Self.
SolWasFound:=False;
. Stop:=False; Self.
GoToEnd:=ToGoToEnd;:=False;
Self. CurFormatState
of_SolvingEqsM1: Res1:=Self. SolveEqsWithM1;_SolvingEqsM2: Res1:=Self. SolveEqsWithM2;_SolvingLTask:
Res1:=Self. SolveMultiCritLTask;
Self.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add (sc_CurProcName +
sc_NoSolveMode);;;
Self.
CurOutConsole<>Nil then:='Вирішування закінчено.';Res1 then st1:=st1+'
Успішно.' else st1:=st1+' З помилками' + sc_TriSpot;. CurOutConsole. Lines.
Add(st1);;
. InSolving:=False;
{Відображаємо таблицю
вкінці вирішування:}.
WriteTableToGrid (Self.CHeadColNum, Self.CHeadRowNum, True);:=Res1;;
TGridFormattingProcs.
Create;Create;:=False;:=False; WasNoRoots:=False;
WasManyRoots:=False;TaskPrepared:=False; EqM2TaskPrepared:=False;
LTaskPrepared:=False;
:=False; GoToEnd:=False;
Stop:=False;
:=False;:=0;
CurGridSolveRow:=0;
:=fs_NoFormatting;
:=Nil;:=Nil;:=Nil;:=Nil;:=Nil;:=Nil;:=Nil;
{SetLength (CurHeadRow,
0); SetLength (CurHeadCol, 0);(CurTable, 0);}
. CurHeadRow:=Nil;.
CurHeadCol:=Nil;. CurTable:=Nil;
. CopyHeadRow:=Nil;.
CopyHeadCol:=Nil;. CopyTable:=Nil;
:=Nil;;
TGridFormattingProcs.
Free;
{Inherited Free;} {inaccessible value;
…raised too many
consecutive exceptions:violation at address 0x00000000 read of address
0x00000000…};
TGridFormattingProcs.
GetColorByElmType
(CurType:THeadLineElmType):TColor;sc_CurProcName='GetColorByElmType';CurColor:TColor;CurType
of_IndependentVar: CurColor:=lwc_IndependentColor;_DependentVar:
CurColor:=lwc_DependentColor;_FuncVal: CurColor:=lwc_HeadColColor;_Number:
CurColor:=lwc_ValInHeadColOrRowColor;_DestFuncToMax:
CurColor:=lwc_DestFuncToMaxNameColor;_DestFuncToMin:
CurColor:=lwc_DestFuncToMinNameColor;_OtherType:Self. CurGrid<>Nil then
CurColor:=Self. CurGrid. ColorCurColor:=clWindow;Self. CurOutConsole<>Nil
then. CurOutConsole. Lines. Add
(sc_CurProcName+':'+sc_Space+_UnknownVarType+sc_Space+IntToStr
(Ord(CurType))+_Space+sc_TriSpot);:=bc_NotColored;;;:=CurColor;;
TGridFormattingProcs.
GetNameByElmType
(CurType:THeadLineElmType):String;sc_CurProcName='GetNameByElmType';CurName:
String;CurType of_IndependentVar: CurName:=sc_IndependentVar;_DependentVar:
CurName:=sc_DependentVar;_FuncVal: CurName:=sc_InequalFuncName;_Number:
CurName:=sc_ValInHeadColOrRow;_DestFuncToMax:
CurName:=sc_DestFuncToMaxName;_DestFuncToMin:
CurName:=sc_DestFuncToMinName;_OtherType: CurName:=sc_OtherType;Self.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add (sc_CurProcName+':'+sc_Space+_UnknownVarType+sc_Space+IntToStr
(Ord(CurType))+sc_Space+_TriSpot);:=sc_UnknownVarType;;;
:=CurName;;
TGridFormattingProcs.
ReadFromFile (Const SPath: String):Boolean;
{Читання умови задачі із
файла.}sc_CurProcName='ReadFromFile';CurFile:
File; CurColCount, CurRowCount, CurCol, CurRow, ControlSize:
Integer;:TTableFormatState;: String;((Self.
CurFormatState<>fs_EnteringEqs) and
(Self.
CurFormatState<>fs_EnteringLTask) and
(Self.
CurFormatState<>fs_NoFormatting) and
(Self.
CurFormatState<>fs_FreeEdit))(Self. InSolving)
then:=sc_CurProcName+sc_CantReadTaskInCurMode+sc_TriSpot;Self.
CurOutConsole<>Nil then. CurOutConsole. Lines.
Add(CurMessage);(CurMessage, mtError, [mbOk], 0);:=False; Exit;;
. AssignFile (CurFile,
SPath);. FileMode:=fmOpenRead;{Пробуємо відкрити файл:}. Reset (CurFile,
1);:=sc_CurProcName+sc_CantOpenFile+SPath+sc_DoubleQuot;Self.
CurOutConsole<>Nil then. CurOutConsole. Lines.
Add(CurMessage);(CurMessage, mtError, [mbOk], 0);:=False; Exit;;
{Пробуємо прочитати
дескриптори кількості рядків і стовпців у задачі:}. BlockRead (CurFile, CurColCount, SizeOf(CurColCount));.
BlockRead (CurFile, CurRowCount,
SizeOf(CurRowCount));:=sc_CurProcName+sc_EmptyFileOrCantRead+SPath+_DoubleQuot;Self.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add(CurMessage);(CurMessage,
mtError, [mbOk], 0);:=False; Exit;;
{Обчислюємо розмір, який
повинні займати усі дані у файлі:}:=SizeOf(CurColCount)+SizeOf(CurRowCount)+
+SizeOf (Self.
CurFormatState)+(TValOrName)*CurColCount+
SizeOf(TValOrName)*CurRowCount+(TWorkFloat)*CurColCount*CurRowCount;
{Перевіряємо, чи має
файл такий розмір:}ControlSize<>System.
FileSize(CurFile)
then:=sc_CurProcName+sc_FileNotFullOrHasWrongFormat+SPath+_DoubleQuot;Self.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add(CurMessage);(CurMessage,
mtError, [mbOk], 0);:=False; Exit;;
. BlockRead (CurFile,
GotFormatState,
SizeOf(GotFormatState));:=sc_CurProcName+sc_CantReadFile+SPath+sc_DoubleQuot;Self.
CurOutConsole<>Nil then. CurOutConsole. Lines.
Add(CurMessage);(CurMessage, mtError, [mbOk], 0);:=False; Exit;;
{Встановлюємо режим, що
був збережений у файлі разом з умовою задачі:}. TableFormatState:=GotFormatState;
{Читаємо
рядок-заголовок:}(Self. CurHeadRow,
CurColCount);CurCol:=0 to CurColCount-1 do. BlockRead (CurFile, Self.
CurHeadRow[CurCol],
SizeOf(TValOrName));:=sc_CurProcName+sc_CantReadFile+SPath+sc_DoubleQuot;Self.
CurOutConsole<>Nil then. CurOutConsole. Lines.
Add(CurMessage);(CurMessage, mtError, [mbOk], 0);:=False; Exit;;;
{Читаємо стовпець-заголовок:}(Self. CurHeadCol, CurRowCount);CurRow:=0 to CurRowCount-1 do.
BlockRead (CurFile, Self. CurHeadCol[CurRow],
SizeOf(TValOrName));:=sc_CurProcName+sc_CantReadFile+SPath+sc_DoubleQuot;Self.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add(CurMessage);(CurMessage,
mtError, [mbOk], 0);:=False; Exit;;;
{Читаємо таблицю
коефіцієнтів і вільних членів:}(Self.
CurTable, CurRowCount, CurColCount);CurRow:=0 to CurRowCount-1 doCurCol:=0 to
CurColCount-1 do. BlockRead (CurFile, Self. CurTable [CurRow, CurCol],(TWorkFloat));:=sc_CurProcName+sc_CantReadFile+SPath+sc_DoubleQuot;Self.
CurOutConsole<>Nil then. CurOutConsole. Lines.
Add(CurMessage);(CurMessage, mtError, [mbOk], 0);:=False; Exit;;;;
.
Close(CurFile);:=sc_CurProcName + sc_CantCloseFile + SPath + sc_DoubleQuot;Self.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add(CurMessage);;
.
CurGridModified:=False;
. Refresh;
{Відмічаємо, що
прочитана умова задачі не підготована ще до вирішування
жодним із методів
вирішування:}.
EqM1TaskPrepared:=False;. EqM2TaskPrepared:=False;.LTaskPrepared:=False;
:=True;;
TGridFormattingProcs.
SaveToFile (Const SPath: String):Boolean;
{Запис умови задачі у
файл.}sc_CurProcName='SaveToFile';CurFile:
File; CurColCount, CurRowCount, CurCol, CurRow: Integer;: String;((Self. CurFormatState<>fs_EnteringEqs)
and
(Self.
CurFormatState<>fs_EnteringLTask) and
(Self.
CurFormatState<>fs_FreeEdit))(Self. InSolving)
then:=sc_CurProcName+sc_CantWriteTaskInCurMode;Self. CurOutConsole<>Nil
then. CurOutConsole. Lines. Add(CurMessage);(CurMessage, mtError, [mbOk],
0);:=False; Exit;;
{Якщо таблиця
модифікована, умова не прочитана з неї, то читаємо:}Self. CurGridModified thenNot (Self. GetTask(True)) then:=False;
Exit;;;
. AssignFile (CurFile,
SPath);. FileMode:=fmOpenWrite;{Пробуємо створити новий файл:}. Rewrite
(CurFile, 1);:=sc_CurProcName+sc_CantCreateFile+SPath+sc_DoubleQuot;Self.
CurOutConsole<>Nil then. CurOutConsole. Lines.
Add(CurMessage);(CurMessage, mtError, [mbOk], 0);:=False; Exit;;
. GetTaskSizes
(CurColCount, CurRowCount);
{Пробуємо прочитати
дескриптори кількості рядків і стовпців у задачі:}. BlockWrite (CurFile, CurColCount, SizeOf(CurColCount));.
BlockWrite (CurFile, CurRowCount, SizeOf(CurRowCount));. BlockWrite (CurFile,
Self. CurFormatState,(Self. CurFormatState));:=sc_CurProcName+sc_CantWriteFile+SPath+sc_DoubleQuot;Self.
CurOutConsole<>Nil then. CurOutConsole. Lines.
Add(CurMessage);(CurMessage, mtError, [mbOk], 0);:=False; Exit;;
{Записуємо
рядок-заголовок:}CurCol:=0 to
CurColCount-1 do. BlockWrite (CurFile, Self. CurHeadRow[CurCol],
SizeOf(TValOrName));:=sc_CurProcName+sc_CantWriteFile+SPath+sc_DoubleQuot;Self.
CurOutConsole<>Nil then. CurOutConsole. Lines.
Add(CurMessage);(CurMessage, mtError, [mbOk], 0);:=False; Exit;;;
{Записуємо
стовпець-заголовок:}CurRow:=0
to CurRowCount-1 do. BlockWrite (CurFile, Self. CurHeadCol[CurRow],
SizeOf(TValOrName));:=sc_CurProcName+sc_CantWriteFile+SPath+sc_DoubleQuot;Self.
CurOutConsole<>Nil then. CurOutConsole. Lines.
Add(CurMessage);(CurMessage, mtError, [mbOk], 0);:=False; Exit;;;
{Записуємо таблицю
коефіцієнтів і вільних членів:}CurRow:=0
to CurRowCount-1 doCurCol:=0 to CurColCount-1 do. BlockWrite (CurFile, Self.
CurTable [CurRow,
CurCol],(TWorkFloat));:=sc_CurProcName+sc_CantWriteFile+SPath+sc_DoubleQuot;Self.
CurOutConsole<>Nil then. CurOutConsole. Lines.
Add(CurMessage);(CurMessage, mtError, [mbOk], 0);:=False; Exit;;;;
:=True;;
TGridFormattingProcs.
SetTable (Const SHeadRow, SHeadCol:TValOrNameMas;STable:TFloatMatrix);
{Задає нову таблицю і
загноловки (що могли бути сформовані поза об'єктом):}. CurTable:=STable;. CurHeadRow:=SHeadRow;. CurHeadCol:=SHeadCol;
. TaskWidth; {перевіряємо
розміри нової таблиці і її заголовків};
TGridFormattingProcs.
GetTable (Var DHeadRow, DHeadCol:TValOrNameMas;DTable:TFloatMatrix);
{Повертає посилання на
таблицю і її заголовки.}:=Self.
CurTable;:=Self. CurHeadRow;:=Self. CurHeadCol;;TGridFormattingProcs.
ReadHeadRowCell (SCol: Integer);
{Зчитує комірку з
екранної таблиці в рядок-заголовок.
Вхідні дані:- номер
комірки у рядку-заголовку.
Для екранної таблиці
використовуються координати комірки відповідно до
координат
рядка-заголовка та стовпця заголовка (верхнього лівого кута
таблиці з заголовками):
HeadColNumInGrid і HeadRowNumInGrid.}CurFloatVal:TWorkFloat;
CurElmType:THeadLineElmType;:=CurHeadRow[SCol].ElmType;:=0;{Пробуємо
розпізнати число:}:=StrToFloat (CurGrid. Cells
[SCol+bc_LTaskColsBeforeVars+.CHeadColNum, Self.CHeadRowNum]);:=bc_Number; {якщо
число розпізналося, то це число}{Якщо рядок не інтерпретується як число, але
під час редагування
була зроблена помітка
про те, що це є число або функція, то вважаємо
його назвою незалежної
змінної (бо всі функції в умові задачі мають
бути в
стовпці-заголовку, а не в рядку):}(CurElmType<>bc_IndependentVar)
and (CurElmType<>bc_DependentVar) then:=bc_IndependentVar;; {Виправлений
тип елемента:}[SCol].ElmType:=CurElmType;CurElmType=bc_Number then {записуємо
число, якщо розпізналося:}[SCol].AsNumber:=CurFloatVal{якщо число не
розпізналося, то записуємо як назву змінної:}CurHeadRow[SCol] do:=CurGrid.
Cells [SCol+bc_LTaskColsBeforeVars+Self.CHeadColNum,.CHeadRowNum]; {назва}:=SCol;
{номер п/п у рядку в умові задачі}:=True; {ознака, що змінна спочатку
була у рядку-заголовку};;;
TGridFormattingProcs.
ReadHeadColCell (SRow: Integer);
{Зчитує комірку з
екранної таблиці в стовпець-заголовок.
Вхідні дані:- номер
комірки у стовпці-заголовку.
Для екранної таблиці
використовуються координати комірки відповідно до
координат
рядка-заголовка та стовпця заголовка (верхнього лівого кута
таблиці з заголовками):
HeadColNumInGrid і HeadRowNumInGrid.}CurFloatVal:TWorkFloat;
CurElmType:THeadLineElmType;:=CurHeadCol[SRow].ElmType;:=0;{Пробуємо
розпізнати число:}:=StrToFloat (CurGrid. Cells
[Self.CHeadColNum,+bc_LTaskRowsBeforeVars+Self.CHeadRowNum]);:=bc_Number; {якщо
число розпізналося, то це число}{Якщо рядок не інтерпретується як число, але комірка
вважалася
такою, що містить число
або змінну, то вважаємо його назвою функції
(бо це не число, і не
повинно бути змінною - усі змінні спочатку
у рядку-заголовку):}(CurElmType<>bc_FuncVal) and
(CurElmType<>bc_DestFuncToMax) and
(CurElmType<>bc_DestFuncToMin)
then:=bc_FuncVal;; {Виправлений тип елемента:}[SRow].ElmType:=CurElmType;CurElmType=bc_Number
then {записуємо число, якщо розпізналося:}[SRow].AsNumber:=CurFloatVal{якщо
число не розпізналося, то записуємо як назву змінної:}CurHeadCol[SRow]
do:=CurGrid. Cells [Self.CHeadColNum,+bc_LTaskRowsBeforeVars+Self.CHeadRowNum];
{назва}:=SRow; {номер п/п у стовпці в умові задачі}
{Ознака, що змінна
спочатку була у стовпці-заголовку:}:=False;;;;
TGridFormattingProcs.
ReadTableFromGrid: Boolean;sc_CurProcName='ReadTableFromGrid';
{Процедура для
зчитування таблиці та її заголовків із CurGrid.
Для екранної таблиці
використовуються координати рядка-заголовка та
стовпця заголовка
(верхнього лівого кута таблиці з заголовками):(CHeadColNum) і HeadRowNumInGrid
(CHeadRowNum).}CurRow, CurCol,
CurWidth, CurHeight: Integer;:TWorkFloat;Self. CurGrid=Nil thenSelf.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add (sc_CurProcName+
':
'+sc_NoGrowingStringGrid);:=False;;;
{Ширина і висота таблиці
з заголовками:}:=Self. CurGrid.
ColCount-Self.CHeadColNum-bc_LTaskColsBeforeVars;:=Self. CurGrid.
RowCount-Self.CHeadRowNum-bc_LTaskRowsBeforeVars;
(CurHeight<=0) or
(CurWidth<=0) thenSelf. CurOutConsole<>Nil then. CurOutConsole. Lines.
Add (sc_CurProcName+
': починаючи з комірки
['+IntToStr (Self.CHeadColNum+1)+'; '+(Self.CHeadRowNum+1)+'] таблиці не
знайдено' + sc_TriSpot);:=False;;;
{Виділяємо пам'ять:}(Self. CurHeadRow, CurWidth); {рядок-заголовок}(Self.
CurHeadCol, CurHeight); {стовпець-заголовок}(Self. CurTable, CurHeight,
CurWidth); {таблиця}
{Читаємо
рядок-заголовок:}CurCol:=0 to
CurWidth-1 do ReadHeadRowCell(CurCol);
{Читаємо
стовпець-заголовок:}CurRow:=0
to CurHeight-1 do ReadHeadColCell(CurRow);
{Читаємо таблицю
коефіцієнтів:}CurRow:=Self.CHeadRowNum+bc_LTaskRowsBeforeVars
to. CurGrid. RowCount-1 doCurCol:=Self.CHeadColNum+bc_LTaskColsBeforeVars to.
CurGrid. ColCount-1 do{Пробуємо інтерпретувати рядок із комірки як число:}:=StrToFloat
(CurGrid. Cells [CurCol, CurRow]);{Якщо не вдалося, то вважаємо це число нулем:}:=0;;.
CurTable
[CurRow-bc_LTaskRowsBeforeVars-Self.CHeadRowNum,bc_LTaskColsBeforeVars-Self.CHeadColNum]:=CurFloatVal;;;
{Після читання зміни в
екранній таблиці враховані:}.
CurGridModified:=False;:=True;;
TGridFormattingProcs.
WriteTableToGrid (SHeadColNum,: Integer; ToTuneColWidth: Boolean=True):Boolean;
{Процедура для
відображення таблиці та її заголовків у CurGrid.}sc_CurProcName='WriteTableToGrid';CurRow, CurCol, CurWidth,
CurHeight: Integer;:THeadLineElmType;Self. CurGrid=Nil thenSelf. CurOutConsole<>Nil
then. CurOutConsole. Lines. Add (sc_CurProcName+
': GrowingStringGrid не
заданий!..');:=True;;;
{Ширина і висота
таблиці:}. GetTaskSizes
(CurWidth, CurHeight);
(CurHeight<=0) or
(CurWidth<=0) thenSelf. CurOutConsole<>Nil then. CurOutConsole. Lines.
Add (sc_CurProcName+sc_EmptyTable);:=False;;;
{Виділяємо комірки для
таблиці у екранному CurGrid:}.
CurGrid. ColCount:=CurWidth+SHeadColNum+1;. CurGrid.
RowCount:=CurHeight+SHeadRowNum+1;
{Відображаємо
рядок-заголовок:}CurCol:=SHeadColNum+1
to Self. CurGrid. ColCount-1 do:=CurHeadRow [CurCol-1-SHeadColNum].ElmType;
CurElmType=bc_Number
then {записуємо число, якщо є числом:}. Cells [CurCol,
SHeadRowNum]:=(CurHeadRow[CurCol-1-SHeadColNum].AsNumber){Якщо це не число,
то це рядок з якоюсь назвою. Записуємо:}. CurGrid. Cells [CurCol,
SHeadRowNum]:=[CurCol-1-SHeadColNum].AsVarName;;
{Відображаємо
стовпець-заголовок:}CurRow:=SHeadRowNum+1
to Self. CurGrid. RowCount-1 do:=CurHeadCol [CurRow-1-SHeadRowNum].ElmType;
CurElmType=bc_Number
then {записуємо число, якщо є числом:}. Cells [SHeadColNum,
CurRow]:=(CurHeadCol[CurRow-1-SHeadRowNum].AsNumber){Якщо це не число, то це
рядок з якоюсь назвою. Записуємо:}. CurGrid. Cells [SHeadColNum,
CurRow]:=[CurRow-1-SHeadRowNum].AsVarName;;
{Відображаємо таблицю
коефіцієнтів:}CurRow:=SHeadRowNum+1
to Self. CurGrid. RowCount-1 doCurCol:=SHeadColNum+1 to Self. CurGrid.
ColCount-1 do. Cells [CurCol, CurRow]:=(Self. CurTable [CurRow-1-SHeadRowNum,
CurCol-1-SHeadColNum]);;
{Комірка на перехресті
заголовків пуста:}(SHeadRowNum<Self.
CurGrid. RowCount) and
(SHeadColNum<Self.
CurGrid. ColCount) then. Cells [SHeadColNum, SHeadRowNum]:='';
{Після запису в екранну
таблицю: зміни, що могли бути у ній, вважаємо
затертими:}. CurGridModified:=False;
{Якщо задано, настроюємо
ширини стовпців по довжині тексту у комірках:}ToTuneColWidth then Self. CurGrid. TuneColWidth;
:=True;;
TGridFormattingProcs.
GetTaskSizes (Var DWidth, DHeight: Integer);
{Визначення розмірів
таблиці задачі, і корегування довжини заголовків
таблиці та зовнішнього
масиву таблиці (масиву масивів).}:=Length
(Self. CurTable);
DHeight>0
then:=Length (Self. CurTable[0])DWidth:=0;DWidth=0 then DHeight:=0;
DWidth>Length (Self.
CurHeadRow) then:=Length (Self. CurHeadRow);
DHeight>Length (Self.
CurHeadCol) then:=Length (Self. CurHeadCol);
{Якщо комірок немає,
то:}DWidth=0 then
{Зовнійшій масив
встановлюємо у нульову довжину:}(Self.
CurTable, 0);
{Заголовки теж:}(Self. CurHeadRow, 0);(Self. CurHeadCol, 0);;;
{Розміри прочитаної
таблиці задачі:}TGridFormattingProcs.
TaskWidth: Integer;CurWidth, CurHeight: Integer;. GetTaskSizes (CurWidth,
CurHeight);:=CurWidth;;
TGridFormattingProcs.
TaskHeight: Integer;CurWidth, CurHeight: Integer;. GetTaskSizes (CurWidth,
CurHeight);:=CurHeight;;
TGridFormattingProcs.
GetTask (ToPrepareGrid: Boolean=True):Boolean;
{Зчитування умови задачі
із CurGrid та відображення прочитаного
на тому ж місці, де воно
було. Працює у режимах_EnteringEqs і fs_EnteringLTask.}sc_CurProcName='GetTask';Res1: Boolean;DoGetTask;ToPrepareGrid
then. ShrinkToFilled (Self.CHeadColNum+1, Self.CHeadRowNum+1);
{Читаємо комірки
таблиці:}:=Self.
ReadTableFromGrid;
{Відображаємо те, що
вийшло прочитати, у тих самих комірках на екрані:}Not (Self. WriteTableToGrid (Self.CHeadColNum, Self.CHeadRowNum))
then:=False;;Self. CurGrid=Nil thenSelf. CurOutConsole<>Nil then.
CurOutConsole. Lines. Add (sc_CurProcName+':
'+sc_NoGrowingStringGrid);:=False;;;
Self. CurFormatState
of_EnteringEqs: {режим редагування системи лінійних рівнянь:}
{Зчитуємо таблицю. Як
рядок-заголовок зчитуємо автоматично
сформовані назви змінних
x1…xn та множник вільних членів (1).
Як стовпець-заголовок
зчитуємо стовпець нумерації.
При переході до режиму
вирішування задачі у цей стовпець
будуть скопійовані
вільні члени (режим способу 1, fs_SolvingEqsM1),
або нулі (режим способу
2, fs_SolvingEqsM2):};
Not(Res1) then Begin
GetTask:=False; Exit; End;;_EnteringLTask: {режим редагування форми задачі
лінійного програмування:}
{Зчитуємо таблицю умови
для задачі ЛП максимізації або
мінімізації лінійної
форми (функції з умовами-нерівностями,
рівняннями та
обмеженнями невід'ємності, імена змінних, нерівностей,
функцій):};
Not(Res1) then Begin
GetTask:=False; Exit; End;;_FreeEdit: {режим вільного редагування:}
{Читаємо таблицю, рядок-заголовок,
стовпець-заголовок:};
Not(Res1) then Begin
GetTask:=False; Exit; End;;{інші режими:}Self. CurOutConsole<>Nil
then. CurOutConsole. Lines. Add (sc_CurProcName + sc_CantReadTaskInCurMode
+
sc_TriSpot);:=False;;;;
{If ToPrepareGrid then
CurGrid. TuneColWidth;}
.
EqM1TaskPrepared:=False;.
EqM2TaskPrepared:=False;.LTaskPrepared:=False;:=True;;
TGridFormattingProcs.
Refresh;sc_CurProcName='Refresh';Res1: Boolean;Self.
CurFormatState<>fs_NoFormatting thenSelf. CurGrid=Nil thenSelf.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add (sc_CurProcName+':
'+_NoGrowingStringGrid);;;
:=False;
{Якщо таблиця редагована
або ще не читана, то запускаємо її зчитування:}Self. CurGridModified or (Self. TaskWidth<=0) then Res1:=Self.
GetTask;
Not(Res1) then {Якщо
таблиця не була віджображена у GetTask, відображаємо:}. WriteTableToGrid
(Self.CHeadColNum, Self.CHeadRowNum);;;
TGridFormattingProcs.
ResetModified; {скидає прапорець зміненого стану}.
CurGridModified:=False;;
TGridFormattingProcs.
UndoChanges;
{Відкидає останні зміни
(ResetModified+Refresh).}.
ResetModified; Self. Refresh;;
Transpose (Var
SDMatrix:TFloatMatrix);
{Транспонування
двовимірної матриці.}CurCol,
CurRow, CurWidth, CurHeight:
Integer;:TWorkFloat;:=Length(SDMatrix);CurHeight>0 then CurWidth:=Length
(SDMatrix[0])CurWidth:=0;
(CurHeight=0) or
(CurWidth=0) then Exit;
{Збільшуємо розміри
матриці до квадратних:}CurWidth>CurHeight
then {Якщо ширина була більша за висоту:}(SDMatrix, CurWidth, CurWidth);
{збільшуємо висоту}if CurWidth<CurHeight then {Якщо висота була
більша за ширину:}(SDMatrix, CurHeight, CurHeight); {збільшуємо ширину};
{Міняємо елементи
місцями: рядки будуть стовпцями, а стовпці - рядками:}CurRow:=0 to Length(SDMatrix) - 1 doCurCol:=CurRow + 1 to Length
(SDMatrix[CurRow]) - 1 do:=SDMatrix [CurRow, CurCol];[CurRow, CurCol]:=SDMatrix
[CurCol, CurRow];[CurCol, CurRow]:=SafeElm;;;
{Ширина тепер буде така
як була висота, а висота - як була ширина:}(SDMatrix, CurWidth, CurHeight);;
TGridFormattingProcs.
MakeDualLTask: Boolean;
{Перехід від зчитаної
умови задачі максимізації чи мінімізації
лінійної форми до
двоїстої задачі. Працює у режимі редагування
задачі
максимізації-мінімізації (fs_EnteringLTask).
За правилом двоїсту
задачу потрібно мінімізувати, якщо для прямої
потрібно було знайти
максимум, і максимізувати, якщо для прямої потрібно
було знайти мінімум.
}sc_CurProcName='MakeDualLTask';SafeMas:TValOrNameMas; CurCol,
CurRow, DFuncCount: Integer;:TDualTaskType; NewDFuncType,
OldDFuncType:THeadLineElmType;:=Nil;Self. CurFormatState<>fs_EnteringLTask
thenSelf. CurOutConsole<>Nil then. CurOutConsole. Lines. Add
(sc_CurProcName+sc_CanMakeOnlyInELTaskMode);:=False; Exit;;
Self. CurGridModified
thenNot (Self. GetTask(True)) then:=False; Exit;;;
Self. TaskHeight<=0
then {Якщо таблиця пуста:}Self. CurOutConsole<>Nil then.
CurOutConsole. Lines. Add (sc_CurProcName+sc_EmptyTable);:=False; Exit;;
{Перевіряємо, чи функція
мети лише одна, і визначаємо її тип
(для максимізації чи
мінімізації):}:=0;
DualTType:=dt_MaxToMin; OldDFuncType:=bc_DestFuncToMax;CurRow:=0 to Length
(Self. CurHeadCol) - 1 doSelf. CurHeadCol[CurRow].ElmType=bc_DestFuncToMax
then:=dt_MaxToMin;:=Self. CurHeadCol[CurRow].ElmType;(DFuncCount);if Self.
CurHeadCol[CurRow].ElmType=bc_DestFuncToMin then:=dt_MinToMax;:=Self.
CurHeadCol[CurRow].ElmType;(DFuncCount);;;
{Якщо функцій мети
декілька або жодної:}DFuncCount<>1
thenSelf. CurOutConsole<>Nil then. CurOutConsole. Lines. Add
(sc_CurProcName+_CanMakeDTaskOnlyForOneDFunc+IntToStr(DFuncCount));:=False;
Exit;;
DualTType=dt_MaxToMin
then NewDFuncType:=bc_DestFuncToMinNewDFuncType:=bc_DestFuncToMax;
{Зсуваємо рядок функції
мети вниз таблиці. При цьому позначки порядку
рядків залишаємо на тих
самих місцях (і присвоюємо тим рядкам, які
стають на ці місця):}. ShiftRowsDown([bc_DestFuncToMax, bc_DestFuncToMin], True);
(Self. CurTable); {транспонуємо
таблицю коефіцієнтів}
{Обробляємо заголовки
таблиці у відповідність до двоїстої задачі:}
{Для рядка-заголовка, що
стане стовпцем-заголовком:}CurCol:=0
to Length (Self. CurHeadRow) - 1 do{Проходимо по усіх змінних і останньому
елементу -
множнику стовпця вільних
членів - одиниці:}Self.
CurHeadRow[CurCol].ElmType=bc_DependentVar then {Якщо змінна >=0:}{Ця
комірка буде заголовком функції умови-нерівності зі знаком «>=»:}.
CurHeadRow[CurCol].ElmType:=bc_FuncVal;.
CurHeadRow[CurCol].VarInitInRow:=False;
{Формуємо назву
функції:}
{якщо змінна має назву
змінної двоїстої задачі, то дамо назву
функції прямої задачі,
якщо назва прямої - назву двоїстої:}Pos
(sc_DualTaskVarNameStart, Self. CurHeadRow[CurCol].AsVarName)>0 then.
CurHeadRow[CurCol].AsVarName:=sc_YFuncName + IntToStr (CurCol+1)Self.
CurHeadRow[CurCol].AsVarName:=sc_DualTaskFuncNameStart +(CurCol+1);
{Якщо переходимо від
задачі максимізації до двоїстої задачі
мінімізації, то для
нерівності треба буде змінити знак «>=» на «<=»,
(якщо для змінної була
умова «>=0», і заголовок для неї був додатний),
тому змінюємо знак
заголовка:}DualTType=dt_MaxToMin
then(Self. CurHeadRow[CurCol]);{Якщо змінна вільна:}if Self.
CurHeadRow[CurCol].ElmType=bc_IndependentVar then{Ця комірка буде заголовком
умови-рівняння:}. CurHeadRow[CurCol].ElmType:=bc_Number;.
CurHeadRow[CurCol].AsNumber:=0;{Якщо це число:}if Self.
CurHeadRow[CurCol].ElmType=bc_Number thenSelf. CurHeadRow[CurCol].AsNumber=1 then
{якщо це множник вільних членів}.
CurHeadRow[CurCol].ElmType:=NewDFuncType;.
CurHeadRow[CurCol].VarInitInRow:=False;
{Формуємо назву функції
мети двоїстої задачі
(залежно від назви
функції мети поданої задачі):}Pos
(sc_DualDestFuncHdr,. CurHeadCol [Length(Self. CurHeadCol) - 1].AsVarName)>0
then. CurHeadRow[CurCol].AsVarName:=sc_DestFuncHdrSelf.
CurHeadRow[CurCol].AsVarName:=sc_DualDestFuncHdr;;;;
{Для стовпця-заголовка,
що стане рядком-заголовком:}CurRow:=0
to Length (Self. CurHeadCol) - 1 do
{Проходимо по усіх
елементах-заголовках рядків, і останньому елементу -
заголовку рядка функції
мети:}Self.
CurHeadCol[CurRow].ElmType=bc_FuncVal then {Якщо нерівність «<=»:}.
CurHeadCol[CurRow].ElmType:=bc_DependentVar; {буде змінна >=0}.
CurHeadCol[CurRow].VarInitInRow:=True;
{Формуємо назву змінної:
якщо функція-нерівність
має назву функції двоїстої задачі, то
дамо назву змінної
прямої задачі, якщо назва прямої - назву двоїстої:}Pos (sc_DualTaskFuncNameStart, CurHeadCol[CurRow].AsVarName)>0
then. CurHeadCol[CurRow].AsVarName:=sc_XVarName + IntToStr (CurRow+1)Self.
CurHeadCol[CurRow].AsVarName:=sc_DualTaskVarNameStart +(CurRow+1);
{Якщо переходимо від
задачі мінімізації до двоїстої задачі
максимізації, то для
змінної треба буде змінити знак і умову «<=0»
на «>=0», (якщо для
нерівність була зі знаком «<=», і заголовок для
неї був додатний), тому
змінюємо знак заголовка:}DualTType=dt_MinToMax
then(Self. CurHeadCol[CurRow]);if Self. CurHeadCol[CurRow].ElmType=bc_Number
thenSelf. CurHeadCol[CurRow].AsNumber=0 then {Якщо 0, заголовок рівняння:}.
CurHeadCol[CurRow].ElmType:=bc_IndependentVar;.
CurHeadCol[CurRow].VarInitInRow:=True;
{Формуємо назву змінної
двоїстої задачі
(залежно від назви
функції мети поданої задачі):}Pos
(sc_DualDestFuncHdr,. CurHeadCol [Length(Self. CurHeadCol) - 1].AsVarName)>0
then. CurHeadCol[CurRow].AsVarName:=sc_XVarName+IntToStr (CurRow+1)Self.
CurHeadCol[CurRow].AsVarName:=sc_DualTaskVarNameStart+(CurRow+1);;{Якщо
заголовок рядка функції мети:}if Self. CurHeadCol[CurRow].ElmType=OldDFuncType
then. CurHeadCol[CurRow].ElmType:=bc_Number;. CurHeadCol[CurRow].AsNumber:=1; {буде
множник стовпця вільних членів};;
{Міняємо рядок і
стовпець-заголовки таблиці місцями:}:=Self.
CurHeadRow;. CurHeadRow:=Self. CurHeadCol;. CurHeadCol:=SafeMas;
{У новому
стовпці-заголовку шукаємо комірки-заголовки нерівностей «>=».
Їх заміняємо на «<=»
множенням рядка на -1:}CurRow:=0
to Length (Self. CurHeadCol) - 1 doSelf. CurHeadCol[CurRow].ElmType=bc_FuncVal
thenValSign (Self. CurHeadCol[CurRow])=bc_Negative then.
ChangeSignsInRow(CurRow);;;
{У новому
рядку-заголовку шукаємо комірки-заголовки залежних змінних,
які мають умову
«<=0». Змінюємо цю умову на «>=0» множенням стовпця на -1:}CurCol:=0 to Length (Self. CurHeadRow) - 1 doSelf.
CurHeadRow[CurCol].ElmType=bc_DependentVar thenValSign (Self.
CurHeadRow[CurCol])=bc_Negative then. ChangeSignsInCol(CurCol);;;
{Відображаємо отриману
таблицю у екранній таблиці:}.
WriteTableToGrid (Self.CHeadColNum, Self.CHeadRowNum);
MakeDualLTask:=True;;
TGridFormattingProcs.
PrepareToSolveEqsWithM1:
Boolean;sc_CurProcName='PrepareToSolveEqsWithM1';CurRow, ColToDel:
Integer;(Self. CurFormatState=fs_EnteringEqs) or
(Self.
CurFormatState=fs_NoFormatting) then
{Якщо таблиця не
зчитана, то читаємо:}(Self.
CurGridModified) and (Self. CurFormatState=fs_EnteringEqs) thenNot (Self.
GetTask) then:=False; Exit;;;
Self. TaskHeight<=0
then {Якщо таблиця пуста:}Self. CurOutConsole<>Nil then.
CurOutConsole. Lines. Add (sc_CurProcName+sc_EmptyTable);:=False;;;
Not (Self.
EqM1TaskPrepared) then
{Копіюємо стовпець
вільних членів (правих частин рівнянь) із
останнього стовпця
таблиці до стовпця-заголовка:}CurRow:=0
to Length (Self. CurHeadCol) - 1 do. CurHeadCol[CurRow].ElmType:=bc_Number;.
CurHeadCol[CurRow].AsNumber:=. CurTable [CurRow, Length (CurTable[CurRow]) -
1];;
{Видаляємо цей останній
стовпець із таблиці:}:=Length
(Self. CurTable[0]) - 1;(Self. CurTable, ColToDel, 1);(Self. CurHeadRow,
ColToDel, 1);;
{Позиціювання
відображення таблиці у даному режимі вирішування:}.CHeadColNum:=CurGrid. FixedCols;.CHeadRowNum:=CurGrid.
FixedRows-1;
{Відображаємо таблицю,
що підготована для розв'язування:}.
WriteTableToGrid (Self.CHeadColNum, Self.CHeadRowNum);
{Якщо таблиця пуста
після перенесення останнього стовпця у
стовпець-заголовок:}Self. TaskHeight<=0 then:=False;;;
.
EqM1TaskPrepared:=True;:=True;Self. CurOutConsole<>Nil then.
CurOutConsole. Lines. Add (sc_CurProcName+sc_WrongEditMode);:=False;;;
TGridFormattingProcs.
PrepareToSolveEqsWithM2: Boolean;sc_CurProcName='PrepareToSolveEqsWithM2';CurRow:
Integer;(Self. CurFormatState=fs_EnteringEqs) or
(Self.
CurFormatState=fs_NoFormatting) then{Якщо таблиця не зчитана, то читаємо:}(Self.
CurGridModified) and (Self. CurFormatState=fs_EnteringEqs) thenNot (Self.
GetTask) then:=False; Exit;;;
Self. TaskHeight<=0
then {Якщо таблиця пуста:}Self. CurOutConsole<>Nil then.
CurOutConsole. Lines. Add (sc_CurProcName+sc_TableIsNotReady);:=False;
Exit;;Not (Self. EqM2TaskPrepared) thenCurRow:=0 to Length (Self. CurHeadCol) -
1 do
{Заповнюємо стовпець-заголовок
нулями:}.
CurHeadCol[CurRow].ElmType:=bc_Number;. CurHeadCol[CurRow].AsNumber:=0;
{Змінюємо знаки у
останньому стовпці таблиці - стовпці вільних
членів. Так як вони у
правих частинах рівнянь, то знаходячись у
таблиці коефіцієнтів
лівих частин, повинні бути з протилежними
знаками:}. CurTable [CurRow, Length (CurTable[CurRow]) - 1]:=
Self. CurTable [CurRow,
Length (CurTable[CurRow]) - 1];;;
{Позиціювання
відображення таблиці у даному режимі вирішування:}.CHeadColNum:=CurGrid. FixedCols;.CHeadRowNum:=CurGrid.
FixedRows-1;
{Відображаємо таюдицю,
що підготована для розв'язування:}.
WriteTableToGrid (Self.CHeadColNum, Self.CHeadRowNum);
.
EqM2TaskPrepared:=True;:=True;Self. CurOutConsole<>Nil then.
CurOutConsole. Lines. Add (sc_CurProcName+sc_WrongEditMode);:=False;;;
{TTableFormatState=(fs_EnteringEqs,
fs_EnteringLTask, fs_SolvingEqsM1,_SolvingEqsM2, fs_SolvingLTask,_NoFormatting,
fs_FreeEdit);}
TGridFormattingProcs.
PrepareToSolveLTask: Boolean;sc_CurProcName='PrepareToSolveLTask';(Self.
CurFormatState=fs_EnteringLTask) or
(Self.
CurFormatState=fs_NoFormatting) then{Якщо таблиця у режимі редагування
задачі, і модифікована, то зчитуємо:}(Self. CurGridModified) and (Self.
CurFormatState=fs_EnteringLTask) thenNot (Self. GetTask) then {зчитуємо
таблицю (умову) з екранної таблиці}:=False; Exit;;;
Self. TaskHeight<=0
then {Якщо таблиця пуста:}Self. CurOutConsole<>Nil then.
CurOutConsole. Lines. Add (sc_CurProcName+sc_TableIsNotReady);:=False;
Exit;;Not (Self.LTaskPrepared) then {якщо ця підготовка ще не виконувалася:}
{Зсуваємо рядки цільових
функцій вниз. При цьому позначки порядку
рядків залишаємо на тих
самих місцях (і присвоюємо тим рядкам, які
стають на ці місця):}. ShiftRowsDown([bc_DestFuncToMax, bc_DestFuncToMin], True);
{Позиціювання
відображення таблиці у даному режимі вирішування:}.CHeadColNum:=CurGrid. FixedCols;.CHeadRowNum:=CurGrid.
FixedRows-1;
{Відображаємо таблицю,
що підготована для розв'язування:}.
WriteTableToGrid (Self.CHeadColNum,
Self.CHeadRowNum);.LTaskPrepared:=True;;:=True;Self. CurOutConsole<>Nil
then. CurOutConsole. Lines. Add (sc_CurProcName+sc_WrongEditMode);:=False;;;
TGridFormattingProcs.
PrepareDFuncForSimplexMaximize: Boolean;ToMax: Boolean; Row, Col, CurWidth,
DFuncRowNum: Integer;sc_CurProcName='PrepareDFuncForSimplexMaximize';:=Length
(Self. CurHeadRow);:=Length (Self. CurHeadCol) - 1;
Self.
CurHeadCol[DFuncRowNum].ElmType of {перевіряємо тип функції мети:}_DestFuncToMax:
ToMax:=True;_DestFuncToMin: ToMax:=False;{якщо заданий рядок виявився не
функцією мети:}Self. CurOutConsole<>Nil then. CurOutConsole. Lines.
Add (sc_CurProcName+_CurRowNotMarkedAsDestFunc+IntToStr
(DFuncRowNum+1));:=False; Exit;;;
{Готуємо умову для
вирішування симплекс-методом максимізації:}
{Міняємо знаки у
елементів рядка-заголовка, окрім знака останньої
комірки - то множник для
стовпця правих частин. Це є
інтерпретацією
перенесення усіх доданків у праву частину, і
форматом для виконання
модифікованих Жорданових виключень:}Col:=0
to CurWidth-2 do(Self. CurHeadRow[Col]);
{Якщо треба шукати
максимум, то множимо коефіцієнти функції мети
на -1 (окрім вільгого
члена), бо помножили і усі x1…xn на -1.
Якщо треба мінімум, то
ці коефіцієнти не множимо
(бо x1…xn вже
помножені), але множимо вільний член функції. Тоді
отримаємо протилежну
функцію, щоб знайти її максимум
(це протилежний мінімум
заданої функції):}:=Length (Self.
CurHeadCol) - 1; {рядок функції мети}ToMax thenCol:=0 to CurWidth-2 do {коефіцієнти
функції мети міняють знаки:}. CurTable [Row, Col]:=-Self. CurTable [Row,
Col];{Якщо треба знайти мінімум:}{Множимо вільний член функції мети на -1:}.
CurTable [Row, CurWidth-1]:=-Self. CurTable [Row, CurWidth-1];
{Назва функції теж міняє
знак:}(Self. CurHeadCol[Row]);
{Тепер це протилежна
функція для максимізації:}.
CurHeadCol[Row].ElmType:=bc_DestFuncToMax;;:=True;;
TGridFormattingProcs.
PrepareDestFuncInMultiDFuncLTask (, MinDestFuncRowNum: Integer):Boolean;
{Готує таблицю для
розв'язування задачі ЛП відносно одної заданої функції
мети із
багатокритеріальної задачі.
Вхідні дані:- номер
рядка у таблиці Self. CopyTable (і комірки у
стовпці-заголовку Self.
CopyHeadCol), в якому записана портібна
функція мети;- номер
найвищого (з найменшим номером) рядка
функції мети. Усі
функції мети мають бути зібрані внизу таблиці;. CopyTable - таблиця
коефіцієнтів та вільних членів;. CopyHeadRow - рядок-заголовок зі змінними та
одиницею-множником
стовпця вільних членів
(має бути останнім);. CopyHeadCol - стовпець-заголовок з іменами
функцій-нерівностей,
нулями (заголовки
рядків-рівнянь), іменами функцій мети
(що максимізуються (тип
комірки bc_DestFuncToMax) або мінімізуються
(тип bc_DestFuncToMin)).
Вихідні дані:
Умова для одної
функції:. CurTable - таблиця коефіцієнтів та вільних членів з одною
функцією мети в
останньому рядку, для максимізації симплекс-методом;. CurHeadRow -
рядок-заголовок;. CurHeadCol - стовпець-заголовок з іменами
функцій-нерівностей,
нулями (заголовки
рядків-рівнянь), і одною коміркою функції мети
(остання, найнижча
комірка), яку треба максимізувати. Якщо у цій
комірці перед назвою
функції стоїть знак «-», то після максимізації
її треба замінити на
протилежну функцію (і отримати мінімізацію
тої функції, яка була
задана в умові).
Підпрограма повертає
ознаку успішності підготовки умови із одною
заданою функцією мети.}Row, Col, CurWidth, CurHeight: Integer;sc_CurProcName='PrepareDestFuncInMultiDFuncLTask';LStopLabel;Not
(Self. GoToEnd) then{Демонструємо функцію мети у таблиці, з якою будемо
працювати:}
{Таблиця
багатокритеріальної задачі для відображення:}. CurHeadRow:=Self. CopyHeadRow; Self. CurHeadCol:=Self.
CopyHeadCol;. CurTable:=Self. CopyTable;
{Координати рядка
функції для помітки його кольором:}.
CurGridSolveCol:=Self.CHeadColNum;.
CurGridSolveRow:=SFuncRowNum+Self.CHeadRowNum+bc_LTaskRowsBeforeVars;
{Відображаємо і чекаємо
реакції користувача:}(Self.CHeadColNum,
Self.CHeadRowNum);Self. Stop then Goto LStopLabel;;
:=Length (Self.
CopyHeadRow);:=Length (Self. CopyHeadCol);
(SFuncRowNum<0) or
(MinDestFuncRowNum<0) or
(SFuncRowNum>=CurHeight)
or (MinDestFuncRowNum>=CurHeight) thenSelf. CurOutConsole<>Nil then.
CurOutConsole. Lines. Add (sc_CurProcName+sc_RowNumsIsOutOfTable);:=False;
Exit;;
{Формуємо умову
однокритеріальної задачі лінійного програмування із
копії умови
багатокритеріальної задачі:}
{Копіюємо заголовки і
таблицю коефіцієнтів:}(Self.
CurHeadRow, CurWidth); {довжина для рядка заголовка така сама}Col:=0 to
CurWidth-1 do Self. CurHeadRow[Col]:=Self. CopyHeadRow[Col];
{Стовпець-заголовок і
висота таблиці мають усі рядки умов (рівнянь
та нерівностей) і один
рядок функції мети:}(Self.
CurHeadCol, MinDestFuncRowNum+1);(Self. CurTable, MinDestFuncRowNum+1,
CurWidth);Row:=0 to MinDestFuncRowNum-1 do {копіюємо рядки умов:}.
CurHeadCol[Row]:=Self. CopyHeadCol[Row];Col:=0 to CurWidth-1 do. CurTable [Row,
Col]:=Self. CopyTable [Row, Col];;
{В останній рядок
таблиці однокритеріальної задачі копіюємо заданий
рядок функції мети із
багатокритеріальної задачі:}:=MinDestFuncRowNum;
{номер останнього рядка у однокритеріальній задачі}.
CurHeadCol[Row]:=Self. CopyHeadCol[SFuncRowNum];Col:=0 to CurWidth-1 do.
CurTable [Row, Col]:=Self. CopyTable [SFuncRowNum, Col];
:=Self.
PrepareDFuncForSimplexMaximize;;::=False; Exit;;
TGridFormattingProcs.
ShowLTaskResultCalc (DualTaskVals: Boolean);
{Процедура зчитує
значення функції мети у таблиці розв'язаної
однокритеріальної
задачі, і значення усіх змінних або функцій в цьому
розв'язку. Відображає
значення цих змінних, функцій-нерівностей, і
функції мети в Self.
CurOutConsole.
Вхідні дані:- вмикач
режиму відображення значень двоїстої задачі:
читаються значення змінних
і функцій двоїстої задачі. Їхні
значення розміщені не на
місці стовпця вільних членів, а у рядку
коефіцієнтів функції
мети (функції мети прямої задачі). Вони є
значеннями змінних чи
функцій, імена яких у рядку-заголовку.
Змінні чи
функції-нерівності двоїстої задачі з іменами у
стовпці-заголовку є
рівними нулю.
Таблиця розв'язаної
однокритеріальної (з одною функцією мети) задачі:. CurTable - таблиця
коефіцієнтів та вільних членів;. CurHeadRow - рядок-заголовок з іменами
змінних, іменами
функцій-нерівностей (що
перейшли в рядок-заголовок) та
одиницею-множником
стовпця вільних членів (має бути останнім);. CurHeadCol - стовпець-заголовок з
іменами функцій-нерівностей,
іменами змінних
(виключених), іменем функції мети.}DestFuncsTypes=[bc_DestFuncToMax,
bc_DestFuncToMin];st1: String; CurColNum, CurRowNum, LastColNum, LastRowNum:
Integer;Self. CurOutConsole<>Nil then:=Length (Self. CurHeadRow) -
1;:=Length (Self. CurHeadCol) - 1;
:=sc_ResultIs;DualTaskVals
then:=st1+sc_ForDualTaskst1:=st1+sc_ForDirectTask;
. CurOutConsole. Lines.
Add(st1);. CurOutConsole. Lines. Add (sc_InHeadRow);
{Показуємо значення
змінних (або функцій) у рядку-заголовку:}CurColNum:=0 to LastColNum-1 do:='';Self.
CurHeadRow[CurColNum].ElmType=bc_Number then:=st1+FloatToStr (Self. CurHeadRow[CurColNum].AsNumber)st1:=st1+Self.
CurHeadRow[CurColNum].AsVarName;:=st1 + sc_Space+sc_Equal+sc_Space;
{Усі змінні прямої
задачі (або функції) у рядку-заголовку в точці
задачі рівні нулю, а
змінні двоїстої - у рядку коефіцієнтів функції
мети:}DualTaskVals then:=st1+ FloatToStr (Self. CurTable [LastRowNum,
CurColNum])st1:=st1+'0';:=st1+sc_KrKm;
. CurOutConsole. Lines.
Add(st1);;. CurOutConsole. Lines. Add (sc_InHeadCol);
CurRowNum:=0 to
LastRowNum do:='';Self. CurHeadCol[CurRowNum].ElmType=bc_Number
then:=st1+FloatToStr (Self. CurHeadCol[CurRowNum].AsNumber)st1:=st1+Self.
CurHeadCol[CurRowNum].AsVarName;:=st1 + sc_Space+sc_Equal+sc_Space;
{Усі змінні прямої
задачі (або функції) у стовпці-заголовку в точці
задачі мають свої
значення у стовпці вільних членів,
а змінні двоїстої -
рівні нулю:}(Self.
CurHeadCol[CurRowNum].ElmType in DestFuncsTypes) or(DualTaskVals) then:=st1+
FloatToStr (Self. CurTable [CurRowNum, LastColNum])st1:=st1+'0';
(Self.
CurHeadCol[CurRowNum].ElmType in DestFuncsTypes) then:=sc_ResFunc+sc_Space+st1;
CurRowNum=LastRowNum
then st1:=st1+sc_Spotst1:=st1+sc_KrKm;
. CurOutConsole. Lines.
Add(st1);;;;
TGridFormattingProcs.
ReadCurFuncSolution (Var SDValVecs:TFloatMatrix;SDDestFuncVals:TFloatArr;
SVecRow: Integer;: Boolean; DualTaskVals: Boolean);
{Процедура зчитує
значення функції мети у таблиці розв'язаної
однокритеріальної
задачі, і значення усіх змінних або функцій в цьому
розв'язку.
Вхідні дані:- номер
поточної функції мети (нумерація з нуля) у масивахі SDDestFuncVals;- перемикач:
якщо рівний False, то зчитуються значення
змінних (і значення
функції мети); True - зчитуються значення
функцій-нерівностей (і
значення функції мети);- вмикач режиму читання змінних двоїстої задачі:
читаються значення
змінних і функцій двоїстої задачі. Їхні
значення розміщені не на
місці стовпця вільних членів, а у рядку
коефіцієнтів функції
мети (функції мети прямої задачі). Вони є
значеннями змінних чи
функцій, імена яких у рядку-заголовку.
Змінні чи
функції-нерівності двоїстої задачі з іменами у
стовпці-заголовку є
рівними нулю.
Таблиця розв'язаної
однокритеріальної (з одною функцією мети) задачі:. CurTable - таблиця
коефіцієнтів та вільних членів;. CurHeadRow - рядок-заголовок з іменами
змінних, іменами
функцій-нерівностей (що
перейшли в рядок-заголовок) та
одиницею-множником
стовпця вільних членів (має бути останнім);. CurHeadCol - стовпець-заголовок з
іменами функцій-нерівностей,
іменами змінних
(виключених), іменем функції мети. Функція мети
має бути в останньому
рядку, і бути одна;- масив для запису векторів значень змінних;- масив для
запису значень функцій мети
(для цих двох останніх
масивів пам'ять має бути вже виділеною).
Вихідні дані:- масив
векторів значень змінних із заповненим вектором
номер SVecRow. Змінні,
яких немає в таблиці розв'язку, вважаються
такими що можуть мати
будь-яке значення, і приймаються рівними нулю;- масив значень функцій мети з
поточни значенням
у комірці номер
SVecRow.}CurColNum, CurRowNum,
LastColNum, LastRowNum: Integer;:THeadLineElmTypes;
{Ініціюємо нулями
поточний вектор значень.
Змінні чи функції, імена
яких у рядку-заголовку, рівні нулю
для прямої задачі (для
двоїстої - у стовпці-заголовку).
Змінні і функції, яких
немає в таблиці, теж вважаємо рівними нулю:}CurColNum:=0 to Length (SDValVecs[SVecRow]) - 1 do[SVecRow, CurColNum]:=0;
{Читаємо
стовпець-заголовок і значення із останнього стовпця таблиці:}:=Length (Self. CurHeadRow) - 1;:=Length (Self. CurHeadCol) - 1;
{Значення функції мети:}[SVecRow]:=Self. CurTable [LastRowNum, LastColNum];
{Функції-нерівності
прямої задачі відповідають змінним двоїстої задачі
за позиціюванням в
заголовках (не за значеннями, значення різні!),
змінні прямої - функціям
двоїстої:}(ToReadFuncVals) xor
(DualTaskVals) then:=[bc_FuncVal]WorkCellTypes:=[bc_IndependentVar,
bc_DependentVar];
{Читаємо змінні або
функції-нерівності (в залежності від того, що
задано прочитати):}DualTaskVals thenCurColNum:=0 to LastColNum-1 do {усі стовпці
крім стовпця вільних членів}{значення записуємо у заданий вектор (SVecRow):}(Self.
CurHeadRow[CurColNum].ElmType in WorkCellTypes) then[SVecRow, Self.
CurHeadRow[CurColNum].VarInitPos]:=. CurTable [LastRowNum,
CurColNum];CurRowNum:=0 to LastRowNum-1 do {усі рядки крім рядка функції
мети}{значення записуємо у заданий вектор (SVecRow):}(Self.
CurHeadCol[CurRowNum].ElmType in WorkCellTypes) then[SVecRow, Self.
CurHeadCol[CurRowNum].VarInitPos]:=. CurTable [CurRowNum, LastColNum];;;
TGridFormattingProcs.
BuildPaymentTaskOfOptim (SOptimXVecs:TFloatMatrix; Const
SOptimFuncVals:TFloatArr;: Integer);
{Будує однокритеріальну
задачу максимізації для пошуку вагових
коефіцієнтів і
компромісного вектора значень змінних для
усіх заданих функцій
мети.
Вхідні дані:- масив
векторів оптимальних значень змінних для
кожної з фунуцій мети;-
масив оптимальних значень функцій мети;- номер першої (найвищої) функції мети
у Self. CopyTable і
Self. CopyHeadCol;. CopyTable - матриця коефіцієнтів умови багатокритеріальної
задачі;
Вихідні дані:
Однокритеріальна задача
ЛП для максимізації:. CurTable - матриця коефіцієнтів оптимальності,
вільних членів і
коефіцієнтів функції мети;. CurHeadCol - імена змінних двоїстої задачі (як
функції-нерівності
прямої задачі);. CurHeadRow - імена функцій-нерівностей двоїстої задачі
(як залежні (тільки
більше нуля) змінні прямої задачі).}jCol,
iRow, FuncCount, FuncRow: Integer; MinQ,
CurQ:TWorkFloat;sc_CurProcName='BuildPaymentTaskOfOptim';CalcQ (ZjFuncRow:
Integer; Const XiVals:TFloatArr;ZjXj:TWorkFloat):TWorkFloat;
{Підраховує міру
неоптимальності.
Вхідні дані:- номер
рядка j-ої функції мети у таблиці Self. CopyTable;. CopyTable - таблиця
коефіцієнтів умови багатокритеріальної
задачі ЛП;- оптимальні
значення змінних для i-ої функції мети
(для формування i-го
рядка матриці неоптимальності);- значення j-ої функції мети за j-го набору
оптимальних
значень змінних (тобто
оптимальне значення цієї функції). Для
формування j-го стовпця
матриці неоптимальності.
Вихідні дані: міра
неоптимальності.}VarNum: Integer;
ZjXi:TWorkFloat;:=0;
{Шукаємо суму добутків
значень змінних і коефіцієнтів при них -
значення функції у
точці, координатами якої є подані значення змінних:}VarNum:=0 to Length(XiVals) - 1 do:=ZjXi + Self. CopyTable
[ZjFuncRow, VarNum]*XiVals[VarNum];
:=-Abs((ZjXi/ZjXj) - 1);
{qij=-|(ZjXi-ZjXj)/(ZjXj)|};
{Заповнення імен змінних
- імен фукнцій двоїстої задачі у рядку-заголовку:}FillHRowVarName (SCol: Integer);.
CurHeadRow[SCol].VarInitPos:=SCol;. CurHeadRow[SCol].VarInitInRow:=True;.
CurHeadRow[SCol].ElmType:=bc_DependentVar;.
CurHeadRow[SCol].AsVarName:=sc_Minus+sc_DualTaskFuncNameStart+(SCol+1);;
{Заповнення у комірки рядка-заголовка
числом:}FillHRowWithNum (SCol:
Integer; Const SNumber:TWorkFloat);. CurHeadRow[SCol].VarInitPos:=SCol;.
CurHeadRow[SCol].VarInitInRow:=True;. CurHeadRow[SCol].ElmType:=bc_Number;.
CurHeadRow[SCol].AsNumber:=SNumber;;
{Заповнення імен функцій
- імен змінних двоїстої задачі у стовпці-заголовку:}FillHColFuncName (SRow: Integer);.
CurHeadCol[SRow].VarInitPos:=SRow;. CurHeadCol[SRow].VarInitInRow:=False;.
CurHeadCol[SRow].ElmType:=bc_FuncVal;.
CurHeadCol[SRow].AsVarName:=sc_Minus+sc_DualTaskVarNameStart+(SRow+1);;
{Заповнення імені
функції мети:}FillHColDFuncName
(SRow: Integer);. CurHeadCol[SRow].VarInitPos:=SRow;.
CurHeadCol[SRow].VarInitInRow:=False;.
CurHeadCol[SRow].ElmType:=bc_DestFuncToMax;.
CurHeadCol[SRow].AsVarName:=sc_DestFuncHdr;;LStopLabel;:=Length(SOptimFuncVals);
Self.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add
(sc_CurProcName+sc_CalculatingNoOptMeasures);
{Таблиця мір
неоптимальності квадратна: кількість стовпців рівна
кількості функцій мети;
кількість рядків рівна кількості оптимальних
векторів значень змінних
для кожної з цих функцій (тобто тій же самій
кількості). Додатково
виділимо один стовпець для вільних членів
і один рядок для
коефіцієнтів функції мети задачі-інтерпретації
гри двох гравців з
нульовою сумою, що буде сформована далі:}(Self. CurTable, FuncCount + 1, FuncCount + 1);
{Відповідну довжину
задаємо і заголовкам таблиці:}(Self.
CurHeadCol, FuncCount + 1);(Self. CurHeadRow, FuncCount + 1);
{Підраховуємо міри
неоптимальності векторів значень змінних для
кожної функції мети, і
записуємо їх у таблицю коефіцієнтів -
формуємо матрицю
неоптимальності:}
{Шукаємо мінімальну
(найбільшу за модулем) міру неоптимальності.
Спочатку за неї беремо
міру у верхньому лівому куті матриці:}:=CalcQ (SFirstDFuncRow, SOptimXVecs[0], SOptimFuncVals[0]);.
CurTable [0, 0]:=MinQ; {записуємо одразу цю міру в матрицю}jCol:=0 to
FuncCount-1 do:=SFirstDFuncRow+jCol;
{Комірка [0, 0] вже
порахована, її обходимо. Для всіх інших виконуємо:}iRow:=Ord (jCol=0) to FuncCount-1 do {Ord (0=0)=1; Ord (<не
нуль>=0)=0}{Підраховуємо міру неоптимальності:}:=CalcQ (FuncRow,
SOptimXVecs[iRow], SOptimFuncVals[jCol]);MinQ>CurQ then MinQ:=CurQ; {шукаємо
найбільшу за модулем міру}. CurTable [iRow, jCol]:=CurQ; {записуємо міру
в матрицю неоптимальності};;
:=-MinQ; {найбільше
абсолютне значення (модуль) усіх мір в матриці}
{Заповнюємо заголовки
таблиці (це будуть заголовки задачі ЛП):}jCol:=0 to FuncCount-1 do FillHRowVarName(jCol);iRow:=0 to
FuncCount-1 do FillHColFuncName(iRow);(FuncCount, 1);(FuncCount);
{Коефіцієнти функції
мети: усі однакові і рівні одиниці (бо
відхилення чи наближення
будь-якої з цільових функцій від свого
оптимального значення
пропорційно (у відсотках) має однакову ціну):}jCol:=0 to FuncCount-1 do Self. CurTable [FuncCount, jCol]:=1;
{Вільні члени: усі рівні
одиниці:}iRow:=0 to FuncCount-1
do Self. CurTable [iRow, FuncCount]:=1;
{Комірка значення
функції мети:}. CurTable
[FuncCount, FuncCount]:=0;
{Ховаємо розв'язувальну
комірку у екранній таблиці:}.
CurGridSolveCol:=0; Self. CurGridSolveRow:=0;(Self.CHeadColNum,
Self.CHeadRowNum); {показуємо матрицю}Self. Stop then Goto LStopLabel;
{Якщо MinQ=0, то усі
міри рівні нулю (бо MinQ тут насправді є
багатокритеріальної
задачі рівна одній (тобто задача однокритеріальна),
то і міра є лише одна, і
для неї MinQ=-q [0,0], тому при додаванні[0,0]+MinQ=q [0,0] - q [0,0]=0.
Щоб в обох цих випадках
розв'язування симплекс-методом працювало
коректно, замінимо MinQ
на інше число:}MinQ=0 thenSelf.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add
(sc_CurProcName+sc_AllMeasurIsZero);:=1 {одиниця, якщо всі нулі (отримаємо
матрицю із одиниць)}if Length(SOptimFuncVals)=1 then {якщо всього одна
функція мети:}Self. CurOutConsole<>Nil then. CurOutConsole. Lines.
Add (sc_CurProcName+sc_UniqueMeasureCantSetZero);:=MinQ+1; {збільшимо на 1 -
отримаємо матрицю з одною одиницею.};
{Додаємо до усіх мір
неоптимальності максимальну за модулем, і
отримуємо матрицю
коефіцієнтів, до якої можна застосувати
симплекс-метод:}iRow:=0 to FuncCount-1 dojCol:=0 to FuncCount-1 do. CurTable
[iRow, jCol]:=Self. CurTable [iRow, jCol]+MinQ;
:;
TGridFormattingProcs.
CalcComprVec (Const SVarVecs:TFloatMatrix;SWeightCoefs:TFloatArr; Var
DComprVec:TFloatArr);
{Обчислює компромісний
вектор (масив) значень змінних із
із заданих векторів
значень і вагових коефіцієнтів для кожного із
цих векторів.
Вхідні дані:- вектори
значень змінних;- вагові коефіцієнти для кожного вектора.
Вихідні дані:-
компромісний вектор значень змінних.}VecNum,
VarNum: Integer; CurComprVal:TWorkFloat;:=Nil;Length(SVarVecs)<=0 then
Exit;(DComprVec, Length (SVarVecs[0]));
VarNum:=0 to
Length(DComprVec) - 1 do {для кожної змінної:}:=0;
{Множимо значення
змінної з кожного вектора на свій ваговий
коефіцієнт, і знаходимо
суму:}VecNum:=0 to
Length(SVarVecs) - 1 do:=CurComprVal + SVarVecs [VecNum,
VarNum]*SWeightCoefs[VecNum];
[VarNum]:=CurComprVal;;;
TGridFormattingProcs.
CalcDFuncVal (Const SVarVec:TFloatArr;: Integer):TWorkFloat;
{Обчислює значення
функції мети за заданих значень змінних.
Вхідні дані:- вектор
значень змінних (в такому порядку, в якому змінні
йдуть в рядку-заголовку
умови багатокритеріальної задачі);- номер рядка функції мети в умові задачі у.
CopyTable;. CopyTable - матриця коефіцієнтів умови
багатокритеріальної
лінійної задачі оптимізації.
Вихідні дані:
Повертає значення
функції мети.}VarNum: Integer;
FuncVal:TWorkFloat;:=0;VarNum:=0 to Length(SVarVec) - 1 do {для кожної
змінної:}:=FuncVal + SVarVec[VarNum]*Self. CopyTable [SDestFuncRowNum,
VarNum];;:=FuncVal;;
TGridFormattingProcs.
SolveMultiCritLTask: Boolean;
{Вирішування задачі
багатокритеріальної оптимізації лінійної форми
з використанням
теоретико-ігрового підходу.
Умовою задачі є
умови-нерівності, рівняння та умови на невід'ємність
окремих змінних, і декілька
функцій мети, для яких треба знайти
якомога більші чи менші
значення.
Вхідні дані:. CurTable -
таблиця коефіцієнтів та вільних членів;. CurHeadRow - рядок-заголовок зі
змінними та одиницею-множником
стовпця вільних членів
(має бути останнім);. CurHeadCol - стовпець-заголовок з іменами
функцій-нерівностей,
нулями (заголовки
рядків-рівнянь), іменами функцій мети
(що максимізуються (тип
комірки bc_DestFuncToMax) або мінімізуються
(тип bc_DestFuncToMin)).
Функція повертає ознаку
успішності вирішування.}Row,
CurWidth, CurHeight, FirstDestFuncRow,, VarCount: Integer;: Boolean;: String;,
DualUVec:TFloatMatrix;, OptGTaskVal,
ComprXVec:TFloatArr;sc_CurProcName='SolveMultiCritLTask';_TextMarkRow='############';
Procedure
ShowWeightCoefs (Const SCoefs:TFloatArr; FirstDestFuncRow: Integer);i:
Integer;Self. CurOutConsole<>Nil then. CurOutConsole. Lines. Add
(sc_WeightCoefs);i:=0 to Length(SCoefs) - 1 do
{Відображаємо вагові
коефіцієнти для кожної з функцій мети
багатокритеріальної
задачі:}. CurOutConsole. Lines.
Add ('l['+. CopyHeadCol [FirstDestFuncRow+i].AsVarName+'] = '+(SCoefs[i]));;;;
ShowComprVarVec (Const
ComprXVec:TFloatArr);Col: Integer; st1: String;Self. CurOutConsole<>Nil
then. CurOutConsole. Lines. Add (sc_ComprVarVals);Col:=0 to Length(ComprXVec) -
1 do:=Self. CopyHeadRow[Col].AsVarName + ' = ';:=st1 + FloatToStr
(ComprXVec[Col]);. CurOutConsole. Lines. Add(st1);;;;
ShowDFuncVals (Const
ComprXVec:TFloatArr; FirstDFuncRow: Integer);Row: Integer; st1: String;Self.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add
(sc_DestFuncComprVals);Row:=FirstDFuncRow to Length (Self. CopyTable) - 1
do:=Self. CopyHeadCol[Row].AsVarName + ' = ';:=st1 + FloatToStr (Self.
CalcDFuncVal (ComprXVec, Row));. CurOutConsole. Lines. Add(st1);;;;
LStopLabel, LFinish;:=True;
{прапорець успішності}. GetTaskSizes (CurWidth, CurHeight);
CurWidth<=0 then {Якщо
таблиця пуста, то задача пуста:}Self. CurOutConsole<>Nil then.
CurOutConsole. Lines. Add (sc_CurProcName + sc_EmptyTable);.
WasNoRoots:=True;:=False;;;
Self. CurOutConsole<>Nil
then. CurOutConsole. Lines. Add('');. CurOutConsole. Lines. Add (sc_CurProcName
+ sc_StartSolving);;
{Зберігаємо посилання на
масиви умови багатокритеріальної задачі:}. CopyHeadRow:=Self. CurHeadRow;. CopyHeadCol:=Self. CurHeadCol;.
CopyTable:=Self. CurTable;
{Шукаємо цільові функції
внизу таблиці:}Row:=CurHeight-1
downto 0 doSelf. CopyHeadCol[Row].ElmType of_DestFuncToMax:;_DestFuncToMin:;
{Якщо знизу вгору дійшли
до рядка, що не є функцією мети - завершуємо:}Break;;;
Row>=CurHeight-1 then
{якщо рядків функцій мети взагалі немає:}Self. CurOutConsole<>Nil
then. CurOutConsole. Lines. Add (sc_CurProcName + sc_NoDestFuncs);.
WasNoRoots:=True;:=False; Goto LFinish;if Row<0 then {якщо в таблиці є
тільки рядки функцій мети:}Self. CurOutConsole<>Nil then. CurOutConsole.
Lines. Add (sc_CurProcName + sc_OnlyDestFuncsPresent);
:=False; Goto LFinish;
(* Row:=-1; *);:=Row+1; {найвищий
у таблиці рядок функції мети}
:=CurHeight-FirstDestFuncRow;
{кількість функцій мети}
{Змінні: усі стовпці
окрім останнього (стовпця вільних членів з
одиницею в заголовку):}:=CurWidth-1;
{Вектори змінних в
оптимальних розв'язках задач:}(OptimXVecs,
DestFuncCount, VarCount);
{Оптимальні значення
функцій (максимальні або мінімальні значення):}(OptimFuncVals, DestFuncCount);
{############ Шукаємо
min або max кожної функції мети окремо: ############}Row:=FirstDestFuncRow to CurHeight-1 do {для усіх функцій
мети:}Self. CurOutConsole<>Nil then:=sc_TextMarkRow+sc_CurProcName +
sc_ForDestFunc+_DoubleQuot+ Self. CopyHeadCol[Row].AsVarName
+sc_DoubleQuot+sc_Space;Self. CopyHeadCol[Row].ElmType=bc_DestFuncToMin
then:=st1+sc_SearchingMinst1:=st1+sc_SearchingMax;:=st1+sc_TriSpot+sc_TextMarkRow;
. CurOutConsole. Lines.
Add(st1);;
{Формуємо умову
однокритеріальної задачі максимізації:}Not (Self. PrepareDestFuncInMultiDFuncLTask (Row,
FirstDestFuncRow)) then:=False; Break;;Self. Stop then Break;
{Ховаємо розв'язувальну
комірку у екранній таблиці (її нема тут):}. CurGridSolveCol:=0; Self. CurGridSolveRow:=0;
{Відображаємо
підготовану однокритеріальну задачу:}(Self.CHeadColNum,
Self.CHeadRowNum);Self. Stop then Break;
{Запускаємо вирішування
однокритеріальної задачі максимізації лінійної
форми (так як поточна
функція є функцією максимізації, або зведена
до такої):}. WasNoRoots:=False; Self. WasManyRoots:=False; Self.
SolWasFound:=False;Not (Self. SolveLTaskToMax(False)) then:=False; Break;;
{Якщо функція мети
необмежена або система умов несумісна:}Not (Self. SolWasFound) then
{Якщо функцій мети
більше одної, то так як компромісний вектор
через необмеженість
принаймні одної з функцій мети знайти неможливо:}(FirstDestFuncRow+1)<CurHeight then
Res1:=FalseRes1:=True;LFinish;;Self. Stop then Break;
{Читаємо вектор значень
змінних та оптимальне значення функції мети
з таблиці:}. ReadCurFuncSolution (OptimXVecs, OptimFuncVals,
Row-FirstDestFuncRow,, False);;Not(Res1) then Goto LFinish;Self. Stop then Goto
LStopLabel;
{############ Шукаємо
міри неоптимальності і будуємо задачу: ############}
{######## пошуку
компромісних вагових коефіцієнтів, вирішуємо її: ########}Self. CurOutConsole<>Nil then Self. CurOutConsole. Lines.
Add (sc_TextMarkRow);(OptimXVecs, OptimFuncVals, FirstDestFuncRow);Self. Stop
then Goto LStopLabel;Self. CurOutConsole<>Nil then. CurOutConsole. Lines.
Add (sc_TextMarkRow);
{Готуємо задачу до
максимізації симплекс-методом:}:=Self.
PrepareDFuncForSimplexMaximize;Not(Res1) then Goto LFinish;
{Запускаємо вирішування
цієї задачі:}. WasNoRoots:=False;
Self. WasManyRoots:=False; Self. SolWasFound:=False;
{«True» - з
відображенням значень двоїстої:}Not
(Self. SolveLTaskToMax(True)) then:=False; Goto LFinish;;
{Якщо функція мети
необмежена або система умов несумісна:}Not (Self. SolWasFound) then:=False; Goto LFinish;;Self. Stop then
Goto LStopLabel;
{############ Обчислюємо
вагові коефіцієнти: ############}
{Якщо
задача-інтерпретація гри вирішена і знайдено оптимальне
значення функції, то
читаємо це значення і значення змінних
двоїстої задачі:}(OptGTaskVal, 1); {для запису значення функції мети}(DualUVec,
1, DestFuncCount); {для запису значень змінних}. ReadCurFuncSolution
(DualUVec, OptGTaskVal, 0, False, True);
{Обчислюємо вагові
коефіцієнти:}Row:=0 to
DestFuncCount-1 do[0, Row]:=(DualUVec [0, Row]/OptGTaskVal[0]); {Li=ui/(W(U))}
Self.
CurOutConsole<>Nil then Self. CurOutConsole. Lines. Add (sc_TextMarkRow);(DualUVec[0],
FirstDestFuncRow);
{############ Обчислюємо
компромісний вектор: ############}.
CalcComprVec (OptimXVecs, DualUVec[0], ComprXVec);
(ComprXVec);(ComprXVec,
FirstDestFuncRow);
LFinish;: {Якщо
вирішування було перервано:}
{Повертаємо початкову
умову на попереднє місце:}.
CurHeadRow:=Self. CopyHeadRow;. CurHeadCol:=Self. CopyHeadCol;. CurTable:=Self.
CopyTable;:
{Обнуляємо посилання на
копію умови. Так як це динамічні масиви і
щодо них йде відлік
кількості посилань, то для них не створюватимуться
зайві копії у пам'яті, і
при роботі з CurHeadRow, CurHeadCol, CurTable
пам'ять буде виділена
завжди тільки для їхніх поточних даних:}. CopyHeadRow:=Nil;. CopyHeadCol:=NIl;. CopyTable:=Nil;
:=Res1;;
TGridFormattingProcs.
ChangeSignsInRow (CurRowNum: Integer);
{Зміна знаків у рядку
таблиці і відповідній комірці у стовпці-заголовку.}CurColNum: Integer;CurColNum:=0 to Length (Self. CurHeadRow) - 1
do[CurRowNum, CurColNum]:=-CurTable [CurRowNum, CurColNum];(Self.
CurHeadCol[CurRowNum]);;
TGridFormattingProcs.
ChangeSignsInCol (CurColNum: Integer);
{Зміна знаків у стовпці
таблиці і відповідній комірці у рядку-заголовку.}CurRowNum: Integer;CurRowNum:=0 to Length (Self. CurHeadCol) - 1
do[CurRowNum, CurColNum]:=-CurTable [CurRowNum, CurColNum];(Self.
CurHeadRow[CurColNum]);;
TGridFormattingProcs.
ShiftRowsUp (SHeadColElmTypes:THeadLineElmTypes;: Boolean=False):Integer;
{Функція переміщує рядки
таблиці CurTable (разом із відповідними
комірками у
стовпці-заголовку CurHeadCol) з заданими типами комірок
стовпця-заголовка вгору.
Вхідні дані:- множина
типів комірок, що мають бути переміщені вгору
(у стовпці-заголовку);-
вмикач зміни позначок номера по порядку та
позначки розташування в
таблиці як рядка чи стовпця.
Якщо рівний True, то
рядки при переміщенні змінюють ці позначки
на позначки тих рядків,
що були в тих місцях, на які рядки переміщені;. CurTable - таблиця
коефіцієнтів;. CurHeadCol - стовпець-заголовок.
Вихідні дані:. CurTable
і Self. CurHeadCol - таблиця коефіцієнтів і
стовпець-заголовок з
перенесеними вгору рядками і комірками;
функція повертає номер
найвищого рядка із тих, що не було задано
переміщувати вгору (вище
нього - ті, що переміщені вгору).}HiNotInSetRow,
CurRowToUp, CurRowNum: Integer;
{Номер найвищого рядка,
що не є в множині тих, які переміщуються вгору.
Спочатку ставимо тут
номер неіснуючого рядка:}:=-1;
{Йдемо по рядкам згори
вниз:}CurRowNum:=0 to Length
(Self. CurHeadCol) - 1 do{Шукаємо перший рядок з типом комірки, що не має
переміщуватися вгору:}Not (Self. CurHeadCol[CurRowNum].ElmType in
SHeadColElmTypes) then:=CurRowNum;
{шукаємо найнижчий
рядок, який портібно переміщувати вгору:}CurRowToUp:=Length (Self. CurHeadCol) - 1 downto CurRowNum+1
doSelf. CurHeadCol[CurRowToUp].ElmType in SHeadColElmTypes then Break;;
{Якщо таких рядків не
знайдено, то усі вони вже вгорі:}CurRowToUp<=CurRowNum
then Break{Міняємо місцями рядок, що має бути вгорі, і рядок, що не має,
але розташований вище:}(Self. CurTable, Self. CurHeadCol, CurRowNum,,
ToChangeInitPosNums);;;:=HiNotInSetRow;;
TGridFormattingProcs.
ShiftRowsDown (:THeadLineElmTypes;: Boolean=False):Integer;
{Функція переміщує рядки
таблиці CurTable (разом із відповідними
комірками у
стовпці-заголовку CurHeadCol) з заданими типами комірок
стовпця-заголовка вниз.
Вхідні дані:- множина
типів комірок, що мають бути переміщені вниз
(у стовпці-заголовку);-
вмикач зміни позначок номера по порядку та
позначки розташування в
таблиці як рядка чи стовпця.
Якщо рівний True, то
рядки при переміщенні змінюють ці позначки
на позначки тих рядків,
що були в тих місцях, на які рядки переміщені;. CurTable - таблиця
коефіцієнтів;. CurHeadCol - стовпець-заголовок.
Вихідні дані:. CurTable
і Self. CurHeadCol - таблиця коефіцієнтів і
стовпець-заголовок з
перенесеними донизу рядками і комірками;
функція повертає номер найвищого
рядка із тих, що переміщені вниз
(вище нього - рядки тих
типів, що не було задано переміщувати донизу).}AllOtherHeadTypes:THeadLineElmTypes;
{Отримуємо протилежну
множину типів комірок:}:=[bc_IndependentVar..bc_OtherType]
- SHeadColElmTypes;
{Зсуваємо рядки з усіма
іншими типами вгору (і рядки з заданими
типами залишаються
внизу):}:=Self. ShiftRowsUp
(AllOtherHeadTypes, ToChangeInitPosNums);;
TGridFormattingProcs.
SolveLTaskToMax (DualTaskVals: Boolean):Boolean;
{Вирішування задачі
максимізації лінійної форми (що містить умови-
нерівності, рівняння та
умови на невід'ємність окремих змінних і
одну функцію мети, для
якої треба знайти максимальне значення).
Вхідні дані:- вмикач
режиму відображення змінних двоїстої задачі
(після завершення
розв'язування, якщо оптимальне значення знайдено):
читаються значення
змінних і функцій двоїстої задачі. Їхні
значення розміщені не на
місці стовпця вільних членів, а у рядку
коефіцієнтів функції
мети (функції мети прямої задачі). Вони є
значеннями змінних чи
функцій, імена яких у рядку-заголовку.
Змінні чи
функції-нерівності двоїстої задачі з іменами у
стовпці-заголовку є
рівними нулю.
Вихідні дані:- тип
результату вирішування, який досягнутий (у випадку
успішного вирішування);
Функція повертає ознаку
успішності вирішування.}sc_CurProcName='SolveLTaskToMax';CurRowNum,
CurRow2N, CurColNum: Integer;, HeadColNum: Integer;: Integer;, RowDeleted,
AllExcluded, WasNothingToDo: Boolean;: String;
SearchMNNCellForCol
(CurColNum: Integer;, EndRowNum: Integer;DRowNum: Integer;
AllowNegatCellIfZero: Boolean=False);
{Пошук у стовпці
CurColNum комірки з МНВ (мінімального невід'ємного
відношення вільного
члена до значення комірки у стовпці).- дозволити від'ємне значення комірки і
при
нульовому вільному
члені.}CurRowNum, FoundRow:
Integer; MNN, CurRelat:TWorkFloat;
{Шукаємо МНВ у заданому
інтервалі рядків:}:=-1;
MNN:=-1;CurRowNum:=StartRowNum to EndRowNum do{Перевірка виконання умов
невід'ємного відношення:}(CurTable [CurRowNum, CurColNum]<>0) and
(AllowNegatCellIfZero or
(CurTable [CurRowNum,
Length (Self. CurHeadRow) - 1]<>0) or
(CurTable [CurRowNum,
CurColNum]>0)) and
((ValSign
(CurTable[CurRowNum, Length (Self. CurHeadRow) - 1])*(CurTable[CurRowNum,
CurColNum]))>=0) then:=CurTable [CurRowNum, Length (Self. CurHeadRow) -
1]/[CurRowNum, CurColNum];
{Якщо знайшли менше, або
знайшли перше значення:}(CurRelat<MNN)
or (FoundRow=-1) then:=CurRelat; FoundRow:=CurRowNum;;;;
(Self.
CurOutConsole<>Nil) and (FoundRow<0) then. CurOutConsole. Lines. Add
(sc_CurProcName+sc_NoMNN+sc_Space+(CurColNum+1)+sc_Space+sc_TriSpot);
:=FoundRow;;
LStopLabel;Self.
TaskWidth<=0 then {Якщо таблиця пуста, то задача пуста:}Self.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add (sc_CurProcName +
sc_EmptyTable);:=False;;;:=Self.CHeadRowNum;:=Self.CHeadColNum;
Self.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add (sc_CurProcName +
sc_StartSolving);. CurOutConsole. Lines. Add (sc_CurProcName +
sc_ExcludingFreeVars);;
{##############
Виключаємо незалежні змінні: ##############}:=0;:=True; AllExcluded:=True;:=0;CurColNum<(Length (Self.
CurHeadRow) - 1) do {усі стовпці окрім останнього}:=False;
{Координати
розв'язувальної комірки для помітки кольором в екранній
таблиці:}. CurGridSolveCol:=CurColNum+HeadColNum+bc_LTaskColsBeforeVars;.
CurGridSolveRow:=CurRowNum+HeadRowNum+bc_LTaskRowsBeforeVars;
{Якщо поточна змінна
незалежна:}Self.
CurHeadRow[CurColNum].ElmType=bc_IndependentVar then{Перевіряємо, чи не
дійшли до рядка функції
(або взагалі за низ
таблиці):}CurRowNum<(Length
(Self. CurHeadCol) - 1) then{якщо рядки для виключення ще залишились:}
{Шукаємо ненульову
комірку серед коефіцієнтів поточної
незалежної змінної
(окрім останнього рядка, що є
рядком поточної функції
мети):}SearchNozeroSolveCell
(CurRowNum, CurColNum,(Self. CurHeadCol) - 2, Length (Self. CurHeadRow) - 2,,
HeadColNum, False) then{якщо змінну можна виключити:}(HeadColNum,
HeadRowNum);Self. Stop then Goto LStopLabel;
{Обробляємо таблицю
модифікованим Жордановим виключенням:}Not (Self.GI (CurColNum, CurRowNum, Self. CurHeadRow,. CurHeadCol,
Self. CurTable, ColDeleted, True,)) then:=False; Exit;;
:=False;
{Переходимо до
наступного рядка, бо даний рядок тепер вже є
рядком виключеної
вільної змінної (і змінна виражена як
функція-нерівність):}(CurRowNum);{якщо для незалежної змінної усі коефіцієнти
обмежень - нулі}{то змінна зовсім незалежна:}
{І якщо в рядку функції
мети теж нуль, то:}Self. CurTable
[Length(Self. CurHeadCol) - 1, CurColNum]=0 then{хоч змінна й незалежна, від
неї теж нічого тут не залежить:}Self. CurOutConsole<>Nil then:=sc_CurProcName+sc_FreeVar;Self.
CurHeadRow[CurColNum].ElmType=bc_Number then:=st1+sc_Space+(Self.
CurHeadRow[CurColNum].AsNumber)st1:=st1+sc_Space+sc_DoubleQuot+.
CurHeadRow[CurColNum].AsVarName+sc_DoubleQuot;
. CurOutConsole. Lines.
Add(st1);;
(HeadColNum,
HeadRowNum);Self. Stop then Goto LStopLabel;
{Видаляємо стовпець цієї
змінної:}(Self. CurHeadRow,
CurColNum, 1);(Self. CurTable, CurColNum, 1);:=True;
:=False;AllExcluded:=False;
{не усі вільні вдалося виключити};AllExcluded:=False; {не усі вільні
вдалося виключити};
Not(ColDeleted) then
Inc(CurColNum);; {While (CurColNum<(Length (Self. CurHeadRow) - 1)) do…}AllExcluded
or WasNothingToDo;
Not(AllExcluded)
thenSelf. CurOutConsole<>Nil then. CurOutConsole. Lines. Add
(sc_CurProcName+sc_CantExcludeFreeVars);. WriteTableToGrid (HeadColNum,
HeadRowNum, True);:=True; Exit;;
{Переміщаємо рядки з
усіма незалежними змінними вгору:}:=Self.
ShiftRowsUp([bc_IndependentVar], False);
Self.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add
(sc_CurProcName+sc_AllFreeVarsExcluded);
{Ховаємо розв'язувальну
комірку у екранній таблиці:}.
CurGridSolveCol:=0; Self. CurGridSolveRow:=0;
(HeadColNum,
HeadRowNum);Self. Stop then Goto LStopLabel;
{Якщо усі рядки є
рядками незалежних змінних, то номер найвищого рядка
іншого типу вважаємо
нижче таблиці (бо нема таких рядків):}HiNoIndepRow<0 then HiNoIndepRow:=Length (Self. CurHeadCol);
{Якщо після виключення
незалежних змінних не залишилося рядків, окрім
рядка функції:}HiNoIndepRow>=(Length (Self. CurHeadCol) - 1) thenSelf.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add
(sc_CurProcName+sc_NoTableAreaToWork);;
Self.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add
(sc_CurProcName+sc_ExcludingZeroRows);
{############## Виключаємо
0-рядки. Шукаємо їх: ##############}:=HiNoIndepRow;CurRowNum<=(Length
(Self. CurHeadCol) - 2) do:=False;Self. CurHeadCol[CurRowNum].ElmType=bc_Number
thenSelf. CurHeadCol[CurRowNum].AsNumber=0 then {якщо знайшли 0-рядок:}{Для
помітки 0-рядка на екранній таблиці:}. CurGridSolveCol:=HeadColNum;.
CurGridSolveRow:=CurRowNum+HeadRowNum+bc_LTaskRowsBeforeVars;
(HeadColNum,
HeadRowNum);Self. Stop then Goto LStopLabel;
{Перевіряємо вільний
член рядка, чи він невід'ємний.
Якщо від'ємний, то
множимо обидві частини рівняння на -1:}CurTable [CurRowNum, Length (Self. CurHeadRow) - 1]<0
then(CurRowNum);
{Шукаємо у рядку перший
додатний коефіцієнт:}CurColNum:=0
to Length (Self. CurHeadRow) - 2 doCurTable [CurRowNum, CurColNum]>0 then
Break;
CurColNum>(Length
(Self. CurHeadRow) - 2) then {Якщо усі недодатні:}CurTable [CurRowNum,
Length (Self. CurHeadRow) - 1]=0 then{Якщо вільний член рівний нулю, то
помножимо рівняння на -1:}(CurRowNum);
{Шукаємо у рядку перший
додатний коефіцієнт:}CurColNum:=0
to Length (Self. CurHeadRow) - 2 doCurTable [CurRowNum, CurColNum]>0 then
Break;
{Якщо знову додатних
нема, значить усі нулі. Видаляємо рядок:}CurColNum>(Length (Self. CurHeadRow) - 2) thenSelf.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add
(sc_CurProcName+sc_AllZeroInRow+_Space+IntToStr (CurRowNum+1));
(CurTable, CurRowNum,
1);(Self. CurHeadCol, CurRowNum, 1);. Continue; {переходимо одразу до
наступного рядка};{Якщо вільний член додатній, а коефіцієнти недодатні,
то
система несумісна:}Self. CurOutConsole<>Nil then. CurOutConsole. Lines. Add
(sc_CurProcName+sc_DoubleSpot+_Space+sc_NoVals);
. WasNoRoots:=True;.
WriteTableToGrid (HeadColNum, HeadRowNum, True);:=True; Exit;;;
{Якщо додатний
коефіцієнт у 0-рядку обрано, шукаємо МНВ
(мінімальне невід'ємне
серед відношень вільних членів до членів
стовпця, у якому обрали
цей коефіцієнт):}(CurColNum,
HiNoIndepRow, Length (Self. CurHeadCol) - 2,N, False);CurRow2N<0 then {Якщо
МНВ не знайдено:}. WriteTableToGrid (HeadColNum, HeadRowNum, True);:=False;
Exit;;
{Якщо МНВ знайдено:}. CurGridSolveCol:=CurColNum + HeadColNum+bc_LTaskColsBeforeVars;.
CurGridSolveRow:=CurRow2N + HeadRowNum+bc_LTaskRowsBeforeVars;(HeadColNum,
HeadRowNum);Self. Stop then Goto LStopLabel;
{Обробляємо таблицю
модифікованим Жордановим виключенням:}Not (Self.GI (CurColNum, CurRow2N, Self. CurHeadRow,. CurHeadCol,
Self. CurTable, ColDeleted, True,)) then:=False; Exit;;
CurRow2N<>CurRowNum
then {Якщо виключили не цей 0-рядок:}. Continue; {продовжуємо
працювати з цим рядком}; {If Self. CurHeadCol[CurRowNum].AsNumber=0
then…}; {If Self. CurHeadCol[CurRowNum].ElmType=bc_Number then…}Not(RowDeleted)
then Inc(CurRowNum);; {While CurRowNum<=(Length (Self. CurHeadCol) - 2)
do…}
Self.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add (sc_CurProcName+sc_AllZeroRowsExcluded);
{Ховаємо розв'язувальну
комірку у екранній таблиці:}.
CurGridSolveCol:=0; Self. CurGridSolveRow:=0;(HeadColNum, HeadRowNum); {відмічаємо
новий крок}Self. Stop then Goto LStopLabel;
Self.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add
(sc_CurProcName+sc_SearchingBaseSolve);
{############## Шукаємо
опорний розв'язок задачі: ##############}:=HiNoIndepRow;CurRowNum<=(Length (Self. CurHeadCol) - 2) do
{Якщо знайшли від'ємний
елемент у стовпці вільних членів:}Self.
CurTable [CurRowNum, Length (Self. CurHeadRow) - 1]<0 then
{Для помітки поточного
рядка на екранній таблиці:}.
CurGridSolveCol:=HeadColNum;.
CurGridSolveRow:=CurRowNum+HeadRowNum+bc_LTaskRowsBeforeVars;
(HeadColNum,
HeadRowNum);Self. Stop then Goto LStopLabel;
{Шукаємо у рядку перший
від'ємний коефіцієнт:}CurColNum:=0
to Length (Self. CurHeadRow) - 2 doCurTable [CurRowNum, CurColNum]<0 then
Break;
CurColNum>(Length
(Self. CurHeadRow) - 2) then {Якщо усі невід'ємні:}
{Якщо вільний член
від'ємний, а коефіцієнти невід'ємні, то
система несумісна:}Self. CurOutConsole<>Nil then. CurOutConsole. Lines. Add
(sc_CurProcName+sc_DoubleSpot+sc_Space+_NoVals);
. WasNoRoots:=True;.
WriteTableToGrid (HeadColNum, HeadRowNum, True);:=True; Exit;;
{Якщо від'ємний
коефіцієнт у рядку обрано, шукаємо МНВ
(мінімальне невід'ємне
серед відношень вільних членів до членів
стовпця, у якому обрали
цей коефіцієнт):}(CurColNum,
HiNoIndepRow, Length (Self. CurHeadCol) - 2,N, False);CurRow2N<0 then {Якщо
МНВ не знайдено:}. WriteTableToGrid (HeadColNum, HeadRowNum, True);:=False;
Exit;;
{Якщо МНВ знайдено:}. CurGridSolveCol:=CurColNum + HeadColNum+bc_LTaskColsBeforeVars;.
CurGridSolveRow:=CurRow2N + HeadRowNum+bc_LTaskRowsBeforeVars;
(HeadColNum,
HeadRowNum);Self. Stop then Goto LStopLabel;
{Обробляємо таблицю
модифікованим Жордановим виключенням:}Not (Self.GI (CurColNum, CurRow2N, Self. CurHeadRow,. CurHeadCol,
Self. CurTable, ColDeleted, True,)) then:=False; Exit;;
CurRow2N<>CurRowNum
then {Якщо виключили не цей рядок:}. Continue; {продовжуємо працювати
з цим рядком}; {If Self. CurTable [CurRowNum, Length (Self. CurHeadRow)
- 1]<0 then…}(CurRowNum);; {While CurRowNum<=(Length (Self.
CurHeadCol) - 2) do…}
Self.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add
(sc_CurProcName+sc_BaseSolveFound);
{Ховаємо розв'язувальну
комірку у екранній таблиці:}.
CurGridSolveCol:=0; Self. CurGridSolveRow:=0;(HeadColNum, HeadRowNum); {відмічаємо
новий крок}Self. Stop then Goto LStopLabel;
Self.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add (sc_CurProcName+sc_SearchingOptimSolve);
{############## Шукаємо
оптимальний розв'язок задачі: ##############}:=0;CurColNum<=(Length (Self. CurHeadRow) - 2) do:=False;
{Якщо знайшли від'ємний
коефіцієнт у рядку функції мети:}CurTable
[Length(Self. CurHeadCol) - 1, CurColNum]<0 then
{Шукаємо МНВ (мінімальне
невід'ємне серед відношень вільних членів
до членів стовпця, у
якому обрали цей коефіцієнт) серед усіх рядків
умов, окрім рядків
вільних змінних і рядка функції мети:}(CurColNum, HiNoIndepRow, Length (Self. CurHeadCol) - 2,N,
False);CurRow2N<0 then {Якщо МНВ не знайдено:}{то функція мети не
обмежена зверху, максимальне значення безмежне:}Self.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add
(sc_CurProcName+sc_DoubleSpot+sc_Space+_UnlimitedFunc);
. WasManyRoots:=True;.
WriteTableToGrid (HeadColNum, HeadRowNum, True);:=True; Exit;;
{Якщо МНВ знайдено:}. CurGridSolveCol:=CurColNum + HeadColNum+bc_LTaskColsBeforeVars;.
CurGridSolveRow:=CurRow2N + HeadRowNum+bc_LTaskRowsBeforeVars;
(HeadColNum,
HeadRowNum);Self. Stop then Goto LStopLabel;
{Обробляємо таблицю
модифікованим Жордановим виключенням:}Not (Self.GI (CurColNum, CurRow2N, Self. CurHeadRow,. CurHeadCol,
Self. CurTable, ColDeleted, True,)) then:=False; Exit;;
:=0; {після
виключення могли з'явитися нові від'ємні комірки}. Continue;;
Not(ColDeleted) then
Inc(CurColNum);;
{Якщо назва функції мети
вказана зі знаком «-», то це протилежна
функція мети. Змінимо
знаки у її рядку, і отримаємо шукану
мінімізацію функції:}:=Length (Self. CurHeadCol) - 1;ValSign (Self. CurHeadCol[CurRowNum])=bc_Negative
then(CurRowNum);. CurHeadCol[CurRowNum].ElmType:=bc_DestFuncToMin;;
Self.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add
(sc_CurProcName+sc_DoubleSpot+sc_Space+_ValFound);
.
ShowLTaskResultCalc(DualTaskVals);
. SolWasFound:=True;:=True;
{Ховаємо розв'язувальну
комірку у екранній таблиці:}.
CurGridSolveCol:=0; Self. CurGridSolveRow:=0;(HeadColNum, HeadRowNum);
;:Self.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add (sc_CurProcName +
sc_SolvingStopped);
. CurGridSolveCol:=0;
Self. CurGridSolveRow:=0;
:=False;;;
TGridFormattingProcs.
EditLineEqsOnNewRow (Sender: TObject;: array of Integer);
{Підтримує форматування
стовпця нумерації таблиці у такому вигляді:
…}CurNum: Integer; CurGrid:TStringGrid;Sender=Nil then Exit;
{Якщо до вмикання
форматування був якийсь обробник події, запускаємо його:}@Self. OldOnNewRow<>Nil then Self. OldOnNewRow (Sender,
NewRows);
Sender is TStringGrid
then:=TStringGrid(Sender);CurNum:=0 to Length(NewRows) - 1 do
{Нумерація з третього
рядка, бо два перших - заголовки:}NewRows[CurNum]>=(Self.CHeadRowNum+1)
then. Cells [0, NewRows[CurNum]]:=IntToStr
(NewRows[CurNum]-.CHeadRowNum);;;;;TGridFormattingProcs. EditLineEqsOnNewCol
(Sender: TObject;: array of Integer);
{Підтримує форматування
рядка нумерації та рядка-заголовка таблиці у
такому вигляді:
2 3 4 5… n n+1x2 x3 x4
x5… xn 1
}CurNum: Integer; CurGrid:TStringGrid;: String;Sender=Nil then
Exit;
{Якщо до вмикання
форматування був якийсь обробник події, запускаємо його:}@Self. OldOnNewCol<>Nil then Self. OldOnNewCol (Sender,
NewCols);
Sender is TStringGrid
then:=TStringGrid(Sender);CurNum:=0 to Length(NewCols) - 1 do
{Заголовки лише для
комірок, які можна редагувати:}NewCols[CurNum]>=(Self.CHeadColNum+1)
then:=IntToStr (NewCols[CurNum] - Self.CHeadColNum);. Cells [NewCols[CurNum],
0]:=CurColNumStr;
{Останній стовпець -
числа у правих частинах рівнянь:}(NewCols[CurNum]+1)=CurGrid.
ColCount then. Cells [NewCols[CurNum], 1]:=sc_RightSideValsHdr
{в усіх інших -
коефіцієнти при змінних X1…Xn:}. Cells
[NewCols[CurNum], 1]:=sc_XVarName+CurColNumStr;;;
Length(NewCols)>0
then
{Якщо перед оновленими
або новими стовпцями були інші стовпці, то
в останному з них
оновлюємо підпис: тепер він буде з іменем змінної
(«xn»), а не з іменем
стовпця правих частин рівнянь (a).
(Тут покладаємося на те,
що номери оновлених стовпців сортовані
за зростанням):}NewCols[0]>(Self.CHeadColNum+1) then. Cells [NewCols[0] - 1,
1]:=sc_XVarName+IntToStr (NewCols[0]-
(Self.CHeadColNum+1));{Якщо
нових стовпців немає (тобто кількість стовпців зменшилася):}{Оновлюємо підпис
останнього стовпця (праві частини рівнянь):}. Cells [CurGrid. ColCount-1,
1]:=sc_RightSideValsHdr;;;;
TGridFormattingProcs.
EditLineEqsOnDrawCell (Sender: TObject; ACol,: Integer; Rect: TRect; State:
TGridDrawState);
{Процедура виконується
при малюванні кожної комірки StringGrid
у режимі набору вхідних
даних системи лінійних рівнянь.
Зафарбовує в інший колір
останній стовпець - стовпець
правих частин рівнянь.}CurGrid:TStringGrid; SafeBrushColor:TColor;Sender=Nil then Exit;
{Якщо до вмикання
форматування був якийсь обробник події, запускаємо його:}@Self. OldOnDrawCell<>Nil then Self. OldOnDrawCell (Sender,
ACol, ARow, Rect,);
Sender is TStringGrid
then:=TStringGrid(Sender);:=CurGrid. Canvas. Brush. Color;
{Комірки останнього
стовпця є стовпцем правих сторін рівнянь.
Фарбуємо їх у блакитний
колір (окрім комірок заголовка):}(ACol>=(CurGrid.
ColCount-bc_LineEqM2ColsAfterVars)) and
(Not (gdFixed in State))
then. Canvas. Brush. Color:=lwc_RightSideColColor;
{Малюємо текст на фоні з
кольором Brush:}. Canvas. TextRect
(Rect, Rect. Left, Rect. Top,. Cells [ACol, ARow]);;
. Canvas. Brush.
Color:=SafeBrushColor;;;
TGridFormattingProcs.
SolveLineEqsM1OrM2OnDrawCell (Sender: TObject;, ARow: Integer; Rect: TRect;
State: TGridDrawState);
{Процедура фарбує
комірки (їхній фон) таблиці вирішування системи лінійних
рівнянь у стовпці правих
частин (вільних членів). У залежності від
методу розв'язання цей
стопець може бути першим стовпцем-заголовком
(1-ий спосіб, з
отриманням оберненої матриці коефіцієнтів), або останнім
стовпцем (2-ий спосіб, з
отриманням нулів у рядку-заголовку і видаленням
стовпців цих нулів).}CurGrid:TStringGrid; SafeBrushColor:TColor;
CurColor:TColor;Sender=Nil then Exit;
{Якщо до вмикання
форматування був якийсь обробник події, запускаємо його:}@Self. OldOnDrawCell<>Nil then Self. OldOnDrawCell (Sender,
ACol, ARow, Rect,);
Sender is TStringGrid
then:=TStringGrid(Sender);:=CurGrid. Canvas. Brush. Color;:=bc_NotColored;
Not (gdFixed in State)
then {якщо комірка не у заголовках StringGrid}
{У режимі розв'язування
способом 1 відмічаємо перший стовпець
кольором, а у режимі
способу 2 - відмічаємо останній
(стовпець правих частин
- вільних членів):}((Self.
CurFormatState=fs_SolvingEqsM1) and
(ACol<(Self.CHeadColNum+bc_LineEqM1ColsBeforeVars)))
or
((Self.
CurFormatState=fs_SolvingEqsM2) and
(ACol>=(CurGrid.
ColCount-bc_LineEqM2ColsAfterVars))) then:=lwc_RightSideColColor
{Якщо це комірка
коефіцієнта при змінній, і задача у ході вирішування:}if InSolving thenSelf. CurGridSolveCol=ACol then {якщо це
розв'язувальний стовпець:}Self. CurGridSolveRow=ARow then {якщо це
розв'язувальна комірка:}:=lwc_SolveCellColorCurColor:=lwc_SolveColColor;{Якщо
це розв'язувальний рядок (але не розв'язувальна комірка):}if Self.
CurGridSolveRow=ARow then CurColor:=lwc_SolveRowColor;;;
CurColor<>bc_NotColored
then {якщо комірку треба пофарбувати:}{Малюємо текст на фоні з кольором
CurColor:}. Canvas. Brush. Color:=CurColor;. Canvas. TextRect (Rect, Rect.
Left, Rect. Top,. Cells [ACol, ARow]);;
. Canvas. Brush.
Color:=SafeBrushColor;;;
TGridFormattingProcs.
EdLineTaskOnNewRow (Sender: TObject;: array of Integer);
{Процедура працює при
виникненні події оновлення рядка чи додавання нового
рядка у
GrowingStringGrid.
Підтримує форматування
стовпця нумерації і стовпця-заголовка таблиці у
такому вигляді:
y1
y2
y3
y4
y5
…ym
Стовпець-заголовок (нові
комірки стовпця-заголовка за змовчуванням
заповнюються значеннями
типу «функції-нерівності»).}CurNum,
CurTableRow: Integer; CurGrid:TStringGrid;Sender=Nil then Exit;
{Якщо до вмикання
форматування був якийсь обробник події, запускаємо його:}@Self. OldOnNewRow<>Nil then Self. OldOnNewRow (Sender,
NewRows);
Sender is TStringGrid
then:=TStringGrid(Sender);
{Освіжаємо масив
стовпця-заголовка відповідно до висоти таблиці:}(CurGrid, NewRows);
{Відображаємо заголовки
оновлених або нових рядків:}CurNum:=0
to Length(NewRows) - 1 do
{Нумерація з першого
рядка, що не є рядком заголовків:}NewRows[CurNum]>=(Self.CHeadRowNum+1)
then{Нумерація рядків:}. Cells [Self.CHeadColNum-1,
NewRows[CurNum]]:=(NewRows[CurNum] - Self.CHeadRowNum);
{Заголовки із масиву
стовпця-заголовка:}:=NewRows[CurNum] -
Self.CHeadRowNum-bc_LTaskRowsBeforeVars;. Cells [Self.CHeadColNum,
NewRows[CurNum]]:=(Self. CurHeadCol[CurTableRow]);;;
{Якщо нові або змінені
рядки були, то вважаємо таблицю зміненою:}Length(NewRows)>0 then Self. CurGridModified:=True;;;
TGridFormattingProcs.
EdLineTaskOnNewCol (Sender: TObject;: array of Integer);
{Підтримує форматування
рядка нумерації та рядка-заголовка таблиці у
такому вигляді:
2 3 4 5… n n+1x1 x2 x3
x4… xn 1
}CurNum, CurTableCol: Integer; CurGrid:TStringGrid;Sender=Nil then
Exit;
{Якщо до вмикання
форматування був якийсь обробник події, запускаємо його:}@Self. OldOnNewCol<>Nil then Self. OldOnNewCol (Sender,
NewCols);
Sender is TStringGrid
then:=TStringGrid(Sender);
{Освіжаємо масив поміток
залежності змінних x:}.
UpdateLTaskHeadRowToStrGrid(CurGrid);
{Відображаємо заголовки
оновлених або нових стовпців:}CurNum:=0
to Length(NewCols) - 1 do
{Заголовки лише для
комірок, які можна редагувати:}NewCols[CurNum]>=Self.CHeadColNum
then{Нумерація стовпців:}. Cells [NewCols[CurNum],
Self.CHeadRowNum-1]:=(NewCols[CurNum] - Self.CHeadColNum);
{Заголовки із масиву
рядка-заголовка:}:=NewCols[CurNum] -
Self.CHeadColNum-bc_LTaskColsBeforeVars;. Cells [NewCols[CurNum],
Self.CHeadRowNum]:=(Self. CurHeadRow[CurTableCol]);;;
Length(NewCols)>0
then
{Якщо нові або змінені
стовпці були, то вважаємо таблицю зміненою:}. CurGridModified:=True;
{Якщо перед оновленими
або новими стовпцями були інші стовпці, то
в останному з них
оновлюємо підпис: тепер він буде з іменем змінної
(«xn») або, якщо це
перший стовпець-то з підписом стовпця імен
функцій та констант
рівнянь.
(Тут покладаємося на те,
що номери оновлених стовпців сортовані
за зростанням):}NewCols[0]>Self.CHeadColNum+bc_LTaskColsBeforeVars
then:=NewCols[0] - 1-Self.CHeadColNum-bc_LTaskColsBeforeVars;
. Cells [NewCols[0] - 1,
Self.CHeadRowNum]:=(Self. CurHeadRow[CurTableCol]);;{Якщо нових стовпців
нема (кількість стовпців зменшилася):}
{відображаємо останню
(найправішу) комірку}. Cells
[CurGrid. ColCount-1, 1]:=(Self. CurHeadRow [CurGrid.
ColCount-1-.CHeadColNum-bc_LTaskColsBeforeVars]);;;
TGridFormattingProcs.
NumerationOnNewRow (Sender: TObject;: array of Integer);
{Процедура працює при
виникненні події оновлення рядка чи додавання нового
рядка у
GrowingStringGrid.
такому вигляді:
…}CurNum: Integer; CurGrid:TStringGrid;Sender=Nil then Exit;
{Якщо до вмикання
форматування був якийсь обробник події, запускаємо його:}@Self. OldOnNewRow<>Nil then Self. OldOnNewRow (Sender,
NewRows);
Sender is TStringGrid
then:=TStringGrid(Sender);
CurNum:=0 to
Length(NewRows) - 1 do
{Нумерація з першого
рядка, що не є рядком заголовків:}NewRows[CurNum]>=(Self.CHeadRowNum+1)
then. Cells [0, NewRows[CurNum]]:=(NewRows[CurNum] - Self.CHeadRowNum);; {For
CurNum:=0 to Length(NewRows) - 1 do…}; {If Sender is TStringGrid then…};
TGridFormattingProcs.
NumerationOnNewCol (Sender: TObject;: array of Integer);
{Процедура працює при
виникненні події оновлення чи додавання нового
стовпця у
GrowingStringGrid.
Підтримує форматування
рядка нумерації таблиці у такому вигляді:
2 3 4 5… n}CurNum: Integer; CurGrid:TStringGrid;Sender=Nil then Exit;
{Якщо до вмикання
форматування був якийсь обробник події, запускаємо його:}@Self. OldOnNewCol<>Nil then Self. OldOnNewCol (Sender,
NewCols);
Sender is TStringGrid
then:=TStringGrid(Sender);CurNum:=0 to Length(NewCols) - 1 do
{Заголовки лише для
нефіксованих комірок:}NewCols[CurNum]>=(Self.CHeadColNum+1)
then. Cells [NewCols[CurNum], 0]:=(NewCols[CurNum] - Self.CHeadColNum);;;;
TGridFormattingProcs.
UpdateLTaskHeadRowToStrGrid (SGrid:TStringGrid);
{Процедура для підтримки
масиву рядка-заголовка під час редагування
таблиці. Встановлює
довжину масиву відповідно до ширини екранної таблиці
і координат вписування в
неї таблиці задачі, заповнює нові комірки
значеннями за
змовчуванням, а також змінює останню комірку перед новими.}CurLTaskVarCount, OldCount, CurVarMark: Integer;
{Кількість стовпців для
коефіцієнтів змінних у таблиці:}:=SGrid.
ColCount-Self.CHeadColNum-_LTaskColsBeforeVars {-bc_LTaskColsAfterVars};
{Якщо таблиця має надто
малу ширину, то нічого тут не робимо:}CurLTaskVarCount<0 then Exit;
{Масив видовжуємо до
кількості стовпців у StringGrid, у яких
редагуємо коєфіцієнти
при змінних:}:=Length (Self.
CurHeadRow);OldCount<>CurLTaskVarCount then(Self. CurHeadRow,
CurLTaskVarCount); {змінюємо довжину}
{Заповнюємо нові
елементи масиву значеннями за змовчуванням:
вільні змінні:}CurVarMark:=OldCount to CurLTaskVarCount-2 do.
CurHeadRow[CurVarMark].ElmType:=bc_IndependentVar;.
CurHeadRow[CurVarMark].VarInitInRow:=True;. CurHeadRow[CurVarMark].VarInitPos:=CurVarMark;.
CurHeadRow[CurVarMark].AsVarName:=sc_XVarName+IntToStr (CurVarMark+1);;
{Останній елемент є
числом, а не змінною: це множник стовпця
вільних членів (правих
частин):}CurLTaskVarCount>0
then. CurHeadRow [CurLTaskVarCount-1].ElmType:=bc_Number;. CurHeadRow
[CurLTaskVarCount-1].AsNumber:=1;
{Колишній останній
елемент тепер буде змінною:}(OldCount>0)
and (OldCount<CurLTaskVarCount) then. CurHeadRow
[OldCount-1].ElmType:=bc_IndependentVar;. CurHeadRow
[OldCount-1].AsVarName:=sc_XVarName+IntToStr(OldCount);;;;
TGridFormattingProcs.
UpdateLTaskHeadColToStrGrid (SGrid:TStringGrid;: array of Integer);
{Процедура для підтримки
масиву стовпця-заголовка під час редагування
таблиці. Встановлює
довжину масиву відповідно до висоти екранної таблиці
і координат вписування в
неї таблиці задачі, заповнює нові комірки
значеннями за
змовчуванням.
Вхідні дані:- екранна
таблиця, під яку треба настроїти масив;- масив номерів рядків таблиці, що були
додані чи змінені
(що зазнали змін з часу
останнього виклику цієї процедури під час
редагування).}CurHeight, OldHeight, CurRow: Integer;FillWithDefVal (SElmNum:
Integer);. CurHeadCol[SElmNum].ElmType:=bc_FuncVal;.
CurHeadCol[SElmNum].VarInitInRow:=False;.
CurHeadCol[SElmNum].VarInitPos:=SElmNum;. CurHeadCol[SElmNum].AsVarName:=sc_YFuncName+(SElmNum+1);;{Висота
таблиці за поточною висотою екранної таблиці:}:=SGrid.
RowCount-Self.CHeadRowNum-bc_LTaskRowsBeforeVars;:=Length (Self. CurHeadCol); {попередня
висота таблиці}(OldHeight<>CurHeight) and (CurHeight>=0) then
{Змінюємо довжину масиву
стовпця-заголовка:}(Self. CurHeadCol,
CurHeight);
CurRow:=OldHeight to
CurHeight-1 do(CurRow); {заповнюємо нові комірки за змовчуванням};;
TGridFormattingProcs.
EdLineTaskOnDrawCell (Sender: TObject; ACol,: Integer; Rect: TRect; State:
TGridDrawState);
{Процедура виконується
при малюванні кожної комірки StringGrid.
Зафарбовує в інший колір
фону комірок:
перший стовпець комірок
(стовпець-заголовок таблиці задачі лінійного
програмування). Комірки
цього стовпця зафарбовуються відповідно до типів
елементів у масиві
стовпця-заголовка (якщо цей масив створений для цих
комірок, інакше - за
змовчуванням: кольором назв функцій умов-нерівностей,
і найнижчу комірку -
кольором для назви функції мети);
останній стовпець
(стовпець значень правих сторін рівнянь або
нерівностей та комірка
значення цільової функції);
найнижчий рядок (рядок
коефіцієнтів цільової функції);
відмічає кольором
комірки-заголовки стовпців коефіцієнтів змінних
за відмітками про
залежність змінних (рядок-заголовок таблиці задачі ЛП).}CurGrid:TStringGrid; SafeBrushColor:TColor;:THeadLineElmType;
CurColor:TColor;: Integer;
Sender=Nil then Exit;
{Якщо до вмикання
форматування був якийсь обробник події, запускаємо його:}@Self. OldOnDrawCell<>Nil then Self. OldOnDrawCell (Sender,
ACol, ARow, Rect,);
:=ARow -
(Self.CHeadRowNum+bc_LTaskRowsBeforeVars);Sender is TStringGrid
then:=TStringGrid(Sender);:=CurGrid. Canvas. Brush. Color;:=bc_NotColored;
{Комірки останнього
стовпця є стовпцем правих сторін рівнянь.
Фарбуємо їх у блакитний
колір (окрім комірок заголовків):}Not
(gdFixed in State) then {якщо комірка не у заголовках StringGrid}ACol>=(CurGrid.
ColCount-bc_LTaskColsAfterVars) then {останні стовпці:}
{Якщо це комірка
значення цільової функції - для неї свій колір:}Self. CurHeadCol[ArrRowNum].ElmType of_DestFuncToMax:
CurColor:=lwc_DestFuncValColor;_DestFuncToMin:
CurColor:=lwc_DestFuncValColor;CurColor:=lwc_RightSideColColor;;if
ACol<(Self.CHeadColNum+bc_LTaskColsBeforeVars) then{Якщо перші стовпці
(стовпець-заголовок):}
{Якщо для цієї комірки
задано елемент у масиві стовпця-заголовка,
то фарбуємо її залежно
від типу цього елемента:}Length
(Self. CurHeadCol)>
(ARow -
(Self.CHeadRowNum + bc_LTaskRowsBeforeVars)) then{Тип елемента у комірці:}:=Self.
CurHeadCol [ARow - (Self.CHeadRowNum+_LTaskRowsBeforeVars)].ElmType;:=GetColorByElmType(CurVarColState);
{колір за типом}{Якщо масив стовпця-заголовка не визначено для комірки -
фарбуємо за змовчуванням
- як назву функції умови-нерівності:}:=lwc_HeadColColor;{Якщо
рядок коефіцієнтів при змінних цільової функції:}if (Self.
CurHeadCol[ArrRowNum].ElmType=bc_DestFuncToMax) or
(Self.
CurHeadCol[ArrRowNum].ElmType=bc_DestFuncToMin) then
{Якщо рядок функції
виділений, то виділяємо кольором:}InSolving
and (Self. CurGridSolveRow=ARow) then:=lwc_SolveRowColorCurColor:=lwc_FuncRowColor;
{інакше - колір рядка функції мети}{Якщо це розв'язувальна комірка, чи рядок
або стовпець з такою
коміркою, і треба
відображати хід вирішування задачі:}if
InSolving thenSelf. CurGridSolveCol=ACol then {якщо це розв'язувальний
стовпець:}Self. CurGridSolveRow=ARow then {якщо це розв'язувальна
комірка:}:=lwc_SolveCellColorCurColor:=lwc_SolveColColor;{Якщо це
розв'язувальний рядок (але не розв'язувальна комірка):}if Self.
CurGridSolveRow=ARow then CurColor:=lwc_SolveRowColor;;;
{Зафарбовуємо
комірки-заголовки стовпців коефіцієнтів при змінних
відповідно до масиву
поміток про залежність:}(ARow=Self.CHeadRowNum)
and
(Not
(ACol<(Self.CHeadColNum+bc_LTaskColsBeforeVars))) then:=Self. CurHeadRow
[ACol - Self.CHeadColNum-_LTaskColsBeforeVars].ElmType;:=GetColorByElmType(CurVarColState);
CurColor<>bc_NotColored
then {якщо комірку треба пофарбувати:}{Малюємо текст на фоні з кольором
CurColor:}. Canvas. Brush. Color:=CurColor;. Canvas. TextRect (Rect, Rect.
Left, Rect. Top,. Cells [ACol, ARow]);;
. Canvas. Brush.
Color:=SafeBrushColor;;;
TGridFormattingProcs.
EdLineTaskOnDblClick (Sender: TObject);
{Процедура реагує на
подвійне натискання лівою кнопкою миші на
комірки рядка-заголовка
таблиці (другий рядок StringGrid).
Редагує масив позначок
про обрані стовпці (SipmlexVarsDependencyRec)
залежних змінних.
Залежні змінні - це змінні, для яких є умова
невід'ємності. Тобто
вони не повинні бути менше нуля.}CurGrid:TStringGrid;
CurCol, CurRow: Integer;:TPoint;Sender=Nil then Exit;
{Якщо до вмикання
форматування був якийсь обробник події, запускаємо його:}@Self. OldOnDblClick<>Nil then Self. OldOnDblClick(Sender);
Sender is TStringGrid
then:=TStringGrid(Sender);
{Пробуємо узнати, на яку
комірку двічі натиснула миша:}:=CurGrid.
ScreenToClient (Mouse. CursorPos);:=-1; CurRow:=-1;. MouseToCell
(MouseCoordsInGrid.X, MouseCoordsInGrid.Y, CurCol, CurRow);
{Якщо натиснуто на
комірку-заголовок стовпця коефіцієнтів при змінній, то:}((CurCol>=(Self.CHeadColNum+bc_LTaskColsBeforeVars)) and
(CurCol<(CurGrid. ColCount-bc_LTaskColsAfterVars)))
and
(CurRow=Self.CHeadRowNum)
then
{Змінюємо ознаку
залежності відповідної змінної:}CurHeadRow
[CurCol - Self.CHeadColNum-_LTaskColsBeforeVars].ElmType=bc_IndependentVar
then[CurCol - Self.CHeadColNum-_LTaskColsBeforeVars].ElmType:=bc_DependentVar[CurCol
- Self.CHeadColNum-_LTaskColsBeforeVars].ElmType:=bc_IndependentVar;
{Задаємо перемалювання
комірок, щоб відобразилася зміна позначки
для змінної:}. Invalidate;;;;
TGridFormattingProcs.
InitGridPopupMenu (SGrid:TStringGrid);
{Процедура перевіряє
наявність об'єкта TPopupMenu. Якщо його немає
(SGrid. PopupMenu=Nil),
то створює новий.
Видаляє усі пунтки
(елементи, теми) з меню.}SGrid.
PopupMenu=Nil then. PopupMenu:=TPopupMenu. Create(Application);;. PopupMenu.
AutoPopup:=False;. PopupMenu. Items. Clear;;
TGridFormattingProcs.
ProcOnCellTypeSelInMenu (Sender: TObject);
{Обробник вибору пункту
в меню типів для комірки
рядка - чи
стовпця-заголовка.}sc_CurProcName='ProcOnCellTypeSelInMenu';ReportUnsupportedCell;
{Відображає координати
комірки з повідомленням про те, що вона
не підтримується:}Self. CurOutConsole<>Nil then. CurOutConsole. Lines. Add
(sc_CurProcName + sc_NoCellOrNotSupported+
' ['+IntToStr (Self.
CurGridSolveCol)+';'+IntToStr (Self. CurGridSolveRow)+
']… ');;;CurMenuItem:TMenuItem;
TypeForCell:THeadLineElmType;(Sender=Nil) or (Not (Sender is TMenuItem))
thenSelf. MemoForOutput<>Nil then. MemoForOutput. Lines. Add
(sc_CurProcName + sc_CantDetMenuItem);;;
{Читаємо тип, що обраний
для комірки:}:=TMenuItem(Sender);:=THeadLineElmType
(CurMenuItem. Tag);
(Self.
CurGridSolveCol<0) and (Self. CurGridSolveRow<0) then{якщо комірка
вище чи лівіше заголовків таблиці:}; Exit;;
{Перевіряємо координати
комірки і змінюємо її тип:}
{координати комірки
мають бути записані у CurGridSolveRow і CurGridSolveCol:}Self. CurGridSolveRow=-bc_LTaskRowsBeforeVars then{якщо це
комірка рядка-заголовка:}Length (Self. CurHeadRow)>Self. CurGridSolveCol
then {якщо комірка існує:}{задаємо тип комірки:}. CurHeadRow [Self.
CurGridSolveCol].ElmType:=TypeForCell;{якщо в рядку-заголовку немає такої
комірки:}; Exit;;if Self. CurGridSolveCol=-bc_LTaskColsBeforeVars then{якщо
це комірка стовпця-заголовка:}Length (Self. CurHeadCol)>Self.
CurGridSolveRow then {якщо комірка існує:}{задаємо тип комірки:}. CurHeadCol
[Self. CurGridSolveRow].ElmType:=TypeForCell;{якщо в стовпці-заголовку немає
такої комірки:}; Exit;;{якщо комірка у таблиці коефіцієнтів або правіше
чи нижче неї:}; Exit;;
{Якщо тип комірки
змінено, то перемальовуємо екранну таблицю для
відображення нового типу
комірки:}Self. CurGrid<>Nil
then Self. CurGrid. Invalidate;;
TGridFormattingProcs.
AddCellTypeItemToMenu (SMenu:TPopupMenu;: String; IsCurrentItem: Boolean;
SAssocType:THeadLineElmType;: Boolean=True);
{Додає пункт меню для
вибору типу комірки в таблиці з заданим
написом SCaption і
кругом того кольору, що асоційований з даним
типом SAssocType. Для
нового пункту меню настроює виклик процедури обробки
комірки для задавання їй
обраного типу SAssocType. Значення SAssocType
записує у поле Tag об'єкта
пункту меню.
Вхідні дані:- контекстне
меню для комірки, що формується;- підпис для пункту меню (назва типу комірки);-
ознака того, що даний пункт меню має бути поточним
(ввімкненим, відміченим)
- що це поточний тип комірки;- тип комірки, що прив'язаний до цього пункта
меню, і буде
присвоєний комірці при
виборі цього пункту;- вмикач настройки виклику процедури задавання нового
типу комірки (при виборі
елемента меню). При ToSetReactOnClick=False
це не виконується, і
натискання елемента меню не викликає ніяких дій.}CurMenuItem:TMenuItem;:TColor;SMenu=Nil then Exit; {якщо меню
не задано - елемент не додаємо в нього}
{Створюємо новий тункт
меню:}:=TMenuItem.
Create(Application);
{Отримуємо колір для
даного типу комірки:}:=Self.
GetColorByElmType(SAssocType);
{Біля тексту малюємо
круг такого кольору, який асоційований
з типом комірки, і буде
присвоєний їй у разі вибору цього пунтку
меню:}. Bitmap. Height:=bc_MenuItemColorCircleDiameter;. Bitmap.
Width:=bc_MenuItemColorCircleDiameter;. Bitmap. Canvas. Pen. Color:=SAssocColor;.
Bitmap. Canvas. Brush. Color:=SAssocColor;. Bitmap. Canvas. Ellipse
(CurMenuItem. Bitmap. Canvas. ClipRect);
{0 - картинка задана у
самому об'єкті, а не в SMenu. Images:}. ImageIndex:=0;. RadioItem:=True; {промальовувати перемикач,
якщо не буде картинки}
{Текст пункту меню:}. Caption:=SCaption;
.
Checked:=IsCurrentItem;
ToSetReactOnClick then {якщо
обробка вибору елемента меню ввімкнена}
{Тип для комірки у
випадку вибору цього пунтку меню:}.
Tag:=Integer(SAssocType);
{Процедура-обробник вибору
пункта меню:}. OnClick:=Self.
ProcOnCellTypeSelInMenu;. AutoCheck:=True;;
. Items.
Add(CurMenuItem);;
(* {Ідентифікатор для
типу елемента масиву чисел та імен змінних.
Типи змінних: залежні,
незалежні, функції (умови-нерівності).
Залежні змінні - це змінні,
для яких діє умова невід'ємності:}=(bc_IndependentVar,
bc_DependentVar, bc_FuncVal, bc_Number,_DestFuncToMax);}
*)TGridFormattingProcs. EdLineTaskOnMouseUp (Sender: TObject;: TMouseButton;
Shift: TShiftState; X, Y: Integer);
{Процедура реагує на
відпускання правої кнопки миші на
комірках рядка-заголовка
та стовпця-заголовка таблиці.
Формує та відкриває
контекстне меню для вибору типу комірки із можливих
типів для цієї комірки.}sc_CurProcName='EdLineTaskOnMouseUp';CurCol, CurRow, ArrayRow,
ArrayCol: Integer; CurElmType:THeadLineElmType;:TPoint;
{Якщо до вмикання
форматування був якийсь обробник події, запускаємо його:}@Self. OldOnMouseUp<>Nil then Self. OldOnMouseUp (Sender,
Button, Shift, X, Y);
Sender=Nil then Exit;
{Якщо задано екранну
таблицю даного об'єкта TGridFormattingProcs:}Sender = Self. CurGrid thenButton=mbRight then {якщо була
відпущена права кнопка миші}
{Пробуємо узнати, на яку
комірку натиснула миша:}:=-1;
CurRow:=-1;. CurGrid. MouseToCell (X, Y, CurCol, CurRow);:=Self. CurGrid.
ClientToScreen (Point(X, Y));
{Координати комірки у
масивах таблиці і її заголовків:}:=CurRow-Self.CHeadRowNum-bc_LTaskRowsBeforeVars;:=CurCol-Self.CHeadColNum-bc_LTaskColsBeforeVars;
{Якщо натиснуто на
комірку рядка-заголовка:}(CurRow=Self.CHeadRowNum)
and (ArrayCol>=0) and
(ArrayCol<Length
(Self. CurHeadRow)) then{очищаємо меню перед заповненням:}.
InitGridPopupMenu (Self. CurGrid);
{Якщо в екранній таблиці
були зміни з часу останнього її читання,
то читаємо комірку, для
якої треба сформувати меню:}Self.
CurGridModified then Self. ReadHeadRowCell(ArrayCol);
{Читаємо поточний тип
комірки:}:=Self.
CurHeadRow[ArrayCol].ElmType;
{Додаємо пункти меню:}
{Якщо в комірці число-то
тип комірки може бути тільки числовий:}CurElmType=bc_Number then. AddCellTypeItemToMenu (Self. CurGrid.
PopupMenu,_ValInHeadColOrRow, True, CurElmType){якщо в комірці не число:}
{незалежна змінна:}. AddCellTypeItemToMenu (Self. CurGrid.
PopupMenu,_IndependentVar,= bc_IndependentVar, bc_IndependentVar);
{залежна змінна:}. AddCellTypeItemToMenu (Self. CurGrid. PopupMenu,_DependentVar,=
bc_DependentVar, bc_DependentVar);;If (CurCol=Self.CHeadColNum) and
(ArrayRow>=0) and
(ArrayRow<Length
(Self. CurHeadCol)) then{якщо натиснуто на комірку стовпця-заголовка:}.
InitGridPopupMenu (Self. CurGrid);
{Якщо в екранній таблиці
були зміни з часу останнього її читання,
то читаємо комірку, для
якої треба сформувати меню:}Self.
CurGridModified then Self. ReadHeadColCell(ArrayRow);
{Читаємо поточний тип
комірки:}:=Self.
CurHeadCol[ArrayRow].ElmType;
{Додаємо пункти меню:}
{Якщо в комірці число-то
тип комірки може бути тільки числовий:}CurElmType=bc_Number then. AddCellTypeItemToMenu (Self. CurGrid.
PopupMenu,_ValInHeadColOrRow, True, CurElmType){якщо в комірці не число:}
{назва фінкції - рядка
нерівності:}. AddCellTypeItemToMenu
(Self. CurGrid. PopupMenu,_InequalFuncName, CurElmType = bc_FuncVal,
bc_FuncVal);
{назва функції мети, що
максимізується:}.
AddCellTypeItemToMenu (Self. CurGrid. PopupMenu,_DestFuncToMaxName, CurElmType
= bc_DestFuncToMax,_DestFuncToMax);
{назва функції мети, що
мінімізується:}.
AddCellTypeItemToMenu (Self. CurGrid. PopupMenu,_DestFuncToMinName, CurElmType
= bc_DestFuncToMin,_DestFuncToMin);;{якщо для даної комірки вибір типу не
передбачено}{ставимо в меню координати комірки
(щоб користувач взагалі
помітив, що меню є…)}.
InitGridPopupMenu (Self. CurGrid);. AddCellTypeItemToMenu (Self. CurGrid.
PopupMenu,_Row+sc_DoubleSpot+sc_Space+IntToStr
(ArrayRow+1)+sc_KrKm+_Space+sc_Col+sc_DoubleSpot+sc_Space+IntToStr
(ArrayCol+1),, bc_OtherType);;
{Записуємо координати
комірки для обробника вибору типу з меню:}. CurGridSolveCol:=ArrayCol;. CurGridSolveRow:=ArrayRow;
{Відображаємо меню:}. CurGrid. PopupMenu. Popup (MouseScrCoords.X, MouseScrCoords.Y);;
{If Button=mbRight then…}{If Sender = Self. CurGrid then…}{якщо обробник
викликала «чужа» таблиця або невідомий об'єкт:}Self.
CurOutConsole<>Nil then. CurOutConsole. Lines. Add
(sc_CurProcName+sc_UnknownObjectCall+_DoubleQuot+Sender.
ClassName+sc_DoubleQuot);;;
TGridFormattingProcs.
ReactOnSetEditText (Sender: TObject; ACol,: Longint; const Value: string);
{Процедура для
реагування на редагування вмісту комірок
під час редагування
вхідних даних. Встановлює прапорець:=True про те, що екранна таблиця має зміни.}
{Старий обробник теж
викликаємо, якщо він є:}@Self.
OldOnSetEditText<>Nil then. OldOnSetEditText (Sender, ACol, ARow, Value);
.
CurGridModified:=True;;
TGridFormattingProcs.
SetNewState (Value:TTableFormatState);sc_CurProcName='SetNewState';StateSafe:TTableFormatState;,
OldHRowPos: Integer;
{Процедура для зміни
режиму форматування GrowingStringGrid}GoSolveLTask;{Вирішування задачі ЛП симплекс-методом:}.
ColCount:=bc_FixedCols+1;. RowCount:=bc_FixedRows+1;. FixedRows:=bc_FixedRows;.
FixedCols:=bc_FixedCols;
Not (Self.
PrepareToSolveLTask) then{Якщо не вдається підготувати таблицю до
вирішування задачі:}:=Self. CurFormatState;
{Перемикаємо на режим
fs_NoFormatting, і назад у поточний,
щоб встановити усі
настройки цього режиму (повернутися до них):}. TableFormatState:=fs_NoFormatting;.
TableFormatState:=StateSafe;;;
.
OnNewCol:=NumerationOnNewCol;. OnNewRow:=NumerationOnNewRow;.
OnDrawCell:=EdLineTaskOnDrawCell;
.
OnDblClick:=OldOnDblClick;. OnMouseUp:=OldOnMouseUp;
.
OnSetEditText:=OldOnSetEditText;
{Вимикаємо редагування
екранної таблиці:}. Options:=CurGrid.
Options - [goEditing];;InSolving thenSelf. CurOutConsole<>Nil then.
CurOutConsole. Lines. Add (sc_CurProcName+sc_CantChangeStateInSolving);;;
Self. CurGrid=Nil then {Якщо
екранну таблицю не задано:}{запам'ятовуємо поточний режим, і більше нічого не
робимо тут:}. CurFormatState:=Value; Exit;;
{Якщо задано новий
режим:}Self.
CurFormatState<>Value then{Якщо форматування було вимкнене:}Self.
CurFormatState=fs_NoFormatting then{Запам'ятовуємо обробники подій, які
замінимо на свої
форматувальники:}:=CurGrid. OnNewCol;:=CurGrid. OnNewRow;:=CurGrid.
OnDrawCell;:=CurGrid. OnDblClick;:=CurGrid. OnSetEditText;:=CurGrid.
OnMouseUp;;
{Якщо таблиця
редагована, то приймаємо останні зміни перед
зміною режиму:}Self. CurGridModified then Self. Refresh;
Value of_EnteringEqs: {редагування
таблиці системи лінійних рівнянь:}
{Встановлюємо потрібну
кількість рядків і стовпців екранної
таблиці для фіксованих
заголовків («тільки для читання»).
Для цього забезпечуємо
щоб кількість рядків і стовпців не була
меншою за потрібну
кількість фіксованих, плюс хоч один
стовпець / рядок (хоч
одна комірка) для редагування:}CurGrid.
ColCount<bc_FixedCols+1 then. ColCount:=bc_FixedCols+1;CurGrid.
RowCount<bc_FixedRows+1 then. RowCount:=bc_FixedRows+1;
.
FixedRows:=bc_FixedRows;. FixedCols:=bc_FixedCols;
{Позиціювання таблиці до
зміни режиму:}:=Self.CHeadColNum;
OldHRowPos:=Self.CHeadRowNum;
{Позиціювання
відображення таблиці у даному режимі редагування:}.CHeadColNum:=CurGrid. FixedCols-1;.CHeadRowNum:=CurGrid.
FixedRows-1;
{Якщо позиціювання
змінилося, то відображаємо таблицю
в новому місці:}(OldHColPos<>Self.CHeadColNum) or
(OldHRowPos<>Self.CHeadRowNum)
then Self. Refresh;
.
OnNewCol:=EditLineEqsOnNewCol;. OnNewRow:=EditLineEqsOnNewRow;. OnDrawCell:=EditLineEqsOnDrawCell;
.
OnDblClick:=OldOnDblClick;. OnMouseUp:=OldOnMouseUp;
{Вмикаємо можливість
редагування:}. Options:=CurGrid.
Options+[goEditing];. OnSetEditText:=ReactOnSetEditText;
:=False;;_EnteringLTask:{Редагування
таблиці задачі ЛП (максимізації/мінімізації):}
{Встановлюємо потрібну
кількість рядків і стовпців екранної
таблиці для фіксованих
заголовків («тільки для читання»).
Для цього забезпечуємо
щоб кількість рядків і стовпців не була
меншою за потрібну
кількість фіксованих, плюс хоч один
стовпець / рядок (хоч
одна комірка) для редагування:}CurGrid.
ColCount<bc_FixedCols+1 then. ColCount:=bc_FixedCols+1;CurGrid.
RowCount<bc_FixedRows+1 then. RowCount:=bc_FixedRows+1;.
FixedRows:=bc_FixedRows;. FixedCols:=bc_FixedCols;
{Позиціювання таблиці до
зміни режиму:}:=Self.CHeadColNum;
OldHRowPos:=Self.CHeadRowNum;
{Позиціювання
відображення таблиці у даному режимі редагування:}.CHeadColNum:=CurGrid. FixedCols-1 +
bc_LTaskColsBeforeVars;.CHeadRowNum:=CurGrid. FixedRows-1;
{Якщо позиціювання змінилося,
то відображаємо таблицю
в новому місці:}(OldHColPos<>Self.CHeadColNum) or
(OldHRowPos<>Self.CHeadRowNum)
then Self. Refresh;
.
OnNewCol:=EdLineTaskOnNewCol;. OnNewRow:=EdLineTaskOnNewRow;.
OnDrawCell:=EdLineTaskOnDrawCell;
.
OnDblClick:=EdLineTaskOnDblClick;. OnMouseUp:=EdLineTaskOnMouseUp;
{Вмикаємо можливість
редагування:}. Options:=CurGrid.
Options+[goEditing];. OnSetEditText:=ReactOnSetEditText;
:=False;;_SolvingEqsM1: {вирішування
системи лінійних рівнянь способом 1:}. ColCount:=bc_FixedCols+1;.
RowCount:=bc_FixedRows+1;. FixedRows:=bc_FixedRows;. FixedCols:=bc_FixedCols;
{Пробуємо підготувати
таблицю до вирішування. Якщо не
вдається, то залишаємось
у режимі, який був до спроби його
змінити:}Not (Self. PrepareToSolveEqsWithM1) then:=Self. CurFormatState;
{Перемикаємо на режим
fs_NoFormatting, і назад у поточний,
щоб встановити усі
настройки цього режиму:}.
TableFormatState:=fs_NoFormatting;. TableFormatState:=StateSafe;;;
.
OnNewCol:=NumerationOnNewCol;. OnNewRow:=NumerationOnNewRow;. OnDrawCell:=SolveLineEqsM1OrM2OnDrawCell;
.
OnDblClick:=OldOnDblClick;. OnMouseUp:=OldOnMouseUp;
{Вимикаємо редагування
екранної таблиці:}. Options:=CurGrid.
Options - [goEditing];. OnSetEditText:=OldOnSetEditText;;_SolvingEqsM2: {вирішування
системи лінійних рівнянь способом 2:}. ColCount:=bc_FixedCols+1;.
RowCount:=bc_FixedRows+1;. FixedRows:=bc_FixedRows;. FixedCols:=bc_FixedCols;
{Пробуємо підготувати
таблицю до вирішування. Якщо не
вдається, то залишаємось
у режимі, який був до спроби його
змінити:}Not (Self. PrepareToSolveEqsWithM2) then:=Self. CurFormatState;
{Перемикаємо на режим
fs_NoFormatting, і назад у поточний,
щоб встановити усі
настройки цього режиму:}.
TableFormatState:=fs_NoFormatting;. TableFormatState:=StateSafe;;;
.
OnNewCol:=NumerationOnNewCol;. OnNewRow:=NumerationOnNewRow;.
OnDrawCell:=SolveLineEqsM1OrM2OnDrawCell;. OnDblClick:=OldOnDblClick;.
OnMouseUp:=OldOnMouseUp;. OnSetEditText:=OldOnSetEditText;
{Вимикаємо редагування
екранної таблиці:}. Options:=CurGrid.
Options - [goEditing];;_SolvingLTask: GoSolveLTask;_FreeEdit: {Режим
вільного редагування таблиці:}. OnNewCol:=OldOnNewCol;.
OnNewRow:=OldOnNewRow;. OnDrawCell:=OldOnDrawCell;. OnDblClick:=OldOnDblClick;.
OnMouseUp:=OldOnMouseUp;
{Вмикаємо редагування
екранної таблиці:}. Options:=CurGrid.
Options+[goEditing];
{Вмикаємо стеження за
змінами в екнанній таблиці:}.
OnSetEditText:=ReactOnSetEditText;:=False;;{Без форматування
(fs_NoFormatting), або невідомий режим:}. OnNewCol:=OldOnNewCol;.
OnNewRow:=OldOnNewRow;. OnDrawCell:=OldOnDrawCell;. OnDblClick:=OldOnDblClick;.
OnMouseUp:=OldOnMouseUp;
.
OnSetEditText:=OldOnSetEditText;:=False;;;. Invalidate; {перемальовуємо
таблицю з новими форматувальниками}. CurFormatState:=Value; {запам'ятовуємо
новий режим форматування};;
TGridFormattingProcs.
SetNewGrid (Value:TGrowingStringGrid);SafeFormatState:TTableFormatState;Self.
CurGrid<>Value then {якщо задано новий об'єкт таблиці:}:=Self.
TableFormatState;
{Знімаємо усі
процедури-форматувальники, перемальовуємо таблицю
(якщо вона була) перед
заміною її на задану:}.
TableFormatState:=fs_NoFormatting;. CurGrid:=Value; {запам'ятовуємо
вказівник на новий об'єкт таблиці}
{Застосовуємо
форматування для нової таблиці (якщо вона не відсутня,
вказівник на неї не
рівний Nil):}. TableFormatState:=SafeFormatState;
.
Refresh;;;TGridFormattingProcs. SetHeadColNum (Value: Integer);Self.
CurFormatState=fs_FreeEdit thenValue<0 then Value:=0;.CHeadColNum:=Value;;;
TGridFormattingProcs.
SetHeadRowNum (Value: Integer);Self. CurFormatState=fs_FreeEdit thenValue<0
then Value:=0;.CHeadRowNum:=Value;;;
TGridFormattingProcs.
SetNewMemo (Value:TMemo);Self. CurOutConsole<>Nil then. CurOutConsole.
Lines. Add (Self. ClassName+': повідомлення вимкнені.');.
CurOutConsole:=Value;Self. CurOutConsole<>Nil then. CurOutConsole. Lines.
Add (Self. ClassName+': повідомлення ввімкнені.');;.
Висновки
лінійний програмування
компромісний розв'язок
Хоч кожній залежній
змінній одної задачі відповідає функція-умова (нерівність) двоїстої, і кожній
функції-умові відповідає залежна змінна, ці пари величин приймають різні
значення у розв’язку пари задач.
Компромісний розв’язок
багатокритеріальної задачі ЛП зручно застосовувати для об’єктів управління з
такими вихідними параметрами (функціями мети), які є практично рівноправними
(мають однаковий пріоритет до оптимізації, або їх пріоритети складно оцінити).
За допомогою нього можна отримати розв’язок з мінімальним сумарним програшем
оптимізації параметрів.
Використана література
1. Левин С.В., Александрова В.В.: «БАГАТОКРИТЕРІАЛЬНА ОПТИМІЗАЦІЯ З ВИКОРИСТАННЯМ
ТЕОРЕТИКО-ІГРОВОГО ПІДХОДУ»: методичні вказівки до виконання курсової роботи з
курсу «Математичні методи дослідження операцій» - Харків, Національний
аерокосмічний університет ім. М.Є. Жуковського «Харківський авіаційний інститут»,
2008 р.
2. Довідка з Borland
Delphi 6.