Багатокритеріальна задача лінійного програмування

 

1. Завдання


Розвязати багатокритеріальну задачу лінійного програмування з отриманням компромісного розвязку за допомогою теоретико-ігрового підходу.

Задача (варіант 1):


Z1= x1+2x2+x3 ® max

Z2= - x1 -2x2+x3+x4 ® min3= -2x1 -x2+x3+x4 ® max

з обмеженнями

x1 -x2+3x3+4x4 £ 10

x1+x2+x3 -x4 £ 5

x1+2x2 -2x3+4x4 £ 12

"x ³ 0


2. Теоретичні відомості

У цій роботі реалізовано вирішування таких задач лінійного програмування: розвязування задач багатокритеріальної оптимізації, тобто пошук компромісного рішення для задач з кількома функціями мети.

Ця задача така:

Задано обєкт управління, що має n входів і k виходів. Вхідні параметри складають вектор X = {xj}, . Кожен з вхідних параметрів може мати обмеження, що накладене на область його значень. В програмі підтримуються параметри без обмежень на значення, і з обмеженнями невідємності (з областю ). Також на комбінації вхідних значень можуть бути накладені обмеження як система лінійних рівнянь або нерівностей:


Вихідні сигнали обєкта є лінійними комбінаціями вхідних сигналів. Для досягнення ефективності роботи обєкта управління частину вихідних сигналів треба максимізувати, інші - мінімізувати, змінюючи вхідні сигнали і дотримуючись обмежень на ці сигнали (задоволення усіх нерівностей, рівнянь і обмежень області значень кожного з вхідних параметрів). Тобто вихідні сигнали є функціями мети від вхідних:



Як правило, для багатокритеріальної задачі не існує розвязку, який би був найкращим (оптимальним) для усіх функцій мети одночасно. Проте можна підібрати такий розвязок, який є компромісним для усіх функцій мети (в точці цього розвязку кожна з функцій мети якнайменше відхиляється від свого оптимального значення в заданій системі умов (обмежень).

Тут реалізовано пошук компромісного розвязку за допомогою теоретико-ігрового підходу, що був розроблений під керівництвом доцента ХАІ Яловкіна Б.Д. Цей підхід дозволяє знайти компромісний розвязок з мінімальним сумарним відхиленням всіх виходів (значень функцій мети) від їхніх екстремальних значень за даної системи обмежень.

Йде пошук компромісного вектора значень змінних в такому вигляді:


тут - вектор, що оптимальний для i-го критерію (функції мети); li - вагові коефіцієнти.

Для отримання цього вектора виконуються такі кроки розвязування:

) Розвязується k однокритеріальних задач ЛП за допомогою симплекс-методу (для кожної з функцій мети окремо, з тією самою системою обмежень, що задана для багатокритеріальної задачі). Так отримуємо k оптимальних векторів значень змінних (для кожної з цільових функцій - свій).

) Підраховуються міри неоптимальності для всіх можливих підстановок кожного вектора значень змінних у кожну з функцій мети, за такою формулою:



де Cj - вектор коефіцієнтів j-ої функції мети;

X*i - вектор, що оптимальний для i-ої функції мети;

X*j - вектор, що оптимальний для j-ої функції мети;

Всі ці міри неоптимальності складають квадратну матрицю, рядки якої відповідають k оптимальним векторам X*i для кожної функції мети, а стовпці - k функціям мети Cj. Ця матриця розглядається як платіжна матриця матричної гри двох партнерів X* і Z, що визначена множиною стратегій X*={X*1, …, X*k} першого гравця, і Z={C1X, …, CkX} другого. Всі міри неоптимальності є недодатними, і є коефіцієнтами програшу першого гравця. На головній діагоналі вони рівні нулю (бо є мірами неоптимальності оптимального вектора для своєї ж функції).

) Матриця мір неоптимальності заміняється еквівалентною їй матрицею додаванням до кожної міри неоптимальності , тобто найбільшого з абсолютних значень всіх мір. Якщо таке найбільше значення рівне нулю, то всі міри рівні нулю, і в такому випадку замість нього до усіх мір додається число 1. В результаті отримуємо матрицю з невідємними елементами. На головній діагоналі усі вони рівні максимальному значенню. Така заміна матриці не змінює рішення гри, змінює тільки її ціна. Тобто тепер гра має вигляд не гри програшів, а гри з пошуком максимального виграшу. Для пошуку оптимальної стратегії для першого гравця гра подається як пара взаємнодвоїстих однокритеріальних задач ЛП. Для першого гравця потрібні значення змінних двоїстої задачі :


v1=v2=…vk=W=--…-1-u1=1-u2=1…….....-uk=11Z =-1-1…-10

Розвязавши цю задачу і отримавши оптимальні значення 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;;;;

. Close(CurFile);:=sc_CurProcName + sc_CantCloseFile + 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.


1. Завдання Розвязати багатокритеріальну задачу лінійного програмування з отриманням компромісного розвязку за допомогою теоретико-ігрового підходу. З

Больше работ по теме:

КОНТАКТНЫЙ EMAIL: [email protected]

Скачать реферат © 2017 | Пользовательское соглашение

Скачать      Реферат

ПРОФЕССИОНАЛЬНАЯ ПОМОЩЬ СТУДЕНТАМ