}
Constsc_CurProcName='MakeDualLTask';
Var SafeMas:TValOrNameMas; CurCol, CurRow, DFuncCount: Integer;
DualTType:TDualTaskType; NewDFuncType, OldDFuncType:THeadLineElmType;
Begin
SafeMas:=Nil;
If Self. CurFormatState<>fs_EnteringLTask then
Begin
If Self. CurOutConsole<>Nil then
Self. CurOutConsole. Lines. Add (sc_CurProcName+sc_CanMakeOnlyInELTaskMode);
MakeDualLTask:=False; Exit;
End;
If Self. CurGridModified then
Begin
If Not (Self. GetTask(True)) then
Begin
MakeDualLTask:=False; Exit;
End;
End;
If Self. TaskHeight<=0 then {Якщо таблиця пуста:}
Begin
If Self. CurOutConsole<>Nil then
Self. CurOutConsole. Lines. Add (sc_CurProcName+sc_EmptyTable);
MakeDualLTask:=False; Exit;
End;
{Перевіряємо, чи функція мети лише одна, і визначаємо її тип
(для максимізації чи мінімізації):}
DFuncCount:=0; DualTType:=dt_MaxToMin; OldDFuncType:=bc_DestFuncToMax;
For CurRow:=0 to Length (Self. CurHeadCol) – 1 do
Begin
If Self. CurHeadCol[CurRow].ElmType=bc_DestFuncToMax then
Begin
DualTType:=dt_MaxToMin;
OldDFuncType:=Self. CurHeadCol[CurRow].ElmType;
Inc(DFuncCount);
End
Else if Self. CurHeadCol[CurRow].ElmType=bc_DestFuncToMin then
Begin
DualTType:=dt_MinToMax;
OldDFuncType:=Self. CurHeadCol[CurRow].ElmType;
Inc(DFuncCount);
End;
End;
{Якщо функцій мети декілька або жодної:}
If DFuncCount<>1 then
Begin
If Self. CurOutConsole<>Nil then
Self. CurOutConsole. Lines. Add (sc_CurProcName+
sc_CanMakeDTaskOnlyForOneDFunc+IntToStr(DFuncCount));
MakeDualLTask:=False; Exit;
End;
If DualTType=dt_MaxToMin then NewDFuncType:=bc_DestFuncToMin
Else NewDFuncType:=bc_DestFuncToMax;
{Зсуваємо рядок функції мети вниз таблиці. При цьому позначки порядку
рядків залишаємо на тих самих місцях (і присвоюємо тим рядкам, які
стають на ці місця):}
Self. ShiftRowsDown([bc_DestFuncToMax, bc_DestFuncToMin], True);
Transpose (Self. CurTable); {транспонуємо таблицю коефіцієнтів}
{Обробляємо заголовки таблиці у відповідність до двоїстої задачі:}
{Для рядка-заголовка, що стане стовпцем-заголовком:}
For CurCol:=0 to Length (Self. CurHeadRow) – 1 do
Begin {Проходимо по усіх змінних і останньому елементу –
множнику стовпця вільних членів – одиниці:}
If Self. CurHeadRow[CurCol].ElmType=bc_DependentVar then {Якщо змінна >=0:}
Begin {Ця комірка буде заголовком функції умови-нерівності зі знаком «>=»:}
Self. CurHeadRow[CurCol].ElmType:=bc_FuncVal;
Self. CurHeadRow[CurCol].VarInitInRow:=False;
{Формуємо назву функції:}
{якщо змінна має назву змінної двоїстої задачі, то дамо назву
функції прямої задачі, якщо назва прямої – назву двоїстої:}
If Pos (sc_DualTaskVarNameStart, Self. CurHeadRow[CurCol].AsVarName)>0 then
Self. CurHeadRow[CurCol].AsVarName:=sc_YFuncName + IntToStr (CurCol+1)
Else Self. CurHeadRow[CurCol].AsVarName:=sc_DualTaskFuncNameStart +
IntToStr (CurCol+1);
{Якщо переходимо від задачі максимізації до двоїстої задачі
мінімізації, то для нерівності треба буде змінити знак «>=» на «<=»,
(якщо для змінної була умова «>=0», і заголовок для неї був додатний),
тому змінюємо знак заголовка:}
IfDualTType=dt_MaxToMinthen
ChangeSignForValOrVarName (Self. CurHeadRow[CurCol]);
End {Якщо змінна вільна:}
Else if Self. CurHeadRow[CurCol].ElmType=bc_IndependentVar then
Begin{Ця комірка буде заголовком умови-рівняння:}
Self. CurHeadRow[CurCol].ElmType:=bc_Number;
Self. CurHeadRow[CurCol].AsNumber:=0;
End {Якщо це число:}
Else if Self. CurHeadRow[CurCol].ElmType=bc_Number then
Begin
If Self. CurHeadRow[CurCol].AsNumber=1 then {якщо це множник вільних членів}
Begin
Self. CurHeadRow[CurCol].ElmType:=NewDFuncType;
Self. CurHeadRow[CurCol].VarInitInRow:=False;
{Формуємо назву функції мети двоїстої задачі
(залежно від назви функції мети поданої задачі):}
If Pos (sc_DualDestFuncHdr,
Self. CurHeadCol [Length(Self. CurHeadCol) – 1].AsVarName)>0 then
Self. CurHeadRow[CurCol].AsVarName:=sc_DestFuncHdr
Else Self. CurHeadRow[CurCol].AsVarName:=sc_DualDestFuncHdr;
End;
End;
End;
{Для стовпця-заголовка, що стане рядком-заголовком:}
For CurRow:=0 to Length (Self. CurHeadCol) – 1 do
Begin
{Проходимо по усіх елементах-заголовках рядків, і останньому елементу –
заголовку рядка функції мети:}
IfSelf. CurHeadCol[CurRow].ElmType=bc_FuncValthen{Якщо нерівність «<=»:}
Begin
Self. CurHeadCol[CurRow].ElmType:=bc_DependentVar; {буде змінна >=0}
Self. CurHeadCol[CurRow].VarInitInRow:=True;
{Формуємо назву змінної:
якщо функція-нерівність має назву функції двоїстої задачі, то
дамо назву змінної прямої задачі, якщо назва прямої – назву двоїстої:}
If Pos (sc_DualTaskFuncNameStart, CurHeadCol[CurRow].AsVarName)>0 then
Self. CurHeadCol[CurRow].AsVarName:=sc_XVarName + IntToStr (CurRow+1)
Else Self. CurHeadCol[CurRow].AsVarName:=sc_DualTaskVarNameStart +
IntToStr (CurRow+1);
{Якщо переходимо від задачі мінімізації до двоїстої задачі
максимізації, то для змінної треба буде змінити знак і умову «<=0»
на «>=0», (якщо для нерівність була зі знаком «<=», і заголовок для
неї був додатний), тому змінюємо знак заголовка:}
If DualTType=dt_MinToMax then
ChangeSignForValOrVarName (Self. CurHeadCol[CurRow]);
End
Else if Self. CurHeadCol[CurRow].ElmType=bc_Number then
Begin
If Self. CurHeadCol[CurRow].AsNumber=0 then {Якщо 0, заголовок рівняння:}
Begin
Self. CurHeadCol[CurRow].ElmType:=bc_IndependentVar;
Self. CurHeadCol[CurRow].VarInitInRow:=True;
{Формуємо назву змінної двоїстої задачі
(залежно від назви функції мети поданої задачі):}
If Pos (sc_DualDestFuncHdr,
Self. CurHeadCol [Length(Self. CurHeadCol) – 1].AsVarName)>0 then
Self. CurHeadCol[CurRow].AsVarName:=sc_XVarName+IntToStr (CurRow+1)
Else Self. CurHeadCol[CurRow].AsVarName:=sc_DualTaskVarNameStart+
IntToStr (CurRow+1);
End;
End {Якщо заголовок рядка функції мети:}
Else if Self. CurHeadCol[CurRow].ElmType=OldDFuncType then
Begin
Self. CurHeadCol[CurRow].ElmType:=bc_Number;
Self. CurHeadCol[CurRow].AsNumber:=1; {буде множник стовпця вільних членів}
End;
End;
{Міняємо рядок і стовпець-заголовки таблиці місцями:}
SafeMas:=Self. CurHeadRow;
Self. CurHeadRow:=Self. CurHeadCol;
Self. CurHeadCol:=SafeMas;
{У новому стовпці-заголовку шукаємо комірки-заголовки нерівностей «>=».
Їх заміняємо на «<=» множенням рядка на -1:}
For CurRow:=0 to Length (Self. CurHeadCol) – 1 do
Begin
If Self. CurHeadCol[CurRow].ElmType=bc_FuncVal then
Begin
If ValSign (Self. CurHeadCol[CurRow])=bc_Negative then
Self. ChangeSignsInRow(CurRow);
End;
End;
{У новому рядку-заголовку шукаємо комірки-заголовки залежних змінних,
які мають умову «<=0». Змінюємо цю умову на «>=0» множенням стовпця на -1:}
For CurCol:=0 to Length (Self. CurHeadRow) – 1 do
Begin
If Self. CurHeadRow[CurCol].ElmType=bc_DependentVar then
Begin
If ValSign (Self. CurHeadRow[CurCol])=bc_Negative then
Self. ChangeSignsInCol(CurCol);
End;
End;
{Відображаємо отриману таблицю у екранній таблиці:}
Self. WriteTableToGrid (Self.CHeadColNum, Self.CHeadRowNum);
MakeDualLTask:=True;
End;
Function TGridFormattingProcs. PrepareToSolveEqsWithM1: Boolean;
Const sc_CurProcName='PrepareToSolveEqsWithM1';
Var CurRow, ColToDel: Integer;
Begin
If (Self. CurFormatState=fs_EnteringEqs) or
(Self. CurFormatState=fs_NoFormatting) then
Begin
{Якщо таблиця не зчитана, то читаємо:}
If (Self. CurGridModified) and (Self. CurFormatState=fs_EnteringEqs) then
Begin
If Not (Self. GetTask) then
Begin
PrepareToSolveEqsWithM1:=False; Exit;
End;
End;
If Self. TaskHeight<=0 then {Якщо таблиця пуста:}
Begin
If Self. CurOutConsole<>Nil then
Self. CurOutConsole. Lines. Add (sc_CurProcName+sc_EmptyTable);
PrepareToSolveEqsWithM1:=False;
Exit;
End;
If Not (Self. EqM1TaskPrepared) then
Begin
{Копіюємо стовпець вільних членів (правих частин рівнянь) із
останнього стовпця таблиці до стовпця-заголовка:}
For CurRow:=0 to Length (Self. CurHeadCol) – 1 do
Begin
Self. CurHeadCol[CurRow].ElmType:=bc_Number;
Self. CurHeadCol[CurRow].AsNumber:=
Self. CurTable [CurRow, Length (CurTable[CurRow]) – 1];
End;
{Видаляємо цей останній стовпець із таблиці:}
ColToDel:=Length (Self. CurTable[0]) – 1;
DelColsFromMatr (Self. CurTable, ColToDel, 1);
DeleteFromArr (Self. CurHeadRow, ColToDel, 1);
End;
{Позиціювання відображення таблиці у даному режимі вирішування:}
Self.CHeadColNum:=CurGrid. FixedCols;
Self.CHeadRowNum:=CurGrid. FixedRows-1;
{Відображаємо таблицю, що підготована для розв'язування:}
Self. WriteTableToGrid (Self.CHeadColNum, Self.CHeadRowNum);
{Якщо таблиця пуста після перенесення останнього стовпця у
стовпець-заголовок:}
If Self. TaskHeight<=0 then
Begin
PrepareToSolveEqsWithM1:=False;
Exit;
End;
Self. EqM1TaskPrepared:=True;
PrepareToSolveEqsWithM1:=True;
End
Else
Begin
If Self. CurOutConsole<>Nil then
Self. CurOutConsole. Lines. Add (sc_CurProcName+sc_WrongEditMode);
PrepareToSolveEqsWithM1:=False;
End;
End;
Function TGridFormattingProcs. PrepareToSolveEqsWithM2: Boolean;
Const sc_CurProcName='PrepareToSolveEqsWithM2';
Var CurRow: Integer;
Begin
If (Self. CurFormatState=fs_EnteringEqs) or
(Self. CurFormatState=fs_NoFormatting) then
Begin {Якщо таблиця не зчитана, то читаємо:}
If (Self. CurGridModified) and (Self. CurFormatState=fs_EnteringEqs) then
Begin
If Not (Self. GetTask) then
Begin
PrepareToSolveEqsWithM2:=False; Exit;
End;
End;
If Self. TaskHeight<=0 then {Якщо таблиця пуста:}
Begin
If Self. CurOutConsole<>Nil then
Self. CurOutConsole. Lines. Add (sc_CurProcName+sc_TableIsNotReady);
PrepareToSolveEqsWithM2:=False; Exit;
End;
If Not (Self. EqM2TaskPrepared) then
Begin
For CurRow:=0 to Length (Self. CurHeadCol) – 1 do
Begin
{Заповнюємо стовпець-заголовок нулями:}
Self. CurHeadCol[CurRow].ElmType:=bc_Number;
Self. CurHeadCol[CurRow].AsNumber:=0;
{Змінюємо знаки у останньому стовпці таблиці – стовпці вільних
членів. Так як вони у правих частинах рівнянь, то знаходячись у
таблиці коефіцієнтів лівих частин, повинні бути з протилежними
знаками:}
Self. CurTable [CurRow, Length (CurTable[CurRow]) – 1]:=
– Self. CurTable [CurRow, Length (CurTable[CurRow]) – 1];
End;
End;
{Позиціювання відображення таблиці у даному режимі вирішування:}
Self.CHeadColNum:=CurGrid. FixedCols;
Self.CHeadRowNum:=CurGrid. FixedRows-1;
{Відображаємо таюдицю, що підготована для розв'язування:}
Self. WriteTableToGrid (Self.CHeadColNum, Self.CHeadRowNum);
Self. EqM2TaskPrepared:=True;
PrepareToSolveEqsWithM2:=True;
End
Else
Begin
If Self. CurOutConsole<>Nil then
Self. CurOutConsole. Lines. Add (sc_CurProcName+sc_WrongEditMode);
PrepareToSolveEqsWithM2:=False;
End;
End;
{TTableFormatState=(fs_EnteringEqs, fs_EnteringLTask, fs_SolvingEqsM1,
fs_SolvingEqsM2, fs_SolvingLTask,
fs_NoFormatting, fs_FreeEdit);}
Function TGridFormattingProcs. PrepareToSolveLTask: Boolean;
Const sc_CurProcName='PrepareToSolveLTask';
Begin
If (Self. CurFormatState=fs_EnteringLTask) or
(Self. CurFormatState=fs_NoFormatting) then
Begin {Якщо таблиця у режимі редагування задачі, і модифікована, то зчитуємо:}
If (Self. CurGridModified) and (Self. CurFormatState=fs_EnteringLTask) then
Begin
If Not (Self. GetTask) then {зчитуємо таблицю (умову) з екранної таблиці}
Begin
PrepareToSolveLTask:=False; Exit;
End;
End;
If Self. TaskHeight<=0 then {Якщо таблиця пуста:}
Begin
If Self. CurOutConsole<>Nil then
Self. CurOutConsole. Lines. Add (sc_CurProcName+sc_TableIsNotReady);
PrepareToSolveLTask:=False; Exit;
End;
If Not (Self.LTaskPrepared) then {якщо ця підготовка ще не виконувалася:}
Begin
{Зсуваємо рядки цільових функцій вниз. При цьому позначки порядку
рядків залишаємо на тих самих місцях (і присвоюємо тим рядкам, які
стають на ці місця):}
Self. ShiftRowsDown([bc_DestFuncToMax, bc_DestFuncToMin], True);
{Позиціювання відображення таблиці у даному режимі вирішування:}
Self.CHeadColNum:=CurGrid. FixedCols;
Self.CHeadRowNum:=CurGrid. FixedRows-1;
{Відображаємо таблицю, що підготована для розв'язування:}
Self. WriteTableToGrid (Self.CHeadColNum, Self.CHeadRowNum);
Self.LTaskPrepared:=True;
End;
PrepareToSolveLTask:=True;
End
Else
Begin
If Self. CurOutConsole<>Nil then
Self. CurOutConsole. Lines. Add (sc_CurProcName+sc_WrongEditMode);
PrepareToSolveLTask:=False;
End;
End;
Function TGridFormattingProcs. PrepareDFuncForSimplexMaximize: Boolean;